diff --git a/atom/common/keyboard_util.cc b/atom/common/keyboard_util.cc index c8e9628f3bcc..541cacbcf8c1 100644 --- a/atom/common/keyboard_util.cc +++ b/atom/common/keyboard_util.cc @@ -7,6 +7,8 @@ #include "atom/common/keyboard_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" +#include "third_party/WebKit/public/web/WebInputEvent.h" +#include "ui/events/event_constants.h" namespace atom { @@ -174,4 +176,33 @@ ui::KeyboardCode KeyboardCodeFromStr(const std::string& str, bool* shifted) { return KeyboardCodeFromKeyIdentifier(str, shifted); } +int WebEventModifiersToEventFlags(int modifiers) { + int flags = 0; + + if (modifiers & blink::WebInputEvent::ShiftKey) + flags |= ui::EF_SHIFT_DOWN; + if (modifiers & blink::WebInputEvent::ControlKey) + flags |= ui::EF_CONTROL_DOWN; + if (modifiers & blink::WebInputEvent::AltKey) + flags |= ui::EF_ALT_DOWN; + if (modifiers & blink::WebInputEvent::MetaKey) + flags |= ui::EF_COMMAND_DOWN; + if (modifiers & blink::WebInputEvent::CapsLockOn) + flags |= ui::EF_CAPS_LOCK_ON; + if (modifiers & blink::WebInputEvent::NumLockOn) + flags |= ui::EF_NUM_LOCK_ON; + if (modifiers & blink::WebInputEvent::ScrollLockOn) + flags |= ui::EF_SCROLL_LOCK_ON; + if (modifiers & blink::WebInputEvent::LeftButtonDown) + flags |= ui::EF_LEFT_MOUSE_BUTTON; + if (modifiers & blink::WebInputEvent::MiddleButtonDown) + flags |= ui::EF_MIDDLE_MOUSE_BUTTON; + if (modifiers & blink::WebInputEvent::RightButtonDown) + flags |= ui::EF_RIGHT_MOUSE_BUTTON; + if (modifiers & blink::WebInputEvent::IsAutoRepeat) + flags |= ui::EF_IS_REPEAT; + + return flags; +} + } // namespace atom diff --git a/atom/common/keyboard_util.h b/atom/common/keyboard_util.h index c9d1b809e8f7..651cf6a92024 100644 --- a/atom/common/keyboard_util.h +++ b/atom/common/keyboard_util.h @@ -15,6 +15,9 @@ namespace atom { // pressed. ui::KeyboardCode KeyboardCodeFromStr(const std::string& str, bool* shifted); +// Ported from ui/events/blink/blink_event_util.h +int WebEventModifiersToEventFlags(int modifiers); + } // namespace atom #endif // ATOM_COMMON_KEYBOARD_UTIL_H_ diff --git a/atom/common/native_mate_converters/blink_converter.cc b/atom/common/native_mate_converters/blink_converter.cc index 9adb03d4cde3..07971e78dd43 100644 --- a/atom/common/native_mate_converters/blink_converter.cc +++ b/atom/common/native_mate_converters/blink_converter.cc @@ -18,6 +18,7 @@ #include "third_party/WebKit/public/web/WebFindOptions.h" #include "third_party/WebKit/public/web/WebInputEvent.h" #include "ui/base/clipboard/clipboard.h" +#include "ui/events/keycodes/keyboard_code_conversion.h" namespace { @@ -166,15 +167,25 @@ bool Converter::FromV8( return false; std::string str; - bool shifted = false; - if (dict.Get("keyCode", &str)) - out->windowsKeyCode = atom::KeyboardCodeFromStr(str, &shifted); - else + if (!dict.Get("keyCode", &str)) return false; + bool shifted = false; + ui::KeyboardCode keyCode = atom::KeyboardCodeFromStr(str, &shifted); + out->windowsKeyCode = keyCode; if (shifted) out->modifiers |= blink::WebInputEvent::ShiftKey; out->setKeyIdentifierFromWindowsKeyCode(); + + ui::DomCode domCode = ui::UsLayoutKeyboardCodeToDomCode(keyCode); + out->domCode = static_cast(domCode); + + ui::DomKey domKey; + ui::KeyboardCode dummy_code; + int flags = atom::WebEventModifiersToEventFlags(out->modifiers); + if (ui::DomCodeToUsLayoutDomKey(domCode, flags, &domKey, &dummy_code)) + out->domKey = static_cast(domKey); + if ((out->type == blink::WebInputEvent::Char || out->type == blink::WebInputEvent::RawKeyDown)) { // Make sure to not read beyond the buffer in case some bad code doesn't diff --git a/spec/api-web-contents-spec.js b/spec/api-web-contents-spec.js index 7e77c39bdb55..d7a2ae50f3cf 100644 --- a/spec/api-web-contents-spec.js +++ b/spec/api-web-contents-spec.js @@ -5,7 +5,7 @@ const path = require('path') const {closeWindow} = require('./window-helpers') const {remote} = require('electron') -const {BrowserWindow, webContents} = remote +const {BrowserWindow, webContents, ipcMain} = remote const isCi = remote.getGlobal('isCi') @@ -97,4 +97,80 @@ describe('webContents module', function () { }) }) }) + + describe('sendInputEvent(event)', function () { + beforeEach(function (done) { + w.loadURL('file://' + path.join(__dirname, 'fixtures', 'pages', 'key-events.html')) + w.webContents.once('did-finish-load', function () { + done() + }) + }) + + it('can send keydown events', function (done) { + ipcMain.once('keydown', function (event, key, code, keyCode, shiftKey, ctrlKey, altKey) { + assert.equal(key, 'a') + assert.equal(code, 'KeyA') + assert.equal(keyCode, 65) + assert.equal(shiftKey, false) + assert.equal(ctrlKey, false) + assert.equal(altKey, false) + done() + }) + w.webContents.sendInputEvent({type: 'keyDown', keyCode: 'A'}) + }) + + it('can send keydown events with modifiers', function (done) { + ipcMain.once('keydown', function (event, key, code, keyCode, shiftKey, ctrlKey, altKey) { + assert.equal(key, 'Z') + assert.equal(code, 'KeyZ') + assert.equal(keyCode, 90) + assert.equal(shiftKey, true) + assert.equal(ctrlKey, true) + assert.equal(altKey, false) + done() + }) + w.webContents.sendInputEvent({type: 'keyDown', keyCode: 'Z', modifiers: ['shift', 'ctrl']}) + }) + + it('can send keydown events with special keys', function (done) { + ipcMain.once('keydown', function (event, key, code, keyCode, shiftKey, ctrlKey, altKey) { + assert.equal(key, 'Tab') + assert.equal(code, 'Tab') + assert.equal(keyCode, 9) + assert.equal(shiftKey, false) + assert.equal(ctrlKey, false) + assert.equal(altKey, true) + done() + }) + w.webContents.sendInputEvent({type: 'keyDown', keyCode: 'Tab', modifiers: ['alt']}) + }) + + it('can send char events', function (done) { + ipcMain.once('keypress', function (event, key, code, keyCode, shiftKey, ctrlKey, altKey) { + assert.equal(key, 'a') + assert.equal(code, 'KeyA') + assert.equal(keyCode, 65) + assert.equal(shiftKey, false) + assert.equal(ctrlKey, false) + assert.equal(altKey, false) + done() + }) + w.webContents.sendInputEvent({type: 'keyDown', keyCode: 'A'}) + w.webContents.sendInputEvent({type: 'char', keyCode: 'A'}) + }) + + it('can send char events with modifiers', function (done) { + ipcMain.once('keypress', function (event, key, code, keyCode, shiftKey, ctrlKey, altKey) { + assert.equal(key, 'Z') + assert.equal(code, 'KeyZ') + assert.equal(keyCode, 90) + assert.equal(shiftKey, true) + assert.equal(ctrlKey, true) + assert.equal(altKey, false) + done() + }) + w.webContents.sendInputEvent({type: 'keyDown', keyCode: 'Z'}) + w.webContents.sendInputEvent({type: 'char', keyCode: 'Z', modifiers: ['shift', 'ctrl']}) + }) + }) }) diff --git a/spec/fixtures/pages/key-events.html b/spec/fixtures/pages/key-events.html new file mode 100644 index 000000000000..7402daf5e999 --- /dev/null +++ b/spec/fixtures/pages/key-events.html @@ -0,0 +1,12 @@ + + + + + diff --git a/spec/fixtures/pages/onkeyup.html b/spec/fixtures/pages/onkeyup.html index 4e75dbb1e4ac..0ff0f3d449cf 100644 --- a/spec/fixtures/pages/onkeyup.html +++ b/spec/fixtures/pages/onkeyup.html @@ -2,7 +2,7 @@ diff --git a/spec/webview-spec.js b/spec/webview-spec.js index 1eb14442adaa..1c49688adeb8 100644 --- a/spec/webview-spec.js +++ b/spec/webview-spec.js @@ -776,7 +776,7 @@ describe(' tag', function () { it('can send keyboard event', function (done) { webview.addEventListener('ipc-message', function (e) { assert.equal(e.channel, 'keyup') - assert.deepEqual(e.args, [67, true, false]) + assert.deepEqual(e.args, ['C', 'KeyC', 67, true, false]) done() }) webview.addEventListener('dom-ready', function () {