chiark / gitweb /
Rewrite the JS keyboard handling to cope with IE and Chrome.
authorSimon Tatham <anakin@pobox.com>
Fri, 5 Apr 2013 15:49:27 +0000 (15:49 +0000)
committerSimon Tatham <anakin@pobox.com>
Fri, 5 Apr 2013 15:49:27 +0000 (15:49 +0000)
Unlike Firefox, IE and Chrome don't generate keypress events at all if
you suppress the default handling of keydowns. Therefore, we have to
figure out everything from the keydown event, because if we unsuppress
the default handling of any keydowns then we'll get annoyances like ^R
going back to meaning reload-page rather than redo-move.

[originally from svn r9810]

emcc.c
emccpre.js

diff --git a/emcc.c b/emcc.c
index e3bcbf579bd7830e733e6997270c7db2ff1482bd..d85a0e85843372bbfbec7ca3d6a67d33a2e3e010 100644 (file)
--- a/emcc.c
+++ b/emcc.c
@@ -148,6 +148,17 @@ void debug_printf(char *fmt, ...)
     js_debug(buf);
 }
 
+/*
+ * Helper function that makes it easy to test strings that might be
+ * NULL.
+ */
+int strnullcmp(const char *a, const char *b)
+{
+    if (a == NULL || b == NULL)
+        return a != NULL ? +1 : b != NULL ? -1 : 0;
+    return strcmp(a, b);
+}
+
 /*
  * HTMLish names for the colours allocated by the puzzle.
  */
@@ -245,67 +256,64 @@ void mousemove(int x, int y, int buttons)
 /*
  * Keyboard handler called from JS.
  */
