<!DOCTYPE HTML>
<html>
<head>
  <title>Test for DOM KeyboardEvent</title>
  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
  
</div>
<pre id="test">
<script type="application/javascript">

var gCodeEnabled = SpecialPowers.getBoolPref("dom.keyboardevent.code.enabled");

SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(runTests, window);

function testInitializingUntrustedEvent()
{
  const kTests = [
    { createEventArg: "KeyboardEvent",
      type: "keydown", bubbles: true, cancelable: true, view: null,
      ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
      keyCode: 0x00, charCode: 0x00 },

    { createEventArg: "keyboardevent",
      type: "keyup", bubbles: false, cancelable: true, view: window,
      ctrlKey: true, altKey: false, shiftKey: false, metaKey: false,
      keyCode: 0x10, charCode: 0x00 },

    { createEventArg: "Keyboardevent",
      type: "keypess", bubbles: true, cancelable: false, view: null,
      ctrlKey: false, altKey: true, shiftKey: false, metaKey: false,
      keyCode: 0x11, charCode: 0x30 },

    { createEventArg: "keyboardEvent",
      type: "boo", bubbles: false, cancelable: false, view: window,
      ctrlKey: false, altKey: false, shiftKey: true, metaKey: false,
      keyCode: 0x30, charCode: 0x40 },

    { createEventArg: "KeyBoardEvent",
      type: "foo", bubbles: true, cancelable: true, view: null,
      ctrlKey: false, altKey: false, shiftKey: false, metaKey: true,
      keyCode: 0x00, charCode: 0x50 },

    { createEventArg: "keyboardevEnt",
      type: "bar", bubbles: false, cancelable: true, view: window,
      ctrlKey: true, altKey: true, shiftKey: false, metaKey: false,
      keyCode: 0x00, charCode: 0x60 },

    { createEventArg: "KeyboaRdevent",
      type: "keydown", bubbles: true, cancelable: false, view: null,
      ctrlKey: false, altKey: true, shiftKey: false, metaKey: true,
      keyCode: 0x30, charCode: 0x00 },

    { createEventArg: "KEYBOARDEVENT",
      type: "keyup", bubbles: false, cancelable: false, view: window,
      ctrlKey: true, altKey: false, shiftKey: true, metaKey: false,
      keyCode: 0x10, charCode: 0x80 },

    { createEventArg: "KeyboardEvent",
      type: "keypress", bubbles: false, cancelable: false, view: window,
      ctrlKey: true, altKey: false, shiftKey: true, metaKey: true,
      keyCode: 0x10, charCode: 0x80 },

    { createEventArg: "KeyboardEvent",
      type: "foo", bubbles: false, cancelable: false, view: window,
      ctrlKey: true, altKey: true, shiftKey: true, metaKey: true,
      keyCode: 0x10, charCode: 0x80 },
  ];

  const kOtherModifierName = [
    "CapsLock", "NumLock", "ScrollLock", "Symbol", "SymbolLock", "Fn", "FnLock", "OS", "AltGraph"
  ];

  const kInvalidModifierName = [
    "shift", "control", "alt", "meta", "capslock", "numlock", "scrolllock",
    "symbollock", "fn", "os", "altgraph", "Invalid", "Shift Control",
    "Win", "Scroll"
  ];

  for (var i = 0; i < kTests.length; i++) {
    var description = "testInitializingUntrustedEvent, Index: " + i + ", ";
    const kTest = kTests[i];
    var e = document.createEvent(kTest.createEventArg);
    e.initKeyEvent(kTest.type, kTest.bubbles, kTest.cancelable, kTest.view,
                   kTest.ctrlKey, kTest.altKey, kTest.shiftKey, kTest.metaKey,
                   kTest.keyCode, kTest.charCode);
    is(e.toString(), "[object KeyboardEvent]",
       description + 'class string should be "KeyboardEvent"');

    for (var attr in kTest) {
      if (attr == "createEventArg") {
        continue;
      }
      if (attr == "keyCode") {
        // If this is keydown, keyup of keypress event, keycod must be correct.
        if (kTest.type == "keydown" || kTest.type == "keyup" || kTest.type == "keypress") {
          is(e[attr], kTest[attr], description + attr + " returns wrong value");
        // Otherwise, should be always zero (why?)
        } else {
          is(e[attr], 0, description + attr + " returns non-zero for invalid event");
        }
      } else if (attr == "charCode") {
        // If this is keydown or keyup event, charCode always 0.
        if (kTest.type == "keydown" || kTest.type == "keyup") {
          is(e[attr], 0, description + attr + " returns non-zero for keydown or keyup event");
        // If this is keypress event, charCode must be correct.
        } else if (kTest.type == "keypress") {
          is(e[attr], kTest[attr], description + attr + " returns wrong value");
        // Otherwise, we have a bug.
        } else {
          if (e[attr] != kTest[attr]) { // avoid random unexpected pass.
            todo_is(e[attr], kTest[attr], description + attr + " returns wrong value");
          }
        }
      } else {
        is(e[attr], kTest[attr], description + attr + " returns wrong value");
      }
    }
    is(e.isTrusted, false, description + "isTrusted returns wrong value");

    // key and code values cannot be initialized with initKeyEvent().
    is(e.key, "", description + "key must return empty string");
    if (gCodeEnabled) {
      is(e.code, "", description + "code must be empty string");
    }

    // getModifierState() tests
    is(e.getModifierState("Shift"), kTest.shiftKey,
       description + "getModifierState(\"Shift\") returns wrong value");
    is(e.getModifierState("Control"), kTest.ctrlKey,
       description + "getModifierState(\"Control\") returns wrong value");
    is(e.getModifierState("Alt"), kTest.altKey,
       description + "getModifierState(\"Alt\") returns wrong value");
    is(e.getModifierState("Meta"), kTest.metaKey,
       description + "getModifierState(\"Meta\") returns wrong value");

    for (var j = 0; j < kOtherModifierName.length; j++) {
      ok(!e.getModifierState(kOtherModifierName[j]),
         description + "getModifierState(\"" + kOtherModifierName[j] + "\") returns wrong value");
    }
    for (var k = 0; k < kInvalidModifierName.length; k++) {
      ok(!e.getModifierState(kInvalidModifierName[k]),
         description + "getModifierState(\"" + kInvalidModifierName[k] + "\") returns wrong value");
    }
  }
}

