Skip to content

Commit d7df908

Browse files
committed
MacOS support
1 parent 131a4ee commit d7df908

File tree

4 files changed

+265
-7
lines changed

4 files changed

+265
-7
lines changed

loader/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ file(GLOB SOURCES CONFIGURE_DEPENDS
9191
file(GLOB OBJC_SOURCES
9292
src/platform/Objcpp.mm
9393
src/load.mm
94+
95+
src/hooks/AddExtraKeys.mm
9496
)
9597
set_source_files_properties(${OBJC_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
9698

loader/include/Geode/cocos/robtop/keyboard_dispatcher/CCKeyboardDelegate.h

+5-5
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66

77
NS_CC_BEGIN
88

9-
/*no clue if this is accurate.
10-
* https://github.com/cocos2d/cocos2d-x/blob/cocos2d-x-3.13/cocos/base/CCEventKeyboard.h#L48
11-
* https://github.com/reneklacan/cocos2d-x/wiki/Keyboard-keycodes-enum
12-
* not sure which one is which
9+
/*no clue if this is accurate.
10+
* https://github.com/cocos2d/cocos2d-x/blob/cocos2d-x-3.13/cocos/base/CCEventKeyboard.h#L48
11+
* https://github.com/reneklacan/cocos2d-x/wiki/Keyboard-keycodes-enum
12+
* not sure which one is which
1313
* @note RobTop Addition
14-
*/
14+
*/
1515
typedef enum
1616
{
1717
KEY_Unknown = -0x01,

loader/src/hooks/AddExtraKeys.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#ifdef GEODE_IS_DESKTOP
1+
#ifdef GEODE_IS_WINDOWS
22

33
#include <Geode/DefaultInclude.hpp>
44
#include <Geode/cocos/robtop/glfw/glfw3.h>
@@ -13,7 +13,6 @@ using namespace geode::prelude;
1313

1414
class $modify(GeodeCCEGLView, CCEGLView) {
1515
void onGLFWKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
16-
log::info("glfw key {}", key);
1716
bool extraKey = isExtraKey(key);
1817
bool numpad = isKeyNumpad(key);
1918
if (!extraKey && !numpad) {

loader/src/hooks/AddExtraKeys.mm

+257
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
#import <Cocoa/Cocoa.h>
2+
#include <objc/runtime.h>
3+
#include <Carbon/Carbon.h>
4+
5+
#include <Geode/DefaultInclude.hpp>
6+
#include <Geode/cocos/robtop/keyboard_dispatcher/CCKeyboardDispatcher.h>
7+
#include <Geode/cocos/robtop/keyboard_dispatcher/CCKeyboardDelegate.h>
8+
#include <Geode/cocos/text_input_node/CCIMEDispatcher.h>
9+
#include <Geode/modify/Modify.hpp>
10+
#include <Geode/modify/CCKeyboardDispatcher.hpp>
11+
12+
using namespace geode::prelude;
13+
14+
// https://github.com/SpaghettDev/BetterInputs/blob/44f249cd94f4cc19fca4de570dfab28f4efa3db8/src/platform/macos.mm#L121
15+
// we use this instead of [event keyCode] because the returned value of keyCode for letters is keyboard locale-specific
16+
int normalizedCodeFromEvent(NSEvent* event) {
17+
if ([[event characters] length] > 0) {
18+
return [[event characters] characterAtIndex:0];
19+
} else if ([[event charactersIgnoringModifiers] length] > 0) {
20+
return [[event charactersIgnoringModifiers] characterAtIndex:0];
21+
}
22+
23+
return 0;
24+
}
25+
26+
enumKeyCodes mouseButtonToKeyCode(NSEvent* event) {
27+
switch ([event buttonNumber]) {
28+
case 2:
29+
return enumKeyCodes::MOUSE_4;
30+
case 3:
31+
return enumKeyCodes::MOUSE_5;
32+
case 4:
33+
return enumKeyCodes::MOUSE_6;
34+
case 5:
35+
return enumKeyCodes::MOUSE_7;
36+
case 6:
37+
return enumKeyCodes::MOUSE_8;
38+
default:
39+
return enumKeyCodes::KEY_Unknown;
40+
}
41+
}
42+
43+
bool isExtraMouseButton(NSEvent* event) {
44+
return [event buttonNumber] > 1;
45+
}
46+
47+
enumKeyCodes extraKeyToKeyCode(NSEvent* event) {
48+
switch (normalizedCodeFromEvent(event)) {
49+
case ';':
50+
return enumKeyCodes::KEY_Semicolon;
51+
case '\'':
52+
return enumKeyCodes::KEY_Apostrophe;
53+
case '/':
54+
return enumKeyCodes::KEY_Slash;
55+
case '=':
56+
return enumKeyCodes::KEY_OEMEqual;
57+
case '[':
58+
return enumKeyCodes::KEY_LeftBracket;
59+
case '\\':
60+
return enumKeyCodes::KEY_Backslash;
61+
case ']':
62+
return enumKeyCodes::KEY_RightBracket;
63+
case '`':
64+
return enumKeyCodes::KEY_GraveAccent;
65+
default:
66+
break;
67+
}
68+
69+
switch ([event keyCode]) {
70+
case kVK_ISO_Section:
71+
return enumKeyCodes::KEY_World2;
72+
default:
73+
break;
74+
}
75+
76+
return enumKeyCodes::KEY_Unknown;
77+
}
78+
79+
bool isExtraKey(NSEvent* event) {
80+
return extraKeyToKeyCode(event) != enumKeyCodes::KEY_Unknown;
81+
}
82+
83+
enumKeyCodes numpadToKeyCode(NSEvent* event) {
84+
switch (normalizedCodeFromEvent(event)) {
85+
case '0':
86+
return enumKeyCodes::KEY_NumPad0;
87+
case '1':
88+
return enumKeyCodes::KEY_NumPad1;
89+
case '2':
90+
return enumKeyCodes::KEY_NumPad2;
91+
case '3':
92+
return enumKeyCodes::KEY_NumPad3;
93+
case '4':
94+
return enumKeyCodes::KEY_NumPad4;
95+
case '5':
96+
return enumKeyCodes::KEY_NumPad5;
97+
case '6':
98+
return enumKeyCodes::KEY_NumPad6;
99+
case '7':
100+
return enumKeyCodes::KEY_NumPad7;
101+
case '8':
102+
return enumKeyCodes::KEY_NumPad8;
103+
case '9':
104+
return enumKeyCodes::KEY_NumPad9;
105+
case '.':
106+
return enumKeyCodes::KEY_Decimal;
107+
case '/':
108+
return enumKeyCodes::KEY_Divide;
109+
case '*':
110+
return enumKeyCodes::KEY_Multiply;
111+
case '-':
112+
return enumKeyCodes::KEY_Subtract;
113+
case '+':
114+
return enumKeyCodes::KEY_Add;
115+
case 3:
116+
return enumKeyCodes::KEY_NumEnter;
117+
case '=':
118+
return enumKeyCodes::KEY_Equal;
119+
default:
120+
return enumKeyCodes::KEY_Unknown;
121+
}
122+
}
123+
124+
bool isKeyNumpad(NSEvent* event) {
125+
return ([event modifierFlags] & NSEventModifierFlagNumericPad) != 0;
126+
}
127+
128+
129+
static void(*s_keyDownExecOrig)(void*, SEL, NSEvent*);
130+
void keyDownExecHook(void* self, SEL sel, NSEvent* event)
131+
{
132+
bool extraKey = isExtraKey(event);
133+
bool numpad = isKeyNumpad(event);
134+
if (!extraKey && !numpad) {
135+
return s_keyDownExecOrig(self, sel, event);
136+
}
137+
if (CCIMEDispatcher::sharedDispatcher()->hasDelegate()) {
138+
return s_keyDownExecOrig(self, sel, event);
139+
}
140+
141+
enumKeyCodes keyCode = enumKeyCodes::KEY_Unknown;
142+
if (extraKey) {
143+
keyCode = extraKeyToKeyCode(event);
144+
}
145+
if (numpad) {
146+
keyCode = numpadToKeyCode(event);
147+
}
148+
CCKeyboardDispatcher::get()->dispatchKeyboardMSG(keyCode, true, [event isARepeat]);
149+
}
150+
151+
static void(*s_keyUpExecOrig)(void*, SEL, NSEvent*);
152+
void keyUpExecHook(void* self, SEL sel, NSEvent* event)
153+
{
154+
bool extraKey = isExtraKey(event);
155+
bool numpad = isKeyNumpad(event);
156+
if (!extraKey && !numpad) {
157+
return s_keyUpExecOrig(self, sel, event);
158+
}
159+
if (CCIMEDispatcher::sharedDispatcher()->hasDelegate()) {
160+
return s_keyUpExecOrig(self, sel, event);
161+
}
162+
163+
enumKeyCodes keyCode = enumKeyCodes::KEY_Unknown;
164+
if (extraKey) {
165+
keyCode = extraKeyToKeyCode(event);
166+
}
167+
if (numpad) {
168+
keyCode = numpadToKeyCode(event);
169+
}
170+
CCKeyboardDispatcher::get()->dispatchKeyboardMSG(keyCode, false, [event isARepeat]);
171+
}
172+
173+
static void(*s_mouseDownExecOrig)(void*, SEL, NSEvent*);
174+
void mouseDownExecHook(void* self, SEL sel, NSEvent* event)
175+
{
176+
if (!isExtraMouseButton(event)) {
177+
return s_mouseDownExecOrig(self, sel, event);
178+
}
179+
180+
enumKeyCodes keyCode = mouseButtonToKeyCode(event);
181+
CCKeyboardDispatcher::get()->dispatchKeyboardMSG(keyCode, true, false);
182+
}
183+
184+
static void(*s_mouseUpExecOrig)(void*, SEL, NSEvent*);
185+
void mouseUpExecHook(void* self, SEL sel, NSEvent* event)
186+
{
187+
if (!isExtraMouseButton(event)) {
188+
return s_mouseUpExecOrig(self, sel, event);
189+
}
190+
191+
enumKeyCodes keyCode = mouseButtonToKeyCode(event);
192+
CCKeyboardDispatcher::get()->dispatchKeyboardMSG(keyCode, false, false);
193+
}
194+
195+
196+
class $modify(CCKeyboardDispatcher) {
197+
GEODE_FORWARD_COMPAT_DISABLE_HOOKS("CCKeyboardDispatcher new keys")
198+
199+
const char* keyToString(enumKeyCodes key) {
200+
if (key < 0x1000) {
201+
return CCKeyboardDispatcher::keyToString(key);
202+
}
203+
204+
switch (key) {
205+
case KEY_GraveAccent:
206+
return "`";
207+
case KEY_OEMEqual:
208+
return "=";
209+
case KEY_LeftBracket:
210+
return "[";
211+
case KEY_RightBracket:
212+
return "]";
213+
case KEY_Backslash:
214+
return "\\";
215+
case KEY_Semicolon:
216+
return ";";
217+
case KEY_Apostrophe:
218+
return "'";
219+
case KEY_Slash:
220+
return "/";
221+
case KEY_NumEnter:
222+
return "NumEnter";
223+
case KEY_World1:
224+
return "INTL-1";
225+
case KEY_World2:
226+
return "INTL-2";
227+
case MOUSE_4:
228+
return "Mouse 4";
229+
case MOUSE_5:
230+
return "Mouse 5";
231+
case MOUSE_6:
232+
return "Mouse 6";
233+
case MOUSE_7:
234+
return "Mouse 7";
235+
case MOUSE_8:
236+
return "Mouse 8";
237+
default:
238+
return CCKeyboardDispatcher::keyToString(KEY_Unknown);
239+
}
240+
}
241+
};
242+
243+
244+
#define OBJC_SWIZZLE(klass, methodName) \
245+
auto methodName##Method = class_getInstanceMethod(klass, @selector(methodName:)); \
246+
s_##methodName##Orig = reinterpret_cast<decltype(s_##methodName##Orig)>(method_getImplementation(methodName##Method)); \
247+
method_setImplementation(methodName##Method, reinterpret_cast<IMP>(&methodName##Hook));
248+
249+
__attribute__((constructor)) void initialize_newKeyboardMSGKeysHooks() {
250+
auto eaglView = objc_getClass("EAGLView");
251+
252+
OBJC_SWIZZLE(eaglView, keyDownExec);
253+
OBJC_SWIZZLE(eaglView, keyUpExec);
254+
255+
OBJC_SWIZZLE(eaglView, mouseDownExec);
256+
OBJC_SWIZZLE(eaglView, mouseUpExec);
257+
}

0 commit comments

Comments
 (0)