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.
  • 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