1

I bought a really nice keyboard (logitech G915) that for whatever inane reason doesn't have a numlock indicator. Thus, I'm using Logitech's lighting SDK to make the functionality myself using the key's rgb backlight.

I have an extremely simple console proof of concept that works:

    while (true)
    {
        if (GetKeyState(VK_NUMLOCK) & 0x1)
            LogiLedSetLightingForKeyWithKeyName(LogiLed::KeyName::NUM_LOCK, 0, 100, 100);
        else
            LogiLedSetLightingForKeyWithKeyName(LogiLed::KeyName::NUM_LOCK, 0, 0, 0);
    }

But I don't think it's good to eat up cpu cycles with a perpetual while loop for such a tiny feature. Should I just have it sleep for time (length suggested?) or is there a way to sleep until the system gets a numlock state change or am I simply going about this wrong?

Additionally, I haven't looked into it yet, but I want to make this a background process or a tray application (doesn't matter, just hidden away) so I guess answers should have that limitation in mind if it is one.

Thanks!

Tmsrise
  • 13
  • 2
  • 1
    Global hook. Have you read for example [this](https://stackoverflow.com/q/22975916/7143595)? – MatG Apr 22 '22 at 21:23

1 Answers1

1

At app startup, use GetAsyncKeyState() instead of GetKeyState() to get the key's current state and update the light accordingly.

Then, use SetWindowsHookEx() to install a global WH_KEYBOARD_LL hook to detect whenever the key is pressed afterwards. On each callback event, use the state information provided by the hook, or start an asynchronous task to get the current key state immediately after your hook callback exits (as GetAsyncKeyState() has not been updated yet when the callback is called), and then update the light accordingly.

Alternatively, use the Raw Input API to monitor the keyboard and receive WM_INPUT window messages on each key press. And then get the key's current state and update the light accordingly.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Thanks! I just got back to this. GetKeyState() also gives the toggle state of a key (if applicable) so I don't necessarily see the point in using GetAsyncKeyState? – Tmsrise May 16 '22 at 23:05
  • Also, how do I go about doing something after the hook callback exits? It's not being called through normal means so I can't just call a function afterwards..? I have it working by calling GetKeyState in the callback, but there's a very tiny delay that I hope your clarifications might solve. – Tmsrise May 16 '22 at 23:12
  • @Tmsrise `GetKeyState()` is thread-specific. Each thread maintains its own keyboard state table, that is updated when the thread processes keyboard messages from its own message queue, and that state can't be queried across thread boundaries. Whereas `GetAsyncKeyState()` is not tied to any particular thread, it gets the actual hardware state instead. – Remy Lebeau May 16 '22 at 23:45
  • @Tmsrise there are many ways to call a function asynchronously. Start a new thread to call it. Post a message to a window in another thread. Use an APC or Completion Port callback that runs in another thread. Etc – Remy Lebeau May 16 '22 at 23:59
  • GetAsyncKeyState() doesn't return toggle state though? I suppose I could get around that, but not nicely. – Tmsrise May 17 '22 at 01:33
  • @Tmsrise no, `GetAsyncKeyState()` does not provide a toggle state. But the keyboard hook will give you every key up/down event, so if you get the initial toggle state at startup from elsewhere, you can use the hook events to keep track of the toggle state changes. – Remy Lebeau May 17 '22 at 04:38
  • That's along the lines of what I was thinking, but GetAsyncKeyState doesn't guarantee that some other process won't steal the bit change. While it probably works 99% of the time, it feels like bad coding practice to hope that the 2 states stay synchronized instead of monitoring toggle state directly. Also, could you clarify why GetKeyState being thread specific matters? I create a thread each time I'm callling the function to GetKeyState and apply LED's and I haven't run into issues other than admin processes, which is solved by elevating perms. The delay I mentioned was solved via new threads – Tmsrise May 17 '22 at 14:39