Comment ajouter une applet d'état de modificateur de clavier au panneau Unity?


18

Je suis un utilisateur de KDE qui envisage de passer à Unity. En raison d'un handicap manuel, j'utilise des touches rémanentes et dans KDE, j'ai une applet dans le panneau système qui indique quelles touches de modification sont actives. Je me souviens que Gnome avait également cette fonctionnalité, tout comme Windows et OS X.

Comment ajouter l'applet d'état du modificateur de clavier au panneau dans Unity?

Précision: j'ai déjà activé les touches rémanentes. Je demande comment ajouter une applet qui indique l'état des touches de modification . Cet indicateur montrerait lorsque la touche Maj est enfoncée, lorsque la touche Alt est enfoncée, lorsque la touche Tux est enfoncée et lorsque la touche Ctrl est enfoncée. Cette applet existe dans tous les principaux environnements de bureau (KDE, Windows, Mac OSX et Gnome). Il est nécessaire pour l'accessibilité du bureau.

Voici une image de l'applet d'état du modificateur de clavier, à côté de l'applet d'indicateur de disposition du clavier. Les modificateurs représentés sont, de gauche à droite, Shift, Ctrl, Alt, I-dont-know-this-one, Tux/Win, NumLock, et CapsLock. On peut voir que la touche NumLock est active.

entrez la description de l'image ici


Euh ... Il semble y avoir un grand écart quand il s'agit de cela ... Il y a cependant un bip à entendre quand une touche de modification est enfoncée.
Wilf

@wilf Si je ne me trompe pas, il y a une icône d'accessibilité dans Unity (identique à Gnome 3) mais pas une icône "supplémentaire" pour informer l'utilisateur du statut.
Braiam

4
@Takkat: Merci pour la suggestion. indicator-keylockaffiche uniquement l'état de ces clés qui ont traditionnellement des indicateurs d'état sur le clavier lui - même: CapsLock, ScrollLock, NumLock. Je besoin d' un indicateur qui montre l'état des touches de modification standard: Shift, Ctrl, Tux, Alt. Tous les principaux bureaux (KDE, Windows, Mac OSX) ont cette applet d'indicateur disponible.
dotancohen

1
Je pense que le nom de paquet de l'outil KDE auquel vous faites référence l'est aussi plasma-widget-kbstateet une recherche rapide dans le centre logiciel ne tient en effet pas compte de résultats équivalents
Daniel W.

2
@shengy: J'utilise le plasmoïde KB State. Si vous êtes sur Kubuntu, installez-le avec sudo apt-get install plasma-widget-kbstate.
dotancohen

Réponses:


7

Il s'agit d'un problème en suspens dans Unity:

Le code ci-dessous a été mis à jour, il peut désormais utiliser des icônes pour afficher l'état. Mais cela peut parfois ralentir car je dois mettre à jour le fichier icône sur le disque dur, puis le recharger à nouveau. (Voir les notes sur ce problème / cette limitation dans libappindicator)

Une version bien packagée a été mise à disposition sur webupd8 ppa (Merci à Alin Andrei / Andrew /)

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

Référence: indicateur d'état des modificateurs de clavier pour Ubuntu: indicateur Xkbmod


Réponse originale:

Il ne s'agit pas d'une réponse canonique à la question. Cela pourrait être considéré comme un contournement. Hopping quelqu'un écrit une solution sophistiquée pour cela.

Il s'agit d'un simple indicateur de modificateurs de clavier prototype pour Unity.

