Как генерировать события нажатия клавиш с помощью Подсистемы ввода

Я пишу программу эмулятора клавиатуры в Linux. Сначала я смог отобразить нажатия клавиш в окне X11, но это не работает на виртуальных терминалах, и я попробовал другой способ. Я сослался на http://thiemonge.org/getting-started-with-uinput и попробовал с модулем ядра uinput. В соответствии с руководством, нажатия клавиш могут быть введены как событие uinput, и я написал соответствующий код ниже.

#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 в учебнике.

РЕДАКТИРОВАТЬ:
Я написал другую программу, но ничего не вижу. Я заблудился и любую помощь оценил.

#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

Решение

С вышеуказанными 2 программами все в порядке. Проблема здесь в том, что эта программа создает новое устройство ввода (вероятно, где-то в «/ dev / input»), и что X не может зарегистрировать устройство ввода достаточно быстро, чтобы оно могло извлечь ввод. Простой «сон (1);» (с соответствующим «#include») после создания устройства ввода решает проблему. Чтобы быть (вероятно, ненужным) конкретным, после изменения кода программа будет вести себя как положено, потому что теперь у X было достаточно времени, чтобы понять, что есть новое устройство ввода. Добавьте оператор sleep () после сегмента кода ниже.

    // 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://www.linuxforums.org/forum/ubuntu-linux/161718-its-no-effect-when-using-uinput.html решение берется оттуда.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]