0

I currently have a C/C++ program which uses a barcode scanner as a keyboard, catches the input and does something with it. Here's the relevant parts of code:

int get_InStream() {
        struct timeval tv;
        fd_set fds;
        tv.tv_sec = 0;
        tv.tv_usec = 0;
        FD_ZERO(&fds);
        FD_SET(STDIN_FILENO, &fds);
        select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
        return FD_ISSET(STDIN_FILENO, &fds);
}    

void nonblock(int state) {
    struct termios ttystate;
    tcgetattr(STDIN_FILENO, &ttystate);

    if (state == 1) {
        
        // ~ICANON: turn off canonical mode
        // ~ECHO: not display character
        //~ ttystate.c_lflag &= ~ECHO; // (ICANON & ECHO); 

        tcgetattr( 0, &ttystate);       /* read curr. setting   */
        original_mode       = ttystate; /* remember these   */
        ttystate.c_lflag        &= ~ICANON; /* no buffering     */
        //~ ttystate.c_lflag        &= ~ECHO;   /* no echo either   */
        tcsetattr( 0 , TCSANOW, &ttystate); /* install settings */
        
        //minimum of number input read.
        ttystate.c_cc[VMIN] = 1;
    }
    else if (state == 0) {
        //~ // turn on canonical mode
        //~ ttystate.c_lflag |= ECHO;
        
        tcsetattr(0, TCSANOW, &original_mode);  /* undo -icanon, -echo  */
    }
    // set the terminal attributes.
    tcsetattr(STDIN_FILENO, TCSANOW, &ttystate);
}

bool keyState(int key) { // Uses ASCII table
    bool pressed = false;
    int i = get_InStream(); //   Allows to read from terminal
    if (i != 0) {
        char c = fgetc(stdin);
        
        if (c == (char) key) {              
            pressed = true;
        } else {
            pressed = false;
            char string_key = c;
            
            pthread_mutex_lock(&id_mutex);
            // Append character to content buffer
            strcat(content, string_key);
            pthread_mutex_unlock(&id_mutex);
        }
    }

    return pressed;
}
    
void* get_inputContent(void* arg) {
    
    pthread_detach(pthread_self());
    
    nonblock(1);
    
    while (1) {
        // if this returns True, content contains data
        if (keyState(0x0A)) { // 0x0A in ASCII table corresponds to New Line
            pthread_mutex_lock(&id_mutex);
            
            printf("Read this %d characters through barcode scanner: %s\n", strlen(content), content); //DEBUG
            
           // doSomething()
            
            strcpy(content, "\0"); // empty out content

            pthread_mutex_unlock(&id_mutex);
        }
    }
        
    nonblock(0);
    
    pthread_exit(NULL);
}

Right now this works well as a separate thread from the main program, but if I open another terminal while the main program is running and I leave the focus on the new one, the barcode input is not caught by the thread. So I'd like, either in C/C++ or in Bash, to let's say share the input accross various terminals, so that my thread can use it. Is there any way to do this?

I've searched for various options:

  • another descriptor to use in select()
  • using export in Bash
  • writing to a shared file but I'm not so sure for any of those. Any suggestions?

EDIT: the program is being run on Raspberry Pi OS, previously Raspbian if I'm not mistaken

slim71
  • 27
  • 1
  • 9

1 Answers1

2

This is a XY problem situation right here. Your problem 'X' is

How can I access the keyboard device as which the barcode scanner presents itself to the system regardless of the current state of the system?

But you think, that by solving the problem 'Y'

How can I keygrab input directed to a different terminal?

Problem Y is hard, because it has security implications. Problem X is easy, but its solution depends on the operating system being used.

You mention bash and POSIX style file descriptor. So I'm guessing, that you're on some flavor of Linux. And with that, the problem is easy to solve! Each and every input device presents itself as a evdev device under /dev/input/event<X>. Your barcode scanner will show up there, as well.

You could either implement the evdev protocol yourself. Or just use libinput to do the heavy lifting.

And it being present as an independent input device allows you to do a few things:

  1. Use udev to control which user accounts get access to it.

  2. Use udev to actually detach it from the terminals, so that the barcode scanner can not be used to input (possibly harmful) commands.

0stone0
  • 34,288
  • 4
  • 39
  • 64
datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • ops, forgot to mention my OS! I'll add it to the thread, but I'm on Raspberry Pi OS! as for the rest, I was indeed aware of the security issues, but did not know/think about what you suggested! I'll look into that and hopefully report back my results, thanks! – slim71 Jul 09 '21 at 12:52
  • I've been able to achieve what I wanted thanks to the _libinput_ library, thanks! I had to map my keyboard layout (not a problem with other keyboard since the program will be executed alway on the same machine), but that wasn't so hard! Thank you :) – slim71 Jul 22 '21 at 07:56