add tests, patch by roc, b=432773 r=josh
authorjoshmoz@gmail.com
Thu, 08 May 2008 15:41:13 -0700
changeset 15069 1884ad99e7a4128e11b5bc34904fb12811ba66fc
parent 15068 5fb940a40a63aa08b8d402e81d3d8a5cdebff1c4
child 15070 0dbd025ca9c03561ca8d773ca2f5c2b030c5e6d6
push idunknown
push userunknown
push dateunknown
reviewersjosh
bugs432773
milestone1.9pre
add tests, patch by roc, b=432773 r=josh
widget/src/cocoa/nsChildView.mm
widget/tests/test_keycodes.xul
--- a/widget/src/cocoa/nsChildView.mm
+++ b/widget/src/cocoa/nsChildView.mm
@@ -370,18 +370,37 @@ nsChildView::nsChildView() : nsBaseWidge
 , mDrawing(PR_FALSE)
 , mLiveResizeInProgress(PR_FALSE)
 , mIsPluginView(PR_FALSE)
 , mPluginDrawing(PR_FALSE)
 , mPluginIsCG(PR_FALSE)
 , mInSetFocus(PR_FALSE)
 {
 #ifdef PR_LOGGING
-  if (!sCocoaLog)
+  if (!sCocoaLog) {
     sCocoaLog = PR_NewLogModule("nsCocoaWidgets");
+    CFIndex idx;
+    KLGetKeyboardLayoutCount(&idx);
+    PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("Keyboard layout configuration:"));
+    for (CFIndex i = 0; i < idx; ++i) {
+      KeyboardLayoutRef curKL;
+      if (KLGetKeyboardLayoutAtIndex(i, &curKL) == noErr) {
+        CFStringRef name;
+        if (KLGetKeyboardLayoutProperty(curKL, kKLName, (const void**)&name) == noErr) {
+          int idn;
+          KLGetKeyboardLayoutProperty(curKL, kKLIdentifier, (const void**)&idn);
+          int kind;
+          KLGetKeyboardLayoutProperty(curKL, kKLKind, (const void**)&kind);
+          char buf[256];
+          CFStringGetCString(name, buf, 256, kCFStringEncodingASCII);
+          PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("  %d,%s,%d\n", idn, buf, kind));
+        }
+      }
+    }
+  }
 #endif
 
   SetBackgroundColor(NS_RGB(255, 255, 255));
   SetForegroundColor(NS_RGB(0, 0, 0));
 
   if (nsToolkit::OnLeopardOrLater() && !Leopard_TISCopyCurrentKeyboardLayoutInputSource) {
     void* hitoolboxHandle = dlopen("/System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/Versions/A/HIToolbox", RTLD_LAZY);
     if (hitoolboxHandle) {
@@ -1292,18 +1311,16 @@ static const PRUint32 sModifierFlagMap[]
 nsresult nsChildView::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout,
                                                PRInt32 aNativeKeyCode,
                                                PRUint32 aModifierFlags,
                                                const nsAString& aCharacters,
                                                const nsAString& aUnmodifiedCharacters)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
   
-  NS_ASSERTION(aNativeKeyboardLayout, "Layout cannot be 0");
-
   PRUint32 modifierFlags = 0;
   for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(sModifierFlagMap); ++i) {
     if (aModifierFlags & sModifierFlagMap[i][0]) {
       modifierFlags |= sModifierFlagMap[i][1];
     }
   }
   int windowNumber = [[mView window] windowNumber];
   NSEvent* downEvent = [NSEvent keyEventWithType:NSKeyDown
--- a/widget/tests/test_keycodes.xul
+++ b/widget/tests/test_keycodes.xul
@@ -8,16 +8,23 @@
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <title>Key event tests</title>
   <script type="application/javascript" 
    src="chrome://mochikit/content/MochiKit/packed.js"></script>
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
 
+<keyset>
+  <key id="unshiftedKey" key=";" modifiers="accel" oncommand="this.activeCount++"/>
+  <key id="shiftedKey" key=":" modifiers="accel" oncommand="this.activeCount++"/>
+  <key id="commandOptionF" key='f' modifiers="accel,alt" oncommand="this.activeCount++"/>
+  <key id="question" key='?' modifiers="accel" oncommand="this.activeCount++"/>
+</keyset>
+
 <body  xmlns="http://www.w3.org/1999/xhtml">
 <p id="display">
   <!-- for some reason, if we don't have 'accesskey' here, adding it dynamically later
        doesn't work! -->
   <button id="button" accesskey="z">Hello</button>
 </p>
 <div id="content" style="display: none">
   
@@ -34,18 +41,16 @@ SimpleTest.waitForExplicitFinish();
 function synthesizeNativeKey(aLayout, aKeyCode, aModifiers, aSystemChars,
                              aSystemUnmodifiedChars, aWindow)
 {
   netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
 
   if (!aWindow)
     aWindow = window;
 
-  document.getElementById("button").focus();
-
   var utils = aWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
                       getInterface(Components.interfaces.nsIDOMWindowUtils);
 
   if (utils) {
     var modifiers = 0;
     if (aModifiers.capsLock) modifiers |= 0x01;
     if (aModifiers.numLock) modifiers |= 0x02;
     if (aModifiers.shift) modifiers |= 0x0100;
@@ -66,29 +71,58 @@ function synthesizeNativeKey(aLayout, aK
 
 var keyboardLayouts;
 if (navigator.platform.indexOf("Mac") == 0) {
   // These constants can be found by inspecting files under
   // /System/Library/Keyboard\ Layouts/Unicode.bundle/Contents/Resources/
   // XXX if you need a new keyboard layout and that uses KCHR resource,
   // you need to modify GetScriptFromKeyboardLayout of nsChildView.mm
   keyboardLayouts = {
-    "US-Extended":-2,
+    "US":0,
     "Greek":-18944,
-    "German":3
+    "German":3,
+    "Swedish":224
   };
 } else if (navigator.platform.indexOf("Win") == 0) {
   // These constants can be found by inspecting registry keys under
   // HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Keyboard Layouts
   keyboardLayouts = {
     "US":0x409,
-    "Greek":0x408
+    "Greek":0x408,
+    "Swedish":0x41d
   };
 }
 
+function eventToString(aEvent)
+{
+  var name = aEvent.layout + " '" + aEvent.chars + "'";
+  if (aEvent.shift) {
+    name += " [Shift]";
+  }
+  if (aEvent.ctrl) {
+    name += " [Ctrl]";
+  }
+  if (aEvent.alt) {
+    name += " [Alt]";
+  }
+  if (aEvent.command) {
+    name += " [Command]";
+  }
+
+  return name;  
+}
+
+function synthesizeKey(aEvent)
+{
+  document.getElementById("button").focus();
+
+  synthesizeNativeKey(keyboardLayouts[aEvent.layout],
+                      aEvent.keyCode, aEvent, aEvent.chars, aEvent.unmodifiedChars);
+}
+
 // Test the charcodes and modifiers being delivered to keypress handlers.
 function runPressTests()
 {
   var pressList;
   function onKeyPress(e)
   {
     pressList.push(e);
     e.preventDefault();
@@ -96,29 +130,19 @@ function runPressTests()
 
   // The first parameter is the complete input event. The second parameter is
   // what to test against.
   // XXX should probably check that keydown and keyup events were dispatched too
   function testKey(aEvent, aExpectGeckoChar)
   {
     pressList = [];
     
-    synthesizeNativeKey(keyboardLayouts[aEvent.layout],
-                        aEvent.keyCode, aEvent, aEvent.chars, aEvent.unmodifiedChars);
+    synthesizeKey(aEvent);
 
-    var name = aEvent.layout + " '" + aEvent.chars + "'";
-    if (aEvent.shift) {
-      name += " [Shift]";
-    }
-    if (aEvent.ctrl) {
-      name += " [Ctrl]";
-    }
-    if (aEvent.alt) {
-      name += " [Alt]";
-    }
+    var name = eventToString(aEvent);
 
     is(pressList.length, aExpectGeckoChar == "" ? 0 : 1, name + ", wrong number of press events");
     if (pressList.length == 0)
       return;
     var e = pressList[0];
     is(e.ctrlKey, aEvent.ctrl || 0, name + ", Ctrl mismatch");
     is(e.metaKey, aEvent.command || 0, name + ", Command mismatch");
     is(e.altKey, aEvent.alt || 0, name + ", Alt mismatch");
@@ -126,63 +150,63 @@ function runPressTests()
   
     if (aExpectGeckoChar.length > 0) {
       is(e.charCode, aExpectGeckoChar.charCodeAt(0), name + ", charcode");
     } else {
       is(e.charCode, 0, name + ", no charcode");
     }
   }
 
+  // These tests have to be per-plaform.
   document.addEventListener("keypress", onKeyPress, false);
 
-  // These tests have to be per-plaform.
   if (navigator.platform.indexOf("Mac") == 0) {
     // On Mac, you can produce event records for any desired keyboard input
     // by running with NSPR_LOG_MODULES=nsCocoaWidgets:5 and typing into the browser.
     // We will dump the key event fields to the console. Use the International system
     // preferences widget to enable other keyboard layouts and select them from the
     // input menu to see what keyboard events they generate.
     // Note that it's possible to send bogus key events here, e.g.
     // {keyCode:0, chars:"z", unmodifiedChars:"P"} --- sendNativeKeyEvent
     // makes no attempt to verify that the keyCode matches the characters. So only
     // test key event records that you saw Cocoa send.
 
     // Plain text input
-    testKey({layout:"US-Extended", keyCode:0, chars:"a", unmodifiedChars:"a"},
+    testKey({layout:"US", keyCode:0, chars:"a", unmodifiedChars:"a"},
             "a");
-    testKey({layout:"US-Extended", keyCode:11, chars:"b", unmodifiedChars:"b"},
+    testKey({layout:"US", keyCode:11, chars:"b", unmodifiedChars:"b"},
             "b");
-    testKey({layout:"US-Extended", keyCode:0, shift:1, chars:"A", unmodifiedChars:"A"},
+    testKey({layout:"US", keyCode:0, shift:1, chars:"A", unmodifiedChars:"A"},
             "A");
 
     // Ctrl keys
-    testKey({layout:"US-Extended", keyCode:0, ctrl:1, chars:"\u0001", unmodifiedChars:"a"},
+    testKey({layout:"US", keyCode:0, ctrl:1, chars:"\u0001", unmodifiedChars:"a"},
             "a");
-    testKey({layout:"US-Extended", keyCode:0, ctrl:1, shift:1, chars:"\u0001", unmodifiedChars:"A"},
+    testKey({layout:"US", keyCode:0, ctrl:1, shift:1, chars:"\u0001", unmodifiedChars:"A"},
             "A");
 
     // Alt keys
-    testKey({layout:"US-Extended", keyCode:0, alt:1, chars:"\u00e5", unmodifiedChars:"a"},
+    testKey({layout:"US", keyCode:0, alt:1, chars:"\u00e5", unmodifiedChars:"a"},
             "\u00e5");
-    testKey({layout:"US-Extended", keyCode:0, alt:1, shift:1, chars:"\u00c5", unmodifiedChars:"A"},
+    testKey({layout:"US", keyCode:0, alt:1, shift:1, chars:"\u00c5", unmodifiedChars:"A"},
             "\u00c5");
     
     // Command keys
-    testKey({layout:"US-Extended", keyCode:0, command:1, chars:"a", unmodifiedChars:"a"},
+    testKey({layout:"US", keyCode:0, command:1, chars:"a", unmodifiedChars:"a"},
             "a");
     // Shift-cmd gives us the unshifted character
-    testKey({layout:"US-Extended", keyCode:0, command:1, shift:1, chars:"a", unmodifiedChars:"A"},
+    testKey({layout:"US", keyCode:0, command:1, shift:1, chars:"a", unmodifiedChars:"A"},
             "a");
     // Ctrl-cmd gives us the unshifted character
-    testKey({layout:"US-Extended", keyCode:0, command:1, ctrl:1, chars:"\u0001", unmodifiedChars:"a"},
+    testKey({layout:"US", keyCode:0, command:1, ctrl:1, chars:"\u0001", unmodifiedChars:"a"},
             "a");
     // Alt-cmd gives us the *shifted* character
-    testKey({layout:"US-Extended", keyCode:0, command:1, alt:1, chars:"\u00e5", unmodifiedChars:"a"},
+    testKey({layout:"US", keyCode:0, command:1, alt:1, chars:"\u00e5", unmodifiedChars:"a"},
             "\u00e5");
-    testKey({layout:"US-Extended", keyCode:0, command:1, alt:1, shift:1, chars:"\u00c5", unmodifiedChars:"a"},
+    testKey({layout:"US", keyCode:0, command:1, alt:1, shift:1, chars:"\u00c5", unmodifiedChars:"a"},
             "\u00c5");
 
     // Greek ctrl keys produce Latin charcodes
     testKey({layout:"Greek", keyCode:0, ctrl:1, chars:"\u0001", unmodifiedChars:"\u03b1"},
             "a");
     testKey({layout:"Greek", keyCode:0, ctrl:1, shift:1, chars:"\u0001", unmodifiedChars:"\u0391"},
             "A");
 
@@ -267,58 +291,61 @@ function runAccessKeyTests()
 
   // The first parameter is the complete input event. The second and third parameters are
   // what to test against.
   function testKey(aEvent, aAccessKey, aShouldActivate)
   {
     activationCount = 0;
     button.setAttribute("accesskey", aAccessKey);
 
-    synthesizeNativeKey(keyboardLayouts[aEvent.layout],
-                        aEvent.keyCode, aEvent, aEvent.chars, aEvent.unmodifiedChars);
+    synthesizeKey(aEvent);
 
-    var name = aEvent.layout + " '" + aEvent.chars + "'";
+    var name = eventToString(aEvent);
 
     is(activationCount, aShouldActivate ? 1 : 0, name + ", activating '" + aAccessKey + "'");
   }
 
   button.addEventListener("click", onClick, false);
   
   // These tests have to be per-plaform.
   if (navigator.platform.indexOf("Mac") == 0) {
     // Basic sanity checks
-    testKey({layout:"US-Extended", keyCode:0, chars:"a", unmodifiedChars:"a"},
+    testKey({layout:"US", keyCode:0, chars:"a", unmodifiedChars:"a"},
             "a", false);
-    testKey({layout:"US-Extended", keyCode:0, ctrl:1, chars:"\u0001", unmodifiedChars:"a"},
+    testKey({layout:"US", keyCode:0, ctrl:1, chars:"\u0001", unmodifiedChars:"a"},
             "a", true);
-    testKey({layout:"US-Extended", keyCode:0, ctrl:1, chars:"\u0001", unmodifiedChars:"a"},
+    testKey({layout:"US", keyCode:0, ctrl:1, chars:"\u0001", unmodifiedChars:"a"},
             "A", true);
 
     // Shift-ctrl does not activate accesskeys
-    testKey({layout:"US-Extended", keyCode:0, ctrl:1, shift:1, chars:"\u0001", unmodifiedChars:"A"},
+    testKey({layout:"US", keyCode:0, ctrl:1, shift:1, chars:"\u0001", unmodifiedChars:"A"},
             "a", false);
-    testKey({layout:"US-Extended", keyCode:0, ctrl:1, shift:1, chars:"\u0001", unmodifiedChars:"A"},
+    testKey({layout:"US", keyCode:0, ctrl:1, shift:1, chars:"\u0001", unmodifiedChars:"A"},
             "A", false);
     // Alt-ctrl does not activate accesskeys
-    testKey({layout:"US-Extended", keyCode:0, ctrl:1, alt:1, chars:"\u0001", unmodifiedChars:"a"},
+    testKey({layout:"US", keyCode:0, ctrl:1, alt:1, chars:"\u0001", unmodifiedChars:"a"},
             "a", false);
-    testKey({layout:"US-Extended", keyCode:0, ctrl:1, alt:1, chars:"\u0001", unmodifiedChars:"a"},
+    testKey({layout:"US", keyCode:0, ctrl:1, alt:1, chars:"\u0001", unmodifiedChars:"a"},
             "A", false);
             
     // Greek layout can activate a Latin accesskey
     testKey({layout:"Greek", keyCode:0, ctrl:1, chars:"\u0001", unmodifiedChars:"\u03b1"},
             "a", true);
     testKey({layout:"Greek", keyCode:0, ctrl:1, chars:"\u0001", unmodifiedChars:"\u03b1"},
             "A", true);
     // ... and a Greek accesskey!
     testKey({layout:"Greek", keyCode:0, ctrl:1, chars:"\u0001", unmodifiedChars:"\u03b1"},
             "\u03b1", true);
     testKey({layout:"Greek", keyCode:0, ctrl:1, chars:"\u0001", unmodifiedChars:"\u03b1"},
             "\u0391", true);
 
+    // bug 359638
+    testKey({layout:"US", keyCode:47, ctrl:1, chars:".", unmodifiedChars:"."},
+            ".", true);
+
     // German (KCHR/KeyTranslate case)
     testKey({layout:"German", keyCode:0, ctrl:1, chars:"a", unmodifiedChars:"a"},
             "a", true);
     testKey({layout:"German", keyCode:0, ctrl:1, chars:"a", unmodifiedChars:"a"},
             "A", true);
     testKey({layout:"German", keyCode:33, ctrl:1, chars:"\u00fc", unmodifiedChars:"\u00fc"},
             "\u00fc", true);
     testKey({layout:"German", keyCode:33, ctrl:1, chars:"\u00fc", unmodifiedChars:"\u00fc"},
@@ -345,24 +372,91 @@ function runAccessKeyTests()
             "a", true);
     testKey({layout:"Greek", keyCode:65, shift:1, alt:1, chars:"A"},
             "A", true);
     // ... and a Greek accesskey!
     testKey({layout:"Greek", keyCode:65, shift:1, alt:1, chars:"A"},
             "\u03b1", true);
     testKey({layout:"Greek", keyCode:65, shift:1, alt:1, chars:"A"},
             "\u0391", true);
+
+    // bug 359638
+    testKey({layout:"US", keyCode:190, shift:1, alt:1, chars:".", unmodifiedChars:"."},
+            ".", true);
   }
   
   button.removeEventListener("click", onClick, false);
 }
 
+function runXULKeyTests()
+{
+  function testKey(aEvent, aElem, aShouldActivate)
+  {
+    var elem = document.getElementById(aElem);
+    elem.activeCount = 0;
+
+    synthesizeKey(aEvent);
+
+    var name = eventToString(aEvent);
+
+    is(elem.activeCount, aShouldActivate ? 1 : 0,
+       name + " activating " + aElem);
+  }
+
+  if (navigator.platform.indexOf("Mac") == 0) {
+    testKey({layout:"US", keyCode:41, command:1, chars:";", unmodifiedChars:";"},
+            "unshiftedKey", true);
+    testKey({layout:"US", keyCode:41, command:1, chars:";", unmodifiedChars:";"},
+            "shiftedKey", false);
+    testKey({layout:"US", keyCode:41, command:1, shift:1, chars:";", unmodifiedChars:":"},
+            "shiftedKey", true);
+    testKey({layout:"US", keyCode:41, command:1, shift:1, chars:";", unmodifiedChars:":"},
+            "unshiftedKey", false);
+  }
+  if (navigator.platform.indexOf("Win") == 0) {
+    testKey({layout:"US", keyCode:186, ctrl:1, chars:";"},
+            "unshiftedKey", true);
+    testKey({layout:"US", keyCode:186, ctrl:1, chars:";"},
+            "shiftedKey", false);
+    testKey({layout:"US", keyCode:186, ctrl:1, shift:1, chars:";"},
+            "shiftedKey", true);
+    testKey({layout:"US", keyCode:186, ctrl:1, shift:1, chars:";"},
+            "unshiftedKey", false);
+  }
+
+  keyElems = ["commandOptionF"];
+
+  // 429160
+  if (navigator.platform.indexOf("Mac") == 0) {
+    testKey({layout:"US", keyCode:3, command:1, alt:1, chars:"\u0192", unmodifiedChars:"f"},
+            "commandOptionF", true);
+  }
+  if (navigator.platform.indexOf("Win") == 0) {
+    testKey({layout:"US", keyCode:70, ctrl:1, alt:1, chars:"\u0006"},
+            "commandOptionF", true);
+  }
+  
+  // 432112
+  if (navigator.platform.indexOf("Mac") == 0) {
+// test currently does not work, getting the Swedish layout fails
+//  testKey({layout:"Swedish", keyCode:27, command:1, shift:1, chars:"+", unmodifiedChars:"?"},
+//          "question", true);
+  }
+  if (navigator.platform.indexOf("Win") == 0) {
+    testKey({layout:"Swedish", keyCode:187, ctrl:1, shift:1, chars:""},
+            "question", true);
+    testKey({layout:"Swedish", keyCode:187, ctrl:1, chars:""},
+            "question", false);
+  }
+}
+
 function runTest()
 {
   runPressTests();
   runAccessKeyTests();
+  runXULKeyTests();
   SimpleTest.finish();
 }
 
 ]]>
 </script>
 
 </window>