diff --git a/src/backend.cpp b/src/backend.cpp index 68cd0b0..41ed114 100644 --- a/src/backend.cpp +++ b/src/backend.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include "platform/platform.hpp" #include "DevTools.hpp" @@ -354,3 +355,83 @@ class $modify(CCIMEDispatcher) { io.AddKeyEvent(ImGuiKey_Backspace, false); } }; + +ImGuiKey cocosToImGuiKey(cocos2d::enumKeyCodes key) { + if (key >= KEY_A && key <= KEY_Z) { + return static_cast(ImGuiKey_A + (key - KEY_A)); + } + if (key >= KEY_Zero && key <= KEY_Nine) { + return static_cast(ImGuiKey_0 + (key - KEY_Zero)); + } + switch (key) { + case KEY_Up: return ImGuiKey_UpArrow; + case KEY_Down: return ImGuiKey_DownArrow; + case KEY_Left: return ImGuiKey_LeftArrow; + case KEY_Right: return ImGuiKey_RightArrow; + + case KEY_Control: return ImGuiKey_ModCtrl; + case KEY_LeftWindowsKey: return ImGuiKey_ModSuper; + case KEY_Shift: return ImGuiKey_ModShift; + case KEY_Alt: return ImGuiKey_ModAlt; + case KEY_Enter: return ImGuiKey_Enter; + + case KEY_Home: return ImGuiKey_Home; + case KEY_End: return ImGuiKey_End; + case KEY_Delete: return ImGuiKey_Delete; + case KEY_Escape: return ImGuiKey_Escape; + + // KEY_Control and KEY_Shift aren't called on android like windows or mac + #ifdef GEODE_IS_ANDROID + case KEY_LeftControl: return ImGuiKey_ModCtrl; + case KEY_RightContol: return ImGuiKey_ModCtrl; + case KEY_LeftShift: return ImGuiKey_ModShift; + case KEY_RightShift: return ImGuiKey_ModShift; + #endif + + default: return ImGuiKey_None; + } +} + +class $modify(CCKeyboardDispatcher) { + bool dispatchKeyboardMSG(enumKeyCodes key, bool down, bool repeat) { + log::info("{}", keyToString(key)); + auto& io = ImGui::GetIO(); + const auto imKey = cocosToImGuiKey(key); + if (imKey != ImGuiKey_None) { + io.AddKeyEvent(imKey, down); + } + + // CCIMEDispatcher stuff doesn't get called on android unless the virtual keyboard would be up. + // Similarly, CCKeyboardDispatcher doesn't get called if the virtual keyboard would be up. + #ifdef GEODE_IS_ANDROID + if (down) { + char c = 0; + if (key >= KEY_A && key <= KEY_Z) { + c = static_cast(key); + if (!io.KeyShift) { + c = static_cast(tolower(c)); + } + } else if (key >= KEY_Zero && key <= KEY_Nine) { + c = static_cast('0' + (key - KEY_Zero)); + } else if (key == KEY_Space) { + c = ' '; + } + + if (c != 0) { + std::string str(1, c); + io.AddInputCharactersUTF8(str.c_str()); + } + } + if (key == KEY_Backspace) { + io.AddKeyEvent(ImGuiKey_Backspace, true); + io.AddKeyEvent(ImGuiKey_Backspace, false); + } + #endif + + if (io.WantCaptureKeyboard) { + return false; + } else { + return CCKeyboardDispatcher::dispatchKeyboardMSG(key, down, repeat); + } + } +}; \ No newline at end of file diff --git a/src/platform/Mac.mm b/src/platform/Mac.mm index da6df32..051b1d4 100644 --- a/src/platform/Mac.mm +++ b/src/platform/Mac.mm @@ -18,6 +18,16 @@ #include #import +#include +#import + +#include +#import +#include +#include + +#include + static std::vector getAllImages() { std::vector images; struct task_dyld_info dyldInfo; @@ -86,4 +96,53 @@ else return fmt::format("{:#x}", addr - base); } +// Below is adapted from BetterInputs - thanks Spaghett + +#define OBJC_SWIZZLE(klass, type, cleanFuncName, funcName) \ + do { \ + 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("Swizzled Objective C Method '" #klass " " #funcName "'"); \ + } while(0) + +using key_event_t = void(*)(EAGLView*, SEL, NSEvent*); + +static key_event_t flagsChangedExecOIMP; +void flagsChangedExec(EAGLView* self, SEL sel, NSEvent* event) +{ + + flagsChangedExecOIMP(self, sel, event); + + auto& io = ImGui::GetIO(); + const NSEventModifierFlags flags = [event modifierFlags]; + + static NSEventModifierFlags previousFlags = 0; + NSEventModifierFlags changedFlags = flags ^ previousFlags; + + if (changedFlags & NSEventModifierFlagControl) { + bool isPressed = flags & NSEventModifierFlagControl; + io.AddKeyEvent(ImGuiKey_ModCtrl, isPressed); + } + if (changedFlags & NSEventModifierFlagOption) { + bool isPressed = flags & NSEventModifierFlagOption; + io.AddKeyEvent(ImGuiKey_ModAlt, isPressed); + } + if (changedFlags & NSEventModifierFlagCommand) { + bool isPressed = flags & NSEventModifierFlagCommand; + io.AddKeyEvent(ImGuiKey_ModSuper, isPressed); + } + if (changedFlags & NSEventModifierFlagShift) { + bool isPressed = flags & NSEventModifierFlagShift; + io.AddKeyEvent(ImGuiKey_ModShift, isPressed); + } + + previousFlags = flags; +} + +$on_mod(Loaded) +{ + OBJC_SWIZZLE(EAGLView, key_event_t, flagsChangedExec, flagsChanged:); +} + #endif \ No newline at end of file diff --git a/src/platform/Win32.cpp b/src/platform/Win32.cpp index 37725f0..bd3d724 100644 --- a/src/platform/Win32.cpp +++ b/src/platform/Win32.cpp @@ -9,30 +9,6 @@ using namespace cocos2d; using namespace geode; -ImGuiKey keyFromGLFW(int key) { - if (key >= GLFW_KEY_0 && key <= GLFW_KEY_9) { - return static_cast(ImGuiKey_0 + (key - GLFW_KEY_0)); - } else if (key >= GLFW_KEY_A && key <= GLFW_KEY_Z) { - return static_cast(ImGuiKey_A + (key - GLFW_KEY_A)); - } - switch (key) { - case GLFW_KEY_SPACE: return ImGuiKey_Space; - case GLFW_KEY_BACKSPACE: return ImGuiKey_Backspace; - case GLFW_KEY_COMMA: return ImGuiKey_Comma; - case GLFW_KEY_LEFT: return ImGuiKey_LeftArrow; - case GLFW_KEY_RIGHT: return ImGuiKey_RightArrow; - case GLFW_KEY_UP: return ImGuiKey_UpArrow; - case GLFW_KEY_DOWN: return ImGuiKey_DownArrow; - case GLFW_KEY_ESCAPE: return ImGuiKey_Escape; - case GLFW_KEY_LEFT_SHIFT: return ImGuiKey_LeftShift; - case GLFW_KEY_RIGHT_SHIFT: return ImGuiKey_RightShift; - case GLFW_KEY_LEFT_CONTROL: return ImGuiKey_LeftCtrl; - case GLFW_KEY_LEFT_ALT: return ImGuiKey_LeftAlt; - // TODO: rest :-) - } - return ImGuiKey_None; -} - class $modify(CCEGLView) { void updateWindow(int width, int height) { shouldUpdateGDRenderBuffer() = true; @@ -46,15 +22,7 @@ class $modify(CCEGLView) { DevTools::get()->destroy(); CCEGLView::toggleFullScreen(value, borderless, fix); DevTools::get()->setup(); - } - - //todo: i dont care someone else can figure it out, it completely breaks keyboard support - /*void onGLFWKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { - //auto& io = ImGui::GetIO(); - CCEGLView::onGLFWKeyCallback(window, key, scancode, action, mods); - // in practice this is only used for arrow keys - //io.AddKeyEvent(keyFromGLFW(key), action != GLFW_RELEASE); - }*/ + } }; #include "utils.hpp"