Перехватывать ввод из другой оболочки

#c #bash #input #barcode-scanner

Вопрос:

В настоящее время у меня есть программа на C/C , которая использует сканер штрих-кода в качестве клавиатуры, улавливает ввод и что-то с ним делает. Вот соответствующие части кода:

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

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

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

        tcgetattr( 0, amp;ttystate);       /* read curr. setting   */
        original_mode       = ttystate; /* remember these   */
        ttystate.c_lflag        amp;= ~ICANON; /* no buffering     */
        //~ ttystate.c_lflag        amp;= ~ECHO;   /* no echo either   */
        tcsetattr( 0 , TCSANOW, amp;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, amp;original_mode);  /* undo -icanon, -echo  */
    }
    // set the terminal attributes.
    tcsetattr(STDIN_FILENO, TCSANOW, amp;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(amp;id_mutex);
            // Append character to content buffer
            strcat(content, string_key);
            pthread_mutex_unlock(amp;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(amp;id_mutex);
            
            printf("Read this %d characters through barcode scanner: %sn", strlen(content), content); //DEBUG
            
           // doSomething()
            
            strcpy(content, ""); // empty out content

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

Прямо сейчас это хорошо работает как отдельный поток от основной программы, но если я открою другой терминал во время работы основной программы и оставлю фокус на новом, ввод штрих-кода не будет пойман потоком.
Поэтому я хотел бы, либо в C/C , либо в Bash, скажем, разделить входные данные между различными терминалами, чтобы мой поток мог их использовать. Есть ли какой-нибудь способ сделать это?

Я искал различные варианты:

  • еще один дескриптор для использования в select()
  • использование export в Bash
  • запись в общий файл, но я не уверен ни в одном из них. Есть какие-нибудь предложения?

РЕДАКТИРОВАТЬ: программа запускается на ОС Raspberry Pi, ранее Raspbian, если я не ошибаюсь

Комментарии:

1. ОС Raspberry Pi, предыдущая версия. Raspbian-это разновидность GNU/Linux.

Ответ №1:

Это проблемная ситуация XY прямо здесь. Ваша проблема » X » заключается в том, что

Как я могу получить доступ к клавиатурному устройству, в качестве которого сканер штрих-кода представляется системе независимо от текущего состояния системы?

Но вы думаете, что, решив проблему «У»

Как я могу ввести keygrab, направленный на другой терминал?

Проблема Y сложна, потому что она имеет последствия для безопасности. Проблема X проста, но ее решение зависит от используемой операционной системы.

Вы упомянули файловый дескриптор в стиле bash и POSIX. Так что я предполагаю, что вы используете какой-то вид Linux. И с этим проблему легко решить! Каждое устройство ввода представляет себя как evdev устройство под /dev/input/event<X> . Ваш сканер штрих — кода также появится там.

Вы можете либо реализовать evdev протокол самостоятельно. Или просто используйте libinput для выполнения тяжелой работы.

И то, что он присутствует в качестве независимого устройства ввода, позволяет вам делать несколько вещей:

  1. Используйте udev, чтобы контролировать, какие учетные записи пользователей получают к нему доступ.
  2. Используйте udev, чтобы фактически отсоединить его от терминалов, чтобы сканер штрих-кода нельзя было использовать для ввода (возможно, вредных) команд.

Комментарии:

1. оперативники, забыли упомянуть мою операционную систему! Я добавлю это в поток, но я на Raspberry Pi OS! что касается остального, я действительно был осведомлен о проблемах безопасности, но не знал/не думал о том, что вы предложили! Я изучу это и, надеюсь, сообщу о своих результатах, спасибо!

2. Я смог добиться того, чего хотел, благодаря библиотеке libinput , спасибо! Мне пришлось сопоставить раскладку клавиатуры (не проблема с другой клавиатурой, так как программа всегда будет выполняться на одной и той же машине), но это было не так сложно! Спасибо вам 🙂