Tk Source Code

Artifact [e4c581165d]
Login

Artifact e4c581165d3560eae34064d724dd2fd130acea6b:

Attachment "tkc_inputManager_20120125.patch" to ticket [3205153fff] added by arobert3434 2012-01-26 10:41:58.
Index: macosx/tkMacOSXKeyEvent.c
===================================================================
--- macosx/tkMacOSXKeyEvent.c
+++ macosx/tkMacOSXKeyEvent.c
@@ -17,168 +17,426 @@
 /*
 #ifdef TK_MAC_DEBUG
 #define TK_MAC_DEBUG_KEYBOARD
 #endif
 */
+#define NS_KEYLOG 0
+
 
 static Tk_Window grabWinPtr = NULL;
 				/* Current grab window, NULL if no grab. */
 static Tk_Window keyboardGrabWinPtr = NULL;
 				/* Current keyboard grab window. */
 static NSModalSession modalSession = NULL;
 
+static BOOL processingCompose = NO;
+static BOOL finishedCompose = NO;
+
+static int caret_x = 0, caret_y = 0, caret_height = 0;
+
+static void setupXEvent(XEvent *xEvent, NSWindow *w, unsigned int state);
+static unsigned isFunctionKey(unsigned int code);
+
+
 #pragma mark TKApplication(TKKeyEvent)
 
 @implementation TKApplication(TKKeyEvent)
+
 - (NSEvent *) tkProcessKeyEvent: (NSEvent *) theEvent
 {
 #ifdef TK_MAC_DEBUG_EVENTS
     TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, theEvent);
 #endif
     NSWindow*	    w;
     NSEventType	    type = [theEvent type];
-    NSUInteger	    modifiers, len;
+    NSUInteger	    modifiers, len = 0;
     BOOL	    repeat = NO;
     unsigned short  keyCode;
     NSString	    *characters = nil, *charactersIgnoringModifiers = nil;
     static NSUInteger savedModifiers = 0;
+    static NSMutableArray *nsEvArray;
+
+    if (nsEvArray == nil)
+      {
+        nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
+        processingCompose = NO;
+      }
 
     switch (type) {
     case NSKeyUp:
+      if (finishedCompose)
+        {
+          // if we were composing, swallow the last release since we already sent
+          finishedCompose = NO;
+          return theEvent;
+        }
     case NSKeyDown:
 	repeat = [theEvent isARepeat];
 	characters = [theEvent characters];
 	charactersIgnoringModifiers = [theEvent charactersIgnoringModifiers];
+        len = [charactersIgnoringModifiers length];
     case NSFlagsChanged:
 	modifiers = [theEvent modifierFlags];
 	keyCode = [theEvent keyCode];
 	w = [self windowWithWindowNumber:[theEvent windowNumber]];
-#ifdef TK_MAC_DEBUG_EVENTS
-	TKLog(@"-[%@(%p) %s] %d %u %@ %@ %u %@", [self class], self, _cmd, repeat, modifiers, characters, charactersIgnoringModifiers, keyCode, w);
+#if defined(TK_MAC_DEBUG_EVENTS) || NS_KEYLOG == 1
+	NSLog(@"-[%@(%p) %s] r=%d mods=%u '%@' '%@' code=%u c=%d %@ %d", [self class], self, _cmd, repeat, modifiers, characters, charactersIgnoringModifiers, keyCode,([charactersIgnoringModifiers length] == 0) ? 0 : [charactersIgnoringModifiers characterAtIndex: 0], w, type);
 #endif
 	break;
 
     default:
 	return theEvent;
     }
 
