-2

! does not exist in the virtual key codes of Win32. Is there a way I could use keybd_event(), or anything else, to simulate a keyboard entry leading to !?

It's my first time making a bot to spam in a Discord casino (private).

3
  • 3
    Well, there isn't a ! key on a qwerty keyboard. To type !, you need two keys, shift + 1 Commented Dec 15, 2021 at 20:46
  • See my previous answer for sending Unicode strings with SendInput() (keybd_event()'s successor) in C++. Commented Dec 16, 2021 at 1:02
  • @RemyLebeau Only now did I notice that you have a C++ answer for it too :-) Light Blur: Mind if we close this as a duplicate? Commented Dec 16, 2021 at 18:42

1 Answer 1

0

Since keybd_event() has been superseded by SendInput(), I suggest that you use that instead.

With SendInput(), you send a number of INPUT structures. You can send mouse input, keyboard input, and hardware input. I'll show how to send keyboard input.

Keyboard input can be sent using scan codes - or Unicode characters. I'll use Unicode. Finding the Unicode character for something you don't know is usually as easy as: https://www.google.com/search?q=unicode+exclamation+mark and you'll get the answer, like U+0021 for !, which can be encoded as \u0021 in Unicode strings in C++.

I'll start by inheriting the INPUT structure to make it simpler to instantiate it:

#include <Windows.h> #include <iostream> #include <stdexcept> #include <vector> struct mINPUT : INPUT { mINPUT() : INPUT{} {} // make sure it's clean if default constructed. // this constructor prepares the structure for different kinds of input: mINPUT(DWORD type) : INPUT{type} { switch (type) { case INPUT_MOUSE: // use mi. break; case INPUT_KEYBOARD: // use ki. ki.dwFlags = KEYEVENTF_UNICODE; // we'll use unicode break; case INPUT_HARDWARE: // use hi. break; } } }; 
// helper functions to create `mINPUT` structures from Unicode values: mINPUT key_down(char16_t unicode_char) { mINPUT rv{INPUT_KEYBOARD}; rv.ki.wScan = unicode_char; return rv; } mINPUT key_up(char16_t unicode_char) { mINPUT rv{INPUT_KEYBOARD}; rv.ki.dwFlags |= KEYEVENTF_KEYUP; rv.ki.wScan = unicode_char; return rv; } 
// Helper functions to check UTF16 surrogate ranges bool is_surrogate(char16_t code_unit) { return code_unit >= 0xD800 && code_unit <= 0xDFFF; } bool is_high_surrogate(char16_t code_unit) { return code_unit >= 0xD800 && code_unit <= 0xDBFF; } bool is_low_surrogate(char16_t code_unit) { return code_unit >= 0xDC00 && code_unit <= 0xDFFF; } 
// A helper structure to prepare a sequence of events struct Inputs { UINT cInputs() const { return static_cast<UINT>(inputs.size()); } LPINPUT pInputs() { return inputs.data(); } int cbSize() const { return static_cast<int>(sizeof(INPUT)); } // A helper function to add down+up events for a string: void add_string(const char16_t* str) { while (*str) { char16_t ch = *str++; if (is_surrogate(ch)) { char16_t first = ch; char16_t second = *str++; if (!is_high_surrogate(first) || !is_low_surrogate(second)) throw std::runtime_error("Broken UTF16 surrogate pair"); inputs.push_back(key_down(first)); inputs.push_back(key_down(second)); inputs.push_back(key_up(first)); inputs.push_back(key_up(second)); } else { inputs.push_back(key_down(ch)); inputs.push_back(key_up(ch)); } } } UINT Send() { // Send the stored events return SendInput(cInputs(), pInputs(), cbSize()); } std::vector<mINPUT> inputs; }; 
int main() { std::cout << "Switch to Notepad or some other app taking input" << std::endl; Sleep(5000); // in 5 seconds, you should see the input Inputs x; // Create an event container // Add events for a full string including exclamation marks in two // different formats: x.add_string(u"Hello world!!! or \u0021\u0021\u0021 "); x.add_string(u"This is something with surrogate pairs: 𐐷 𤭢"); // Send the events: UINT rv = x.Send(); std::cout << "Sent " << rv << " events\n"; } 

If everything goes according to plan, it will send 134 events and you should see the exclamation mark and other characters appear in any app you have active if it's capable of receiving keyboard input and displaying the result, like Notepad or Visual Studio - so be careful where you place the cursor.

Sign up to request clarification or add additional context in comments.

6 Comments

Note, your code is not handling UTF-16 surrogates correctly. See my previous answer about that issue.
@RemyLebeau Thanks, that looks nice! Strange that MS haven't documented this. I'll read your answer more closely after work. :)
@RemyLebeau Thanks again for bringing this to my attention. I updated it to take care of the surrogates too.
After detecting the 1st surrogate, if (*str == u'\0') doesn't detect an invalid 2nd surrogate correctly. I would suggest something more like this instead: if (first >= 0xDC00 || *str < 0xDC00 || *str > 0xDFFF) throw ...;
@RemyLebeau Ah, yes, thanks. I added a proper surrogate check.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.