Results 1 to 4 of 4

Thread: keys map (cross platform)

  1. #1
    Join Date
    Feb 2017
    Posts
    7
    Thanks
    4
    Qt products
    Qt5
    Platforms
    Windows

    Default keys map (cross platform)

    Hello,
    I'm working on a cross platform application in which user must be able to check whether a particular key is pressed or not.

    So, I create a map of keys like this:
    Qt Code:
    1. std::unordered_set<int> pressedKeys;
    To copy to clipboard, switch view to plain text mode 
    ... and store each key when is pressed
    Qt Code:
    1. void MyAapp::keyPressEvent(QKeyEvent *e) {
    2. e->accept();
    3. mymutex->lock();
    4. qDebug() << "+key:" << e->key() << "=" << e->text() <<", nativeVirtualKey:" << e->nativeVirtualKey() <<", isAutoRepeat:" << e->isAutoRepeat() <<", modifiers" << e->modifiers();;
    5. if(!e->isAutoRepeat()){
    6. // Note that if the event is a multiple-key compressed event that is partly due to auto-repeat,
    7. // isAutoRepeat() function could return either true or false indeterminately.
    8. if( e->modifiers() & Qt::ShiftModifier )
    9. {
    10. pressedKeys.insert(Qt::Key_Shift);
    11. }else{
    12. pressedKeys.erase(Qt::Key_Shift);
    13. }
    14. if( e->modifiers() & Qt::ControlModifier )
    15. {
    16. pressedKeys.insert(Qt::Key_Control);
    17. }else{
    18. pressedKeys.erase(Qt::Key_Control);
    19. }
    20. if( e->modifiers() & Qt::AltModifier )
    21. {
    22. pressedKeys.insert(Qt::Key_Alt);
    23. }else{
    24. pressedKeys.erase(Qt::Key_Alt);
    25. }
    26. if( e->modifiers() & Qt::MetaModifier )
    27. {
    28. pressedKeys.insert(Qt::Key_Meta);
    29. }else{
    30. pressedKeys.erase(Qt::Key_Meta);
    31. }
    32. pressedKeys.insert(e->key());
    33. }
    34. mymutex->unlock();
    35. }
    To copy to clipboard, switch view to plain text mode 
    ... and delete a key when key is released:
    Qt Code:
    1. void MyApp::keyReleaseEvent(QKeyEvent *e) {
    2. e->accept();
    3. mymutex->lock();
    4. qDebug() << "-key:" << e->key() << "=" << e->text() <<", nativeVirtualKey:" << e->nativeVirtualKey() <<", isAutoRepeat:" << e->isAutoRepeat() <<", modifiers" << e->modifiers();;
    5. if(!e->isAutoRepeat()){
    6. pressedKeys.erase(e->key());
    7. if( e->modifiers() & Qt::ShiftModifier )
    8. {
    9. pressedKeys.insert(Qt::Key_Shift);
    10. }else{
    11. pressedKeys.erase(Qt::Key_Shift);
    12. }
    13. if( e->modifiers() & Qt::ControlModifier )
    14. {
    15. pressedKeys.insert(Qt::Key_Control);
    16. }else{
    17. pressedKeys.erase(Qt::Key_Control);
    18. }
    19. if( e->modifiers() & Qt::AltModifier )
    20. {
    21. pressedKeys.insert(Qt::Key_Alt);
    22. }else{
    23. pressedKeys.erase(Qt::Key_Alt);
    24. }
    25. if( e->modifiers() & Qt::MetaModifier )
    26. {
    27. pressedKeys.insert(Qt::Key_Meta);
    28. }else{
    29. pressedKeys.erase(Qt::Key_Meta);
    30. }
    31. }
    32. mymutex->unlock();
    33. }
    To copy to clipboard, switch view to plain text mode 

    Everything is perfect.
    To be a cross platform I use Qt Key-enum values for keys (http://doc.qt.io/qt-4.8/qt.html#Key-enum).

    The problem appears when I press a sequence like this:
    (notation: + is keyPressEvent, - is keyReleaseEvent):
    user press SHIFT
    +key: 16777248 = "" , nativeVirtualKey: 16 , isAutoRepeat: false , modifiers QFlags<Qt::KeyboardModifiers>(ShiftModifier)
    user press "2", but because SHIFT is pressed, then Qt returns Qt::Key_At "@"
    +key: 64 = "@" , nativeVirtualKey: 50 , isAutoRepeat: false , modifiers QFlags<Qt::KeyboardModifiers>(ShiftModifier)
    -key: 64 = "@" , nativeVirtualKey: 50 , isAutoRepeat: true , modifiers QFlags<Qt::KeyboardModifiers>(ShiftModifier)
    ... keep pressing SHIFT+2 = "@" but in fact user press "2" key
    +key: 64 = "@" , nativeVirtualKey: 50 , isAutoRepeat: true , modifiers QFlags<Qt::KeyboardModifiers>(ShiftModifier)
    release SHIFT
    -key: 16777248 = "" , nativeVirtualKey: 16 , isAutoRepeat: false , modifiers QFlags<Qt::KeyboardModifiers>(NoModifier)
    now the key is "2" but the original key "@"is in map as pressed
    +key: 50 = "2" , nativeVirtualKey: 50 , isAutoRepeat: false , modifiers QFlags<Qt::KeyboardModifiers>(NoModifier)
    -key: 50 = "2" , nativeVirtualKey: 50 , isAutoRepeat: true , modifiers QFlags<Qt::KeyboardModifiers>(NoModifier)
    ...
    I do not like the fact that Qt return "@" as a key instead of "2".
    One of the flaw is in the example above: the "@" key remains in pressedKeys map as pressed even after the key is actually released.
    I want to receive the real key, not the combination.
    And I need in cross platform way.

    Remember that user must be able to check if a specific key is pressed. For this I check if key is in pressedKeys map and return true/false. User use Key-enum values.

    Any ideas?
    Thanks!

  2. #2
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: keys map (cross platform)

    I do not like the fact that Qt return "@" as a key instead of "2".
    Sorry, but you didn't press "2". You pressed "Shift + 2", and the text for that is "@" on your keyboard. Qt (and every other UI system that will track key actions) told you correctly. Too bad if you don't agree with what the OS tells you. Did you notice that Qt reports "native virtual key" as being "50" in both cases though? That's an ASCII "2". The "Shift" modifier turns it into a "@".

    And I need in cross platform way.
    Maybe you should go online and look at some pictures of keyboards for other countries besides your own. You'll be surprised to learn that not all of them look like the keyboard in front of you. Different letters and symbols on different physical keys for almost every different language. Ergonomic keyboards often have different layouts than standard keyboards, even for the same language and country. So, you can't be guaranteed that any keyboard except your own will report "@" for "Shift + 2".

    So, Qt is already giving you "cross-platform" as well as "cross-keyboard" and "cross-country".

    One of the flaw is in the example above: the "@" key remains in pressedKeys map as pressed even after the key is actually released.
    Then you need to fix the logic flaw in your code. Your combinations of if clauses in the two key events don't correctly handle all of the possibilities.

    In this particular example, Qt has told you that the "@" key was pressed with the "Shift" modifier. If you then release the Shift key, then the shift condition no longer applies. It also told you that autorepeat for this key is true, so that additionally tells you that if you keep the key pressed, you will get another key press event from it eventually at the end of the autorepeat delay timeout. You got that one as well, except that before the autorepeat delay timed out, you released the Shift key, so it gets reported (correctly) as a "2". You never got a key release for the "@" key because you didn't release it.

    So your logic needs to take into account the modifiers that were in effect when a key was pressed, whether the key is autorepeat, and what the native virtual key is for that key. If you get another key press event for the same native key and there wasn't a corresponding release event for that native key in between, then you know that is an autorepeat. And then if you can't find a match for the new e->text() in the map, you delete whichever entry is in there that has the same native key value instead, and add the new one.

    The fact that Qt reports both the key text and native value allow you to handle exactly this situation.
    Last edited by d_stranz; 16th September 2017 at 05:49.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  3. The following user says thank you to d_stranz for this useful post:

    junior-root (16th September 2017)

  4. #3
    Join Date
    Feb 2017
    Posts
    7
    Thanks
    4
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: keys map (cross platform)

    First of all, I thank for the answer and the time spent for me.
    I also noticed that nativeVirtualKey() returns the same value in both cases: SHIFT+2="2" and key "2".
    I also played with several layouts for keyboard before that, and I saw that in many cases nativeVirtualKey() is the same (the same physical key is pressed), but the key() value is different.
    The solution is the same as you say: to keep both values in map (key() and nativeVirtualKey()) and to ckeck for one of those values when a key is pressed or released.
    Ok.

    The problem is: inside the event keyPressEvent() or keyReleaseEvent() I can get the corresponding nativeVirtualKey... but:

    Quote Originally Posted by junior-root View Post
    Remember that user must be able to check if a specific key is pressed. For this I check if key is in pressedKeys map and return true/false. User use Key-enum values.
    In this case user wants to check if key "2" is pressed.
    To do this, user's input is the value QT::Key_2 (50).
    But if you press SHIFT+2 and then release it, you will never get the QT::Key_2 value, even the fact that you pressed the key. You wil receive only QT::Key_At value.
    The solution may be the one pointed above and keep both values: key() and keyPressEvent()...

    But to do this I need to know the corresponding nativeVirtualKey value of user input. Ok, inside keyPressEvent() or keyReleaseEvent() is easy to convert a key() into nativeVirtualKey(). How can I convert a Qt::Key (eg. Qt::Key_At) into nativeVirtualKey code outside of a keyPressEvent() or a keyReleaseEvent()?

  5. #4
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: keys map (cross platform)

    But to do this I need to know the corresponding nativeVirtualKey value of user input.
    The trouble is, I don't think the native virtual key codes are platform-independent. The VK_xxx codes on Windows that are returned as the "native virtual key code" in Qt are Windows-specific and defined by Microsoft. You might want to read this discussion of the problem.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  6. The following user says thank you to d_stranz for this useful post:

    junior-root (16th September 2017)

Similar Threads

  1. qt is cross-platform to everting?
    By joaovictor in forum Newbie
    Replies: 2
    Last Post: 9th March 2017, 22:12
  2. Are there any other cross-platform framework like Qt?
    By grayfox in forum Qt Programming
    Replies: 1
    Last Post: 11th July 2011, 18:19
  3. Replies: 1
    Last Post: 11th November 2010, 01:31
  4. Cross-platform GUI app
    By rockballad in forum Qt Programming
    Replies: 2
    Last Post: 21st April 2010, 08:38
  5. Qt's Cross-Platform Functionality
    By winston2020 in forum Qt Programming
    Replies: 3
    Last Post: 18th January 2009, 19:31

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.