¿Cómo agregar un applet de estado modificador de teclado al panel de Unity?

18

Soy un usuario de KDE que piensa mudarse a Unity. Debido a la discapacidad manual, uso teclas fijas y en KDE tengo un applet en el panel del sistema que muestra qué teclas modificadoras están activas. Recuerdo que Gnome también tenía esta característica, al igual que Windows y OS X.

¿Cómo se agrega el applet de estado del modificador de teclado al panel en Unity?

Aclaración: ya he habilitado las teclas adhesivas. Estoy preguntando cómo agregar un applet que indica el estado de las teclas modificadoras . Este indicador mostrará cuándo se presiona la tecla Mayús, cuando se presiona la tecla Alt, cuando se presiona la tecla Tux y cuando se presiona la tecla Ctrl. Este applet existe en todos los principales entornos de escritorio (KDE, Windows, Mac OSX y Gnome). Es necesario para la accesibilidad del escritorio.

Aquí hay una imagen del applet de estado del modificador de teclado, junto al applet indicador de distribución del teclado. Los modificadores representados son, de izquierda a derecha, Shift, Ctrl, Alt, I-dont-know-this-one, Tux/Win, NumLock, y CapsLock. Se puede ver que la tecla Bloq Num está activa.

ingrese la descripción de la imagen aquí

dotancohen
fuente
Errr ... Parece que hay una gran brecha cuando se trata de esto ... Sin embargo, hay algo que emitir un pitido cuando se presiona una tecla modificadora.
Wilf
@wilf Si no me equivoco, hay un ícono de Accesibilidad en Unity (igual que Gnome 3) pero no un ícono "extra" para informar al usuario sobre el estado.
Braiam el
44
@Takkat: Gracias por la sugerencia. indicator-keylocksólo muestra el estado de las teclas que tradicionalmente tienen indicadores de estado en el teclado en sí: CapsLock, ScrollLock, NumLock. Necesito un indicador que muestra el estado de las teclas modificadoras estándar: Shift, Ctrl, Tux, Alt. Todos los escritorios principales (KDE, Windows, Mac OSX) tienen este applet indicador disponible.
dotancohen
1
Creo que el nombre del paquete de la herramienta KDE a la que se refiere también lo es, plasma-widget-kbstatey una búsqueda rápida en el centro de software no tiene en cuenta ningún resultado equivalente
Daniel W.
2
@ shengy: estoy usando el plasmoide KB State. Si está en Kubuntu, instálelo con sudo apt-get install plasma-widget-kbstate.
dotancohen

Respuestas:

7

Este es un tema pendiente en Unity:

El código siguiente se ha actualizado, ahora puede usar iconos para mostrar el estado. Pero a veces puede ser lento ya que tengo que actualizar el archivo de icono en el disco duro y luego volver a cargarlo. (Ver notas sobre este problema / limitación en libappindicator)

Un lanzamiento bien empaquetado se puso a disposición en webupd8 ppa (Gracias a Alin Andrei / Andrew /)

sudo add-apt-repository ppa:nilarimogard/webupd8
sudo apt-get update
sudo apt-get install indicator-xkbmod

Referencia: Modificadores de teclado Indicador de estado para Ubuntu: Indicador Xkbmod


Respuesta original

No se atiende a esto como una respuesta canónica a la pregunta. Se podría contar como una solución alternativa. Saltar a alguien escribe una solución sofisticada para ello.

Este es un indicador de modificadores de teclado prototipo simple para Unity.

Imagen a partir de la izquierda: icono, Mayúsculas, mayúsculas bloqueadas, Ctrl, Alt, Super, AltGr bloqueado (círculo pequeño para indicar el estado bloqueado)

captura de pantalla del prototipo unity-xkbmod

Archivo fuente unity-xkbmod.c:

/*
 * unity-xkbmod.c
 *
 * Copyright 2014 Sneetsher <sneetsher@localhost>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 *
 *
 */

