diff options
author | bryeung@chromium.org <bryeung@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-18 11:24:01 +0000 |
---|---|---|
committer | bryeung@chromium.org <bryeung@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-18 11:24:01 +0000 |
commit | 726002268c55e3597a6965fe69e3d488a9d64586 (patch) | |
tree | 89d21cbb6125a6518bb7128a48f3c8afa5964a7a /ui/keyboard | |
parent | 0cacba977cc16dd6cbd991a75ec7e1e991b0b1dc (diff) | |
download | chromium_src-726002268c55e3597a6965fe69e3d488a9d64586.zip chromium_src-726002268c55e3597a6965fe69e3d488a9d64586.tar.gz chromium_src-726002268c55e3597a6965fe69e3d488a9d64586.tar.bz2 |
Add a virtual keyboard webui at chrome://keyboard/
This is just the old virtual keyboard that was removed a couple of years
ago, being used as a temporary stand-in.
BUG=222801
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=194579
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=194635
Review URL: https://codereview.chromium.org/13652010
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@194881 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/keyboard')
-rw-r--r-- | ui/keyboard/DEPS | 4 | ||||
-rw-r--r-- | ui/keyboard/keyboard.gyp | 37 | ||||
-rw-r--r-- | ui/keyboard/keyboard_constants.cc | 12 | ||||
-rw-r--r-- | ui/keyboard/keyboard_constants.h | 20 | ||||
-rw-r--r-- | ui/keyboard/keyboard_resources.grd | 33 | ||||
-rw-r--r-- | ui/keyboard/keyboard_ui_controller.cc | 55 | ||||
-rw-r--r-- | ui/keyboard/keyboard_ui_controller.h | 29 | ||||
-rw-r--r-- | ui/keyboard/resources/common.js | 716 | ||||
-rw-r--r-- | ui/keyboard/resources/images/chevron.svg | 9 | ||||
-rw-r--r-- | ui/keyboard/resources/images/del.svg | 17 | ||||
-rw-r--r-- | ui/keyboard/resources/images/keyboard.svg | 25 | ||||
-rw-r--r-- | ui/keyboard/resources/images/mic.svg | 23 | ||||
-rw-r--r-- | ui/keyboard/resources/images/ret.svg | 17 | ||||
-rw-r--r-- | ui/keyboard/resources/images/shift-down.svg | 15 | ||||
-rw-r--r-- | ui/keyboard/resources/images/shift.svg | 15 | ||||
-rw-r--r-- | ui/keyboard/resources/images/tab.svg | 14 | ||||
-rw-r--r-- | ui/keyboard/resources/index.html | 10 | ||||
-rw-r--r-- | ui/keyboard/resources/layout_us.js | 89 | ||||
-rw-r--r-- | ui/keyboard/resources/main.css | 193 | ||||
-rw-r--r-- | ui/keyboard/resources/main.js | 192 | ||||
-rw-r--r-- | ui/keyboard/resources/manifest.json | 14 |
21 files changed, 1538 insertions, 1 deletions
diff --git a/ui/keyboard/DEPS b/ui/keyboard/DEPS new file mode 100644 index 0000000..07406d8 --- /dev/null +++ b/ui/keyboard/DEPS @@ -0,0 +1,4 @@ +include_rules = [ + "+content/public", + "+grit/keyboard_resources.h", +] diff --git a/ui/keyboard/keyboard.gyp b/ui/keyboard/keyboard.gyp index add01e5..6562daa 100644 --- a/ui/keyboard/keyboard.gyp +++ b/ui/keyboard/keyboard.gyp @@ -8,35 +8,59 @@ }, 'targets': [ { + 'target_name': 'keyboard_resources', + 'type': 'none', + 'variables': { + 'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/ui/keyboard', + }, + 'actions': [ + { + 'action_name': 'keyboard_resources', + 'variables': { + 'grit_grd_file': 'keyboard_resources.grd', + }, + 'includes': [ '../../build/grit_action.gypi' ], + }, + ], + 'includes': [ '../../build/grit_target.gypi' ], + }, + { 'target_name': 'keyboard', 'type': '<(component)', 'dependencies': [ '../../base/base.gyp:base', + '../../content/content.gyp:content_browser', '../../skia/skia.gyp:skia', '../aura/aura.gyp:aura', '../compositor/compositor.gyp:compositor', '../ui.gyp:ui', + 'keyboard_resources', ], 'defines': [ 'KEYBOARD_IMPLEMENTATION', ], 'sources': [ + 'keyboard_constants.cc', + 'keyboard_constants.h', 'keyboard_controller.cc', 'keyboard_controller.h', 'keyboard_controller_proxy.h', 'keyboard_export.h', 'keyboard_switches.cc', 'keyboard_switches.h', + 'keyboard_ui_controller.cc', + 'keyboard_ui_controller.h', 'keyboard_util.cc', 'keyboard_util.h', ] }, { 'target_name': 'keyboard_unittests', - 'type': 'executable', + 'type': '<(gtest_target_type)', 'dependencies': [ '../../base/base.gyp:base', '../../base/base.gyp:test_support_base', + '../../content/content.gyp:content_browser', '../../skia/skia.gyp:skia', '../../testing/gtest.gyp:gtest', '../aura/aura.gyp:aura', @@ -51,6 +75,17 @@ 'keyboard_controller_unittest.cc', 'keyboard_test_suite.cc', ], + 'conditions': [ + [ 'os_posix == 1 and OS != "mac" and OS != "android" and OS != "ios"', { + 'conditions': [ + ['linux_use_tcmalloc==1', { + 'dependencies': [ + '../../base/allocator/allocator.gyp:allocator', + ], + }], + ], + }], + ], }, ], } diff --git a/ui/keyboard/keyboard_constants.cc b/ui/keyboard/keyboard_constants.cc new file mode 100644 index 0000000..35f8130 --- /dev/null +++ b/ui/keyboard/keyboard_constants.cc @@ -0,0 +1,12 @@ +// Copyright (c) 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. + +#include "ui/keyboard/keyboard_constants.h" + +namespace keyboard { + +const char kKeyboardWebUIURL[] = "chrome://keyboard"; +const char kKeyboardWebUIHost[] = "keyboard"; + +} // namespace keyboard diff --git a/ui/keyboard/keyboard_constants.h b/ui/keyboard/keyboard_constants.h new file mode 100644 index 0000000..eff96ea --- /dev/null +++ b/ui/keyboard/keyboard_constants.h @@ -0,0 +1,20 @@ +// Copyright (c) 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. + +#ifndef UI_KEYBOARD_KEYBOARD_CONSTANTS_H_ +#define UI_KEYBOARD_KEYBOARD_CONSTANTS_H_ + +#include "ui/keyboard/keyboard_export.h" + +namespace keyboard { + +// The URL of the keyboard WebUI. +KEYBOARD_EXPORT extern const char kKeyboardWebUIURL[]; + +// The host of the keyboard WebUI URL. +KEYBOARD_EXPORT extern const char kKeyboardWebUIHost[]; + +} // namespace keyboard + +#endif // UI_KEYBOARD_KEYBOARD_CONSTANTS_H_ diff --git a/ui/keyboard/keyboard_resources.grd b/ui/keyboard/keyboard_resources.grd new file mode 100644 index 0000000..58b93df --- /dev/null +++ b/ui/keyboard/keyboard_resources.grd @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + NOTE: if you are adding resources here, you should probably also edit: + chrome/browser/ui/webui/virtual_keyboard_ui.cc // FIXME: this will move + chrome/browser/extensions/image_loader.cc +--> +<grit latest_public_release="0" current_release="1"> + <outputs> + <output filename="grit/keyboard_resources.h" type="rc_header"> + <emit emit_type='prepend'></emit> + </output> + <output filename="keyboard_resources.pak" type="data_package" /> + <output filename="keyboard_resources.rc" type="rc_all" /> + </outputs> + <release seq="1"> + <includes> + <include name="IDR_KEYBOARD_MANIFEST" file="resources/manifest.json" type="BINDATA" /> + <include name="IDR_KEYBOARD_INDEX" file="resources/index.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> + <include name="IDR_KEYBOARD_MAIN_CSS" file="resources/main.css" type="BINDATA" /> + <include name="IDR_KEYBOARD_MAIN_JS" file="resources/main.js" type="BINDATA" /> + <include name="IDR_KEYBOARD_COMMON_JS" file="resources/common.js" type="BINDATA" /> + <include name="IDR_KEYBOARD_LAYOUT_US_JS" file="resources/layout_us.js" type="BINDATA" /> + <include name="IDR_KEYBOARD_IMAGES_CHEVRON" file="resources/images/chevron.svg" type="BINDATA" /> + <include name="IDR_KEYBOARD_IMAGES_DEL" file="resources/images/del.svg" type="BINDATA" /> + <include name="IDR_KEYBOARD_IMAGES_KEYBOARD" file="resources/images/keyboard.svg" type="BINDATA" /> + <include name="IDR_KEYBOARD_IMAGES_MIC" file="resources/images/mic.svg" type="BINDATA" /> + <include name="IDR_KEYBOARD_IMAGES_RET" file="resources/images/ret.svg" type="BINDATA" /> + <include name="IDR_KEYBOARD_IMAGES_SHIFT_DOWN" file="resources/images/shift-down.svg" type="BINDATA" /> + <include name="IDR_KEYBOARD_IMAGES_SHIFT" file="resources/images/shift.svg" type="BINDATA" /> + <include name="IDR_KEYBOARD_IMAGES_TAB" file="resources/images/tab.svg" type="BINDATA" /> + </includes> + </release> +</grit> diff --git a/ui/keyboard/keyboard_ui_controller.cc b/ui/keyboard/keyboard_ui_controller.cc new file mode 100644 index 0000000..d0bc5ff --- /dev/null +++ b/ui/keyboard/keyboard_ui_controller.cc @@ -0,0 +1,55 @@ +// Copyright (c) 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. + +#include "ui/keyboard/keyboard_ui_controller.h" + +#include "content/public/browser/browser_context.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_ui.h" +#include "content/public/browser/web_ui_data_source.h" +#include "grit/keyboard_resources.h" +#include "ui/keyboard/keyboard_constants.h" + +namespace { + +content::WebUIDataSource* CreateKeyboardUIDataSource() { + content::WebUIDataSource* source = + content::WebUIDataSource::Create(keyboard::kKeyboardWebUIHost); + + source->SetDefaultResource(IDR_KEYBOARD_INDEX); + + source->AddResourcePath("main.css", IDR_KEYBOARD_MAIN_CSS); + + source->AddResourcePath("main.js", IDR_KEYBOARD_MAIN_JS); + source->AddResourcePath("common.js", IDR_KEYBOARD_COMMON_JS); + source->AddResourcePath("layout_us.js", IDR_KEYBOARD_LAYOUT_US_JS); + source->AddResourcePath("images/chevron.svg", IDR_KEYBOARD_IMAGES_CHEVRON); + source->AddResourcePath("images/del.svg", IDR_KEYBOARD_IMAGES_DEL); + source->AddResourcePath("images/keyboard.svg", IDR_KEYBOARD_IMAGES_KEYBOARD); + source->AddResourcePath("images/mic.svg", IDR_KEYBOARD_IMAGES_MIC); + source->AddResourcePath("images/ret.svg", IDR_KEYBOARD_IMAGES_RET); + source->AddResourcePath("images/shift_down.svg", + IDR_KEYBOARD_IMAGES_SHIFT_DOWN); + source->AddResourcePath("images/shift.svg", IDR_KEYBOARD_IMAGES_SHIFT); + source->AddResourcePath("images/tab.svg", IDR_KEYBOARD_IMAGES_TAB); + + return source; +} + +} // namespace + +namespace keyboard { + +KeyboardUIController::KeyboardUIController(content::WebUI* web_ui) + : WebUIController(web_ui) { + content::BrowserContext* browser_context = + web_ui->GetWebContents()->GetBrowserContext(); + content::WebUIDataSource::Add( + browser_context, + CreateKeyboardUIDataSource()); +} + +KeyboardUIController::~KeyboardUIController() {} + +} // namespace keyboard diff --git a/ui/keyboard/keyboard_ui_controller.h b/ui/keyboard/keyboard_ui_controller.h new file mode 100644 index 0000000..b06ec26 --- /dev/null +++ b/ui/keyboard/keyboard_ui_controller.h @@ -0,0 +1,29 @@ +// Copyright (c) 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. + +#ifndef UI_KEYBOARD_KEYBOARD_UI_CONTROLLER_H_ +#define UI_KEYBOARD_KEYBOARD_UI_CONTROLLER_H_ + +#include "content/public/browser/web_ui_controller.h" +#include "ui/keyboard/keyboard_export.h" + +namespace content { +class WebUI; +}; + +namespace keyboard { + +// WebUIController for chrome://keyboard/. +class KEYBOARD_EXPORT KeyboardUIController : public content::WebUIController { + public: + explicit KeyboardUIController(content::WebUI* web_ui); + virtual ~KeyboardUIController(); + + private: + DISALLOW_COPY_AND_ASSIGN(KeyboardUIController); +}; + +} // namespace keyboard + +#endif // UI_KEYBOARD_KEYBOARD_UI_CONTROLLER_H_ diff --git a/ui/keyboard/resources/common.js b/ui/keyboard/resources/common.js new file mode 100644 index 0000000..03aa5509 --- /dev/null +++ b/ui/keyboard/resources/common.js @@ -0,0 +1,716 @@ +// Copyright (c) 2011 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. + +/** + * @fileoverview A simple virtual keyboard implementation. + */ + +var KEY_MODE = 'key'; +var SHIFT_MODE = 'shift'; +var NUMBER_MODE = 'number'; +var SYMBOL_MODE = 'symbol'; +// TODO(bryeung): tear out all of this mode switching code +var MODES = [KEY_MODE, SHIFT_MODE, NUMBER_MODE, SYMBOL_MODE]; +var currentMode = KEY_MODE; +var enterShiftModeOnSpace = false; +var MODE_CODES = {}; +var MODE_TRANSITIONS = {}; + +MODE_CODES[KEY_MODE] = 0; +MODE_CODES[SHIFT_MODE] = 1; +MODE_CODES[NUMBER_MODE] = 2; +MODE_CODES[SYMBOL_MODE] = 3; + +MODE_TRANSITIONS[KEY_MODE + SHIFT_MODE] = SHIFT_MODE; +MODE_TRANSITIONS[KEY_MODE + NUMBER_MODE] = NUMBER_MODE; +MODE_TRANSITIONS[SHIFT_MODE + SHIFT_MODE] = KEY_MODE; +MODE_TRANSITIONS[SHIFT_MODE + NUMBER_MODE] = NUMBER_MODE; +MODE_TRANSITIONS[NUMBER_MODE + SHIFT_MODE] = SYMBOL_MODE; +MODE_TRANSITIONS[NUMBER_MODE + NUMBER_MODE] = KEY_MODE; +MODE_TRANSITIONS[SYMBOL_MODE + SHIFT_MODE] = NUMBER_MODE; +MODE_TRANSITIONS[SYMBOL_MODE + NUMBER_MODE] = KEY_MODE; + +var KEYBOARDS = {}; + +/** + * The long-press delay in milliseconds before long-press handler is invoked. + * @type {number} + */ +var LONGPRESS_DELAY_MSEC = 500; + +/** + * The repeat delay in milliseconds before a key starts repeating. Use the same + * rate as Chromebook. (See chrome/browser/chromeos/language_preferences.cc) + * @type {number} + */ +var REPEAT_DELAY_MSEC = 500; + +/** + * The repeat interval or number of milliseconds between subsequent keypresses. + * Use the same rate as Chromebook. + * @type {number} + */ +var REPEAT_INTERVAL_MSEC = 50; + +/** + * The keyboard layout name currently in use. + * @type {string} + */ +var currentKeyboardLayout = 'us'; + +/** + * A structure to track the currently repeating key on the keyboard. + */ +var repeatKey = { + /** + * The timer for the delay before repeating behaviour begins. + * @type {number|undefined} + */ + timer: undefined, + + /** + * The interval timer for issuing keypresses of a repeating key. + * @type {number|undefined} + */ + interval: undefined, + + /** + * The key which is currently repeating. + * @type {BaseKey|undefined} + */ + key: undefined, + + /** + * Cancel the repeat timers of the currently active key. + */ + cancel: function() { + clearTimeout(this.timer); + clearInterval(this.interval); + this.timer = undefined; + this.interval = undefined; + this.key = undefined; + } +}; + +/** + * Set the keyboard mode. + * @param {string} mode The new mode. + */ +function setMode(mode) { + currentMode = mode; + + var rows = KEYBOARDS[currentKeyboardLayout]['rows']; + for (var i = 0; i < rows.length; ++i) { + rows[i].showMode(currentMode); + } +} + +/** + * Transition the mode according to the given transition. + * @param {string} transition The transition to take. + */ +function transitionMode(transition) { + setMode(MODE_TRANSITIONS[currentMode + transition]); +} + +function logIfError() { + if (chrome.runtime.lastError) { + console.log(chrome.runtime.lastError); + } +} + +/** + * Send the given key to chrome, via the experimental extension API. + * @param {string} keyIdentifier The key to send. + */ +function sendKey(keyIdentifier) { + // FIXME(bryeung) + console.log('Typed: ' + keyIdentifier); + var keyEvent = { + type: 'keydown', + keyIdentifier: keyIdentifier + }; + chrome.experimental.input.virtualKeyboard.sendKeyboardEvent(keyEvent, + logIfError); + keyEvent.type = 'keyup'; + chrome.experimental.input.virtualKeyboard.sendKeyboardEvent(keyEvent, + logIfError); + + // Exit shift mode after pressing any key but space. + if (currentMode == SHIFT_MODE && keyIdentifier != 'Spacebar') { + transitionMode(SHIFT_MODE); + } + // Enter shift mode after typing a closing punctuation and then a space for a + // new sentence. + if (enterShiftModeOnSpace) { + enterShiftModeOnSpace = false; + if (currentMode != SHIFT_MODE && keyIdentifier == 'Spacebar') { + setMode(SHIFT_MODE); + } + } + if (currentMode != SHIFT_MODE && + (keyIdentifier == '.' || keyIdentifier == '?' || keyIdentifier == '!')) { + enterShiftModeOnSpace = true; + } +} + +/** + * Add a child div element that represents the content of the given element. + * A child div element that represents a text content is added if + * opt_textContent is given. Otherwise a child element that represents an image + * content is added. If the given element already has a child, the child element + * is modified. + * @param {Element} element The DOM Element to which the content is added. + * @param {string} opt_textContent The text to be inserted. + */ +function addContent(element, opt_textContent) { + if (element.childNodes.length > 0) { + var content = element.childNodes[0]; + if (opt_textContent) { + content.textContent = opt_textContent; + } + return; + } + + var content = document.createElement('div'); + if (opt_textContent) { + content.textContent = opt_textContent; + content.className = 'text-key'; + } else { + content.className = 'image-key'; + } + element.appendChild(content); +} + +/** + * Set up the event handlers necessary to respond to mouse and touch events on + * the virtual keyboard. + * @param {BaseKey} key The BaseKey object corresponding to this key. + * @param {Element} element The top-level DOM Element to set event handlers on. + * @param {Object.<string, function()>} handlers The object that contains key + * event handlers in the following form. + * + * { 'up': keyUpHandler, + * 'down': keyDownHandler, + * 'long': keyLongHandler } + * + * keyDownHandler: Called when the key is pressed. This will be called + * repeatedly when holding a repeating key. + * keyUpHandler: Called when the key is released. This is only called + * once per actual key press. + * keyLongHandler: Called when the key is long-pressed for + * |LONGPRESS_DELAY_MSEC| milliseconds. + * + * The object does not necessarily contain all the handlers above, but + * needs to contain at least one of them. + */ +function setupKeyEventHandlers(key, element, handlers) { + var keyDownHandler = handlers['down']; + var keyUpHandler = handlers['up']; + var keyLongHandler = handlers['long']; + if (!(keyDownHandler || keyUpHandler || keyLongPressHandler)) { + throw new Error('Invalid handlers passed to setupKeyEventHandlers'); + } + + /** + * Handle a key down event on the virtual key. + * @param {UIEvent} evt The UI event which triggered the key down. + */ + var downHandler = function(evt) { + // Prevent any of the system gestures from happening. + evt.preventDefault(); + + // Don't process a key down if the key is already down. + if (key.pressed) { + return; + } + key.pressed = true; + if (keyDownHandler) { + keyDownHandler(); + } + repeatKey.cancel(); + + // Start a repeating timer if there is a repeat interval and a function to + // process key down events. + if (key.repeat && keyDownHandler) { + repeatKey.key = key; + // The timeout for the repeating timer occurs at + // REPEAT_DELAY_MSEC - REPEAT_INTERVAL_MSEC so that the interval + // function can handle all repeat keypresses and will get the first one + // at the correct time. + repeatKey.timer = setTimeout(function() { + repeatKey.timer = undefined; + repeatKey.interval = setInterval(function() { + keyDownHandler(); + }, REPEAT_INTERVAL_MSEC); + }, Math.max(0, REPEAT_DELAY_MSEC - REPEAT_INTERVAL_MSEC)); + } + + if (keyLongHandler) { + // Copy the currentTarget of event, which is neccessary because |evt| can + // be modified before |keyLongHandler| is called. + var evtCopy = {}; + evtCopy.currentTarget = evt.currentTarget; + key.longPressTimer = setTimeout(function() { + keyLongHandler(evtCopy), + clearTimeout(key.longPressTimer); + delete key.longPressTimer; + key.pressed = false; + }, LONGPRESS_DELAY_MSEC); + } + }; + + /** + * Handle a key up event on the virtual key. + * @param {UIEvent} evt The UI event which triggered the key up. + */ + var upHandler = function(evt) { + // Prevent any of the system gestures from happening. + evt.preventDefault(); + + // Reset long-press timer. + if (key.longPressTimer) { + clearTimeout(key.longPressTimer); + delete key.longPressTimer; + } + + // If they key was not actually pressed do not send a key up event. + if (!key.pressed) { + return; + } + key.pressed = false; + + // Cancel running repeat timer for the released key only. + if (repeatKey.key == key) { + repeatKey.cancel(); + } + + if (keyUpHandler) { + keyUpHandler(); + } + }; + + // Setup mouse event handlers. + element.addEventListener('mousedown', downHandler); + element.addEventListener('mouseup', upHandler); + + // Setup touch handlers. + element.addEventListener('touchstart', downHandler); + element.addEventListener('touchend', upHandler); +} + +/** + * Create closure for the sendKey function. + * @param {string} key The key paramater to sendKey. + * @return {function()} A function which calls sendKey(key). + */ +function sendKeyFunction(key) { + return function() { + sendKey(key); + }; +} + +/** + * Plain-old-data class to represent a character. + * @param {string} display The HTML to be displayed. + * @param {string} id The key identifier for this Character. + * @constructor + */ +function Character(display, id) { + this.display = display; + this.keyIdentifier = id; +} + +/** + * Convenience function to make the keyboard data more readable. + * @param {string} display The display for the created Character. + * @param {string} opt_id The id for the created Character. + * @return {Character} A character that contains display and opt_id. If + * opt_id is omitted, display is used as the id. + */ +function C(display, opt_id) { + var id = opt_id || display; + return new Character(display, id); +} + +/** + * An abstract base-class for all keys on the keyboard. + * @constructor + */ +function BaseKey() {} + +BaseKey.prototype = { + /** + * The cell type of this key. Determines the background colour. + * @type {string} + */ + cellType_: '', + + /** + * If true, holding this key will issue repeat keypresses. + * @type {boolean} + */ + repeat_: false, + + /** + * Track the pressed state of the key. This is true if currently pressed. + * @type {boolean} + */ + pressed_: false, + + /** + * Get the repeat behaviour of the key. + * @return {boolean} True if the key will repeat. + */ + get repeat() { + return this.repeat_; + }, + + /** + * Set the repeat behaviour of the key + * @param {boolean} repeat True if the key should repeat. + */ + set repeat(repeat) { + this.repeat_ = repeat; + }, + + /** + * Get the pressed state of the key. + * @return {boolean} True if the key is currently pressed. + */ + get pressed() { + return this.pressed_; + }, + + /** + * Set the pressed state of the key. + * @param {boolean} pressed True if the key is currently pressed. + */ + set pressed(pressed) { + this.pressed_ = pressed; + }, + + /** + * Create the DOM elements for the given keyboard mode. Must be overridden. + * @param {string} mode The keyboard mode to create elements for. + * @return {Element} The top-level DOM Element for the key. + */ + makeDOM: function(mode) { + throw new Error('makeDOM not implemented in BaseKey'); + }, +}; + +/** + * A simple key which displays Characters. + * @param {Object} key The Character for KEY_MODE. + * @param {Object} shift The Character for SHIFT_MODE. + * @param {string} className An optional class name for the key. + * @constructor + * @extends {BaseKey} + */ +function Key(key, shift, className) { + this.modeElements_ = {}; + this.cellType_ = ''; + this.className_ = (className) ? 'key ' + className : 'key'; + + this.modes_ = {}; + this.modes_[KEY_MODE] = key; + this.modes_[SHIFT_MODE] = shift; +} + +Key.prototype = { + __proto__: BaseKey.prototype, + + /** @override */ + makeDOM: function(mode) { + if (!this.modes_[mode]) { + return null; + } + + this.modeElements_[mode] = document.createElement('div'); + var element = this.modeElements_[mode]; + element.className = this.className_; + + addContent(element, this.modes_[mode].display); + + setupKeyEventHandlers(this, element, + { 'up': sendKeyFunction(this.modes_[mode].keyIdentifier) }); + return element; + } +}; + +/** + * A key which displays an SVG image. + * @param {string} className The class that provides the image. + * @param {string} keyId The key identifier for the key. + * @param {boolean} opt_repeat True if the key should repeat. + * @constructor + * @extends {BaseKey} + */ +function SvgKey(className, keyId, opt_repeat) { + this.modeElements_ = {}; + this.cellType_ = 'nc'; + this.className_ = className; + this.keyId_ = keyId; + this.repeat_ = opt_repeat || false; +} + +SvgKey.prototype = { + __proto__: BaseKey.prototype, + + /** @override */ + makeDOM: function(mode) { + this.modeElements_[mode] = document.createElement('div'); + this.modeElements_[mode].className = 'key'; + this.modeElements_[mode].classList.add(this.className_); + addContent(this.modeElements_[mode]); + + // send the key event on key down if key repeat is enabled + var handler = this.repeat_ ? { 'down' : sendKeyFunction(this.keyId_) } : + { 'up' : sendKeyFunction(this.keyId_) }; + setupKeyEventHandlers(this, this.modeElements_[mode], handler); + + return this.modeElements_[mode]; + } +}; + +/** + * A Key that remains the same through all modes. + * @param {string} className The class name for the key. + * @param {string} content The display text for the key. + * @param {string} keyId The key identifier for the key. + * @constructor + * @extends {BaseKey} + */ +function SpecialKey(className, content, keyId) { + this.modeElements_ = {}; + this.cellType_ = 'nc'; + this.content_ = content; + this.keyId_ = keyId; + this.className_ = className; +} + +SpecialKey.prototype = { + __proto__: BaseKey.prototype, + + /** @override */ + makeDOM: function(mode) { + this.modeElements_[mode] = document.createElement('div'); + this.modeElements_[mode].className = 'key'; + this.modeElements_[mode].classList.add(this.className_); + addContent(this.modeElements_[mode], this.content_); + + setupKeyEventHandlers(this, this.modeElements_[mode], + { 'up': sendKeyFunction(this.keyId_) }); + + return this.modeElements_[mode]; + } +}; + +/** + * A shift key. + * @constructor + * @param {string} className The class name for the key. + * @extends {BaseKey} + */ +function ShiftKey(className) { + this.modeElements_ = {}; + this.cellType_ = 'nc'; + this.className_ = className; +} + +ShiftKey.prototype = { + __proto__: BaseKey.prototype, + + /** @override */ + makeDOM: function(mode) { + this.modeElements_[mode] = document.createElement('div'); + this.modeElements_[mode].className = 'key shift'; + this.modeElements_[mode].classList.add(this.className_); + + if (mode == KEY_MODE || mode == SHIFT_MODE) { + addContent(this.modeElements_[mode]); + } else if (mode == NUMBER_MODE) { + addContent(this.modeElements_[mode], 'more'); + } else if (mode == SYMBOL_MODE) { + addContent(this.modeElements_[mode], '#123'); + } + + if (mode == SHIFT_MODE || mode == SYMBOL_MODE) { + this.modeElements_[mode].classList.add('moddown'); + } else { + this.modeElements_[mode].classList.remove('moddown'); + } + + setupKeyEventHandlers(this, this.modeElements_[mode], + { 'down': function() { + transitionMode(SHIFT_MODE); + }}); + + return this.modeElements_[mode]; + }, +}; + +/** + * The symbol key: switches the keyboard into symbol mode. + * @constructor + * @extends {BaseKey} + */ +function SymbolKey() { + this.modeElements_ = {}; + this.cellType_ = 'nc'; +} + +SymbolKey.prototype = { + __proto__: BaseKey.prototype, + + /** @override */ + makeDOM: function(mode, height) { + this.modeElements_[mode] = document.createElement('div'); + this.modeElements_[mode].className = 'key symbol'; + + if (mode == KEY_MODE || mode == SHIFT_MODE) { + addContent(this.modeElements_[mode], '#123'); + } else if (mode == NUMBER_MODE || mode == SYMBOL_MODE) { + addContent(this.modeElements_[mode], 'abc'); + } + + if (mode == NUMBER_MODE || mode == SYMBOL_MODE) { + this.modeElements_[mode].classList.add('moddown'); + } else { + this.modeElements_[mode].classList.remove('moddown'); + } + + setupKeyEventHandlers(this, this.modeElements_[mode], + { 'down': function() { + transitionMode(NUMBER_MODE); + }}); + + return this.modeElements_[mode]; + } +}; + +/** + * The ".com" key. + * @constructor + * @extends {BaseKey} + */ +function DotComKey() { + this.modeElements_ = {}; + this.cellType_ = 'nc'; +} + +DotComKey.prototype = { + __proto__: BaseKey.prototype, + + /** @override */ + makeDOM: function(mode) { + this.modeElements_[mode] = document.createElement('div'); + this.modeElements_[mode].className = 'key com'; + addContent(this.modeElements_[mode], '.com'); + + setupKeyEventHandlers(this, this.modeElements_[mode], + { 'up': function() { + sendKey('.'); + sendKey('c'); + sendKey('o'); + sendKey('m'); + }}); + + return this.modeElements_[mode]; + } +}; + +/** + * The key that hides the keyboard. + * @constructor + * @extends {BaseKey} + */ +function HideKeyboardKey() { + this.modeElements_ = {}; + this.cellType_ = 'nc'; +} + +HideKeyboardKey.prototype = { + __proto__: BaseKey.prototype, + + /** @override */ + makeDOM: function(mode) { + this.modeElements_[mode] = document.createElement('div'); + this.modeElements_[mode].className = 'key hide'; + addContent(this.modeElements_[mode]); + + setupKeyEventHandlers(this, this.modeElements_[mode], + { 'down': function() { console.log('Hide the keyboard!'); } }); + + return this.modeElements_[mode]; + } +}; + +/** + * A container for keys. + * @param {number} position The position of the row (0-3). + * @param {Array.<BaseKey>} keys The keys in the row. + * @constructor + */ +function Row(position, keys) { + this.position_ = position; + this.keys_ = keys; + this.element_ = null; + this.modeElements_ = {}; +} + +Row.prototype = { + /** + * Create the DOM elements for the row. + * @return {Element} The top-level DOM Element for the row. + */ + makeDOM: function() { + this.element_ = document.createElement('div'); + this.element_.className = 'row'; + for (var i = 0; i < MODES.length; ++i) { + var mode = MODES[i]; + this.modeElements_[mode] = document.createElement('div'); + this.modeElements_[mode].style.display = 'none'; + this.element_.appendChild(this.modeElements_[mode]); + } + + for (var j = 0; j < this.keys_.length; ++j) { + var key = this.keys_[j]; + for (var i = 0; i < MODES.length; ++i) { + var keyDom = key.makeDOM(MODES[i]); + if (keyDom) { + this.modeElements_[MODES[i]].appendChild(keyDom); + } + } + } + + for (var i = 0; i < MODES.length; ++i) { + var clearingDiv = document.createElement('div'); + clearingDiv.style.clear = 'both'; + this.modeElements_[MODES[i]].appendChild(clearingDiv); + } + + return this.element_; + }, + + /** + * Shows the given mode. + * @param {string} mode The mode to show. + */ + showMode: function(mode) { + for (var i = 0; i < MODES.length; ++i) { + this.modeElements_[MODES[i]].style.display = 'none'; + } + this.modeElements_[mode].style.display = '-webkit-box'; + }, + + /** + * Returns the size of keys this row contains. + * @return {number} The size of keys. + */ + get length() { + return this.keys_.length; + } +}; diff --git a/ui/keyboard/resources/images/chevron.svg b/ui/keyboard/resources/images/chevron.svg new file mode 100644 index 0000000..d75deb0 --- /dev/null +++ b/ui/keyboard/resources/images/chevron.svg @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="50px" height="50px" viewBox="-0.042 -8.542 50 50" xml:space="preserve"> +<g> + <path fill="#bababb" d="M24.958,12.318l11.482-6.646v3.801l-11.482,7.904L13.479,9.473V5.672L24.958,12.318z M24.958,22.06l11.482-6.57v3.726 + l-11.482,8.031l-11.479-8.031v-3.701L24.958,22.06z"/> +</g> +</svg> diff --git a/ui/keyboard/resources/images/del.svg b/ui/keyboard/resources/images/del.svg new file mode 100644 index 0000000..1f257d5 --- /dev/null +++ b/ui/keyboard/resources/images/del.svg @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="5 5 40 40" xml:space="preserve"> +<g> + <g> + <path fill="#bababb" d="M20.8,28.75c-0.043,0-0.087-0.012-0.126-0.034l-6-3.5C14.598,25.17,14.55,25.088,14.55,25 + s0.047-0.171,0.124-0.216l6-3.5c0.039-0.023,0.083-0.034,0.126-0.034c0.043,0,0.086,0.011,0.125,0.033 + c0.078,0.044,0.125,0.127,0.125,0.217v7c0,0.09-0.048,0.172-0.125,0.217C20.886,28.739,20.843,28.75,20.8,28.75L20.8,28.75z"/> + <path fill="#bababb" d="M20.8,21.5v7l-6-3.5L20.8,21.5 M20.8,21c-0.087,0-0.174,0.022-0.252,0.068l-6,3.5 + C14.395,24.657,14.3,24.822,14.3,25s0.094,0.342,0.248,0.432l6,3.5C20.626,28.977,20.713,29,20.8,29 + c0.086,0,0.172-0.022,0.249-0.066c0.155-0.089,0.251-0.255,0.251-0.434v-7c0-0.179-0.096-0.344-0.251-0.434 + C20.972,21.021,20.886,21,20.8,21L20.8,21z"/> + </g> + <polygon fill="#bababb" points="33.934,23.5 18.3,23.5 18.3,26.5 35.2,26.5 "/> +</g> +</svg> diff --git a/ui/keyboard/resources/images/keyboard.svg b/ui/keyboard/resources/images/keyboard.svg new file mode 100644 index 0000000..b8c7135 --- /dev/null +++ b/ui/keyboard/resources/images/keyboard.svg @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="50px" height="50px" viewBox="0 0 50 50" xml:space="preserve"> +<g> + <g> + <path fill="#bababb" fill-rule="evenodd" clip-rule="evenodd" d="M41,12H9c-2.209,0-4,1.791-4,4v18c0,2.209,1.791,4,4,4h32c2.209,0,4-1.791,4-4 + V16C45,13.791,43.209,12,41,12z M33,18c0-0.552,0.447-1,1-1h2c0.552,0,1,0.448,1,1v2c0,0.552-0.448,1-1,1h-2c-0.553,0-1-0.448-1-1 + V18z M33,24c0-0.553,0.447-1,1-1h2c0.552,0,1,0.447,1,1v2c0,0.553-0.448,1-1,1h-2c-0.553,0-1-0.447-1-1V24z M28,18 + c0-0.552,0.447-1,1-1h2c0.553,0,1,0.448,1,1v2c0,0.552-0.447,1-1,1h-2c-0.553,0-1-0.448-1-1V18z M28,24c0-0.553,0.447-1,1-1h2 + c0.553,0,1,0.447,1,1v2c0,0.553-0.447,1-1,1h-2c-0.553,0-1-0.447-1-1V24z M23,18c0-0.552,0.447-1,1-1h2c0.553,0,1,0.448,1,1v2 + c0,0.552-0.447,1-1,1h-2c-0.553,0-1-0.448-1-1V18z M23,24c0-0.553,0.447-1,1-1h2c0.553,0,1,0.447,1,1v2c0,0.553-0.447,1-1,1h-2 + c-0.553,0-1-0.447-1-1V24z M18,18c0-0.552,0.447-1,1-1h2c0.553,0,1,0.448,1,1v2c0,0.552-0.447,1-1,1h-2c-0.553,0-1-0.448-1-1V18z + M18,24c0-0.553,0.447-1,1-1h2c0.553,0,1,0.447,1,1v2c0,0.553-0.447,1-1,1h-2c-0.553,0-1-0.447-1-1V24z M13,18 + c0-0.552,0.447-1,1-1h2c0.553,0,1,0.448,1,1v2c0,0.552-0.447,1-1,1h-2c-0.553,0-1-0.448-1-1V18z M8,18c0-0.552,0.447-1,1-1h2 + c0.552,0,1,0.448,1,1v2c0,0.552-0.448,1-1,1H9c-0.553,0-1-0.448-1-1V18z M8,24c0-0.553,0.447-1,1-1h2c0.552,0,1,0.447,1,1v2 + c0,0.553-0.448,1-1,1H9c-0.553,0-1-0.447-1-1V24z M14,32c0,0.553-0.447,1-1,1H9c-0.553,0-1-0.447-1-1v-2c0-0.553,0.447-1,1-1h4 + c0.553,0,1,0.447,1,1V32z M13,26v-2c0-0.553,0.447-1,1-1h2c0.553,0,1,0.447,1,1v2c0,0.553-0.447,1-1,1h-2 + C13.447,27,13,26.553,13,26z M35,32c0,0.553-0.447,1-1,1H16c-0.553,0-1-0.447-1-1v-2c0-0.553,0.447-1,1-1h18c0.553,0,1,0.447,1,1 + V32z M42,32c0,0.553-0.447,1-1,1h-4c-0.553,0-1-0.447-1-1v-2c0-0.553,0.447-1,1-1h4c0.553,0,1,0.447,1,1V32z M42,26 + c0,0.553-0.447,1-1,1h-2c-0.553,0-1-0.447-1-1v-2c0-0.553,0.447-1,1-1h2c0.553,0,1,0.447,1,1V26z M42,20c0,0.552-0.447,1-1,1h-2 + c-0.553,0-1-0.448-1-1v-2c0-0.552,0.447-1,1-1h2c0.553,0,1,0.448,1,1V20z"/> + </g> +</g> +</svg> diff --git a/ui/keyboard/resources/images/mic.svg b/ui/keyboard/resources/images/mic.svg new file mode 100644 index 0000000..2b5711c --- /dev/null +++ b/ui/keyboard/resources/images/mic.svg @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + width="50px" height="50px" viewBox="0 0 50 50" enable-background="new 0 0 50 50" xml:space="preserve"> +<g> + <line fill="#bababb" stroke="#bababb" stroke-width="10" stroke-linecap="round" x1="25" y1="24.5" x2="25" y2="15.5"/> + <g> + <defs> + <rect id="SVGID_1_" x="-295" y="-214.5" width="640" height="480"/> + </defs> + <clipPath id="SVGID_2_"> + <use xlink:href="#SVGID_1_" overflow="visible"/> + </clipPath> + <path clip-path="url(#SVGID_2_)" fill="none" stroke="#bababb" stroke-width="3" stroke-linecap="round" d="M34,24.5 + c0,4.971-4.029,9-9,9c-4.971,0-9-4.029-9-9"/> + + <line clip-path="url(#SVGID_2_)" fill="#bababb" stroke="#bababb" stroke-width="3" stroke-linecap="round" x1="25" y1="33.5" x2="25" y2="39.5"/> + + <line clip-path="url(#SVGID_2_)" fill="#bababb" stroke="#bababb" stroke-width="3" stroke-linecap="round" x1="29" y1="39.5" x2="21" y2="39.5"/> + </g> +</g> +</svg> diff --git a/ui/keyboard/resources/images/ret.svg b/ui/keyboard/resources/images/ret.svg new file mode 100644 index 0000000..9f327f95 --- /dev/null +++ b/ui/keyboard/resources/images/ret.svg @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 50 50" enable-background="new 0 0 50 50" xml:space="preserve"> +<g> + <g> + <path fill="#bababb" d="M22.75,31.432c-0.043,0-0.087-0.012-0.126-0.034l-6-3.5c-0.077-0.045-0.124-0.127-0.124-0.216 + s0.047-0.171,0.124-0.216l6-3.5c0.039-0.023,0.083-0.034,0.126-0.034c0.043,0,0.086,0.011,0.125,0.033 + C22.952,24.01,23,24.093,23,24.182v7c0,0.09-0.048,0.172-0.125,0.217C22.835,31.421,22.792,31.432,22.75,31.432L22.75,31.432z"/> + <path fill="#bababb" d="M22.75,24.182v7l-6-3.5L22.75,24.182 M22.75,23.682c-0.087,0-0.174,0.022-0.252,0.068l-6,3.5 + c-0.154,0.089-0.248,0.254-0.248,0.432s0.094,0.342,0.248,0.432l6,3.5c0.078,0.046,0.165,0.068,0.252,0.068 + c0.086,0,0.172-0.022,0.249-0.066c0.155-0.089,0.251-0.255,0.251-0.434v-7c0-0.179-0.096-0.344-0.251-0.434 + C22.921,23.704,22.835,23.682,22.75,23.682L22.75,23.682z"/> + </g> + <path fill="#bababb" d="M30.25,20.083v6.1h-10v3h11.5c0.828,0,1.5-0.672,1.5-1.5v-8.865L30.25,20.083z"/> +</g> +</svg> diff --git a/ui/keyboard/resources/images/shift-down.svg b/ui/keyboard/resources/images/shift-down.svg new file mode 100644 index 0000000..958aa29 --- /dev/null +++ b/ui/keyboard/resources/images/shift-down.svg @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="50px" height="50px" viewBox="10 10 30 30"> +<!-- TODO(fsamuel): remove the width and height workaround above after fixing SVG bug --> +<g> + <path fill="#e0e0e0" d="M23,29.25c-0.138,0-0.25-0.112-0.25-0.25v-2.75H20c-0.101,0-0.192-0.061-0.231-0.154 + s-0.017-0.201,0.054-0.272l5-5c0.049-0.049,0.113-0.073,0.177-0.073s0.128,0.024,0.177,0.073l5,5 + c0.071,0.071,0.093,0.179,0.055,0.272c-0.039,0.093-0.13,0.154-0.231,0.154h-2.75V29c0,0.138-0.112,0.25-0.25,0.25H23z"/> + <path fill="#e0e0e0" d="M25,21l5,5h-3v3h-4v-3h-3L25,21 M25,20.5c-0.128,0-0.256,0.049-0.354,0.146l-5,5 + c-0.143,0.143-0.186,0.358-0.108,0.545C19.615,26.377,19.797,26.5,20,26.5h2.5V29c0,0.276,0.224,0.5,0.5,0.5h4 + c0.276,0,0.5-0.224,0.5-0.5v-2.5H30c0.202,0,0.385-0.122,0.462-0.309c0.077-0.187,0.034-0.402-0.108-0.545l-5-5 + C25.255,20.548,25.127,20.5,25,20.5L25,20.5z"/> +</g> +</svg> diff --git a/ui/keyboard/resources/images/shift.svg b/ui/keyboard/resources/images/shift.svg new file mode 100644 index 0000000..08d8c8a --- /dev/null +++ b/ui/keyboard/resources/images/shift.svg @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="50px" height="50px" viewBox="10 10 30 30"> +<!-- TODO(fsamuel): remove the width and height workaround above after fixing SVG bug --> +<g> + <path fill="#bababb" d="M23,29.25c-0.138,0-0.25-0.112-0.25-0.25v-2.75H20c-0.101,0-0.192-0.061-0.231-0.154 + s-0.017-0.201,0.054-0.272l5-5c0.049-0.049,0.113-0.073,0.177-0.073s0.128,0.024,0.177,0.073l5,5 + c0.071,0.071,0.093,0.179,0.055,0.272c-0.039,0.093-0.13,0.154-0.231,0.154h-2.75V29c0,0.138-0.112,0.25-0.25,0.25H23z"/> + <path fill="#bababb" d="M25,21l5,5h-3v3h-4v-3h-3L25,21 M25,20.5c-0.128,0-0.256,0.049-0.354,0.146l-5,5 + c-0.143,0.143-0.186,0.358-0.108,0.545C19.615,26.377,19.797,26.5,20,26.5h2.5V29c0,0.276,0.224,0.5,0.5,0.5h4 + c0.276,0,0.5-0.224,0.5-0.5v-2.5H30c0.202,0,0.385-0.122,0.462-0.309c0.077-0.187,0.034-0.402-0.108-0.545l-5-5 + C25.255,20.548,25.127,20.5,25,20.5L25,20.5z"/> +</g> +</svg> diff --git a/ui/keyboard/resources/images/tab.svg b/ui/keyboard/resources/images/tab.svg new file mode 100644 index 0000000..774e306 --- /dev/null +++ b/ui/keyboard/resources/images/tab.svg @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="100%" height="100%" viewBox="5 5 40 40" enable-background="new" xml:space="preserve"> +<g> + <line fill="none" stroke="#bababb" stroke-width="1.7" stroke-linecap="round" x1="36.377" y1="20.5" x2="36.377" y2="29.5"/> + <g> + <path fill="#bababb" d="M27.377,28.75c-0.043,0-0.086-0.011-0.125-0.033c-0.077-0.045-0.125-0.127-0.125-0.217v-7 + c0-0.089,0.048-0.172,0.125-0.217c0.039-0.022,0.082-0.033,0.125-0.033c0.044,0,0.087,0.011,0.126,0.034l6,3.5 + c0.077,0.045,0.124,0.127,0.124,0.216s-0.047,0.171-0.124,0.216l-6,3.5C27.464,28.738,27.421,28.75,27.377,28.75L27.377,28.75z"/> + </g> + <polygon fill="#bababb" points="14.888,23.5 13.623,26.5 29.877,26.5 29.877,23.5 "/> +</g> +</svg> diff --git a/ui/keyboard/resources/index.html b/ui/keyboard/resources/index.html new file mode 100644 index 0000000..8cd8b0e --- /dev/null +++ b/ui/keyboard/resources/index.html @@ -0,0 +1,10 @@ +<!DOCTYPE HTML> +<html> + <head> + <link rel="stylesheet" href="main.css"> + <script src="common.js"></script> + <script src="layout_us.js"></script> + <script src="main.js"></script> + </head> + <body id="b"></body> +</html> diff --git a/ui/keyboard/resources/layout_us.js b/ui/keyboard/resources/layout_us.js new file mode 100644 index 0000000..bea4e57 --- /dev/null +++ b/ui/keyboard/resources/layout_us.js @@ -0,0 +1,89 @@ +// Copyright (c) 2011 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. + +/** + * @fileoverview A simple English virtual keyboard implementation. + */ + +/** + * All keys for the rows of the keyboard. + * NOTE: every row below should have an aspect of 12.6. + * @type {Array.<Array.<BaseKey>>} + */ +var KEYS_US = [ + [ + new Key(C('\`'), C('~')), + new Key(C('1'), C('!')), + new Key(C('2'), C('@')), + new Key(C('3'), C('#')), + new Key(C('4'), C('$')), + new Key(C('5'), C('%')), + new Key(C('6'), C('^')), + new Key(C('7'), C('&')), + new Key(C('8'), C('*')), + new Key(C('9'), C('(')), + new Key(C('0'), C(')')), + new Key(C('-'), C('_')), + new Key(C('='), C('+')), + new SvgKey('backspace', 'Backspace', true /* repeat */) + ], + [ + new SvgKey('tab', 'Tab'), + new Key(C('q'), C('Q')), + new Key(C('w'), C('W')), + new Key(C('e'), C('E')), + new Key(C('r'), C('R')), + new Key(C('t'), C('T')), + new Key(C('y'), C('Y')), + new Key(C('u'), C('U')), + new Key(C('i'), C('I')), + new Key(C('o'), C('O')), + new Key(C('p'), C('P')), + new Key(C('['), C('{')), + new Key(C(']'), C('}')), + new Key(C('\\'), C('|'), 'bar'), + ], + [ + new SymbolKey(), + new Key(C('a'), C('A')), + new Key(C('s'), C('S')), + new Key(C('d'), C('D')), + new Key(C('f'), C('F')), + new Key(C('g'), C('G')), + new Key(C('h'), C('H')), + new Key(C('j'), C('J')), + new Key(C('k'), C('K')), + new Key(C('l'), C('L')), + new Key(C(';'), C(':')), + new Key(C('\''), C('"')), + new SvgKey('return', 'Enter') + ], + [ + new ShiftKey('left-shift'), + new Key(C('z'), C('Z')), + new Key(C('x'), C('X')), + new Key(C('c'), C('C')), + new Key(C('v'), C('V')), + new Key(C('b'), C('B')), + new Key(C('n'), C('N')), + new Key(C('m'), C('M')), + new Key(C(','), C('<')), + new Key(C('.'), C('>')), + new Key(C('/'), C('?')), + new ShiftKey('right-shift') + ], + [ + new DotComKey(), + new SpecialKey('at', '@', '@'), + new SpecialKey('space', ' ', 'Spacebar'), + new SpecialKey('comma', ',', ','), + new SpecialKey('period', '.', '.') + ] +]; + +// Add layout to KEYBOARDS, which is defined in common.js +KEYBOARDS['us'] = { + 'definition': KEYS_US, + 'aspect': 3.15, +}; diff --git a/ui/keyboard/resources/main.css b/ui/keyboard/resources/main.css new file mode 100644 index 0000000..6dbe38a --- /dev/null +++ b/ui/keyboard/resources/main.css @@ -0,0 +1,193 @@ +/* + Copyright (c) 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. +*/ + +body { + -webkit-user-select: none; + color: white; + margin: 0; + overflow: hidden; + padding: 0; +} + +div.main { + -webkit-box-orient: vertical; + background: -webkit-linear-gradient(#bababa, #868686) no-repeat; + display: -webkit-box; + left: 0; + position: absolute; + right: 0; + top: -10px; +} + +div.keyboard { + -webkit-box-flex: 1; + display: -webkit-box; + margin: 0 auto; + text-align: center; +} + +div.rows { + -webkit-box-flex: 1; + -webkit-box-orient: vertical; + display: -webkit-box; + margin-bottom: 5px; + text-align: center; +} + +div.row { + -webkit-box-flex: 1; + display: -webkit-box; + margin-right: 5px; + margin-top: 5px; +} + +div.row > div { + -webkit-box-flex: 1; + display: -webkit-box; +} + +.panel { + border: 0; + clear: both; + margin-left: 5px; + text-align: left; +} + +.backspace > div { + background-image: url('images/del.svg'); +} + +.tab > div { + background-image: url('images/tab.svg'); +} + +.return > div { + background-image: url('images/ret.svg'); +} + +.mic > div { + background-image: url('images/mic.svg'); +} + +.button { + background: -webkit-linear-gradient(rgb(90, 97, 111), rgb(80, 86, 98)); +} +.button:active { + background: -webkit-linear-gradient(rgb(80, 86, 98), rgb(90, 97, 111)); +} + +.auxiliary:active { + background: -webkit-linear-gradient(rgb(90, 97, 111), rgb(80, 86, 98)); +} + +.key { + -webkit-box-flex: 1; + background: -webkit-linear-gradient(#fff, #cacaca); + border: 1px solid transparent; + border-radius: 6px; + /* Reserving equivalent space to .key:active so + keys don't shift when selected. */ + /* Do not use box shadow until performance improves + * http://code.google.com/p/chromium/issues/detail?id=99045 + box-shadow: 0px 1px 1px #000; + */ + color: #535353; + display: -webkit-box; + font-family: sans-serif; + font-weight: 100; + margin-left: 5px; + position: relative; +} + +.key > div { + bottom: 0; + left: 0; + margin: auto; + position: absolute; + right: 0; + top: 0; +} + +.key:active { + background: -webkit-linear-gradient(#d6d6d6, #acacac); + border: 1px solid rgba(125,125,125,0.5); + /* Do not use box shadow until performance improves + * http://code.google.com/p/chromium/issues/detail?id=99045 + box-shadow: 0px 0px 15px #fff; + */ +} + +div.moddown { + background: -webkit-linear-gradient(#d6d6d6, #acacac); + border-color: rgb(48, 74, 155); +} + +.image-key { + background-position: center center; + background-repeat: no-repeat; + background-size: contain; + height: 100%; + width: 100%; +} + +.text-key { + height: 1.2em; +} + + +.shift > div.image-key { + background-image: url('images/shift.svg'); +} + +.moddown.shift > div.image-key { + background-image: url('images/shift-down.svg'); +} + +.hide > div { + background-image: url('images/keyboard.svg'); +} + +.at, +.tab, +.com, +.comma, +.hide, +.mic, +.period { + -webkit-box-flex: 1.3; +} + +.symbol { + -webkit-box-flex: 1.4; +} + +.return { + -webkit-box-flex: 1.5; +} + +.backspace { + -webkit-box-flex: 1.6; +} + +.left-shift { + -webkit-box-flex: 1.8; +} + +.right-shift { + -webkit-box-flex: 2.0; +} + +.space { + -webkit-box-flex: 4.8; +} + +.bar { + -webkit-box-flex: 0.6; +} + +.nodisplay { + display: none; +} diff --git a/ui/keyboard/resources/main.js b/ui/keyboard/resources/main.js new file mode 100644 index 0000000..a628cad --- /dev/null +++ b/ui/keyboard/resources/main.js @@ -0,0 +1,192 @@ +// Copyright (c) 2011 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. + +/** + * @fileoverview A simple virtual keyboard implementation. + */ + +/** + * The ratio of the row height to the font size. + * @type {number} + */ +/** @const */ var kFontSizeRatio = 3.5; + +/** + * Alias for document.getElementById. + * @param {string} id The ID of the element to find. + * @return {HTMLElement} The found element or null if not found. + */ +function $(id) { + return document.getElementById(id); +} + +/** + * Return the id attribute of the keyboard element for the given layout. + * @param {string} layout The keyboard layout. + * @return {string} The id attribute of the keyboard element. + */ +function getKeyboardId(layout) { + return 'keyboard_' + layout; +} + +/** + * Return the aspect ratio of the current keyboard. + * @return {number} The aspect ratio of the current keyboard. + */ +function getKeyboardAspect() { + return KEYBOARDS[currentKeyboardLayout]['aspect']; +} + +/** + * Calculate the height of the keyboard based on the size of the page. + * @return {number} The height of the keyboard in pixels. + */ +function getKeyboardHeight() { + var x = window.innerWidth; + var y = window.innerHeight; + return (x > getKeyboardAspect() * y) ? + y : Math.floor(x / getKeyboardAspect()); +} + +/** + * Create a DOM of the keyboard rows for the given keyboard layout. + * Do nothing if the DOM is already created. + * @param {string} layout The keyboard layout for which rows are created. + * @param {Element} element The DOM Element to which rows are appended. + * @param {boolean} autoPadding True if padding needs to be added to both side + * of the rows that have less keys. + */ +function initRows(layout, element, autoPadding) { + var keyboard = KEYBOARDS[layout]; + if ('rows' in keyboard) { + return; + } + var def = keyboard['definition']; + var rows = []; + for (var i = 0; i < def.length; ++i) { + rows.push(new Row(i, def[i])); + } + keyboard['rows'] = rows; + + var maxRowLength = -1; + for (var i = 0; i < rows.length; ++i) { + if (rows[i].length > maxRowLength) { + maxRowLength = rows[i].length; + } + } + + // A div element which holds rows for the layout. + var rowsDiv = document.createElement('div'); + rowsDiv.className = 'rows'; + for (var i = 0; i < rows.length; ++i) { + var rowDiv = rows[i].makeDOM(); + if (autoPadding && rows[i].length < maxRowLength) { + var padding = 50 * (maxRowLength - rows[i].length) / maxRowLength; + rowDiv.style.paddingLeft = padding + '%'; + rowDiv.style.paddingRight = padding + '%'; + } + rowsDiv.appendChild(rowDiv); + rows[i].showMode(currentMode); + } + keyboard['rowsDiv'] = rowsDiv; + element.appendChild(rowsDiv); +} + +/** + * Create a DOM of the keyboard for the given keyboard layout. + * Do nothing if the DOM is already created. + * @param {string} layout The keyboard layout for which keyboard is created. + * @param {Element} element The DOM Element to which keyboard is appended. + */ +function initKeyboard(layout, element) { + var keyboard = KEYBOARDS[layout]; + if (!keyboard || keyboard['keyboardDiv']) { + return; + } + var keyboardDiv = document.createElement('div'); + keyboardDiv.id = getKeyboardId(layout); + keyboardDiv.className = 'keyboard'; + initRows(layout, keyboardDiv); + keyboard['keyboardDiv'] = keyboardDiv; + window.onresize(); + element.appendChild(keyboardDiv); +} + +/** + * Resize the keyboard according to the new window size. + */ +window.onresize = function() { + var keyboardDiv = KEYBOARDS[currentKeyboardLayout]['keyboardDiv']; + var height = getKeyboardHeight(); + keyboardDiv.style.height = height + 'px'; + var mainDiv = $('main'); + mainDiv.style.width = Math.floor(getKeyboardAspect() * height) + 'px'; + var rowsLength = KEYBOARDS[currentKeyboardLayout]['rows'].length; + keyboardDiv.style.fontSize = (height / kFontSizeRatio / rowsLength) + 'px'; +}; + +/** + * Init the keyboard. + */ +var mainDiv = null; + +/** + * Initialize keyboard. + */ +window.onload = function() { + var body = $('b'); + + // Catch all unhandled touch events and prevent default, to prevent the + // keyboard from responding to gestures like double tap. + function disableGestures(evt) { + evt.preventDefault(); + } + body.addEventListener('touchstart', disableGestures); + body.addEventListener('touchmove', disableGestures); + body.addEventListener('touchend', disableGestures); + + mainDiv = document.createElement('div'); + mainDiv.className = 'main'; + mainDiv.id = 'main'; + body.appendChild(mainDiv); + + initKeyboard(currentKeyboardLayout, mainDiv); + + window.onhashchange(); +}; + +/** + * Switch the keyboard layout based on the current URL hash. + */ +window.onhashchange = function() { + var oldLayout = currentKeyboardLayout; + var newLayout = location.hash.replace(/^#/, ''); + if (oldLayout == newLayout) { + return; + } + + if (KEYBOARDS[newLayout] === undefined) { + // Unsupported layout. + newLayout = 'us'; + } + currentKeyboardLayout = newLayout; + + var mainDiv = $('main'); + initKeyboard(currentKeyboardLayout, mainDiv); + + [newLayout, oldLayout].forEach(function(layout) { + var visible = (layout == newLayout); + var keyboardDiv = KEYBOARDS[layout]['keyboardDiv']; + keyboardDiv.className = visible ? 'keyboard' : 'nodisplay'; + var canvas = KEYBOARDS[layout]['canvas']; + if (canvas !== undefined) { + if (!visible) { + canvas.clear(); + } + } + if (visible) { + window.onresize(); + } + }); +}; diff --git a/ui/keyboard/resources/manifest.json b/ui/keyboard/resources/manifest.json new file mode 100644 index 0000000..9076308 --- /dev/null +++ b/ui/keyboard/resources/manifest.json @@ -0,0 +1,14 @@ +{ + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCtEsRXms+bpXbcmBFljmWOKVkVPteGqY376YUY6CRcUNsYft98M41KO+oPURWfbauCErLyJb4Y1xcb4ZrRnwGoNSvLaTY/ij4bdUn8eNPtqviLLrHZCEBaNwHYFNPCOEQqvtmjZ+J0NGCgUbx2bUouD+BDDG30GeMfu7ArzB5RLQIDAQAB", + "name": "Virtual Keyboard", + "version": "0.0.1", + "manifest_version": 2, + "description": "Virtual Keyboard", + "incognito" : "split", + "chrome_url_overrides": { + "keyboard": "index.html" + }, + "permissions": [ + "experimental" + ] +} |