Wie füge ich ein Tastatur-Modifikator-Status-Applet zum Unity-Bedienfeld hinzu?

18

Ich bin ein KDE-Benutzer und denke darüber nach, zu Unity zu wechseln. Aufgrund manueller Behinderung verwende ich Sticky-Keys und in KDE habe ich ein Applet im System-Panel, das anzeigt, welche Modifier-Keys aktiv sind. Ich erinnere mich, dass Gnome diese Funktion ebenfalls hatte, ebenso wie Windows und OS X.

Wie fügt man das Tastaturmodifikator-Status-Applet in das Bedienfeld von Unity ein?

Klarstellung: Ich habe Sticky Keys bereits aktiviert. Ich frage, wie man ein Applet hinzufügt, das den Status der Modifikatortasten anzeigt . Diese Anzeige würde anzeigen, wenn die Umschalttaste gedrückt ist, wenn die Alt-Taste gedrückt ist, wenn die Tux-Taste gedrückt ist und wenn die Strg-Taste gedrückt ist. Dieses Applet ist in allen gängigen Desktop-Umgebungen (KDE, Windows, Mac OSX und Gnome) verfügbar. Es ist für die Erreichbarkeit des Desktops erforderlich.

Hier ist ein Bild des Applets zum Ändern des Tastaturstatus neben dem Applet zur Anzeige des Tastaturlayouts. Die Modifikatoren vertreten sind, von links nach rechts, Shift, Ctrl, Alt, I-dont-know-this-one, Tux/Win, NumLock, und CapsLock. Es ist zu sehen, dass die NumLock-Taste aktiv ist.

Bildbeschreibung hier eingeben

dotancohen
quelle
Errr ... Es scheint eine große Lücke zu geben, wenn es darum geht ... Es gibt jedoch etwas zu piepen, wenn eine Modifikatortaste gedrückt wird.
Wilf
@wilf Wenn ich mich nicht irre, gibt es in Unity ein Eingabehilfesymbol (wie in Gnome 3), aber kein zusätzliches Symbol, um den Benutzer über den Status zu informieren.
Braiam
4
@Takkat: Danke für den Vorschlag. indicator-keylockzeigt nur den Zustand dieser Tasten , die traditionell Zustandsanzeigen auf der Tastatur hat selbst: CapsLock, ScrollLock, NumLock. Ich brauche einen Indikator, der den Zustand der Standard - Zusatztasten zeigt: Shift, Ctrl, Tux, Alt. Auf allen wichtigen Desktops (KDE, Windows, Mac OS X) ist dieses Indikator-Applet verfügbar.
Dotancohen
1
Ich glaube, der Paketname des KDE-Tools, auf das Sie sich ebenfalls beziehen, ist plasma-widget-kbstateund eine schnelle Suche im Software-Center berücksichtigt in der Tat keine entsprechenden Ergebnisse
Daniel W.
2
@shengy: Ich verwende das KB-State-Plasmoid. Wenn Sie auf Kubuntu sind, dann installieren Sie es mit sudo apt-get install plasma-widget-kbstate.
Dotancohen

Antworten:

7

Dies ist ein herausragendes Problem in Unity:

Der folgende Code wurde aktualisiert. Jetzt kann er mithilfe von Symbolen den Status anzeigen. Es kann jedoch langsam werden, da ich die Symboldatei auf der Festplatte aktualisieren und dann erneut laden muss. (Siehe Hinweise zu diesem Problem / Einschränkung in libappindicator)

Eine gut verpackte Veröffentlichung wurde auf webupd8 ppa zur Verfügung gestellt (Dank geht an Alin Andrei / Andrew /)

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

Referenz: Tastaturmodifikatoren Statusanzeige Für Ubuntu: Xkbmod-Anzeige


Ursprüngliche Antwort:

Dies ist keine kanonische Antwort auf die Frage. Es könnte als Umgehungslösung gewertet werden. Hopping jemand schreibt raffinierte Lösung dafür.

Dies ist ein einfacher Prototyp eines Tastaturmodifikators für Unity.

Bild von links beginnend: Symbol, Umschalttaste, Feststelltaste, Strg, Alt, Super, Feststelltaste AltGr (kleiner Kreis, um den gesperrten Zustand anzuzeigen)

Screenshot des Prototyps von unity-xkbmod

Quelldatei 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. Benötigte Header / Bibliotheken installieren: (Ich bin mir nicht sicher, ob ich welche vermisse)

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

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

    ./unity-xkbmod
    

Hinweis:

  • libappindicatorFür Unity-Indikatoren fehlt eine wichtige Funktion, mit der andere Desktop-Indikatoren problemlos portiert werden können. Siehe Bug # 812067 API benötigt: Unterstützung der Einstellung von Pixbuf-Symbolen

    Angenommen, wir benötigen ohne diese Funktion (Umschalt, Strg, Alt, AltGr, Super) Sticky-Keys. Wir haben jeweils 3 Hauptstatus (Aus, Ein / Gesperrt, Gesperrt). Es sollten also 3 ^ 5 kombinierte Icons generiert werden. (Wo im Normalfall nur 3x5 einzelne Icons)

    Aus diesem Grund habe ich ein Indikatorlabel mit Symbolen aus der Schriftart DejaVu Sans verwendet .

  • Um ein Symbol zu platzieren, legen Sie es in denselben Ordner und benennen Sie es icon.*. Akzeptierte Formate: png, svg, ico, xpm ...

    Wenn Ihnen ein Symbol nicht gefällt, erstellen Sie stattdessen ein 1x1 px-Bild.

