From cf9a4e236891ce2f6d9469a017e880eed704dea0 Mon Sep 17 00:00:00 2001
From: Sven Gothel <sgothel@jausoft.com>
Date: Sun, 28 Oct 2012 05:44:24 +0100
Subject: Fix NEWT KeyCode: Basic KeyCode Validation on X11, Windows and OSX

- X11: Add VK_QUOTE mapping

- OSX: Add single shift, ctrl alt key press;
       Fix mapping: Command -> Windows, Option -> ALT, add BACK_QUOTE and QUOTE.
---
 src/newt/native/NewtMacWindow.h |  4 +++
 src/newt/native/NewtMacWindow.m | 74 ++++++++++++++++++++++++++++++++++++-----
 src/newt/native/X11Display.c    |  2 ++
 3 files changed, 71 insertions(+), 9 deletions(-)

(limited to 'src/newt/native')

diff --git a/src/newt/native/NewtMacWindow.h b/src/newt/native/NewtMacWindow.h
index c0912ad3c..29b646fbf 100644
--- a/src/newt/native/NewtMacWindow.h
+++ b/src/newt/native/NewtMacWindow.h
@@ -111,6 +111,7 @@
     BOOL mouseInside;
     BOOL cursorIsHidden;
     BOOL realized;
+    BOOL modsDown[4]; // shift, ctrl, alt/option, win/command
     NSPoint lastInsideMousePosition;
 @public
     int cachedInsets[4]; // l, r, t, b
@@ -145,6 +146,7 @@
 - (void) setMousePosition:(NSPoint)p;
 
 - (void) sendKeyEvent: (NSEvent*) event eventType: (jint) evType;
+- (void) sendKeyEvent: (jint) keyCode characters: (NSString*) chars modifiers: (NSUInteger)mods eventType: (jint) evType;
 - (void) sendMouseEvent: (NSEvent*) event eventType: (jint) evType;
 - (void) focusChanged: (BOOL) gained;
 
@@ -157,6 +159,8 @@
 - (void) windowDidResignKey: (NSNotification *) notification;
 - (void) keyDown: (NSEvent*) theEvent;
 - (void) keyUp: (NSEvent*) theEvent;
+- (void) handleFlagsChanged:(int) keyMask keyIndex: (int) keyIdx keyCode: (int) keyCode modifiers: (NSUInteger) mods;
+- (void) flagsChanged: (NSEvent *) theEvent;
 - (void) mouseEntered: (NSEvent*) theEvent;
 - (void) mouseExited: (NSEvent*) theEvent;
 - (void) mouseMoved: (NSEvent*) theEvent;
diff --git a/src/newt/native/NewtMacWindow.m b/src/newt/native/NewtMacWindow.m
index b58b99e38..de5f3773c 100644
--- a/src/newt/native/NewtMacWindow.m
+++ b/src/newt/native/NewtMacWindow.m
@@ -368,6 +368,10 @@ static jmethodID windowRepaintID = NULL;
     cachedInsets[1] = 0; // r
     cachedInsets[2] = 0; // t
     cachedInsets[3] = 0; // b
+    modsDown[0] = NO; // shift
+    modsDown[1] = NO; // ctrl
+    modsDown[2] = NO; // alt
+    modsDown[3] = NO; // win
     mouseConfined = NO;
     mouseVisible = YES;
     mouseInside = NO;
@@ -596,6 +600,14 @@ static jint mods2JavaMods(NSUInteger mods)
 }
 
 - (void) sendKeyEvent: (NSEvent*) event eventType: (jint) evType
