我想检查在程序启动前用户是否按下了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。
您需要更改键盘设备的名称。我不知道如何找到默认的键盘设备。(如果您知道,我会很高兴听到的 ;))
这个方法非常好用:我用它来启动Xorg的自启动,只需按住Shift键即可。
platform-i8042-serio-0-event-kbd
,所以可能每台PC都有它?)。通过运行sudo xxd /dev/input/by-path/platform-i8042-serio-0-event-kbd
,我发现每当键盘状态改变时,该文件就会“增长”另一个sizeof(keymap)
。 - Tomasz Gandor#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);
}
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键来使用“enter”运行您的程序。
另外,您要监视哪个Shift键?本地机器上的键还是用户所在位置的键?请记住,SSH存在并且常用于远程访问伪终端。
如果您是root用户并想要监视本地计算机上的Shift键,您可以读取evdev设备以获取有关Shift键的事件。但这仅在自动键重复的情况下才可能发生,因此您不会检测到在运行程序之前按下的Shift键,而只能在几秒钟之前检测到。
当然,您不能在远程计算机上执行此操作,那将是一个安全漏洞。
而且,无论如何,为什么要这样做呢?在您的情况下,X应用程序不是正确的选择吗?
--conf
选项,但是知道这是不可能的就足够了,我会尝试其他方法。 - Lenik