-    unsigned int state = 0;
-
-    if (modifiers & NSAlphaShiftKeyMask) {
-	state |= LockMask;
-    }
-    if (modifiers & NSShiftKeyMask) {
-	state |= ShiftMask;
-    }
-    if (modifiers & NSControlKeyMask) {
-	state |= ControlMask;
-    }
-    if (modifiers & NSCommandKeyMask) {
-	state |= Mod1Mask;		/* command key */
-    }
-    if (modifiers & NSAlternateKeyMask) {
-	state |= Mod2Mask;		/* option key */
-    }
-    if (modifiers & NSNumericPadKeyMask) {
-	state |= Mod3Mask;
-    }
-    if (modifiers & NSFunctionKeyMask) {
-	state |= Mod4Mask;
-    }
-
-    /*
-     * The focus must be in the FrontWindow on the Macintosh. We then query Tk
-     * to determine the exact Tk window that owns the focus.
-     */
-
-    TkWindow *winPtr = TkMacOSXGetTkWindow(w);
-    Tk_Window tkwin = (Tk_Window) winPtr;
-
-    if (!tkwin) {
-	TkMacOSXDbgMsg("tkwin == NULL");
-	return theEvent;
-    }
-    tkwin = (Tk_Window) winPtr->dispPtr->focusPtr;
-    if (!tkwin) {
-	TkMacOSXDbgMsg("tkwin == NULL");
-	return theEvent;
-    }
-
-    XEvent xEvent;
-
-    memset(&xEvent, 0, sizeof(XEvent));
-    xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
-    xEvent.xany.send_event = false;
-    xEvent.xany.display = Tk_Display(tkwin);
-    xEvent.xany.window = Tk_WindowId(tkwin);
-
-    xEvent.xkey.root = XRootWindow(Tk_Display(tkwin), 0);
-    xEvent.xkey.subwindow = None;
-    xEvent.xkey.time = TkpGetMS();
-    xEvent.xkey.state = state;
-    xEvent.xkey.same_screen = true;
-    xEvent.xkey.trans_chars[0] = 0;
-    xEvent.xkey.nbytes = 0;
-
-    if (type == NSFlagsChanged) {
-	if (savedModifiers > modifiers) {
-	    xEvent.xany.type = KeyRelease;
-	} else {
-	    xEvent.xany.type = KeyPress;
-	}
-
-	/*
-	 * Use special '-1' to signify a special keycode to our platform
-	 * specific code in tkMacOSXKeyboard.c. This is rather like what
-	 * happens on Windows.
-	 */
-
-	xEvent.xany.send_event = -1;
-
-	/*
-	 * Set keycode (which was zero) to the changed modifier
-	 */
-
-	xEvent.xkey.keycode = (modifiers ^ savedModifiers);
-    } else {
-	if (type == NSKeyUp || repeat) {
-	    xEvent.xany.type = KeyRelease;
-	} else {
-	    xEvent.xany.type = KeyPress;
-	}
-
-/* prevent SF bug 2907388 here (crash on composite characters) */
-if ([characters length] > 0) {
-	xEvent.xkey.keycode = (keyCode << 16) | (UInt16)
-		[characters characterAtIndex:0];
-	if (![characters getCString:xEvent.xkey.trans_chars
-		maxLength:XMaxTransChars encoding:NSUTF8StringEncoding]) {
-	    TkMacOSXDbgMsg("characters too long");
-	    return theEvent;
-	}
-}
-/* end workaround */
-
-	len = [charactersIgnoringModifiers length];
-	if (len) {
-	    xEvent.xkey.nbytes = [charactersIgnoringModifiers characterAtIndex:0];
-	    if (len > 1) {
-		TkMacOSXDbgMsg("more than one charactersIgnoringModifiers");
-	    }
-	}
-	if (repeat) {
-	    Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
-	    xEvent.xany.type = KeyPress;
-	    xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
-	}
-    }
-    Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
+    if (!processingCompose) {
+        unsigned int state = 0;
+
+        if (modifiers & NSAlphaShiftKeyMask) {
+          state |= LockMask;
+        }
+        if (modifiers & NSShiftKeyMask) {
+          state |= ShiftMask;
+        }
+        if (modifiers & NSControlKeyMask) {
+          state |= ControlMask;
+        }
+        if (modifiers & NSCommandKeyMask) {
+          state |= Mod1Mask;		/* command key */
+        }
+        if (modifiers & NSAlternateKeyMask) {
+          state |= Mod2Mask;		/* option key */
+        }
+        if (modifiers & NSNumericPadKeyMask) {
+          state |= Mod3Mask;
+        }
+        if (modifiers & NSFunctionKeyMask) {
+          state |= Mod4Mask;
+        }
+
+        /*
+         * The focus must be in the FrontWindow on the Macintosh. We then query Tk
+         * to determine the exact Tk window that owns the focus.
+         */
+
+        TkWindow *winPtr = TkMacOSXGetTkWindow(w);
+        Tk_Window tkwin = (Tk_Window) winPtr;
+
+        if (!tkwin) {
+          TkMacOSXDbgMsg("tkwin == NULL");
+          return theEvent;
+        }
+        tkwin = (Tk_Window) winPtr->dispPtr->focusPtr;
+        if (!tkwin) {
+          TkMacOSXDbgMsg("tkwin == NULL");
+          return theEvent;
+        }
+
+        /*
+         * If it's a function key, or we have modifiers other than Shift or Alt,
+         * pass it straight to Tk.  Otherwise we'll send for input processing.
+         */
+        int code = (len == 0) ?
+          0 : [charactersIgnoringModifiers characterAtIndex: 0];
+        if (type != NSKeyDown || isFunctionKey(code)
+            || (len > 0 && state & (ControlMask | Mod1Mask | Mod3Mask | Mod4Mask))) {
+
+            XEvent xEvent;
+            setupXEvent(&xEvent, w, state);
+
+            if (type == NSFlagsChanged) {
+              if (savedModifiers > modifiers) {
+                xEvent.xany.type = KeyRelease;
+              } else {
+                xEvent.xany.type = KeyPress;
+              }
+
+              /*
+               * Use special '-1' to signify a special keycode to our platform
+               * specific code in tkMacOSXKeyboard.c. This is rather like what
+               * happens on Windows.
+               */
+
+              xEvent.xany.send_event = -1;
+
+              /*
+               * Set keycode (which was zero) to the changed modifier
+               */
+
+              xEvent.xkey.keycode = (modifiers ^ savedModifiers);
+            } else {
+              if (type == NSKeyUp || repeat) {
+                xEvent.xany.type = KeyRelease;
+              } else {
+                xEvent.xany.type = KeyPress;
+              }
+
+              /* For command key, take input manager's word so things
+                 like dvorak / qwerty layout work. */
+              if ((modifiers & NSCommandKeyMask) == NSCommandKeyMask
+                  && (modifiers & NSAlternateKeyMask) != NSAlternateKeyMask
+                  && len > 0 && !isFunctionKey(code)) {
+                // head off keycode-based translation in tkMacOSXKeyboard.c
+                xEvent.xkey.nbytes = [characters length]; //len
+              }
+
+              if ([characters length] > 0) {
+                xEvent.xkey.keycode =
+                  (keyCode << 16) | (UInt16) [characters characterAtIndex:0];
+                if (![characters getCString:xEvent.xkey.trans_chars
+                                  maxLength:XMaxTransChars encoding:NSUTF8StringEncoding]) {
+                  /* prevent SF bug 2907388 (crash on some composite chars) */
+                  //PENDING: we might not need this anymore
+                  TkMacOSXDbgMsg("characters too long");
+                  return theEvent;
+                }
+              }
+
+              if (repeat) {
+                Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
+                xEvent.xany.type = KeyPress;
+                xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
+              }
+            }
+            Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
+            savedModifiers = modifiers;
+            return theEvent;
+          }  /* if send straight to TK */
+
+      }  /* if not processing compose */
+
+    if (type == NSKeyDown) {
+        if (NS_KEYLOG)
+          fprintf (stderr, "keyDown: %s compose sequence.\n",
+                   processingCompose == YES ? "Continue" : "Begin");
+        processingCompose = YES;
+        [nsEvArray addObject: theEvent];
+        [[w contentView] interpretKeyEvents: nsEvArray];
+        [nsEvArray removeObject: theEvent];
+      }
+
     savedModifiers = modifiers;
 
     return theEvent;
 }
 @end
