Skip to content

Commit 74f6ffe

Browse files
SintendoScrewtapello
authored andcommitted
ruby/input: Add macOS mouse support
While keyboard and joypad input had already been present for some time, mouse input for macOS remained unimplemented in ruby. Until now, that is.
1 parent 6df1807 commit 74f6ffe

File tree

2 files changed

+91
-4
lines changed

2 files changed

+91
-4
lines changed

ruby/input/mouse/quartz.cpp

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#pragma once
2+
3+
struct InputMouseQuartz {
4+
Input& input;
5+
InputMouseQuartz(Input& input) : input(input) {}
6+
7+
shared_pointer<HID::Mouse> hid{new HID::Mouse};
8+
9+
bool mouseAcquired = false;
10+
11+
auto acquire() -> bool {
12+
if(!mouseAcquired) {
13+
CGError error = CGAssociateMouseAndMouseCursorPosition(NO);
14+
if(error != kCGErrorSuccess) return false;
15+
[NSCursor hide];
16+
17+
mouseAcquired = true;
18+
}
19+
return true;
20+
}
21+
22+
auto acquired() -> bool {
23+
return mouseAcquired;
24+
}
25+
26+
auto release() -> bool {
27+
if(mouseAcquired) {
28+
CGError error = CGAssociateMouseAndMouseCursorPosition(YES);
29+
if(error != kCGErrorSuccess) return false;
30+
[NSCursor unhide];
31+
32+
mouseAcquired = false;
33+
}
34+
return true;
35+
}
36+
37+
auto assign(uint groupID, uint inputID, int16_t value) -> void {
38+
auto& group = hid->group(groupID);
39+
if(group.input(inputID).value() == value) return;
40+
input.doChange(hid, groupID, inputID, group.input(inputID).value(), value);
41+
group.input(inputID).setValue(value);
42+
}
43+
44+
auto poll(vector<shared_pointer<HID::Device>>& devices) -> void {
45+
int deltaX, deltaY;
46+
CGGetLastMouseDelta(&deltaX, &deltaY);
47+
48+
assign(HID::Mouse::GroupID::Axis, 0, deltaX);
49+
assign(HID::Mouse::GroupID::Axis, 1, deltaY);
50+
51+
NSUInteger buttons = [NSEvent pressedMouseButtons];
52+
53+
assign(HID::Mouse::GroupID::Button, 0, !!(buttons & (1 << 0)));
54+
assign(HID::Mouse::GroupID::Button, 2, !!(buttons & (1 << 1)));
55+
assign(HID::Mouse::GroupID::Button, 1, !!(buttons & (1 << 2)));
56+
assign(HID::Mouse::GroupID::Button, 4, !!(buttons & (1 << 3)));
57+
assign(HID::Mouse::GroupID::Button, 3, !!(buttons & (1 << 4)));
58+
59+
devices.append(hid);
60+
}
61+
62+
auto initialize() -> bool {
63+
hid->setVendorID(HID::Mouse::GenericVendorID);
64+
hid->setProductID(HID::Mouse::GenericProductID);
65+
hid->setPathID(0);
66+
67+
hid->axes().append("X");
68+
hid->axes().append("Y");
69+
70+
hid->buttons().append("Left");
71+
hid->buttons().append("Middle");
72+
hid->buttons().append("Right");
73+
hid->buttons().append("Up");
74+
hid->buttons().append("Down");
75+
76+
return true;
77+
}
78+
79+
auto terminate() -> void {
80+
release();
81+
}
82+
};

ruby/input/quartz.cpp

+9-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
#include "keyboard/quartz.cpp"
2+
#include "mouse/quartz.cpp"
23
#include "joypad/iokit.cpp"
34

45
struct InputQuartz : InputDriver {
56
InputQuartz& self = *this;
6-
InputQuartz(Input& super) : InputDriver(super), keyboard(super), joypad(super) {}
7+
InputQuartz(Input& super) : InputDriver(super), keyboard(super), mouse(super), joypad(super) {}
78
~InputQuartz() { terminate(); }
89

910
auto create() -> bool override {
@@ -13,13 +14,14 @@ struct InputQuartz : InputDriver {
1314
auto driver() -> string override { return "Quartz"; }
1415
auto ready() -> bool override { return isReady; }
1516

16-
auto acquired() -> bool override { return false; }
17-
auto acquire() -> bool override { return false; }
18-
auto release() -> bool override { return false; }
17+
auto acquired() -> bool override { return mouse.acquired(); }
18+
auto acquire() -> bool override { return mouse.acquire(); }
19+
auto release() -> bool override { return mouse.release(); }
1920

2021
auto poll() -> vector<shared_pointer<HID::Device>> override {
2122
vector<shared_pointer<HID::Device>> devices;
2223
keyboard.poll(devices);
24+
mouse.poll(devices);
2325
joypad.poll(devices);
2426
return devices;
2527
}
@@ -32,17 +34,20 @@ struct InputQuartz : InputDriver {
3234
auto initialize() -> bool {
3335
terminate();
3436
if(!keyboard.initialize()) return false;
37+
if(!mouse.initialize()) return false;
3538
if(!joypad.initialize()) return false;
3639
return isReady = true;
3740
}
3841

3942
auto terminate() -> void {
4043
isReady = false;
4144
keyboard.terminate();
45+
mouse.terminate();
4246
joypad.terminate();
4347
}
4448

4549
bool isReady = false;
4650
InputKeyboardQuartz keyboard;
51+
InputMouseQuartz mouse;
4752
InputJoypadIOKit joypad;
4853
};

0 commit comments

Comments
 (0)