Skip to content

Commit 39ddfe0

Browse files
authored
Merge pull request #20 from Pennywise007/develop
2 parents 150adcf + eecfde8 commit 39ddfe0

9 files changed

Lines changed: 136 additions & 54 deletions

File tree

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,15 @@ A library for simulating keyboard and mouse input with drivers.
1313

1414
- [Logitech G HUB](https://www.logitechg.com/innovation/g-hub.html)
1515

16-
No Logitech hardware required. However, in the new versions of G HUB, the mouse driver has been removed ([#8](https://github.com/Chaoses-Ib/IbInputSimulator/issues/8)). Unfortunately, there is currently no known way to install an old version.
16+
No Logitech hardware required. Supports old version of the G HUB([#8](https://github.com/Chaoses-Ib/IbInputSimulator/issues/8)).
1717

1818
e.g. `IbSendInit("Logitech")`
19+
20+
- [Logitech G HUB new](https://www.logitechg.com/innovation/g-hub.html)
21+
22+
No Logitech hardware required. Works with new versions of the G HUB. Mouse input stops working after the first reboot following the installation of the G HUB. To restore mouse functionality, you may need to reinstall the software.
23+
24+
e.g. `IbSendInit("LogitechGHubNew")`
1925

2026
- [Razer Synapse 3](https://www.razer.com/synapse-3)
2127

Simulator/include/IbInputSimulator/InputSimulator.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ namespace Send {
2424
AnyDriver,
2525
SendInput,
2626
Logitech,
27+
LogitechGHubNew,
2728
Razer,
2829
DD,
2930
MouClassInputInjection

Simulator/include/IbInputSimulator/SendTypes/DD.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ namespace Send::Type::Internal {
6565
}
6666

6767
uint32_t send_mouse_input(const INPUT inputs[], uint32_t n) override {
68-
update_screen_resolution();
6968
return Base::send_mouse_input(inputs, n);
7069
}
7170

@@ -74,7 +73,10 @@ namespace Send::Type::Internal {
7473
if (mi.dwFlags & MOUSEEVENTF_MOVE) {
7574
POINT move{ mi.dx, mi.dy };
7675
if (mi.dwFlags & MOUSEEVENTF_ABSOLUTE) {
77-
mouse_absolute_to_screen(move);
76+
if (mi.dwFlags & MOUSEEVENTF_VIRTUALDESK)
77+
mouse_virtual_desk_absolute_to_screen(move);
78+
else
79+
mouse_absolute_to_screen(move);
7880
if constexpr (debug)
7981
DebugOStream() << L"DD_mov: (" << move.x << L", " << move.y << L")\n";
8082
DD_mov(move.x, move.y);

Simulator/include/IbInputSimulator/SendTypes/Logitech.hpp

Lines changed: 96 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -120,21 +120,6 @@ namespace Send::Type::Internal {
120120
bool unknown : 3;
121121
};
122122

123-
struct MouseReport {
124-
union {
125-
MouseButton button;
126-
Byte button_byte;
127-
};
128-
int8_t x;
129-
int8_t y;
130-
Byte unknown_W; //#TODO: Wheel?
131-
Byte unknown_T; //#TODO: T?
132-
private:
133-
void assert_size() {
134-
static_assert(sizeof MouseReport == 5);
135-
}
136-
};
137-
138123
private:
139124
[[deprecated]] static LONG compensate_win_acceleration(LONG x) {
140125
//#TODO
@@ -167,40 +152,42 @@ namespace Send::Type::Internal {
167152
return x;
168153
}
169154

170-
static int8_t compensate_lgs_acceleration(int8_t x) {
171-
int8_t abs_x = abs(x);
172-
int8_t sign = x > 0 ? 1 : -1;
155+
template <typename T>
156+
static T compensate_lgs_acceleration(T x) {
157+
T abs_x = abs(x);
158+
T sign = x > 0 ? 1 : -1;
173159

174160
if (abs_x <= 5)
175161
return x;
176162
else if (abs_x <= 10)
177163
return sign * (abs_x + 1);
178164
else
179-
return sign * (int8_t)round(0.6156218196 * abs_x + 4.45777444629);
165+
return sign * (T)round(0.6156218196 * abs_x + 4.45777444629);
180166
}
181167

182168
public:
183-
bool report_mouse(MouseReport report, int8_t compensate_switch) const {
169+
template <class ReportType>
170+
bool report_mouse(ReportType report, int8_t compensate_switch) const {
184171
constexpr DWORD IOCTL_BUSENUM_PLAY_MOUSEMOVE = 0x2A2010;
185172
DWORD bytes_returned;
186173

187174
if (has_acceleration && (report.x || report.y)) {
188-
MouseReport report11 = report;
175+
ReportType report11 = report;
189176
report11.x = report11.y = compensate_switch;
190-
DeviceIoControl(device, IOCTL_BUSENUM_PLAY_MOUSEMOVE, &report11, sizeof MouseReport, nullptr, 0, &bytes_returned, nullptr);
177+
DeviceIoControl(device, IOCTL_BUSENUM_PLAY_MOUSEMOVE, &report11, sizeof(ReportType), nullptr, 0, &bytes_returned, nullptr);
191178

192179
report.x = compensate_lgs_acceleration(report.x);
193180
report.y = compensate_lgs_acceleration(report.y);
194181
}
195182

196183
if constexpr (debug) {
197-
bool success = DeviceIoControl(device, IOCTL_BUSENUM_PLAY_MOUSEMOVE, &report, sizeof MouseReport, nullptr, 0, &bytes_returned, nullptr);
184+
bool success = DeviceIoControl(device, IOCTL_BUSENUM_PLAY_MOUSEMOVE, &report, sizeof(ReportType), nullptr, 0, &bytes_returned, nullptr);
198185
DWORD error = GetLastError();
199186
DebugOStream() << L"report_mouse: " << report.button_byte << L", " << report.x << L", " << report.y << L". "
200187
<< success << L", " << error << std::endl;
201188
return success;
202189
}
203-
return DeviceIoControl(device, IOCTL_BUSENUM_PLAY_MOUSEMOVE, &report, sizeof MouseReport, nullptr, 0, &bytes_returned, nullptr);
190+
return DeviceIoControl(device, IOCTL_BUSENUM_PLAY_MOUSEMOVE, &report, sizeof(ReportType), nullptr, 0, &bytes_returned, nullptr);
204191
}
205192

206193
struct KeyboardReport {
@@ -229,8 +216,22 @@ namespace Send::Type::Internal {
229216
}
230217
};
231218

232-
class Logitech final : public VirtualKeyStates {
233-
LogitechDriver driver;
219+
class Logitech : public VirtualKeyStates {
220+
struct MouseReport {
221+
union {
222+
LogitechDriver::MouseButton button;
223+
Byte button_byte;
224+
};
225+
int8_t x;
226+
int8_t y;
227+
Byte wheel;
228+
Byte unknown_T; //#TODO: T?
229+
private:
230+
void assert_size() {
231+
static_assert(sizeof MouseReport == 5);
232+
}
233+
};
234+
234235
public:
235236
Logitech() : VirtualKeyStates(keyboard_report.modifiers, keyboard_mutex) {}
236237

@@ -242,44 +243,70 @@ namespace Send::Type::Internal {
242243
driver.destroy();
243244
}
244245

245-
private:
246-
LogitechDriver::MouseReport mouse_report{};
246+
protected:
247+
LogitechDriver driver;
247248
uint8_t compensate_switch = -1;
248249
std::mutex mouse_mutex;
249250

251+
template <typename T>
252+
static constexpr T max_value()
253+
{
254+
if constexpr (std::is_same_v<T, int8_t>)
255+
return INT8_MAX;
256+
else
257+
{
258+
static_assert(std::is_same_v<T, int16_t>, "Unknown type");
259+
return INT16_MAX;
260+
}
261+
}
262+
250263
public:
251264
uint32_t send_mouse_input(const INPUT inputs[], uint32_t n) override {
252-
update_screen_resolution();
253265
return Base::send_mouse_input(inputs, n);
254266
}
255267

256-
bool send_mouse_input(const MOUSEINPUT& mi) override {
268+
virtual bool send_mouse_input(const MOUSEINPUT& mi) override {
269+
return send_mouse_report<MouseReport>(mi);
270+
}
271+
272+
template <class ReportType>
273+
bool send_mouse_report(const MOUSEINPUT& mi)
274+
{
257275
std::lock_guard lock(mouse_mutex);
258276

259277
if constexpr (debug)
260278
DebugOStream() << L"send_mouse_input: " << mi.dwFlags << L", " << mi.dx << L", " << mi.dy << std::endl;
261279

280+
ReportType mouse_report{};
281+
262282
//#TODO: move and then click, or click and then move? former?
263283

264-
//#TODO: MOUSEEVENTF_MOVE_NOCOALESCE, MOUSEEVENTF_VIRTUALDESK
284+
//#TODO: MOUSEEVENTF_MOVE_NOCOALESCE
265285
if (mi.dwFlags & MOUSEEVENTF_MOVE) {
266-
POINT move { mi.dx, mi.dy };
286+
POINT move{ mi.dx, mi.dy };
267287
if (mi.dwFlags & MOUSEEVENTF_ABSOLUTE) {
268-
mouse_absolute_to_screen(move);
288+
if (mi.dwFlags & MOUSEEVENTF_VIRTUALDESK)
289+
mouse_virtual_desk_absolute_to_screen(move);
290+
else
291+
mouse_absolute_to_screen(move);
269292
mouse_screen_to_relative(move);
270293
}
271294

272-
while (abs(move.x) > 127 || abs(move.y) > 127) {
273-
if (abs(move.x) > 127) {
274-
mouse_report.x = move.x > 0 ? 127 : -127;
295+
static_assert(std::is_same_v<decltype(mouse_report.x), decltype(mouse_report.y)>);
296+
using CoordinatesType = decltype(mouse_report.x);
297+
constexpr auto maxValue = max_value<CoordinatesType>();
298+
299+
while (abs(move.x) > maxValue || abs(move.y) > maxValue) {
300+
if (abs(move.x) > maxValue) {
301+
mouse_report.x = move.x > 0 ? maxValue : -maxValue;
275302
move.x -= mouse_report.x;
276303
}
277304
else {
278305
mouse_report.x = 0;
279306
}
280307

281-
if (abs(move.y) > 127) {
282-
mouse_report.y = move.y > 0 ? 127 : -127;
308+
if (abs(move.y) > maxValue) {
309+
mouse_report.y = move.y > 0 ? maxValue : -maxValue;
283310
move.y -= mouse_report.y;
284311
}
285312
else {
@@ -289,13 +316,17 @@ namespace Send::Type::Internal {
289316
driver.report_mouse(mouse_report, compensate_switch = -compensate_switch);
290317
}
291318

292-
mouse_report.x = (uint8_t)move.x;
293-
mouse_report.y = (uint8_t)move.y;
319+
mouse_report.x = (CoordinatesType)move.x;
320+
mouse_report.y = (CoordinatesType)move.y;
294321
} else {
295322
mouse_report.x = 0;
296323
mouse_report.y = 0;
297324
}
298325

326+
if (mi.dwFlags & MOUSEEVENTF_WHEEL) { // TODO MOUSEEVENTF_HWHEEL
327+
mouse_report.wheel = std::bit_cast<int32_t>(mi.mouseData) > 0 ? 1 : -1;
328+
}
329+
299330
#define CODE_GENERATE(down, up, member) \
300331
if (mi.dwFlags & down || mi.dwFlags & up) \
301332
mouse_report.button.##member = mi.dwFlags & down;
@@ -352,4 +383,29 @@ namespace Send::Type::Internal {
352383
}
353384
#pragma warning(suppress : 4250) //'class1' : inherits 'class2::member' via dominance
354385
};
386+
387+
// new Ghub send type, same as Logitech but with another types in MouseReport struct
388+
class LogitechGHubNew : public Logitech {
389+
struct MouseReport {
390+
union {
391+
LogitechDriver::MouseButton button;
392+
Byte button_byte;
393+
};
394+
int16_t x;
395+
int16_t y;
396+
Byte wheel;
397+
Byte unknown_T; //#TODO: T?
398+
private:
399+
void assert_size() {
400+
static_assert(sizeof MouseReport == 8);
401+
}
402+
};
403+
404+
public:
405+
LogitechGHubNew() = default;
406+
407+
bool send_mouse_input(const MOUSEINPUT& mi) override {
408+
return Logitech::send_mouse_report<MouseReport>(mi);
409+
}
410+
};
355411
}

Simulator/include/IbInputSimulator/SendTypes/Razer.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,12 @@ namespace Send::Type::Internal {
9999
RzControl control{ .type = RzControl::Type::Mouse };
100100

101101
if (mi.dwFlags & MOUSEEVENTF_MOVE) {
102-
POINT move{ mi.dx, mi.dy };
103102
if (mi.dwFlags & MOUSEEVENTF_ABSOLUTE) {
104103
control.mi.Flags = MOUSE_MOVE_ABSOLUTE;
105104
}
105+
if (mi.dwFlags & MOUSEEVENTF_VIRTUALDESK) {
106+
control.mi.Flags |= MOUSE_VIRTUAL_DESKTOP;
107+
}
106108
control.mi.LastX = mi.dx;
107109
control.mi.LastY = mi.dy;
108110
}
@@ -138,7 +140,7 @@ namespace Send::Type::Internal {
138140
control.mi.ButtonFlags |= MOUSE_WHEEL;
139141
else
140142
control.mi.ButtonFlags |= MOUSE_HWHEEL;
141-
control.mi.ButtonData = 120 * std::bit_cast<int32_t>(mi.mouseData); //#TODO
143+
control.mi.ButtonData = std::bit_cast<int32_t>(mi.mouseData);
142144
}
143145

144146
if constexpr (debug)

Simulator/include/IbInputSimulator/SendTypes/base.hpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,18 +47,22 @@ namespace Send::Type::Internal {
4747
return false;
4848
}
4949

50-
POINT screen;
5150
void mouse_absolute_to_screen(POINT& absolute) const {
52-
// absolute.x = round(x / screen.x * 65536)
53-
absolute.x = absolute.x * screen.x / 65536;
54-
absolute.y = absolute.y * screen.y / 65536;
51+
const static int mainScreenWidth = GetSystemMetrics(SM_CXSCREEN);
52+
const static int mainScreenHeight = GetSystemMetrics(SM_CYSCREEN);
53+
54+
// the overhead of WM_DISPLAYCHANGE is a bit high
55+
56+
absolute.x = MulDiv(absolute.x, mainScreenWidth, 65536);
57+
absolute.y = MulDiv(absolute.y, mainScreenHeight, 65536);
5558
}
5659

57-
void update_screen_resolution() {
58-
screen.x = GetSystemMetrics(SM_CXSCREEN); //#TODO: SM_CXVIRTUALSCREEN?
59-
screen.y = GetSystemMetrics(SM_CYSCREEN);
60+
void mouse_virtual_desk_absolute_to_screen(POINT& absolute) const {
61+
const static int virtualDeskWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
62+
const static int virtualDeskHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
6063

61-
// the overhead of WM_DISPLAYCHANGE is a bit high
64+
absolute.x = MulDiv(absolute.x, virtualDeskWidth, 65536);
65+
absolute.y = MulDiv(absolute.y, virtualDeskHeight, 65536);
6266
}
6367

6468
// need to call update_screen_resolution first

Simulator/include/IbInputSimulator/SendTypes/types.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ namespace Send
1313
using Internal::Base;
1414
using Internal::SendInput;
1515
using Internal::Logitech;
16+
using Internal::LogitechGHubNew;
1617
using Internal::Razer;
1718
using Internal::DD;
1819
using Internal::MouClassInputInjection;

Simulator/source/API 3.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ DLLAPI bool __stdcall IbSendMouseMove(uint32_t x, uint32_t y, Send::MoveMode mod
1313
.mouseData = 0,
1414
.dwFlags = [mode]() -> DWORD {
1515
switch (mode) {
16-
case MoveMode::Absolute: return MOUSEEVENTF_ABSOLUTE;
16+
case MoveMode::Absolute: return MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK;
1717
case MoveMode::Relative: return MOUSEEVENTF_MOVE;
1818
default: assert(false);
1919
}

Simulator/source/dllmain.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,16 @@ DLLAPI Send::Error __stdcall IbSendInit(SendType type, InitFlags flags, void* ar
122122
main::send = std::move(type);
123123
}
124124
break;
125+
case SendType::LogitechGHubNew:
126+
{
127+
auto type = std::make_unique<Type::LogitechGHubNew>();
128+
type->create_base(&SendInputHook::GetAsyncKeyState_real);
129+
Error error = type->create();
130+
if (error != Error::Success)
131+
return error;
132+
main::send = std::move(type);
133+
}
134+
break;
125135
case SendType::Razer:
126136
{
127137
auto type = std::make_unique<Type::Razer>();

0 commit comments

Comments
 (0)