我想在程序启动时检查用户是否按下 SHIFT 键。 (这意味着,在程序启动之前按下 SHIFT 键)这是一个简单的控制台程序,与X无关。
这可能类似于Win32 GetKeyboardState()
函数。
我想知道我是否能够做到这一点,以及如何直接访问终端,但没有任何利弊。
答案 0 :(得分:30)
我认为有办法做到这一点。问题是您必须直接从键盘设备读取。你不会从终端获得输入。我也有同样的问题。我有一个程序运行(在后台),我想知道用户是否按住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。
您需要更改键盘设备的名称。我不知道找到默认键盘设备的方法。 (如果你知道我很乐意听到;))
这很有效:如果我按住shift键,我会用它来启动Xorg的自动启动。
答案 1 :(得分:3)
AFAIK如果没有没有root级别权限的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);
}
答案 2 :(得分:2)
我通过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");
}
}
答案 3 :(得分:-10)
你不能。
Shift键不被视为字符键,因此即使您直接访问终端,也无法检测到此键。
也许你不应该这样做。想象一下,例如,您正在使用美国键盘,其中数字可以在顶行访问而无需修饰符,并且还检查shift键。具有其他键盘布局的人可能必须使用移位修改器来访问数字。如果你的程序对这个班次按下做出反应,那么你的程序基本上无法使用。同样适用于其他修饰键:只有在按下普通字符键后才能检测到其中一些键。或者更糟糕的是,他们可能需要使用shift键来使用“enter”来运行程序。
另外,您想要监控什么换档键?本地机器上的那个,还是用户所在的机器?请记住,SSH存在并且通常用于远程访问伪终端。
如果您是root用户并希望监控本地计算机上的Shift键,则可以阅读evdev设备以获取有关shift键的事件。但这只是因为自动键重复才有可能,所以你不会检测到在运行你的程序之前按下的shift键,而是之前只有几秒钟。
当然,你不能在远程机器上做到这一点,这将是一个安全漏洞。
无论如何,你为什么要那样做?在您的情况下,X应用程序不是正确的做法吗?