|
G A C E T A D E L I N U X
...haciendo a Linux un poco más divertido! |
|
Rompi La Barrera De La Consola
Por Stephen Bint Traducción al español por Fernando Frias
|
Cuando comence a usar Linux note que la mayoria de los editores de texto son rudimentarios, teniendo muy poco o ningun soporte para el raton, sin seleccion y sin menus o dialogos para abrir archivos. Entonces pense que podria hacer una contribucion, escribiendo un editor que tuviera todas las caracteristicas que asociamos con los editores DOS, para la consola linux. ¿Por que el mejor SO no deberia de tener editores que fueran al menos igual de buenos?
Entonces busque una libreria que me diera una interface a color en modo texto para ambas plataformas y encontre Slang y curses. Ninguna era satisfactoria. Para proveer una interface a una enorme lista de plataformas, muchas caracteristicas posibles para la console Linux no eran permitidas. Tambien, eran tan grandes que no habia perspectiva de desarrollarlas para mis propias necesidades ni de conjuntar las versiones modificadas con mis propias fuentes. Fuera de la frustracion parti a escribir las mias propias.
Me puse el objetivo de producir una interface con un rango, lo mas ancho posible, de combinaciones ctrl- y alt-, una funcion para reportar el estado e las teclas shift, ctrl y alt, reporte completo del raton (incluyendo movimiento) y acceso directo al erreglo de memoria caracter-color del estilo EGA. Esperaba producir algo pequeño y simple suficiente para que los programadores lo integraran con sus propias fuentes, entonces podrian modificarla si lo deseaban y distribuirla con confianza.
Programar el raton fue relativamente facil. Bajo DOS, Solo use int86 y la lista de interrupciones de Ralf Brown. Bajo Linux, luche por un momento y eventualmente domine el controlador gpm del raton, el cual tiene muy buenos documentos y programas demo.
Encontrando que la salida de texto en color a la pantalla Linux era mas dificil. Fui salvado por un articulo en la Gaceta de Linux llamado "Entonces te gusta el color!!!". Me impacto bastante lo que ahi dice.
A diferencia de DOS, en donde los caracteres y colores son escritos directamente a la memoria de video como pares de bytes, La pantalla Linux es refrescada usando fwrite a write a stdout! en vez de que un color sea escrito con cada caracter, la salida en color debe ser cambiada siempre que un caracter es de diferente color que el que esta antes. Cambiar el color de salida involucra escribir un string de 11 bytes a stdout.
Consecuentemente, el refrescado de la pantalla es muy lento el Linux. Hice lo que pude para que fuera mas rapido. Guarde un duplicado del buffer de pantalla el cual es actualizado cuando la pantalla es refrescada. Comparando esta con el buffer de pantalla, refresco las partes de la pantalla que han cambiado. Aun asi, el refrescado de la pantalla toma veinte veces mas en Linux que en DOS.
Es posible acceder a la memoria de video en las ultimas versiones de Linux, abriendo /dev/vcsa como un archivo. (ve la pagina man de vcs para mas detalles) hay dos razanes para no hacer esto. Una es que solo a los programas que son ejecutados por el superusuario se les permite hacer esto. La segunda es que solo el conjunto de caracteres US ASCII esta soportado. Al menos con fwrite, el conjunto de caracteres local es respetado, lo cual es importante porque Linux es algo internacional, desde su amigable pantalla de bienvenida hasta su grande y calido corazon.
Encontre como mostrar, esconder y posicionar el cursor examinando las fuentes de Slang y usando un excelente programa empacado con Slang, llamado untic. Untic lee la base de datos terminfo y la translada a una froma humano-leible. (La base de datos terminfo contiene el comando string para escribir a stdout para controlar las operaciones sobre cualquier terminal.)
Habia un pequeño inconveniente. Bajo Linux, los caracteres para dibujar cajas no son parte del conjunto de caracteres default. Los valores ASCII que producen cajas bajo DOS producen divertidas letras extrañas bajo Linux a menos que envies un string a stdout para cambiar al conjunto de caraceres alt. Cambiar a ese conjunto de caracteres permanentemente no era una opcion. Quise que la libreria fuera internacional como Linux, soportando conjuntos de caracteres international, entonces ¿Que hacer?
Decidi usar el bit alto del byte de color como bit de caja. Los programadores que desearan dibujar cajas tendrian que activar el color del bit de caja para cualquier caracter que quisieran mostrar como caracter para dibujar cajas. Esto significa que el parpadeo de texto no estaria disponible, porque el bit alto es es usado para eso, pero fui feliz. De cualquier forma nunca me ha gustado el parpadeo.
Interpretar los eventos del teclado en cualquier plataforma es un gran grito de pesadilla en zancos. Bajo DOS, los codigos de busqueda del BIOS son tan ilogicamente asignados, que bien podrian ser numeros aleatorios. Bajo Linux, la terminal tiene que ser especialmente preparada y entonces, las teclas de funcion generan strings de bytes que necesitan ser convertidos a codigos de busqueda a travez de una tabla de busqueda.
Fue casi inconcebible convertir eventos Linux a eventos DOS, o viceversa. En vez de eso decidi, producir una funcion de tecla pura, la cual reportaria un valor de tecla que no es alterado por control o alt, pero sera afectado si la tecla shift es presionada. Los programadores que desearan usar una combinacion de teclas ctrl- o alt- para una tecla caliente pdrian examinar el estatus del teclado separadamente.
Quiza esperas que un codigo de busqueda BIOS de dos bytes usaria el byte alto como ID de la tecla el cual nunca varia y que el byte bajo para un valor ASCII el cual depende de si la tecla shift, control o alt esta presionada. Desafortunadamente, debido a la necesidad de mantener compatibilidad con los viejos teclados XT, el byte alto varia tanto como el byte bajo. Lo que es peor, diferentes teclas reaccionan diferente a control y alt. Para evitar un bloque interruptor consumiendo tiempo, produje un enredo de "if" para probar las identidades fuera de los codigos de busqueda de ctrl y alt.
Entonces encontre que el pulsar shift cambia la sensibilidad del bloque numerico bajo DOS, pero no en Linux. Tuve que complicar mi purificador de teclas aun mas alla para deshacer esa estupidez, entonces el bloque numerico significa numeros, no importa que. entonces el DOS fue conquistado y enfrente el horror del teclado en Linux.
En su estado default, el teclado linux esta lejos de ser adecuado para un programa interactivo. La funcion fgetc() no termina hasta que se pulsa return, entonces regresa un string completo, por lo tanto mover el cursor con felchas no funciona. Esto lanza caracteres a la pantalla ademas ctrl-z, ctrl-q y ctrl-s generan interrupciones. Es una pesadilla.
Yo hubiera esperado poder evitar el uso de fgetc() y deslizar el tecaldo dentro del modo crudo (codigos de busqueda puros), per el controlador gpm del mouse no me ofrecio opcion. Provee una sencilla funcion para leer eventos desde el teclado y raton, y la parte del teclado usa fgetc(stdin). Hay una sola funcion para el raton, pero no pude hacerla funcionar.
Estoy contento por esto ahora, porque me he dado cuenta que cuando fgetc() recibe codigos de tecla de alto nivel los cuales parece que son los mismos en teclados extraños, donde la estructura y probablemente los codigos de busqueda serian diferentes. me resigne a transladar cadenas de bytes a codigos de busqueda como una necesidad y eso se torno mas facil que lo que hubiera sido tratar con codigos de busqueda del BIOS bajo DOS.
Encontre como preparar la terminal examinando las fuentes de Slang. Usa una funcion llamada tcsetattr() para activar banderas y valores en una estructura de control de terminal. Entonces arregle el teclado para devolver caracteres imediatamente sin echo y tratar ctrl-z, ctrl-q y ctrl-s como teclas ordinarias.
Aun no tengo la funcion kbhit() , tampoco ninguna forma para leer el estado shift (si ctrl, alt o shift son pulsados). Google publico un articulo en la gaceta de linux llamado "Domando el teclado Linux", el cual me dio el codigo fuente completo de ambas funciones.
Aun quedaba un problema. Quiza te parezca trivial pero fue todo para mi. Parecio insuperable y no pienso admitirlo, casi me arruina.
Tu sabes como en los editores DOS puedes seleccionar texto pulsando shift mientras usas las teclas de movimiento de cursor, incluyendo page up y page down? Bien bajo Linux, shift-PageUp y shift-PageDown estan reservadas para una funcion sin sentido llamada scrollback. Esto significa que las aplicaciones no reciben nada de fgetc() cuando shift-PageUp/Down son pulsadas. El nucelo envia estas teclas fuera y tu programa nunca las ve.
Pero eso no es lo peor de todo. Despues de semanas de golpearme el craneo Me di cuenta en la parte final, que si un usuario intenta seleccionar texto con shift-PageUp, la mitad de mi precioso texto en color en pantalla desaparece - scrolled back!
No hubo manera que pudiera liberar mi libreria ahora. Me senti como si hubiera leido una novela de mil paginas y no encontrar la ultima pagina. Busque y busque una y otra vez en las paginas man y archivos de informacion y explore la red sin tener exito. Entonces note que la funcion shift_state() que obtuve del articulo mecionado anteriormente, usaba una funcion llamada ioctl() para trabajar su magia.
Use "apropos ioctl" para buscar en las paginas man y encontre una llamada "console_ioctls". Ahi descubri que ioctl() es el equivalente Linux a las interrupciones DOS . La misma pagina dio un listado completo de llamadas al sistema de bajo nivel y una adevertencia de un programador del kernel, nuca usar estas llamadas al sistema porque son no garantizadas y son objeto de cambios en futuras versiones del kernel.
Pero todos sabemos que podemos ignorar a los programadores del kernel cuando dicen cosas como esa. Ellos solo estan negando responsabilidad, como cuando Scotty le dice al Captain Kirk que va a tomar dos veces siempre y cuando lo haga.
En el listado encontre algo para cambiar las funciones asociadas con teclas - incluyendo PageUp and PageDown. Esto involucro llenar una estructura con tres enteros para indicar que tabla, que tecla y que comando asignar . El problema fue que, no hubo documentos que me indicaran que debian de ser esos numeros, para deshabilitar scrollback para shift-PageUp.
Busquedas adicionales descubrieron el paquete kbd, el cual contiene extensos documentos y un monton de utilidades para cambiar el mapeo de teclas. Puedes vaciar el mapeo actual hacia stdout corriendo dumpkeys. Aqui esta un extracto de mi salida dumpkeys. Nota que solo me da uno de los tres numeros que necesito - el keycode.
keycode 103 = Up alt keycode 103 = KeyboardSignal keycode 104 = Prior shift keycode 104 = Scroll_Backward keycode 105 = Left alt keycode 105 = Decr_Console keycode 106 = Right alt keycode 106 = Incr_Console keycode 107 = Select keycode 108 = Down keycode 109 = Next shift keycode 109 = Scroll_Forward keycode 110 = Insert
Si redireccionas la salida a un archivo de texto, puedes editarlo y pasarlo a loadkeys para alterar el mapeo. Experimentos revelaron que puedes borrar la mayor parte del archivo - solo dejando las teclas que quieres cambiar. Entonces lo reduci a dos lineas:
shift keycode 104 = Scroll_Backward shift keycode 109 = Scroll_Forward
y cambiando las funciones actuales por aquellas sin pulsar la tecla shift:
shift keycode 104 = Prior shift keycode 109 = Next
Llame al archivo kmap y corri "loadkeys kmap". Entonces intente mi prueba y encontre que que el scrollback habia sido deshabilitado - exactamente el resultado que estaba buscando. Supe que fue posible. Un vistazo al codigo fuente para loadkeys revelo que utilizo la ioctl que yo habia encontrado, para cambiar las teclas de funcion, pero aun no sabia que numeros usar.
No tuve eleccion salvo usar astutamente. Encontre que los loadkeys tienen una opcion -m, para producir un archivo fuente, el cual contiene tablas de 256 valores. Corri "loadkeys -m kmap" y encontre que produjo una tabla con 254 valores null y dos no-null. Contando elementos encontre que los elementos no-null estaban numerados como 104 y 109 - los codigos de tecla en mi archivo kmap . Los valores en la tabla tuvieron que ser valores de los comandos "Prior" y "Next".
Tambien vi que esta tabla tenia un numero. Intente cambiar "shift" a "control" en una de las lineas del archivo kmap y obtuve dos tablas, una para shift y una para control. En ambos casos la tabla shift era la tabla 1. Junto con los valores actuales en la tabla, tuve mis tres numeros.
Para deshabilitar el scrollback y scroll forward y hacer de shift-PageUp/Down teclas ordinarias, debes guardar los valores existentes, entonces cambiarlos e instalar una rutina de salida para restaurarlos a la funcion normal de antes.
Si quieres deshabilitar cualquier tecla, como las teclas para cambiar de consola por ejemplo, necesitaras perder el tiempo como lo hice con "loadkeys -m" para encontrar los numeros que estas buscando.
Esta funcion cambia el efecto de una tecal y guarda la anterior en un entero que pasas por referencia (escrito para gcc):
(version texto de todos los listados)
#include <sys/ioctl.h>
#include <linux/kd.h>
#include <linux/keyboard.h>
#include <stdio.h>
int set_kb_entry( unsigned short table, unsigned short keycode,
unsigned short value, unsigned short *oldvalue ) {
struct kbentry ke;
ke.kb_table = table;
ke.kb_index = keycode;
/* Get old value, return error if table or keycode are duff */
if( ioctl( fileno(stdin), KDGKBENT, &ke ) )
return -1;
/* Unless oldvalue ptr is NULL, save old value to restore later */
if( oldvalue ) *oldvalue = ke.kb_value;
/* The new action for this key */
ke.kb_value = value;
/* Do the business, return error if value is duff */
if( ioctl( fileno(stdin), KDSKBENT, &ke ) )
return -1;
return 0;
}
Para usar la funcionde arriba y deshabilitar scrollback y restaurlarlo en la salida:
#include <stdlib.h>
/* Old key action values will be stored in these */
unsigned short scroll_forward = 0;
unsigned short scroll_backward = 0;
/* The magic numbers gleaned from dumpkeys and loadkeys -m */
#define SHIFT_TABLE 1
#define PAGE_UP_KEYCODE 104
#define PAGE_DOWN_KEYCODE 109
#define PAGE_UP_ACTION 0x0118 /* Prior */
#define PAGE_DOWN_ACTION 0x0119 /* Next */
/* Restore default funcs for shift-PageUp and shift-PageDown */
static void restore_scrollback() {
if( scroll_backward )
set_kb_entry( SHIFT_TABLE, PAGE_UP_KEYCODE,
scroll_backward, 0 );
if( scroll_forward )
set_kb_entry( SHIFT_TABLE, PAGE_DOWN_KEYCODE,
scroll_forward, 0 );
}
/* Liberate shift-PageUp and shift-PageDown for normal use */
int disable_scrollback() {
if( set_kb_entry( SHIFT_TABLE, PAGE_UP_KEYCODE,
PAGE_UP_ACTION, &scroll_backward ) )
return -1;
if( set_kb_entry( SHIFT_TABLE, PAGE_DOWN_KEYCODE,
PAGE_DOWN_ACTION, &scroll_forward ) )
return -1;
atexit( restore_scrollback );
return 0;
}
Asi emergi desde el obscuro inframundo de la consola Linux, premio en mano, triunfante. Habia hecho posible para los programadores escribir aplicaciones de consola que se comportaban exactamente de la misma forma bajo DOS y Linux y (creo) asegure mi lugar como leyenda.
¿Y sabes que? nunca escribi ese editor de textos. no pude porque no tengo casa y tuve suerte de tener acceso a una computadora lo suficiente para hacer esta pequeña cosa. Quizas es donde tu entras.
Linux es un territorio virgen, proximo a ser colonizado por gente de India y Africa. Ellos no pueden permitirse computadoras impresionanates que puedan correr X, asi que necesitan aplicaciones de consola. Ahora aun para aquellos de ustedes que no tienen Linux instalado puede ayudarlos.
Linux necesita pioneros para conquistar la infraestructura antes que la primer gran ola de pobladores pueda mudarse. Esos pobladores necesitaran dialogos configurados para aplicaciones comunes como Apache y para filtros comunes como grep. Necesitaran un buen editor de textos, con un menu de click derecho y cut-copy-paste .
Los programadores que tengan pensado hacer estas herramientas necesitaran una libreria objeto y especialmente, un dialogo para abrir/cerrar archivos. Ellos se beneficiarian de una bien escrita clase de arreglo de strings con funciones cut-copy, suministrada por separado para ser usada en diversos y competitivos editores de texto.
El editor perfecto no tendria muchas caracteristicas, pero tendria una sencilla facilidad para agregar funciones a sus menus. Estaria listo entonces para que cualquier tonto pudiera escribir una funcion C++ que tome un puntero al editor como argumento y agregar esa funcion al menu del editor, solo agregando una simple linea a main(). Los programadores podrian intercambiar funciones C++ del editor con cualquier otra y estariamos con rumbo a el ultimo editor .
¿Seras un pionero? si nadie te molesta, me temo que Linux podria caer y todos nosotros podriamos terminar con el indefenso juguete de la figura maligna de Gates. Asi que estoy esperando que tu levantes mi caido estandar. Tu puedes ser nuestra ultima, nuestra ultima esperanza. Buena suerte.
Puede estar contigo el codigo fuente.
Slang, por John E. Davis. Slang es facil de arrebatar porque esta bien escrita. Aprendi como inicializar el teclado y obtener la mayoria de los string de command para la pantalla desde las fuentes de Slang. Obtuve otro string de comando usando el programa untic que viene con el. Pero la mejor cosa acerca de Slang es que permite que Midnight Commander corra en una ventana telnet. Cualquiera que haya tenido que corregir un web server remotamente sabra, que es una cosa bella.
Asi que te gusta el color !!! por Pradeep Padala (LG #65). Este articulo me inicio en la pantalla de la consola Linux.
Domando el teclado Linux por Petar Marinov (LG #76). Mis funciones shift_status() y key_awaits() son versiones modificadas de shift_state() y kbhit() cedidas por este articulo.
Ralf Brown, Patron de los programadores DOS
Stephen es un Inglés sin casa, quien vive en una tienda de campaña en los bosques. Come fuera
y fuma colillas de cigarro el encuentra en el camino. Aunque alguna vez trabajo
por corto tiempo como programador C, el prefiere describirse a si mismo como "amateur
entusiasta".