+
+
+
+@implementation TKContentView(TKKeyEvent)
+/* <NSTextInput> implementation (called through interpretKeyEvents:]). */
+
+/* <NSTextInput>: called when done composing;
+   NOTE: also called when we delete over working text, followed immed.
+         by doCommandBySelector: deleteBackward: */
+- (void)insertText: (id)aString
+{
+  int i, len = [(NSString *)aString length];
+  XEvent xEvent;
+  TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);
+  Tk_Window tkwin = (Tk_Window) winPtr;
+
+  if (NS_KEYLOG)
+    NSLog (@"insertText '%@'\tlen = %d", aString, len);
+  processingCompose = NO;
+  finishedCompose = YES;
+
+  /* first, clear any working text */
+  if (_workingText != nil)
+    [self deleteWorkingText];
+
+  /* now insert the string as keystrokes */
+  setupXEvent(&xEvent, [self window], 0);
+  xEvent.xany.type = KeyPress;
+
+  for (i =0; i<len; i++)
+    {
+      xEvent.xkey.keycode = (UInt16) [aString characterAtIndex: i];
+      [[aString substringWithRange: NSMakeRange(i,1)]
+        getCString: xEvent.xkey.trans_chars
+         maxLength: XMaxTransChars encoding: NSUTF8StringEncoding];
+      xEvent.xkey.nbytes = strlen(xEvent.xkey.trans_chars);
+      xEvent.xany.type = KeyPress;
+      Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
+
+      xEvent.xany.type = KeyRelease;
+      xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
+      Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
+      xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
+    }
+}
+
+
+/* <NSTextInput>: inserts display of composing characters */
+- (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
+{
+  NSString *str = [aString respondsToSelector: @selector (string)] ?
+    [aString string] : aString;
+  if (NS_KEYLOG)
+    NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
+           selRange.length, selRange.location);
+
+  if (_workingText != nil)
+    [self deleteWorkingText];
+  if ([str length] == 0)
+    return;
+
+  processingCompose = YES;
+  _workingText = [str copy];
+
+  //PENDING: insert workingText underlined
+}
+
+
+/* delete display of composing characters [not in <NSTextInput>] */
+- (void)deleteWorkingText
+{
+  if (_workingText == nil)
+    return;
+  if (NS_KEYLOG)
+    NSLog(@"deleteWorkingText len = %d\n", [_workingText length]);
+  [_workingText release];
+  _workingText = nil;
+  processingCompose = NO;
+
+  //PENDING: delete working text
+}
+
+
+- (BOOL)hasMarkedText
+{
+  return _workingText != nil;
+}
+
+
+- (NSRange)markedRange
+{
+  NSRange rng = _workingText != nil
+    ? NSMakeRange (0, [_workingText length]) : NSMakeRange (NSNotFound, 0);
+  if (NS_KEYLOG)
+    NSLog (@"markedRange request");
+  return rng;
+}
+
+
+- (void)unmarkText
+{
+  if (NS_KEYLOG)
+    NSLog (@"unmark (accept) text");
+  [self deleteWorkingText];
+  processingCompose = NO;
+}
+
+
+/* used to position char selection windows, etc. */
+- (NSRect)firstRectForCharacterRange: (NSRange)theRange
+{
+  NSRect rect;
+  NSPoint pt;
+
+  pt.x = caret_x;
+  pt.y = caret_y;
+
+  pt = [self convertPoint: pt toView: nil];
+  pt = [[self window] convertBaseToScreen: pt];
+  pt.y -= caret_height;
+
+  rect.origin = pt;
+  rect.size.width = caret_height;
+  rect.size.height = caret_height;
+  return rect;
+}
+
+
+- (NSInteger)conversationIdentifier
+{
+  return (NSInteger)self;
+}
+
+
+- (void)doCommandBySelector: (SEL)aSelector
+{
+  if (NS_KEYLOG)
+    NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
+  processingCompose = NO;
+  if (aSelector == @selector (deleteBackward:))
+    {
+      /* happens when user backspaces over an ongoing composition:
+         throw a 'delete' into the event queue */
+      XEvent xEvent;
+      setupXEvent(&xEvent, [self window], 0);
+      xEvent.xany.type = KeyPress;
+      xEvent.xkey.nbytes = 1;
+      xEvent.xkey.keycode = (0x33 << 16) | 0x7F;
+      xEvent.xkey.trans_chars[0] = 0x7F;
+      xEvent.xkey.trans_chars[1] = 0x0;
+      Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
+    }
+}
+
+
+- (NSArray *)validAttributesForMarkedText
+{
+  static NSArray *arr = nil;
+  if (arr == nil) arr = [NSArray new];
+ /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
+  return arr;
+}
+
+
+- (NSRange)selectedRange
+{
+  if (NS_KEYLOG)
+    NSLog (@"selectedRange request");
+  return NSMakeRange (NSNotFound, 0);
+}
+
+
+- (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
+{
+  if (NS_KEYLOG)
+    NSLog (@"characterIndexForPoint request");
+  return 0;
+}
+
+
+- (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
+{
+  static NSAttributedString *str = nil;
+  if (str == nil) str = [NSAttributedString new];
+  if (NS_KEYLOG)
+    NSLog (@"attributedSubstringFromRange request");
+  return str;
+}
+/* End <NSTextInput> impl. */
+@end
+
+
+
+/*
+ *  Set up basic fields in xevent for keyboard input.
+ */
+static void
+setupXEvent(XEvent *xEvent, NSWindow *w, unsigned int state)
+{
+    TkWindow *winPtr = TkMacOSXGetTkWindow(w);
+    Tk_Window tkwin = (Tk_Window) winPtr;
+
+    memset(xEvent, 0, sizeof(XEvent));
+    xEvent->xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
+    xEvent->xany.send_event = false;
+    xEvent->xany.display = Tk_Display(tkwin);
+    xEvent->xany.window = Tk_WindowId(tkwin);
+
+    xEvent->xkey.root = XRootWindow(Tk_Display(tkwin), 0);
+    xEvent->xkey.subwindow = None;
+    xEvent->xkey.time = TkpGetMS();
+    xEvent->xkey.state = state;
+    xEvent->xkey.same_screen = true;
+    xEvent->xkey.trans_chars[0] = 0;
+    xEvent->xkey.nbytes = 0;
+}
 
 #pragma mark -
 
 /*
  *----------------------------------------------------------------------
@@ -342,10 +600,120 @@
     Tk_Window tkwin,
     int x,
     int y,
     int height)
 {
+    TkCaret *caretPtr = &(((TkWindow *) tkwin)->dispPtr->caret);
+
+    /*
+     * Prevent processing anything if the values haven't changed. Windows only
+     * has one display, so we can do this with statics.
+     */
+
+    if ((caretPtr->winPtr == ((TkWindow *) tkwin))
+	    && (caretPtr->x == x) && (caretPtr->y == y)) {
+	return;
+    }
+
+    caretPtr->winPtr = ((TkWindow *) tkwin);
+    caretPtr->x = x;
+    caretPtr->y = y;
+    caretPtr->height = height;
+
+    /*
+     * As in Windows, adjust to the toplevel to get the coords right.
+     */
+
+    while (!Tk_IsTopLevel(tkwin)) {
+	x += Tk_X(tkwin);
+	y += Tk_Y(tkwin);
+	tkwin = Tk_Parent(tkwin);
+	if (tkwin == NULL) {
+	    return;
+	}
+    }
+
+    /* But adjust for fact that NS uses flipped view. */
+    y = Tk_Height(tkwin) - y;
+
+    caret_x = x;
+    caret_y = y;
+    caret_height = height;
+}
+
+
+
+static unsigned convert_ns_to_X_keysym[] =
+{
+  NSHomeFunctionKey,            0x50,
+  NSLeftArrowFunctionKey,       0x51,
+  NSUpArrowFunctionKey,         0x52,
+  NSRightArrowFunctionKey,      0x53,
+  NSDownArrowFunctionKey,       0x54,
+  NSPageUpFunctionKey,          0x55,
+  NSPageDownFunctionKey,        0x56,
+  NSEndFunctionKey,             0x57,
+  NSBeginFunctionKey,           0x58,
+  NSSelectFunctionKey,          0x60,
+  NSPrintFunctionKey,           0x61,
+  NSExecuteFunctionKey,         0x62,
+  NSInsertFunctionKey,          0x63,
+  NSUndoFunctionKey,            0x65,
+  NSRedoFunctionKey,            0x66,
+  NSMenuFunctionKey,            0x67,
+  NSFindFunctionKey,            0x68,
+  NSHelpFunctionKey,            0x6A,
+  NSBreakFunctionKey,           0x6B,
+
+  NSF1FunctionKey,              0xBE,
+  NSF2FunctionKey,              0xBF,
+  NSF3FunctionKey,              0xC0,
+  NSF4FunctionKey,              0xC1,
+  NSF5FunctionKey,              0xC2,
+  NSF6FunctionKey,              0xC3,
+  NSF7FunctionKey,              0xC4,
+  NSF8FunctionKey,              0xC5,
+  NSF9FunctionKey,              0xC6,
+  NSF10FunctionKey,             0xC7,
+  NSF11FunctionKey,             0xC8,
+  NSF12FunctionKey,             0xC9,
+  NSF13FunctionKey,             0xCA,
+  NSF14FunctionKey,             0xCB,
+  NSF15FunctionKey,             0xCC,
+  NSF16FunctionKey,             0xCD,
+  NSF17FunctionKey,             0xCE,
+  NSF18FunctionKey,             0xCF,
+  NSF19FunctionKey,             0xD0,
+  NSF20FunctionKey,             0xD1,
+  NSF21FunctionKey,             0xD2,
+  NSF22FunctionKey,             0xD3,
+  NSF23FunctionKey,             0xD4,
+  NSF24FunctionKey,             0xD5,
+
+  NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
+  NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
+  NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
+
+  NSTabCharacter,		0x09,
+  0x19,				0x09,  /* left tab->regular since pass shift */
+  NSCarriageReturnCharacter,	0x0D,
+  NSNewlineCharacter,		0x0D,
+  NSEnterCharacter,		0x8D,
+
+  0x1B,				0x1B   /* escape */
+};
+
+
+static unsigned isFunctionKey(unsigned code)
+{
+    const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
+                                / sizeof (convert_ns_to_X_keysym[0]));
+  unsigned keysym;
+  for (keysym = 0; keysym < last_keysym; keysym += 2)
+    if (code == convert_ns_to_X_keysym[keysym])
+      return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
+  return 0;
 }
 
 /*
  * Local Variables:
  * mode: objc

Index: macosx/tkMacOSXKeyboard.c
===================================================================
--- macosx/tkMacOSXKeyboard.c
+++ macosx/tkMacOSXKeyboard.c
@@ -764,15 +764,15 @@
 
 	    return NoSymbol;
 	}
     }
 
-#if 0
+    /* If nbytes has been set, it's not a function key, but a regular key that
+       has been translated in tkMacOSXKeyEvent.c; just use that. */
     if (eventPtr->xkey.nbytes) {
-	return eventPtr->xkey.nbytes;
+      return eventPtr->xkey.keycode & 0xFFFF;
     }
