Repository navigation
Expand file tree
/
Copy path09_Mouse_Move_Horizontal.cpp
More file actions
135 lines (131 loc) · 5.51 KB
/
Copy path09_Mouse_Move_Horizontal.cpp
File metadata and controls
135 lines (131 loc) · 5.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include "Interceptor.h"
#include <iostream>
#include <system_error>
#include <algorithm>
#include <charconv>
using namespace Interceptor;
int main() try {
std::cout
<< "Enter relative mouse X counts: 300 moves right, -485 moves left. Enter q to quit.\n"
"Run one example at a time as administrator. Close this window or press Ctrl+C to stop.\n"
<< std::flush;
// Check installation and initialize supported devices before capturing.
Get_Status();
const auto init = Init_AllDevices();
if (!init.ready) {
std::cerr << "Initialization failed. Error: " << init.error
<< ". Restart required: " << init.reboot_required << "\n";
return 1;
}
DWORD consoleMode = 0; // Console only: prevent text selection from blocking console writes.
if (GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &consoleMode)) {
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE),
(consoleMode | ENABLE_EXTENDED_FLAGS) & ~ENABLE_QUICK_EDIT_MODE);
}
const auto console = GetStdHandle(STD_INPUT_HANDLE);
DWORD oldMode = 0;
if (!GetConsoleMode(console, &oldMode)) {
throw std::runtime_error("Open an interactive Windows console.");
}
struct RestoreMode {
HANDLE console;
DWORD mode;
~RestoreMode() {
SetConsoleMode(console, mode);
}
} restore{console, oldMode};
if (!SetConsoleMode(console, ENABLE_PROCESSED_INPUT | ENABLE_EXTENDED_FLAGS)) {
throw std::runtime_error("Cannot configure the console.");
}
const auto devices = Get_Devices();
const auto mouse = std::find_if(devices.begin(), devices.end(), [](const auto& d) {
return d.type == static_cast<unsigned>(Device_Type::Mouse);
});
if (mouse == devices.end()) {
throw std::runtime_error("Connect and associate a mouse first.");
}
std::string number;
bool tooLong = false;
std::cout
<< "Raw counts are not screen pixels; Windows/games apply their sensitivity. Escape also exits.\nX > "
<< std::flush;
for (;;) {
{ // The console handle wakes this wait too; no polling thread or idle timer is needed.
auto inputs = Get_Input_With_Timeout(INFINITE, console);
const auto sent =
Send_Input(inputs); // Keep the physical keyboard/mouse working while typing.
if (!sent) {
throw std::system_error(sent.error, std::system_category(), "Send_Input");
}
}
DWORD pending = 0;
if (!GetNumberOfConsoleInputEvents(console, &pending)) {
throw std::runtime_error("Cannot read console input.");
}
if (!pending) {
continue;
}
INPUT_RECORD record{};
DWORD read = 0;
if (!ReadConsoleInputW(console, &record, 1, &read)) {
throw std::runtime_error("Cannot read a console key.");
}
if (record.EventType != KEY_EVENT || !record.Event.KeyEvent.bKeyDown) {
continue;
}
if (record.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) {
return 0;
}
for (WORD repeat = 0; repeat < record.Event.KeyEvent.wRepeatCount; ++repeat) {
const auto character = record.Event.KeyEvent.uChar.UnicodeChar;
if (character == L'\r') {
if (number == "q" || number == "Q") {
return 0;
}
std::int32_t delta = 0;
const char* first = number.data();
const char* last = first + number.size();
if (first != last && *first == '+') {
++first;
}
const auto parsed = std::from_chars(first, last, delta);
const bool invalidPlus = !number.empty() && number[0] == '+' &&
(number.size() < 2 || number[1] < '0' || number[1] > '9');
if (tooLong || invalidPlus || parsed.ec != std::errc{} || parsed.ptr != last) {
std::cout << "Enter a signed 32-bit whole number.\n";
} else {
Mouse_Input movement{};
movement.device = mouse->id;
auto& state = movement.stroke;
state.x =
delta; // A real relative mouse packet. Y, buttons and flags stay zero.
const auto sent = Send_Input(movement);
if (!sent || sent.accepted != 1) {
throw std::runtime_error("Could not send mouse movement.");
}
}
number.clear();
tooLong = false;
std::cout << "\nX > " << std::flush;
} else if (character == L'\b' && !number.empty()) {
number.pop_back();
std::cout << "\b \b" << std::flush;
} else if (character >= L' ' && character <= L'~') {
if (number.size() < 32) {
number += static_cast<char>(character);
std::cout << static_cast<char>(character) << std::flush;
} else {
tooLong = true;
}
}
}
}
} catch (const std::system_error& error) {
std::cerr
<< "Driver error: " << error.code().value()
<< ". Install this edition with InterceptorSetup.exe, restart if requested, and run as administrator.\n";
return 1;
} catch (const std::exception& error) {
std::cerr << error.what() << '\n';
return 1;
}