Nota del autor

Si la entrada que estás leyendo carece de imágenes, no se ve el vídeo que teóricamente lleva incrustado o el código fuente mostrado aparece sin formato, podéis conocer los motivos aquí. Poco a poco iré restableciendo la normalidad en el blog.
Este blog es un archivo de los artículos situados previamente en Lobosoft.es y ha dejado de ser actualizado. Las nuevas entradas pueden encontrarse en www.lobosoft.es. Un saludo,
Lobosoft.

sábado, 31 de enero de 2009

KeyLed


Debido a un accidente navideño con el teclado del ordenador, que incluyó el agravante de la sidra ecológica, tenemos desde hace poco uno nuevo, inalámbrico, que con estas ideas brillantes para abaratar costes, resulta que no tiene LEDs indicadores del estado de las teclas de bloqueo de mayúsculas, numérico y de desplazamiento. A resultas de esto, me ha picado el gusanillo de la programación rápida, y he creado una aplicacioncita en .NET que se encarga de controlar el estado de esas teclas e informa al usuario mediante un icono de notificación en la barra de sistema.


La verdad es que es una aplicación bastante simple, pero ya que hacía tiempo que no subía nada de programación al blog, me ha parecido interesante dejarla aquí por si interesa a alguien y, de paso para recabar la opinión de los incondicionales ;) . Su nombre es KeyLed.


También incluyo la parte relevante del código, que no es demasiado extenso: Se trata de un WinForm que muestra el estado de las teclas en varios checkboxes, y que al ser minimizada queda en el systray. En todo momento, muestra un bocadillo con el estado de las teclas de bloqueo, mediante el uso de un temporizador que va comprobándolo cada cierto tiempo (500 milisegundos). He probado utilizando un delegado para el evento Idle de la aplicación, pero no se refresca tan a menudo como debiera, de ahí el uso final del temporizador.



[Csharp]
{
public partial class KeyLed : Form
{
const int Interval = 500;

public KeyLed()
{
InitializeComponent();

KeyLedTimer.Interval = Interval;
KeyLedTimer.Enabled = true;
}

[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
public static extern short GetKeyState(int keyCode);

private void KeyNotifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
{
//Hacemos visible el formulario
this.Show();
this.WindowState = FormWindowState.Normal;
//Ocultamos el icono de la bandeja de sistema
KeyNotifyIcon.Visible = false;
}

private void KeyLed_Resize(object sender, EventArgs e)
{
//Si el estado actual de la ventana es "minimizado"...
if (this.WindowState == FormWindowState.Minimized)
{
//Ocultamos el formulario
this.Hide();
//this.Visible = false;
//Hacemos visible el icono de la bandeja del sistema
KeyNotifyIcon.Visible = true;
}
}

private void KeyLedTimer_Tick(object sender, EventArgs e)
{
this.CapsLockCheckBox.Checked = (((ushort)GetKeyState(0x14)) & 0xffff) != 0;
this.NumLockCheckBox.Checked = (((ushort)GetKeyState(0x90)) & 0xffff) != 0;
this.ScrollLockCheckBox.Checked = (((ushort)GetKeyState(0x91)) & 0xffff) != 0;

KeyNotifyIcon.ShowBalloonTip(Interval, "", _numLock + _capsLock + _scrollLock, ToolTipIcon.Info);
}
}
[/CSharp]

Se me ocurren diversas mejoras, por ejemplo, que muestre la información de los leds cambiando el icono asociado al objeto NotifyIcon, de hecho funciona sin problema. Pero crear ocho iconos para esto me parece un pasote. Como con System.Drawing no he tenido que pelearme demasiado, a ver si existe una opción más eficiente que la que os presento. A partir del icono inicial, es posible usar el método ToBitmap() de la clase Icon para obtener un BMP en memoria sobre el que trabajar (por ejemplo, cambiando el color de un determinado pixel con SetPixel. Sin embargo, me parece poco adecuado tratar dinámicamente el icono, porque posiblemente sea mayor el tiempo de volver a dibujar el estado de los leds que cargar un icono distinto. ¿Alguna opinión al respecto? ¿Monto ambos sistemas y le hacemos pasar unos pocos benchmarks? ¿Merece la pena, realmente, todo esto? Jajaja.


Un saludo.



Actualización:
Acabo de darme cuenta, al encender el altavoz, del molesto efecto de "pop, pop" en el refresco del estado, al volver a pintar el bocadillo. Así las cosas, me da que no hay más opción que diseñarme el icono adecuado y actualizarlo dinámicamente. Así las cosas, vuelvo a la pregunta que planteaba al final de la entrada: ¿lo "repinto" en memoria, o cargo uno de una colección de iconos previamente almacenados?

3 comentarios:

  1. Yo tengo un teclado de logitech y le pasa lo mismo. No tiene LEDs para el estado del teclado. Esta gente, en vez de darte un systray con el estado tiene un Gadget Sidebar que te muestra esos LEDs.

    http://www.inspectmygadget.com/2007/11/05/sidebar-gadgets-logitech-typing-tools/

    ResponderEliminar
  2. Muy buena y útil, valga la redundancia, utilidad ;-).

    ¡Y claro que merece la pena! Sin duda alguna son este tipo de utilidades "caseras" las que más satisfacciones dan (al menos a mi) a los informáticos, a las que más cariño se les pillan; más que nada, porque las hemos programado nosotros para resolver algún "problemilla" que nos haya surgido, lo cual siempre es reconfortante. Eso es lo que hace grande al increible mundo de la programación ;-).

    Respecto a los iconos almacenados (me refiero a los incrustrados como recursos .resx), yo los suelo utilizar bastante para botones de tipo toolbar, porque una vez se realiza la carga inicial, luego el cambio de iconos es inmediato; así todo, sin saber muy bien por qué, he de admitir que no soy muy amigo de ellos..., así que...¡tu mismo con tu mecanismo!

    Gracias por estas eficientes y sabias líneas de código.

    SaludoX.

    ResponderEliminar
  3. @Oscar, la verdad es que el tema del gadget no es tan cómodo como una aplicación que quede en el systray, aunque vista la captura que incluye el enlace que incluyes, lo cierto es que queda mucho más vistoso así, jejeje. Me lo apunto para futuras actualizaciones.

    @Lonifasiko, ciertamente estas pequeñas utilidades son "la salsa" en muchas ocasiones que da alegría a nuestra vida de desarrolladores. ¡Cuántas pequeñas satisfacciones nos habrán dado! Aunque no nos saquen de pobres, la satisfacción personal suele ser mayor que cualquier otro aliciente. Algo así ocurre con los blogs, ¿verdad? ;)

    Gracias por la indicación sobre los archivos incrustrados. Me temo que el recurso .resx no es más que una serialización del objeto (en este caso, el .ICO), por lo que vendrá a ser más o menos igual que cargarlo desde el archivo en cuanto a eficiencia. De todas formas, siendo tan pequeños no creo que vaya a notarse mucho la diferencia, pero puestos a hacerlo de algún modo, quería saber si os habíais topado con situaciones similares y si habíais visto qué era más eficiente :)

    Un cordial saludo, y mucho ánimo con esos dominios .eus ;)

    ResponderEliminar