2016-11-18 5 views
0

Ich schreibe ein Key Board Emulator Programm in Linux, als Start war ich in der Lage, Tastenstriche in X11 Fenster zu rendern, aber dies funktioniert nicht in virtuellen Terminals und probieren Sie ein anderes aus Weg. Ich bezog mich auf http://thiemonge.org/getting-started-with-uinput und versuchte mit uinput Kernel-Modul. Entsprechend dem Tutorial können Schlüsselstriche als ein Eingabe-Ereignis eingegeben werden und ich schrieb entsprechend unter Code.Wie erzeugt man Tastenanschläge mit dem Input Subsystem

#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); 

} 

in diesem Fall ist das, was ich versuche, ein uinput Ereignisse für Tastenhub ‚d‘ zu erzeugen. aber mit der Programmausführung kann ich nichts sehen. kann mir jemand helfen, dieses Programm zu überprüfen. Es ist nicht klar, wie ein Schlüsselstrich mit dem uinput-Subsystem auch im Tutorial eingefügt wird.

EDIT: Ich schrieb ein anderes Programm, aber ich kann keine Ausgabe sehen. Ich habe mich verlaufen und jede Hilfe zu schätzen wissen.

#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; 
} 

Antwort

0

Es ist nichts falsch mit über 2 Programmen. Das Problem hierbei ist, dass dieses Programm ein neues Eingabegerät erzeugt (wahrscheinlich irgendwo in "/ dev/input") und dass X das Eingabegerät nicht schnell genug registrieren kann, so dass es die Eingabe abrufen kann. Ein einfacher "Schlaf (1);" (mit dem entsprechenden "# include") nach der Erstellung des Eingabegerätes löst das Problem. Um (wahrscheinlich unnötig) spezifisch zu sein, wird sich das Programm nach dem Ändern des Codes wie erwartet verhalten, da X nun genügend Zeit hatte, um zu erkennen, dass es ein neues Eingabegerät gibt. Fügen Sie die Anweisung sleep() nach dem folgenden Code-Segment hinzu.

// 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. 

Jetzt funktioniert das Programm wie erwartet. Gleiches Vorkommen gefunden bei http://www.linuxforums.org/forum/ubuntu-linux/161718-its-no-effect-when-using-uinput.html Lösung wird von dort genommen.