#include <string.h>

#include <X11/XKBlib.h>

#include <glib/gprintf.h>
#include <gtk/gtk.h>
#include <libappindicator/app-indicator.h>

//callback data structure
typedef struct _AppData {
  Display *_display;
  int *_deviceId;
  AppIndicator *indicator;
} AppData;

//menu ui
static GtkActionEntry entries[] = {
  { "Quit",     "application-exit", "_Quit", "<control>Q",
    "Exit the application", G_CALLBACK (gtk_main_quit) },
};

static guint n_entries = G_N_ELEMENTS (entries);

static const gchar *ui_info =
"<ui>"
"  <popup name='IndicatorPopup'>"
"    <menuitem action='Quit' />"
"  </popup>"
"</ui>";

//callback function, get xkb state, update indicator label (icon have limitation)
static gboolean update_xkb_state (gpointer data)
{
  //get xkb state
  XkbStateRec xkbState;
  XkbGetState(((AppData*) data)->_display, *(((AppData*) data)->_deviceId), &xkbState);

  //construct label
  GString *label = g_string_new("");

  register int i;
  unsigned bit;

  //loop taken from xkbwatch source
  for (i = XkbNumModifiers - 1, bit = 0x80; i >= 0; i--, bit >>= 1)
  {
    //printf("base%d %s  ", i, (xkbState.base_mods & bit) ? "on " : "off");
    //printf("latched%d %s  ", i, (xkbState.latched_mods & bit) ? "on " : "off");
    //printf("locked%d %s  ", i, (xkbState.locked_mods & bit) ? "on " : "off");
    //printf("effective%d %s  ", i, (xkbState.mods & bit) ? "on " : "off");
    //printf("compat%d %s\n", i, (xkbState.compat_state & bit) ? "on " : "off");

    //todo: change constant with xkb modifier constant (defined in the headers)
    // show effective modifier stat
    switch (i)
    {
      case 7:
        g_string_prepend (label,  ((xkbState.mods & bit) ? "⎇" : ""));
        break;
      case 6:
        g_string_prepend (label,  ((xkbState.mods & bit) ? "⌘" : ""));
        break;
      case 5:
        g_string_prepend (label,  ((xkbState.mods & bit) ? "5" : ""));
        break;
      case 4:
        g_string_prepend (label,  ((xkbState.mods & bit) ? "①" : ""));
        break;
      case 3:
        g_string_prepend (label,  ((xkbState.mods & bit) ? "⌥" : ""));
        break;
      case 2:
        g_string_prepend (label,  ((xkbState.mods & bit) ? "⋀" : ""));
        break;
      case 1:
        g_string_prepend (label,  ((xkbState.mods & bit) ? "⇬" : ""));
        break;
      case 0:
        g_string_prepend (label,  ((xkbState.mods & bit) ? "⇧" : ""));
        break;
      default:
        break;
    };

    // show if modifier is locked
    g_string_prepend (label,  ((xkbState.locked_mods & bit) ? " ˳" : " "));
  }

  //g_string_prepend (label,  "");
  app_indicator_set_label (((AppData*) data)->indicator, label->str, NULL);

  //g_free(label);
  return TRUE;
}


