diff --git a/glfw/cocoa_platform.h b/glfw/cocoa_platform.h index 3596c223f..ee18cbb51 100644 --- a/glfw/cocoa_platform.h +++ b/glfw/cocoa_platform.h @@ -37,6 +37,7 @@ typedef void* id; #endif typedef VkFlags VkMacOSSurfaceCreateFlagsMVK; +typedef int (* GLFWcocoatextinputfilterfun)(int,int,int); typedef struct VkMacOSSurfaceCreateInfoMVK { @@ -98,6 +99,8 @@ typedef struct _GLFWwindowNS // This is kept to counteract Cocoa doing the same internally double cursorWarpDeltaX, cursorWarpDeltaY; + // The text input filter callback + GLFWcocoatextinputfilterfun textInputFilterCallback; } _GLFWwindowNS; // Cocoa-specific global data diff --git a/glfw/cocoa_window.m b/glfw/cocoa_window.m index 1f7782e0d..c24c12990 100644 --- a/glfw/cocoa_window.m +++ b/glfw/cocoa_window.m @@ -725,10 +725,12 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; const int key = translateKey(scancode, GLFW_TRUE); const int mods = translateFlags([event modifierFlags]); _glfw.ns.text[0] = 0; - // this will call insertText with the text for this event, if any - [self interpretKeyEvents:[NSArray arrayWithObject:event]]; - if ((1 <= _glfw.ns.text[0] && _glfw.ns.text[0] <= 31) || (unsigned)_glfw.ns.text[0] == 127) _glfw.ns.text[0] = 0; // dont send text for ascii control codes - debug_key(@"scancode: 0x%x (%s) mods: %stext: %s glfw_key: %s\n", + if (!window->ns.textInputFilterCallback || window->ns.textInputFilterCallback(key, mods, scancode) != 1) { + // this will call insertText with the text for this event, if any + [self interpretKeyEvents:[NSArray arrayWithObject:event]]; + if ((1 <= _glfw.ns.text[0] && _glfw.ns.text[0] <= 31) || (unsigned)_glfw.ns.text[0] == 127) _glfw.ns.text[0] = 0; // dont send text for ascii control codes + } + debug_key(@"scancode: 0x%x (%s)%stext: %s glfw_key: %s\n", scancode, safe_name_for_scancode(scancode), format_mods(mods), format_text(_glfw.ns.text), _glfwGetKeyName(key)); _glfwInputKeyboard(window, key, scancode, GLFW_PRESS, mods, _glfw.ns.text, 0); @@ -2000,3 +2002,11 @@ GLFWAPI id glfwGetCocoaWindow(GLFWwindow* handle) _GLFW_REQUIRE_INIT_OR_RETURN(nil); return window->ns.object; } + +GLFWAPI GLFWcocoatextinputfilterfun glfwSetCocoaTextInputFilter(GLFWwindow *handle, GLFWcocoatextinputfilterfun callback) { + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(nil); + GLFWcocoatextinputfilterfun previous = window->ns.textInputFilterCallback; + window->ns.textInputFilterCallback = callback; + return previous; +} diff --git a/glfw/glfw.py b/glfw/glfw.py index 8b5505a6c..7446dff6c 100755 --- a/glfw/glfw.py +++ b/glfw/glfw.py @@ -196,6 +196,7 @@ def generate_wrappers(glfw_header, glfw_native_header): for line in '''\ void* glfwGetCocoaWindow(GLFWwindow* window) uint32_t glfwGetCocoaMonitor(GLFWmonitor* monitor) + GLFWcocoatextinputfilterfun glfwSetCocoaTextInputFilter(GLFWwindow* window, GLFWcocoatextinputfilterfun callback) void* glfwGetX11Display(void) int32_t glfwGetX11Window(GLFWwindow* window) void glfwSetX11SelectionString(const char* string) @@ -212,6 +213,7 @@ def generate_wrappers(glfw_header, glfw_native_header): #pragma once #include #include +typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int); {} {} diff --git a/kitty/glfw-wrapper.c b/kitty/glfw-wrapper.c index d3a839ba4..1b142ca5c 100644 --- a/kitty/glfw-wrapper.c +++ b/kitty/glfw-wrapper.c @@ -357,6 +357,8 @@ load_glfw(const char* path) { *(void **) (&glfwGetCocoaMonitor_impl) = dlsym(handle, "glfwGetCocoaMonitor"); + *(void **) (&glfwSetCocoaTextInputFilter_impl) = dlsym(handle, "glfwSetCocoaTextInputFilter"); + *(void **) (&glfwGetX11Display_impl) = dlsym(handle, "glfwGetX11Display"); *(void **) (&glfwGetX11Window_impl) = dlsym(handle, "glfwGetX11Window"); diff --git a/kitty/glfw-wrapper.h b/kitty/glfw-wrapper.h index 72ce55ed3..74010ab47 100644 --- a/kitty/glfw-wrapper.h +++ b/kitty/glfw-wrapper.h @@ -1,6 +1,7 @@ #pragma once #include #include +typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int); /*! @name GLFW version macros @@ -1825,6 +1826,10 @@ typedef uint32_t (*glfwGetCocoaMonitor_func)(GLFWmonitor*); glfwGetCocoaMonitor_func glfwGetCocoaMonitor_impl; #define glfwGetCocoaMonitor glfwGetCocoaMonitor_impl +typedef GLFWcocoatextinputfilterfun (*glfwSetCocoaTextInputFilter_func)(GLFWwindow*, GLFWcocoatextinputfilterfun); +glfwSetCocoaTextInputFilter_func glfwSetCocoaTextInputFilter_impl; +#define glfwSetCocoaTextInputFilter glfwSetCocoaTextInputFilter_impl + typedef void* (*glfwGetX11Display_func)(); glfwGetX11Display_func glfwGetX11Display_impl; #define glfwGetX11Display glfwGetX11Display_impl diff --git a/kitty/glfw.c b/kitty/glfw.c index bc5d0dff7..b04718d79 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -309,6 +309,13 @@ set_dpi_from_os_window(OSWindow *w) { static bool is_first_window = true; +#ifdef __APPLE__ +static int +filter_option(int key UNUSED, int mods, unsigned int scancode UNUSED) { + return ((mods == GLFW_MOD_ALT) || (mods == (GLFW_MOD_ALT | GLFW_MOD_SHIFT))) ? 1 : 0; +} +#endif + static PyObject* create_os_window(PyObject UNUSED *self, PyObject *args) { int width, height, x = -1, y = -1; @@ -367,6 +374,7 @@ create_os_window(PyObject UNUSED *self, PyObject *args) { Py_DECREF(ret); #ifdef __APPLE__ cocoa_create_global_menu(); + if (OPT(macos_option_as_alt)) glfwSetCocoaTextInputFilter(glfw_window, filter_option); #endif is_first_window = false; } diff --git a/kitty/keys.c b/kitty/keys.c index 013adf820..eae62eb5a 100644 --- a/kitty/keys.c +++ b/kitty/keys.c @@ -43,22 +43,6 @@ active_window() { return NULL; } -void -on_text_input(unsigned int codepoint, int mods) { - Window *w = active_window(); - static char buf[16]; - unsigned int sz = 0; - - if (w != NULL) { - bool is_text = mods <= GLFW_MOD_SHIFT; - if (is_text) sz = encode_utf8(codepoint, buf); -#ifdef __APPLE__ - if (!OPT(macos_option_as_alt) && IS_ALT_MODS(mods)) sz = encode_utf8(codepoint, buf); -#endif - if (sz) schedule_write_to_child(w->id, buf, sz); - } -} - static inline bool is_modifier_key(int key) { switch(key) { @@ -107,9 +91,6 @@ on_key_input(int key, int scancode, int action, int mods, const char* text, int } Screen *screen = w->render_data.screen; bool has_text = text && !is_ascii_control_char(text[0]); -#ifdef __APPLE__ - if (has_text && IS_ALT_MODS(mods) && OPT(macos_option_as_alt)) has_text = false; -#endif if (action == GLFW_PRESS || action == GLFW_REPEAT) { uint16_t qkey = (0 <= key && key < (ssize_t)arraysz(key_map)) ? key_map[key] : UINT8_MAX; bool special = false;