Как добавить апплет состояния модификатора клавиатуры на панель Unity?

18

Я пользователь KDE и думаю о переходе на Unity. Из-за ручного отключения я использую липкие клавиши, а в KDE на системной панели есть апплет, который показывает, какие клавиши-модификаторы активны. Я помню, что Gnome также имел эту функцию, как и Windows и OS X.

Как можно добавить апплет состояния модификатора клавиатуры на панель в Unity?

Уточнение: я уже включил липкие клавиши. Я спрашиваю, как добавить апплет, который указывает состояние клавиш-модификаторов . Этот индикатор показывает, когда нажата клавиша Shift, когда нажата клавиша Alt, когда нажата клавиша Tux и когда нажата клавиша Ctrl. Этот апплет существует во всех основных средах рабочего стола (KDE, Windows, Mac OSX и Gnome). Это необходимо для доступности рабочего стола.

Вот изображение апплета состояния модификатора клавиатуры, рядом с апплетом индикатора раскладки клавиатуры. Модификаторы , представленные, слева направо, Shift, Ctrl, Alt, I-dont-know-this-one, Tux/Win, NumLock, и CapsLock. Видно, что клавиша NumLock активна.

введите описание изображения здесь

dotancohen
источник
Errr ... Кажется, что есть большой разрыв, когда дело доходит до ... Есть что-то, чтобы подать звуковой сигнал, когда нажата клавиша-модификатор.
Уилф
@wilf Если я не ошибаюсь, в Unity есть значок Accessibility (такой же, как в Gnome 3), но нет значка «extra» для информирования пользователя о статусе.
Брайам
4
@Takkat: Спасибо за предложение. indicator-keylockтолько отображает состояние тех ключей , которые традиционно имеют индикаторы состояния на самой клавиатуре: CapsLock, ScrollLock, NumLock. Мне нужен индикатор , который показывает состояние стандартных клавиш - модификаторов: Shift, Ctrl, Tux, Alt. Все основные рабочие столы (KDE, Windows, Mac OSX) имеют доступ к этому апплету индикатора.
Dotancohen
1
Я полагаю, что имя пакета инструмента KDE, на который вы ссылаетесь, также является plasma-widget-kbstateбыстрым, и поиск в центре программного обеспечения действительно не учитывает никаких эквивалентных результатов
Даниэль В.
2
@shengy: я использую плазмоид KB State. Если вы используете Kubuntu, установите его с помощью sudo apt-get install plasma-widget-kbstate.
Dotancohen

Ответы:

7

Это выдающаяся проблема в Unity:

Код ниже был обновлен, теперь он может использовать иконки для отображения состояния. Но иногда это может замедлиться, так как мне приходится обновлять файл значков на жестком диске, а затем снова его загружать. (См. Примечания об этой проблеме / ограничение в libappindicator)

Хорошо упакованный релиз был сделан доступным на webupd8 ppa (спасибо Алине Андрей / Андрей /)

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

Ссылка: Индикатор состояния модификаторов клавиатуры Для Ubuntu: Индикатор Xkbmod


Оригинальный ответ:

Это не является каноническим ответом на вопрос. Это можно считать обходным решением. Прыжки кто-то пишет сложные решения для этого.

Это простой прототип индикатора модификаторов клавиатуры для Unity.

Изображение начинается слева: иконка, Shift, закрытые буквы, Ctrl, Alt, Super, Locked AltGr (маленький кружок для обозначения заблокированного состояния)

скриншот прототипа unity-xkbmod

Исходный файл 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. Установка необходимых заголовков / библиотек: (Не уверен, что я что-то пропустил)

    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
    

Замечания:

  • libappindicatorИспользуемые для индикаторов Unity отсутствуют важные функции, упрощающие портирование других индикаторов рабочего стола. См. Ошибка # 812067 Необходим API: поддержка настройки иконки pixbuf

    Без этой функции, скажем, нам нужны (Shift, Ctrl, Alt, AltGr, Super) с активными липкими клавишами; у нас есть 3 основных статуса для каждого (Выкл., Вкл / Защелка, Заблокировано). Таким образом, 3 ^ 5 комбинированных иконок должны быть сгенерированы. (Где нормальный случай только 3х5 одиночных значков)

    Поэтому я использовал индикаторную метку с символами из шрифта DejaVu Sans .

  • Чтобы поместить значок, поместите его в ту же папку и назовите его icon.*. Принятые форматы: PNG, SVG, ICO, XPM ...

    Если вам не нравится какой-либо значок, просто создайте изображение размером 1x1 px.

