From 036ede3379285cbe678d79aad3b9442dca8b31e6 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 5 Nov 2017 09:47:30 +0900 Subject: support mutliple modifiers for key bindings --- src/content/actions/setting.js | 16 ++++++++++++++- src/content/components/common/follow.js | 2 +- src/content/components/common/input.js | 21 ++------------------ src/content/components/common/keymapper.js | 23 +++++++++++++++++----- .../components/top-content/follow-controller.js | 2 +- src/content/reducers/input.js | 6 +++--- src/content/reducers/setting.js | 2 +- 7 files changed, 41 insertions(+), 31 deletions(-) (limited to 'src/content') diff --git a/src/content/actions/setting.js b/src/content/actions/setting.js index c874294..353dd24 100644 --- a/src/content/actions/setting.js +++ b/src/content/actions/setting.js @@ -1,9 +1,23 @@ import actions from 'content/actions'; +import * as keyUtils from 'shared/utils/keys'; const set = (value) => { + let maps = new Map(); + if (value.keymaps) { + let entries = Object.entries(value.keymaps).map((entry) => { + return [ + keyUtils.fromMapKeys(entry[0]), + entry[1], + ]; + }); + maps = new Map(entries); + } + return { type: actions.SETTING_SET, - value, + value: Object.assign({}, value, { + keymaps: maps, + }) }; }; diff --git a/src/content/components/common/follow.js b/src/content/components/common/follow.js index 83aeb0a..7a35105 100644 --- a/src/content/components/common/follow.js +++ b/src/content/components/common/follow.js @@ -46,7 +46,7 @@ export default class Follow { } this.win.parent.postMessage(JSON.stringify({ type: messages.FOLLOW_KEY_PRESS, - key, + key: key.key, }), '*'); return true; } diff --git a/src/content/components/common/input.js b/src/content/components/common/input.js index 8b1d35d..22b0a91 100644 --- a/src/content/components/common/input.js +++ b/src/content/components/common/input.js @@ -1,22 +1,5 @@ import * as dom from 'shared/utils/dom'; - -const modifierdKeyName = (name) => { - if (name.length === 1) { - return name.toUpperCase(); - } else if (name === 'Escape') { - return 'Esc'; - } - return name; -}; - -const mapKey = (e) => { - if (e.ctrlKey) { - return ''; - } else if (e.shiftKey && e.key.length !== 1) { - return ''; - } - return e.key; -}; +import * as keys from 'shared/utils/keys'; export default class InputComponent { constructor(target) { @@ -64,7 +47,7 @@ export default class InputComponent { return; } - let key = mapKey(e); + let key = keys.fromKeyboardEvent(e); for (let listener of this.onKeyListeners) { let stop = listener(key); diff --git a/src/content/components/common/keymapper.js b/src/content/components/common/keymapper.js index 1da3c0d..0abbc91 100644 --- a/src/content/components/common/keymapper.js +++ b/src/content/components/common/keymapper.js @@ -1,6 +1,19 @@ import * as inputActions from 'content/actions/input'; import * as operationActions from 'content/actions/operation'; import operations from 'shared/operations'; +import * as keyUtils from 'shared/utils/keys'; + +const mapStartsWith = (mapping, keys) => { + if (mapping.length < keys.length) { + return false; + } + for (let i = 0; i < keys.length; ++i) { + if (!keyUtils.equals(mapping[i], keys[i])) { + return false; + } + } + return true; +}; export default class KeymapperComponent { constructor(store) { @@ -14,14 +27,14 @@ export default class KeymapperComponent { let input = state.input; let keymaps = state.setting.keymaps; - let matched = Object.keys(keymaps).filter((keyStr) => { - return keyStr.startsWith(input.keys); + let matched = Array.from(keymaps.keys()).filter((mapping) => { + return mapStartsWith(mapping, input.keys); }); if (!state.addon.enabled) { // available keymaps are only ADDON_ENABLE and ADDON_TOGGLE_ENABLED if // the addon disabled matched = matched.filter((keys) => { - let type = keymaps[keys].type; + let type = keymaps.get(keys).type; return type === operations.ADDON_ENABLE || type === operations.ADDON_TOGGLE_ENABLED; }); @@ -30,10 +43,10 @@ export default class KeymapperComponent { this.store.dispatch(inputActions.clearKeys()); return false; } else if (matched.length > 1 || - matched.length === 1 && input.keys !== matched[0]) { + matched.length === 1 && input.keys.length < matched[0].length) { return true; } - let operation = keymaps[matched]; + let operation = keymaps.get(matched[0]); this.store.dispatch(operationActions.exec(operation)); this.store.dispatch(inputActions.clearKeys()); return true; diff --git a/src/content/components/top-content/follow-controller.js b/src/content/components/top-content/follow-controller.js index 38869e6..d373177 100644 --- a/src/content/components/top-content/follow-controller.js +++ b/src/content/components/top-content/follow-controller.js @@ -76,7 +76,7 @@ export default class FollowController { this.activate(); this.store.dispatch(followControllerActions.disable()); break; - case 'Escape': + case 'Esc': this.store.dispatch(followControllerActions.disable()); break; case 'Backspace': diff --git a/src/content/reducers/input.js b/src/content/reducers/input.js index 9457604..134aa95 100644 --- a/src/content/reducers/input.js +++ b/src/content/reducers/input.js @@ -1,18 +1,18 @@ import actions from 'content/actions'; const defaultState = { - keys: '' + keys: [] }; export default function reducer(state = defaultState, action = {}) { switch (action.type) { case actions.INPUT_KEY_PRESS: return Object.assign({}, state, { - keys: state.keys + action.key + keys: state.keys.concat([action.key]), }); case actions.INPUT_CLEAR_KEYS: return Object.assign({}, state, { - keys: '', + keys: [], }); default: return state; diff --git a/src/content/reducers/setting.js b/src/content/reducers/setting.js index b6f6c58..a54f5a3 100644 --- a/src/content/reducers/setting.js +++ b/src/content/reducers/setting.js @@ -1,7 +1,7 @@ import actions from 'content/actions'; const defaultState = { - keymaps: {}, + keymaps: new Map(), }; export default function reducer(state = defaultState, action = {}) { -- cgit v1.2.3