Isolate different keyboard input in Widget



  • I am developing an app for the raspberry pi and EGLFS. I have a keyboard connected, as well as a magnetic card reader which reads as keyboard input. Both show up in /dev as hidraw items with random proceeding numbers. I need to isolate the input from both of them so that they get parsed differently because I don't want a card to be able to be read in a QLineEdit, and the input from a card should be read and parsed before anything shows up on the screen. Is there an easy way to isolate these two keyboard inputs and deal with them seperately? Thanks in advance for any help!


  • Moderators

    @nicktlloyd You're probably going to have to go to a raw linux level for that.

    I don't think Qt has anything that allows you to differentiate between devices. I could be wrong, but I just don't recall seeing a feature like that.

    This article will help you handle the device raw though:
    http://www.thelinuxdaily.com/2010/05/grab-raw-keyboard-input-from-event-device-node-devinputevent/

    You could easily use that information and write the code that will deliver that input only to a specific widget that registered for those events.

    Maybe someone else will come along with a better idea or know of a method that Qt has to do this. :)



  • I was worried this would be my only option... My question then becomes: how do I intercept the input and then give it to Qt as separate types of events? Thanks for your help ambershark!


  • Moderators

    @nicktlloyd So you would use the idea from that example I linked. You would put that in it's own thread as it has a while loop. When the data comes in on that loop you would signal an event from your class, we'll call it MyDeviceHandler and anyone registered for that signal would then be able to handle it.

    So something like:

    class MyDeviceHandler : public QObject
    {
       Q_OBJECT
    public:
       void readDevice()
       {
          while (readDevice(...))
          {
             emit keyPressed(key);
          }
       }
    
    signals:
       void keyPressed(int key);
    };
    

    The above is pseudo code, you'll need to actually make it work with the proper logic.

    Also don't forget you need to add that class and specifically the readDevice function to it's own thread or you won't get events and your main thread will lock up.


  • Qt Champions 2016

    You could try to intercept the native events by installing a native event filter. For example take a peek at QCoreApplication::installNativeEventFilter and the QAbstractNativeEventFilter class.


  • Lifetime Qt Champion

    Hi,

    What about adding an udev rule that would maybe create a symbolic link to whatever device is created when you connect your card reader ?



  • Thanks to everyone for your help! I ended up going with ambershark's suggestions. I wrote several threads that constantly watch for input. I had to translate the input from input events, which wasn't particularly fun, but it worked. Again, thank you to everyone!



  • In case anyone is interested, I'll post some code below for the QThread I made.

    namespace KeyboardConstants {
        static const QString keys[] = {"","","1","2","3","4","5","6","7","8","9","0",
                                       "-","=","","","q","w","e","r","t","y","u",
                                      "i","o","p","[","]","","","a","s","d","f",
                                      "g","h","j","k","l",";","'","`","","\\","z",
                                      "x","c","v","B","n","m",",",".","/","","","",
                                      " ","",""};
        static const QString shiftKeys[] = {"","","!","@","#","$","%","^","&","*","(",")",
                                           "_","+","","","Q","W","E","R","T","Y","U",
                                           "I","O","P","{","}","","","A","S","D","F",
                                           "G","H","J","K","L",":","\"","~","","|","Z",
                                           "X","C","V","B","N","M","<",">","?","","",""};
    }
    
    void ccWatcher::run()
    {
        struct input_event ev[1];
        int fevdev = -1;
        int size = sizeof(struct input_event);
        int rd;
        char name[256] = "Unknown";
        bool shift = false;
        QString device = "/dev/input/by-id/XXXXX";
    
    
        fevdev = open(device.toStdString().c_str(), O_RDONLY);
    
        if (fevdev >= 0) {
            ioctl(fevdev, EVIOCGNAME(sizeof(name)), name);
            ioctl(fevdev, EVIOCGRAB, 1);
            while (1)
            {
                if ((rd = read(fevdev, ev, size)) < size) {
                    break;
                }
                // ensure it's a keypress input event
                if (ev[0].type == 1 && ev[0].value == 1) {
                    // 28 and 96 are enter codes
                    if (ev[0].code != 28 && ev[0].code != 96) {
                        // If it's a shift key, enter shift mode
                        if (ev[0].code == 42 || ev[0].code == 54) {
                            shift = true;
                        } else { // otherwise use the code as an index to an array of String characters
                            if (shift) {
                                input.append(KeyboardConstants::shiftKeys[ev[0].code]);
                                shift = false;
                            } else input.append(KeyboardConstants::keys[ev[0].code]);
                        }
                    } else { // Emit a signal out of the thread to by sent as a QEvent to the QWindow in focus
                        emit ccReadin(input);
                        input = "";
                    }
                }
            }
        }
    }
    

  • Moderators

    @nicktlloyd Looks good. You'll probably want to add a way to signal your thread to get out of that loop and exit. Otherwise you will have issues quitting your application and end up having to kill the thread with terminate. Which seems to cause crashes more often than not.

    Is it working out for you though? Did it fix the original issue? EDIT: Nevermind just read your above post and saw that it worked. Great news! :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.