int main (int argc, char **argv)
{
  AppData appdata;
  Display *_display;
  int _deviceId;

  char* displayName = strdup("");
  int eventCode;
  int errorReturn;
  int major = XkbMajorVersion;
  int minor = XkbMinorVersion;;
  int reasonReturn;


  AppIndicator *indicator;
  GtkWidget *indicator_menu;
  GtkUIManager *uim;
  GtkActionGroup *action_group;
  GError *error = NULL;

  gtk_init (&argc, &argv);


  XkbIgnoreExtension(False);

  g_printf("Xkb client lib ver: %d.%d\n" , major , minor );
  _display = XkbOpenDisplay(displayName, &eventCode, &errorReturn,
                            &major, &minor, &reasonReturn);
  g_printf("Xkb server lib ver: %d.%d\n" , major , minor );

  if (reasonReturn != XkbOD_Success)
  {
    g_printf("Unable to open display!\n");
    return 1;
  }

  XkbDescRec* kbdDescPtr = XkbAllocKeyboard();
  if (kbdDescPtr == NULL)
  {
    g_printf ("Failed to get keyboard description.\n");
    return 2;
  }
  kbdDescPtr->dpy = _display;
  _deviceId = kbdDescPtr->device_spec;

  /*
  //no need for event listener, used gtk_timeout timer
  XkbSelectEventDetails(_display, XkbUseCoreKbd, XkbStateNotify,
                     XkbAllStateComponentsMask, XkbGroupStateMask);
  */


  action_group = gtk_action_group_new ("AppActions");
  gtk_action_group_add_actions (action_group, entries, n_entries, NULL);

  indicator = app_indicator_new_with_path (
                                        "Simple XKB Modifier Indicator",
                                        "icon",
                                        APP_INDICATOR_CATEGORY_HARDWARE,
                                        g_get_current_dir());

  uim = gtk_ui_manager_new ();
  gtk_ui_manager_insert_action_group (uim, action_group, 0);
  if (!gtk_ui_manager_add_ui_from_string (uim, ui_info, -1, &error))
  {
    g_printf ("Failed to build menus: %s\n", error->message);
    g_error_free (error);
    error = NULL;
    return 3;
  }

  indicator_menu = gtk_ui_manager_get_widget (uim, "/ui/IndicatorPopup");
  app_indicator_set_menu (indicator, GTK_MENU (indicator_menu));
  app_indicator_set_status (indicator, APP_INDICATOR_STATUS_ACTIVE);

  //app_indicator_set_label (indicator, " ⇧ ⋀ ⌥ ⎇  ⌘ ", NULL);
  //symbols: shift U21E7 ctrl U22C0 alt/altgr U2325 U2387  cmd U2318
  //from font: DejaVu Sans

  appdata._display = _display;
  appdata._deviceId = &_deviceId;
  appdata.indicator = indicator;
  gtk_timeout_add (120, (GtkFunction) update_xkb_state, &appdata);
  //nice for realtime tasks, to replace gtk_timeout
  //gtk_idle_add ((GtkFunction) idle_func, &appdata);

  gtk_main ();

  XCloseDisplay (_display);
  return 0;
}
  1. Instalación de encabezados / libs necesarios: (No estoy seguro si me falta alguno)

    sudo apt-get install libx11-dev libappindicator-dev libgtk2.0-dev
    
  2. Compilación:

    gcc -Wall unity-xkbmod.c -o unity-xkbmod `pkg-config --cflags --libs appindicator-0.1` -lX11
    
  3. Correr:

    ./unity-xkbmod
    

Nota:

  • libappindicatorLos indicadores utilizados para Unity carecen de una característica importante que facilita la conexión de otros indicadores de escritorios Ver Bug # 812067 API necesaria: compatibilidad con la configuración del icono pixbuf

    Sin esta característica, digamos que necesitamos (Shift, Ctrl, Alt, AltGr, Super) con teclas adhesivas activas; Tenemos 3 estados principales para cada uno (Off, On / Latched, Locked). Entonces se deben generar 3 ^ 5 iconos combinados. (Donde el caso normal solo 3x5 iconos individuales)

    Es por eso que usé la etiqueta indicadora con símbolos de la fuente DejaVu Sans .

  • Para poner un icono, colóquelo en la misma carpeta y asígnele un nombre icon.*. Formatos aceptados: png, svg, ico, xpm ...

    Si no te gusta ningún ícono, solo crea una imagen de 1x1 px.

Referencias

