diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cc445010..896e958a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -158,11 +158,12 @@ endif() if (GLFW_BUILD_COCOA) target_link_libraries(glfw PRIVATE "-framework Cocoa" + "-framework Carbon" "-framework IOKit" "-framework CoreFoundation") set(glfw_PKG_DEPS "") - set(glfw_PKG_LIBS "-framework Cocoa -framework IOKit -framework CoreFoundation") + set(glfw_PKG_LIBS "-framework Cocoa -framework Carbon -framework IOKit -framework CoreFoundation") endif() if (GLFW_BUILD_WAYLAND) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 444bd563..848e3a97 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -331,6 +331,10 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; window->ns.occluded = GLFW_TRUE; } +- (void)imeStatusChangeNotified:(NSNotification *)notification { + _glfwInputIMEStatus(window); +} + @end @@ -687,6 +691,57 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; markedText = [[NSMutableAttributedString alloc] initWithAttributedString:string]; else markedText = [[NSMutableAttributedString alloc] initWithString:string]; + + NSString* markedTextString = markedText.string; + + NSUInteger i, length = [markedTextString length]; + int ctext = window->ctext; + while (ctext < length+1) { + ctext = (ctext == 0) ? 1 : ctext*2; + } + if (ctext != window->ctext) { + unsigned int* preeditText = realloc(window->preeditText, sizeof(unsigned int)*ctext); + if (preeditText == NULL) { + return; + } + window->preeditText = preeditText; + window->ctext = ctext; + } + window->ntext = length; + window->preeditText[length] = 0; + for (i = 0; i < length; i++) + { + const unichar codepoint = [markedTextString characterAtIndex:i]; + window->preeditText[i] = codepoint; + } + int focusedBlock = 0; + NSInteger offset = 0; + window->nblocks = 0; + while (offset < length) { + NSRange effectiveRange; + NSDictionary *attributes = [markedText attributesAtIndex:offset effectiveRange:&effectiveRange]; + + if (window->nblocks == window->cblocks) { + int cblocks = window->cblocks * 2; + int* blocks = realloc(window->preeditAttributeBlocks, sizeof(int)*cblocks); + if (blocks == NULL) { + return; + } + window->preeditAttributeBlocks = blocks; + window->cblocks = cblocks; + } + window->preeditAttributeBlocks[window->nblocks] = effectiveRange.length; + offset += effectiveRange.length; + if (effectiveRange.length == 0) { + break; + } + NSNumber* underline = (NSNumber*) [attributes objectForKey:@"NSUnderline"]; + if ([underline intValue] != 1) { + focusedBlock = window->nblocks; + } + window->nblocks++; + } + _glfwInputPreedit(window, focusedBlock); } - (void)unmarkText @@ -958,6 +1013,12 @@ int _glfwCreateWindowCocoa(_GLFWwindow* window, } } + [[NSNotificationCenter defaultCenter] + addObserver: window->ns.delegate + selector:@selector(imeStatusChangeNotified:) + name:NSTextInputContextKeyboardSelectionDidChangeNotification + object: nil]; + return GLFW_TRUE; } // autoreleasepool @@ -970,6 +1031,8 @@ void _glfwDestroyWindowCocoa(_GLFWwindow* window) if (_glfw.ns.disabledCursorWindow == window) _glfw.ns.disabledCursorWindow = NULL; + [[NSNotificationCenter defaultCenter] removeObserver: window->ns.delegate]; + [window->ns.object orderOut:nil]; if (window->monitor) @@ -1930,6 +1993,49 @@ VkResult _glfwCreateWindowSurfaceCocoa(VkInstance instance, } // autoreleasepool } +void _glfwPlatformResetPreeditText(_GLFWwindow* window) +{ + NSTextInputContext *context = [NSTextInputContext currentInputContext]; + [context discardMarkedText]; + [window->ns.view unmarkText]; +} + +void _glfwPlatformSetIMEStatus(_GLFWwindow* window, int active) +{ + // Mac OS has several input sources. + // this code assumes input methods not in ascii capable inputs using IME. + NSArray* asciiInputSources = CFBridgingRelease(TISCreateASCIICapableInputSourceList()); + TISInputSourceRef asciiSource = (__bridge TISInputSourceRef)([asciiInputSources firstObject]); + if (active) { + NSArray* allInputSources = CFBridgingRelease(TISCreateInputSourceList(NULL, false)); + NSString* asciiSourceID = (__bridge NSString *)(TISGetInputSourceProperty(asciiSource, kTISPropertyInputSourceID)); + int i; + int count = [allInputSources count]; + for (i = 0; i < count; i++) { + TISInputSourceRef source = (__bridge TISInputSourceRef)([allInputSources objectAtIndex: i]); + NSString* sourceID = (__bridge NSString *)(TISGetInputSourceProperty(source, kTISPropertyInputSourceID)); + if ([asciiSourceID compare: sourceID] != NSOrderedSame) { + TISSelectInputSource(source); + break; + } + } + } else if (asciiSource) { + TISSelectInputSource(asciiSource); + } +} + +int _glfwPlatformGetIMEStatus(_GLFWwindow* window) +{ + TISInputSourceRef currentSource = TISCopyCurrentKeyboardInputSource(); + NSString* currentSourceID = (__bridge NSString *)(TISGetInputSourceProperty(currentSource, kTISPropertyInputSourceID)); + NSArray* asciiInputSources = CFBridgingRelease(TISCreateASCIICapableInputSourceList()); + TISInputSourceRef asciiSource = (__bridge TISInputSourceRef)([asciiInputSources firstObject]); + if (asciiSource) { + NSString* asciiSourceID = (__bridge NSString *)(TISGetInputSourceProperty(asciiSource, kTISPropertyInputSourceID)); + return ([asciiSourceID compare: currentSourceID] == NSOrderedSame) ? GLFW_FALSE : GLFW_TRUE; + } + return GLFW_FALSE; +} ////////////////////////////////////////////////////////////////////////// ////// GLFW native API //////