Ссылки:

user.dz
источник
Хорошо.Спасибо! Я попробую и вернусь к вам. Отличная работа, Sneetsher!
Dotancohen
Это ты чихаешь!
dotancohen
да, спасибо @dotancohen. Так что, по крайней мере, вы можете использовать Unity, может быть, это безобразно без значков фиксированной позиции?
user.dz
1
Я не против урод, вы должны увидеть мою фотографию! Я упомянул эту проблему на багтрекер Ubuntu .
dotancohen
1
Снишер, я хотел еще раз сказать спасибо. Теперь я переехал в Unity, и переезд был бы невозможен без этого потрясающего приложения. Я также многому научился из кода. Спасибо!
Dotancohen
2

Другое решение, которое не является идеальным, но некоторые могут найти его полезным, так как возможно иметь полную функциональность, как в KDE, например, активировать мод одним кликом.

  1. установить kbstateапплет

    sudo apt-get install plasma-widget-kbstate kde-workspace-bin
    
  2. Запустите его в plasma-windowedплеере

    • Обычное окно

      plasma-windowed kbstate
      

      снимок экрана с плазмой-виджетом-kbstate в Xubuntu

    • Окно без границ

      plasma-windowed --noborder kbstate
      

      снимок экрана без плазмы-виджета-kbstate в Unity

У меня не было много времени, чтобы поиграть, но я wmctrlмогу помочь позиционировать, изменять размеры и делать это на вершине при запуске.

Ссылка: Какая команда для запуска плазмоида kde и меню кикстарта

user.dz
источник
1

Я выполнил поиск монитора липких ключей Ubuntu и нашел кое-что полезное здесь: http://code.google.com/p/key-mon/

снимок экрана

Попробуйте запустить

key-mon --sticky Поддержка липких ключей.

Ссылка: http://code.google.com/p/key-mon/

Обратите внимание, что версия, доступная через центр программного обеспечения, - 1.6-0ubuntu1. Выпущен в июне 2011 года, который не поддерживает параметр --sticky. Если индикатор выглядит точно так же, как указано выше, у вас есть более старая версия. Попробуйте последнюю версию по адресу http://code.google.com/p/key-mon/. На момент написания статьи она выпущена keymon_1.17-1_all.deb 229 КБ. 3 января 2014 года. Поддержка --sticky switch проверена и подтверждена.

Старейшина Гик
источник
1
Хорошая находка, однако key-monпоказывает, какая кнопка была нажата, а не состояние клавиш-модификаторов . Различие состоит в том, что key-monдисплей возвращается в неотжатое состояние через 1 секунду после нажатия кнопки . Апплет состояния модификатора клавиатуры вернет дисплей в состояние без нажатия, когда произойдет следующее нажатие клавиши, и, следовательно, отключит состояние «нажато» .
Dotancohen
отредактированный ответ.
Старейшина Гик
Извините за путаницу. Я отредактировал ответ (снова), чтобы предоставить именно то, что вам нужно.
Старейшина Гик
1
Спасибо старейшина Гик. Эта --stickyопция, кажется, угадывает состояние клавиш-модификаторов, наблюдая за состоянием других клавиш, вместо того, чтобы запрашивать правильный интерфейс, как это делают надлежащие апплеты состояния модификатора клавиатуры. Это можно увидеть, дважды нажав клавишу-модификатор: первый раз включает индикатор в апплете, но второй раз не отпускает его. Таким образом, состояние ошибочно сообщается как активное, когда это не так. Эта связанная ошибка решает проблему частично, я буду заполнять детали там и в дополнительных ошибках. Спасибо.
dotancohen
1
@dotancohen Я протестировал, основываясь на вашем утверждении, что «Апплет состояния модификатора клавиатуры вернет дисплей в состояние без нажатия, когда произойдет следующее нажатие клавиши, и, следовательно, отключит состояние« нажато ».» и мне никогда не приходило в голову, что кто-то намеренно дважды нажимает клавишу-модификатор подряд. Мои извинения за недосмотр.
Старейшина Гик