En principio, el uso del sistema de ficheros para Entrada/Salida con el teclado y la pantalla debería ser suficiente, pero por desgracia no es así. Su uso es relativamente lento, por lo que solo parece útil utilizarlo cuando necesitamos poder redireccionar la entrada o la salida del programa, o cuando la velocidad no es importante.
Para mejorar y simplificar el acceso a los tres dispositivos principales de entrada de datos, OS/2 permite el acceso directo a los subsistemas de Video, Teclado y Ratón, de modo que se puede mejorar notablemente la velocidad de los programas. El acceso a estas funciones va desde el mismo procedimiento que en el acceso a través del sistema de archivos (una ristra de caracteres) hasta el acceso directo al hardware del sistema. Entre ambos extremos hay un amplio abanico de posibilidades. De entre todas ellas, se deberá escoger la que mejor se adapte a las necesidades de velocidad y flexibilidad del programa.
Estrictamente hablando, siempre usamos los subsistemas. El sistema de ficheros, cuando sabe que una salida es para la pantalla, envía los datos al subsistema de video (VIO). Sin embargo, antes tiene que comprobar para quien es la salida, con lo que pierde algo de rendimiento. Así mismo, la posibilidad de redireccionar entradas y salidas es otra opción que ralentiza el sistema. En muchos casos, la pérdida de velocidad es totalmente inapreciable, pero en algunos programas (juegos, aplicaciones a pantalla completa,...) el uso del sistema de ficheros puede ser totalmente contraproducente para el rendimiento. Usando el subsistema directamente nos ahorramos pasos intermedios, a costa de perder la posibilidad de redirección y de entrada/salida generalizada para ficheros y dispositivos.
En OS/2 disponemos de los siguientes subsistemas:
El subsistema de vídeo (VIO) es el encargado de gestionar la comunicación entre los programas y la pantalla. Es, sin duda, el subsistema más complejo de los tres, y el que ofrece, por tanto, mayores posibilidades.
Dado que puede haber varios programas ejecutandose a la vez en el sistema, pero solo uno puede acceder a la vez a la pantalla (normalmente el programa que se encuentra en primer plano o
foreground), es necesario virtualizar ésta por medio de un
buffer de pantalla propio de cada programa: el
LVB (
Logic
Video
Buffer, buffer de vídeo virtual). Cuando una aplicación quiere escribir en pantalla y se encuentra en segundo plano (
background), su salida se escribe en dicho LVB. En el momento en que el usuario conmuta dicho programa a primer plano, el LVB se copia tal cual en la memoria de pantalla, y el resto de las escrituras van a ésta directamente. Si se vuelve a conmutar dicho programa a segundo plano, OS/2 copia lo que hubiese en pantalla en ese momento al LVB. De este modo, el programa nunca sabe ni le preocupa cuando está en primer o en segundo plano.
FUNCIONES VIO
Salida por TTY virtual
En un extremo se encuentra el primer servicio que ofrece el subsistema VIO, que es el de salida TTY. Este servicio es casi idéntico a la salida de caracteres por medio del sistema de archivos. De hecho, éste, cuando comprueba que lo que el programa envía va dirigido a la pantalla, usa este servicio para realizar la función.
¿Cual es la diferencia entre uno y otro, entonces? Las diferencias son dos: la primera es que el uso del subsistema VIO es una opción más rápida que el sistema de ficheros; la segunda es que si usamos el subsistema, no podremos redireccionar la salida a un fichero, o a otro dispositivo de salida. Siempre irá a la pantalla.
El servicio TTY admite los caracteres de control estandar del ASCII, y también puede soportar ANSI, si éste es activado mediante la llamada correspondiente.
VioWrtTTY
VioGetAnsi
VioSetAnsi
VioGetMode
VioSetMode
VioGetState
VioSetState
Salida de cadenas de caracteres
Los siguientes servicios se encargan del tratamiento de la pantalla a más bajo nivel. Con ellos podemos imprimir largas cadenas de caracteres con atributos y leer los caracteres que hay en determinadas posiciones de la pantalla. También podemos repetir un caracter o una pareja caracter-atributo un número determinado de veces.
Los atributos son bytes que definen el color de tinta y de fondo para cada caracter, así como otras características como el parpadeo. Están compuestos por un byte, el cual se divide en dos nibbles (grupos de 4 bits). El nibble de menor peso determina el color de la tinta del caracter, y el de mayor peso el color de fondo y, según se encuentre activo o no, el parpadeo del caracter. La distribución es como sigue:
|| Parpadeo activado|| Bit || Significado || || 7 || Parpadeo del caracter || || 6 || Rojo del fondo || || 5 || Verde del fondo || || 4 || Azul del fondo || || 3 || Intensidad de la tinta || || 2 || Rojo de la tinta || || 1 || Verde de la tinta || || || Azul de la tinta || || Intensidad activada|| Bit || Significado || || 7 || Intensidad del fondo || || 6 || Rojo del fondo || || 5 || Verde del fondo || || 4 || Azul del fondo || || 3 || Intensidad de la tinta || || 2 || Rojo de la tinta || || 1 || Verde de la tinta || || || Azul de la tinta || ||
Los bits de color activan directamente cada una de las componentes del monitor, de modo que éstas se suman directamente, dando lugar a los siguientes colores:
|| || Negro || 1 || Azul || 2 || Verde || 3 || Celeste ||
|| 4 || Rojo || 5 || Magenta || 6 || Amarillo || 7 || Blanco ||
El bit de intensidad se limita a hacer estos colores más o menos brillantes.
Estos servicios orientados a caracter siguen siendo independientes del hardware utilizado de modo que no es necesario saber como se trabaja a nivel físico con ellos. Por otra parte, el propio OS/2 optimiza las transferencias para cada uno de ellos, de modo que se consigue la mayor velocidad posible, y se eliminan ciertos problemas inherentes a algunos sistemas gráficos (por ejemplo, en las tarjetas CGA sincroniza automáticamente la escritura con el retrazado vertical, de modo que se evita la aparición de
nieve en la pantalla).
Tanto cuando hacemos una lectura como una escritura, si excedemos el fin de una línea se seguirá leyendo en la siguiente, y si llegamos al final de la pantalla no se seguirá leyendo ni imprimiendo.
VioWrtCellStr
VioWrtCharStr
VioWrtCharStrAtt
VioWrtNAttr
VioWrtNCell
VioWrtNChar
VioReadCellStr
VioReadCharStr
Funciones de Scroll
El subsistema VIO ofrece, además, la posibilidad de realizar scroll de ventanas en modo texto. Con este conjunto de funciones, podemos desplazar parte o toda la pantalla en cualquiera de las cuatro direcciones posibles. La razón de incluirlas es que resulta mucho más rápido que hacer una rutina que lea cada posición del buffer de video y la reescriba en el lugar adecuado, aparte de que se trata de una función muy común en casi cualquier programa.
VioScrollDn
VioScrollLf
VioScrollRt
VioScrollUp
Definición y movimiento del cursor
El cursor (el cuadradito parpadeante) es totalmente definible por el usuario en las sesiones de texto y gráficos de OS/2. Podemos definir tanto su tamaño como su posición dentro del caracter.
Al contrario que en MS-DOS, cuando escribimos en la pantalla de OS/2 la posición del cursor no se cambia. Esto se hace así para ganar tiempo. Normalmente el cursor solo se usa cuando hay que introducir datos por teclado, y el resto de las veces se suele hacer desaparecer de la pantalla. Esta es la razón de que halla un conjunto de funciones para situar el cursor. De esta manera se gana en velocidad.
VioGetCurPos
VioSetCurPos
VioGetCurType
VioSetCurType
Acceso al LVB
Cuando se necesite alta velocidad, se puede pedir acceso directo al buffer virtual de video asociado con la aplicación. Al hacerlo, OS/2 devuelve un puntero a la zona de memoria en donde está situado, con lo que podremos escribir en él como si se tratase de la pantalla física. Una vez que hemos terminado, debemos enviar una orden de retrazado, que hará que OS/2 copie el LVB a la pantalla física (siempre que la aplicación se encuentre en primer plano). Esto significa que los cambios que hagamos en el LVB no son visibles hasta que nosotros queramos.
Usar esta opción implica que perdemos el aislamiento entre el hardware y nosotros: dado que el LVB no es más que una copia del buffer real de pantalla, es necesario que nuestro programa conozca la geometría y la forma de almacenamiento de los datos en ésta.
VioGetBuf
VioShowBuf
Acceso directo al buffer real de video
En el extremo opuesto se encuentran las funciones de acceso directo al video. Con ellas, OS/2 da acceso directo a la memoria de pantalla. Sin embargo, esto que en el DOS de siempre es la opción más normal y común, puede resultar catastrófico en un Sistema Operativo multitarea como OS/2; no se hundiría el suelo bajo nuestros pies, pero la pantalla podría ser alterada en un momento poco oportuno... si OS/2 no tomase las debidas precauciones.
Para que un programa pueda acceder directamente a la memoria real de video, es absolutamente necesario que se encuentre en primer plano. Esto es así porque si escribiese algo en pantalla cuando estuviese en background, machacaría la imagen de la aplicación que se encontrase en ese momento en primer plano.
Lo primero que hay que hacer es pedir la dirección física de la memoria de vídeo. OS/2 devuelve un selector (o varios) a dicha zona de memoria (ver modos de direccionamiento del 286). Estos selectores deben ser convertidos a punteros antes de poder trabajar con ellos. Pueden ser varios pues cada selector no puede apuntar a un bloque de memoria mayor de 64Ks, el cual es también, casualmente, el tamaño de cada bloque de memoria de las tarjetas de vídeo actuales. Esto ayuda a simplificar el acceso, pues en modos como 640x480x16colores no necesitaremos cambiar de bancos; OS/2 nos devuelve un selector que apunta a cada uno de ellos, con lo que solo tenemos que acceder normalmente como si fuese memoria lineal, y el Sistema Operativo conmutará de uno a otro automáticamente.
El hecho de obtener un selector no significa que dispongamos de acceso todavía a la pantalla. De hecho, si intentásemos escribir o leer algo en ese momento y la aplicación no se encontrase en primer plano, OS/2 la cerraría inmediatamente, dando un
Fallo de Protección General (el cual ya sabemos que no es tan fatal como el de Windows, pues en OS/2 solo afecta a la aplicación que lo ha provocado, dejando intacto al Sistema Operativo y al resto de los programas).
Cada vez que queramos acceder a la memoria física de video, debemos bloquear el acceso al buffer. Si el programa estaba en primer plano, OS/2 devolverá un valor afirmativo al retornar de la llamada, y bloqueará el selector de programas. Esto significa que el usuario no podrá conmutar la sesión actual a segundo plano hasta que ésta termine el acceso. Sin embargo, el resto de las aplicaciones siguen funcionando en segundo plano, sin verse afectadas por este hecho. Por supuesto, esto puede ser peligroso, y OS/2 toma algunas precauciones: si el sistema está bloqueado y el usuario hace una conmutación de tarea, si el programa no desbloquea el conmutador antes de un cierto tiempo definido por el sistema, queda congelado y se realiza la conmutación. Por eso es recomendable desbloquear cada x tiempo el selector de programas y volverlo a bloquear.
Si por el contrario el programa se encontraba en segundo plano, hay dos opciones: OS/2 puede retornar un código de error al programa, con lo que este sabrá que no tiene acceso al buffer y puede seguir trabajando en otra cosa, o bien OS/2 congelará al programa hasta que el usuario lo pase a primer plano, momento en que lo despertará indicandole que tiene acceso al buffer real.
Una vez que OS/2 ha devuelto un resultado afirmativo, el programa tiene acceso total a la memoria de video. Cuando haya terminado, tiene que proceder a desbloquear la pantalla, de modo que OS/2 pueda desbloquear el selector de programas y devolver el sistema a la normalidad.
VioGetPhysBuf
VioScrLock
VioScrUnLock
Existe una dificultad adicional a la hora de trabajar con acceso directo a la pantalla. Se trata de que OS/2, al conmutar de una tarea a otra, solo guarda el contenido de la pantalla si ésta se encontraba en modo texto (esto se cumple para OS/2 1.x. En Warp 4, sin embargo, SI conserva el contenido de la pantalla, pero no se si se cumple también para OS/2 2.x o 3.x). Si estabamos trabajando en modo gráfico, el contenido se perderá. Para evitarlo, OS/2 facilita la posibilidad de crear un thread (este concepto será explicado más adelante, cuando veamos la multitarea a fondo) que será activado cuando el programa vaya a cambiar de primer a segundo plano, y viceversa. Esto es así para permitir que un programa pueda almacenar el contenido de la pantalla en modo gráfico cuando no tiene bloqueado el acceso a la memoria de video. Es el thread
SavRedrawWait.
Para implementarlo, es necesario crear un nuevo thread en el que se ejecute la llamada
VioSavRedrawWait. Esta llamada bloqueará el thread hasta que el usuario pulse CTRL+ESC, momento en que OS/2, antes de conmutar de tarea, despertará a dicho thread indicándole que debe almacenar el contenido de la pantalla. Cuando el thread termine, debe volver a ejecutar la llamada, con lo que OS/2 sabrá que ha finalizado. El thread se quedará dormido de nuevo, y solo será despertado cuando el usuario vuelva a conmutar a primer plano el programa. Entonces OS/2 le indicará que debe repintar la pantalla.
VioSavRedrawWait
La inclusión de este sistema de acceso puede parecer innecesaria, a la vista de la potencia del acceso al LVB; la razón de haberla implementado fue que, cuando salió OS/2, no llevaba todavía el
Presentation Manager, el gestor de ventanas, sino que era un Sistema Operativo en modo texto, por lo que se incluyó este sistema para poder acceder en modo gráfico a la pantalla, dado que VIO no ofrece ninguna facilidad como el trazado de puntos o líneas. Actualmente, al disponer de un completo (y complejo) gestor de ventanas, este método puede parecer inutil, sin embargo, para juegos puede ser muy útil, pues permite acceder a pantalla completa en modos como 320x200 en 256 colores, lo que permite una alta velocidad de refresco, así como una gran facilidad de manejo. Hay que señalar que el acceso directo a la memoria de vídeo solo se puede hacer estando en una sesión de pantalla completa; no funcionará en una sesión de ventana.
El subsistema de teclado es el encargado de gestionar el acceso de los programas a este periférico. Al igual que el subsistema de vídeo, no es necesario usarlo para escribir programas sencillos de cara al interface de usuario, pues se puede acceder fácilmente a él a través del sistema de archivos. Es más, el uso del subsistema de teclado no ofrece casi ninguna ventaja en lo que a velocidad se refiere. Por tanto ¿para qué usarlo? Simplemente porque el acceso a través del sistema de archivos solo nos permite detectar códigos ASCII, pero no la pulsación de teclas de funcion, o, por ejemplo, si tenemos pulsada la tecla ALT, o CTRL, etc. Para este tipo de funciones necesitamos usar los servicios del subsistema de teclado.
FUNCIONES KBD
Acceso a nivel de cadenas de caracteres
La primera posibilidad que ofrece el subsistema de teclado es leer caracteres, lo cual se puede hacer de dos formas: por cadenas, o caracter a caracter.
La lectura por cadenas es exactamente igual que el uso de los servicios del sistema de archivos. De hecho, es el servicio que emplea la función DosRead cuando tiene que leer del teclado. Sin embargo, no necesita un indicativo de dispositivo abierto, ni participa en el redireccionamiento de E/S. Además, funciona de modo diferente según el modo de teclado en que se encuentre: ASCII, BINARIO o ECO.
Con este sistema, se leen caracteres hasta que el buffer definido esté lleno o hasta que se pulse el
caracter de retorno, que por defecto es el
retorno de carro (tecla
enter).
KbdStringIn
KbdGetStatus
KbdSetStatus
La lectura por caracteres es un acceso más a bajo nivel. En este caso podemos saber exactamente qué tecla está pulsada y cual no, y saber si además se encuentran apretadas teclas como
Ctrl,
Alt,
AltGr, etc. Además, si el informe de cambio está activo, se notificará no solo cuando se pulse una tecla, sino también cuando se suelte.
KbdCharIn
KbdPeek
Por último, tenemos una función que nos permite vaciar el buffer de teclado, de modo que todas las pulsaciones hechas hasta el momento que no han sido atendidas serán borradas.
- Subsistema de Puntero (Ratón)
El subsistema de ratón controla todo lo referente a este dispositivo.
Lo primero que hay que hacer para trabajar con el ratón es abrir el dispositivo. Esta acción crea una cola de eventos para el ratón e inicializa todos los parámetros de la sesión a un valor conocido.
MouOpen
MouClose
La cola de eventos del ratón almacena todos los sucesos ocurridos con éste dispositivo, de modo que puedan ser leídos por el programa en el momento adecuado. Un evento es, por ejemplo, mover el ratón, pulsar un botón, soltarlo... Existe la posibilidad de filtrar determinados eventos, de modo que al leer la cola, el resultado será exactamente igual que si no se hubiesen producido.
Cuando se lee la cola, se puede especificar además si la función retornará aún en el caso de que ésta esté vacía, o bien si debe esperar a que haya algún evento en ella. Además de esto, podemos conocer en cualquier momento la posición actual del ratón, así como cambiarla por otra. Estas opciones deben usarse sólo con fines de actualizar alguna variable del programa; si se pretende que sea el propio programa el que pinte el cursor, es mejor leer las coordenadas por medio de la cola de eventos.
MouReadEventQue
MouGetEventMask
MouSetEventMask
MouFlushQue
MouGetNumQueEl
MouGetPtrPos
MouSetPtrPos
El controlador de ratón puede encargarse él mismo de pintar el cursor en pantalla (solo en sesiones de texto), o bien relegar dicha acción al programa. Así mismo, puede devolver las coordenadas bien en coordenadas de pantalla, bien en
Mickeys, que son unidades naturales del ratón.
Por otro lado, es posible definir un área de la pantalla que será especifica de la aplicación, de modo que el controlador no pintará el cursor cuando éste se encuentre dentro de aquella. Por defecto, este área ocupa toda la pantalla.
MouDrawPtr
MouRemovePtr
MouGetDevStatus
MouSetDevStatus
Por último, es posible obtener información sobre las características de nuestro ratón.
MouGetNumButtons
MouGetNumMickeys