-#endif
 
     /*
      * Figure out which of the four slots in the keymap vector to use for this
      * key. Refer to Xlib documentation for more info on how this computation
      * works. (Note: We use "Option" in keymap columns 2 and 3 where other

Index: macosx/tkMacOSXMenu.c
===================================================================
--- macosx/tkMacOSXMenu.c
+++ macosx/tkMacOSXMenu.c
@@ -288,10 +288,16 @@
 	    NSDeviceIndependentModifierFlagsMask;
 
     if (modifiers == (NSCommandKeyMask | NSShiftKeyMask) &&
 	    [key compare:@"?"] == NSOrderedSame) {
 	return NO;
+    }
+
+    // For command key, take input manager's word so things
+    // like dvorak / qwerty layout work.
+    if (([event modifierFlags] & NSCommandKeyMask) == NSCommandKeyMask) {
+      key = [event characters];
     }
 
     NSArray *itemArray = [self itemArray];
 
     for (NSMenuItem *item in itemArray) {

Index: macosx/tkMacOSXPrivate.h
===================================================================
--- macosx/tkMacOSXPrivate.h
+++ macosx/tkMacOSXPrivate.h
@@ -314,15 +314,20 @@
 - (void)tkProvidePasteboard:(TkDisplay *)dispPtr;
 - (void)tkCheckPasteboard;
 @end
 
 VISIBILITY_HIDDEN
-@interface TKContentView : NSView {
+@interface TKContentView : NSView <NSTextInput> {
 @private
     id _savedSubviews;
     BOOL _subviewsSetAside;
+    NSString *_workingText;
 }
+@end
+
+@interface TKContentView(TKKeyEvent)
+- (void) deleteWorkingText;
 @end
 
 VISIBILITY_HIDDEN
 @interface TKWindow : NSWindow
 @end