function testSynthesizedKeyLocation()
{
  const kTests = [
    { key: "a", isModifier: false,
      event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false,
               location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
    },
    { key: "VK_SHIFT", isModifier: true,
      event: { shiftKey: true, ctrlKey: false, altKey: false, metaKey: false,
               location: KeyboardEvent.DOM_KEY_LOCATION_LEFT },
    },
    { key: "VK_SHIFT", isModifier: true,
      event: { shiftKey: true, ctrlKey: false, altKey: false, metaKey: false,
               location: KeyboardEvent.DOM_KEY_LOCATION_RIGHT },
    },
    { key: "VK_CONTROL", isModifier: true,
      event: { shiftKey: false, ctrlKey: true, altKey: false, metaKey: false,
               location: KeyboardEvent.DOM_KEY_LOCATION_LEFT },
    },
    { key: "VK_CONTROL", isModifier: true,
      event: { shiftKey: false, ctrlKey: true, altKey: false, metaKey: false,
               location: KeyboardEvent.DOM_KEY_LOCATION_RIGHT },
    },
/* XXX Alt key activates menubar even if we consume the key events.
    { key: "VK_ALT", isModifier: true,
      event: { shiftKey: false, ctrlKey: false, altKey: true, metaKey: false,
               location: KeyboardEvent.DOM_KEY_LOCATION_LEFT },
    },
    { key: "VK_ALT", isModifier: true,
      event: { shiftKey: false, ctrlKey: false, altKey: true, metaKey: false,
               location: KeyboardEvent.DOM_KEY_LOCATION_RIGHT },
    },
*/
    { key: "VK_META", isModifier: true,
      event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: true,
               location: KeyboardEvent.DOM_KEY_LOCATION_LEFT },
    },
    { key: "VK_META", isModifier: true,
      event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: true,
               location: KeyboardEvent.DOM_KEY_LOCATION_RIGHT },
    },
    { key: "VK_DOWN", isModifier: false,
      event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false,
               location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
    },
    { key: "VK_DOWN", isModifier: false,
      event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false,
               location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
    },
    { key: "5", isModifier: false,
      event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false,
               location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
    },
    { key: "VK_NUMPAD5", isModifier: false,
      event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false,
               location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
    },
    { key: "+", isModifier: false,
      event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false,
               location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
    },
    { key: "VK_ADD", isModifier: false,
      event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false,
               location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
    },
    { key: "VK_RETURN", isModifier: false,
      event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false,
               location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
    },
    { key: "VK_RETURN", isModifier: false,
      event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false,
               location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
    },
    { key: "VK_NUM_LOCK", isModifier: true,
      event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false,
               location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
    },
    { key: "VK_INSERT", isModifier: false,
      event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false,
               location: KeyboardEvent.DOM_KEY_LOCATION_STANDARD },
    },
    { key: "VK_INSERT", isModifier: false,
      event: { shiftKey: false, ctrlKey: false, altKey: false, metaKey: false,
               location: KeyboardEvent.DOM_KEY_LOCATION_NUMPAD },
    },
  ];

  function getLocationName(aLocation)
  {
    switch (aLocation) {
      case KeyboardEvent.DOM_KEY_LOCATION_STANDARD:
        return "DOM_KEY_LOCATION_STANDARD";
      case KeyboardEvent.DOM_KEY_LOCATION_LEFT:
        return "DOM_KEY_LOCATION_LEFT";
      case KeyboardEvent.DOM_KEY_LOCATION_RIGHT:
        return "DOM_KEY_LOCATION_RIGHT";
      case KeyboardEvent.DOM_KEY_LOCATION_NUMPAD:
        return "DOM_KEY_LOCATION_NUMPAD";
      default:
        return "Invalid value (" + aLocation + ")";
    }
  }

  var currentTest, description;
  var events = { keydown: false, keypress: false, keyup: false };

  function handler(aEvent)
  {
    is(aEvent.location, currentTest.event.location,
       description + "location of " + aEvent.type + " was invalid");
    events[aEvent.type] = true;
    if (aEvent.type != "keydown" ||
        (currentTest.event.isModifier && aEvent.type == "keydown")) {
      aEvent.preventDefault();
    }
  }

  window.addEventListener("keydown", handler, true);
  window.addEventListener("keypress", handler, true);
  window.addEventListener("keyup", handler, true);

  for (var i = 0; i < kTests.length; i++) {
    currentTest = kTests[i];
    events = { keydown: false, keypress: false, keyup: false };
    description = "testSynthesizedKeyLocation, " + i + ", key: " +
      currentTest.key + ", location: " +
      getLocationName(currentTest.event.location) + ": ";
    synthesizeKey(currentTest.key, currentTest.event);
    ok(events.keydown, description + "keydown event wasn't fired");
    if (currentTest.isModifier) {
      todo(events.keypress, description + "keypress event was fired for modifier key");
    } else {
      ok(events.keypress, description + "keypress event wasn't fired");
    }
    ok(events.keyup, description + "keyup event wasn't fired");
  }

  window.removeEventListener("keydown", handler, true);
  window.removeEventListener("keypress", handler, true);
  window.removeEventListener("keyup", handler, true);
}

function runTests()
{
  testInitializingUntrustedEvent();
  testSynthesizedKeyLocation();
  SimpleTest.finish();
}

</script>
</pre>
</body>
</html>