+2007-12-07 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Darin.
+
+ <rdar://problem/5535636>
+ Have to press 4 times instead of 2 times to get the expected result of ^^ with german keyboard.
+
+ http://bugs.webkit.org/show_bug.cgi?id=13916
+ JavaScript detects Tab as a character input on a textfield validation
+
+ * platform/win/fast/events: Added.
+ * platform/win/fast/events/double-dead-char-expected.txt: Added.
+ * platform/win/fast/events/double-dead-char.html: Added.
+ * fast/events/key-events-in-input-button.html: Added
+ * fast/events/key-events-in-input-button-expected.txt: Added
+ * fast/events/key-events-in-input-text.html: Added
+ * fast/events/key-events-in-input-text-expected.txt: Added
+
+ * fast/events/access-key-self-destruct.html:
+ * fast/forms/listbox-onchange.html:
+ * fast/forms/listbox-selection.html:
+ * fast/forms/access-key.html:
+ * fast/forms/legend-access-key.html:
+ * fast/forms/enter-clicks-buttons.html:
+ * fast/forms/check-box-enter-key.html:
+ * fast/forms/button-enter-click.html:
+ * fast/events/onsearch-enter.html:
+ * fast/events/onchange-passwordfield.html:
+ * fast/events/onchange-searchfield.html:
+ * fast/events/onchange-textfield.html:
+ Use eventSender instead of DOM events, because it emulates the real user action much better,
+ and we weren't getting cross-browser compatibility for the tests anyway.
+
+ * fast/events/frame-tab-focus.html:
+ * fast/html/tab-order.html:
+ * fast/forms/select-enter-key.html:
+ * fast/forms/focus2-expected.txt:
+ * fast/forms/focus2.html:
+ * fast/events/option-tab.html:
+ Dispatch a keydown instead of keypress, as this is when default processing is now done.
+ Possibly, it would be better stiull to use eventSender here, as well.
+
+ * fast/forms/onchange-enter-submit.html:
+ * fast/forms/select-double-onchange.html:
+ * fast/forms/textfield-onchange-deletion.html:
+ The correct code is '\r', not '\n' - previously, the difference was lost while converting
+ events back and forth.
+
+ * fast/forms/search-event-delay.html: Use a new named key to dispatch backspace - the
+ character code for it is cross-platform, but key code is not.
+ Also changed the test to call notifyDone() from a timer - otherwise, DRT would hang as
+ WM_KEYUP was dispatched after WM_QUIT. I tried and couldn't make DRT work, but I'm
+ fairly confident that this issue doesn't affect Safari.
+
+ * fast/events/keydown-keypress-preventDefault-expected.txt:
+ * fast/events/keydown-keypress-preventDefault.html:
+ This test claimed that its expacted behavior matched both IE and Firefox, but it did not.
+ We now match IE.
+
+ * fast/events/js-keyboard-event-creation-expected.txt:
+ * fast/events/js-keyboard-event-creation.html:
+ This test was problematic, because it was tabbing out to chrome, and that doesn't work
+ well in DRT. I have added another input for it to have a nicer target.
+
+ * platform/mac/fast/events/objc-event-api-expected.txt:
+ Updated for new behavior:
+ - eventSender.keyDown() now dispatches a keyUp, too;
+ - raw events do not have charCode;
+ - keypresses do not have keyIdentifiers.
+
2007-12-10 Oliver Hunt <oliver@apple.com>
Reviewed by Weinig, Dan and Alexey.
}
function test()
{
- if (window.layoutTestController)
+ if (window.layoutTestController) {
layoutTestController.dumpAsText();
-
- var event = document.createEvent("KeyboardEvent");
- if (navigator.userAgent.search(/\bMac OS X\b/) != -1)
- event.initKeyboardEvent("keydown", true, true, document.defaultView, "a", 0, true, false, false, false, false);
- else
- event.initKeyboardEvent("keydown", true, true, document.defaultView, "a", 0, false, true, false, false, false);
- document.dispatchEvent(event);
+ if (navigator.userAgent.search(/\bMac OS X\b/) != -1)
+ modifier = "ctrlKey";
+ else
+ modifier = "altKey";
+ eventSender.keyDown("a", [modifier]);
+ }
}
</script>
<body onload="test()">
{
var event = document.createEvent('KeyboardEvents');
var tabKeyIdentifier = 'U+0009';
- event.initKeyboardEvent('keypress', true, true, document.defaultView, tabKeyIdentifier, 0, false, altKey, shiftKey, false, false);
+ event.initKeyboardEvent('keydown', true, true, document.defaultView, tabKeyIdentifier, 0, false, altKey, shiftKey, false, false);
element.dispatchEvent(event);
}
-
+
This tests that DOMKeyboardEvents are created correctly in the JavaScript API.
-keydown - key: U+0009@0 (keyCode/charCode: 9/9) modifiers: false,false,false,false
-
-keypress - key: U+0009@0 (keyCode/charCode: 9/9) modifiers: false,false,false,false
-
-keydown - key: U+0009@0 (keyCode/charCode: 9/9) modifiers: false,false,true,false
+keydown - key: U+0009@0 (keyCode/charCode: 9/0) modifiers: false,false,false,false
-keypress - key: U+0009@0 (keyCode/charCode: 9/9) modifiers: false,false,true,false
+keyup - key: U+0009@0 (keyCode/charCode: 9/0) modifiers: false,false,true,false
input.addEventListener("keypress", keyevent, true);
input.addEventListener("keyup", keyevent, true);
- if (layoutTestController)
+ if (window.layoutTestController)
layoutTestController.dumpAsText();
input.focus();
<body onload="init()">
<form>
<input type="text" size="50" id="testinput" />
+ <input type="text" size="50" />
</form>
<p>This tests that DOMKeyboardEvents are created correctly in the JavaScript API.</p>
--- /dev/null
+To test manually, press keys and compare results to other browsers.
+
+
+target - type - ctrlKey,altKey,shiftKey,metaKey - keyIdentifier - keyCode - charCode
+Space:
+INPUT - keydown - false,false,false,false - U+0020 - 32 - 0
+INPUT - keypress - false,false,false,false - - 32 - 32
+INPUT - keyup - false,false,false,false - U+0020 - 32 - 0
+INPUT - click
+Enter:
+INPUT - keydown - false,false,false,false - Enter - 13 - 0
+INPUT - keypress - false,false,false,false - - 13 - 13
+INPUT - click
+INPUT - keyup - false,false,false,false - Enter - 13 - 0
+A:
+INPUT - keydown - false,false,true,false - U+0041 - 65 - 0
+INPUT - keypress - false,false,true,false - - 65 - 65
+INPUT - keyup - false,false,true,false - U+0041 - 65 - 0
+
--- /dev/null
+<p>To test manually, press keys and compare results to other browsers.</p>
+<input type="button" value="Input"
+ onclick="log(eventInfo(event));"
+ onmousedown="log(eventInfo(event));"
+ onmouseup="log(eventInfo(event));"
+ onkeypress="log(eventInfo(event));"
+ onkeydown="log(eventInfo(event));"
+ onkeyup="log(eventInfo(event));">
+</input>
+<div id="log"></div>
+
+<script>
+function log(msg) {
+ document.getElementById("log").innerHTML+= msg + "<br />";
+}
+function eventInfo(event, where) {
+ try {
+ if (!event)
+ event = window.event;
+ target = event.srcElement ? event.srcElement : event.target;
+ if (event.type == "textInput")
+ return (where ? "(" + where + ") " : "") + target.tagName + " - " + event.type + " - " + event.data;
+ else if (event.type == "keydown" || event.type == "keypress" || event.type == "keyup")
+ return (where ? "(" + where + ") " : "") + target.tagName + " - " + event.type
+ + ' - ' + [event.ctrlKey, event.altKey, event.shiftKey, event.metaKey]
+ + ' - ' + event.keyIdentifier
+ + ' - ' + event.keyCode
+ + ' - ' + event.charCode;
+ else if (event.type == "mousedown" || event.type == "click" || event.type == "mouseup")
+ return (where ? "(" + where + ") " : "") + target.tagName + " - " + event.type;
+
+ } catch (ex) {
+ alert(ex);
+ }
+}
+log("target - type - " + ["ctrlKey", "altKey", "shiftKey", "metaKey"]
+ + ' - ' + "keyIdentifier"
+ + ' - ' + "keyCode"
+ + ' - ' + "charCode");
+
+if (document.getElementsByTagName("input")[0].addEventListener)
+ document.getElementsByTagName("input")[0].addEventListener('textInput', function(e) {log(eventInfo(e));}, false);
+
+document.getElementsByTagName("input")[0].focus();
+
+if (window.layoutTestController) {
+ layoutTestController.dumpAsText();
+ log("Space:");
+ eventSender.keyDown(" ", []);
+ log("Enter:");
+ eventSender.keyDown("\r", []);
+ log("A:");
+ eventSender.keyDown("A", []);
+}
+</script>
--- /dev/null
+To test manually, press keys and compare results to other browsers.
+
+
+target - type - ctrlKey,altKey,shiftKey,metaKey - keyIdentifier - keyCode - charCode
+Space:
+INPUT - keydown - false,false,false,false - U+0020 - 32 - 0. Value: "".
+INPUT - keypress - false,false,false,false - - 32 - 32. Value: "".
+INPUT - textInput - . Value: "".
+INPUT - keyup - false,false,false,false - U+0020 - 32 - 0. Value: " ".
+Backspace:
+INPUT - keydown - false,false,false,false - U+0008 - 8 - 0. Value: " ".
+INPUT - keyup - false,false,false,false - U+0008 - 8 - 0. Value: "".
+Left Arrow:
+INPUT - keydown - false,false,false,false - Left - 37 - 0. Value: "".
+INPUT - keyup - false,false,false,false - Left - 37 - 0. Value: "".
+Tab:
+INPUT - keydown - false,false,false,false - U+0009 - 9 - 0. Value: "".
+
--- /dev/null
+<p>To test manually, press keys and compare results to other browsers.</p>
+<input type="text"
+ onclick="log(eventInfo(event));"
+ onmousedown="log(eventInfo(event));"
+ onmouseup="log(eventInfo(event));"
+ onkeypress="log(eventInfo(event));"
+ onkeydown="log(eventInfo(event));"
+ onkeyup="log(eventInfo(event));">
+</input>
+<input type=text></input>
+<div id="log"></div>
+
+<script>
+function log(msg) {
+ document.getElementById("log").innerHTML+= msg + "<br />";
+}
+function eventInfo(event, where) {
+ try {
+ if (!event)
+ event = window.event;
+ target = event.srcElement ? event.srcElement : event.target;
+ if (event.type == "textInput")
+ return (where ? "(" + where + ") " : "") + target.tagName + " - " + event.type + " - " + event.data
+ + '. Value: "' + target.value + '".';
+ else if (event.type == "keydown" || event.type == "keypress" || event.type == "keyup")
+ return (where ? "(" + where + ") " : "") + target.tagName + " - " + event.type
+ + ' - ' + [event.ctrlKey, event.altKey, event.shiftKey, event.metaKey]
+ + ' - ' + event.keyIdentifier
+ + ' - ' + event.keyCode
+ + ' - ' + event.charCode
+ + '. Value: "' + target.value + '".';
+ else if (event.type == "mousedown" || event.type == "click" || event.type == "mouseup")
+ return (where ? "(" + where + ") " : "") + target.tagName + " - " + event.type
+ '. Value: "' + target.value + '".';
+
+ } catch (ex) {
+ alert(ex);
+ }
+}
+log("target - type - " + ["ctrlKey", "altKey", "shiftKey", "metaKey"]
+ + ' - ' + "keyIdentifier"
+ + ' - ' + "keyCode"
+ + ' - ' + "charCode");
+
+if (document.getElementsByTagName("input")[0].addEventListener)
+ document.getElementsByTagName("input")[0].addEventListener('textInput', function(e) {log(eventInfo(e));}, false);
+
+document.getElementsByTagName("input")[0].focus();
+
+if (window.layoutTestController) {
+ layoutTestController.dumpAsText();
+ log("Space:");
+ eventSender.keyDown(" ", []);
+ log("Backspace:");
+ eventSender.keyDown("\x08", []);
+ log("Left Arrow:");
+ eventSender.keyDown("leftArrow", []);
+ log("Tab:");
+ eventSender.keyDown("\t", []);
+}
+</script>
-This tests that preventing the default behavior for a keydown event will not prevent the keypress event from firing, but will prevent text from being inserted.
-This matches IE7 and Firefox.
+This tests that preventing the default behavior for a keydown event will prevent the keypress event from firing, and will prevent text from being inserted.
+This matches IE7, but not Firefox, which still dispatches a keypress.
key down
-key press
key down
-key press
key down
-key press
key down
-key press
-<html>\r
-<script>\r
- function test() {\r
- var tf = document.getElementById('tf');\r
- tf.focus();\r
- if (window.layoutTestController) {\r
- layoutTestController.dumpAsText();\r
- eventSender.keyDown('F');\r
- eventSender.keyDown('A');\r
- eventSender.keyDown('I');\r
- eventSender.keyDown('L');\r
- log(tf.value);\r
- }\r
- }\r
- \r
- function log(msg) {\r
- var res = document.getElementById('res');\r
- res.innerHTML = res.innerHTML + msg + "<br>";\r
- }\r
-</script> \r
-<body onload="test()">\r
- This tests that preventing the default behavior for a keydown event will not prevent the keypress event from firing, but will prevent text from being inserted.<br>\r
- This matches IE7 and Firefox.<br>\r
- <input id="tf" onkeydown="log('key down'); event.preventDefault();" onkeypress="log('key press')">\r
- <br>\r
- <div id="res"></div>\r
-</body>\r
-</html>\r
+<html>
+<script>
+ function test() {
+ var tf = document.getElementById('tf');
+ tf.focus();
+ if (window.layoutTestController) {
+ layoutTestController.dumpAsText();
+ eventSender.keyDown('F');
+ eventSender.keyDown('A');
+ eventSender.keyDown('I');
+ eventSender.keyDown('L');
+ log(tf.value);
+ }
+ }
+
+ function log(msg) {
+ var res = document.getElementById('res');
+ res.innerHTML = res.innerHTML + msg + "<br>";
+ }
+</script>
+<body onload="test()">
+ This tests that preventing the default behavior for a keydown event will prevent the keypress event from firing, and will prevent text from being inserted.<br>
+ This matches IE7, but not Firefox, which still dispatches a keypress.<br>
+ <input id="tf" onkeydown="log('key down'); return false" onkeypress="log('key press')">
+ <br>
+ <div id="res"></div>
+</body>
+</html>
document.execCommand("InsertText", false, "foo bar baz");
// hit enter
-var enterEvent = document.createEvent("KeyboardEvents");
-enterEvent.initKeyboardEvent("keypress", true, false, window, "Enter", 0, false, false, false, false, false); // This is not at all like pulling teeth
-input.dispatchEvent(enterEvent);
+input.focus();
+if (window.eventSender)
+ eventSender.keyDown("\r", []);
</script>
document.execCommand("InsertText", false, "foo bar baz");
// hit enter
-var enterEvent = document.createEvent("KeyboardEvents");
-enterEvent.initKeyboardEvent("keypress", true, false, window, "Enter", 0, false, false, false, false, false); // This is not at all like pulling teeth
-input.dispatchEvent(enterEvent);
+input.focus();
+if (window.eventSender)
+ eventSender.keyDown("\r", []);
</script>
document.execCommand("InsertText", false, "foo bar baz");
// hit enter
-var enterEvent = document.createEvent("KeyboardEvents");
-enterEvent.initKeyboardEvent("keypress", true, false, window, "Enter", 0, false, false, false, false, false); // This is not at all like pulling teeth
-input.dispatchEvent(enterEvent);
+input.focus();
+if (window.eventSender)
+ eventSender.keyDown("\r", []);
</script>
{
var sf = document.getElementById('sf');
sf.focus();
- var enterEvent = document.createEvent("KeyboardEvents");
- enterEvent.initKeyboardEvent("keypress", true, false, window, "Enter", 0, false, false, false, false, false);
- sf.dispatchEvent(enterEvent);
- if (window.layoutTestController)
+ if (window.layoutTestController) {
layoutTestController.dumpAsText();
+ eventSender.keyDown("\r", []);
+ }
}
function log(msg)
{
window.linkFocused = false;
document.getElementById(fieldId).focus();
var event = document.createEvent("KeyboardEvents");
- event.initKeyboardEvent("keypress", true, true, document.defaultView, "U+0009", 0, false, true, false, false, false);
+ event.initKeyboardEvent("keydown", true, true, document.defaultView, "U+0009", 0, false, true, false, false, false);
document.getElementById(fieldId).dispatchEvent(event);
if (window.linkFocused)
document.getElementById("console").innerHTML += "SUCCESS: Option-tab did tab to the link (" + fieldId + ").\n";
window.linkFocused = false;
document.getElementById(fieldId).focus();
event = document.createEvent("KeyboardEvents");
- event.initKeyboardEvent("keypress", true, true, document.defaultView, "U+0009", 0, false, false, false, false, false);
+ event.initKeyboardEvent("keydown", true, true, document.defaultView, "U+0009", 0, false, false, false, false, false);
document.getElementById(fieldId).dispatchEvent(event);
if (window.linkFocused)
document.getElementById("console").innerHTML += "FAIL: Plain old tab did tab to the link (" + fieldId + ").\n";
}
function pressKey(key)
{
- var event = document.createEvent("KeyboardEvent");
if (navigator.userAgent.search(/\bMac OS X\b/) != -1)
- event.initKeyboardEvent("keydown", true, true, document.defaultView, key, 0, true, false, false, false, false);
+ modifier = "ctrlKey";
else
- event.initKeyboardEvent("keydown", true, true, document.defaultView, key, 0, false, true, false, false, false);
- document.dispatchEvent(event);
+ modifier = "altKey";
+ eventSender.keyDown(key, [modifier]);
}
function test()
{
- if (window.layoutTestController)
+ if (window.layoutTestController) {
layoutTestController.dumpAsText();
- for (i = 1; i <= 9; i++)
- pressKey(i);
- pressKey("a");
- pressKey("b");
- pressKey("c");
+ for (i = 1; i <= 9; i++)
+ pressKey(i.toString());
+ pressKey("a");
+ pressKey("b");
+ pressKey("c");
+ }
}
</script>
</head>
function test() {
var bt = document.getElementById('bt');
bt.focus();
- if (window.layoutTestController)
+ if (window.layoutTestController) {
layoutTestController.dumpAsText();
- var keyEvent = document.createEvent("KeyboardEvents");
- keyEvent.initKeyboardEvent("keypress", true, true, window, "Enter", 0, false, false, false, false, false);
- bt.dispatchEvent(keyEvent);
+ eventSender.keyDown("\r", []);
+ }
}
function log(msg) {
var console = document.getElementById('console');
}
function test()
{
- if (window.layoutTestController)
- layoutTestController.dumpAsText();
-
document.getElementById("form").onsubmit = submitHandler;
- var event = document.createEvent("KeyboardEvents");
- event.initKeyboardEvent("keypress", true, true, document.defaultView, "Enter", 0, false, false, false, false, false);
- document.getElementById("check").dispatchEvent(event);
+ document.getElementById("check").focus();
+ if (window.layoutTestController) {
+ layoutTestController.dumpAsText();
+ eventSender.keyDown("\r", []);
+ }
}
</script>
</head>
if (window.layoutTestController)
layoutTestController.dumpAsText();
- var keys = ['Enter', 'U+0020'];
+ var keys = ['\r', ' '];
+ var keyNames = ['Enter', 'U+0020'];
var tagNames = ['button', 'input'];
for (var i in keys) {
- log('\n\nSending ' + keys[i] + ' keypresses...\n');
+ log('\n\nSending ' + keyNames[i] + ' keypresses...\n');
for (var j in tagNames) {
var elements = document.getElementsByTagName(tagNames[j]);
log('\nLooping over ' + elements.length + ' ' + tagNames[j] + ' elements...\n');
for (var k = 0; k < elements.length; ++k) {
- var event = elements[k].ownerDocument.createEvent("KeyboardEvent");
- event.initKeyboardEvent("keypress", true, true, elements[k].ownerDocument.defaultView, keys[i], 0, false, false, false, false, false);
- elements[k].dispatchEvent(event);
+ elements[k].focus();
+ eventSender.keyDown(keys[i], []);
}
}
}
PARENT DOCUMENT:
focus event: [to] BUTTON
-keypress event: [to] BUTTON
+keydown event: [to] BUTTON
blur event: [to] BUTTON
focus event: [to] CHECKBOX
-keypress event: [to] CHECKBOX
+keydown event: [to] CHECKBOX
blur event: [to] CHECKBOX
focus event: [to] FILE
-keypress event: [to] FILE
+keydown event: [to] FILE
blur event: [to] FILE
focus event: [to] IMAGE
-keypress event: [to] IMAGE
+keydown event: [to] IMAGE
blur event: [to] IMAGE
focus event: [to] ISINDEX
-keypress event: [to] ISINDEX
+keydown event: [to] ISINDEX
blur event: [to] ISINDEX
focus event: [to] PASSWORD
-keypress event: [to] PASSWORD
+keydown event: [to] PASSWORD
blur event: [to] PASSWORD
focus event: [to] RANGE
-keypress event: [to] RANGE
+keydown event: [to] RANGE
blur event: [to] RANGE
focus event: [to] RESET
-keypress event: [to] RESET
+keydown event: [to] RESET
blur event: [to] RESET
focus event: [to] SEARCH
-keypress event: [to] SEARCH
+keydown event: [to] SEARCH
blur event: [to] SEARCH
focus event: [to] SUBMIT
-keypress event: [to] SUBMIT
+keydown event: [to] SUBMIT
blur event: [to] SUBMIT
focus event: [to] TEXT
-keypress event: [to] TEXT
+keydown event: [to] TEXT
blur event: [to] TEXT
focus event: [to] TEXTAREA
-keypress event: [to] TEXTAREA
+keydown event: [to] TEXTAREA
blur event: [to] TEXTAREA
focus event: [to] DIV
-keypress event: [to] DIV
+keydown event: [to] DIV
blur event: [to] DIV
focus event: [to] ANCHOR
blur event: [to] ANCHOR
IFRAME DOCUMENT:
focus event: [to] BUTTON
-keypress event: [to] BUTTON
+keydown event: [to] BUTTON
blur event: [to] BUTTON
focus event: [to] CHECKBOX
-keypress event: [to] CHECKBOX
+keydown event: [to] CHECKBOX
blur event: [to] CHECKBOX
focus event: [to] FILE
-keypress event: [to] FILE
+keydown event: [to] FILE
blur event: [to] FILE
focus event: [to] IMAGE
-keypress event: [to] IMAGE
+keydown event: [to] IMAGE
blur event: [to] IMAGE
focus event: [to] ISINDEX
-keypress event: [to] ISINDEX
+keydown event: [to] ISINDEX
blur event: [to] ISINDEX
focus event: [to] PASSWORD
-keypress event: [to] PASSWORD
+keydown event: [to] PASSWORD
blur event: [to] PASSWORD
focus event: [to] RANGE
-keypress event: [to] RANGE
+keydown event: [to] RANGE
blur event: [to] RANGE
focus event: [to] RESET
-keypress event: [to] RESET
+keydown event: [to] RESET
blur event: [to] RESET
focus event: [to] SEARCH
-keypress event: [to] SEARCH
+keydown event: [to] SEARCH
blur event: [to] SEARCH
focus event: [to] SUBMIT
-keypress event: [to] SUBMIT
+keydown event: [to] SUBMIT
blur event: [to] SUBMIT
focus event: [to] TEXT
-keypress event: [to] TEXT
+keydown event: [to] TEXT
blur event: [to] TEXT
focus event: [to] TEXTAREA
-keypress event: [to] TEXTAREA
+keydown event: [to] TEXTAREA
blur event: [to] TEXTAREA
focus event: [to] DIV
-keypress event: [to] DIV
+keydown event: [to] DIV
blur event: [to] DIV
focus event: [to] ANCHOR
return element.toString();
}
-function keypressListener(event)
+function keydownListener(event)
{
- log("keypress event: [to] " + description(event.target) + "\n");
+ log("keydown event: [to] " + description(event.target) + "\n");
}
function blurListener(event)
function addEventListeners(element)
{
- element.addEventListener('keypress', keypressListener, false);
+ element.addEventListener('keydown', keydownListener, false);
element.addEventListener('focus', focusListener, false);
element.addEventListener('blur', blurListener, false);
}
{
var event = document.createEvent("KeyboardEvents");
var tabKeyIdentifier = "U+0009";
- event.initKeyboardEvent("keypress", true, true, document.defaultView, tabKeyIdentifier, 0, false, true, shiftKey, false, false);
+ event.initKeyboardEvent("keydown", true, true, document.defaultView, tabKeyIdentifier, 0, false, true, shiftKey, false, false);
element.dispatchEvent(event);
}
}
function test()
{
- if (window.layoutTestController)
+ if (window.layoutTestController) {
layoutTestController.dumpAsText();
- var event = document.createEvent("KeyboardEvent");
- if (navigator.userAgent.search(/\bMac OS X\b/) != -1)
- event.initKeyboardEvent("keydown", true, true, document.defaultView, "f", 0, true, false, false, false, false);
- else
- event.initKeyboardEvent("keydown", true, true, document.defaultView, "f", 0, false, true, false, false, false);
- document.dispatchEvent(event);
+ if (navigator.userAgent.search(/\bMac OS X\b/) != -1)
+ modifier = "ctrlKey";
+ else
+ modifier = "altKey";
+ eventSender.keyDown("f", [modifier]);
+ }
}
</script>
</head>
checkSelection("0");
log("6) Make sure onChange fires when changing the selection with the keyboard");
- keyPressOnSelect("sl1", "Down", true, false);
+ keyDownOnSelect("sl1", "downArrow", true, false);
checkSelection("0,1");
log("7) Make sure onChange doesn't fire when setting the select element's value from JS");
sl.dispatchEvent(event);
}
- function keyPressOnSelect(selId, identifier, shift, metaOrCtrl)
+ function keyDownOnSelect(selId, identifier, shift, metaOrCtrl)
{
- var meta = false;
- var ctrl = false;
+ modifiers = [];
+ if (shift)
+ modifiers[0] = "shiftKey";
if (metaOrCtrl) {
if (navigator.userAgent.search(/\bMac OS X\b/) != -1)
- meta = true;
+ modifiers[modifiers.length] = "metaKey";
else
- ctrl = true;
+ modifiers[modifiers.length] = "controlKey";
}
- var sl = document.getElementById(selId);
- var event = document.createEvent("KeyboardEvents");
- event.initKeyboardEvent("keypress", true, true, document.defaultView, identifier, 0, ctrl, false, shift, meta, false);
- sl.dispatchEvent(event);
+
+ document.getElementById(selId).focus();
+ eventSender.keyDown(identifier, modifiers);
}
function getSelectedOptions(selId)
testResults(expectedSelectionResults, 2);
// 3) Select one item with the keyboard (no previous selection)
- keyPressOnSelect("sl3", "Up", false, false);
+ keyDownOnSelect("sl3", "upArrow", false, false);
expectedSelectionResults = new Array(false, false, false, false, true);
testResults(expectedSelectionResults, 3);
// 4) Select one item with the keyboard (with previous selection)
- keyPressOnSelect("sl4", "Down", false, false);
+ keyDownOnSelect("sl4", "downArrow", false, false);
expectedSelectionResults = new Array(false, false, true, false, false);
testResults(expectedSelectionResults, 4);
testResults(expectedSelectionResults, 6);
// 7) Attempt to select a range with the keyboard
- keyPressOnSelect("sl7", "Down", true, false);
+ keyDownOnSelect("sl7", "downArrow", true, false);
expectedSelectionResults = new Array(false, false, true, false, false);
testResults(expectedSelectionResults, 7);
testResults(expectedSelectionResults, 9);
// 10) Select one item with the keyboard (no previous selection)
- keyPressOnSelect("sl10", "Up", false, false);
+ keyDownOnSelect("sl10", "upArrow", false, false);
expectedSelectionResults = new Array(false, false, false, false, true);
testResults(expectedSelectionResults, 10);
// 11) Select one item with the keyboard (with previous selection)
- keyPressOnSelect("sl11", "Down", false, false);
+ keyDownOnSelect("sl11", "downArrow", false, false);
expectedSelectionResults = new Array(false, false, true, false, false);
testResults(expectedSelectionResults, 11);
testResults(expectedSelectionResults, 13);
// 14) Select a range with the keyboard
- keyPressOnSelect("sl14", "Down", true, false);
+ keyDownOnSelect("sl14", "downArrow", true, false);
expectedSelectionResults = new Array(false, true, true, false, false);
testResults(expectedSelectionResults, 14);
sl.dispatchEvent(event);
}
- function keyPressOnSelect(selId, identifier, shift, metaOrCtrl)
+ function keyDownOnSelect(selId, identifier, shift, metaOrCtrl)
{
- var meta = false;
- var ctrl = false;
+ modifiers = [];
+ if (shift)
+ modifiers[0] = "shiftKey";
if (metaOrCtrl) {
if (navigator.userAgent.search(/\bMac OS X\b/) != -1)
- meta = true;
+ modifiers[modifiers.length] = "metaKey";
else
- ctrl = true;
+ modifiers[modifiers.length] = "controlKey";
}
- var sl = document.getElementById(selId);
- sl.focus();
- var event = document.createEvent("KeyboardEvents");
- event.initKeyboardEvent("keypress", true, true, document.defaultView, identifier, 0, ctrl, false, shift, meta, false);
- sl.dispatchEvent(event);
+
+ document.getElementById(selId).focus();
+ eventSender.keyDown(identifier, modifiers);
}
function createSelect(idName, sz, mlt, selIndex, testMsg)
tf.focus();
if (window.layoutTestController) {
eventSender.keyDown('a');
- eventSender.keyDown('\n');
+ eventSender.keyDown('\r');
}
}
function sendDeleteKeyEvent()
{
if (window.eventSender)
- eventSender.keyDown("\x7F");
+ eventSender.keyDown("delete");
}
function keyEvent(event)
}
} else {
if (window.layoutTestController)
- layoutTestController.notifyDone();
+ setTimeout("layoutTestController.notifyDone()", 0); // Do it on a timer to avoid Windows DRT hanging.
}
}
<p>As of this writing we can't use DOM events to type into a search field, so the test uses the event sender and only runs under DumpRenderTree.</p>
-<p><input id="search" type="search" incremental onkeypress="keyEvent(event)" onsearch="searchEvent(event)"></p>
+<p><input id="search" type="search" incremental onkeydown="keyEvent(event)" onsearch="searchEvent(event)"></p>
<div>The two rows below should match.</div>
<div>0.5 0.4 0.3 0.2 0.2 0</p>
popup.focus();
eventSender.keyDown("t", null);
- eventSender.keyDown("\n", null);
+ eventSender.keyDown("\r", null);
}
function changed(select)
}
function test()
{
- if (window.layoutTestController)
- layoutTestController.dumpAsText();
-
document.getElementById("form").onsubmit = submitHandler;
- var event = document.createEvent("KeyboardEvents");
- event.initKeyboardEvent("keypress", true, true, document.defaultView, "Enter", 0, false, false, false, false, false);
- document.getElementById("select").dispatchEvent(event);
+ document.getElementById("select").focus();
+ if (window.layoutTestController) {
+ layoutTestController.dumpAsText();
+ eventSender.keyDown("\r", []);
+ }
}
</script>
</head>
function test2() {\r
document.getElementById('tf').focus();\r
eventSender.keyDown('a');\r
- eventSender.keyDown("\n", null);\r
+ eventSender.keyDown("\r", null);\r
if (window.layoutTestController)\r
layoutTestController.notifyDone();\r
}\r
{
var event = document.createEvent('KeyboardEvents');
var tabKeyIdentifier = 'U+0009';
- event.initKeyboardEvent('keypress', true, true, document.defaultView, tabKeyIdentifier, 0, false, false, shiftKey, false, false);
+ event.initKeyboardEvent('keydown', true, true, document.defaultView, tabKeyIdentifier, 0, false, false, shiftKey, false, false);
element.dispatchEvent(event);
}
keyLocation: 0
modifier keys: c:0 s:0 a:0 m:0
keyCode: 65
- charCode: 97
+ charCode: 0
event type: keypress
target: <body>
eventPhase: 3
cancelable: 1
detail: 0
view: OK (document: OK)
- keyIdentifier: U+0041
+ keyIdentifier:
keyLocation: 0
modifier keys: c:0 s:0 a:0 m:0
keyCode: 97
charCode: 97
+event type: keyup
+ target: <body>
+ eventPhase: 3
+ bubbles: 1
+ cancelable: 1
+ detail: 0
+ view: OK (document: OK)
+ keyIdentifier: U+0041
+ keyLocation: 0
+ modifier keys: c:0 s:0 a:0 m:0
+ keyCode: 65
+ charCode: 0
event type: keydown
target: <body>
eventPhase: 3
keyLocation: 0
modifier keys: c:1 s:0 a:0 m:0
keyCode: 66
- charCode: 98
+ charCode: 0
event type: keypress
target: <body>
eventPhase: 3
cancelable: 1
detail: 0
view: OK (document: OK)
- keyIdentifier: U+0042
+ keyIdentifier:
keyLocation: 0
modifier keys: c:1 s:0 a:0 m:0
keyCode: 98
charCode: 98
+event type: keyup
+ target: <body>
+ eventPhase: 3
+ bubbles: 1
+ cancelable: 1
+ detail: 0
+ view: OK (document: OK)
+ keyIdentifier: U+0042
+ keyLocation: 0
+ modifier keys: c:1 s:0 a:0 m:0
+ keyCode: 66
+ charCode: 0
event type: keydown
target: <body>
eventPhase: 3
keyLocation: 0
modifier keys: c:0 s:1 a:0 m:0
keyCode: 68
- charCode: 100
+ charCode: 0
event type: keypress
target: <body>
eventPhase: 3
cancelable: 1
detail: 0
view: OK (document: OK)
- keyIdentifier: U+0044
+ keyIdentifier:
keyLocation: 0
modifier keys: c:0 s:1 a:0 m:0
keyCode: 100
charCode: 100
+event type: keyup
+ target: <body>
+ eventPhase: 3
+ bubbles: 1
+ cancelable: 1
+ detail: 0
+ view: OK (document: OK)
+ keyIdentifier: U+0044
+ keyLocation: 0
+ modifier keys: c:0 s:1 a:0 m:0
+ keyCode: 68
+ charCode: 0
event type: keydown
target: <body>
eventPhase: 3
keyLocation: 0
modifier keys: c:0 s:0 a:1 m:1
keyCode: 69
- charCode: 101
+ charCode: 0
event type: keypress
target: <body>
eventPhase: 3
cancelable: 1
detail: 0
view: OK (document: OK)
- keyIdentifier: U+0045
+ keyIdentifier:
keyLocation: 0
modifier keys: c:0 s:0 a:1 m:1
keyCode: 101
charCode: 101
+event type: keyup
+ target: <body>
+ eventPhase: 3
+ bubbles: 1
+ cancelable: 1
+ detail: 0
+ view: OK (document: OK)
+ keyIdentifier: U+0045
+ keyLocation: 0
+ modifier keys: c:0 s:0 a:1 m:1
+ keyCode: 69
+ charCode: 0
event type: mousemove
target: <div>
eventPhase: 3
--- /dev/null
+Test for rdar://problem/5535636: Have to press 4 times instead of 2 times to get the expected result of ^^ with German keyboard.
+
+^^
--- /dev/null
+<body>
+ <p>Test for <a href="rdar://problem/5535636">rdar://problem/5535636</a>:
+ Have to press 4 times instead of 2 times to get the expected result of ^^
+ with German keyboard.
+</p>
+<div contenteditable id=ce></div>
+<script>
+ if (window.layoutTestController) {
+ layoutTestController.dumpAsText();
+ document.getElementById("ce").focus();
+
+ eventSender.dispatchMessage(eventSender.WM_KEYDOWN, 220 /* VK_OEM_5 */, 0x00290001);
+ eventSender.dispatchMessage(eventSender.WM_DEADCHAR, 94 /* '^' */, 0x00290001);
+ eventSender.dispatchMessage(eventSender.WM_KEYUP, 220, 0xc0290001);
+ eventSender.dispatchMessage(eventSender.WM_KEYDOWN, 220, 0x00290001);
+ eventSender.dispatchMessage(eventSender.WM_CHAR, 94, 0x00290001);
+ eventSender.dispatchMessage(eventSender.WM_CHAR, 94, 0x00290001);
+ eventSender.dispatchMessage(eventSender.WM_KEYUP, 220, 0xc0290001);
+ } else
+ document.write("To test manually, switch to German keyboard layout, and press circumflex key two times " +
+ "(on my MBP with Russian physical keyboard, it is located to the left of 1).");
+</script>
+</body>
+2007-12-07 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Darin.
+
+ <rdar://problem/5535636>
+ Have to press 4 times instead of 2 times to get the expected result of ^^ with german keyboard.
+
+ http://bugs.webkit.org/show_bug.cgi?id=13916
+ JavaScript detects Tab as a character input on a textfield validation
+
+ Test: platform/win/fast/events/double-dead-char.html
+
+ * platform/PlatformKeyboardEvent.h:
+ (WebCore::PlatformKeyboardEvent::):
+ (WebCore::PlatformKeyboardEvent::type):
+ (WebCore::PlatformKeyboardEvent::windowsVirtualKeyCode):
+ (WebCore::PlatformKeyboardEvent::setWindowsVirtualKeyCode):
+ (WebCore::PlatformKeyboardEvent::keyIdentifier):
+ (WebCore::PlatformKeyboardEvent::setIsAutoRepeat):
+ Added an explicit type member to differentiate different kinds of events:
+ RawKeyDown == keydown == WM_KEYDOWN
+ KeyUp == keyup == WM_KEYUP
+ Char == keypress == WM_CHAR
+ KeyDown == e.g. NSKeyDown or NSFlagsChanged, used on platforms that have a different model for
+ event processing, and needs to be converted to RawKeyDown (+ Char) for processing in DOM.
+
+ * platform/mac/KeyEventMac.mm:
+ (WebCore::PlatformKeyboardEvent::PlatformKeyboardEvent): Updated for changed data members.
+ Fix Enter (numeric keypad) charCode to match Return, as we check for it from keypress default handlers.
+ (WebCore::windowsKeyCodeForKeyEvent):
+ (WebCore::isKeyUpEvent): Made it do something closer to what it claims; added a FIXME explaining
+ that it still fails.
+ (WebCore::disambiguateKeyDownEvent): Downgrade from KeyDown to RawKeyDown or Char, removing information that
+ should not be available in those (because it cannot be provided on Windows).
+
+ * platform/win/KeyEventWin.cpp:
+ (WebCore::PlatformKeyboardEvent::PlatformKeyboardEvent): Updated for changed data members.
+ Used standard Windows constants for bit masks instead of our own ones.
+ (WebCore::PlatformKeyboardEvent::disambiguateKeyDownEvent): Should never be called on Windows.
+
+ * platform/gtk/KeyEventGtk.cpp:
+ (WebCore::PlatformKeyboardEvent::PlatformKeyboardEvent):
+ (WebCore::PlatformKeyboardEvent::disambiguateKeyDownEvent):
+ * platform/qt/PlatformKeyboardEventQt.cpp:
+ (WebCore::PlatformKeyboardEvent::PlatformKeyboardEvent):
+ (WebCore::PlatformKeyboardEvent::disambiguateKeyDownEvent):
+ * platform/wx/KeyboardEventWx.cpp:
+ (WebCore::PlatformKeyboardEvent::PlatformKeyboardEvent):
+ (WebCore::PlatformKeyboardEvent::disambiguateKeyDownEvent):
+ Updated for cross-platform changes as much as it was possible without appropriate build
+ environments.
+
+ * WebCore.base.exp: Export PlatformKeyboardEvent::disambiguateKeyDownEvent(), used by platforms that need to
+ convert their fancy key events to RawKeyDown/Char pairs. Export Editor::isTextInsertionCommand().
+
+ * bridge/EditorClient.h:
+ Renamed handleKeypress() to handleKeyboardEvent(), as it gets both keydowns and keypresses.
+ Renamed handleInputMethodKeypress() to handleInputMethodKeydown(), as IMs work with raw keydowns.
+
+ * dom/Document.h:
+ * dom/Document.cpp:
+ (WebCore::Document::defaultEventHandler): Moved accesskey processing to EventHandler.
+
+ * dom/KeyboardEvent.h: Added comments describing keyCode/charCode behavior.
+
+ * dom/KeyboardEvent.cpp:
+ (WebCore::eventTypeForKeyboardEventType):
+ (WebCore::KeyboardEvent::KeyboardEvent): Conversion between platform and DOM event types is
+ now straightforward, so scary hacks such as using autorepeat to distinguish types are
+ not needed.
+ (WebCore::KeyboardEvent::keyCode): Added a comment describing other browsers' behavior.
+ (WebCore::KeyboardEvent::charCode): Added a comment describing other browsers' behavior.
+ Changed to a more compatible behavior: raw keydown/keyup events do not and can not have
+ character codes.
+
+ * editing/Editor.h:
+ * editing/Editor.cpp:
+ (WebCore::Editor::isTextInsertionCommand): Is this command actually text input in disguise?
+ (WebCore::Editor::handleKeyboardEvent): Updated for new function names.
+ (WebCore::Editor::handleInputMethodKeydown): Ditto.
+
+ * html/HTMLButtonElement.cpp:
+ (WebCore::HTMLButtonElement::defaultEventHandler): Perform the default action when handling an
+ appropriate event. Enter is processed on keypress (and thus should be checked for via charCode,
+ not keyIdentifier), Space is processed on keydown+keyup! We now match IE in that a button is
+ highlighted when Space is pressed.
+
+ * html/HTMLInputElement.cpp:
+ (WebCore::HTMLInputElement::defaultEventHandler):
+ * html/HTMLSelectElement.cpp:
+ (WebCore::HTMLSelectElement::menuListDefaultEventHandler):
+ (WebCore::HTMLSelectElement::listBoxDefaultEventHandler):
+ Made a number of fixes to when default actions take place, similar to HTMLButtonElement ones
+ described above.
+
+ * page/EventHandler.cpp:
+ (WebCore::EventHandler::keyEvent): Unless we have a combined KeyDown, just forward the event
+ to the target. Call accesskey handling directly, as it doesn't seem to be part of normal event
+ handling in IE. Also streamlined the code in KeyDown case, thanks to handleInputMethodKeypress()
+ now being handleInputMethodKeydown().
+ (WebCore::EventHandler::handleTextInputEvent): Check that we were not called from keydown.
+ (WebCore::EventHandler::defaultTextInputEventHandler): Removed a call to defaultTabEventHandler,
+ as default tab handling happens when processing keydown.
+ (WebCore::handleAccessKey): Moved from Document, as access keys are processed outside normal
+ event handling. Fixed accesskey processing to use information that's available in a raw keydown
+ event.
+
+ (WebCore::EventHandler::defaultKeyboardEventHandler): Do not ignore keydown; in particular,
+ handle tabs during keydown processing.
+
+ * page/mac/EventHandlerMac.mm:
+ (WebCore::EventHandler::currentKeyboardEvent): Disambiguate KeyDown as RawKeyDown, as this is
+ what callers want.
+
+ * platform/text/PlatformString.h:
+ * platform/text/String.cpp:
+ (WebCore::String::characterStartingAt):
+ * platform/text/StringImpl.cpp:
+ (WebCore::StringImpl::characterStartingAt):
+ * platform/text/StringImpl.h:
+ Added a UChar32 accessor.
+
+ * svg/graphics/SVGImageEmptyClients.h:
+ (WebCore::SVGEmptyEditorClient::handleKeyboardEvent):
+ (WebCore::SVGEmptyEditorClient::handleInputMethodKeydown):
+ Updated for new function names.
+
2007-12-11 John Sullivan <sullivan@apple.com>
Reviewed by Adele
__ZN7WebCore20JavaScriptStatistics31garbageCollectOnAlternateThreadEb
__ZN7WebCore20ResourceResponseBase24setExpectedContentLengthEx
__ZN7WebCore21ContextMenuController16clearContextMenuEv
-__ZN7WebCore21PlatformKeyboardEventC1EP7NSEventb
+__ZN7WebCore21PlatformKeyboardEventC1EP7NSEvent
+__ZN7WebCore21PlatformKeyboardEvent24disambiguateKeyDownEventENS0_4TypeEb
__ZN7WebCore21WindowsLatin1EncodingEv
__ZN7WebCore21findEventWithKeyStateEPNS_5EventE
__ZN7WebCore21isBackForwardLoadTypeENS_13FrameLoadTypeE
__ZN7WebCore6Editor10applyStyleEPNS_19CSSStyleDeclarationENS_10EditActionE
__ZN7WebCore6Editor10insertTextERKNS_6StringEPNS_5EventE
__ZN7WebCore6Editor11canDHTMLCutEv
+__ZN7WebCore6Editor22isTextInsertionCommandERKNS_12AtomicStringE
__ZN7WebCore6Editor11execCommandERKNS_12AtomicStringEPNS_5EventE
__ZN7WebCore6Editor11tryDHTMLCutEv
__ZN7WebCore6Editor12canDHTMLCopyEv
virtual void undo() = 0;
virtual void redo() = 0;
- virtual void handleKeypress(KeyboardEvent*) = 0;
- virtual void handleInputMethodKeypress(KeyboardEvent*) = 0;
+ virtual void handleKeyboardEvent(KeyboardEvent*) = 0;
+ virtual void handleInputMethodKeydown(KeyboardEvent*) = 0;
virtual void textFieldDidBeginEditing(Element*) = 0;
virtual void textFieldDidEndEditing(Element*) = 0;
(*it)->listener()->handleEvent(evt, true);
}
-
-void Document::defaultEventHandler(Event *evt)
-{
- // handle accesskey
- if (evt->type() == keydownEvent) {
- KeyboardEvent* kevt = static_cast<KeyboardEvent *>(evt);
-#if PLATFORM(MAC)
- if (kevt->ctrlKey())
-#else
- if (kevt->altKey())
-#endif
- {
- const PlatformKeyboardEvent* ev = kevt->keyEvent();
- String key = (ev ? ev->unmodifiedText() : kevt->keyIdentifier()).lower();
- Element* elem = getElementByAccessKey(key);
- if (elem) {
- elem->accessKeyAction(false);
- evt->setDefaultHandled();
- return;
- }
- }
- }
-
- ContainerNode::defaultEventHandler(evt);
-}
-
void Document::setHTMLWindowEventListener(const AtomicString &eventType, PassRefPtr<EventListener> listener)
{
// If we already have it we don't want removeWindowEventListener to delete it
CSSStyleDeclaration* getOverrideStyle(Element*, const String& pseudoElt);
- virtual void defaultEventHandler(Event*);
void handleWindowEvent(Event*, bool useCapture);
void setHTMLWindowEventListener(const AtomicString &eventType, PassRefPtr<EventListener>);
EventListener* getHTMLWindowEventListener(const AtomicString &eventType);
#include "config.h"
#include "KeyboardEvent.h"
+#include "Document.h"
+#include "DOMWindow.h"
#include "EventNames.h"
#include "PlatformKeyboardEvent.h"
+#include "Settings.h"
namespace WebCore {
using namespace EventNames;
+static inline const AtomicString& eventTypeForKeyboardEventType(PlatformKeyboardEvent::Type type)
+{
+ switch (type) {
+ case PlatformKeyboardEvent::KeyUp:
+ return keyupEvent;
+ case PlatformKeyboardEvent::RawKeyDown:
+ return keydownEvent;
+ case PlatformKeyboardEvent::Char:
+ return keypressEvent;
+ case PlatformKeyboardEvent::KeyDown:
+ // The caller should disambiguate the combined event into RawKeyDown or Char events.
+ break;
+ }
+ ASSERT_NOT_REACHED();
+ return keydownEvent;
+}
+
KeyboardEvent::KeyboardEvent()
: m_keyEvent(0)
, m_keyLocation(DOM_KEY_LOCATION_STANDARD)
}
KeyboardEvent::KeyboardEvent(const PlatformKeyboardEvent& key, AbstractView* view)
- : UIEventWithKeyState(key.isKeyUp() ? keyupEvent : key.isAutoRepeat() ? keypressEvent : keydownEvent,
+ : UIEventWithKeyState(eventTypeForKeyboardEventType(key.type()),
true, true, view, 0, key.ctrlKey(), key.altKey(), key.shiftKey(), key.metaKey())
, m_keyEvent(new PlatformKeyboardEvent(key))
, m_keyIdentifier(key.keyIdentifier())
- , m_keyLocation(key.isKeypad() ? DOM_KEY_LOCATION_NUMPAD : DOM_KEY_LOCATION_STANDARD)
+ , m_keyLocation(key.isKeypad() ? DOM_KEY_LOCATION_NUMPAD : DOM_KEY_LOCATION_STANDARD) // FIXME: differentiate right/left, too
, m_altGraphKey(false)
{
}
int KeyboardEvent::keyCode() const
{
+ // IE: virtual key code for keyup/keydown, character code for keypress
+ // Firefox: virtual key code for keyup/keydown, zero for keypress
+ // We match IE.
if (!m_keyEvent)
return 0;
if (type() == keydownEvent || type() == keyupEvent)
- return m_keyEvent->WindowsKeyCode();
+ return m_keyEvent->windowsVirtualKeyCode();
return charCode();
}
int KeyboardEvent::charCode() const
{
- if (!m_keyEvent)
+ // IE: not supported
+ // Firefox: 0 for keydown/keyup events, character code for keypress
+ // We match Firefox, unless in Dashboard compatibility mode, where we always return the character code.
+ bool dashboardCompatibilityMode = false;
+ if (view())
+ if (Settings* settings = view()->document()->settings())
+ dashboardCompatibilityMode = settings->usesDashboardBackwardCompatibilityMode();
+
+ if (!m_keyEvent || (type() != keypressEvent && !dashboardCompatibilityMode))
return 0;
String text = m_keyEvent->text();
- if (text.length() != 1)
- return 0;
- return text[0];
+ return static_cast<int>(text.characterStartingAt(0));
}
bool KeyboardEvent::isKeyboardEvent() const
const PlatformKeyboardEvent* keyEvent() const { return m_keyEvent; }
- int keyCode() const; // key code for keydown and keyup, character for other events
- int charCode() const;
+ int keyCode() const; // key code for keydown and keyup, character for keypress
+ int charCode() const; // character code for keypress, 0 for keydown and keyup
virtual bool isKeyboardEvent() const;
virtual int which() const;
return 0;
}
-void Editor::handleKeypress(KeyboardEvent* event)
+void Editor::handleKeyboardEvent(KeyboardEvent* event)
{
if (EditorClient* c = client())
if (selectionForEvent(m_frame, event).isContentEditable())
- c->handleKeypress(event);
+ c->handleKeyboardEvent(event);
}
-void Editor::handleInputMethodKeypress(KeyboardEvent* event)
+void Editor::handleInputMethodKeydown(KeyboardEvent* event)
{
if (EditorClient* c = client())
if (selectionForEvent(m_frame, event).isContentEditable())
- c->handleInputMethodKeypress(event);
+ c->handleInputMethodKeydown(event);
}
bool Editor::canEdit() const
m_customCompositionUnderlines.clear();
}
+bool Editor::isTextInsertionCommand(const AtomicString& command)
+{
+ return command == "InsertBacktab"
+ || command == "InsertTab"
+ || command == "InsertLineBreak"
+ || command == "InsertNewline";
+}
+
bool Editor::execCommand(const AtomicString& command, Event* triggeringEvent)
{
if (!m_frame->document())
DeleteButtonController* deleteButtonController() const { return m_deleteButtonController.get(); }
EditCommand* lastEditCommand() { return m_lastEditCommand.get(); }
- void handleKeypress(KeyboardEvent*);
- void handleInputMethodKeypress(KeyboardEvent*);
+ void handleKeyboardEvent(KeyboardEvent*);
+ void handleInputMethodKeydown(KeyboardEvent*);
bool canEdit() const;
bool canEditRichly() const;
bool selectionStartHasStyle(CSSStyleDeclaration*) const;
bool clientIsEditable() const;
-
+
+ static bool isTextInsertionCommand(const AtomicString&);
+
bool execCommand(const AtomicString&, Event* triggeringEvent = 0);
bool insertText(const String&, Event* triggeringEvent);
form()->reset();
}
- if (evt->type() == keypressEvent && evt->isKeyboardEvent()) {
- String key = static_cast<KeyboardEvent*>(evt)->keyIdentifier();
-
- if (key == "Enter" || key == "U+0020") {
- dispatchSimulatedClick(evt);
+ if (evt->isKeyboardEvent()) {
+ if (evt->type() == keydownEvent && static_cast<KeyboardEvent*>(evt)->keyIdentifier() == "U+0020") {
+ setActive(true, true);
+ // No setDefaultHandled() - IE dispatches a keypress in this case.
+ return;
+ }
+ if (evt->type() == keypressEvent) {
+ switch (static_cast<KeyboardEvent*>(evt)->charCode()) {
+ case '\r':
+ dispatchSimulatedClick(evt);
+ evt->setDefaultHandled();
+ return;
+ case ' ':
+ // Prevent scrolling down the page.
+ evt->setDefaultHandled();
+ return;
+ default:
+ break;
+ }
+ }
+ if (evt->type() == keyupEvent && static_cast<KeyboardEvent*>(evt)->keyIdentifier() == "U+0020") {
+ if (active())
+ dispatchSimulatedClick(evt);
evt->setDefaultHandled();
return;
}
}
}
- // Before calling the base class defaultEventHandler, which will call handleKeypress, call doTextFieldCommandFromEvent.
- if (isTextField() && evt->type() == keypressEvent && evt->isKeyboardEvent() && focused() && document()->frame()
+ if (isTextField() && evt->type() == keydownEvent && evt->isKeyboardEvent() && focused() && document()->frame()
&& document()->frame()->doTextFieldCommandFromEvent(this, static_cast<KeyboardEvent*>(evt))) {
evt->setDefaultHandled();
return;
if (evt->type() == keypressEvent && evt->isKeyboardEvent()) {
bool clickElement = false;
- String key = static_cast<KeyboardEvent*>(evt)->keyIdentifier();
-
- if (key == "U+0020") {
- switch (inputType()) {
- case BUTTON:
- case CHECKBOX:
- case FILE:
- case IMAGE:
- case RESET:
- case SUBMIT:
- // Simulate mouse click for spacebar for these types of elements.
- // The AppKit already does this for some, but not all, of them.
- clickElement = true;
- break;
- case RADIO:
- // If an unselected radio is tabbed into (because the entire group has nothing
- // checked, or because of some explicit .focus() call), then allow space to check it.
- if (!checked())
- clickElement = true;
- break;
- case HIDDEN:
- case ISINDEX:
- case PASSWORD:
- case RANGE:
- case SEARCH:
- case TEXT:
- break;
- }
- }
+ int charCode = static_cast<KeyboardEvent*>(evt)->charCode();
- if (key == "Enter") {
+ if (charCode == '\r') {
switch (inputType()) {
case CHECKBOX:
case HIDDEN:
case RADIO:
break; // Don't do anything for enter on a radio button.
}
+ } else if (charCode == ' ') {
+ switch (inputType()) {
+ case BUTTON:
+ case CHECKBOX:
+ case FILE:
+ case IMAGE:
+ case RESET:
+ case SUBMIT:
+ case RADIO:
+ // Prevent scrolling down the page.
+ evt->setDefaultHandled();
+ return;
+ default:
+ break;
+ }
+ }
+
+ if (clickElement) {
+ dispatchSimulatedClick(evt);
+ evt->setDefaultHandled();
+ return;
+ }
+ }
+
+ if (evt->type() == keydownEvent && evt->isKeyboardEvent()) {
+ String key = static_cast<KeyboardEvent*>(evt)->keyIdentifier();
+
+ if (key == "U+0020") {
+ switch (inputType()) {
+ case BUTTON:
+ case CHECKBOX:
+ case FILE:
+ case IMAGE:
+ case RESET:
+ case SUBMIT:
+ case RADIO:
+ setActive(true, true);
+ // No setDefaultHandled() - IE dispatches a keypress in this case.
+ return;
+ default:
+ break;
+ }
}
if (inputType() == RADIO && (key == "Up" || key == "Down" || key == "Left" || key == "Right")) {
}
}
}
+ }
+
+ if (evt->type() == keyupEvent && evt->isKeyboardEvent()) {
+ bool clickElement = false;
+
+ String key = static_cast<KeyboardEvent*>(evt)->keyIdentifier();
+
+ if (key == "U+0020") {
+ switch (inputType()) {
+ case BUTTON:
+ case CHECKBOX:
+ case FILE:
+ case IMAGE:
+ case RESET:
+ case SUBMIT:
+ // Simulate mouse click for spacebar for these types of elements.
+ // The AppKit already does this for some, but not all, of them.
+ clickElement = true;
+ break;
+ case RADIO:
+ // If an unselected radio is tabbed into (because the entire group has nothing
+ // checked, or because of some explicit .focus() call), then allow space to check it.
+ if (!checked())
+ clickElement = true;
+ break;
+ case HIDDEN:
+ case ISINDEX:
+ case PASSWORD:
+ case RANGE:
+ case SEARCH:
+ case TEXT:
+ break;
+ }
+ }
if (clickElement) {
- dispatchSimulatedClick(evt);
+ if (active())
+ dispatchSimulatedClick(evt);
evt->setDefaultHandled();
return;
}
{
RenderMenuList* menuList = static_cast<RenderMenuList*>(renderer());
- // Use key press event here since sending simulated mouse events
- // on key down blocks the proper sending of the key press event.
- if (evt->type() == keypressEvent) {
+ if (evt->type() == keydownEvent) {
if (!renderer() || !evt->isKeyboardEvent())
return;
String keyIdentifier = static_cast<KeyboardEvent*>(evt)->keyIdentifier();
bool handled = false;
#if ARROW_KEYS_POP_MENU
- if (keyIdentifier == "Enter") {
- menuListOnChange();
- if (form())
- form()->submitClick(evt);
- handled = true;
- }
- if (keyIdentifier == "Down" || keyIdentifier == "Up" || keyIdentifier == "U+0020") {
+ if (keyIdentifier == "Down" || keyIdentifier == "Up") {
focus();
// Save the selection so it can be compared to the new selection when we call onChange during setSelectedIndex,
// which gets called from RenderMenuList::valueChanged, which gets called after the user makes a selection from the menu.
if (listIndex >= 0 && listIndex < size)
setSelectedIndex(listToOptionIndex(listIndex));
handled = true;
- } else if (keyIdentifier == "Enter") {
+ }
+#endif
+ if (handled)
+ evt->setDefaultHandled();
+ }
+
+ // Use key press event here since sending simulated mouse events
+ // on key down blocks the proper sending of the key press event.
+ if (evt->type() == keypressEvent) {
+ if (!renderer() || !evt->isKeyboardEvent())
+ return;
+ int keyCode = static_cast<KeyboardEvent*>(evt)->keyCode();
+ bool handled = false;
+#if ARROW_KEYS_POP_MENU
+ if (keyCode == ' ') {
+ focus();
+ // Save the selection so it can be compared to the new selection when we call onChange during setSelectedIndex,
+ // which gets called from RenderMenuList::valueChanged, which gets called after the user makes a selection from the menu.
+ saveLastSelection();
+ menuList->showPopup();
+ handled = true;
+ }
+ if (keyCode == '\r') {
+ menuListOnChange();
+ if (form())
+ form()->submitClick(evt);
+ handled = true;
+ }
+#else
+ int listIndex = optionToListIndex(selectedIndex());
+ if (keyCode == '\r') {
// listIndex should already be selected, but this will fire the onchange handler.
setSelectedIndex(listToOptionIndex(listIndex), true, true);
handled = true;
#endif
if (handled)
evt->setDefaultHandled();
-
}
+
if (evt->type() == mousedownEvent && evt->isMouseEvent() && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
focus();
if (menuList->popupIsVisible())
} else if (evt->type() == mouseupEvent && evt->isMouseEvent() && static_cast<MouseEvent*>(evt)->button() == LeftButton && document()->frame()->eventHandler()->autoscrollRenderer() != renderer())
// This makes sure we fire onChange for a single click. For drag selection, onChange will fire when the autoscroll timer stops.
listBoxOnChange();
- else if (evt->type() == keypressEvent) {
+ else if (evt->type() == keydownEvent) {
if (!evt->isKeyboardEvent())
return;
String keyIdentifier = static_cast<KeyboardEvent*>(evt)->keyIdentifier();
- if (keyIdentifier == "Enter") {
- if (form())
- form()->submitClick(evt);
- evt->setDefaultHandled();
- return;
- }
-
int endIndex = 0;
if (m_activeSelectionEndIndex < 0) {
// Initialize the end index
listBoxOnChange();
evt->setDefaultHandled();
}
+ } else if (evt->type() == keypressEvent) {
+ if (!evt->isKeyboardEvent())
+ return;
+ int keyCode = static_cast<KeyboardEvent*>(evt)->keyCode();
+
+ if (keyCode == '\r') {
+ if (form())
+ form()->submitClick(evt);
+ evt->setDefaultHandled();
+ return;
+ }
}
}
return EventTargetNodeCast(node);
}
+static bool handleAccessKey(Document* document, const PlatformKeyboardEvent& evt)
+{
+#if PLATFORM(MAC)
+ if (evt.ctrlKey())
+#else
+ if (evt.altKey())
+#endif
+ {
+ String key = evt.unmodifiedText();
+ Element* elem = document->getElementByAccessKey(key.lower());
+ if (elem) {
+ elem->accessKeyAction(false);
+ return true;
+ }
+ }
+
+ return false;
+}
bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
{
// Check for cases where we are too early for events -- possible unmatched key up
// from pressing return in the location bar.
- EventTargetNode* node = eventTargetNodeForDocument(m_frame->document());
+ RefPtr<EventTargetNode> node = eventTargetNodeForDocument(m_frame->document());
if (!node)
return false;
-
- if (initialKeyEvent.isKeyUp())
- return !node->dispatchKeyEvent(initialKeyEvent);
-
+
+ // FIXME: what is this doing here, in keyboard event handler?
m_frame->loader()->resetMultipleFormSubmissionProtection();
+
+ // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match.
+ // On Windows, we process them before dispatching keypress event (and rely on WebKit to not drop WM_SYSCHAR events when a keydown representing WM_SYSKEYDOWN is canceled).
+ // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict with access keys.
+ // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
+ bool matchedAnAccessKey = false;
+ if (initialKeyEvent.type() == PlatformKeyboardEvent::Char) {
+ if (handleAccessKey(m_frame->document(), initialKeyEvent))
+ return true;
+ } else if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyDown)
+ matchedAnAccessKey = handleAccessKey(m_frame->document(), initialKeyEvent);
+
+ // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
+ if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyUp || initialKeyEvent.type() == PlatformKeyboardEvent::Char)
+ return !node->dispatchKeyEvent(initialKeyEvent);
+
+ bool dashboardCompatibilityMode = false;
+ if (Settings* settings = node->document()->settings())
+ dashboardCompatibilityMode = settings->usesDashboardBackwardCompatibilityMode();
+
+ ExceptionCode ec;
+ PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
+ if (keyDownEvent.type() != PlatformKeyboardEvent::RawKeyDown)
+ keyDownEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::RawKeyDown, dashboardCompatibilityMode);
+ RefPtr<KeyboardEvent> keydown = new KeyboardEvent(keyDownEvent, m_frame->document()->defaultView());
+ if (matchedAnAccessKey)
+ keydown->setDefaultPrevented(true);
+ keydown->setTarget(node);
+
+ if (initialKeyEvent.type() == PlatformKeyboardEvent::RawKeyDown) {
+ node->dispatchEvent(keydown, ec, true);
+ return keydown->defaultHandled() || keydown->defaultPrevented();
+ }
+
+ // Run input method in advance of DOM event handling. This may result in the IM
+ // modifying the page prior the keydown event, but this behaviour is necessary
+ // in order to match IE:
+ // 1. preventing default handling of keydown and keypress events has no effect on IM input;
+ // 2. if an input method handles the event, its keyCode is set to 229 in keydown event.
+ m_frame->editor()->handleInputMethodKeydown(keydown.get());
+
+ bool handledByInputMethod = keydown->defaultHandled();
+
+ if (handledByInputMethod) {
+ keyDownEvent.setWindowsVirtualKeyCode(CompositionEventKeyCode);
+ keydown = new KeyboardEvent(keyDownEvent, m_frame->document()->defaultView());
+ keydown->setTarget(node);
+ keydown->setDefaultHandled();
+ }
+
+ node->dispatchEvent(keydown, ec, true);
+ bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented();
+ if (handledByInputMethod || (keydownResult && !dashboardCompatibilityMode) || initialKeyEvent.text().isEmpty())
+ return keydownResult;
- // Prepare the keyPress in advance of the keyDown so we can fire the input method
- // in advance of keyDown
- PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
- keyPressEvent.setIsAutoRepeat(true);
+ // Focus may have changed during keydown handling, so refetch node.
+ // But if we are dispatching a fake Dashboard compatibility keypress, then we pretend that the keypress happened on the original node.
+ if (!keydownResult) {
+ node = eventTargetNodeForDocument(m_frame->document());
+ if (!node)
+ return false;
+ }
+
+ PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
+ keyPressEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::Char, dashboardCompatibilityMode);
RefPtr<KeyboardEvent> keypress = new KeyboardEvent(keyPressEvent, m_frame->document()->defaultView());
keypress->setTarget(node);
-
- // Run input method in advance of DOM event handling. This may result in the IM
- // modifying the page prior the keydown event, however this behaviour is necessary
- // in order to match IE
- m_frame->editor()->handleInputMethodKeypress(keypress.get());
-
- bool handledByInputMethod = keypress->defaultHandled();
-
- PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
-
- if (handledByInputMethod)
- keyDownEvent.setWindowsKeyCode(CompositionEventKeyCode);
-
- // We always send keyDown and keyPress for all events, including autorepeat keys
- keyDownEvent.setIsAutoRepeat(false);
-
- bool result = !node->dispatchKeyEvent(keyDownEvent);
-
- // Focus may have change during the keyDown handling, so refetch node
- node = eventTargetNodeForDocument(m_frame->document());
- if (!node)
- return result;
-
- if (keypress->defaultHandled())
- return true;
-
- if (handledByInputMethod || initialKeyEvent.isModifierKeyPress())
- return result;
-
- // If the default handling has been prevented on the keydown, we prevent it on
- // the keypress as well
- if (result)
- keypress->setDefaultHandled();
-
- ExceptionCode ec;
+ if (keydownResult)
+ keypress->setDefaultPrevented(true);
node->dispatchEvent(keypress, ec, true);
-
- return result || keypress->defaultHandled() || keypress->defaultPrevented();
+
+ return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled();
}
void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event)
{
- if (event->type() == keypressEvent) {
- m_frame->editor()->handleKeypress(event);
+ if (event->type() == keydownEvent) {
+ m_frame->editor()->handleKeyboardEvent(event);
if (event->defaultHandled())
return;
if (event->keyIdentifier() == "U+0009")
defaultTabEventHandler(event, false);
- }
+ }
+ if (event->type() == keypressEvent) {
+ m_frame->editor()->handleKeyboardEvent(event);
+ if (event->defaultHandled())
+ return;
+ }
}
bool EventHandler::dragHysteresisExceeded(const FloatPoint& floatDragViewportLocation) const
{
if (!m_frame)
return false;
+#ifndef NDEBUG
+ // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline),
+ // and avoid dispatching text input events from keydown default handlers.
+ if (underlyingEvent && underlyingEvent->isKeyboardEvent())
+ ASSERT(static_cast<KeyboardEvent*>(underlyingEvent)->type() == keypressEvent);
+#endif
EventTarget* target;
if (underlyingEvent)
target = underlyingEvent->target();
void EventHandler::defaultTextInputEventHandler(TextEvent* event)
{
String data = event->data();
- if (data == "\t") {
- defaultTabEventHandler(event, event->isBackTab());
- if (event->defaultHandled())
- return;
- }
if (data == "\n") {
if (event->isLineBreak()) {
if (m_frame->editor()->insertLineBreak())
if (!event)
return 0;
switch ([event type]) {
- case NSKeyDown:
+ case NSKeyDown: {
+ PlatformKeyboardEvent platformEvent(event);
+ platformEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::RawKeyDown);
+ return new KeyboardEvent(platformEvent, m_frame->document() ? m_frame->document()->defaultView() : 0);
+ }
case NSKeyUp:
return new KeyboardEvent(event, m_frame->document() ? m_frame->document()->defaultView() : 0);
default:
class PlatformKeyboardEvent {
public:
+ enum Type {
+ // KeyDown is sent by platforms such as Mac OS X, gtk and Qt, and has information about both physical pressed key, and its translation.
+ // For DOM processing, it needs to be disambiguated as RawKeyDown or Char event.
+ KeyDown,
+
+ // KeyUp is sent by all platforms.
+ KeyUp,
+
+ // These events are sent by platforms such as Windows and wxWidgets. RawKeyDown only has information about a physical key, and Char
+ // only has information about a character it was translated into.
+ RawKeyDown,
+ Char
+ };
+
+ Type type() const { return m_type; }
+ void disambiguateKeyDownEvent(Type, bool dashboardCompatibilityMode = false); // Only used on platforms that need it, i.e. those that generate KeyDown events.
+
+ // Text as as generated by processing a virtual key code with a keyboard layout
+ // (in most cases, just a character code, but the layout can emit several
+ // characters in a single keypress event on some platforms).
+ // This may bear no resemblance to the ultimately inserted text if an input method
+ // processes the input.
+ // Will be null for KeyUp and RawKeyDown events.
String text() const { return m_text; }
+
+ // Text that would have been generated by the keyboard if no modifiers were pressed
+ // (except for Shift); useful for shortcut (accelerator) key handling.
+ // Otherwise, same as text().
String unmodifiedText() const { return m_unmodifiedText; }
+
+ // Most compatible Windows virtual key code associated with the event.
+ // Zero for Char events.
+ int windowsVirtualKeyCode() const { return m_windowsVirtualKeyCode; }
+ void setWindowsVirtualKeyCode(int code) { m_windowsVirtualKeyCode = code; }
+
String keyIdentifier() const { return m_keyIdentifier; }
- bool isKeyUp() const { return m_isKeyUp; }
bool isAutoRepeat() const { return m_autoRepeat; }
void setIsAutoRepeat(bool in) { m_autoRepeat = in; }
- int WindowsKeyCode() const { return m_WindowsKeyCode; }
- void setWindowsKeyCode(int code) { m_WindowsKeyCode = code; }
bool isKeypad() const { return m_isKeypad; }
bool shiftKey() const { return m_shiftKey; }
bool ctrlKey() const { return m_ctrlKey; }
bool altKey() const { return m_altKey; }
bool metaKey() const { return m_metaKey; }
- bool isModifierKeyPress() const { return m_isModifierKeyPress; }
static bool currentCapsLockState();
#if PLATFORM(MAC)
- PlatformKeyboardEvent(NSEvent*, bool forceAutoRepeat = false);
+ PlatformKeyboardEvent(NSEvent*);
NSEvent* macEvent() const { return m_macEvent.get(); }
#endif
#if PLATFORM(WIN)
- PlatformKeyboardEvent(HWND, WPARAM, LPARAM, UChar, bool);
+ PlatformKeyboardEvent(HWND, WPARAM, LPARAM, Type, bool);
bool isSystemKey() const { return m_isSystemKey; }
#endif
#if PLATFORM(WX)
PlatformKeyboardEvent(wxKeyEvent&);
- bool isWxCharEvent() const { return m_isWxCharEvent; }
#endif
private:
+ Type m_type;
String m_text;
String m_unmodifiedText;
String m_keyIdentifier;
- bool m_isKeyUp;
bool m_autoRepeat;
- int m_WindowsKeyCode;
+ int m_windowsVirtualKeyCode;
bool m_isKeypad;
bool m_shiftKey;
bool m_ctrlKey;
bool m_altKey;
bool m_metaKey;
-
- // A control key event -- eg. keydown/up for shift, ctrl, alt, and meta -- needs
- // a flag to indicate that we should not generate a keyPress event.
- bool m_isModifierKeyPress;
-#if PLATFORM(WX)
- bool m_isWxCharEvent;
-#endif
+
#if PLATFORM(MAC)
RetainPtr<NSEvent> m_macEvent;
#endif
}
PlatformKeyboardEvent::PlatformKeyboardEvent(GdkEventKey* event)
- : m_text(singleCharacterString(event->keyval))
+ : m_type((event->type == GDK_KEY_RELEASE) ? KeyUp : KeyDown)
+ , m_text(singleCharacterString(event->keyval))
, m_unmodifiedText(singleCharacterString(event->keyval))
, m_keyIdentifier(keyIdentifierForGdkKeyCode(event->keyval))
- , m_isKeyUp(event->type == GDK_KEY_RELEASE)
, m_autoRepeat(false)
- , m_WindowsKeyCode(windowsKeyCodeForKeyEvent(event->keyval))
+ , m_windowsVirtualKeyCode(windowsKeyCodeForKeyEvent(event->keyval))
, m_isKeypad(false)
, m_shiftKey((event->state & GDK_SHIFT_MASK) || (event->keyval == GDK_3270_BackTab))
, m_ctrlKey(event->state & GDK_CONTROL_MASK)
, m_altKey(event->state & GDK_MOD1_MASK)
, m_metaKey(event->state & GDK_MOD2_MASK)
- , m_isModifierKeyPress(false)
{
}
+void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type type, bool)
+{
+ // Can only change type from KeyDown to RawKeyDown or Char, as we lack information for other conversions.
+ ASSERT(m_type == KeyDown);
+ m_type = type;
+
+ if (type == RawKeyDown) {
+ m_text = String();
+ m_unmodifiedText = String();
+ } else {
+ m_keyIdentifier = String();
+ m_windowsVirtualKeyCode = 0;
+ }
+}
+
bool PlatformKeyboardEvent::currentCapsLockState()
{
notImplemented();
return false;
}
-static int WindowsKeyCodeForKeyEvent(NSEvent* event)
+static int windowsKeyCodeForKeyEvent(NSEvent* event)
{
switch ([event keyCode]) {
// VK_TAB (09) TAB key
static inline bool isKeyUpEvent(NSEvent *event)
{
if ([event type] != NSFlagsChanged)
- return false;
+ return [event type] == NSKeyUp;
+ // FIXME: This logic fails if the user presses both Shift keys at once, for example:
+ // we treat releasing one of them as keyDown.
switch ([event keyCode]) {
case 54: // Right Command
case 55: // Left Command
return "";
return [event charactersIgnoringModifiers];
}
-
-PlatformKeyboardEvent::PlatformKeyboardEvent(NSEvent *event, bool forceAutoRepeat)
- : m_text(textFromEvent(event))
+
+PlatformKeyboardEvent::PlatformKeyboardEvent(NSEvent *event)
+ : m_type(isKeyUpEvent(event) ? PlatformKeyboardEvent::KeyUp : PlatformKeyboardEvent::KeyDown)
+ , m_text(textFromEvent(event))
, m_unmodifiedText(unmodifiedTextFromEvent(event))
, m_keyIdentifier(keyIdentifierForKeyEvent(event))
- , m_isKeyUp([event type] == NSKeyUp || isKeyUpEvent(event))
- , m_autoRepeat(([event type] != NSFlagsChanged) && (forceAutoRepeat || [event isARepeat]))
- , m_WindowsKeyCode(WindowsKeyCodeForKeyEvent(event))
+ , m_autoRepeat(([event type] != NSFlagsChanged) && [event isARepeat])
+ , m_windowsVirtualKeyCode(windowsKeyCodeForKeyEvent(event))
, m_isKeypad(isKeypadEvent(event))
, m_shiftKey([event modifierFlags] & NSShiftKeyMask)
, m_ctrlKey([event modifierFlags] & NSControlKeyMask)
, m_altKey([event modifierFlags] & NSAlternateKeyMask)
, m_metaKey([event modifierFlags] & NSCommandKeyMask)
- , m_isModifierKeyPress([event type] == NSFlagsChanged)
, m_macEvent(event)
{
+ // Always use 13 for Enter/Return -- we don't want to use AppKit's different character for Enter.
+ if (m_windowsVirtualKeyCode == '\r') {
+ m_text = "\r";
+ m_unmodifiedText = "\r";
+ }
+
+ // The adjustments below are only needed in Dashboard compatibility mode, but we cannot tell what mode we are in from here.
+
// Turn 0x7F into 8, because backspace needs to always be 8.
if (m_text == "\x7F")
m_text = "\x8";
if (m_unmodifiedText == "\x7F")
m_unmodifiedText = "\x8";
// Always use 9 for tab -- we don't want to use AppKit's different character for shift-tab.
- if (m_WindowsKeyCode == 9) {
+ if (m_windowsVirtualKeyCode == 9) {
m_text = "\x9";
m_unmodifiedText = "\x9";
}
}
+void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type type, bool dashboardCompatibilityMode)
+{
+ // Can only change type from KeyDown to RawKeyDown or Char, as we lack information for other conversions.
+ ASSERT(m_type == KeyDown);
+ ASSERT(type == RawKeyDown || type == Char);
+ m_type = type;
+ if (dashboardCompatibilityMode)
+ return;
+
+ if (type == RawKeyDown) {
+ m_text = String();
+ m_unmodifiedText = String();
+ } else {
+ m_keyIdentifier = String();
+ m_windowsVirtualKeyCode = 0;
+ }
+}
+
bool PlatformKeyboardEvent::currentCapsLockState()
{
return GetCurrentKeyModifiers() & alphaLock;
PlatformKeyboardEvent::PlatformKeyboardEvent(QKeyEvent* event)
{
const int state = event->modifiers();
+ m_type = (event->type() == QEvent::KeyRelease) ? KeyUp : KeyDown;
m_text = event->text();
m_unmodifiedText = event->text(); // FIXME: not correct
m_keyIdentifier = keyIdentifierForQtKeyCode(event->key());
- m_isKeyUp = (event->type() == QEvent::KeyRelease);
m_autoRepeat = event->isAutoRepeat();
m_ctrlKey = (state & Qt::ControlModifier) != 0;
m_altKey = (state & Qt::AltModifier) != 0;
m_metaKey = (state & Qt::MetaModifier) != 0;
- m_WindowsKeyCode = windowsKeyCodeForKeyEvent(event->key());
+ m_windowsVirtualKeyCode = windowsKeyCodeForKeyEvent(event->key());
m_isKeypad = (state & Qt::KeypadModifier) != 0;
m_shiftKey = (state & Qt::ShiftModifier) != 0 || event->key() == Qt::Key_Backtab; // Simulate Shift+Tab with Key_Backtab
}
+void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type type, bool)
+{
+ // Can only change type from KeyDown to RawKeyDown or Char, as we lack information for other conversions.
+ ASSERT(m_type == KeyDown);
+ m_type = type;
+
+ if (type == RawKeyDown) {
+ m_text = String();
+ m_unmodifiedText = String();
+ } else {
+ m_keyIdentifier = String();
+ m_windowsVirtualKeyCode = 0;
+ }
+}
+
bool PlatformKeyboardEvent::currentCapsLockState()
{
notImplemented();
const UChar* characters() const;
const UChar* charactersWithNullTermination();
- UChar operator[](unsigned i) const; // if i >= length(), returns 0
+ UChar operator[](unsigned i) const; // if i >= length(), returns 0
+ UChar32 characterStartingAt(unsigned) const; // Ditto.
bool contains(UChar c) const { return find(c) != -1; }
bool contains(const char* str, bool caseSensitive = true) const { return find(str, 0, caseSensitive) != -1; }
return m_impl->characters()[i];
}
+UChar32 String::characterStartingAt(unsigned i) const
+{
+ if (!m_impl || i >= m_impl->length())
+ return 0;
+ return m_impl->characterStartingAt(i);
+}
unsigned String::length() const
{
if (!m_impl)
return new StringImpl(m_data + pos, len);
}
+UChar32 StringImpl::characterStartingAt(unsigned i) const
+{
+ if (U16_IS_SINGLE(m_data[i]))
+ return m_data[i];
+ if (i + 1 < m_length && U16_IS_LEAD(m_data[i]) && U16_IS_TRAIL(m_data[i + 1]))
+ return U16_GET_SUPPLEMENTARY(m_data[i], m_data[i + 1]);
+ return 0;
+}
+
static Length parseLength(const UChar* m_data, unsigned int m_length)
{
if (m_length == 0)
StringImpl* substring(unsigned pos, unsigned len = UINT_MAX);
UChar operator[](int pos) const { return m_data[pos]; }
+ UChar32 characterStartingAt(unsigned) const;
Length toLength() const;
namespace WebCore {
-static const unsigned REPEAT_COUNT_MASK = 0x0000FFFF;
-static const unsigned NEW_RELEASE_STATE_MASK = 0x80000000;
-static const unsigned PREVIOUS_DOWN_STATE_MASK = 0x40000000;
-
static const unsigned short HIGH_BIT_MASK_SHORT = 0x8000;
// FIXME: This is incomplete. We could change this to mirror
static inline String singleCharacterString(UChar c) { return String(&c, 1); }
-PlatformKeyboardEvent::PlatformKeyboardEvent(HWND, WPARAM virtualKeyCode, LPARAM keyData, UChar characterCode, bool systemKey)
- : m_text(singleCharacterString(characterCode))
- , m_unmodifiedText(singleCharacterString(characterCode))
- , m_keyIdentifier(keyIdentifierForWindowsKeyCode(virtualKeyCode))
- , m_isKeyUp((keyData & NEW_RELEASE_STATE_MASK))
- , m_autoRepeat((keyData & REPEAT_COUNT_MASK) > 1)
- , m_WindowsKeyCode(virtualKeyCode)
+PlatformKeyboardEvent::PlatformKeyboardEvent(HWND, WPARAM code, LPARAM keyData, Type type, bool systemKey)
+ : m_type(type)
+ , m_text((type == Char) ? singleCharacterString(code) : String())
+ , m_unmodifiedText((type == Char) ? singleCharacterString(code) : String())
+ , m_keyIdentifier((type == Char) ? String() : keyIdentifierForWindowsKeyCode(code))
+ , m_autoRepeat(keyData & KF_REPEAT)
+ , m_windowsVirtualKeyCode((type == RawKeyDown || type == KeyUp) ? code : 0)
, m_isKeypad(false) // FIXME: Need to implement this.
, m_shiftKey(GetKeyState(VK_SHIFT) & HIGH_BIT_MASK_SHORT)
, m_ctrlKey(GetKeyState(VK_CONTROL) & HIGH_BIT_MASK_SHORT)
, m_altKey(GetKeyState(VK_MENU) & HIGH_BIT_MASK_SHORT)
, m_metaKey(m_altKey)
- , m_isModifierKeyPress(virtualKeyCode == VK_SHIFT || virtualKeyCode == VK_CONTROL || virtualKeyCode == VK_MENU || virtualKeyCode == VK_CAPITAL)
, m_isSystemKey(systemKey)
{
}
+void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type, bool)
+{
+ // No KeyDown events here to change.
+ ASSERT_NOT_REACHED();
+}
+
bool PlatformKeyboardEvent::currentCapsLockState()
{
return GetKeyState(VK_CAPITAL) & 1;
PlatformKeyboardEvent::PlatformKeyboardEvent(wxKeyEvent& event)
{
- m_text = wxString(event.GetUnicodeKey());
- m_unmodifiedText = m_text;
- m_keyIdentifier = keyIdentifierForWxKeyCode(event.GetKeyCode());
- m_isKeyUp = event.GetEventType() == wxEVT_KEY_UP;
+ switch (event.GetEventType()) {
+ case wxEVT_KEY_UP:
+ m_type = KeyUp;
+ break;
+ case wxEVT_KEY_DOWN:
+ m_type = KeyDown;
+ break;
+ case wxEVT_CHAR:
+ m_type = Char;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ m_text = (type == Char) ? wxString(event.GetUnicodeKey()) : String();
+ m_unmodifiedText = (type == Char) ? m_text : String();
+ m_keyIdentifier = (type == Char) ? String() : keyIdentifierForWxKeyCode(event.GetKeyCode());
m_autoRepeat = false; // FIXME: not correct.
- m_WindowsKeyCode = windowsKeyCodeForKeyEvent(event.GetKeyCode());
+ m_windowsVirtualKeyCode = windowsKeyCodeForKeyEvent(event.GetKeyCode());
m_isKeypad = (event.GetKeyCode() >= WXK_NUMPAD_SPACE) && (event.GetKeyCode() <= WXK_NUMPAD_DIVIDE);
m_shiftKey = event.ShiftDown();
m_ctrlKey = event.CmdDown();
m_altKey = event.AltDown();
m_metaKey = event.MetaDown();
- m_isModifierKeyPress = false;
- m_isWxCharEvent = event.GetEventType() == wxEVT_CHAR;
+}
+
+void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type type, bool)
+{
+ // Can only change type from KeyDown to RawKeyDown or Char, as we lack information for other conversions.
+ ASSERT(m_type == KeyDown);
+ m_type = type;
+ if (type == RawKeyDown) {
+ m_text = String();
+ m_unmodifiedText = String();
+ } else {
+ m_keyIdentifier = String();
+ m_windowsVirtualKeyCode = 0;
+ }
}
bool PlatformKeyboardEvent::currentCapsLockState()
virtual void undo() { }
virtual void redo() { }
- virtual void handleKeypress(KeyboardEvent*) { }
- virtual void handleInputMethodKeypress(KeyboardEvent*) { }
+ virtual void handleKeyboardEvent(KeyboardEvent*) { }
+ virtual void handleInputMethodKeydown(KeyboardEvent*) { }
virtual void textFieldDidBeginEditing(Element*) { }
virtual void textFieldDidEndEditing(Element*) { }
+2007-12-07 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Darin.
+
+ <rdar://problem/5535636>
+ Have to press 4 times instead of 2 times to get the expected result of ^^ with german keyboard.
+
+ http://bugs.webkit.org/show_bug.cgi?id=13916
+ JavaScript detects Tab as a character input on a textfield validation
+
+ * WebCoreSupport/EditorClientGtk.cpp:
+ (WebKit::EditorClient::handleKeyboardEvent):
+ (WebKit::EditorClient::handleInputMethodKeydown):
+ * WebCoreSupport/EditorClientGtk.h:
+ Updated for cross-platform changes as much as it was possible without a gtk build environment.
+
2007-12-08 Luca Bruno <lethalman88@gmail.com>
Reviewed by Alp Toker.
{
}
-void EditorClient::handleKeypress(KeyboardEvent* event)
+void EditorClient::handleKeyboardEvent(KeyboardEvent* event)
{
Frame* frame = core(m_page)->focusController()->focusedOrMainFrame();
if (!frame || !frame->document()->focusedNode())
return;
const PlatformKeyboardEvent* kevent = event->keyEvent();
- if (!kevent || kevent->isKeyUp())
+ if (!kevent || kevent->type() == PlatformKeyboardEvent::KeyUp)
return;
Node* start = frame->selectionController()->start().node();
// http://bugs.webkit.org/show_bug.cgi?id=15911
if (start->isContentEditable()) {
- switch(kevent->WindowsKeyCode()) {
+ switch (kevent->windowsVirtualKeyCode()) {
case VK_BACK:
frame->editor()->deleteWithDirection(SelectionController::BACKWARD,
kevent->ctrlKey() ? WordGranularity : CharacterGranularity, false, true);
}
frame->editor()->insertText(kevent->text(), event);
} else if (kevent->ctrlKey()) {
- switch (kevent->WindowsKeyCode()) {
+ switch (kevent->windowsVirtualKeyCode()) {
case VK_B:
frame->editor()->execCommand("ToggleBold");
break;
} else return;
}
} else {
- switch (kevent->WindowsKeyCode()) {
+ switch (kevent->windowsVirtualKeyCode()) {
case VK_UP:
frame->editor()->execCommand("MoveUp");
break;
}
-void EditorClient::handleInputMethodKeypress(KeyboardEvent*)
+void EditorClient::handleInputMethodKeydown(KeyboardEvent*)
{
notImplemented();
}
virtual void undo();
virtual void redo();
- virtual void handleKeypress(WebCore::KeyboardEvent*);
- virtual void handleInputMethodKeypress(WebCore::KeyboardEvent*);
+ virtual void handleKeyboardEvent(WebCore::KeyboardEvent*);
+ virtual void handleInputMethodKeydown(WebCore::KeyboardEvent*);
virtual void textFieldDidBeginEditing(WebCore::Element*);
virtual void textFieldDidEndEditing(WebCore::Element*);
+2007-12-07 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Darin.
+
+ <rdar://problem/5535636>
+ Have to press 4 times instead of 2 times to get the expected result of ^^ with german keyboard.
+
+ http://bugs.webkit.org/show_bug.cgi?id=13916
+ JavaScript detects Tab as a character input on a textfield validation
+
+ * WebCoreSupport/WebEditorClient.h:
+ Renamed handleKeypress() to handleKeyboardEvent(), as it gets both keydowns and keypresses.
+ Renamed handleInputMethodKeypress() to handleInputMethodKeydown().
+ * WebCoreSupport/WebEditorClient.mm:
+ (WebEditorClient::handleKeyboardEvent): This change makes sense only remotely, but it helped
+ to get tests working. I guess Mac keyboard event handling needs further refactoring.
+
+ * WebView/WebHTMLView.mm:
+ (selectorToCommandName): Convert AppKit editing selector name to Editor command name - extracted
+ from callWebCoreCommand:.
+ (_interceptEditingKeyEvent:shouldSaveCommand:): Insert text from keypress.
+
+ * WebView/WebPDFView.mm:
+ (-[WebPDFView PDFViewWillClickOnLink:withURL:]):
+ Convert incoming platform KeyDown into RawKeyDown, as this is what the view is interested in.
+
2007-12-10 Brady Eidson <beidson@apple.com>
Reviewed by John Sullivan
virtual void undo();
virtual void redo();
- virtual void handleKeypress(WebCore::KeyboardEvent*);
- virtual void handleInputMethodKeypress(WebCore::KeyboardEvent*);
+ virtual void handleKeyboardEvent(WebCore::KeyboardEvent*);
+ virtual void handleInputMethodKeydown(WebCore::KeyboardEvent*);
virtual void textFieldDidBeginEditing(WebCore::Element*);
virtual void textFieldDidEndEditing(WebCore::Element*);
[[m_webView undoManager] redo];
}
-void WebEditorClient::handleKeypress(KeyboardEvent* event)
+void WebEditorClient::handleKeyboardEvent(KeyboardEvent* event)
{
Frame* frame = event->target()->toNode()->document()->frame();
WebHTMLView *webHTMLView = [[kit(frame) frameView] documentView];
event->setDefaultHandled();
}
-void WebEditorClient::handleInputMethodKeypress(KeyboardEvent* event)
+void WebEditorClient::handleInputMethodKeydown(KeyboardEvent* event)
{
Frame* frame = event->target()->toNode()->document()->frame();
WebHTMLView *webHTMLView = [[kit(frame) frameView] documentView];
return [[webView _editingDelegateForwarder] webView:webView doCommandBySelector:selector];
}
-- (void)callWebCoreCommand:(SEL)selector
+static AtomicString selectorToCommandName(SEL selector)
{
- if ([self callDelegateDoCommandBySelectorIfNeeded:selector])
- return;
-
- Frame* coreFrame = core([self _frame]);
- if (!coreFrame)
- return;
-
// Capitalize the first letter of the selector, since we use capitalized command
// names in the Editor object (why?). And remove the trailing colon.
+ // And change a few command names into ones supported by WebCore::Editor.
+
+ if (selector == @selector(insertParagraphSeparator:) || selector == @selector(insertNewlineIgnoringFieldEditor:))
+ return "InsertNewline";
+ if (selector == @selector(insertTabIgnoringFieldEditor:))
+ return "InsertTab";
+
const char* selectorName = sel_getName(selector);
size_t selectorNameLength = strlen(selectorName);
ASSERT(selectorNameLength >= 2);
memcpy(&commandName[1], &selectorName[1], selectorNameLength - 2);
commandName[selectorNameLength - 1] = 0;
- coreFrame->editor()->execCommand(commandName.data());
+ return AtomicString(commandName.data());
+}
+
+- (void)callWebCoreCommand:(SEL)selector
+{
+ if ([self callDelegateDoCommandBySelectorIfNeeded:selector])
+ return;
+
+ Frame* coreFrame = core([self _frame]);
+ if (!coreFrame)
+ return;
+
+ coreFrame->editor()->execCommand(selectorToCommandName(selector));
}
// These commands are forwarded to the Editor object in WebCore.
// and only change this assumption if one of the NSTextInput/Responder callbacks is used.
// We assume the IM will *not* consume hotkey sequences
parameters.consumedByIM = !event->metaKey() && shouldSave;
-
+
if (const PlatformKeyboardEvent* platformEvent = event->keyEvent()) {
NSEvent *macEvent = platformEvent->macEvent();
if ([macEvent type] == NSKeyDown && [_private->compController filterKeyDown:macEvent])
KeypressCommand command = event->keypressCommand();
bool hasKeypressCommand = !command.commandNames.isEmpty() || !command.text.isEmpty();
+ // FIXME: interpretKeyEvents doesn't match application key equivalents (such as Cmd+A),
+ // and sends noop: for those. As a result, we don't handle those from within WebCore,
+ // but send a full sequence of DOM events, including an unneeded keypress.
if (parameters.shouldSaveCommand || !hasKeypressCommand)
[self interpretKeyEvents:[NSArray arrayWithObject:macEvent]];
else {
- if (!command.text.isEmpty())
- [self insertText:command.text];
- else {
- size_t size = command.commandNames.size();
+ ASSERT(platformEvent->type() == PlatformKeyboardEvent::RawKeyDown);
+ size_t size = command.commandNames.size();
+ // Are there commands that would just cause text insertion if executed via Editor?
+ // WebKit doesn't have enough information about mode to decide how they should be treated, so we leave it upon WebCore
+ // to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated
+ // (e.g. Tab that inserts a Tab character, or Enter).
+ bool haveTextInsertionCommands = false;
+ for (size_t i = 0; i < size; ++i) {
+ if (Editor::isTextInsertionCommand(selectorToCommandName(NSSelectorFromString(command.commandNames[i]))))
+ haveTextInsertionCommands = true;
+ }
+ if (!haveTextInsertionCommands)
for (size_t i = 0; i < size; ++i)
[self doCommandBySelector:NSSelectorFromString(command.commandNames[i])];
- }
}
_private->interpretKeyEventsParameters = 0;
}
WebView *webView = [self _webView];
Frame* coreFrame = core([self _frame]);
if (![[webView _editingDelegateForwarder] webView:webView doCommandBySelector:selector] && coreFrame) {
- if (selector == @selector(insertNewline:) || selector == @selector(insertParagraphSeparator:) || selector == @selector(insertNewlineIgnoringFieldEditor:))
- eventWasHandled = coreFrame->editor()->execCommand("InsertNewline", event);
- else if (selector == @selector(insertLineBreak:))
- eventWasHandled = coreFrame->editor()->execCommand("InsertLineBreak", event);
- else if (selector == @selector(insertTab:) || selector == @selector(insertTabIgnoringFieldEditor:))
- eventWasHandled = coreFrame->editor()->execCommand("InsertTab", event);
- else if (selector == @selector(insertBacktab:))
- eventWasHandled = coreFrame->editor()->execCommand("InsertBacktab", event);
+ AtomicString commandName = selectorToCommandName(selector);
+ if (Editor::isTextInsertionCommand(commandName))
+ eventWasHandled = coreFrame->editor()->execCommand(commandName, event);
else {
_private->selectorForDoCommandBySelector = selector;
[super doCommandBySelector:selector];
break;
case NSKeyDown: {
PlatformKeyboardEvent pe(nsEvent);
+ pe.disambiguateKeyDownEvent(PlatformKeyboardEvent::RawKeyDown);
event = new KeyboardEvent(keydownEvent, true, true, 0,
- pe.keyIdentifier(), pe.WindowsKeyCode(),
+ pe.keyIdentifier(), pe.windowsVirtualKeyCode(),
pe.ctrlKey(), pe.altKey(), pe.shiftKey(), pe.metaKey(), false);
}
default:
+2007-12-07 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Darin.
+
+ <rdar://problem/5535636>
+ Have to press 4 times instead of 2 times to get the expected result of ^^ with german keyboard.
+
+ http://bugs.webkit.org/show_bug.cgi?id=13916
+ JavaScript detects Tab as a character input on a textfield validation
+
+ * WebCoreSupport/EditorClientQt.cpp:
+ (WebCore::EditorClientQt::handleKeyboardEvent):
+ (WebCore::EditorClientQt::handleInputMethodKeydown):
+ * WebCoreSupport/EditorClientQt.h:
+ Updated for cross-platform changes as much as it was possible without a Qt build environment.
+
2007-12-07 Darin Adler <darin@apple.com>
- try to fix build
notImplemented();
}
-void EditorClientQt::handleKeypress(KeyboardEvent* event)
+void EditorClientQt::handleKeyboardEvent(KeyboardEvent* event)
{
Frame* frame = m_page->d->page->focusController()->focusedOrMainFrame();
if (!frame || !frame->document()->focusedNode())
return;
const PlatformKeyboardEvent* kevent = event->keyEvent();
- if (!kevent || kevent->isKeyUp())
+ if (!kevent || kevent->type() == PlatformKeyboardEvent::KeyUp)
return;
Node* start = frame->selectionController()->start().node();
// FIXME: refactor all of this to use Actions or something like them
if (start->isContentEditable()) {
- switch(kevent->WindowsKeyCode()) {
+ switch (kevent->windowsVirtualKeyCode()) {
case VK_RETURN:
frame->editor()->execCommand("InsertLineBreak");
break;
if (!kevent->ctrlKey() && !kevent->altKey() && !kevent->text().isEmpty()) {
frame->editor()->insertText(kevent->text(), event);
} else if (kevent->ctrlKey()) {
- switch (kevent->WindowsKeyCode()) {
+ switch (kevent->windowsVirtualKeyCode()) {
case VK_A:
frame->editor()->execCommand("SelectAll");
break;
} else return;
}
} else {
- switch (kevent->WindowsKeyCode()) {
+ switch (kevent->windowsVirtualKeyCode()) {
case VK_UP:
frame->editor()->execCommand("MoveUp");
break;
break;
default:
if (kevent->ctrlKey()) {
- switch(kevent->WindowsKeyCode()) {
+ switch(kevent->windowsVirtualKeyCode()) {
case VK_A:
frame->editor()->execCommand("SelectAll");
break;
event->setDefaultHandled();
}
-void EditorClientQt::handleInputMethodKeypress(KeyboardEvent*)
+void EditorClientQt::handleInputMethodKeydown(KeyboardEvent*)
{
}
virtual void undo();
virtual void redo();
- virtual void handleKeypress(KeyboardEvent*);
- virtual void handleInputMethodKeypress(KeyboardEvent*);
+ virtual void handleKeyboardEvent(KeyboardEvent*);
+ virtual void handleInputMethodKeydown(KeyboardEvent*);
virtual void textFieldDidBeginEditing(Element*);
virtual void textFieldDidEndEditing(Element*);
+2007-12-07 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Darin.
+
+ <rdar://problem/5535636>
+ Have to press 4 times instead of 2 times to get the expected result of ^^ with german keyboard.
+
+ http://bugs.webkit.org/show_bug.cgi?id=13916
+ JavaScript detects Tab as a character input on a textfield validation
+
+ Listen to WM_CHAR messages, and actually pass the type of message received down to WebCore.
+ Since WM_KEYDOWN == keydown and WM_CHAR == keypress, this allows for much better IE compatibility
+ than layering Windows keyboard event handling on top of Mac one.
+
+ * WebView.cpp:
+ (WebView::keyUp): Do not special case Alt+F4 and Alt+Space - we don't get keyups for those anyway!
+ (WebView::interpretKeyEvent): Renamed WindowsKeyCode() to windowsVirtualKeyCode().
+ (WebView::handleEditingKeyboardEvent): Use the additional information about event type that
+ we now pass with PlatformKeyboardEvent.
+ (WebView::keyDown): (WebView::keyPress): Split WM_KEYDOWN and WM_CHAR handling in separate
+ functions, pass them down as is, without trying to guess what WM_CHAR Windows would have sent
+ for a given WM_KEYDOWN.
+
+ (WebViewWndProc): Handle WM_CHAR and WM_SYSCHAR.
+
+ * WebView.h: Removed inIMEKeyDown() - it doesn't look like we need it at all. At least, I didn't
+ notice any regressions after removing the only call to it in WebEditorClient.
+
+ * WebEditorClient.cpp:
+ (WebEditorClient::handleKeyboardEvent):
+ (WebEditorClient::handleInputMethodKeydown):
+ * WebEditorClient.h:
+ Renamed handleKeypress() to handleKeyboardEvent(), as it gets both keydowns and keypresses.
+ Renamed handleInputMethodKeypress() to handleInputMethodKeydown() and removed
+ inIMEKeyDown()-related code.
+
2007-12-10 Geoffrey Garen <ggaren@apple.com>
Reviewed by Sam Weinig.
}
}
-void WebEditorClient::handleKeypress(KeyboardEvent* evt)
+void WebEditorClient::handleKeyboardEvent(KeyboardEvent* evt)
{
if (m_webView->handleEditingKeyboardEvent(evt))
evt->setDefaultHandled();
}
-void WebEditorClient::handleInputMethodKeypress(KeyboardEvent* evt)
+void WebEditorClient::handleInputMethodKeydown(KeyboardEvent* )
{
- if (m_webView->inIMEKeyDown())
- evt->setDefaultHandled();
}
bool WebEditorClient::isEditable()
virtual void textWillBeDeletedInTextField(WebCore::Element* input);
virtual void textDidChangeInTextArea(WebCore::Element*);
- void handleKeypress(WebCore::KeyboardEvent*);
- void handleInputMethodKeypress(WebCore::KeyboardEvent*);
+ void handleKeyboardEvent(WebCore::KeyboardEvent*);
+ void handleInputMethodKeydown(WebCore::KeyboardEvent*);
virtual void ignoreWordInSpellDocument(const WebCore::String&);
virtual void learnWord(const WebCore::String&);
bool WebView::keyUp(WPARAM virtualKeyCode, LPARAM keyData, bool systemKeyDown)
{
- PlatformKeyboardEvent keyEvent(m_viewWindow, virtualKeyCode, keyData, m_currentCharacterCode, systemKeyDown);
-
- // Don't send key events for alt+space and alt+f4.
- if (keyEvent.altKey() && (virtualKeyCode == VK_SPACE || virtualKeyCode == VK_F4))
- return false;
+ PlatformKeyboardEvent keyEvent(m_viewWindow, virtualKeyCode, keyData, PlatformKeyboardEvent::KeyUp, systemKeyDown);
Frame* frame = m_page->focusController()->focusedOrMainFrame();
m_currentCharacterCode = 0;
static const unsigned ShiftKey = 1 << 2;
-struct KeyEntry {
+struct KeyDownEntry {
unsigned virtualKey;
unsigned modifiers;
const char* name;
};
-static const KeyEntry keyEntries[] = {
+struct KeyPressEntry {
+ unsigned charCode;
+ unsigned modifiers;
+ const char* name;
+};
+
+static const KeyDownEntry keyDownEntries[] = {
{ VK_LEFT, 0, "MoveLeft" },
{ VK_LEFT, ShiftKey, "MoveLeftAndModifySelection" },
{ VK_LEFT, CtrlKey, "MoveWordLeft" },
{ 'Z', CtrlKey | ShiftKey, "Redo" },
};
+static const KeyPressEntry keyPressEntries[] = {
+ { '\t', 0, "InsertTab" },
+ { '\t', ShiftKey, "InsertBacktab" },
+ { '\r', 0, "InsertNewline" },
+ { '\r', CtrlKey, "InsertNewline" },
+ { '\r', AltKey, "InsertNewline" },
+ { '\r', AltKey | ShiftKey, "InsertNewline" },
+};
+
const char* WebView::interpretKeyEvent(const KeyboardEvent* evt)
{
- const PlatformKeyboardEvent* keyEvent = evt->keyEvent();
- if (!keyEvent)
- return "";
+ ASSERT(evt->type() == keydownEvent || evt->type() == keypressEvent);
+
+ static HashMap<int, const char*>* keyDownCommandsMap = 0;
+ static HashMap<int, const char*>* keyPressCommandsMap = 0;
- static HashMap<int, const char*>* commandsMap = 0;
+ if (!keyDownCommandsMap) {
+ keyDownCommandsMap = new HashMap<int, const char*>;
+ keyPressCommandsMap = new HashMap<int, const char*>;
- if (!commandsMap) {
- commandsMap = new HashMap<int, const char*>;
+ for (unsigned i = 0; i < _countof(keyDownEntries); i++)
+ keyDownCommandsMap->set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, keyDownEntries[i].name);
- for (unsigned i = 0; i < _countof(keyEntries); i++)
- commandsMap->set(keyEntries[i].modifiers << 16 | keyEntries[i].virtualKey, keyEntries[i].name);
+ for (unsigned i = 0; i < _countof(keyPressEntries); i++)
+ keyPressCommandsMap->set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].virtualKey, keyPressEntries[i].name);
}
unsigned modifiers = 0;
- if (keyEvent->shiftKey())
+ if (evt->shiftKey())
modifiers |= ShiftKey;
- if (keyEvent->altKey())
+ if (evt->altKey())
modifiers |= AltKey;
- if (keyEvent->ctrlKey())
+ if (evt->ctrlKey())
modifiers |= CtrlKey;
- return commandsMap->get(modifiers << 16 | keyEvent->WindowsKeyCode());
+ return evt->type() == keydownEvent ?
+ keyDownCommandsMap->get(modifiers << 16 | evt->keyCode()) :
+ keyPressCommandsMap->get(modifiers << 16 | evt->charCode());
}
bool WebView::handleEditingKeyboardEvent(KeyboardEvent* evt)
{
- String command(interpretKeyEvent(evt));
-
Node* node = evt->target()->toNode();
ASSERT(node);
Frame* frame = node->document()->frame();
ASSERT(frame);
- if (!command.isEmpty())
+ const PlatformKeyboardEvent* keyEvent = evt->keyEvent();
+ if (!keyEvent || keyEvent->isSystemKey()) // do not treat this as text input if it's a system key event
+ return false;
+
+ if (keyEvent->type() == PlatformKeyboardEvent::RawKeyDown) {
+ String command = interpretKeyEvent(evt);
+
+ // WebKit doesn't have enough information about mode to decide how commands that just insert text if executed via Editor should be treated,
+ // so we leave it upon WebCore to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated
+ // (e.g. Tab that inserts a Tab character, or Enter).
+ if (!command.isEmpty() && !Editor::isTextInsertionCommand(command))
+ if (frame->editor()->execCommand(command, evt))
+ return true;
+ return false;
+ }
+
+ String command = interpretKeyEvent(evt);
+ if (!command.isEmpty())
if (frame->editor()->execCommand(command, evt))
return true;
- if (!evt->keyEvent() || evt->keyEvent()->isSystemKey()) // do not treat this as text input if it's a system key event
+ // Don't insert null or control characters as they can result in unexpected behaviour
+ if (evt->charCode() < ' ')
return false;
- if (evt->keyEvent()->text().length() == 1) {
- UChar ch = evt->keyEvent()->text()[0];
- // Don't insert null or control characters as they can reslt in unexpected behaviour
- if (ch < ' ')
- return false;
- }
-
return frame->editor()->insertText(evt->keyEvent()->text(), evt);
}
if (virtualKeyCode == VK_CAPITAL)
frame->eventHandler()->capsLockStateMayHaveChanged();
- // Don't send key events for alt+space and alt+f4, since the OS needs to handle that.
- if (systemKeyDown && (virtualKeyCode == VK_SPACE || virtualKeyCode == VK_F4))
- return false;
-
- MSG msg;
- // If the next message is a WM_CHAR message, then take it out of the queue, and use
- // the message parameters to get the character code to construct the PlatformKeyboardEvent.
- if (systemKeyDown) {
- if (::PeekMessage(&msg, m_viewWindow, WM_SYSCHAR, WM_SYSCHAR, PM_NOREMOVE)) // don't remove sys key message from the windows message queue until we know we can handle it
- m_currentCharacterCode = (UChar)msg.wParam;
- } else if (::PeekMessage(&msg, m_viewWindow, WM_CHAR, WM_CHAR, PM_REMOVE))
- m_currentCharacterCode = (UChar)msg.wParam;
-
- // FIXME: We need to check WM_UNICHAR to support supplementary characters.
- // FIXME: We may need to handle other messages for international text.
-
- m_inIMEKeyDown = virtualKeyCode == VK_PROCESSKEY;
- if (virtualKeyCode == VK_PROCESSKEY && !m_inIMEComposition)
- virtualKeyCode = MapVirtualKey(LOBYTE(HIWORD(keyData)), 1);
-
- PlatformKeyboardEvent keyEvent(m_viewWindow, virtualKeyCode, keyData, m_currentCharacterCode, systemKeyDown);
+ PlatformKeyboardEvent keyEvent(m_viewWindow, virtualKeyCode, keyData, PlatformKeyboardEvent::RawKeyDown, systemKeyDown);
bool handled = frame->eventHandler()->keyEvent(keyEvent);
- m_inIMEKeyDown = false;
- if (handled)
- goto exit;
+
+ // These events cannot be canceled.
+ // FIXME: match IE list more closely, see <http://msdn2.microsoft.com/en-us/library/ms536938.aspx>.
+ if (systemKeyDown)
+ handled = false;
+
+ if (handled) {
+ // FIXME: remove WM_UNICHAR, too
+ MSG msg;
+ // WM_SYSCHAR events should not be removed, because access keys are implemented in WebCore in WM_SYSCHAR handler.
+ if (!systemKeyDown)
+ ::PeekMessage(&msg, m_viewWindow, WM_CHAR, WM_CHAR, PM_REMOVE);
+ return true;
+ }
// We need to handle back/forward using either Backspace(+Shift) or Ctrl+Left/Right Arrow keys.
- int windowsKeyCode = keyEvent.WindowsKeyCode();
- if ((windowsKeyCode == VK_BACK && keyEvent.shiftKey()) || (windowsKeyCode == VK_RIGHT && keyEvent.ctrlKey()))
+ if ((virtualKeyCode == VK_BACK && keyEvent.shiftKey()) || (virtualKeyCode == VK_RIGHT && keyEvent.ctrlKey()))
m_page->goForward();
- else if (windowsKeyCode == VK_BACK || (windowsKeyCode == VK_LEFT && keyEvent.ctrlKey()))
+ else if (virtualKeyCode == VK_BACK || (virtualKeyCode == VK_LEFT && keyEvent.ctrlKey()))
m_page->goBack();
// Need to scroll the page if the arrow keys, space(shift), pgup/dn, or home/end are hit.
ScrollDirection direction;
ScrollGranularity granularity;
- switch (windowsKeyCode) {
+ switch (virtualKeyCode) {
case VK_LEFT:
granularity = ScrollByLine;
direction = ScrollLeft;
default:
// We want to let Windows handle the WM_SYSCHAR event if we can't handle it
// We do want to return true for regular key down case so the WM_CHAR handler won't pick up unhandled messages
- return !systemKeyDown;
+ return false;
}
if (!frame->eventHandler()->scrollOverflow(direction, granularity))
frame->view()->scroll(direction, granularity);
+ return true;
+}
-exit:
- if (systemKeyDown) // remove sys key message if we have handled it
- ::PeekMessage(&msg, m_viewWindow, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE);
+bool WebView::keyPress(WPARAM charCode, LPARAM keyData, bool systemKeyDown)
+{
+ Frame* frame = m_page->focusController()->focusedOrMainFrame();
- return true;
+ PlatformKeyboardEvent keyEvent(m_viewWindow, charCode, keyData, PlatformKeyboardEvent::Char, systemKeyDown);
+ return frame->eventHandler()->keyEvent(keyEvent);
}
bool WebView::inResizer(LPARAM lParam)
case WM_KEYUP:
handled = webView->keyUp(wParam, lParam);
break;
+ case WM_SYSCHAR:
+ handled = webView->keyPress(wParam, lParam, true);
+ break;
+ case WM_CHAR:
+ handled = webView->keyPress(wParam, lParam);
+ break;
+ // FIXME: We need to check WM_UNICHAR to support supplementary characters (that don't fit in 16 bits).
case WM_SIZE:
if (webView->isBeingDestroyed())
// If someone has sent us this message while we're being destroyed, we should bail out so we don't crash.
bool execCommand(WPARAM wParam, LPARAM lParam);
bool keyDown(WPARAM, LPARAM, bool systemKeyDown = false);
bool keyUp(WPARAM, LPARAM, bool systemKeyDown = false);
+ bool keyPress(WPARAM, LPARAM, bool systemKeyDown = false);
bool inResizer(LPARAM lParam);
void paint(HDC, LPARAM);
void paintIntoBackingStore(WebCore::FrameView*, HDC bitmapDC, const WebCore::IntRect& dirtyRect);
bool onIMESetContext(WPARAM, LPARAM);
void selectionChanged();
void resetIME(WebCore::Frame*);
- bool inIMEKeyDown() const { return m_inIMEKeyDown; }
void setInputMethodState(bool);
HRESULT registerDragDrop();
bool m_didClose;
bool m_hasCustomDropTarget;
unsigned m_inIMEComposition;
- bool m_inIMEKeyDown;
HWND m_toolTipHwnd;
WebCore::String m_toolTip;
+2007-12-07 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Darin.
+
+ <rdar://problem/5535636>
+ Have to press 4 times instead of 2 times to get the expected result of ^^ with german keyboard.
+
+ http://bugs.webkit.org/show_bug.cgi?id=13916
+ JavaScript detects Tab as a character input on a textfield validation
+
+ * WebKitSupport/EditorClientWx.cpp:
+ (WebCore::EditorClientWx::handleInputMethodKeydown):
+ (WebCore::EditorClientWx::handleKeyboardEvent):
+ * WebKitSupport/EditorClientWx.h:
+ Updated for cross-platform changes as much as it was possible without a wx build environment.
+ The keyboard event model of wx is similar to Windows one, so further fixes can be modeled
+ after the Windows port.
+
2007-12-06 Kevin Ollivier <kevino@theolliviers.com>
Fix page leak caused because the Frame's page pointer is 0 by the
notImplemented();
}
-void EditorClientWx::handleInputMethodKeypress(KeyboardEvent* event)
+void EditorClientWx::handleInputMethodKeydown(KeyboardEvent* event)
{
// NOTE: we don't currently need to handle this. When key events occur,
-// both this method and handleKeypress get a chance at handling them.
+// both this method and handleKeyboardEvent get a chance at handling them.
// We might use this method later on for IME-specific handling.
}
-void EditorClientWx::handleKeypress(KeyboardEvent* event)
+void EditorClientWx::handleKeyboardEvent(KeyboardEvent* event)
{
Frame* frame = m_page->focusController()->focusedOrMainFrame();
if (!frame)
return;
const PlatformKeyboardEvent* kevent = event->keyEvent();
- if (!kevent->isKeyUp()) {
+ if (!kevent->type() == PlatformKeyboardEvent::KeyUp) {
Node* start = frame->selectionController()->start().node();
if (!start || !start->isContentEditable())
return;
- if (kevent->isWxCharEvent() && !kevent->ctrlKey() && !kevent->altKey()) {
- switch(kevent->WindowsKeyCode()) {
+ if (kevent->type() == PlatformKeyboardEvent::Char && !kevent->ctrlKey() && !kevent->altKey()) {
+ switch (kevent->windowsVirtualKeyCode()) {
// we handled these on key down, ignore them for char events
case VK_BACK:
case VK_DELETE:
return;
}
- switch(kevent->WindowsKeyCode()) {
+ switch (kevent->windowsVirtualKeyCode()) {
case VK_BACK:
frame->editor()->deleteWithDirection(SelectionController::BACKWARD,
CharacterGranularity, false, true);
virtual void undo();
virtual void redo();
- virtual void handleKeypress(KeyboardEvent*);
- virtual void handleInputMethodKeypress(KeyboardEvent*);
+ virtual void handleKeyboardEvent(KeyboardEvent*);
+ virtual void handleInputMethodKeydown(KeyboardEvent*);
virtual void textFieldDidBeginEditing(Element*);
virtual void textFieldDidEndEditing(Element*);
+2007-12-07 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Darin.
+
+ <rdar://problem/5535636>
+ Have to press 4 times instead of 2 times to get the expected result of ^^ with german keyboard.
+
+ http://bugs.webkit.org/show_bug.cgi?id=13916
+ JavaScript detects Tab as a character input on a textfield validation
+
+ * DumpRenderTree/mac/EventSendingController.mm:
+ (-[EventSendingController keyDown:withModifiers:]): Added a few more named keys.
+ Dispatch a keyup to better match what happens when a key is physically pressed.
+
+ * DumpRenderTree/win/EventSender.cpp:
+ (keyDownCallback): Ditto. Also make sure that WM_CHAR is consistently dispatched before
+ returning from keyDown().
+ (getConstantCallback): Fixed a couple copy/paste mistakes.
+
2007-12-07 Kevin McCullough <kmccullough@apple.com>
Reviewed by Oliver.
- (void)keyDown:(NSString *)character withModifiers:(WebScriptObject *)modifiers
{
NSString *eventCharacter = character;
- if ([character isEqualToString:@"rightArrow"]) {
- const unichar rightArrowCharacter = NSRightArrowFunctionKey;
- eventCharacter = [NSString stringWithCharacters:&rightArrowCharacter length:1];
+ if ([character isEqualToString:@"leftArrow"]) {
+ const unichar ch = NSLeftArrowFunctionKey;
+ eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ } else if ([character isEqualToString:@"rightArrow"]) {
+ const unichar ch = NSRightArrowFunctionKey;
+ eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ } else if ([character isEqualToString:@"upArrow"]) {
+ const unichar ch = NSUpArrowFunctionKey;
+ eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ } else if ([character isEqualToString:@"downArrow"]) {
+ const unichar ch = NSDownArrowFunctionKey;
+ eventCharacter = [NSString stringWithCharacters:&ch length:1];
+ } else if ([character isEqualToString:@"delete"]) {
+ const unichar ch = 0x7f;
+ eventCharacter = [NSString stringWithCharacters:&ch length:1];
}
NSString *charactersIgnoringModifiers = eventCharacter;
keyCode:0];
[[[[mainFrame webView] window] firstResponder] keyDown:event];
+
+ event = [NSEvent keyEventWithType:NSKeyUp
+ location:NSMakePoint(5, 5)
+ modifierFlags:modifierFlags
+ timestamp:[self currentEventTime]
+ windowNumber:[[[mainFrame webView] window] windowNumber]
+ context:[NSGraphicsContext currentContext]
+ characters:eventCharacter
+ charactersIgnoringModifiers:charactersIgnoringModifiers
+ isARepeat:NO
+ keyCode:0];
+
+ [[[[mainFrame webView] window] firstResponder] keyUp:event];
}
- (void)enableDOMUIEventLogging:(WebScriptObject *)node
if (JSStringIsEqualToUTF8CString(propertyName, "WM_KEYUP"))
return JSValueMakeNumber(context, WM_KEYUP);
if (JSStringIsEqualToUTF8CString(propertyName, "WM_CHAR"))
- return JSValueMakeNumber(context, WM_KEYDOWN);
- if (JSStringIsEqualToUTF8CString(propertyName, "WM_DEADCHAR"))
return JSValueMakeNumber(context, WM_CHAR);
+ if (JSStringIsEqualToUTF8CString(propertyName, "WM_DEADCHAR"))
+ return JSValueMakeNumber(context, WM_DEADCHAR);
if (JSStringIsEqualToUTF8CString(propertyName, "WM_SYSKEYDOWN"))
return JSValueMakeNumber(context, WM_SYSKEYDOWN);
if (JSStringIsEqualToUTF8CString(propertyName, "WM_SYSKEYUP"))
int virtualKeyCode;
int charCode = 0;
bool needsShiftKeyModifier = false;
- if (JSStringIsEqualToUTF8CString(character, "rightArrow")) {
+ if (JSStringIsEqualToUTF8CString(character, "leftArrow"))
+ virtualKeyCode = VK_LEFT;
+ else if (JSStringIsEqualToUTF8CString(character, "rightArrow"))
virtualKeyCode = VK_RIGHT;
- } else {
+ else if (JSStringIsEqualToUTF8CString(character, "upArrow"))
+ virtualKeyCode = VK_UP;
+ else if (JSStringIsEqualToUTF8CString(character, "downArrow"))
+ virtualKeyCode = VK_DOWN;
+ else if (JSStringIsEqualToUTF8CString(character, "delete"))
+ virtualKeyCode = VK_BACK;
+ else {
charCode = JSStringGetCharactersPtr(character)[0];
virtualKeyCode = LOBYTE(VkKeyScan(charCode));
if (isupper(charCode))
// For characters that do not exist in the active keyboard layout,
// ::Translate will not work, so we post an WM_CHAR event ourselves.
::PostMessage(webViewWindow, WM_CHAR, charCode, 0);
- ::DispatchMessage(&msg);
}
+ // Tests expect that all messages are processed by the time keyDown() returns.
+ if (::PeekMessage(&msg, webViewWindow, WM_CHAR, WM_CHAR, PM_REMOVE))
+ ::DispatchMessage(&msg);
+
+ MSG msgUp = makeMsg(webViewWindow, WM_KEYUP, virtualKeyCode, 0);
+ ::DispatchMessage(&msgUp);
+
if (argumentCount > 1 || needsShiftKeyModifier)
::SetKeyboardState(keyState);
} else
msg.pt = lastMousePosition;
- dispatchMessage(&msg);
+ ::DispatchMessage(&msg);
return JSValueMakeUndefined(context);
}