c++linuxusbasciikeystroke

Can we generate keystrokes using a raw ASCII values using C++ in Linux?


I have barcode data received from a barcode scanner in ASCII format. I need to write a program to emulate keyboard using data received to the computer via the barcode scanner in Linux. I read source code available for USB-HIDKB driver for Linux as well (http://lxr.free-electrons.com/source/drivers/hid/usbhid/usbkbd.c) but I feel I have to do inverse of it. Exactly what I want to do is data is receiving from scanner as a data stream in ASCII format and need to generate key strokes using scanned data. Data reading part is almost done and need to find out a way to convert the ASCII data into key strokes.

example operation:

There is a barcode for CTRL + z (keyboard short cut for undo operation), once scan the barcode data will receive, 08 10 03 00 1a 00 18 0b is received as the data in HEX then data is 1a 00 18 0b. here first 4 bytes are header and remaining is the data portion. now what I need to do is execute an undo operation instead of printing data.

I'm welcome any code example or suggestions have a start to coding. Thanks.


Solution

  • A useful piece of code found [1]: http://www.doctort.org/adam/nerd-notes/x11-fake-keypress-event.html , helped me to get a start to emulate a key strokes using already processed data.

    but this is working only on systems which having the xwindowing systems. This won't work on systems which are base on only terminals. In that case we need to use uinput subsystem to generate a software key press.

    sample program about how to use uinput in Linux can be found here http://thiemonge.org/getting-started-with-uinput

    I wrote a simple program using uinput. This is working.

    example code:

    #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 SetupUinputDevice()
    {
        //  file descriptor for input subsystem device
        int fd_uinput_device;
        // read only, non-blocking, no delay file descriptor
        fd_uinput_device = open("/dev/uinput", O_WRONLY | O_NONBLOCK | O_NDELAY);
        if(fd_uinput_device < 0)
        {
            std::cout << "Error : open file descriptor /dev/uinput : " << strerror(errno) << std::endl; 
            return -1;
        }
        
        // create and initiate uinput_user_dev struct for KeyboardEmulator device
        struct uinput_user_dev dev_key_board_emulator;
        memset(&dev_key_board_emulator, 0, sizeof(uinput_user_dev));
        snprintf(dev_key_board_emulator.name, UINPUT_MAX_NAME_SIZE, "zebra-scanner-hidkb-emulator");
        dev_key_board_emulator.id.bustype = BUS_USB;
        dev_key_board_emulator.id.vendor = 0x01;
        dev_key_board_emulator.id.product = 0x02;
        dev_key_board_emulator.id.version = 1;
        
        /** configure the uinput device to key board events, these will inform to 
         * subsystem  via ioctl calls which type of events will be handled by 
         * the device
         */
        // configure/set key press and release events
        if(ioctl(fd_uinput_device, UI_SET_EVBIT, EV_KEY) < 0)
        {
            std::cout << "Error : ioctl : UI_SET_EVBIT for EV_KEY " << strerror(errno) << std::endl;
            return -1;
        }
        
        // enable set of key board events
        for(int iEvent=0; iEvent < 254; iEvent++)
        {
            if(ioctl(fd_uinput_device, UI_SET_KEYBIT, iEvent) < 0)
            {
                std::cout << "Error : ioctl : UI_SET_KEYBIT for event ID: " << iEvent << " : " << strerror(errno) << std::endl;
            }
        }
        
        // enable synchronization events
        if(ioctl(fd_uinput_device, UI_SET_EVBIT, EV_SYN) < 0)
        {
            std::cout << "Error : ioctl : UI_SET_EVBIT for EV_SYN: " << strerror(errno) << std::endl;
            return -1;
        }
        
        // write the uinput_user_dev structure into the device file descriptor
        if(write(fd_uinput_device, &dev_key_board_emulator, sizeof(uinput_user_dev)) < 0)
        {
            std::cout << "Error : failed to write uinput_user_dev structure into the device file descriptor: " << strerror(errno) << std::endl;
            return -1;
        }
        
        // Create the end point file descriptor for user input device descriptor.
        if(ioctl(fd_uinput_device, UI_DEV_CREATE) < 0)
        {
            std::cout << "Error : failed to create end point for user input device: " << strerror(errno) << std::endl;
            return -1;
        }
        
        return fd_uinput_device;
    }
    
    int CloseUinputDevice(int fd_dev)
    {
        if(ioctl(fd_dev, UI_DEV_DESTROY) < 0)
        {
            std::cout << "Error : ioctl failed: UI_DEV_DESTROY : " << strerror(errno) << std::endl;
            return -1;
        }
        
        if(close(fd_dev) < 0)
        {
            std::cout << "Error : close device file descriptor : " << strerror(errno) << std::endl;
            return -1;
        }
    }
    
    int SendKeyboardEvents(int fd_dev, int event_type, int key_code, int value)
    {
        // input_event struct member for input events
        struct input_event key_input_event;
        memset(&key_input_event, 0, sizeof(input_event));
        
        // set event values
        key_input_event.type = event_type;
        key_input_event.code = key_code;
        key_input_event.value = value;
            
        if(write(fd_dev, &key_input_event, sizeof(input_event)) < 0)
        {
            std::cout << "Error writing input events to the device descriptor: " << strerror(errno) << std::endl;
            return -1;
        }
        return 0;
    }
    
    int main(int argc, char** argv) {
        
        std::cout << "------------key - emulator------------" << std::endl;
        int fd_keyEmulator = SetupUinputDevice();
        sleep(3);
        if(fd_keyEmulator < 0)
        {
            std::cout << "Error in setup file descriptor for uinput device..." << std::endl;
            return 0;
        }
        
        // start to send events
        int returnValue;
        returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_A, 1);
        returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_A, 0);
        returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_B, 1);
        returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_B, 0);
        returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_C, 1);
        returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_C, 0);
        returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_D, 1);
        returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_D, 0);
        returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_E, 1);
        returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_E, 0);
        returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_F, 1);
        returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_F, 0);
        returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_G, 1);
        returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_G, 0);
        returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_H, 1);
        returnValue = SendKeyboardEvents(fd_keyEmulator, EV_KEY, KEY_H, 0);
        
        CloseUinputDevice(fd_keyEmulator);
    
        std::cout << "------------end of program------------" << std::endl;
    
        return 0;
    }
    

    execute the program and switch to a text editor. you will see printing a text there.