Bug 433030. Desired character codes for DOM events with Cmd+Shift. p=masayuki+karl r=josh sr=roc a=discore.
authorkarlt+@karlt.net
Fri, 09 May 2008 16:10:40 -0700
changeset 15096 fc78e1cc1361190aeba2fb5ec485d6ed04286081
parent 15095 cffecdc2e605e6aee957f89ec16b7d2272d84cad
child 15097 40bfaf37b5dbed0dc3968ae0955ef3ef24d7a478
push idunknown
push userunknown
push dateunknown
reviewersjosh, roc, discore
bugs433030
milestone1.9pre
Bug 433030. Desired character codes for DOM events with Cmd+Shift. p=masayuki+karl r=josh sr=roc a=discore.
widget/src/cocoa/nsChildView.mm
widget/tests/test_keycodes.xul
--- a/widget/src/cocoa/nsChildView.mm
+++ b/widget/src/cocoa/nsChildView.mm
@@ -4249,16 +4249,19 @@ GetUSLayoutCharFromKeyTranslate(UInt32 a
       PRUint32 shiftedChar = GetUniCharFromKeyTranslate(kt, key, shiftLockMod);
 
       // characters generated with Cmd key
       // XXX we should remove CapsLock state, which changes characters from
       //     Latin to Cyrillic with Russian layout on 10.4 only when Cmd key
       //     is pressed.
       UInt32 numState = (lockState & ~alphaLock); // only num lock state
       PRUint32 uncmdedChar = GetUniCharFromKeyTranslate(kt, key, numState);
+      UInt32 shiftNumMod = numState | shiftKey;
+      PRUint32 uncmdedShiftChar =
+                 GetUniCharFromKeyTranslate(kt, key, shiftNumMod);
       PRUint32 uncmdedUSChar = GetUSLayoutCharFromKeyTranslate(key, numState);
       UInt32 cmdNumMod = cmdKey | numState;
       PRUint32 cmdedChar = GetUniCharFromKeyTranslate(kt, key, cmdNumMod);
       UInt32 cmdShiftNumMod = shiftKey | cmdNumMod;
       PRUint32 cmdedShiftChar =
         GetUniCharFromKeyTranslate(kt, key, cmdShiftNumMod);
 
       // Is the keyboard layout changed by Cmd key?
@@ -4272,31 +4275,41 @@ GetUSLayoutCharFromKeyTranslate(UInt32 a
       // we should append unshiftedChar and shiftedChar for handling the
       // normal characters.
       if ((unshiftedChar || shiftedChar) &&
           (!outGeckoEvent->isMeta || !isDvorakQWERTY)) {
         nsAlternativeCharCode altCharCodes(unshiftedChar, shiftedChar);
         outGeckoEvent->alternativeCharCodes.AppendElement(altCharCodes);
       }
 
+
+      // On a German layout, the OS gives us '/' with Cmd+Shift+SS(eszett)
+      // even though Cmd+SS is 'SS' and Shift+'SS' is '?'.  This '/' seems
+      // like a hack to make the Cmd+"?" event look the same as the Cmd+"?"
+      // event on a US keyboard.  The user thinks they are typing Cmd+"?", so
+      // we'll prefer the "?" character, replacing charCode with shiftedChar
+      // when Shift is pressed.  However, in case there is a layout where the
+      // character unique to Cmd+Shift is the character that the user expects,
+      // we'll send it as an alternative char.
+      PRBool hasCmdShiftOnlyChar =
+        cmdedChar != cmdedShiftChar && uncmdedShiftChar != cmdedShiftChar;
+      PRUint32 originalCmdedShiftChar = cmdedShiftChar;
+
       // Cleaning up cmdedShiftChar with CapsLocked characters.
       if (!isCmdSwitchLayout) {
         if (unshiftedChar)
           cmdedChar = unshiftedChar;
-        // Don't replace if cmdedChar and cmdedShiftChar are not same.
-        // E.g., Cmd+Shift+SS(eszett) is '/'. But Shift+SS is '?'. Then,
-        // we should send '/' directly and '?' should be sent as alternative.
-        if (shiftedChar && cmdedChar == cmdedShiftChar)
+        if (shiftedChar)
           cmdedShiftChar = shiftedChar;
       } else if (uncmdedUSChar == cmdedChar) {
         PRUint32 ch = GetUSLayoutCharFromKeyTranslate(key, lockState);
         if (ch)
           cmdedChar = ch;
         ch = GetUSLayoutCharFromKeyTranslate(key, shiftLockMod);
-        if (ch && cmdedChar == cmdedShiftChar)
+        if (ch)
           cmdedShiftChar = ch;
       }
 
       // XXX We should do something similar when Control is down (bug 429510).
       if (outGeckoEvent->isMeta &&
            !(outGeckoEvent->isControl || outGeckoEvent->isAlt)) {
 
         // The character to use for charCode.
@@ -4320,16 +4333,22 @@ GetUSLayoutCharFromKeyTranslate(UInt32 a
       // If the current keyboard layout is switched by the Cmd key,
       // we should append cmdedChar and shiftedCmdChar that are
       // Latin char for the key. But don't append at Dvorak-QWERTY.
       if ((cmdedChar || cmdedShiftChar) &&
           isCmdSwitchLayout && !isDvorakQWERTY) {
         nsAlternativeCharCode altCharCodes(cmdedChar, cmdedShiftChar);
         outGeckoEvent->alternativeCharCodes.AppendElement(altCharCodes);
       }
+      // Special case for 'SS' key of German layout. See the comment of
+      // hasCmdShiftOnlyChar definition for the detail.
+      if (hasCmdShiftOnlyChar && originalCmdedShiftChar) {
+        nsAlternativeCharCode altCharCodes(0, originalCmdedShiftChar);
+        outGeckoEvent->alternativeCharCodes.AppendElement(altCharCodes);
+      }
     }
   }
   else {
     NSString* characters = nil;
     if ([aKeyEvent type] != NSFlagsChanged)
       characters = [aKeyEvent charactersIgnoringModifiers];
     
     outGeckoEvent->keyCode = ConvertMacToGeckoKeyCode([aKeyEvent keyCode], outGeckoEvent, characters);
--- a/widget/tests/test_keycodes.xul
+++ b/widget/tests/test_keycodes.xul
@@ -225,16 +225,26 @@ function runPressTests()
     testKey({layout:"Greek", keyCode:0, command:1, alt:1, shift:1, chars:"\u00b9", unmodifiedChars:"\u0391"},
             "\u00b9");
 
     // German (KCHR/KeyTranslate case)
     testKey({layout:"German", keyCode:0, chars:"a", unmodifiedChars:"a"},
             "a");
     testKey({layout:"German", keyCode:33, chars:"\u00fc", unmodifiedChars:"\u00fc"},
             "\u00fc");
+    testKey({layout:"German", keyCode:27, chars:"\u00df", unmodifiedChars:"\u00df"},
+            "\u00df");
+    testKey({layout:"German", keyCode:27, shift:1, chars:"?", unmodifiedChars:"?"},
+            "?");
+    testKey({layout:"German", keyCode:27, command:1, chars:"\u00df", unmodifiedChars:"\u00df"},
+            "\u00df");
+    // Shift+SS is '?' but Cmd+Shift+SS is '/' on German layout.
+    // XXX this test failed on 10.4
+    //testKey({layout:"German", keyCode:27, command:1, shift:1, chars:"/", unmodifiedChars:"?"},
+    //        "?");
   }
   
   if (navigator.platform.indexOf("Win") == 0) {
     // On Windows, you can use Spy++ or Winspector (free) to watch window messages.
     // The keyCode is given by the wParam of the last WM_KEYDOWN message. The
     // chars string is given by the wParam of the WM_CHAR message. unmodifiedChars
     // is not needed on Windows.