blob: de01ae98e4993a5a99bc8715c2218780844830d1 [file] [log] [blame]
// Copyright 2010-2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/**
* @fileoverview This file contains key transrator implementation.
*
*/
'use strict';
/**
* Function key mapping table.
* Keycode is defined on http://www.w3.org/TR/uievents/#keyboard-key-codes
* @const
* @type {!Object.<string, string>}
* @private
*/
mozc.FUNCTION_KEY_MAP_ = {
'HistoryBack': 'F1',
'HistoryForward': 'F2',
'BrowserRefresh': 'F3',
'ChromeOSFullscreen': 'F4',
'ChromeOSSwitchWindow': 'F5',
'BrightnessDown': 'F6',
'BrightnessUp': 'F7',
'AudioVolumeMute': 'F8',
'AudioVolumeDown': 'F9',
'AudioVolumeUp': 'F10'
};
/**
* Normal key code mapping table for JP keyboard.
* Keycode is defined on http://www.w3.org/TR/uievents/#keyboard-key-codes
* @const
* @type {!Object.<string, !Array.<string>>}
* @private
*/
mozc.KEY_CODE_MAP_JP_ = {
'Digit1': ['1', '!', '\u306C', '\u306C'], // 'ぬ', 'ぬ'
'Digit2': ['2', '"', '\u3075', '\u3075'], // 'ふ', 'ふ'
'Digit3': ['3', '#', '\u3042', '\u3041'], // 'あ', 'ぁ'
'Digit4': ['4', '$', '\u3046', '\u3045'], // 'う', 'ぅ'
'Digit5': ['5', '%', '\u3048', '\u3047'], // 'え', 'ぇ'
'Digit6': ['6', '&', '\u304A', '\u3049'], // 'お', 'ぉ'
'Digit7': ['7', '\'', '\u3084', '\u3083'], // 'や', 'ゃ'
'Digit8': ['8', '(', '\u3086', '\u3085'], // 'ゆ', 'ゅ'
'Digit9': ['9', ')', '\u3088', '\u3087'], // 'よ', 'ょ'
'Digit0': ['0', '0', '\u308F', '\u3092'], // 'わ', 'を'
'Minus': ['-', '=', '\u307B', '\u307B'], // 'ほ', 'ほ'
'Equal': ['^', '~', '\u3078', '\u3078'], // 'へ', 'へ'
'IntlYen': ['\\', '|', '\u30FC', '\u30FC'], // 'ー', 'ー'
'KeyQ': ['q', 'Q', '\u305F', '\u305F'], // 'た', 'た'
'KeyW': ['w', 'W', '\u3066', '\u3066'], // 'て', 'て'
'KeyE': ['e', 'E', '\u3044', '\u3043'], // 'い', 'ぃ'
'KeyR': ['r', 'R', '\u3059', '\u3059'], // 'す', 'す'
'KeyT': ['t', 'T', '\u304B', '\u304B'], // 'か', 'か'
'KeyY': ['y', 'Y', '\u3093', '\u3093'], // 'ん', 'ん'
'KeyU': ['u', 'U', '\u306A', '\u306A'], // 'な', 'な'
'KeyI': ['i', 'I', '\u306B', '\u306B'], // 'に', 'に'
'KeyO': ['o', 'O', '\u3089', '\u3089'], // 'ら', 'ら'
'KeyP': ['p', 'P', '\u305B', '\u305B'], // 'せ', 'せ'
'BracketLeft': ['@', '`', '\u309B', '\u309B'], // '゛', '゛'
'BracketRight': ['[', '{', '\u309C', '\u300C'], // '゜', '「'
'KeyA': ['a', 'A', '\u3061', '\u3061'], // 'ち', 'ち'
'KeyS': ['s', 'S', '\u3068', '\u3068'], // 'と', 'と'
'KeyD': ['d', 'D', '\u3057', '\u3057'], // 'し', 'し'
'KeyF': ['f', 'F', '\u306F', '\u306F'], // 'は', 'は'
'KeyG': ['g', 'G', '\u304D', '\u304D'], // 'き', 'き'
'KeyH': ['h', 'H', '\u304F', '\u304F'], // 'く', 'く'
'KeyJ': ['j', 'J', '\u307E', '\u307E'], // 'ま', 'ま'
'KeyK': ['k', 'K', '\u306E', '\u306E'], // 'の', 'の'
'KeyL': ['l', 'L', '\u308A', '\u308A'], // 'り', 'り'
'Semicolon': [';', '+', '\u308C', '\u308C'], // 'れ', 'れ'
'Quote': [':', '*', '\u3051', '\u3051'], // 'け', 'け'
'Backslash': [']', '}', '\u3080', '\u300D'], // 'む', '」'
'KeyZ': ['z', 'Z', '\u3064', '\u3063'], // 'つ', 'っ'
'KeyX': ['x', 'X', '\u3055', '\u3055'], // 'さ', 'さ'
'KeyC': ['c', 'C', '\u305D', '\u305D'], // 'そ', 'そ'
'KeyV': ['v', 'V', '\u3072', '\u3072'], // 'ひ', 'ひ'
'KeyB': ['b', 'B', '\u3053', '\u3053'], // 'こ', 'こ'
'KeyN': ['n', 'N', '\u307F', '\u307F'], // 'み', 'み'
'KeyM': ['m', 'M', '\u3082', '\u3082'], // 'も', 'も'
'Comma': [',', '<', '\u306D', '\u3001'], // 'ね', '、'
'Period': ['.', '>', '\u308B', '\u3002'], // 'る', '。'
'Slash': ['/', '?', '\u3081', '\u30FB'], // 'め', '・'
'IntlRo': ['\\', '_', '\u308D', '\u308D'] // 'ろ', 'ろ'
};
/**
* Normal key code mapping table for US keyboard.
* Keycode is defined on http://www.w3.org/TR/uievents/#keyboard-key-codes
* @const
* @type {!Object.<string, !Array.<string>>}
* @private
*/
mozc.KEY_CODE_MAP_US_ = {
'Backquote': ['`', '~', '\u308D', '\u308D'], // 'ろ', 'ろ'
'Digit1': ['1', '!', '\u306C', '\u306C'], // 'ぬ', 'ぬ'
'Digit2': ['2', '@', '\u3075', '\u3075'], // 'ふ', 'ふ'
'Digit3': ['3', '#', '\u3042', '\u3041'], // 'あ', 'ぁ'
'Digit4': ['4', '$', '\u3046', '\u3045'], // 'う', 'ぅ'
'Digit5': ['5', '%', '\u3048', '\u3047'], // 'え', 'ぇ'
'Digit6': ['6', '^', '\u304A', '\u3049'], // 'お', 'ぉ'
'Digit7': ['7', '&', '\u3084', '\u3083'], // 'や', 'ゃ'
'Digit8': ['8', '*', '\u3086', '\u3085'], // 'ゆ', 'ゅ'
'Digit9': ['9', '(', '\u3088', '\u3087'], // 'よ', 'ょ'
'Digit0': ['0', ')', '\u308F', '\u3092'], // 'わ', 'を'
'Minus': ['-', '_', '\u307B', '\u30FC'], // 'ほ', 'ー'
'Equal': ['=', '+', '\u3078', '\u3078'], // 'へ', 'へ'
'KeyQ': ['q', 'Q', '\u305F', '\u305F'], // 'た', 'た'
'KeyW': ['w', 'W', '\u3066', '\u3066'], // 'て', 'て'
'KeyE': ['e', 'E', '\u3044', '\u3043'], // 'い', 'ぃ'
'KeyR': ['r', 'R', '\u3059', '\u3059'], // 'す', 'す'
'KeyT': ['t', 'T', '\u304B', '\u304B'], // 'か', 'か'
'KeyY': ['y', 'Y', '\u3093', '\u3093'], // 'ん', 'ん'
'KeyU': ['u', 'U', '\u306A', '\u306A'], // 'な', 'な'
'KeyI': ['i', 'I', '\u306B', '\u306B'], // 'に', 'に'
'KeyO': ['o', 'O', '\u3089', '\u3089'], // 'ら', 'ら'
'KeyP': ['p', 'P', '\u305B', '\u305B'], // 'せ', 'せ'
'BracketLeft': ['[', '{', '\u309B', '\u309B'], // '゛', '゛'
'BracketRight': [']', '}', '\u309C', '\u300C'], // '゜', '「'
'Backslash': ['\\', '|', '\u3080', '\u300D'], // 'む', '」'
'KeyA': ['a', 'A', '\u3061', '\u3061'], // 'ち', 'ち'
'KeyS': ['s', 'S', '\u3068', '\u3068'], // 'と', 'と'
'KeyD': ['d', 'D', '\u3057', '\u3057'], // 'し', 'し'
'KeyF': ['f', 'F', '\u306F', '\u306F'], // 'は', 'は'
'KeyG': ['g', 'G', '\u304D', '\u304D'], // 'き', 'き'
'KeyH': ['h', 'H', '\u304F', '\u304F'], // 'く', 'く'
'KeyJ': ['j', 'J', '\u307E', '\u307E'], // 'ま', 'ま'
'KeyK': ['k', 'K', '\u306E', '\u306E'], // 'の', 'の'
'KeyL': ['l', 'L', '\u308A', '\u308A'], // 'り', 'り'
'Semicolon': [';', ':', '\u308C', '\u308C'], // 'れ', 'れ'
'Quote': ['\'', '\"', '\u3051', '\u3051'], // 'け', 'け'
'KeyZ': ['z', 'Z', '\u3064', '\u3063'], // 'つ', 'っ'
'KeyX': ['x', 'X', '\u3055', '\u3055'], // 'さ', 'さ'
'KeyC': ['c', 'C', '\u305D', '\u305D'], // 'そ', 'そ'
'KeyV': ['v', 'V', '\u3072', '\u3072'], // 'ひ', 'ひ'
'KeyB': ['b', 'B', '\u3053', '\u3053'], // 'こ', 'こ'
'KeyN': ['n', 'N', '\u307F', '\u307F'], // 'み', 'み'
'KeyM': ['m', 'M', '\u3082', '\u3082'], // 'も', 'も'
'Comma': [',', '<', '\u306D', '\u3001'], // 'ね', '、'
'Period': ['.', '>', '\u308B', '\u3002'], // 'る', '。'
'Slash': ['/', '?', '\u3081', '\u30FB'], // 'め', '・'
// for UK-keybord
'IntlBackslash': ['\\', '|', '', ''],
'IntlHash': ['#', '~', '', '']
};
/**
* Special key code mapping table for JP keyboard.
* Keycode is defined on http://www.w3.org/TR/uievents/#keyboard-key-codes
* @const
* @type {!Object.<string, string>}
* @private
*/
mozc.SPECIAL_KEY_CODE_MAP_JP_ = {
'Escape': 'ESCAPE',
'Backspace': 'BACKSPACE',
'Tab': 'TAB',
'Enter': 'ENTER',
'NumpadMultiply': 'MULTIPLY',
'Space': 'SPACE',
'CapsLock': 'CAPS_LOCK',
'KanaMode': 'KANA',
'PageUp': 'PAGE_UP',
'End': 'END',
'Delete': 'DEL',
'Home': 'HOME',
'PageDown': 'PAGE_DOWN',
'ArrowUp': 'UP',
'ArrowLeft': 'LEFT',
'ArrowRight': 'RIGHT',
'ArrowDown': 'DOWN',
'Numpad0': 'NUMPAD0',
'Numpad1': 'NUMPAD1',
'Numpad2': 'NUMPAD2',
'Numpad3': 'NUMPAD3',
'Numpad4': 'NUMPAD4',
'Numpad5': 'NUMPAD5',
'Numpad6': 'NUMPAD6',
'Numpad7': 'NUMPAD7',
'Numpad8': 'NUMPAD8',
'Numpad9': 'NUMPAD9',
'NumpadSubtract': 'SUBTRACT',
'NumpadAdd': 'ADD',
'NumpadDecimal': 'DECIMAL',
'NumpadEnter': 'SEPARATOR',
'NumpadDivide': 'DIVIDE'
};
/**
* Special key code mapping table for US keyboard.
* Keycode is defined on http://www.w3.org/TR/uievents/#keyboard-key-codes
* @const
* @type {!Object.<string, string>}
* @private
*/
mozc.SPECIAL_KEY_CODE_MAP_US_ = {
'Escape': 'ESCAPE',
'Backspace': 'BACKSPACE',
'Tab': 'TAB',
'Enter': 'ENTER',
'NumpadMultiply': 'MULTIPLY',
'Space': 'SPACE',
'CapsLock': 'CAPS_LOCK',
'KanaMode': 'KANA',
'PageUp': 'PAGE_UP',
'End': 'END',
'Delete': 'DEL',
'Home': 'HOME',
'PageDown': 'PAGE_DOWN',
'ArrowUp': 'UP',
'ArrowLeft': 'LEFT',
'ArrowRight': 'RIGHT',
'ArrowDown': 'DOWN',
'Numpad0': 'NUMPAD0',
'Numpad1': 'NUMPAD1',
'Numpad2': 'NUMPAD2',
'Numpad3': 'NUMPAD3',
'Numpad4': 'NUMPAD4',
'Numpad5': 'NUMPAD5',
'Numpad6': 'NUMPAD6',
'Numpad7': 'NUMPAD7',
'Numpad8': 'NUMPAD8',
'Numpad9': 'NUMPAD9',
'NumpadSubtract': 'SUBTRACT',
'NumpadAdd': 'ADD',
'NumpadDecimal': 'DECIMAL',
'NumpadEnter': 'SEPARATOR',
'NumpadDivide': 'DIVIDE'
};
/**
* The modifier key mask of Shift key.
* @type {number}
* @private
*/
mozc.SHIFT_KEY_MASK_ = 1;
/**
* The modifier key mask of Control key.
* @type {number}
* @private
*/
mozc.CTRL_KEY_MASK_ = 1 << 1;
/**
* The modifier key mask of Alternate key.
* @type {number}
* @private
*/
mozc.ALT_KEY_MASK_ = 1 << 2;
/**
* Modifier key mask table.
* @const
* @type {!Object.<string, number>}
* @private
*/
mozc.MODIFIER_KEY_CODE_MASK_MAP_ = {
'AltLeft': mozc.ALT_KEY_MASK_,
'AltRight': mozc.ALT_KEY_MASK_,
'ControlLeft': mozc.CTRL_KEY_MASK_,
'ControlRight': mozc.CTRL_KEY_MASK_,
'ShiftLeft': mozc.SHIFT_KEY_MASK_,
'ShiftRight': mozc.SHIFT_KEY_MASK_
};
/**
* Key translator
* @constructor
*/
mozc.KeyTranslator = function() {
/**
* Current modifier key status. It is used to handle the keyup event of
* modifier keys.
* @type {number}
* @private
*/
this.modifierKeyFlags_ = 0;
};
/**
* Translates modifier key event and returns Mozc's KeyEvent command message.
* @param {!ChromeKeyboardEvent} keyData key event data.
* @return {!mozc.KeyEvent} Mozc's KeyEvent command message.
* @private
*/
mozc.KeyTranslator.prototype.translateModifierKeyEvent_ = function(keyData) {
var keyEvent = /** @type {!mozc.KeyEvent} */ ({});
var currentModifierKey =
((keyData.shiftKey ? mozc.SHIFT_KEY_MASK_ : 0) +
(keyData.ctrlKey ? mozc.CTRL_KEY_MASK_ : 0) +
(keyData.altKey ? mozc.ALT_KEY_MASK_ : 0));
// To get the current status, calculates the exclusive OR.
currentModifierKey ^= mozc.MODIFIER_KEY_CODE_MASK_MAP_[keyData.code];
if (~this.modifierKeyFlags_ & currentModifierKey) {
// When new modifier key is pressed, overwrites modifierKeyFlags_.
this.modifierKeyFlags_ = currentModifierKey;
}
if (!this.modifierKeyFlags_ || currentModifierKey) {
// We only handle the last modifier key up event.
return keyEvent;
}
keyEvent.modifier_keys = [];
if (this.modifierKeyFlags_ & mozc.ALT_KEY_MASK_) {
keyEvent.modifier_keys.push('ALT');
}
if (this.modifierKeyFlags_ & mozc.CTRL_KEY_MASK_) {
keyEvent.modifier_keys.push('CTRL');
}
if (this.modifierKeyFlags_ & mozc.SHIFT_KEY_MASK_) {
keyEvent.modifier_keys.push('SHIFT');
}
// Clears modifierKeyFlags_.
this.modifierKeyFlags_ = 0;
return keyEvent;
};
/**
* Translates key down event and returns Mozc's KeyEvent command message.
* @param {!ChromeKeyboardEvent} keyData key event data.
* @param {boolean} isKanaMode Whether preedit method is KANA mode.
* @param {string} keyboardLayout current keyboard layout.
* @return {!mozc.KeyEvent} Mozc's KeyEvent command message.
* @private
*/
mozc.KeyTranslator.prototype.translateKeyDownEvent_ = function(keyData,
isKanaMode,
keyboardLayout) {
// Clears modifierKeyFlags_.
this.modifierKeyFlags_ = 0;
var specialKey = (keyboardLayout == 'jp') ?
mozc.SPECIAL_KEY_CODE_MAP_JP_[keyData.code] :
mozc.SPECIAL_KEY_CODE_MAP_US_[keyData.code];
// keyData.code of function keys are not correctly set. So we use keyData.key.
if (mozc.FUNCTION_KEY_MAP_[keyData.key]) {
specialKey = mozc.FUNCTION_KEY_MAP_[keyData.key];
}
var keyCodeMap = (keyboardLayout == 'jp') ?
mozc.KEY_CODE_MAP_JP_[keyData.code] :
mozc.KEY_CODE_MAP_US_[keyData.code];
var keyEvent = /** @type {!mozc.KeyEvent} */ ({});
if (specialKey) {
keyEvent.special_key = specialKey;
}
if (keyData.shiftKey && !keyData.altKey && !keyData.ctrlKey && keyCodeMap) {
// If the modifier is only Shift key and keyEvent is normal key, don't put
// any modifiers.
} else {
var modifiersKey = [];
if (keyData.altKey) {
modifiersKey.push('ALT');
}
if (keyData.ctrlKey) {
modifiersKey.push('CTRL');
}
if (keyData.shiftKey) {
modifiersKey.push('SHIFT');
}
if (modifiersKey.length) {
keyEvent.modifier_keys = modifiersKey;
}
}
if (keyCodeMap) {
keyEvent.key_code =
keyData.shiftKey && !keyData.altKey && !keyData.ctrlKey ?
keyCodeMap[1].charCodeAt(0) :
keyCodeMap[0].charCodeAt(0);
if (isKanaMode) {
keyEvent.key_string = keyData.shiftKey ? keyCodeMap[3] : keyCodeMap[2];
}
}
return keyEvent;
};
/**
* Translates key event and returns Mozc's KeyEvent command message.
* @param {!ChromeKeyboardEvent} keyData key event data.
* @param {boolean} isKanaMode Whether preedit method is KANA mode.
* @param {string} keyboardLayout current keyboard layout.
* @return {!mozc.KeyEvent} Mozc's KeyEvent command message.
*/
mozc.KeyTranslator.prototype.translateKeyEvent = function(keyData,
isKanaMode,
keyboardLayout) {
// Do not disturb taking screenshot.
if (keyData.ctrlKey && keyData.key == 'ChromeOSSwitchWindow') {
return /** @type {!mozc.KeyEvent} */ ({});
} else {
// Since IME API can't send the correct upper case alphabet.
// Need to make a transform first. JP IME use shift status to input upper
// case letter.
var key = keyData.key;
if (keyData.capsLock && key) {
if (key.toUpperCase() != key) {
keyData.shiftKey = !keyData.shiftKey;
}
}
if (mozc.MODIFIER_KEY_CODE_MASK_MAP_[keyData.code]) {
return this.translateModifierKeyEvent_(keyData);
} else if (keyData.type == 'keydown') {
return this.translateKeyDownEvent_(keyData, isKanaMode, keyboardLayout);
}
}
return /** @type {!mozc.KeyEvent} */ ({});
};