8

I'm making a front end for various emulators and triggering their various functionality such as save/load state, save screenshot, but with a unified interface. FS-UAE annoyingly uses "Print Screen" as its screenshot key, and I'd like to avoid the user having to change emulators from their default hotkey settings.

I've managed to simulate any key press I want with SendInput, except for the "Print Screen" key.

I haven't had any luck with using virtual key codes, I think that doesn't work with full screen applications. Hence that part of the code is commented out. (EDIT: better explanation - Virtual Key codes are ignored by DirectInput software)

Using scan codes, I can get any key to press - almost. Print Screen seems to be the odd one out.

Here's the reference I'm using for the scan codes; https://msdn.microsoft.com/en-us/library/aa299374(v=vs.60).aspx

Below is the minimum viable code to reproduce the problem. If you run it, press a key then quickly switch to notepad and wait 2 seconds, it should press the letter "q" into notepad, then quit.

Change the scan code from 0x10 (q) to 0x37 (Print Screen), be sure to do it in both places - KEY DOWN, and KEY UP.

Now run it again, press a key and wait. To see if Print Screen worked, open MS Paint or whatever and press CTRL+V, see if you get a screenshot of your desktop. It doesn't work! But if you manually press Print Screen, and CTRL+V into MS Paint, it will work.

Why doesn't the Print Screen key work?

#include "stdafx.h"

//For create process & keyboard codes
#include <windows.h>
#include <stdio.h>
#include <tchar.h>

int main()
{
    INPUT ip = {};

    ip.type = INPUT_KEYBOARD;
    ip.ki.wScan = 0;
    ip.ki.wVk = 0;
    ip.ki.dwExtraInfo = 0;
    ip.ki.dwFlags = 0;

    printf("Press a key, then taskswitch.\n");
    system("pause");
    Sleep(2000);

    //KEY DOWN
    ip.ki.wScan = 0x10; //0x37 PrintScreen, 0x10 Q
    ip.ki.dwFlags = KEYEVENTF_SCANCODE;
    //ip.ki.wVk = VK_SNAPSHOT;
    //ip.ki.dwFlags = 0;
    SendInput(1, &ip, sizeof(INPUT));

    //KEY UP
    ip.ki.wScan = 0x10;
    ip.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP; 
    //ip.ki.wVk = VK_SNAPSHOT;
    //ip.ki.dwFlags = KEYEVENTF_KEYUP; 
    SendInput(1, &ip, sizeof(INPUT));

    printf("Done.\n");
    system("pause");
    return 0;
}
Domarius
  • 413
  • 1
  • 3
  • 13
  • Yes indeed, that is the "scan code" approach I went with as virtual keys are ignored by Direct Input. Note the use of ip.ki.dwFlags = KEYEVENTF_SCANCODE; and ip.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP; – Domarius Jan 24 '18 at 12:36
  • 4
    Maybe not root of the issue, but the code contains the [classical bug of calling `SendInput` multiple times for a series of input events instead of doing a single call, passing in an array](https://stackoverflow.com/questions/46744894/is-it-a-bug-to-pass-a-single-element-array-to-sendinput). – zett42 Jan 24 '18 at 13:09
  • 1
    `VK_SNAPSHOT` is `0x2C`, not `0x37` – Barmak Shemirani Jan 24 '18 at 16:25
  • @BarmakShemirani I think you might be talking about the Virtual Key code, which I can't use with DirectInput software (i.e. emulators), as I said, I had to switch to Scan Codes to get anything to work. – Domarius Jan 24 '18 at 20:32
  • @zett42 Thanks, I'd like to do it the "right" way even though I'm pretty sure it won't fix this particular problem, so I'll look at re-writing it. Although with the current implementation, I have the power to add delays in the sequence if I need to. – Domarius Jan 24 '18 at 20:34
  • @zett42 although, upon reading your article link, the purpose of sending it as an array means the user can't interject accidentally with a real key press and mess up the sequence, and this is definitely the kind of reliability I want, so I will be doing the array approach, thank you :) – Domarius Jan 24 '18 at 23:12
  • @zett42 Okay I just tried it - and guess what - it messes up! Key presses that are key combos (eg. CTRL+S) are sometimes missed by the emulator software and interpreted as their individual key presses! Some times it works, sometimes it doesn't. When I go back to my method, with a 1/4 second delay between key press and key release, it works flawlessly every time. So I certainly don't see this as a bug, and as a design choice instead. – Domarius Jan 25 '18 at 08:47

2 Answers2

2

Use wVk instead of wScan, and make sure KEYEVENTF_SCANCODE is not set because that ignores wVk. You have to use VK_SNAPSHOT

INPUT ip[2] = { 0 };

ip[0].type = INPUT_KEYBOARD;
ip[0].ki.wVk = VK_SNAPSHOT;

ip[1] = ip[0];
ip[1].ki.dwFlags |= KEYEVENTF_KEYUP;
SendInput(2, ip, sizeof(INPUT));
Barmak Shemirani
  • 30,904
  • 6
  • 40
  • 77
  • That doesn't work with DirectInput games :( As I said, I didn't have any luck with Virtual Keys with the emulators running full screen, so I switched to Scan Codes. – Domarius Jan 24 '18 at 20:17
  • Although I appreciate the demonstration of using an array of key sequences with SendInput, which I will look at doing. – Domarius Jan 24 '18 at 22:54
  • Evidently I don't understand the problem. Does it work when you physically press the `[Print Screen]` on the actual keyboard? – Barmak Shemirani Jan 25 '18 at 00:55
  • Everything you need to know is in the original post :) As I said; you can press Print Screen and then CTRL+V a picture of your desktop into MS Paint. DirectInput ignores Virtual Key codes (the style of key codes you've used), so when the emulator (FS-UAE) is running, SendInput using Virtual Keys have no effect. You need to write it to use Scan Codes (what I've done in my post) but the scan code for the Print Screen key specifically has no effect, and there is some new information as to why, in the answer I wrote for myself below. – Domarius Jan 25 '18 at 05:53
2

Okay I'm answering my own question here;

So I've done some more research, found this amazing post by someone who's nutted out the details of scan codes, and it seems that Print Screen is a weird one, requiring a special sequence to be triggered properly; https://handmade.network/forums/t/2011-keyboard_inputs_-_scancodes,_raw_input,_text_input,_key_names (And for additional reading, there is this article on the history of the 3 different scan code sets, which gives some insight as to why some keys might be weird, as new keys were added to the standard) http://www.quadibloc.com/comp/scan.htm

However, I still couldn't get it to work trying the variety of code sequences in that article - in the end, I managed to work around my original problem by learning that FS-UAE supports an ALTERNATE key sequence for saving a screenshot: F12-S, which I am using instead and it's working great.

So I may have avoided the issue this time, but woe be the person who needs to legitimately simulate a Print Screen key press at the scan code level WITHOUT using "Virtual Key codes"... it is a mysterious arcane task that I have still not achieved.

Domarius
  • 413
  • 1
  • 3
  • 13