[英]How can I get the keyboard state in Linux?
我想檢查程序啟動時用戶是否按下了Shift鍵。 (也就是說,在程序啟動前按下Shift鍵)這是一個簡單的控制台程序,與 X 無關。
這可能類似於 Win32 GetKeyboardState()
函數。
我想知道我是否可以執行此操作以及如何執行此操作,但不知道直接訪問終端的優缺點。
我認為會有辦法做到這一點。 問題是您必須直接從鍵盤設備讀取。 您不會從終端獲得輸入。 我有同樣的問題。 我有一個運行(在后台)的程序,我想知道用戶是否按住了 shift 鍵。
我相信這是可能的,一個開始的地方可能是/dev/input/by-path/*-kbd
。
這個文件在每次按下一個鍵時都會提供輸入,或者如果它被按住則重復輸入,所以它可能值得一看。 (試試 cat /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。
您將需要更改鍵盤設備的名稱。 我不知道找到默認鍵盤設備的方法。 (如果你知道我很想聽聽;))
這很好用:如果我按住 shift 鍵,我會用它來啟動 Xorg 的自動啟動。
AFAIK 如果沒有沒有根級別權限的 Xlib(又名 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);
}
我通過 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");
}
}
你不能。
Shift鍵不被視為字符鍵,因此即使您直接訪問終端,您也無法檢測到此鍵。
也許你不應該這樣做。 想象一下,例如,您正在使用美式鍵盤,在沒有修飾符的情況下可以在頂行訪問數字,並且還檢查Shift鍵。 使用其他鍵盤布局的人可能必須使用Shift修飾符來訪問數字。 如果您的程序對這個Shift鍵有反應,那么您的程序基本上無法使用。 同樣的事情適用於其他修飾鍵:您可能只有在按下普通字符鍵后才能檢測到其中的一些。 或者更糟的是,他們可能需要使用Shift鍵才能使用“輸入”來運行您的程序。
另外,您要監控哪個Shift鍵? 本地機器上的那個,還是用戶所在的那個? 請記住,SSH 存在並且通常用於遠程訪問偽終端。
如果您是 root 並且想要監視本地機器上的Shift鍵,您可以讀取 evdev 設備以獲取有關Shift鍵的事件。 但這只是由於自動重復按鍵才有可能,因此您不會檢測到在運行程序之前按下的Shift鍵,而是僅在幾秒鍾之前按下的。
當然你不能在遠程機器上這樣做,那將是一個安全漏洞。
無論如何,你為什么要這樣做? 在您的情況下,X 應用程序不是正確的做法嗎?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.