diff options
-rw-r--r-- | src/actions/input.js | 12 | ||||
-rw-r--r-- | src/components/background-input.js | 6 | ||||
-rw-r--r-- | src/components/background.js | 2 | ||||
-rw-r--r-- | src/components/content-input.js | 44 | ||||
-rw-r--r-- | src/content/index.js | 19 | ||||
-rw-r--r-- | src/reducers/input.js | 11 | ||||
-rw-r--r-- | src/shared/keys.js | 21 | ||||
-rw-r--r-- | test/actions/input.test.js | 11 | ||||
-rw-r--r-- | test/reducers/input.test.js | 22 | ||||
-rw-r--r-- | test/shared/keys.test.js | 31 |
10 files changed, 77 insertions, 102 deletions
diff --git a/src/actions/input.js b/src/actions/input.js index 07948a1..67788dd 100644 --- a/src/actions/input.js +++ b/src/actions/input.js @@ -1,10 +1,16 @@ import actions from '../actions'; -const keyPress = (code, ctrl) => { +const asKeymapChars = (key, ctrl) => { + if (ctrl) { + return '<C-' + key.toUpperCase() + '>'; + } + return key; +}; + +const keyPress = (key, ctrl) => { return { type: actions.INPUT_KEY_PRESS, - code, - ctrl + key: asKeymapChars(key, ctrl), }; }; diff --git a/src/components/background-input.js b/src/components/background-input.js index 9c6ef1c..4735d5a 100644 --- a/src/components/background-input.js +++ b/src/components/background-input.js @@ -1,5 +1,4 @@ import * as inputActions from '../actions/input'; -import * as keys from '../shared/keys'; import * as operationActions from '../actions/operation'; export default class BackgroundInputComponent { @@ -37,15 +36,14 @@ export default class BackgroundInputComponent { } handleKeysChanged(sender, input) { - let prefix = keys.asKeymapChars(input.keys); let matched = Object.keys(this.keymaps).filter((keyStr) => { - return keyStr.startsWith(prefix); + return keyStr.startsWith(input.keys); }); if (matched.length === 0) { this.store.dispatch(inputActions.clearKeys(), sender); return Promise.resolve(); } else if (matched.length > 1 || - matched.length === 1 && prefix !== matched[0]) { + matched.length === 1 && input.keys !== matched[0]) { return Promise.resolve(); } let operation = this.keymaps[matched]; diff --git a/src/components/background.js b/src/components/background.js index 4c5bb19..0585a04 100644 --- a/src/components/background.js +++ b/src/components/background.js @@ -35,7 +35,7 @@ export default class BackgroundComponent { switch (message.type) { case messages.KEYDOWN: return this.store.dispatch( - inputActions.keyPress(message.code, message.ctrl), sender); + inputActions.keyPress(message.key, message.ctrl), sender); case messages.OPEN_URL: if (message.newTab) { return this.store.dispatch( diff --git a/src/components/content-input.js b/src/components/content-input.js new file mode 100644 index 0000000..6437128 --- /dev/null +++ b/src/components/content-input.js @@ -0,0 +1,44 @@ +import messages from '../content/messages'; + +export default class ContentInputComponent { + constructor(target) { + this.pressed = {}; + + target.addEventListener('keypress', this.onKeyPress.bind(this)); + target.addEventListener('keydown', this.onKeyDown.bind(this)); + target.addEventListener('keyup', this.onKeyUp.bind(this)); + } + + onKeyPress(e) { + this.capture(e); + } + + onKeyDown(e) { + this.capture(e); + } + + onKeyUp(e) { + this.pressed[e.key] = false; + } + + capture(e) { + if (this.pressed[e.key]) { + return; + } + this.pressed[e.key] = true; + + if (e.target instanceof HTMLInputElement || + e.target instanceof HTMLTextAreaElement || + e.target instanceof HTMLSelectElement) { + if (e.key === 'Escape' && e.target.blur) { + e.target.blur(); + } + return; + } + browser.runtime.sendMessage({ + type: messages.KEYDOWN, + key: e.key, + ctrl: e.ctrlKey + }); + } +} diff --git a/src/content/index.js b/src/content/index.js index 0dbc8c1..655bea4 100644 --- a/src/content/index.js +++ b/src/content/index.js @@ -4,6 +4,7 @@ import * as scrolls from '../content/scrolls'; import * as navigates from '../content/navigates'; import * as followActions from '../actions/follow'; import * as store from '../store'; +import ContentInputComponent from '../components/content-input'; import FollowComponent from '../components/follow'; import followReducer from '../reducers/follow'; import operations from '../operations'; @@ -18,25 +19,11 @@ followStore.subscribe(() => { console.error(e); } }); +// eslint-disable-next-line no-unused-vars +const contentInputComponent = new ContentInputComponent(window); consoleFrames.initialize(window.document); -window.addEventListener('keypress', (e) => { - if (e.target instanceof HTMLInputElement || - e.target instanceof HTMLTextAreaElement || - e.target instanceof HTMLSelectElement) { - if (e.key === 'Escape' && e.target.blur) { - e.target.blur(); - } - return; - } - browser.runtime.sendMessage({ - type: messages.KEYDOWN, - code: e.which, - ctrl: e.ctrlKey - }); -}); - const execOperation = (operation) => { switch (operation.type) { case operations.SCROLL_LINES: diff --git a/src/reducers/input.js b/src/reducers/input.js index eb7ff24..8be701e 100644 --- a/src/reducers/input.js +++ b/src/reducers/input.js @@ -1,23 +1,18 @@ import actions from '../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.concat([ - { - code: action.code, - ctrl: action.ctrl - } - ]) + keys: state.keys + action.key }); case actions.INPUT_CLEAR_KEYS: return Object.assign({}, state, { - keys: [], + keys: '', }); default: return state; diff --git a/src/shared/keys.js b/src/shared/keys.js deleted file mode 100644 index aca050e..0000000 --- a/src/shared/keys.js +++ /dev/null @@ -1,21 +0,0 @@ -const asKeymapChars = (keys) => { - return keys.map((k) => { - let c = String.fromCharCode(k.code); - if (k.ctrl) { - return '<C-' + c.toUpperCase() + '>'; - } - return c; - }).join(''); -}; - -const asCaretChars = (keys) => { - return keys.map((k) => { - let c = String.fromCharCode(k.code); - if (k.ctrl) { - return '^' + c.toUpperCase(); - } - return c; - }).join(''); -}; - -export { asKeymapChars, asCaretChars }; diff --git a/test/actions/input.test.js b/test/actions/input.test.js index 9ec6de4..904d3e7 100644 --- a/test/actions/input.test.js +++ b/test/actions/input.test.js @@ -5,10 +5,15 @@ import * as inputActions from '../../src/actions/input'; describe("input actions", () => { describe("keyPress", () => { it('create INPUT_KEY_PRESS action', () => { - let action = inputActions.keyPress(123, true); + let action = inputActions.keyPress('a', false); expect(action.type).to.equal(actions.INPUT_KEY_PRESS); - expect(action.code).to.equal(123); - expect(action.ctrl).to.be.true; + expect(action.key).to.equal('a'); + }); + + it('create INPUT_KEY_PRESS action from key with ctrl', () => { + let action = inputActions.keyPress('b', true); + expect(action.type).to.equal(actions.INPUT_KEY_PRESS); + expect(action.key).to.equal('<C-B>'); }); }); diff --git a/test/reducers/input.test.js b/test/reducers/input.test.js index d7a0855..3c3bf39 100644 --- a/test/reducers/input.test.js +++ b/test/reducers/input.test.js @@ -5,30 +5,22 @@ import inputReducer from '../../src/reducers/input'; describe("input reducer", () => { it('return the initial state', () => { let state = inputReducer(undefined, {}); - expect(state).to.have.deep.property('keys', []); + expect(state).to.have.deep.property('keys', ''); }); it('return next state for INPUT_KEY_PRESS', () => { - let action = { type: actions.INPUT_KEY_PRESS, code: 123, ctrl: true }; + let action = { type: actions.INPUT_KEY_PRESS, key: 'a' }; let state = inputReducer(undefined, action); - expect(state).to.have.deep.property('keys', [{ code: 123, ctrl: true }]); + expect(state).to.have.deep.property('keys', 'a'); - action = { type: actions.INPUT_KEY_PRESS, code: 456, ctrl: false }; + action = { type: actions.INPUT_KEY_PRESS, key: '<C-B>' }; state = inputReducer(state, action); - expect(state).to.have.deep.property('keys', [ - { code: 123, ctrl: true }, - { code: 456, ctrl: false } - ]); + expect(state).to.have.deep.property('keys', 'a<C-B>'); }); it('return next state for INPUT_CLEAR_KEYS', () => { let action = { type: actions.INPUT_CLEAR_KEYS }; - let state = inputReducer({ - keys: [ - { code: 123, ctrl: true }, - { code: 456, ctrl: false } - ] - }, action); - expect(state).to.have.deep.property('keys', []); + let state = inputReducer({ keys: 'abc' }, action); + expect(state).to.have.deep.property('keys', ''); }); }); diff --git a/test/shared/keys.test.js b/test/shared/keys.test.js deleted file mode 100644 index 53c953d..0000000 --- a/test/shared/keys.test.js +++ /dev/null @@ -1,31 +0,0 @@ -import { expect } from "chai"; -import * as keys from '../../src/shared/keys'; - -describe("keys", () => { - const KEYMAP = { - 'g<C-X>GG': [], - 'gg': { type: 'scroll.top' }, - }; - - const g = 'g'.charCodeAt(0); - const G = 'G'.charCodeAt(0); - const x = 'x'.charCodeAt(0); - - describe('#asKeymapChars', () => { - let keySequence = [ - { code: g }, - { code: x, ctrl: true }, - { code: G } - ]; - expect(keys.asKeymapChars(keySequence)).to.equal('g<C-X>G'); - }); - - describe('#asCaretChars', () => { - let keySequence = [ - { code: g }, - { code: x, ctrl: true }, - { code: G } - ]; - expect(keys.asCaretChars(keySequence)).to.equal('g^XG'); - }); -}); |