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!
-
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!
@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!
-
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!
@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. -
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!
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.
-
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 = ""; } } } } }
-
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 = ""; } } } } }
@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! :)