Как получить состояние клавиатуры в Linux? - PullRequest
12 голосов
/ 06 сентября 2010

Я хочу проверить, нажимал ли пользователь клавишу SHIFT при запуске программы.(Это означает, что нажмите клавишу SHIFT до запуска программы). Это простая консольная программа, не имеющая отношения к X.

Это может быть похоже на функцию Win32 GetKeyboardState().

Я хочу знать, смогу ли я сделать это и как, но не о плюсах и минусах с прямым доступом к терминалу.

Ответы [ 4 ]

30 голосов
/ 19 ноября 2010

Я думаю, что был бы способ сделать это. Дело в том, что вам придется читать прямо с клавиатуры устройства. Вы не будете получать вход от терминала. У меня та же проблема. У меня есть программа, которая работает (в фоновом режиме), и я хочу знать, удерживает ли пользователь клавишу Shift.

Я полагаю, что это возможно, и можно начать с /dev/input/by-path/*-kbd.

Этот файл дает ввод каждый раз, когда нажимается или повторяется нажатие клавиши, если он удерживается, поэтому его стоит посмотреть. (Попробуйте кошку /dev/input/by-path/*-kbd)

Если вы поймете это, я хотел бы услышать, как вы это сделали.

РЕДАКТИРОВАТЬ: Я нашел решение

Я понял, как это сделать. Моя программа выглядит следующим образом:

#include <stdlib.h>
#include <stdio.h>

#include <linux/input.h>

void usage ( int argc, char *argv[] )
{
    printf("Usage:\n\t%s key\n\nvalid keys are:\n\tlshift\t- Left Shift key\n" , argv[0]);

    exit(EXIT_FAILURE);
}

int main ( int argc, char *argv[], char *env[] )
{
    if ( argc != 2 )    usage(argc, argv);

    int key;

    if ( strcmp(argv[1], "lshift") == 0 )       key = KEY_LEFTSHIFT;
    else if ( strcmp(argv[1], "rshift") == 0 )  key = KEY_RIGHTSHIFT;
    else if ( strcmp(argv[1], "lalt") == 0 )    key = KEY_LEFTALT;
    else if ( strcmp(argv[1], "ralt") == 0 )    key = KEY_RIGHTALT;
    else if ( strcmp(argv[1], "lctrl") == 0 )   key = KEY_LEFTCTRL;
    else if ( strcmp(argv[1], "rctrl") == 0 )   key = KEY_RIGHTCTRL;


    FILE *kbd = fopen("/dev/input/by-path/platform-i8042-serio-0-event-kbd", "r");

    char key_map[KEY_MAX/8 + 1];    //  Create a byte array the size of the number of keys

    memset(key_map, 0, sizeof(key_map));    //  Initate the array to zero's
    ioctl(fileno(kbd), EVIOCGKEY(sizeof(key_map)), key_map);    //  Fill the keymap with the current keyboard state

    int keyb = key_map[key/8];  //  The key we want (and the seven others arround it)
    int mask = 1 << (key % 8);  //  Put a one in the same column as out key state will be in;

    return !(keyb & mask);  //  Returns true if pressed otherwise false

}

Отсутствует информационное сообщение (я слишком ленив). Но по сути первый аргумент сравнивается со списком ключей и используется соответствующий идентификатор ключа. Возвращает true, если клавиша нажата, и false, если нет.

Обратите внимание

Вам нужно будет изменить название устройства клавиатуры. Я не знаю, как найти устройство клавиатуры по умолчанию. (если вы знаете, я хотел бы услышать;))

Это прекрасно работает: я использую его для запуска автозапуска Xorg, если удерживаю клавишу Shift.

3 голосов
/ 15 апреля 2018

AFAIK это невозможно сделать без Xlib (aka. X) без прав корневого уровня.Использование XQueryKeymap () будет делать то, что вы хотите.однако вы указали, что X нельзя использовать.В любом случае, также потребуется открытие соединения с дисплеем.

#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <stdbool.h>
#include <stdio.h>

int main()
{
    Display* dpy = XOpenDisplay(NULL);
    char keys_return[32];
    XQueryKeymap( dpy, keys_return );
    KeyCode kc2 = XKeysymToKeycode( dpy, XK_Shift_L );
    bool bShiftPressed = !!( keys_return[ kc2>>3 ] & ( 1<<(kc2&7) ) );
    printf("Shift is %spressed\n", bShiftPressed ? "" : "not ");
    XCloseDisplay(dpy);
}
2 голосов
/ 25 ноября 2017

Я нашел очень простой способ через gtk / gdk.

int main ( int argc, char *argv[], char *env[] )
{
    gtk_init(&argc, &argv);

    GdkModifierType button_state;
    gdk_window_get_pointer(NULL, NULL, NULL, &button_state);
    if(button_state & GDK_CONTROL_MASK) {
        printf("ctrl key is pressed");
    }
}
0 голосов
/ 06 сентября 2010

Вы не можете.

Клавиша Shift не считается символьной клавишей, поэтому даже если вы обращаетесь к терминалу напрямую, вы не сможете обнаружить эту клавишу.

Может быть, вам не нужно.Представьте, например, что вы используете клавиатуру США, где цифры доступны в верхнем ряду без модификаторов, а также проверяете наличие клавиши Shift.Люди с другой раскладкой клавиатуры могут использовать модификаторы сдвига для доступа к номерам.Если ваша программа реагирует на эту смену, то ваша программа в основном непригодна для использования.То же самое относится и к другим клавишам-модификаторам: некоторые из них можно обнаружить только после нажатия обычной символьной клавиши.Или, что еще хуже, им может понадобиться использовать клавишу Shift, чтобы использовать «enter» для запуска вашей программы.

Кроме того, какую клавишу Shift вы хотите отслеживать?тот, что на локальной машине, или тот, где находится пользователь?помните, что SSH существует и обычно используется для удаленного доступа к псевдотерминалу.

Если вы являетесь пользователем root и хотите отслеживать клавишу Shift на локальном компьютере, вы можете прочитать на устройствах evdev события о клавише Shift.Но это возможно только из-за автоматического повторения клавиш, поэтому вы не сможете обнаружить клавишу Shift, нажатую непосредственно перед запуском вашей программы, а всего за несколько секунд до этого.

Конечно, вы не можете этого сделатьна удаленной машине это было бы ошибкой безопасности.

И вообще, зачем вам это делать?разве приложение X не будет правильным решением в вашем случае?

...