Como adicionar um applet de estado do modificador de teclado ao painel do Unity?

18

Eu sou um usuário do KDE pensando em mudar para o Unity. Devido a deficiências manuais, eu uso teclas adesivas e no KDE eu tenho um applet no painel do sistema que mostra quais teclas modificadoras são ativo. Lembro que o Gnome também tinha esse recurso, assim como o Windows e o OS X.

Como um anúncio do estado do modificador de teclado é aplicado ao painel no Unity?

Esclarecimento: já ativei as teclas adesivas. Eu estou perguntando como adicionar um applet que indica o estado das teclas modificadoras . Este indicador mostraria quando a tecla Shift é pressionada, quando a tecla Alt é pressionada, quando a tecla Tux é pressionada e quando a tecla Ctrl é pressionada. Este applet existe em todos os principais ambientes de área de trabalho (KDE, Windows, Mac OSX e Gnome). É necessário para acessibilidade da área de trabalho.

Aqui está uma imagem do miniaplicativo de estado do modificador de teclado, ao lado do miniaplicativo do indicador de layout do teclado. Os modificadores representados são, da esquerda para a direita, Shift , Ctrl , Alt , I-dont-know-this-one , Tux/Win , NumLock e CapsLock . Pode ser visto que a tecla NumLock está ativa.

    
por dotancohen 08.01.2014 / 17:46

3 respostas

6

Esta é uma questão pendente na Unity:

O código abaixo foi atualizado, agora ele pode usar ícones para mostrar o estado. Mas pode ficar lento em algum momento, pois tenho que atualizar o arquivo de ícone no disco rígido e recarregá-lo novamente. (Veja notas sobre este assunto / limitação em libappindicator )

Uma versão bem embalada foi disponibilizada no webupd8 ppa (Obrigado ao Alin Andrei / Andrew /)

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

Referência: Indicador de estado de modificadores de teclado para o Ubuntu: Indicador Xkbmod

Resposta original:

Isso não é visto como uma resposta canônica para a pergunta. Poderia ser contado como um trabalho ao redor. Pulando alguém escreve solução sofisticada para isso.

Este é um indicador simples de modificadores de teclado para o Unity.

Imagem a partir da esquerda: ícone, Shift, Caps bloqueados, Ctrl, Alt, Super, AltGr. bloqueado (Círculo pequeno para indicar estado bloqueado)

Arquivo de origem 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. Instalando os cabeçalhos / libs necessários: (Não tenho certeza se sinto falta de algum)

    sudo apt-get install libx11-dev libappindicator-dev libgtk2.0-dev
    
  2. Compilando:

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

    ./unity-xkbmod
    

Nota:

  • libappindicator usado para os indicadores Unity carecem de um recurso importante que torna fácil acessar outros indicadores de desktops. See Bug # 812067 API necessária: suporte a configurações de ícones do pixbuf

    Sem esse recurso, digamos que precisamos (Shift, Ctrl, Alt, AltGr, Super) com as teclas fixas ativas; temos 3 estados principais para cada um (Off, On / Latched, Locked). Portanto, ícones combinados de 3 ^ 5 devem ser gerados. (Onde caso normal apenas 3x5 ícones individuais)

    É por isso que usei o rótulo do indicador com símbolos da fonte DejaVu Sans .

  • Para colocar um ícone, coloque-o na mesma pasta e nomeie-o como icon.* . Formatos aceitos: png, svg, ico, xpm ...

    Se você não gosta de nenhum ícone, basta criar uma imagem de 1x1 px.

Referências:

por user.dz 31.03.2014 / 00:48
2

Outra solução que não é perfeita, mas alguns podem achar útil, já que é possível ter funcionalidade completa como no KDE, como ativar um mod com um clique.

  1. instale o kbstate applet

    sudo apt-get install plasma-widget-kbstate kde-workspace-bin
    
  2. Execute em plasma-windowed player

    • Janela regular

      plasma-windowed kbstate
      

    • Janela sem bordas

      plasma-windowed --noborder kbstate
      

Eu não tive muito tempo para jogar, mas wmctrl pode ajudar a posicionar, redimensionar e chegar ao topo no lançamento.

Referência: Que comando para iniciar um plasmoid do kde e o menu do kickstart

    
por user.dz 15.02.2015 / 01:18
1

Eu pesquisei o monitor de teclas adesivas do Ubuntu e encontrei algo que pode ser útil aqui: link

Tente executar

key-mon --sticky para suporte a teclas adesivas.

Referência: link

Note que a versão disponível através do centro de software é 1.6-0ubuntu1. Lançado em junho de 2011, que não suporta o switch --sticky. Se o indicador se parece exatamente com o acima, você tem a versão mais antiga Experimente a versão mais recente no link no momento da redação deste artigo é keymon_1.17-1_all.deb 229 KB Lançado em 3 de janeiro de 2014. Suporte para --sticky switch testado e confirmado.

    
por Elder Geek 11.03.2014 / 16:05