0

I found this answer when looking for a way to convert a virtual key to a unicode character. It happened to be for c#, but the same method was available in C++, so I used it. This is my current code:

BYTE keyboard_state[256];
GetKeyboardState(keyboard_state); // Fill the array with the status of all keys.

// vk_code comes from a low level keyboard hook.

WCHAR data[256];
const int res = ToUnicode(vk_code, 0, keyboard_state, data, 256, 0); // Convert to unicode.

char str[256];
wcstombs_s(0, str, data, 256); // Convert wchar to string.
std::cout << str << std::endl; // Logs lowercase regardless of shift/caps lock.

This worked great, except it did not take shift, altgr, or caps lock into account, even though GetKeyboardState() gets the current status of all keys. However, if I manually checked shift with GetKeyState() to see if shift is pressed, and then modified keyboard_state by setting the VK_SHIFT index to 0xff, like in the C# example, it works.

Why is that?

  • So, update **your** code so it does take those keys into account? As described in the [documentation](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646299(v=vs.85).aspx), it retrieves the information for whole keyboard, including those keys.. – Algirdas Preidžius Sep 20 '17 at 15:30
  • Your code does'nt show what you question implies. Care to create a [minimal, complete and verifiable example](https://stackoverflow.com/help/mcve)? – spectras Sep 20 '17 at 15:31
  • @AlgirdasPreidžius What do you mean by update my code? I use the value obtained from that method. – Michael Smith Sep 20 '17 at 15:33
  • It is an eternal question, you cannot reliably call neither GetKeyBoardState() nor GetKeyState() in a console mode app. The values they return are synchronized with the message queue, a console mode app doesn't have one. GetAsyncKeyState() is hack around that, but it is racy and can't solve the problem that GetKeyState solves. You must use ReadConsoleInput(). – Hans Passant Sep 20 '17 at 15:35
  • @HansPassant I am not trying to obtain console input, the console logs are only for debugging. The virtual keys come from a low level keyboard hook. – Michael Smith Sep 20 '17 at 15:38
  • @spectras That code is essentially the whole application, besides a keyboard hook to get the virtual key. I added some comments to try and make it more understandable. – Michael Smith Sep 20 '17 at 15:39
  • 1
    Sure, you cannot do this reliably either in a WH_KEYBOARD_LL hook, keyboard state is a thread-specific property and your thread state is not relevant to what the UI thread in the foreground process sees. That is why WH_KEYBOARD exists. – Hans Passant Sep 20 '17 at 15:42
  • @MichaelSmith Did you read the documentation, I linked to? The returned byte array contains the states for all relevant keys, including shift, ctrl, alt, and caps lock. Not every key in keyboard is a character key. – Algirdas Preidžius Sep 20 '17 at 15:42
  • @AlgirdasPreidžius I am aware. I use the returned byte array. I understand the functionality of the method, and it does not work as I expected, which is why I am asking this question. – Michael Smith Sep 20 '17 at 15:47
  • @HansPassant If `GetKeyboardState()` cannot be reliably used with a LL hook, then why does `GetKeyState()` work for individual keys, like shift. – Michael Smith Sep 20 '17 at 15:53
  • @HansPassant When adding this line of code: `keyboard_state[VK_SHIFT] = GetKeyState(VK_SHIFT);` the issue I described is fixed. I just don't understand why I have to do this when `GetKeyboardState` does the same thing as `GetKeyState` but for all keys. – Michael Smith Sep 20 '17 at 17:02
  • 2
    @MichaelSmith: `GetKeyState()` and `GetKeyboardState()` depend on the input state machine of the **calling thread**. Your hook runs in the thread that **installs it**, not the thread that **processes input** (`WH_KEYBOARD` is triggered by that thread). Your hook is not operating in the right state machine. Read the documentation more carefully... – Remy Lebeau Sep 20 '17 at 17:12
  • @MichaelSmith: [`GetKeyState()`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646301.aspx): "*The key status returned from this function changes as a thread reads key messages from its message queue. The status does not reflect the interrupt-level state associated with the hardware. Use the `GetAsyncKeyState` function to retrieve that information.*" – Remy Lebeau Sep 20 '17 at 17:13
  • @MichaelSmith: [`GetKeyboardState()`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646299.aspx): "*The status does not change as keyboard messages are posted to the thread's message queue, nor does it change as keyboard messages are posted to or retrieved from message queues of other threads. (Exception: Threads that are connected through `AttachThreadInput` share the same keyboard state.)*" – Remy Lebeau Sep 20 '17 at 17:13

0 Answers0