+{
+    jint keyCode = (jint) [event keyCode];
+    NSString* chars = [event charactersIgnoringModifiers];
+    NSUInteger mods = [event modifierFlags];
+    [self sendKeyEvent: keyCode characters: chars modifiers: mods eventType: evType];
+}
+
+- (void) sendKeyEvent: (jint) keyCode characters: (NSString*) chars modifiers: (NSUInteger)mods eventType: (jint) evType
 {
     NSView* nsview = [self contentView];
     if( ! [nsview isMemberOfClass:[NewtView class]] ) {
@@ -616,16 +628,30 @@ static jint mods2JavaMods(NSUInteger mods)
     }
 
     int i;
-    jint keyCode = (jint) [event keyCode];
-    NSString* chars = [event charactersIgnoringModifiers];
-    int len = [chars length];
-    jint javaMods = mods2JavaMods([event modifierFlags]);
-
-    for (i = 0; i < len; i++) {
-        // Note: the key code in the NSEvent does not map to anything we can use
-        jchar keyChar = (jchar) [chars characterAtIndex: i];
+    int len = NULL != chars ? [chars length] : 0;
+    jint javaMods = mods2JavaMods(mods);
+
+    if(len > 0) {
+        // printable chars
+        for (i = 0; i < len; i++) {
+            // Note: the key code in the NSEvent does not map to anything we can use
+            jchar keyChar = (jchar) [chars characterAtIndex: i];
+
+            DBG_PRINT("sendKeyEvent: %d/%d char 0x%X, code 0x%X\n", i, len, (int)keyChar, (int)keyCode);
+
+            #ifdef USE_SENDIO_DIRECT
+            (*env)->CallVoidMethod(env, javaWindowObject, sendKeyEventID,
+                                   evType, javaMods, keyCode, keyChar);
+            #else
+            (*env)->CallVoidMethod(env, javaWindowObject, enqueueKeyEventID, JNI_FALSE,
+                                   evType, javaMods, keyCode, keyChar);
+            #endif
+        }
+    } else {
+        // non-printable chars
+        jchar keyChar = (jchar) -1;
 
-        DBG_PRINT("sendKeyEvent: %d/%d char 0x%X, code 0x%X\n", i, len, (int)keyChar, (int)keyCode);
+        DBG_PRINT("sendKeyEvent: code 0x%X\n", (int)keyCode);
 
         #ifdef USE_SENDIO_DIRECT
         (*env)->CallVoidMethod(env, javaWindowObject, sendKeyEventID,
@@ -805,6 +831,36 @@ static jint mods2JavaMods(NSUInteger mods)
     [self sendKeyEvent: theEvent eventType: EVENT_KEY_TYPED];
 }
 
+#define kVK_Shift     0x38
+#define kVK_Option    0x3A
+#define kVK_Control   0x3B
+#define kVK_Command   0x37
+
+- (void) handleFlagsChanged:(int) keyMask keyIndex: (int) keyIdx keyCode: (int) keyCode modifiers: (NSUInteger) mods
+{
+    if ( NO == modsDown[keyIdx] && 0 != ( mods & keyMask ) )  {
+        modsDown[keyIdx] = YES;
+        mods &= ~keyMask;
+        [self sendKeyEvent: keyCode characters: NULL modifiers: mods eventType: EVENT_KEY_TYPED];
+    } else if ( YES == modsDown[keyIdx] && 0 == ( mods & keyMask ) )  {
+        modsDown[keyIdx] = NO;
+        [self sendKeyEvent: keyCode characters: NULL modifiers: mods eventType: EVENT_KEY_RELEASED];
+        [self sendKeyEvent: keyCode characters: NULL modifiers: mods eventType: EVENT_KEY_TYPED];
+    }
+}
+
+- (void) flagsChanged:(NSEvent *) theEvent
+{
+    NSUInteger mods = [theEvent modifierFlags];
+
+    // BOOL modsDown[4]; // shift, ctrl, alt/option, win/command
+
+    [self handleFlagsChanged: NSShiftKeyMask keyIndex: 0 keyCode: kVK_Shift modifiers: mods];
+    [self handleFlagsChanged: NSControlKeyMask keyIndex: 1 keyCode: kVK_Control modifiers: mods];
+    [self handleFlagsChanged: NSAlternateKeyMask keyIndex: 2 keyCode: kVK_Option modifiers: mods];
+    [self handleFlagsChanged: NSCommandKeyMask keyIndex: 3 keyCode: kVK_Command modifiers: mods];
+}
+
 - (void) mouseEntered: (NSEvent*) theEvent
 {
     DBG_PRINT( "mouseEntered: confined %d, visible %d\n", mouseConfined, mouseVisible);
diff --git a/src/newt/native/X11Display.c b/src/newt/native/X11Display.c
index 9f29acc0c..341455f0f 100644
--- a/src/newt/native/X11Display.c
+++ b/src/newt/native/X11Display.c
@@ -148,6 +148,8 @@ static jint X11KeySym2NewtVKey(KeySym keySym) {
             return J_VK_HELP;
         case XK_grave:
             return J_VK_BACK_QUOTE;
+        case XK_apostrophe:
+            return J_VK_QUOTE;
     }
     return keySym;
 }
-- 
cgit v1.2.3