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

18

Eu sou um usuário do KDE pensando em mudar para o Unity. Devido à incapacidade manual, uso teclas de aderência e, no KDE, tenho um applet no painel do sistema que mostra quais teclas modificadoras estão ativas. Lembro que o Gnome também tinha esse recurso, assim como o Windows e o OS X.

Como um anúncio, o modificador de teclado, indica o applet para o painel no Unity?

Esclarecimento: Eu já habilitei teclas de aderência. Estou perguntando como adicionar um applet que indica o estado das teclas modificadoras . Este indicador seria exibido quando a tecla Shift estiver pressionada, quando a tecla Alt estiver pressionada, quando a tecla Tux estiver pressionada e quando a tecla Ctrl estiver pressionada. Este applet existe em todos os principais ambientes de área de trabalho (KDE, Windows, Mac OSX e Gnome). É necessário para a acessibilidade da área de trabalho.

Aqui está uma imagem do applet de estado do modificador de teclado, próximo ao applet de 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.

insira a descrição da imagem aqui

dotancohen
fonte
Errr ... Parece haver uma grande lacuna quando se trata disso ... Há algo a ser emitido quando uma tecla modificadora é pressionada.
Wilf
@ wilf Se não me engano, há um ícone de acessibilidade no Unity (igual ao Gnome 3), mas não um ícone "extra" para informar o usuário sobre o status.
Braiam
4
@ Takkat: Obrigado pela sugestão. indicator-keylocksó exibe o estado dessas teclas que tradicionalmente têm indicadores de estado no próprio teclado: CapsLock, ScrollLock, NumLock. Eu preciso de um indicador que mostra o estado das teclas modificadoras padrão: Shift, Ctrl, Tux, Alt. Todas as principais áreas de trabalho (KDE, Windows, Mac OSX) têm esse applet de indicador disponível.
dotancohen
11
Eu acredito que o nome do pacote da ferramenta KDE você está se referindo também é plasma-widget-kbstatee uma busca rápida no centro da software de fato não atender quaisquer resultados equivalentes
Daniel W.
2
@ shengy: Estou usando o plasmóide KB State. Se você estiver no Kubuntu, instale-o com sudo apt-get install plasma-widget-kbstate.
dotancohen

Respostas:

7

Esta é uma questão excelente no Unity:

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

Uma versão bem empacotada foi disponibilizada no webupd8 ppa (Agradecemos a 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 dos Modificadores de Teclado Para Ubuntu: Indicador Xkbmod


Resposta original:

Isso não é visto como uma resposta canônica para a pergunta. Pode ser contado como uma solução alternativa. Esperar que alguém crie uma solução sofisticada

Este é um indicador simples de modificador de teclado para protótipo do Unity.

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

captura de tela do protótipo unity-xkbmod

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 / bibliotecas 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. Corre:

    ./unity-xkbmod
    

Nota:

  • libappindicatorusado para indicadores Unity não possui um recurso importante que facilite a portabilidade de outros indicadores de desktops. Consulte o Bug # 812067 API necessária: suporte à configuração de ícones pixbuf

    Sem esse recurso, digamos que precisamos (Shift, Ctrl, Alt, AltGr, Super) com as teclas ativadas; temos três status principais para cada um (desativado, ativado / travado, bloqueado). Portanto, 3 ^ 5 ícones combinados devem ser gerados. (Caso normal, apenas 3x5 ícones únicos)

    Por isso, usei etiqueta indicadora com símbolos da fonte DejaVu Sans .

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

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

Referências:

user.dz
fonte
Bom obrigado! Vou tentar e retornar a você. Bom trabalho, Sneetsher!
dotancohen 31/03
Que você zomba!
dotancohen
sim, obrigado @dotancohen. Então, pelo menos você pode usar o Unity, pode ser feio sem ícones de posição fixa?
usar o seguinte comando
11
Eu não me importo feio, você deveria ver uma foto minha! Eu mencionei esse problema no bugtracker do Ubuntu .
dotancohen
11
Sneetsher, queria agradecer novamente. Agora mudei para o Unity e a mudança seria impossível sem essa aplicação fantástica. Eu também aprendi bastante com o código. Obrigado!
dotancohen
2

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

  1. instalar kbstateminiaplicativo

    sudo apt-get install plasma-widget-kbstate kde-workspace-bin
    
  2. Execute-o no plasma-windowedplayer

    • Janela regular

      plasma-windowed kbstate
      

      captura de tela do plasma-widget-kbstate no Xubuntu

    • Janela sem margens

      plasma-windowed --noborder kbstate
      

      captura de tela do plasma-widget-kbstate sem borda no Unity

Não tive muito tempo para brincar, mas wmctrlposso ajudar a posicionar, redimensionar e torná-lo no topo no lançamento.

Referência: Que comando para iniciar um plasmóide kde e o menu kickstart

user.dz
fonte
1

Eu fiz uma pesquisa pelo monitor de chaves adesivas do Ubuntu e encontrei algo que pode ser útil aqui: http://code.google.com/p/key-mon/

captura de tela da vitrine

Tente correr

key-mon --sticky para Suporte para chaves adesivas.

Referência: http://code.google.com/p/key-mon/

Observe que a versão disponível no centro de software é 1.6-0ubuntu1. Lançado em junho de 2011, que não suporta o switch --sticky. Se o indicador se parecer exatamente com o acima, você possui a versão mais antiga. Experimente a versão mais recente em http://code.google.com/p/key-mon/ até o momento da redação deste documento. É keymon_1.17-1_all.deb 229 KB Lançado 3 de janeiro de 2014. Suporte para --sticky switch testado e confirmado.

Elder Geek
fonte
11
Boa descoberta, no entanto, key-monmostra qual botão foi pressionado e não o estado das teclas modificadoras . A distinção é que o key-monvisor retorna ao estado não pressionado 1 segundo depois que o botão foi pressionado . Um miniaplicativo de estado do modificador de teclado retornaria a exibição ao estado não pressionado quando ocorresse o próximo pressionamento de tecla e, portanto, desativaria o estado 'pressionado' .
dotancohen
resposta reeditada.
Elder Geek
Desculpe pela confusão. Editei a resposta (novamente) para fornecer exatamente o que você precisa.
Elder Geek
11
Obrigado Elder Geek. A --stickyopção parece adivinhar o estado das teclas modificadoras observando as demais teclas do estado, em vez de consultar a interface adequada, como fazem os applets de estado do modificador de teclado adequados. Isso pode ser visto pressionando uma tecla modificadora duas vezes: a primeira vez ativa o indicador no miniaplicativo, mas a segunda vez não o libera. Assim, o estado é relatado incorretamente como ativo quando não está. Esse bug relacionado soluciona parcialmente o problema; preencherei os detalhes lá e em erros adicionais. Obrigado.
dotancohen
11
@dotancohen Eu testei com base em sua afirmação de que "um applet de estado modificador de teclado retornaria a exibição ao estado não pressionado quando a próxima pressão de tecla ocorresse e, portanto, desativaria o estado 'pressionado'". e nunca me ocorreu que alguém apertaria a tecla modificadora duas vezes seguidas de propósito. Minhas desculpas pela supervisão.
Elder Geek