浏览代码

Implement NSTextInputClient protocol on OS X

This provides support for IME character composition.

Fixes #456.
Closes #643.
Mario Dorn 9 年之前
父节点
当前提交
3107c9548d
共有 2 个文件被更改,包括 95 次插入14 次删除
  1. 2 0
      README.md
  2. 93 14
      src/cocoa_window.m

+ 2 - 0
README.md

@@ -105,6 +105,7 @@ does not find Doxygen, the documentation will not be generated.
  - [Cocoa] Bugfix: Full screen windows on secondary monitors were mispositioned
  - [Cocoa] Bugfix: Connecting a joystick that reports no name would segfault
  - [Cocoa] Bugfix: Modifier flags cache was not updated when window became key
+ - [Cocoa] Bugfix: Dead key character composition did not work
  - [X11] Bugfix: Monitor connection and disconnection events were not reported
  - [X11] Bugfix: Decoding of UTF-8 text from XIM could continue past the end
  - [X11] Bugfix: An XKB structure was leaked during `glfwInit`
@@ -165,6 +166,7 @@ skills.
  - Paul R. Deppe
  - Michael Dickens
  - Роман Донченко
+ - Mario Dorn
  - Jonathan Dummer
  - Ralph Eastwood
  - Siavash Eliasi

+ 93 - 14
src/cocoa_window.m

@@ -146,6 +146,10 @@ static NSUInteger translateKeyToModifierFlag(int key)
     return 0;
 }
 
+// Defines a constant for empty ranges in NSTextInputClient
+//
+static const NSRange kEmptyRange = {NSNotFound, 0};
+
 
 //------------------------------------------------------------------------
 // Delegate for window related notifications
@@ -296,10 +300,11 @@ static NSUInteger translateKeyToModifierFlag(int key)
 // Content view class for the GLFW window
 //------------------------------------------------------------------------
 
-@interface GLFWContentView : NSView
+@interface GLFWContentView : NSView <NSTextInputClient>
 {
     _GLFWwindow* window;
     NSTrackingArea* trackingArea;
+    NSMutableAttributedString* markedText;
 }
 
 - (id)initWithGlfwWindow:(_GLFWwindow *)initWindow;
@@ -329,6 +334,7 @@ static NSUInteger translateKeyToModifierFlag(int key)
     {
         window = initWindow;
         trackingArea = nil;
+        markedText = [[NSMutableAttributedString alloc] init];
 
         [self updateTrackingAreas];
         [self registerForDraggedTypes:[NSArray arrayWithObjects:
@@ -338,9 +344,10 @@ static NSUInteger translateKeyToModifierFlag(int key)
     return self;
 }
 
--(void)dealloc
+- (void)dealloc
 {
     [trackingArea release];
+    [markedText release];
     [super dealloc];
 }
 
@@ -501,18 +508,7 @@ static NSUInteger translateKeyToModifierFlag(int key)
 
     _glfwInputKey(window, key, [event keyCode], GLFW_PRESS, mods);
 
-    NSString* characters = [event characters];
-    NSUInteger i, length = [characters length];
-    const int plain = !(mods & GLFW_MOD_SUPER);
-
-    for (i = 0;  i < length;  i++)
-    {
-        const unichar codepoint = [characters characterAtIndex:i];
-        if ((codepoint & 0xff00) == 0xf700)
-            continue;
-
-        _glfwInputChar(window, codepoint, mods, plain);
-    }
+    [self interpretKeyEvents:[NSArray arrayWithObject:event]];
 }
 
 - (void)flagsChanged:(NSEvent *)event
@@ -614,6 +610,89 @@ static NSUInteger translateKeyToModifierFlag(int key)
     [self setNeedsDisplay:YES];
 }
 
+- (BOOL)hasMarkedText
+{
+    return (markedText.length > 0);
+}
+
+- (NSRange)markedRange
+{
+    return (markedText.length > 0) ?
+    NSMakeRange(0, markedText.length-1) :
+    kEmptyRange;
+}
+
+- (NSRange)selectedRange
+{
+    return kEmptyRange;
+}
+
+- (void)setMarkedText:(id)aString
+        selectedRange:(NSRange)selectedRange
+     replacementRange:(NSRange)replacementRange
+{
+    if( [aString isKindOfClass: [NSAttributedString class]] )
+    {
+        [markedText initWithAttributedString: aString];
+    }
+    else
+    {
+        [markedText initWithString: aString];
+    }
+}
+
+- (void)unmarkText
+{
+    [[markedText mutableString] setString:@""];
+}
+
+- (NSArray*)validAttributesForMarkedText
+{
+    return [NSArray array];
+}
+
+- (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)aRange
+                                               actualRange:(NSRangePointer)actualRange
+{
+    return nil;
+}
+
+- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint
+{
+    return 0;
+}
+
+- (NSRect)firstRectForCharacterRange:(NSRange)aRange
+                         actualRange:(NSRangePointer)actualRange
+{
+    return NSMakeRect(0, 0, 0, 0);
+}
+
+- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange
+{
+    NSEvent* event = [NSApp currentEvent];
+    const int mods = translateFlags([event modifierFlags]);
+
+    NSString* characters;
+    if ([aString isKindOfClass: [NSAttributedString class]]) {
+        characters = [aString string];
+    } else {
+        characters = (NSString*)aString;
+    }
+
+    NSUInteger i, length = [characters length];
+    const int plain = !(mods & GLFW_MOD_SUPER);
+
+    for (i = 0;  i < length;  i++)
+    {
+        const unichar codepoint = [characters characterAtIndex:i];
+        if ((codepoint & 0xff00) == 0xf700)
+            continue;
+
+        _glfwInputChar(window, codepoint, mods, plain);
+    }
+}
+
 @end