将 Char 转换为内核 Keycode(供 uinput 使用)
Convert Char to kernel Keycode (for uinput use)
我正在尝试在 Debian Stretch 上用 uinput 做一个虚拟键盘,我可以输入字符串,比如 "Toto !",键盘会写这个字符串。
但是,我一直坚持从 C char 到键盘处理的键码的转换。
我没有使用 event-codes.h 中定义的宏,因为我希望我的解决方案适用于计算机的区域设置,并且宏是围绕美国键盘定义的。
这是使用 uinput 创建的设备:
int setup_uinput_device(){
/* Temporary variable */
int i=0;
/* Open the input device */
uinp_fd = open("/dev/uinput", O_WRONLY | O_NDELAY);
if (fcntl(uinp_fd, F_GETFD) == -1)
{
printf("Unable to open /dev/uinput\n");
return -1;
}
memset(&uinp,0,sizeof(uinp)); /* Intialize the uInput device to NULL */
strncpy(uinp.name, "Custom Keyboard", UINPUT_MAX_NAME_SIZE);
uinp.id.bustype = BUS_USB;
// Setup the uinput device
ioctl(uinp_fd, UI_SET_EVBIT, EV_KEY);
ioctl(uinp_fd, UI_SET_EVBIT, EV_REL);
ioctl(uinp_fd, UI_SET_EVBIT, EV_REP);
for (i=0; i < 256; i++) {
ioctl(uinp_fd, UI_SET_KEYBIT, i);
}
/* Create input device into input sub-system */
write(uinp_fd, &uinp, sizeof(uinp));
if (ioctl(uinp_fd, UI_DEV_CREATE))
{
printf("Unable to create UINPUT device.\n");
return -1;
}
return 0;
}
我已经尝试过使用 X11 库的解决方案,如 link 中所述:
Convert ASCII character to x11 keycode
不幸的是,我使用 uinput 创建的键盘使用的键码与 X11 使用的不同。 (我认为我的键盘采用与使用 dumpkeys 命令可以获得的相同的键码)。
肯定可以将 X11 键码转换为我的键盘正确解释的(内核?)键码,但我想保持较低的依赖项数量。
我现在正在尝试使用 linux.h 中描述的 EVIOCGKEYCODE,但我很难理解它是如何工作的,我认为它与我真正想要的相反。
这是一个例子:
int main(int argc, char *argv[]) {
setup_uinput_device();
struct input_keymap_entry mapping;
int i =0;
/* Set the max value at 130 just for the purpose of testing */
for (i=0; i<130; i++) {
mapping.scancode[0] = i;
if(ioctl(fd, EVIOCGKEYCODE_V2, mapping)) {
perror("evdev ioctl");
}
printf("Scancode= %d, Keycode = %d\n",
mapping.scancode[0], mapping.keycode);
}
/* Simple function to destroy the device */
destroy_uinput_device();
return 0;
}
我收到以下错误:"evdev ioctl: Invalid argument"。
我在某处读到它是一种与 PS2 键盘一起使用的旧方法,所以这可能是它不起作用的众多原因之一。
我考虑的最后一个解决方案是在 table 或地图中解析 dumpkeys 的结果,我以后可以使用,但我认为我会遇到性能问题,我不想重新创建可能已经存在的东西。
有什么想法吗?
所以经过大量的尝试,我终于明白内核使用的Keycode和X11使用的Keycode减8是一样的。
我首先必须管理编码。我使用以下代码来管理多字节编码字符(如 €):
char *str = "Test €";
size_t mbslen; /* Number of multibyte characters in source */
wchar_t *wcs; /* Pointer to converted wide character string */
wchar_t *wp;
setlocale(LC_ALL, "");
mbslen = mbstowcs(NULL, str, 0);
if (mbslen == (size_t) -1) {
perror("mbstowcs");
exit(ERROR_FAILURE);
}
wcs = calloc(mbslen + 1, sizeof(wchar_t));
if (wcs == NULL) {
perror("calloc");
exit(ERROR_FAILURE);
}
/* Convert the multibyte character string in str to a wide character string */
if (mbstowcs(wcs, str, mbslen + 1) == (size_t) -1) {
perror("mbstowcs");
exit(ERROR_FAILURE);
}
然后使用我在原始问题中提供的conversion table from ucs to keysym, I managed to translate a widechar array to its corresponding sequences of Keycode, based on the example。
最后一步是为我的 uinput 键盘输入 X11 键码负 8。
我正在尝试在 Debian Stretch 上用 uinput 做一个虚拟键盘,我可以输入字符串,比如 "Toto !",键盘会写这个字符串。 但是,我一直坚持从 C char 到键盘处理的键码的转换。 我没有使用 event-codes.h 中定义的宏,因为我希望我的解决方案适用于计算机的区域设置,并且宏是围绕美国键盘定义的。
这是使用 uinput 创建的设备:
int setup_uinput_device(){
/* Temporary variable */
int i=0;
/* Open the input device */
uinp_fd = open("/dev/uinput", O_WRONLY | O_NDELAY);
if (fcntl(uinp_fd, F_GETFD) == -1)
{
printf("Unable to open /dev/uinput\n");
return -1;
}
memset(&uinp,0,sizeof(uinp)); /* Intialize the uInput device to NULL */
strncpy(uinp.name, "Custom Keyboard", UINPUT_MAX_NAME_SIZE);
uinp.id.bustype = BUS_USB;
// Setup the uinput device
ioctl(uinp_fd, UI_SET_EVBIT, EV_KEY);
ioctl(uinp_fd, UI_SET_EVBIT, EV_REL);
ioctl(uinp_fd, UI_SET_EVBIT, EV_REP);
for (i=0; i < 256; i++) {
ioctl(uinp_fd, UI_SET_KEYBIT, i);
}
/* Create input device into input sub-system */
write(uinp_fd, &uinp, sizeof(uinp));
if (ioctl(uinp_fd, UI_DEV_CREATE))
{
printf("Unable to create UINPUT device.\n");
return -1;
}
return 0;
}
我已经尝试过使用 X11 库的解决方案,如 link 中所述: Convert ASCII character to x11 keycode 不幸的是,我使用 uinput 创建的键盘使用的键码与 X11 使用的不同。 (我认为我的键盘采用与使用 dumpkeys 命令可以获得的相同的键码)。 肯定可以将 X11 键码转换为我的键盘正确解释的(内核?)键码,但我想保持较低的依赖项数量。
我现在正在尝试使用 linux.h 中描述的 EVIOCGKEYCODE,但我很难理解它是如何工作的,我认为它与我真正想要的相反。
这是一个例子:
int main(int argc, char *argv[]) {
setup_uinput_device();
struct input_keymap_entry mapping;
int i =0;
/* Set the max value at 130 just for the purpose of testing */
for (i=0; i<130; i++) {
mapping.scancode[0] = i;
if(ioctl(fd, EVIOCGKEYCODE_V2, mapping)) {
perror("evdev ioctl");
}
printf("Scancode= %d, Keycode = %d\n",
mapping.scancode[0], mapping.keycode);
}
/* Simple function to destroy the device */
destroy_uinput_device();
return 0;
}
我收到以下错误:"evdev ioctl: Invalid argument"。 我在某处读到它是一种与 PS2 键盘一起使用的旧方法,所以这可能是它不起作用的众多原因之一。
我考虑的最后一个解决方案是在 table 或地图中解析 dumpkeys 的结果,我以后可以使用,但我认为我会遇到性能问题,我不想重新创建可能已经存在的东西。
有什么想法吗?
所以经过大量的尝试,我终于明白内核使用的Keycode和X11使用的Keycode减8是一样的。
我首先必须管理编码。我使用以下代码来管理多字节编码字符(如 €):
char *str = "Test €";
size_t mbslen; /* Number of multibyte characters in source */
wchar_t *wcs; /* Pointer to converted wide character string */
wchar_t *wp;
setlocale(LC_ALL, "");
mbslen = mbstowcs(NULL, str, 0);
if (mbslen == (size_t) -1) {
perror("mbstowcs");
exit(ERROR_FAILURE);
}
wcs = calloc(mbslen + 1, sizeof(wchar_t));
if (wcs == NULL) {
perror("calloc");
exit(ERROR_FAILURE);
}
/* Convert the multibyte character string in str to a wide character string */
if (mbstowcs(wcs, str, mbslen + 1) == (size_t) -1) {
perror("mbstowcs");
exit(ERROR_FAILURE);
}
然后使用我在原始问题中提供的conversion table from ucs to keysym, I managed to translate a widechar array to its corresponding sequences of Keycode, based on the example。
最后一步是为我的 uinput 键盘输入 X11 键码负 8。