Image à partir de la gauche: icône, Maj, Maj verrouillées, Ctrl, Alt, Super, AltGr verrouillé (petit cercle pour indiquer l'état verrouillé)

capture d'écran du prototype d'unité-xkbmod

Fichier source 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. Installation des en-têtes / bibliothèques nécessaires: (Je ne sais pas si j'en manque)

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

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

    ./unity-xkbmod
    

Remarque:

  • libappindicatorLes indicateurs utilisés pour Unity ne disposent pas d'une fonctionnalité importante qui facilite le portage d'autres indicateurs de bureau. Voir Bogue n ° 812067 API nécessaire: prise en charge des paramètres d'icône pixbuf

    Sans cette fonctionnalité, disons que nous avons besoin (Maj, Ctrl, Alt, AltGr, Super) avec des touches persistantes actives; nous avons 3 statuts principaux pour chacun (Off, On / Latched, Locked). Il faut donc générer 3 ^ 5 icônes combinées. (Dans le cas normal, seulement 3x5 icônes simples)

    C'est pourquoi j'ai utilisé une étiquette indicatrice avec des symboles de la police DejaVu Sans .

  • Pour mettre une icône, placez-la dans le même dossier et nommez-la icon.*. Formats acceptés: png, svg, ico, xpm ...

    Si vous n'aimez aucune icône, créez simplement une image 1x1 px à la place.

Les références:


Bien merci! Je vais essayer et je vous répondrai. Excellent travail, Sneetsher!
dotancohen

Que vous éternuiez!
dotancohen

oui, merci @dotancohen. Donc, au moins, vous pouvez utiliser Unity, peut-être qu'il est moche sans icônes de position fixe?
user.dz

1
Ça ne me dérange pas moche, tu devrais voir une photo de moi! J'ai mentionné ce problème sur le bugtracker Ubuntu .
dotancohen

1
Sneetsher, je voulais vous remercier encore une fois. Je suis maintenant passé à Unity et le déménagement aurait été impossible sans cette formidable application. J'ai également beaucoup appris du code. Je vous remercie!
dotancohen

2

Une autre solution qui n'est pas parfaite, mais certains peuvent la trouver utile car il est possible d'avoir des fonctionnalités complètes comme dans KDE comme activer un mod en un clic.

  1. installer l' kbstateapplet

    sudo apt-get install plasma-widget-kbstate kde-workspace-bin
    
  2. Exécutez-le dans le plasma-windowedlecteur

    • Fenêtre régulière

      plasma-windowed kbstate
      

      capture d'écran de plasma-widget-kbstate dans Xubuntu

    • Fenêtre sans bordure

      plasma-windowed --noborder kbstate
      

      capture d'écran de borderless plasma-widget-kbstate in Unity

Je n'ai pas eu beaucoup de temps pour jouer avec, mais wmctrlpeut aider à positionner, redimensionner et le rendre au top au lancement.

Référence: quelle commande pour lancer un plasmoïde kde et le menu kickstart


1

J'ai fait une recherche sur le moniteur de clés collantes Ubuntu et j'ai trouvé quelque chose qui peut être utile ici: http://code.google.com/p/key-mon/

capture d'écran de la vitrine

Essayez de courir

key-mon --sticky pour le support des clés collantes.

Référence: http://code.google.com/p/key-mon/

Notez que la version disponible via le centre logiciel est 1.6-0ubuntu1. Sorti en juin 2011 qui ne prend pas en charge le commutateur --sticky. Si l'indicateur ressemble exactement à ce qui précède, vous avez l'ancienne version Essayez la dernière version sur http://code.google.com/p/key-mon/ au moment de la rédaction de cet article, il s'agit de keymon_1.17-1_all.deb 229 Ko publié 3 janvier 2014. Prise en charge du commutateur --sticky testée et confirmée.


1
Une bonne trouvaille key-monmontre cependant quel bouton a été enfoncé et non l'état des touches de modification . La différence est que l' key-monaffichage revient à l'état non enfoncé 1 seconde après avoir appuyé sur le bouton . Une applet d'état de modification du clavier ramènerait l'affichage à l'état non pressé lors de la prochaine pression de touche et désactiverait donc l'état «pressé» .
dotancohen

réponse réédité.
Elder Geek

Désolé pour la confusion. J'ai édité (encore) la réponse pour fournir exactement ce dont vous avez besoin.
Elder Geek

1
Merci frère Geek. L' --stickyoption semble deviner l'état des touches de modification en observant l'état des autres touches, au lieu d'interroger l'interface appropriée comme le font les applets d'état de modification de clavier appropriées. Cela peut être vu en appuyant deux fois sur une touche de modification: la première fois active l'indicateur dans l'applet, mais la deuxième fois ne le relâche pas. Ainsi, l'État est signalé à tort comme étant actif alors qu'il ne l'est pas. Ce bogue associé résout partiellement le problème, je vais remplir les détails là-bas et d'autres bogues. Je vous remercie.
dotancohen

1
@dotancohen J'ai testé sur la base de votre déclaration que "Une applet d'état de modificateur de clavier ramènerait l'affichage à l'état non pressé lors de la prochaine pression de touche et désactiverait donc l'état 'pressé'." et il ne m'est jamais venu à l'esprit que n'importe qui frapperait la touche de modification deux fois de suite exprès. Mes excuses pour la surveillance.
Elder Geek
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.