Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Getting key press event for any key
Forum Updated to NodeBB v4.3 + New Features

Getting key press event for any key

Scheduled Pinned Locked Moved Solved General and Desktop
13 Posts 4 Posters 1.6k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • EngelardE Offline
    EngelardE Offline
    Engelard
    wrote on last edited by
    #1

    Such an example of global hotkleys works perfectly: http://amin-ahmadi.com/2015/11/14/how-to-use-system-wide-hotkeys-in-your-qt-application/ and it is global, exactly what i need, but that seems to be limited, only one hotkey can be bind.

    How can i get info in my Qt app when some key is pressed and when it's released?

    1 Reply Last reply
    0
    • hskoglundH Offline
      hskoglundH Offline
      hskoglund
      wrote on last edited by
      #2

      You can register more than global hotkey, for example this will register ctrl+alt+E, ctrl+alt+F and ctrl+alt+G from mainwindow.cpp:

      RegisterHotKey(reinterpret_cast<HWND>(winId()),100,MOD_CONTROL | MOD_ALT,'E');
      RegisterHotKey(reinterpret_cast<HWND>(winId()),101,MOD_CONTROL | MOD_ALT,'F');
      RegisterHotKey(reinterpret_cast<HWND>(winId()),102,MOD_CONTROL | MOD_ALT,'G');
      

      To catch them, use the same MainWindow::nativeEvent then you can test either on the hotkey identifer in wParam:

      if ((WM_HOTKEY == msg->message) && (100 == msg->wParam))
      {
          qDebug() << "got ctrl+alt+E";
          return true;
      }
      

      or you can identify them via their virtual keycode

      if ((WM_HOTKEY == msg->message) && ('G' == (UINT) HIWORD(msg->lParam)))
      {
          qDebug() << "got ctrl+alt+G";
          return true;
      }
      

      However, to detect when a global hotkey is pressed down and when it is released, this RegisterHotKey() will not help. Instead you will need to use another API call:

      SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, ::GetModuleHandle(NULL), 0);
      
      EngelardE 1 Reply Last reply
      5
      • hskoglundH hskoglund

        You can register more than global hotkey, for example this will register ctrl+alt+E, ctrl+alt+F and ctrl+alt+G from mainwindow.cpp:

        RegisterHotKey(reinterpret_cast<HWND>(winId()),100,MOD_CONTROL | MOD_ALT,'E');
        RegisterHotKey(reinterpret_cast<HWND>(winId()),101,MOD_CONTROL | MOD_ALT,'F');
        RegisterHotKey(reinterpret_cast<HWND>(winId()),102,MOD_CONTROL | MOD_ALT,'G');
        

        To catch them, use the same MainWindow::nativeEvent then you can test either on the hotkey identifer in wParam:

        if ((WM_HOTKEY == msg->message) && (100 == msg->wParam))
        {
            qDebug() << "got ctrl+alt+E";
            return true;
        }
        

        or you can identify them via their virtual keycode

        if ((WM_HOTKEY == msg->message) && ('G' == (UINT) HIWORD(msg->lParam)))
        {
            qDebug() << "got ctrl+alt+G";
            return true;
        }
        

        However, to detect when a global hotkey is pressed down and when it is released, this RegisterHotKey() will not help. Instead you will need to use another API call:

        SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, ::GetModuleHandle(NULL), 0);
        
        EngelardE Offline
        EngelardE Offline
        Engelard
        wrote on last edited by
        #3

        @hskoglund Oh tnx, before creating this topic i thought that it is all about LPARAM, this holds info about which key in that message.

        But how can i convert that LPARAM back to 'E' or 'G' char? Or QString if it was 'Enter' or 'ALT' code?

        1 Reply Last reply
        0
        • hskoglundH Offline
          hskoglundH Offline
          hskoglund
          wrote on last edited by
          #4

          It's all a throwback to the 80's (think Madonna etc.) WPARAM and LPARAM are the generic names for passing around stuff in Windows messages.
          To convert a LPARAM back to a Windows Virtual Key code:

          UINT vk = (UINT) HIWORD(msg->lParam);
          if ('E' == vk)
          // e key
          if (VK_RETURN == vk)
          // return key
          

          Note: 'ALT' key pressed by itself, i.e. not in combination with any other key, is not possible to detect using RegisterHotKey. The same goes for Left Shift or Left Control etc. To detect those guys you need to descend further into the Windows API, using SetWindowsHookEx(WH_KEYBOARD_LL,...);

          EngelardE 1 Reply Last reply
          3
          • hskoglundH hskoglund

            It's all a throwback to the 80's (think Madonna etc.) WPARAM and LPARAM are the generic names for passing around stuff in Windows messages.
            To convert a LPARAM back to a Windows Virtual Key code:

            UINT vk = (UINT) HIWORD(msg->lParam);
            if ('E' == vk)
            // e key
            if (VK_RETURN == vk)
            // return key
            

            Note: 'ALT' key pressed by itself, i.e. not in combination with any other key, is not possible to detect using RegisterHotKey. The same goes for Left Shift or Left Control etc. To detect those guys you need to descend further into the Windows API, using SetWindowsHookEx(WH_KEYBOARD_LL,...);

            EngelardE Offline
            EngelardE Offline
            Engelard
            wrote on last edited by
            #5

            @hskoglund Okay, i almost done that. Last thing is left - understand how can i put my function as a parameter to SetWindowsHookEx.

            Because this function is a class member - it gives me such an error if i try put it as a parameter:

            reference to non static member function must be called

            I even tried to do like this(myHook is my function):

            SetWindowsHookEx(WH_KEYBOARD_LL, &MainAppW::myHook, NULL, 0)
            

            But it also wrong. How should i pass my function as pointer there?

            mrjjM 1 Reply Last reply
            0
            • EngelardE Engelard

              @hskoglund Okay, i almost done that. Last thing is left - understand how can i put my function as a parameter to SetWindowsHookEx.

              Because this function is a class member - it gives me such an error if i try put it as a parameter:

              reference to non static member function must be called

              I even tried to do like this(myHook is my function):

              SetWindowsHookEx(WH_KEYBOARD_LL, &MainAppW::myHook, NULL, 0)
              

              But it also wrong. How should i pass my function as pointer there?

              mrjjM Offline
              mrjjM Offline
              mrjj
              Lifetime Qt Champion
              wrote on last edited by mrjj
              #6

              @Engelard

              Hi
              It expects the call back to be either a global ( non class function) or that memeber function be
              a static one.
              It cannot use a normal member function.

              so MainAppW::myHook must be static or you must use a global/non member function.
              https://www.learncpp.com/cpp-tutorial/812-static-member-functions/
              DO read about static before just uisng it.
              It has restrictions due to being static.
              Like the function cannot use other not non-static members variables.

              EngelardE 1 Reply Last reply
              1
              • mrjjM mrjj

                @Engelard

                Hi
                It expects the call back to be either a global ( non class function) or that memeber function be
                a static one.
                It cannot use a normal member function.

                so MainAppW::myHook must be static or you must use a global/non member function.
                https://www.learncpp.com/cpp-tutorial/812-static-member-functions/
                DO read about static before just uisng it.
                It has restrictions due to being static.
                Like the function cannot use other not non-static members variables.

                EngelardE Offline
                EngelardE Offline
                Engelard
                wrote on last edited by
                #7

                @mrjj forgot about that, tnx)

                Now when my myHook() static function is correct, everything is working. But i can't really interfere with any part of my app, since those all nonstatic.

                How can i from my static function, send any info to my ui->textBrowser for example?

                jsulmJ 1 Reply Last reply
                0
                • hskoglundH Offline
                  hskoglundH Offline
                  hskoglund
                  wrote on last edited by hskoglund
                  #8

                  Hi, I had the same problem last year when I tested SetWindowsHookEx, I created a small QObject-based helper class that had the callback as a static member function. And then to make that class reachable from inside the KeyboardProc(), I created a static instance of it in my mainwindow.cpp.
                  The program is here:
                  https://gitlab.com/tungware/app/-/tree/main/KeyboardHookTest

                  EngelardE 2 Replies Last reply
                  1
                  • EngelardE Engelard

                    @mrjj forgot about that, tnx)

                    Now when my myHook() static function is correct, everything is working. But i can't really interfere with any part of my app, since those all nonstatic.

                    How can i from my static function, send any info to my ui->textBrowser for example?

                    jsulmJ Offline
                    jsulmJ Offline
                    jsulm
                    Lifetime Qt Champion
                    wrote on last edited by
                    #9

                    @Engelard You can always add a static method to your class which returns a pointer to the instance (see singleton pattern).

                    https://forum.qt.io/topic/113070/qt-code-of-conduct

                    1 Reply Last reply
                    1
                    • hskoglundH hskoglund

                      Hi, I had the same problem last year when I tested SetWindowsHookEx, I created a small QObject-based helper class that had the callback as a static member function. And then to make that class reachable from inside the KeyboardProc(), I created a static instance of it in my mainwindow.cpp.
                      The program is here:
                      https://gitlab.com/tungware/app/-/tree/main/KeyboardHookTest

                      EngelardE Offline
                      EngelardE Offline
                      Engelard
                      wrote on last edited by Engelard
                      #10

                      @hskoglund Thank you for your reply, after i finished my version of this problem i viewed to yours. Frankly, it seems bit more complex then i expected) and some things like:
                      alt text
                      Why dont just type simple 8 in array parameters?)

                      But i get the point anyway, i also tried do with signals at first, but it gave me obvious error ": call to non-static member function without an object argument" so i give up))
                      Completely new for me was that thing:
                      alt text
                      Before i only emited signals in a simple way, like "gotKey(qc);" never had a thought that it could be called from the actual object.

                      And here is how i resolved this, some might say it is foolish or dumb, but that's my first solution to this annoying STATIC issue, i get pretty perfect-looking result and i'm happy with it:

                      In my worker class i created two static variables - bool eventOccured and KBDLLHOOKSTRUCT kbdStruct.
                      bool initialized as FALSE, and worker class have only one function:

                      void worker::threadStart()
                      {
                          while(true)
                          {
                              if(eventOccured)
                              {
                                  sendStruct(kbdStruct);    // <---my signal
                                  eventOccured = false;
                              }
                          }
                      }
                      

                      And here is my lovely STATIC function:

                      LRESULT MainAppW::mySukaHook(int nCode, WPARAM wParam, LPARAM lParam)
                      {
                          if(nCode>=0 && WM_KEYDOWN==wParam)
                          {
                              worker::kbdStruct = *(reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam));
                              worker::eventOccured = true;
                          }
                          return CallNextHookEx(MainAppW::myHook, nCode, wParam, lParam);
                      }
                      

                      that's it folks)

                      1 Reply Last reply
                      0
                      • mrjjM Offline
                        mrjjM Offline
                        mrjj
                        Lifetime Qt Champion
                        wrote on last edited by
                        #11

                        @Engelard said in Getting key press event for any key:

                        Why dont just type simple 8 in array parameters?)

                        If you type 8 directly. then in another place, you also type 8 directly and then someday you might want 10
                        and have to go hunt for all the 8 around in the code.
                        So its always much better to use a const named variable instead of the raw value.

                        1 Reply Last reply
                        2
                        • hskoglundH hskoglund

                          Hi, I had the same problem last year when I tested SetWindowsHookEx, I created a small QObject-based helper class that had the callback as a static member function. And then to make that class reachable from inside the KeyboardProc(), I created a static instance of it in my mainwindow.cpp.
                          The program is here:
                          https://gitlab.com/tungware/app/-/tree/main/KeyboardHookTest

                          EngelardE Offline
                          EngelardE Offline
                          Engelard
                          wrote on last edited by
                          #12

                          @hskoglund Eventually made as in your example, i only can't get one thing. What is better way to connect signals? In your program you did:

                          connect(this,&KeyboardHooker::gotKey,pMainWindow,&MainWindow::keyFromHook);
                          

                          When i always use:

                          connect(this, SIGNAL(sendStruct(tagKBDLLHOOKSTRUCT)), mWindow, SLOT(receiveStruct(tagKBDLLHOOKSTRUCT)));
                          

                          Tried to do your way, it gave me bunch of errors. What is the difference?

                          1 Reply Last reply
                          0
                          • hskoglundH Offline
                            hskoglundH Offline
                            hskoglund
                            wrote on last edited by
                            #13

                            Hi, it's called the old and new syntax and the advantage with the new syntax (without SIGNAL/SLOT) is that most of the unexpected/nasty surprises happen at compile time instead of when you run the app. Which is a good thing :-)

                            1 Reply Last reply
                            1

                            • Login

                            • Login or register to search.
                            • First post
                              Last post
                            0
                            • Categories
                            • Recent
                            • Tags
                            • Popular
                            • Users
                            • Groups
                            • Search
                            • Get Qt Extensions
                            • Unsolved