如何使用输入子系统生成按键事件 [英] How to generate key strokes events with the Input Subsystem
问题描述
我正在Linux中编写键盘仿真器程序.首先,我能够将击键渲染到X11窗口中,但这在虚拟终端中不起作用,并尝试了另一种方法.我提到了 http://thiemonge.org/getting-started-with-uinput 并尝试使用uinput内核模块.根据教程的内容,笔划可以作为uinput事件注入,我相应地编写了以下代码.
I am writing a Key board emulator program in Linux, As a start I was able to render key strokes into X11 window but this is not working in virtual terminals and try out a different way. I referred to http://thiemonge.org/getting-started-with-uinput and tried with uinput kernel module. According to the tutorial key strokes can be injected as a uinput event and I wrote below code accordingly.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include <iostream>
#include <time.h>
#include <string>
#define die(str, args...) do { \
perror(str); \
exit(EXIT_FAILURE); \
} while(0)
int main(void)
{
int fd_keyEmulator;
struct uinput_user_dev uidev;
struct input_event ev;
int dx, dy;
int i;
fd_keyEmulator = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if(fd_keyEmulator < 0)
{
std::cout << "error: open : " << strerror(errno) << std::endl;
}
int ret;
//ret = ioctl(fd_keyEmulator, UI_SET_EVBIT, EV_KEY);
//ret = ioctl(fd_keyEmulator, UI_SET_KEYBIT, KEY_D);
//ret = ioctl(fd_keyEmulator, UI_SET_EVBIT, EV_SYN);
sleep(5);
if (ioctl(fd_keyEmulator, UI_SET_EVBIT, EV_KEY) < 0)
{
std::cout << "test 1 ..." << std::endl;
die("error: ioctl");
}
if (ioctl(fd_keyEmulator, UI_SET_KEYBIT, KEY_D) < 0)
{
std::cout << "test 2 ..." << std::endl;
die("error: ioctl");
}
if (ioctl(fd_keyEmulator, UI_SET_EVBIT, EV_REL) < 0)
{
std::cout << "test 3 ..." << std::endl;
die("error: ioctl");
}
memset(&uidev, 0, sizeof(uidev));
snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "keyboard-emulator");
uidev.id.bustype = BUS_USB;
uidev.id.vendor = 0x1;
uidev.id.product = 0x1;
uidev.id.version = 1;
std::cout << "Writing key press..." << std::endl;
if(write(fd_keyEmulator, &uidev, sizeof(uidev)) < 0)
std::cout << "error: write" << strerror(errno) << std::endl;
if(ioctl(fd_keyEmulator, UI_DEV_CREATE) < 0)
std::cout << "error: ioctl" << strerror(errno) << std::endl;
memset(&ev, 0, sizeof(ev));
ev.type = EV_REL;
ev.code = KEY_D;
ev.value = 1;
//ret = write(fd_keyEmulator, &ev, sizeof(ev));
if (write(fd_keyEmulator, &ev, sizeof (struct input_event)) < 0)
die("error: write");
if (write(fd_keyEmulator, &ev, sizeof (struct input_event)) < 0)
die("error: write");
if (write(fd_keyEmulator, &ev, sizeof (struct input_event)) < 0)
die("error: write");
if (write(fd_keyEmulator, &ev, sizeof (struct input_event)) < 0)
die("error: write");
if(ioctl(fd_keyEmulator, UI_DEV_DESTROY) < 0)
std::cout << "error: ioctl" << strerror(errno) << std::endl;
close(fd_keyEmulator);
}
在这种情况下,我要尝试的是为击键'd'生成一个uinput事件.但是通过程序执行,我什么也看不到. 有人可以帮助我验证此程序.在本教程中,也不清楚如何使用uinput子系统注入按键.
in this case, what I am trying is to generate a uinput events for key stroke 'd'. but with the program execution I cannot see anything. can somebody help me to verify this program. It is not clear how to inject a key stroke with uinput subsystem in the tutorial as well.
我编写了另一个程序,但是看不到任何输出.我迷路了,任何帮助我都感激不尽.
I wrote a different program, but I cannot see any output. I got lost and any help appreciate.
#include <cstdlib>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include <iostream>
#include <time.h>
#include <string>
using namespace std;
/*
*
*/
int main(int argc, char** argv) {
// create uinput file descriptor
int fd_key_emulator;
// open file descriptor
fd_key_emulator = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if(fd_key_emulator < 0)
{
std::cout << "error in open : " << strerror(errno) << std::endl;
}
// uinput_user_dev struct for fake keyboard
struct uinput_user_dev dev_fake_keyboard;
memset(&dev_fake_keyboard, 0, sizeof(uinput_user_dev));
snprintf(dev_fake_keyboard.name, UINPUT_MAX_NAME_SIZE, "kb-emulator");
dev_fake_keyboard.id.bustype = BUS_USB;
dev_fake_keyboard.id.vendor = 0x01;
dev_fake_keyboard.id.product = 0x01;
dev_fake_keyboard.id.version = 1;
/**configure the input device to send type of events, inform to subsystem which
* type of input events we are using via ioctl calls.
* UI_SET_EVBIT ioctl request is used to applied on uinput descriptor to enable a type of event.
**/
// enable key press/release event
if(ioctl(fd_key_emulator, UI_SET_EVBIT, EV_KEY))
{
std::cout << "Error in ioctl : UI_SET_EVBIT : EV_KEY : " << strerror(errno) << std::endl;
}
// enable set of KEY events here
if(ioctl(fd_key_emulator, UI_SET_KEYBIT, KEY_A))
{
std::cout << "Error in ioctl : UI_SET_KEYBIT : KEY_A : " << strerror(errno) << std::endl;
}
// enable synchronization event
if(ioctl(fd_key_emulator, UI_SET_EVBIT, EV_SYN))
{
std::cout << "Error in ioctl : UI_SET_EVBIT : EV_SYN : " << strerror(errno) << std::endl;
}
// now write the uinput_user_dev structure into uinput file descriptor
if(write(fd_key_emulator, &dev_fake_keyboard, sizeof(uinput_user_dev)) < 0)
{
std::cout << "Error in write(): uinput_user_dev struct into uinput file descriptor: " << strerror(errno) << std::endl;
}
// create the device via an IOCTL call
if(ioctl(fd_key_emulator, UI_DEV_CREATE))
{
std::cout << "Error in ioctl : UI_DEV_CREATE : " << strerror(errno) << std::endl;
}
// now fd_key_emulator represents the end-point file descriptor of the new input device.
// struct member for input events
struct input_event key_input_event;
memset(&key_input_event, 0, sizeof(input_event));
// key press event for 'a'
key_input_event.type = EV_KEY;
key_input_event.code = KEY_A;
key_input_event.value = 1;
// now write to the file descriptor
if(write(fd_key_emulator, &key_input_event, sizeof(input_event)) < 0)
{
std::cout << "Error write : KEY_A press : " << strerror(errno) << std::endl;
}
memset(&key_input_event, 0, sizeof(input_event));
// EV_SYN for key press event
key_input_event.type = EV_SYN;
key_input_event.code = SYN_REPORT;
key_input_event.value = 0;
// now write to the file descriptor
if(write(fd_key_emulator, &key_input_event, sizeof(input_event)) < 0)
{
std::cout << "Error write : EV_SYN for key press : " << strerror(errno) << std::endl;
}
memset(&key_input_event, 0, sizeof(input_event));
// key release event for 'a'
key_input_event.type = EV_KEY;
key_input_event.code = KEY_A;
key_input_event.value = 0;
// now write to the file descriptor
if(write(fd_key_emulator, &key_input_event, sizeof(input_event)) < 0)
{
std::cout << "Error write : KEY_A release : " << strerror(errno) << std::endl;
}
memset(&key_input_event, 0, sizeof(input_event));
// EV_SYN for key press event
key_input_event.type = EV_SYN;
key_input_event.code = SYN_REPORT;
key_input_event.value = 0;
// now write to the file descriptor
if(write(fd_key_emulator, &key_input_event, sizeof(input_event)) < 0)
{
std::cout << "Error write : EV_SYN for key release : " << strerror(errno) << std::endl;
}
return 0;
}
推荐答案
以上2个程序都没有错.这里的问题是,该程序创建了一个新的输入设备(可能在"/dev/input"中的某处),并且X无法足够快地注册该输入设备,因此它无法获取输入.一个简单的"sleep(1);" (使用适当的"#include")(在输入设备创建后)解决了该问题.具体来说(可能是不必要的),更改代码后程序将按预期方式运行,因为现在X有足够的时间意识到有一个新的输入设备.在下面的代码段之后添加sleep()语句.
There is nothing wrong with above 2 programs. The problem here is, that this program creates a new input device (probably somewhere in "/dev/input") and that X cannot register the input device fast enough so that it can fetch the input. A simple "sleep(1);" (with the appropriate "#include ") after the creation of the input device solves the problem. To be (probably unnecessary) specific, after changing the code the program will behave as expected because now X had ample time to realize there's a new input device. Add the sleep() statement after below code segment.
// create the device via an IOCTL call
if(ioctl(fd_key_emulator, UI_DEV_CREATE))
{
std::cout << "Error in ioctl : UI_DEV_CREATE : " << strerror(errno) << std::endl;
}
// add 1 second sleep.
sleep (1);
// now fd_key_emulator represents the end-point file descriptor of the new input device.
现在程序正在按预期运行. 在 http:中发现了相同的情况: //p>www.linuxforums.org/forum/ubuntu-linux/161718-its-no-effect-when-using-uinput.html 解决方案.
now program is working as expected. Same occurrence found at http://www.linuxforums.org/forum/ubuntu-linux/161718-its-no-effect-when-using-uinput.html solution is taken from there.
这篇关于如何使用输入子系统生成按键事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!