user.dz
fuente
¡Bien gracias! Voy a intentarlo y te responderé. ¡Buen trabajo, Sneetsher!
dotancohen
Que sneetsher!
dotancohen
Sí, gracias @dotancohen. Entonces, al menos puede usar Unity, ¿puede ser feo sin iconos de posición fijos?
user.dz
1
No me importa feo, ¡deberías ver una foto mía! He mencionado este problema en el bugtracker de Ubuntu .
dotancohen
1
Sneetsher, quería agradecerte nuevamente. Ahora me mudé a Unity y la mudanza hubiera sido imposible sin esta excelente aplicación. También aprendí bastante del código. ¡Gracias!
dotancohen
2

Otra solución que no es perfecta, pero a algunos les puede resultar útil, ya que es posible tener una funcionalidad completa como en KDE, como activar un mod con un clic.

  1. instalar kbstateapplet

    sudo apt-get install plasma-widget-kbstate kde-workspace-bin
    
  2. Ejecutarlo en plasma-windowedjugador

    • Ventana regular

      plasma-windowed kbstate
      

      captura de pantalla de plasma-widget-kbstate en Xubuntu

    • Ventana sin bordes

      plasma-windowed --noborder kbstate
      

      captura de pantalla de plasma-widget-kbstate sin bordes en Unity

No tuve mucho tiempo para jugar, pero wmctrlpuedo ayudar a posicionar, cambiar el tamaño y llegar a la cima en el lanzamiento.

Referencia: qué comando lanzar un plasmoide kde y el menú kickstart

user.dz
fuente
1

Hice una búsqueda del monitor de teclas adhesivas de Ubuntu y encontré algo que puede ser útil aquí: http://code.google.com/p/key-mon/

captura de pantalla del caso de exhibición

Intenta correr

key-mon --sticky para soporte de teclas adhesivas.

Referencia: http://code.google.com/p/key-mon/

Tenga en cuenta que la versión disponible a través del centro de software es 1.6-0ubuntu1. Lanzado en junio de 2011, que no admite el interruptor --sticky. Si el indicador se ve exactamente como el anterior, tiene la versión anterior. Pruebe la última versión en http://code.google.com/p/key-mon/ al momento de escribir esto, es keymon_1.17-1_all.deb 229 KB liberado 3 de enero de 2014. Soporte para - interruptor adhesivo probado y confirmado.

Elder Geek
fuente
1
Un buen hallazgo, sin embargo, key-monmuestra qué botón se presionó y no el estado de las teclas modificadoras . La distinción es que la key-monpantalla vuelve al estado no presionado 1 segundo después de presionar el botón . Un applet de estado modificador de teclado devolvería la pantalla al estado no comprimido cuando se produjera la siguiente pulsación de tecla y, por lo tanto, deshabilitaría el estado 'presionado' .
dotancohen
respuesta reeditada.
Élder Geek
Perdón por la confusion. He editado la respuesta (nuevamente) para proporcionar exactamente lo que necesita.
Élder Geek
1
Gracias, élder Geek. La --stickyopción parece adivinar el estado de las teclas modificadoras observando el estado de otras teclas, en lugar de consultar la interfaz adecuada como lo hacen los applets de estado modificadores de teclado adecuados. Esto se puede ver presionando una tecla modificadora dos veces: la primera vez habilita el indicador en el applet, pero la segunda vez no lo suelta. Por lo tanto, se informa erróneamente que el estado está activo cuando no lo está. Este error relacionado soluciona el problema parcialmente, completaré los detalles allí y en errores adicionales. Gracias.
dotancohen
1
@dotancohen Probé en base a su afirmación de que "Un applet de estado modificador de teclado devolvería la pantalla al estado no comprimido cuando se produjera la siguiente pulsación de tecla y, por lo tanto, deshabilitaría el estado 'presionado'". y nunca me di cuenta de que alguien presionaría la tecla modificadora dos veces seguidas a propósito. Mis disculpas por la supervisión.
Élder Geek