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
Qt 6.11 is out! See what's new in the release blog

Getting key press event for any key

Scheduled Pinned Locked Moved Solved General and Desktop
13 Posts 4 Posters 4.9k 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.
  • 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