PDA

View Full Version : Yet another eventFilter question



ls4f
13th September 2011, 12:50
Ok, so I`ve gone through all the documentation I could find, and even looked at some Qt sources, but so far haven`t found a 'clean' way to emulate 'KeyPreview' (for those of you that have ever used WinForms).

What is the case - I have a project, that should be able to handle input from keyboard emulating devices (barcode scanners, card readers and so on). The trick is the user could technically input the stuff from the keyboard, so I monitor the interval between keypresses (and hope I don`t meet someone who can type a whole sentence within less than a second :) ). My main problem is that I should be able to intercept every keypress (no matter which widget is currently focused) and I should be doing it 100% transparently.

What I`ve tried so far is to recursively install an event filter for each child of the MainWindow, but it has the really nasty side effect that I handle the keypress up to 5 times. To make things even more fun - the 'eat/don`t eat' behavior of some widgets seems to change when I install event filter on them ...

I though about adding an eventFilter to the QApplication object, but that looks like an overkill.

Is there any way to pass every event for every child of a MainWindow through a single function, and to do so just once, without some thorough additional checking? If not - I would appreciate any ideas on the 'proper' way to do this.

wysota
13th September 2011, 13:47
What is "KeyPreview"? About fast typing -- what if one pastes text from the clipboard?

ls4f
13th September 2011, 16:21
Sorry if I didn`t explain the idea properly.
MSDN Defines KeyPreview as :

When this property is set to true, the form will receive all KeyPress, KeyDown, and KeyUp events. After the form's event handlers have completed processing the keystroke, the keystroke is then assigned to the control with focus ...
The difference between this and eventFilters is that the KeyPress event is fired once (and only once) no matter how deep the focused child is within the UI tree (meaning I don`t have any logic to check where I should apply the event filter in order not to handle something twice).

Actually I am not concerned with people trying to fool my soft. If someone can type '20006440\n' (which is the barcode of my vitamns for example, followed by Enter) in 300ms - I am perfectly fine with handling it as if it came from the input device. The idea is to handle automatically the stuff that has actually been input by any of those types of devices (it`s not for security purposes but for simple convenience).
Plus - I am actually porting a .Net project of mine, which is modeled after a DOS-based project (meaning some of my users have had about 20 years to get used to this exact way of work ...).

If there isn`t a Qt analog to this - I will take the time to implement it my self, but I did want to hear any opinions on how that should happen.

wysota
13th September 2011, 16:27
I still don't understand what KeyPreview is and what you want to use it for. I don't understand why a form would want to access input events for another widget. Maybe you should explain what is the final effect you want to obtain without focusing on how you are trying to obtain it.

ls4f
13th September 2011, 17:28
Ok, no 'programming' this time :
The Keyboard is not the only thing entering data in the Keyboard Controller.
Meaning if I were to read

1909831
0928*!#
for example, in a normal input there would be no actual way to tell whether this data came from a User or a keyboard emulating device, right?
What I`m looking for is an easy (and cross-platform btw) way to look at all the keypresses so that I can know the interval between them and copy the ones are too close (for example less than 40msec appart) in a different buffer for some 'special handling'. In the example I gave - assuming the first line was input (with the Return at the end) within 100msec, I want to process '1909831' as some special input and I don`t really care about the '0928*!#' part, since it was input for a total of say 4 sec. The problem with that is that I have a ComboBox, a TabWidget, a TableView and a bunch of other stuff on the MainWindow and the user could have focused on any one of them - meaning I can`t just listen on a specific control.

I am currently doing this in another project by enabling http://msdn.microsoft.com/en-us/library/system.windows.forms.form.keypreview.aspx and handling the main window`s 'key_pressed event'. However, I`m trying to port it to Qt (mostly because of the cross-platform features) and preserve the old user interaction as much as possible.

Hope I explained it right this time, and thanks for the time.

wysota
13th September 2011, 22:05
Ok, but this doesn't explain why you want to handle those events that are very close to each other in a special way. In my opinion, whatever the reason is, it is prone to errors. If you really want to do that, create a dedicated "listener" object and make it intercept events from all the objects you want to spy on. You can even listen to focus changes (QApplication::focusChanged() signal) to dynamically install and uninstall the event filter. But personally I don't think such approach is a good idea (whatever the reson of it might be).

ls4f
14th September 2011, 09:56
First of all - Thanks for the idea! Seems to be exactly what I was looking for (since it took 2 lines of code to implement)

void MainWindow::FocusChanged(QWidget * qwOld, QWidget* qwNew)
{
if(qwOld)qwOld->removeEventFilter(this);
if(qwNew) qwNew->installEventFilter(this);
}
Well it could use a check if the user is in this exact window, but thats details (never would have thought of looking for focus change signal on the qApp lvl though ...). My problem with listening on all possible widgets was that proper propagation of events is not as easy to implement (therefore I could miss/duplicate a keypress if I get it wrong).

As for the reason (in case it matters) - the project is a Pos for shops/supermarkets. Most of the competition has a special textedit or a key the user should press before any 'special' input, which frankly seemed lame to me even before I started coding. The current solution, as I said, came from a DOS project (with better gui than Windows 3.1 to be honest :) ), which listens for every possible input there is, thus freeing the user from having to focus a specific control.

Thanks again :)

wysota
14th September 2011, 13:29
The point is I don't understand what is "special" in this "special input". As far as I know barcode scanners generate regular key events so if the right element has the focus, proper input from the scanner will reach it. If you want to ignore the focus, then just don't use it, set the focus policy on the window itself and be done with it. I don't think calculating delays between key events is a good idea. It might be much better to detect patterns or markers in the input you get, it's much more foolproof.

ls4f
14th September 2011, 14:50
The point is I don't understand what is "special" in this "special input". As far as I know barcode scanners generate regular key events so if the right element has the focus, proper input from the scanner will reach it
Well the 'special' part is anything else is on the UI but I have to lookup barcodes in the db (meaning an SQL query, a possible choice dialog and so on).

Again - my point is not to have a specific element for that input :) And if the user is focused say on the TableView - he might type something like 'coca' from they keyboard, mark it or whatever, and then immediately use the barcode scanner (without defocusing the TableView). Since I know there is a way to handle that case - I was looking for it :)

If you happen to visit Bulgaria - I`d be happy to buy you a beer and show you first hand :rolleyes: