如何将键盘修饰符状态小程序添加到Unity面板?

我是KDE用户,想要搬到Unity。 由于手动残疾,我使用粘滞键 ,在KDE中我在系统面板中有一个小程序,显示哪些修饰键是活动的。 我记得Gnome也有这个function,Windows和OS X也是如此。

如何将键盘修饰符状态小程序添加到Unity中的面板?

澄清:我已经启用了粘滞键。 我问如何添加一个指示修饰键的状态的小程序。 当按下Shift键,按下Alt键,按下Tux键,按下Ctrl键时,此指示灯将显示。 此applet存在于所有主要桌面环境(KDE,Windows,Mac OSX和Gnome)中。 桌面的可访问性是必要的。

这是键盘修改器状态小程序的图像,位于键盘布局指示器小程序旁边。 表示的修饰符是从左到右, ShiftCtrlAltI-dont-know-this-oneTux/WinNumLockCapsLock 。 可以看出NumLock键是活动的。

在此处输入图像描述

这是Unity中的一个突出问题:

  • lp#773078应该以某种方式显示StickyKeys状态(a11y)
  • lp#1306584 Unity中没有键盘状态小程序 (感谢@dotancohen)

下面的代码已经更新,现在它可以使用图标来显示状态。 但是有时可能会变慢,因为我必须更新硬盘上的图标文件然后重新加载它。 (请参阅libappindicator有关此问题/限制的libappindicator

在webupd8 ppa上提供了一个包装良好的版本(感谢Alin Andrei / Andrew /)

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

参考: 键盘修饰符状态指示符对于Ubuntu:Xkbmod指示符


原答案:

这不是对问题的规范回答。 它可以算作一种解决方法。 跳跃的人为它编写复杂的解决方案。

这是Unity的简单原型键盘修饰符指示器。

从左侧开始的图像:图标,移位,锁定大写,Ctrl,Alt,超级,锁定AltGr(小圆圈表示锁定状态)

unity-xkbmod原型的截图

源文件unity-xkbmod.c

 /* * unity-xkbmod.c * * Copyright 2014 Sneetsher  * * 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  #include  #include  #include  #include  //callback data structure typedef struct _AppData { Display *_display; int *_deviceId; AppIndicator *indicator; } AppData; //menu ui static GtkActionEntry entries[] = { { "Quit", "application-exit", "_Quit", "Q", "Exit the application", G_CALLBACK (gtk_main_quit) }, }; static guint n_entries = G_N_ELEMENTS (entries); static const gchar *ui_info = "" " " " " " " ""; //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. 安装所需的头文件/库:(不确定我是否错过了)

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

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

     ./unity-xkbmod 

注意:

  • 用于Unity指标的libappindicator缺少一个重要的function,可以轻松端口其他桌面指示器。 请参阅Bug#812067所需的API:pixbuf图标设置支持

    如果没有此function,我们需要(Shift,Ctrl,Alt,AltGr,Super)激活粘滞键; 我们有3个主要状态(关闭,开启/锁定,锁定)。 因此应该生成3 ^ 5个组合图标。 (正常情况下只有3×5单个图标)

    这就是为什么我使用带有DejaVu Sans字体符号的指示标签。

  • 要放置图标,请将其放在同一文件夹中并将其命名为icon.* 。 可接受的格式:png,svg,ico,xpm …

    如果您不喜欢任何图标,只需创建一个1×1 px图像。

参考文献:

  • X键盘扩展
  • 应用面板指标
  • xkbwatchplasma-widget-kbstate

另一种解决方案并不完美,但有些可能会发现它很有用,因为它可以像KDE一样具有完整function,例如通过点击激活mod。

  1. 安装kbstate applet

     sudo apt-get install plasma-widget-kbstate kde-workspace-bin 
  2. plasma-windowed播放器中运行它

    • 常规窗口

       plasma-windowed kbstate 

      Xubuntu中plasma-widget-kbstate的屏幕截图

    • 无边框窗口

       plasma-windowed --noborder kbstate 

      Unity中无边框plasma-widget-kbstate的屏幕截图

我没有太多时间玩,但是wmctrl可能有助于定位,resize并在发布时将其wmctrl

参考: 启动kde等离子体和kickstart菜单的命令

我搜索了Ubuntu粘滞密钥监视器,发现了一些可能有用的东西: http : //code.google.com/p/key-mon/

展示案例截图

试试跑步

key-mon --sticky支持粘滞键。

参考: http : //code.google.com/p/key-mon/

请注意,通过软件中心提供的版本是1.6-0ubuntu1。 发布于2011年6月,不支持-sticky开关。 如果指标与上面的内容完全相同,则表示您使用旧版本在http://code.google.com/p/key-mon/上尝试最新版本,截至撰写本文时,它是keymon_1.17-1_all.deb 229 KB发布2014年1月3日。支持–sticky开关测试和确认。