-void key(int keycode, int charcode, int shift, int ctrl)
+void key(int keycode, int charcode, const char *key, const char *chr,
+         int shift, int ctrl)
 {
     int keyevent = -1;
-    if (charcode != 0) {
-        keyevent = charcode & (ctrl ? 0x1F : 0xFF);
-    } else {
-        switch (keycode) {
-          case 8:
-            keyevent = '\177';         /* backspace */
-            break;
-          case 13:
-            keyevent = 13;             /* return */
-            break;
-          case 37:
-            keyevent = CURSOR_LEFT;
-            break;
-          case 38:
-            keyevent = CURSOR_UP;
-            break;
-          case 39:
-            keyevent = CURSOR_RIGHT;
-            break;
-          case 40:
-            keyevent = CURSOR_DOWN;
-            break;
-            /*
-             * We interpret Home, End, PgUp and PgDn as numeric keypad
-             * controls regardless of whether they're the ones on the
-             * numeric keypad (since we can't tell). The effect of
-             * this should only be that the non-numeric-pad versions
-             * of those keys generate directions in 8-way movement
-             * puzzles like Cube and Inertia.
-             */
-          case 35:                     /* End */
-            keyevent = MOD_NUM_KEYPAD | '1';
-            break;
-          case 34:                     /* PgDn */
-            keyevent = MOD_NUM_KEYPAD | '3';
-            break;
-          case 36:                     /* Home */
-            keyevent = MOD_NUM_KEYPAD | '7';
-            break;
-          case 33:                     /* PgUp */
-            keyevent = MOD_NUM_KEYPAD | '9';
-            break;
-          case 96: case 97: case 98: case 99: case 100:
-          case 101: case 102: case 103: case 104: case 105:
-            keyevent = MOD_NUM_KEYPAD | ('0' + keycode - 96);
-            break;
-          default:
-            /* not a key we care about */
-            return;
-        }
+
+    if (!strnullcmp(key, "Backspace") || !strnullcmp(key, "Del") ||
+        keycode == 8 || keycode == 46) {
+        keyevent = 127;                /* Backspace / Delete */
+    } else if (!strnullcmp(key, "Enter") || keycode == 13) {
+        keyevent = 13;             /* return */
+    } else if (!strnullcmp(key, "Left") || keycode == 37) {
+        keyevent = CURSOR_LEFT;
+    } else if (!strnullcmp(key, "Up") || keycode == 38) {
+        keyevent = CURSOR_UP;
+    } else if (!strnullcmp(key, "Right") || keycode == 39) {
+        keyevent = CURSOR_RIGHT;
+    } else if (!strnullcmp(key, "Down") || keycode == 40) {
+        keyevent = CURSOR_DOWN;
+    } else if (!strnullcmp(key, "End") || keycode == 35) {
+        /*
+         * We interpret Home, End, PgUp and PgDn as numeric keypad
+         * controls regardless of whether they're the ones on the
+         * numeric keypad (since we can't tell). The effect of
+         * this should only be that the non-numeric-pad versions
+         * of those keys generate directions in 8-way movement
+         * puzzles like Cube and Inertia.
+         */
+        keyevent = MOD_NUM_KEYPAD | '1';
+    } else if (!strnullcmp(key, "PageDown") || keycode==34) {
+        keyevent = MOD_NUM_KEYPAD | '3';
+    } else if (!strnullcmp(key, "Home") || keycode==36) {
+        keyevent = MOD_NUM_KEYPAD | '7';
+    } else if (!strnullcmp(key, "PageUp") || keycode==33) {
+        keyevent = MOD_NUM_KEYPAD | '9';
+    } else if (chr && chr[0] && !chr[1]) {
+        keyevent = chr[0] & 0xFF;
+    } else if (keycode >= 96 && keycode < 106) {
+        keyevent = MOD_NUM_KEYPAD | ('0' + keycode - 96);
+    } else if (keycode >= 65 && keycode <= 90) {
+        keyevent = keycode + (shift ? 0 : 32);
+    } else if (keycode >= 48 && keycode <= 57) {
+        keyevent = keycode;
     }
-    if (shift && keyevent >= 0x100)
-        keyevent |= MOD_SHFT;
-    if (ctrl && keyevent >= 0x100)
-        keyevent |= MOD_CTRL;
 
-    midend_process_key(me, 0, 0, keyevent);
-    update_undo_redo();
+    if (keyevent >= 0) {
+        if (shift && keyevent >= 0x100)
+            keyevent |= MOD_SHFT;
+
+        if (ctrl) {
+            if (keyevent >= 0x100)
+                keyevent |= MOD_CTRL;
+            else
+                keyevent &= 0x1F;
+        }
+
+        midend_process_key(me, 0, 0, keyevent);
+        update_undo_redo();
+    }
 }
 
 /*
index 66e63547ce7f4c9353d28ea7c1a0f7cd5366ab36..701c7f79a5e673e8a433f068c0e48c9747f000b2 100644 (file)
@@ -157,26 +157,21 @@ function initPuzzle() {
         }
     };
 
-    // Set up keyboard handlers. We expect ordinary keys (with a
-    // charCode) to be handled by onkeypress, but function keys
-    // (arrows etc) to be handled by onkeydown.
-    //
-    // We also call event.preventDefault() in both handlers. This
-    // means that while the canvas itself has focus, _all_ keypresses
-    // go only to the puzzle - so users of this puzzle collection in
-    // other media can indulge their instinct to press ^R for redo,
-    // for example, without accidentally reloading the page.
-    key = Module.cwrap('key', 'void',
-                       ['number', 'number', 'number', 'number']);
+    // Set up keyboard handlers. We do all the actual keyboard
+    // handling in onkeydown; but we also call event.preventDefault()
+    // in both the keydown and keypress handlers. This means that
+    // while the canvas itself has focus, _all_ keypresses go only to
+    // the puzzle - so users of this puzzle collection in other media
+    // can indulge their instinct to press ^R for redo, for example,
+    // without accidentally reloading the page.
+    key = Module.cwrap('key', 'void', ['number', 'number', 'string',
+                                       'string', 'number', 'number']);
     onscreen_canvas.onkeydown = function(event) {
-        key(event.keyCode, event.charCode,
+        key(event.keyCode, event.charCode, event.key, event.char,
             event.shiftKey ? 1 : 0, event.ctrlKey ? 1 : 0);
         event.preventDefault();
     };
     onscreen_canvas.onkeypress = function(event) {
-        if (event.charCode != 0)
-            key(event.keyCode, event.charCode,
-                event.shiftKey ? 1 : 0, event.ctrlKey ? 1 : 0);
         event.preventDefault();
     };