我需要访问我正在编写的控制台应用程序(个性化编辑器)的修饰键状态。
是否有任何包/库/任何内容提供此访问权限?
我从某个地方拼凑了以下内容,但只有当你是 root 时它才有效,而且我真的不想在 root 级别搞乱。
#include <iostream>
#include <string>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <termios.h>
#include <fcntl.h>
#include <linux/input.h>
#include <unistd.h>
#include <errno.h>
int kbhit(void)
{
struct termios oldt, newt;
int ch;
int oldf;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~0000172 ; //~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
fcntl(STDIN_FILENO, F_SETFL, oldf);
return ch;
}
enum MODKEYS
{
SHIFT_L = 1,
SHIFT_R = 2,
CTRL_L = 4,
CTRL_R = 8,
ALT_L = 16,
ALT_R = 32,
};
int chkmodifiers()
{
int mods=0,keyb,mask;
char key_map[KEY_MAX/8 + 1]; // Create a byte array the size of the number of keys
//event1 - got by inspecting /dev/input/...
FILE *kbd = fopen("/dev/input/event1", "r");
if (kbd == NULL)
{
printf("(chkmodifiers) ERROR: %s\n", strerror(errno)); //permission - got to be root!
return 0;
}
memset(key_map, 0, sizeof(key_map));
ioctl(fileno(kbd), EVIOCGKEY(sizeof(key_map)), key_map); // Fill the keymap with the current keyboard state
keyb = key_map[KEY_LEFTSHIFT/8];
mask = 1 << (KEY_LEFTSHIFT % 8);
if (keyb & mask) mods += SHIFT_L;
keyb = key_map[KEY_RIGHTSHIFT/8];
mask = 1 << (KEY_RIGHTSHIFT % 8);
if (keyb & mask) mods += SHIFT_R;
keyb = key_map[KEY_LEFTCTRL/8];
mask = 1 << (KEY_LEFTCTRL % 8);
if (keyb & mask) mods += CTRL_L;
keyb = key_map[KEY_RIGHTCTRL/8];
mask = 1 << (KEY_RIGHTCTRL % 8);
if (keyb & mask) mods += CTRL_R;
keyb = key_map[KEY_LEFTALT/8];
mask = 1 << (KEY_LEFTALT % 8);
if (keyb & mask) mods += ALT_L;
keyb = key_map[KEY_RIGHTALT/8];
mask = 1 << (KEY_RIGHTALT % 8);
if (keyb & mask) mods += ALT_R;
return mods;
}
int main()
{
puts("Press a key!");
char ch=0;
int n=0,m;
while (ch != 'q')
{
n = kbhit();
if (n != -1)
{
m = chkmodifiers();
ch = (char)n;
printf("You pressed '%c' [%d]\n", ch, n);
if ((m & SHIFT_L) == SHIFT_L) printf(" .. and ls\n");
if ((m & SHIFT_R) == SHIFT_R) printf(" .. and rs\n");
if ((m & CTRL_L) == CTRL_L) printf(" .. and lc\n");
if ((m & CTRL_R) == CTRL_R) printf(" .. and rc\n");
if ((m & ALT_L) == ALT_L) printf(" .. and la\n");
if ((m & ALT_R) == ALT_R) printf(" .. and ra\n");
}
}
return 0;
}
답변1
也许看看libtermkey,一个终端键输入库,可识别特殊键(例如箭头和功能键),包括“修改”键,例如Ctrl-Left
.
另一种选择可能是增强魅力,一个最小的 ncurses 副本。
답변2
在终端中,获得此类信息一直非常困难。您只能获得一个“键码”,当然,它的含义不同,具体取决于您使用的操作系统、键盘和终端的组合。
您将在操作系统上找到这些键码的完整列表,只需调用xmodmap。
$ xmodmap -pke
keycode 9 = Escape NoSymbol Escape
keycode 10 = ampersand 1 ampersand 1 dead_caron dead_ogonek dead_caron dead_ogonek
keycode 11 = eacute 2 eacute 2 asciitilde Eacute asciitilde Eacute
[...]
keycode 244 = XF86Battery NoSymbol XF86Battery
keycode 245 = XF86Bluetooth NoSymbol XF86Bluetooth
keycode 246 = XF86WLAN NoSymbol XF86WLAN
keycode 247 =
以及所有修饰符值的列表:
$ xmodmap
xmodmap: up to 4 keys per modifier, (keycodes in parentheses):
shift Shift_L (0x32), Shift_R (0x3e)
lock Caps_Lock (0x42)
control Control_L (0x25), Control_R (0x69)
mod1 Alt_L (0x40), Meta_L (0xcd)
mod2 Num_Lock (0x4d)
mod3
mod4 Super_L (0x85), Super_R (0x86), Super_L (0xce), Hyper_L (0xcf)
mod5 ISO_Level3_Shift (0x5c), Mode_switch (0xcb)
有一些原始信息术语信息数据库或更完善的恩诅咒API 就是为了帮助系统开发人员克服这个烂摊子。
如果您可以重复使用现有的源代码,例如纳米的一个,它应该可以节省你很多时间。看一下“get_escape_seq_kbinput”函数就明白我的意思了。
如果您只需要现代 Linux 支持,可以调用键名足够。