diff --git a/CHANGELOG.md b/CHANGELOG.md index 620b000..ca695e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [v4.2.0-beta.12] - 2024-12-04 + +### Added + +- MacOS keybinds: `Command + Left/Right Arrow`, `Option + Left/Right Arrow` +- `ALT`/`Option` key detection + ## [v4.2.0-beta.11] - 2024-12-01 ### Changed diff --git a/mod.json b/mod.json index 7a3fefd..c9d965b 100644 --- a/mod.json +++ b/mod.json @@ -4,7 +4,7 @@ "win": "2.2074", "mac": "2.2074" }, - "version": "v4.2.0-beta.11", + "version": "v4.2.0-beta.12", "id": "spaghettdev.betterinputs", "name": "BetterInputs", "developer": "SpaghettDev", diff --git a/src/macos.mm b/src/macos.mm index 674bbbf..9721e8b 100644 --- a/src/macos.mm +++ b/src/macos.mm @@ -15,33 +15,51 @@ #include "types/TouchMessageType.hpp" #include "utils.hpp" -namespace BI::platform +namespace BI { - inline bool keyDown(PlatformKey key, NSEvent* event) + namespace platform { - switch (key) + inline bool keyDown(PlatformKey key, NSEvent* event) { - case BI::PlatformKey::LEFT_CONTROL: - return [event modifierFlags] & NSCommandKeyMask; - case BI::PlatformKey::LEFT_SHIFT: - return [event modifierFlags] & NSShiftKeyMask; + switch (key) + { + case BI::PlatformKey::LEFT_CONTROL: + return [event modifierFlags] & NSCommandKeyMask; + case BI::PlatformKey::LEFT_SHIFT: + return [event modifierFlags] & NSShiftKeyMask; + case BI::PlatformKey::LEFT_ALT: + return [event modifierFlags] & NSAlternateKeyMask; + } + + return false; } + } + + namespace cocos + { + inline cocos2d::CCPoint getMousePosition(NSEvent* event) + { + auto windowFrame = [[event window] frame]; + auto viewFrame = [[[event window] contentView] frame]; + auto winSize = cocos2d::CCDirector::get()->getWinSize(); + auto scaleFactor = cocos2d::CCPoint(winSize) / ccp(viewFrame.size.width, viewFrame.size.height); + auto mouse = [event locationInView]; - return false; + return ccp(mouse.x - windowFrame.origin.x, winSize.height - (mouse.y - windowFrame.origin.y)) * scaleFactor; + } } } #define HOOK_OBJC_METHOD(klass, type, cleanFuncName, funcName) \ do { \ - auto cleanFuncName ## Method = class_getInstanceMethod(klass, @selector(funcName)); \ + auto cleanFuncName ## Method = class_getInstanceMethod(objc_getClass(klass), @selector(funcName)); \ cleanFuncName ## OIMP = reinterpret_cast(method_getImplementation(cleanFuncName ## Method)); \ method_setImplementation(cleanFuncName ## Method, reinterpret_cast(&cleanFuncName)); \ - geode::log::debug("Hooked Objective C Method '{}'", #funcName); \ + geode::log::debug("Hooked Objective C Method '" #klass " " #funcName "'"); \ } while(0) using key_event_t = void(*)(EAGLView*, SEL, NSEvent*); - static key_event_t keyDownExecOIMP; void keyDownExec(EAGLView* self, SEL sel, NSEvent* event) { @@ -71,13 +89,13 @@ void keyDownExec(EAGLView* self, SEL sel, NSEvent* event) { case kVK_RightArrow: return g_selectedInput->onRightArrowKey( - BI::platform::keyDown(BI::PlatformKey::LEFT_CONTROL, event), + BI::platform::keyDown(BI::PlatformKey::LEFT_ALT, event), BI::platform::keyDown(BI::PlatformKey::LEFT_SHIFT, event) ); case kVK_LeftArrow: return g_selectedInput->onLeftArrowKey( - BI::platform::keyDown(BI::PlatformKey::LEFT_CONTROL, event), + BI::platform::keyDown(BI::PlatformKey::LEFT_ALT, event), BI::platform::keyDown(BI::PlatformKey::LEFT_SHIFT, event) ); @@ -91,6 +109,7 @@ void keyDownExec(EAGLView* self, SEL sel, NSEvent* event) !BI::platform::keyDown(BI::PlatformKey::LEFT_SHIFT, event) ) { // https://github.com/WebKit/WebKit/blob/5c8281f146cfbf4b6189b435b80c527f138b829f/Source/WebCore/platform/mac/PlatformEventFactoryMac.mm#L559 + // we use this instead of [event keyCode] because the returned value of keyCode for letters is keyboard locale-specific int code = [[event characters] length] > 0 ? [[event characters] characterAtIndex:0] : [[event charactersIgnoringModifiers] length] > 0 @@ -147,6 +166,21 @@ void keyDownExec(EAGLView* self, SEL sel, NSEvent* event) break; } } + + if (BI::platform::keyDown(BI::PlatformKey::LEFT_CONTROL, event)) + { + switch ([event keyCode]) + { + case kVK_LeftArrow: + return g_selectedInput->onHomeKey(false); + + case kVK_RightArrow: + return g_selectedInput->onEndKey(false); + + default: + break; + } + } } // key is probably a regular character, allow CCIMEDispatcher to pick up the event @@ -169,13 +203,12 @@ void mouseDownExec(EAGLView* self, SEL sel, NSEvent* event) if (!g_selectedInput) return mouseDownExecOIMP(self, sel, event); - cocos2d::CCSize winSize = cocos2d::CCDirector::sharedDirector()->getWinSize(); - cocos2d::CCPoint mousePos = BI::cocos::getMousePosition(); + cocos2d::CCPoint mousePos = BI::cocos::getMousePosition(event); // NSWindow's mouse origin is the bottom left // CCTouch's mouse origin is top left (because of course it is) cocos2d::CCTouch touch{}; - touch.setTouchInfo(0, mousePos.x, winSize.height - mousePos.y); + touch.setTouchInfo(0, mousePos.x, mousePos.y); g_selectedInput->useUpdateBlinkPos(true); @@ -196,11 +229,9 @@ void mouseUpExec(EAGLView* self, SEL sel, NSEvent* event) // https://github.com/qimiko/click-on-steps/blob/d8a87e93b5407e5f2113a9715363a5255724c901/src/macos.mm#L101 $on_mod(Loaded) { - auto eaglView = objc_getClass("EAGLView"); - - HOOK_OBJC_METHOD(eaglView, key_event_t, keyDownExec, keyDownExec:); - HOOK_OBJC_METHOD(eaglView, key_event_t, keyUpExec, keyUpExec:); + HOOK_OBJC_METHOD(EAGLView, key_event_t, keyDownExec, keyDownExec:); + HOOK_OBJC_METHOD(EAGLView, key_event_t, keyUpExec, keyUpExec:); - HOOK_OBJC_METHOD(eaglView, key_event_t, mouseDownExec, mouseDownExec:); - HOOK_OBJC_METHOD(eaglView, key_event_t, mouseUpExec, mouseUpExec:); + HOOK_OBJC_METHOD(EAGLView, key_event_t, mouseDownExec, mouseDownExec:); + HOOK_OBJC_METHOD(EAGLView, key_event_t, mouseUpExec, mouseUpExec:); } diff --git a/src/utils.hpp b/src/utils.hpp index 243de63..1132167 100644 --- a/src/utils.hpp +++ b/src/utils.hpp @@ -99,9 +99,9 @@ namespace BI namespace cocos { +#ifdef GEODE_IS_WINDOWS inline cocos2d::CCPoint getMousePosition() { -#ifdef GEODE_IS_WINDOWS auto* director = cocos2d::CCDirector::sharedDirector(); auto* gl = director->getOpenGLView(); auto winSize = director->getWinSize(); @@ -109,10 +109,8 @@ namespace BI auto mouse = gl->getMousePosition() / frameSize; return cocos2d::CCPoint{ mouse.x, 1.f - mouse.y } * winSize; -#elif defined(GEODE_IS_MACOS) - return geode::cocos::getMousePos(); -#endif } +#endif inline bool isPositionInNode(cocos2d::CCNode* node, const cocos2d::CCPoint& pos) { @@ -132,8 +130,12 @@ namespace BI enum class PlatformKey { + // Windows Control key | MacOS Command key LEFT_CONTROL, - LEFT_SHIFT + // Shift key + LEFT_SHIFT, + // Window Alt key | MacOS Option key + LEFT_ALT }; namespace platform { @@ -146,6 +148,8 @@ namespace BI return GetKeyState(VK_CONTROL) & 0x8000; case BI::PlatformKey::LEFT_SHIFT: return GetKeyState(VK_SHIFT) & 0x8000; + case BI::PlatformKey::LEFT_ALT: + return GetKeyState(VK_LMENU) & 0x8000; } return false;