Verweise:

user.dz
quelle
Nett, danke! Ich werde es versuchen und mich bei Ihnen melden. Großartige Arbeit, Sneetsher!
Dotancohen
Dass du niesst!
Dotancohen
Ja, danke @dotancohen. Sie können also zumindest Unity verwenden. Ist dies ohne Symbole für feste Positionen möglicherweise hässlich?
user.dz
1
Es macht mir nichts aus, du solltest ein Bild von mir sehen! Ich habe dieses Problem im Ubuntu-Bugtracker erwähnt .
Dotancohen
1
Sneetsher, ich wollte mich noch einmal bedanken. Ich bin jetzt zu Unity umgezogen und der Umzug wäre ohne diese großartige Anwendung unmöglich gewesen. Ich habe auch einiges aus dem Code gelernt. Vielen Dank!
Dotancohen
2

Eine andere Lösung, die nicht perfekt ist, aber einige vielleicht nützlich finden, da es möglich ist, die volle Funktionalität wie in KDE zu haben, wie das Aktivieren einer Mod mit einem Klick.

  1. kbstateApplet installieren

    sudo apt-get install plasma-widget-kbstate kde-workspace-bin
    
  2. Führen Sie es im plasma-windowedPlayer aus

    • Normales Fenster

      plasma-windowed kbstate
      

      Screenshot von plasma-widget-kbstate in Xubuntu

    • Randloses Fenster

      plasma-windowed --noborder kbstate
      

      Screenshot von borderless plasma-widget-kbstate in Unity

Ich hatte nicht viel Zeit, um damit zu spielen, aber ich wmctrlkönnte helfen, es beim Start zu positionieren, in der Größe zu ändern und ganz oben zu platzieren.

Referenz: Welcher Befehl, um ein KDE-Plasmoid und das Kickstart-Menü zu starten

user.dz
quelle
1

Ich habe nach Ubuntu Sticky Keys Monitor gesucht und etwas gefunden, das hier hilfreich sein könnte: http://code.google.com/p/key-mon/

Bildschirmfoto zeigen

Versuche zu rennen

key-mon --sticky zur Unterstützung von Sticky Keys.

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

Beachten Sie, dass die im Software Center verfügbare Version 1.6-0ubuntu1 ist. Veröffentlicht im Juni 2011, der den --sticky-Schalter nicht unterstützt. Wenn die Anzeige der oben schaut man genau wie hat die ältere Version die neueste Version bei Versuchen http://code.google.com/p/key-mon/ zum Zeitpunkt des Schreibens es keymon_1.17-1_all.deb 229 KB ist freigegeben 3. Januar 2014. Unterstützung für --sticky switch getestet und bestätigt.

Elder Geek
quelle
1
Schöne Entdeckung, key-monzeigt jedoch , welche Taste gedrückt wurde und nicht den Status der Modifikatortasten . Der Unterschied besteht darin, dass das key-monDisplay 1 Sekunde nach dem Drücken der Taste in den nicht gedrückten Zustand zurückkehrt . Ein Tastaturmodifikator-Status-Applet würde die Anzeige beim nächsten Tastendruck in den nicht gedrückten Zustand zurückversetzen und daher den gedrückten Zustand deaktivieren .
Dotancohen
Antwort überarbeitet.
Elder Geek
Entschuldigung für die Verwirrung. Ich habe die Antwort (erneut) bearbeitet, um genau das bereitzustellen, was Sie benötigen.
Elder Geek
1
Vielen Dank Elder Geek. Die --stickyOption scheint den Status der Modifikatortasten zu erraten, indem sie den Status anderer Tasten überwacht, anstatt die richtige Benutzeroberfläche wie auch die richtigen Tastaturmodifikatorstatus-Applets abzufragen. Dies kann durch zweimaliges Drücken einer Modifikatortaste festgestellt werden: Beim ersten Mal wird der Indikator im Applet aktiviert, beim zweiten Mal wird er jedoch nicht freigegeben. Daher wird der Status fälschlicherweise als aktiv gemeldet, wenn dies nicht der Fall ist. Dieser verwandte Fehler behebt das Problem teilweise. Ich werde die Details dort und zusätzliche Fehler eintragen. Vielen Dank.
Dotancohen
1
@dotancohen Ich habe getestet, basierend auf Ihrer Aussage, dass "Ein Tastaturmodifikator-Status-Applet die Anzeige in den nicht gedrückten Zustand zurückversetzen würde, wenn der nächste Tastendruck stattfinden würde, und daher den gedrückten Zustand deaktivieren würde." und es ist mir nie in den Sinn gekommen, dass jemand absichtlich zweimal hintereinander auf die Modifikatortaste drückt. Ich entschuldige mich für das Versehen.
Elder Geek