3

I am trying to get a small app that will continuously simulate UP (↑ arrow key) while another key is pressed, in my case Right CTRL.

The code I wrote however, will only send one UP for each press - and while I keep Right CTRL pressed, it will only send one UP and stop.

I want to mention that this code is built entirely from documentation I found online, I have never written anything in C++ ever before, or any other language so any suggestions would greatly help me. I initially tried doing this while CAPS LOCK was active, but I found that getting the key state (on/off) did not work for me at all, no matter what I tried.

int main()
{
  // This structure will be used to create the keyboard
  // input event.
  INPUT ip;

  // Pause for 1 seconds.
  Sleep(1000);

  // Set up a generic keyboard event.
  ip.type = INPUT_KEYBOARD;
  ip.ki.wScan = 0; // hardware scan code for key
  ip.ki.time = 0;
  ip.ki.dwExtraInfo = 0;

  while(1){
      if(GetAsyncKeyState(VK_RCONTROL))
      {
            // Press the "UP arrow" key
            ip.ki.wVk = 0x26; // virtual-key code for the "UP arrow" key
            ip.ki.dwFlags = 0; // 0 for key press
            SendInput(1, &ip, sizeof(INPUT));

            Sleep(50);

            // Release the "UP arrow" key
            ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
            SendInput(1, &ip, sizeof(INPUT));

            Sleep(50);
      }
  }

  // Exit normally
  return 0;
}  
Christophe
  • 68,716
  • 7
  • 72
  • 138
Dacul
  • 33
  • 3

1 Answers1

1

GetAsyncKeyState does not return a boolean about whether the key is up or down, but rather a SHORT (a 16 bit integer, usually literally short)

If the function succeeds, the return value specifies whether the key was pressed since the last call to GetAsyncKeyState, and whether the key is currently up or down. If the most significant bit is set, the key is down, and if the least significant bit is set, the key was pressed after the previous call to GetAsyncKeyState.

So what does this mean? The "most significant bit" in hardware is implementation defined (Which end of a bit field is the most significant bit?), but we can treat everything as if the "leftmost" bit is significant (1000 versus 0001).

So we can test for keydown with a bitmask.

I've written a small demo program to help you visualize all this:

std::cout << "number of bytes in a short: " << sizeof(short) << std::endl;
short i = 0;
i = 1 << (sizeof(short)*8-1); // use bit shifting to set most significant bit
std::cout << "Initial value of i: " << i << std::endl;
std::cout << "Initial value of i as hex: " << std::hex << i << std::endl;
std::cout << "Is most significant bit set?\n";
short bitmask = 0x8000;
std::cout << std::boolalpha << ((bitmask & i) != 0) << std::endl;
std::cout << "Unsetting MSB\n";
i = 0x0000;
std::cout << "Is most significant bit set?\n";
std::cout << std::boolalpha << ((bitmask & i) != 0) << std::endl;

This demo shows how you can apply a bitmask to a short to ask if the most significant bit is set.

GetAsyncKeyState gives you the additional ability to check if the key was pressed since last check. For a simpler call, check out GetKeyState

Community
  • 1
  • 1
AndyG
  • 39,700
  • 8
  • 109
  • 143
  • `GetAsyncKeyState` uses the most significant bit to represent the current state of the key: "If the function succeeds, the return value specifies whether the key was pressed since the last call to GetAsyncKeyState, **and whether the key is currently up or down.**" – Miles Budnek Nov 28 '16 at 19:35
  • @MilesBudnek: the "and" here is a logical and I believe. Hence, if they key was not pressed since the last call, the function will always return false no matter the state of the key. – AndyG Nov 28 '16 at 19:56
  • 2
    Nope, just did a quick test. It returns 0x8001 right after I press the key, and then 0x8000 until I release it. – Miles Budnek Nov 28 '16 at 19:58
  • @AndyG thanks a lot for pointing me in the right direction. I actually got to do exactly what I wanted from the get go, which is use a toggled state. I replaced it with this bit if(GetKeyState(VK_CAPITAL) == 1 ) – Dacul Nov 28 '16 at 20:16
  • @MilesBudnek: Thank you very much for your thoroughness! I've updated the post. I hope you find it more accurate. – AndyG Nov 28 '16 at 20:39
  • @Dacul: I thought you wanted to hold the key down manually and not toggle it? – AndyG Nov 28 '16 at 21:36
  • @AndyG I initially tried getting it to work while toggled, but since I couldn't get it to work I had resigned myself to making it work while key was down manually. But using your answer I actually got it to work with the toggle on/off as well, so really, really appreciate it! – Dacul Dec 04 '16 at 13:02