diff options
author | kevers@chromium.org <kevers@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-05 13:04:09 +0000 |
---|---|---|
committer | kevers@chromium.org <kevers@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-05 13:04:09 +0000 |
commit | ce5916aa7b8323c651af377941093c774077cce8 (patch) | |
tree | 55efddc4cb1e0bd705ae369d777861983a61dbb1 /ui/keyboard | |
parent | 6c2beac20246525310f2e85f5f0c33fcdbd2dff8 (diff) | |
download | chromium_src-ce5916aa7b8323c651af377941093c774077cce8.zip chromium_src-ce5916aa7b8323c651af377941093c774077cce8.tar.gz chromium_src-ce5916aa7b8323c651af377941093c774077cce8.tar.bz2 |
Switch from text insertion to key press and release events on the virtual keyboard. First step in integration the virtual keyboard with IMEs.
BUG=257093, 257098
Review URL: https://chromiumcodereview.appspot.com/20145004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@221393 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/keyboard')
-rw-r--r-- | ui/keyboard/keyboard_ui_handler.cc | 38 | ||||
-rw-r--r-- | ui/keyboard/keyboard_ui_handler.h | 5 | ||||
-rw-r--r-- | ui/keyboard/keyboard_util.cc | 64 | ||||
-rw-r--r-- | ui/keyboard/keyboard_util.h | 15 | ||||
-rw-r--r-- | ui/keyboard/resources/api_adapter.js | 6 | ||||
-rw-r--r-- | ui/keyboard/resources/elements/kb-key-base.html | 19 | ||||
-rw-r--r-- | ui/keyboard/resources/elements/kb-key-codes.html | 46 | ||||
-rw-r--r-- | ui/keyboard/resources/elements/kb-key.html | 13 | ||||
-rw-r--r-- | ui/keyboard/resources/elements/kb-keyboard.html | 22 | ||||
-rw-r--r-- | ui/keyboard/resources/webui/api_adapter.js | 4 |
10 files changed, 175 insertions, 57 deletions
diff --git a/ui/keyboard/keyboard_ui_handler.cc b/ui/keyboard/keyboard_ui_handler.cc index 398d2f4..9d3920f 100644 --- a/ui/keyboard/keyboard_ui_handler.cc +++ b/ui/keyboard/keyboard_ui_handler.cc @@ -36,6 +36,11 @@ void KeyboardUIHandler::RegisterMessages() { "getInputContext", base::Bind(&KeyboardUIHandler::HandleGetInputContextMessage, base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "sendKeyEvent", + base::Bind(&KeyboardUIHandler::HandleSendKeyEventMessage, + base::Unretained(this))); + } void KeyboardUIHandler::HandleInsertTextMessage(const base::ListValue* args) { @@ -87,4 +92,37 @@ void KeyboardUIHandler::HandleGetInputContextMessage( results); } +void KeyboardUIHandler::HandleSendKeyEventMessage( + const base::ListValue* args) { + const base::DictionaryValue* params = NULL; + std::string type; + int char_value; + int key_code; + bool shift_modifier; + + if (!args->GetDictionary(0, ¶ms) || + !params->GetString("type", &type) || + !params->GetInteger("charValue", &char_value) || + !params->GetInteger("keyCode", &key_code) || + !params->GetBoolean("shiftKey", &shift_modifier)) { + LOG(ERROR) << "SendKeyEvent failed: bad argument"; + return; + } + + aura::RootWindow* root_window = + web_ui()->GetWebContents()->GetView()->GetNativeView()->GetRootWindow(); + if (!root_window) { + LOG(ERROR) << "sendKeyEvent failed: no root window"; + return; + } + + if (!keyboard::SendKeyEvent(type, + char_value, + key_code, + shift_modifier, + root_window)) { + LOG(ERROR) << "sendKeyEvent failed"; + } +} + } // namespace keyboard diff --git a/ui/keyboard/keyboard_ui_handler.h b/ui/keyboard/keyboard_ui_handler.h index 5ff05a0..719852f 100644 --- a/ui/keyboard/keyboard_ui_handler.h +++ b/ui/keyboard/keyboard_ui_handler.h @@ -29,6 +29,11 @@ class KeyboardUIHandler : public content::WebUIMessageHandler { // |args| should be an integer representing request ID. void HandleGetInputContextMessage(const base::ListValue* args); + // Callback for the "sendKeyEvent" message. The first element in |args| is a + // dictionary containing an event type, the character being pressed or + // released, a virtual key code, and the state of the shift key. + void HandleSendKeyEventMessage(const base::ListValue* args); + DISALLOW_COPY_AND_ASSIGN(KeyboardUIHandler); }; diff --git a/ui/keyboard/keyboard_util.cc b/ui/keyboard/keyboard_util.cc index 8f827a8..b5afa09 100644 --- a/ui/keyboard/keyboard_util.cc +++ b/ui/keyboard/keyboard_util.cc @@ -17,6 +17,13 @@ #include "ui/base/ime/text_input_client.h" #include "ui/keyboard/keyboard_switches.h" +namespace { + +const char kKeyDown[] ="keydown"; +const char kKeyUp[] = "keyup"; + +} // namespace + namespace keyboard { bool IsKeyboardEnabled() { @@ -28,28 +35,6 @@ bool InsertText(const base::string16& text, aura::RootWindow* root_window) { if (!root_window) return false; - // Handle Backspace and Enter specially: using TextInputClient::InsertText is - // very unreliable for these characters. - // TODO(bryeung): remove this code once virtual keyboards are able to send - // these events directly via the Input Injection API. - if (text.length() == 1) { - ui::KeyboardCode code = ui::VKEY_UNKNOWN; - if (text[0] == L'\n') - code = ui::VKEY_RETURN; - else if (text[0] == L'\b') - code = ui::VKEY_BACK; - - if (code != ui::VKEY_UNKNOWN) { - ui::KeyEvent press_event(ui::ET_KEY_PRESSED, code, 0, 0); - root_window->AsRootWindowHostDelegate()->OnHostKeyEvent(&press_event); - - ui::KeyEvent release_event(ui::ET_KEY_RELEASED, code, 0, 0); - root_window->AsRootWindowHostDelegate()->OnHostKeyEvent(&release_event); - - return true; - } - } - ui::InputMethod* input_method = root_window->GetProperty( aura::client::kRootWindowInputMethodKey); if (!input_method) @@ -103,6 +88,41 @@ bool MoveCursor(int swipe_direction, return true; } +bool SendKeyEvent(const std::string type, + int key_value, + int key_code, + bool shift_modifier, + aura::RootWindow* root_window) { + ui::EventType event_type = ui::ET_UNKNOWN; + if (type == kKeyDown) + event_type = ui::ET_KEY_PRESSED; + else if (type == kKeyUp) + event_type = ui::ET_KEY_RELEASED; + if (event_type == ui::ET_UNKNOWN) + return false; + + int flags = ui::EF_NONE; + if (shift_modifier) + flags = ui::EF_SHIFT_DOWN; + + ui::KeyboardCode code = static_cast<ui::KeyboardCode>(key_code); + + ui::KeyEvent event(event_type, code, flags, false); + event.set_character(key_value); + event.set_unmodified_character(key_value); + + if (code != ui::VKEY_UNKNOWN) { + root_window->AsRootWindowHostDelegate()->OnHostKeyEvent(&event); + } else if (event_type == ui::ET_KEY_RELEASED) { + // TODO(kevers): Fix key handling to support key_value when code is + // VKEY_UNKNOWN. + base::string16 text; + text.push_back(static_cast<char16>(key_value)); + InsertText(text, root_window); + } + return true; +} + const GritResourceMap* GetKeyboardExtensionResources(size_t* size) { // This looks a lot like the contents of a resource map; however it is // necessary to have a custom path for the extension path, so the resource diff --git a/ui/keyboard/keyboard_util.h b/ui/keyboard/keyboard_util.h index 7d46433..bb0edfb 100644 --- a/ui/keyboard/keyboard_util.h +++ b/ui/keyboard/keyboard_util.h @@ -29,7 +29,7 @@ enum CursorMoveDirection { KEYBOARD_EXPORT bool IsKeyboardEnabled(); // Insert |text| into the active TextInputClient associated with |root_window|, -// if there is one. Returns true if |text| was successfully inserted. Note +// if there is one. Returns true if |text| was successfully inserted. Note // that this may convert |text| into ui::KeyEvents for injection in some // special circumstances (i.e. VKEY_RETURN, VKEY_BACK). KEYBOARD_EXPORT bool InsertText(const base::string16& text, @@ -41,7 +41,18 @@ KEYBOARD_EXPORT bool MoveCursor(int swipe_direction, int modifier_flags, aura::RootWindow* root_window); -// Get the list of keyboard resources. |size| is populated with the number of +// Sends a fabricated key event, where |type| is the event type, |key_value| +// is the unicode value of the character, |key_code| is the legacy key code +// value, and |shift_modifier| indicates if the shift key is being virtually +// pressed. The event is dispatched to the active TextInputClient associated +// with |root_window|. The type may be "keydown" or "keyup". +KEYBOARD_EXPORT bool SendKeyEvent(std::string type, + int key_value, + int key_code, + bool shift_modifier, + aura::RootWindow* root_window); + +// Get the list of keyboard resources. |size| is populated with the number of // resources in the returned array. KEYBOARD_EXPORT const GritResourceMap* GetKeyboardExtensionResources( size_t* size); diff --git a/ui/keyboard/resources/api_adapter.js b/ui/keyboard/resources/api_adapter.js index ff6192f..b2cbdd7 100644 --- a/ui/keyboard/resources/api_adapter.js +++ b/ui/keyboard/resources/api_adapter.js @@ -1,4 +1,4 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -15,3 +15,7 @@ function insertText(text) { function MoveCursor(swipe_direction, swipe_flags) { chrome.virtualKeyboardPrivate.moveCursor(swipe_direction, swipe_flags); } + +function sendKeyEvent(event) { + chrome.virtualKeyboardPrivate.sendKeyEvent(event, logIfError); +} diff --git a/ui/keyboard/resources/elements/kb-key-base.html b/ui/keyboard/resources/elements/kb-key-base.html index 0b017ff..5968c9c 100644 --- a/ui/keyboard/resources/elements/kb-key-base.html +++ b/ui/keyboard/resources/elements/kb-key-base.html @@ -109,11 +109,7 @@ } }, down: function(event) { - var detail = { - char: this.charValue, - toLayout: this.toLayout, - repeat: this.repeat - }; + var detail = this.PopulateDetails(); if (this.keysetRules && this.keysetRules.down != undefined) { detail.toKeyset = this.keysetRules.down[TO_KEYSET - OFFSET]; detail.nextKeyset = this.keysetRules.down[NEXT_KEYSET - OFFSET]; @@ -136,10 +132,7 @@ }, up: function(event) { clearTimeout(this.longPressTimer); - var detail = { - char: this.charValue, - toLayout: this.toLayout - }; + var detail = this.PopulateDetails(); if (this.keysetRules && this.keysetRules.up != undefined) { detail.toKeyset = this.keysetRules.up[TO_KEYSET - OFFSET]; detail.nextKeyset = this.keysetRules.up[NEXT_KEYSET - OFFSET]; @@ -156,6 +149,14 @@ get charValue() { return this.char || this.textContent; }, + + PopulateDetails: function() { + return { + char: this.charValue, + toLayout: this.toLayout, + repeat: this.repeat + }; + }, }); </script> </polymer-element> diff --git a/ui/keyboard/resources/elements/kb-key-codes.html b/ui/keyboard/resources/elements/kb-key-codes.html index cf1a7c23..b8353ec 100644 --- a/ui/keyboard/resources/elements/kb-key-codes.html +++ b/ui/keyboard/resources/elements/kb-key-codes.html @@ -7,6 +7,9 @@ <polymer-element name="kb-key-codes"> <script> (function() { + // Each virtual key event is assigned a unique ID. + var nextRequestID = 0; + // Keycodes have been deprecated in the KeyEvent specification, but are // nonetheless required to support legacy web content. The Keycodes in the // following table are based on subset of US-EN 101-key keyboard. These @@ -139,31 +142,36 @@ /** * Creates a virtual key event for use with the keyboard extension API. - * @param {kb-key} key Instance of the kb-key element being pressed or - * released. + * See http://www.w3.org/TR/DOM-Level-3-Events/#events-KeyboardEvent. + * @param {Object} detail Attribute of the key being pressed or released. * @param {string} type The type of key event, which may be keydown - * or keyreleased. - * @return {keyCode: numeric, - * modifiers: Array.<string>, - * type: string, - * value: string} + * or keyup. + * @return {?KeyboardEvent} A KeyboardEvent object, or undefined on + * failure. */ - CreateVirtualKeyEvent: function(key, type) { - var keyCode = key.keyCode; - var shiftModifier = key.shiftModifier; + createVirtualKeyEvent: function(detail, type) { + var char = detail.char; + if (!char || char.length != 1) { + console.error('Invalid key. Expected single character.'); + return; + } + var keyCode = detail.keyCode; + var shiftModifier = detail.shiftModifier; if (keyCode == undefined) { - var state = this.GetKeyCodeAndModifiers(key.charValue); - keyCode = state.keyCode; - shiftModifier = state.shiftModifier; + var state = this.GetKeyCodeAndModifiers(char); + if (state) { + keyCode = state.keyCode; + shiftModifier = state.shiftModifier; + } else { + keyCode = 0; + shiftModifier = false; + } } - var modifiers = []; - if (shiftModifier) - modifiers.push('shiftKey'); return { - keyCode: keyCode, - modifiers: modifiers, type: type, - value: key.charValue, + charValue: char.charCodeAt(0), + keyCode: keyCode, + shiftKey: shiftModifier }; }, }); diff --git a/ui/keyboard/resources/elements/kb-key.html b/ui/keyboard/resources/elements/kb-key.html index ffa2e0b3..b8ec5cb 100644 --- a/ui/keyboard/resources/elements/kb-key.html +++ b/ui/keyboard/resources/elements/kb-key.html @@ -39,7 +39,18 @@ * Keys with a high weighting are wider than normal keys. * @type {number} */ - weight: 1 + weight: 1, + + /** + * Returns a subset of the key attributes. + * @return {Object} Mapping of attributes for the key element. + */ + PopulateDetails: function() { + var details = this.super(); + details.keyCode = this.keyCode; + details.shiftModifier = this.shiftModifier; + return details; + }, }); </script> </polymer-element> diff --git a/ui/keyboard/resources/elements/kb-keyboard.html b/ui/keyboard/resources/elements/kb-keyboard.html index 93cc165..2082a84 100644 --- a/ui/keyboard/resources/elements/kb-keyboard.html +++ b/ui/keyboard/resources/elements/kb-keyboard.html @@ -23,6 +23,7 @@ -- keyboard layouts. --> <content select="#{{layout}}-{{keyset}}"></content> + <kb-key-codes id="keyCodeMetadata"></kb-key-codes> </template> <script> /** @@ -297,12 +298,13 @@ } if (detail.repeat) { - insertText(detail.char); + this.keyTyped(detail); repeatKey.key = this.lastPressedKey; + var self = this; repeatKey.timer = setTimeout(function() { repeatKey.timer = undefined; repeatKey.interval = setInterval(function() { - insertText(detail.char); + self.keyTyped(detail); }, REPEAT_INTERVAL_MSEC); }, Math.max(0, REPEAT_DELAY_MSEC - REPEAT_INTERVAL_MSEC)); } @@ -435,7 +437,10 @@ default: break; } - insertText(char); + if (char.length == 1) + this.keyTyped(detail); + else + insertText(char); }, /* @@ -494,6 +499,17 @@ }, /** + * Generates fabricated key events to simulate typing on a + * physical keyboard. + * @param {Object} detail Attributes of the key being typed. + */ + keyTyped: function(detail) { + var builder = this.$.keyCodeMetadata; + sendKeyEvent(builder.createVirtualKeyEvent(detail, "keydown")); + sendKeyEvent(builder.createVirtualKeyEvent(detail, "keyup")); + }, + + /** * Selects the default keyset for a layout. * @return {boolean} True if successful. This method can fail if the * keysets corresponding to the layout have not been injected. diff --git a/ui/keyboard/resources/webui/api_adapter.js b/ui/keyboard/resources/webui/api_adapter.js index 3072775..4adb177 100644 --- a/ui/keyboard/resources/webui/api_adapter.js +++ b/ui/keyboard/resources/webui/api_adapter.js @@ -6,6 +6,10 @@ function insertText(text) { chrome.send('insertText', [ text ]); } +function sendKeyEvent(event) { + chrome.send('sendKeyEvent', [ event ]); +} + (function(exports) { /** * An array to save callbacks of each request. |