diff --git a/src/Keyboard.js b/src/Keyboard.js index 453ddab1e2..478d75acc1 100644 --- a/src/Keyboard.js +++ b/src/Keyboard.js @@ -1,6 +1,7 @@ /* Copyright 2016 OpenMarket Ltd Copyright 2017 New Vector Ltd +Copyright 2019 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,52 +16,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -/* a selection of key codes, as used in KeyboardEvent.keyCode */ -export const KeyCode = { - BACKSPACE: 8, - TAB: 9, - ENTER: 13, - SHIFT: 16, - ESCAPE: 27, - SPACE: 32, - PAGE_UP: 33, - PAGE_DOWN: 34, - END: 35, - HOME: 36, - LEFT: 37, - UP: 38, - RIGHT: 39, - DOWN: 40, - DELETE: 46, - KEY_A: 65, - KEY_B: 66, - KEY_C: 67, - KEY_D: 68, - KEY_E: 69, - KEY_F: 70, - KEY_G: 71, - KEY_H: 72, - KEY_I: 73, - KEY_J: 74, - KEY_K: 75, - KEY_L: 76, - KEY_M: 77, - KEY_N: 78, - KEY_O: 79, - KEY_P: 80, - KEY_Q: 81, - KEY_R: 82, - KEY_S: 83, - KEY_T: 84, - KEY_U: 85, - KEY_V: 86, - KEY_W: 87, - KEY_X: 88, - KEY_Y: 89, - KEY_Z: 90, - KEY_BACKTICK: 223, // DO NOT USE THIS: browsers disagree on backtick 192 vs 223 -}; - export const Key = { HOME: "Home", END: "End", @@ -80,13 +35,35 @@ export const Key = { SHIFT: "Shift", CONTEXT_MENU: "ContextMenu", + COMMA: ",", LESS_THAN: "<", GREATER_THAN: ">", BACKTICK: "`", SPACE: " ", + A: "a", B: "b", + C: "c", + D: "d", + E: "e", + F: "f", + G: "g", + H: "h", I: "i", + J: "j", K: "k", + L: "l", + M: "m", + N: "n", + O: "o", + P: "p", + Q: "q", + R: "r", + S: "s", + T: "t", + U: "u", + V: "v", + W: "w", + X: "x", Y: "y", Z: "z", }; diff --git a/src/async-components/views/dialogs/EncryptedEventDialog.js b/src/async-components/views/dialogs/EncryptedEventDialog.js index 145203136a..15bb1e046b 100644 --- a/src/async-components/views/dialogs/EncryptedEventDialog.js +++ b/src/async-components/views/dialogs/EncryptedEventDialog.js @@ -14,6 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ +import {Key} from "../../../Keyboard"; + const React = require("react"); import createReactClass from 'create-react-class'; import PropTypes from 'prop-types'; @@ -83,7 +85,7 @@ module.exports = createReactClass({ }, onKeyDown: function(e) { - if (e.keyCode === 27) { // escape + if (e.key === Key.ESCAPE) { e.stopPropagation(); e.preventDefault(); this.props.onFinished(false); diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js index 2fbd19c428..123ed7c4e1 100644 --- a/src/components/structures/RoomSubList.js +++ b/src/components/structures/RoomSubList.js @@ -25,7 +25,7 @@ import Unread from '../../Unread'; import * as RoomNotifs from '../../RoomNotifs'; import * as FormattingUtils from '../../utils/FormattingUtils'; import IndicatorScrollbar from './IndicatorScrollbar'; -import {Key, KeyCode} from '../../Keyboard'; +import {Key} from '../../Keyboard'; import { Group } from 'matrix-js-sdk'; import PropTypes from 'prop-types'; import RoomTile from "../views/rooms/RoomTile"; @@ -186,7 +186,7 @@ export default class RoomSubList extends React.PureComponent { dis.dispatch({ action: 'view_room', room_id: roomId, - clear_search: (ev && (ev.keyCode === KeyCode.ENTER || ev.keyCode === KeyCode.SPACE)), + clear_search: (ev && (ev.key === Key.ENTER || ev.key === Key.SPACE)), }); }; diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 8c05acf60a..739519a2b3 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -44,7 +44,7 @@ import ObjectUtils from '../../ObjectUtils'; import * as Rooms from '../../Rooms'; import eventSearch from '../../Searching'; -import { KeyCode, isOnlyCtrlOrCmdKeyEvent } from '../../Keyboard'; +import {isOnlyCtrlOrCmdKeyEvent, Key} from '../../Keyboard'; import MainSplit from './MainSplit'; import RightPanel from './RightPanel'; @@ -561,15 +561,15 @@ module.exports = createReactClass({ let handled = false; const ctrlCmdOnly = isOnlyCtrlOrCmdKeyEvent(ev); - switch (ev.keyCode) { - case KeyCode.KEY_D: + switch (ev.key) { + case Key.D: if (ctrlCmdOnly) { this.onMuteAudioClick(); handled = true; } break; - case KeyCode.KEY_E: + case Key.E: if (ctrlCmdOnly) { this.onMuteVideoClick(); handled = true; diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.js index 17583a22ed..f289720542 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.js @@ -17,7 +17,7 @@ limitations under the License. import React, {createRef} from "react"; import createReactClass from 'create-react-class'; import PropTypes from 'prop-types'; -import { KeyCode } from '../../Keyboard'; +import { Key } from '../../Keyboard'; import Timer from '../../utils/Timer'; import AutoHideScrollbar from "./AutoHideScrollbar"; @@ -532,26 +532,26 @@ module.exports = createReactClass({ * @param {object} ev the keyboard event */ handleScrollKey: function(ev) { - switch (ev.keyCode) { - case KeyCode.PAGE_UP: + switch (ev.key) { + case Key.PAGE_UP: if (!ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) { this.scrollRelative(-1); } break; - case KeyCode.PAGE_DOWN: + case Key.PAGE_DOWN: if (!ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) { this.scrollRelative(1); } break; - case KeyCode.HOME: + case Key.HOME: if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) { this.scrollToTop(); } break; - case KeyCode.END: + case Key.END: if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) { this.scrollToBottom(); } diff --git a/src/components/structures/SearchBox.js b/src/components/structures/SearchBox.js index 0aa2e15f4c..9090152de8 100644 --- a/src/components/structures/SearchBox.js +++ b/src/components/structures/SearchBox.js @@ -18,7 +18,7 @@ limitations under the License. import React, {createRef} from 'react'; import createReactClass from 'create-react-class'; import PropTypes from 'prop-types'; -import { KeyCode } from '../../Keyboard'; +import { Key } from '../../Keyboard'; import dis from '../../dispatcher'; import { throttle } from 'lodash'; import AccessibleButton from '../../components/views/elements/AccessibleButton'; @@ -93,8 +93,8 @@ module.exports = createReactClass({ }, 200, {trailing: true, leading: true}), _onKeyDown: function(ev) { - switch (ev.keyCode) { - case KeyCode.ESCAPE: + switch (ev.key) { + case Key.ESCAPE: this._clearSearch("keyboard"); break; } diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.js index 41283b5308..9d929d313b 100644 --- a/src/components/structures/TimelinePanel.js +++ b/src/components/structures/TimelinePanel.js @@ -34,7 +34,7 @@ const dis = require("../../dispatcher"); const ObjectUtils = require('../../ObjectUtils'); const Modal = require("../../Modal"); const UserActivity = require("../../UserActivity"); -import { KeyCode } from '../../Keyboard'; +import {Key} from '../../Keyboard'; import Timer from '../../utils/Timer'; import shouldHideEvent from '../../shouldHideEvent'; import EditorStateTransfer from '../../utils/EditorStateTransfer'; @@ -942,8 +942,7 @@ const TimelinePanel = createReactClass({ // jump to the live timeline on ctrl-end, rather than the end of the // timeline window. - if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey && - ev.keyCode == KeyCode.END) { + if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey && ev.key === Key.END) { this.jumpToLiveTimeline(); } else { this._messagePanel.current.handleScrollKey(ev); diff --git a/src/components/views/dialogs/AddressPickerDialog.js b/src/components/views/dialogs/AddressPickerDialog.js index 2be505a798..988d22b113 100644 --- a/src/components/views/dialogs/AddressPickerDialog.js +++ b/src/components/views/dialogs/AddressPickerDialog.js @@ -32,6 +32,7 @@ import IdentityAuthClient from '../../../IdentityAuthClient'; import { getDefaultIdentityServerUrl, useDefaultIdentityServer } from '../../../utils/IdentityServerUtils'; import { abbreviateUrl } from '../../../utils/UrlUtils'; import {sleep} from "../../../utils/promise"; +import {Key} from "../../../Keyboard"; const TRUNCATE_QUERY_LIST = 40; const QUERY_USER_DIRECTORY_DEBOUNCE_MS = 200; @@ -142,27 +143,27 @@ module.exports = createReactClass({ }, onKeyDown: function(e) { - if (e.keyCode === 27) { // escape + if (e.key === Key.ESCAPE) { e.stopPropagation(); e.preventDefault(); this.props.onFinished(false); - } else if (e.keyCode === 38) { // up arrow + } else if (e.key === Key.ARROW_UP) { e.stopPropagation(); e.preventDefault(); if (this.addressSelector) this.addressSelector.moveSelectionUp(); - } else if (e.keyCode === 40) { // down arrow + } else if (e.key === Key.ARROW_DOWN) { e.stopPropagation(); e.preventDefault(); if (this.addressSelector) this.addressSelector.moveSelectionDown(); - } else if (this.state.suggestedList.length > 0 && (e.keyCode === 188 || e.keyCode === 13 || e.keyCode === 9)) { // comma or enter or tab + } else if (this.state.suggestedList.length > 0 && [Key.COMMA, Key.ENTER, Key.TAB].includes(e.key)) { e.stopPropagation(); e.preventDefault(); if (this.addressSelector) this.addressSelector.chooseSelection(); - } else if (this._textinput.current.value.length === 0 && this.state.selectedList.length && e.keyCode === 8) { // backspace + } else if (this._textinput.current.value.length === 0 && this.state.selectedList.length && e.key === Key.BACKSPACE) { e.stopPropagation(); e.preventDefault(); this.onDismissed(this.state.selectedList.length - 1)(); - } else if (e.keyCode === 13) { // enter + } else if (e.key === Key.ENTER) { e.stopPropagation(); e.preventDefault(); if (this._textinput.current.value === '') { @@ -171,7 +172,7 @@ module.exports = createReactClass({ } else { this._addAddressesToList([this._textinput.current.value]); } - } else if (e.keyCode === 188 || e.keyCode === 9) { // comma or tab + } else if (e.key === Key.COMMA || e.key === Key.TAB) { e.stopPropagation(); e.preventDefault(); this._addAddressesToList([this._textinput.current.value]); diff --git a/src/components/views/dialogs/BaseDialog.js b/src/components/views/dialogs/BaseDialog.js index f7aae7c6da..6ba0b322c4 100644 --- a/src/components/views/dialogs/BaseDialog.js +++ b/src/components/views/dialogs/BaseDialog.js @@ -24,7 +24,7 @@ import classNames from 'classnames'; import { MatrixClient } from 'matrix-js-sdk'; -import { KeyCode } from '../../../Keyboard'; +import { Key } from '../../../Keyboard'; import AccessibleButton from '../elements/AccessibleButton'; import MatrixClientPeg from '../../../MatrixClientPeg'; import { _t } from "../../../languageHandler"; @@ -102,7 +102,7 @@ export default createReactClass({ if (this.props.onKeyDown) { this.props.onKeyDown(e); } - if (this.props.hasCancel && e.keyCode === KeyCode.ESCAPE) { + if (this.props.hasCancel && e.key === Key.ESCAPE) { e.stopPropagation(); e.preventDefault(); this.props.onFinished(false); diff --git a/src/components/views/dialogs/SetMxIdDialog.js b/src/components/views/dialogs/SetMxIdDialog.js index 0294c1c700..b3c6cc9378 100644 --- a/src/components/views/dialogs/SetMxIdDialog.js +++ b/src/components/views/dialogs/SetMxIdDialog.js @@ -21,7 +21,7 @@ import PropTypes from 'prop-types'; import sdk from '../../../index'; import MatrixClientPeg from '../../../MatrixClientPeg'; import classnames from 'classnames'; -import { KeyCode } from '../../../Keyboard'; +import { Key } from '../../../Keyboard'; import { _t } from '../../../languageHandler'; import { SAFE_LOCALPART_REGEX } from '../../../Registration'; @@ -101,7 +101,7 @@ export default createReactClass({ }, onKeyUp: function(ev) { - if (ev.keyCode === KeyCode.ENTER) { + if (ev.key === Key.ENTER) { this.onSubmit(); } }, diff --git a/src/components/views/elements/AccessibleButton.js b/src/components/views/elements/AccessibleButton.js index 1ccb7d0796..d708a44ab2 100644 --- a/src/components/views/elements/AccessibleButton.js +++ b/src/components/views/elements/AccessibleButton.js @@ -17,7 +17,7 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { KeyCode } from '../../../Keyboard'; +import {Key} from '../../../Keyboard'; /** * AccessibleButton is a generic wrapper for any element that should be treated @@ -40,23 +40,23 @@ export default function AccessibleButton(props) { // Browsers handle space and enter keypresses differently and we are only adjusting to the // inconsistencies here restProps.onKeyDown = function(e) { - if (e.keyCode === KeyCode.ENTER) { + if (e.key === Key.ENTER) { e.stopPropagation(); e.preventDefault(); return onClick(e); } - if (e.keyCode === KeyCode.SPACE) { + if (e.key === Key.SPACE) { e.stopPropagation(); e.preventDefault(); } }; restProps.onKeyUp = function(e) { - if (e.keyCode === KeyCode.SPACE) { + if (e.key === Key.SPACE) { e.stopPropagation(); e.preventDefault(); return onClick(e); } - if (e.keyCode === KeyCode.ENTER) { + if (e.key === Key.ENTER) { e.stopPropagation(); e.preventDefault(); } diff --git a/src/components/views/elements/ImageView.js b/src/components/views/elements/ImageView.js index b2f6d0abbb..2b27c27e78 100644 --- a/src/components/views/elements/ImageView.js +++ b/src/components/views/elements/ImageView.js @@ -28,6 +28,7 @@ const AccessibleButton = require('../../../components/views/elements/AccessibleB const Modal = require('../../../Modal'); const sdk = require('../../../index'); import { _t } from '../../../languageHandler'; +import {Key} from "../../../Keyboard"; export default class ImageView extends React.Component { static propTypes = { @@ -62,7 +63,7 @@ export default class ImageView extends React.Component { } onKeyDown = (ev) => { - if (ev.keyCode === 27) { // escape + if (ev.key === Key.ESCAPE) { ev.stopPropagation(); ev.preventDefault(); this.props.onFinished(); diff --git a/src/components/views/rooms/ForwardMessage.js b/src/components/views/rooms/ForwardMessage.js index 4a6c560d2c..ac803bb23d 100644 --- a/src/components/views/rooms/ForwardMessage.js +++ b/src/components/views/rooms/ForwardMessage.js @@ -20,7 +20,7 @@ import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; import { _t } from '../../../languageHandler'; import dis from '../../../dispatcher'; -import { KeyCode } from '../../../Keyboard'; +import {Key} from '../../../Keyboard'; module.exports = createReactClass({ @@ -52,8 +52,8 @@ module.exports = createReactClass({ }, _onKeyDown: function(ev) { - switch (ev.keyCode) { - case KeyCode.ESCAPE: + switch (ev.key) { + case Key.ESCAPE: this.props.onCancelClick(); break; } diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index cc92f7c750..a5d8492d99 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -33,7 +33,7 @@ import classNames from 'classnames'; import MatrixClientPeg from '../../../MatrixClientPeg'; import type {MatrixClient} from 'matrix-js-sdk/lib/matrix'; import {processCommandInput} from '../../../SlashCommands'; -import { KeyCode, isOnlyCtrlOrCmdKeyEvent } from '../../../Keyboard'; +import { isOnlyCtrlOrCmdKeyEvent, Key} from '../../../Keyboard'; import Modal from '../../../Modal'; import sdk from '../../../index'; import { _t } from '../../../languageHandler'; @@ -608,12 +608,12 @@ export default class MessageComposerInput extends React.Component { // Navigate autocomplete list with arrow keys if (this.autocomplete.countCompletions() > 0) { if (!(ev.ctrlKey || ev.shiftKey || ev.altKey || ev.metaKey)) { - switch (ev.keyCode) { - case KeyCode.UP: + switch (ev.key) { + case Key.ARROW_UP: this.autocomplete.moveSelection(-1); ev.preventDefault(); return true; - case KeyCode.DOWN: + case Key.ARROW_DOWN: this.autocomplete.moveSelection(+1); ev.preventDefault(); return true; @@ -623,38 +623,38 @@ export default class MessageComposerInput extends React.Component { // skip void nodes - see // https://github.com/ianstormtaylor/slate/issues/762#issuecomment-304855095 - if (ev.keyCode === KeyCode.LEFT) { + if (ev.key === Key.ARROW_LEFT) { this.direction = 'Previous'; - } else if (ev.keyCode === KeyCode.RIGHT) { + } else if (ev.key === Key.ARROW_RIGHT) { this.direction = 'Next'; } - switch (ev.keyCode) { - case KeyCode.ENTER: + switch (ev.key) { + case Key.ENTER: return this.handleReturn(ev, change); - case KeyCode.BACKSPACE: + case Key.BACKSPACE: return this.onBackspace(ev, change); - case KeyCode.UP: + case Key.ARROW_UP: return this.onVerticalArrow(ev, true); - case KeyCode.DOWN: + case Key.ARROW_DOWN: return this.onVerticalArrow(ev, false); - case KeyCode.TAB: + case Key.TAB: return this.onTab(ev); - case KeyCode.ESCAPE: + case Key.ESCAPE: return this.onEscape(ev); - case KeyCode.SPACE: + case Key.SPACE: return this.onSpace(ev, change); } if (isOnlyCtrlOrCmdKeyEvent(ev)) { const ctrlCmdCommand = { // C-m => Toggles between rich text and markdown modes - [KeyCode.KEY_M]: 'toggle-mode', - [KeyCode.KEY_B]: 'bold', - [KeyCode.KEY_I]: 'italic', - [KeyCode.KEY_U]: 'underlined', - [KeyCode.KEY_J]: 'inline-code', - }[ev.keyCode]; + [Key.M]: 'toggle-mode', + [Key.B]: 'bold', + [Key.I]: 'italic', + [Key.U]: 'underlined', + [Key.J]: 'inline-code', + }[ev.key]; if (ctrlCmdCommand) { ev.preventDefault(); // to prevent clashing with Mac's minimize window diff --git a/src/components/views/rooms/SearchBar.js b/src/components/views/rooms/SearchBar.js index 492c29a621..33697e8828 100644 --- a/src/components/views/rooms/SearchBar.js +++ b/src/components/views/rooms/SearchBar.js @@ -19,6 +19,7 @@ import createReactClass from 'create-react-class'; const classNames = require('classnames'); const AccessibleButton = require('../../../components/views/elements/AccessibleButton'); import { _t } from '../../../languageHandler'; +import {Key} from "../../../Keyboard"; module.exports = createReactClass({ displayName: 'SearchBar', @@ -42,11 +43,13 @@ module.exports = createReactClass({ }, onSearchChange: function(e) { - if (e.keyCode === 13) { // on enter... - this.onSearch(); - } - if (e.keyCode === 27) { // escape... - this.props.onCancelClick(); + switch (e.key) { + case Key.ENTER: + this.onSearch(); + break; + case Key.ESCAPE: + this.props.onCancelClick(); + break; } }, diff --git a/src/components/views/settings/IntegrationManager.js b/src/components/views/settings/IntegrationManager.js index 1ab17ca8a0..e97d9d4c64 100644 --- a/src/components/views/settings/IntegrationManager.js +++ b/src/components/views/settings/IntegrationManager.js @@ -20,6 +20,7 @@ import PropTypes from 'prop-types'; import sdk from '../../../index'; import { _t } from '../../../languageHandler'; import dis from '../../../dispatcher'; +import {Key} from "../../../Keyboard"; export default class IntegrationManager extends React.Component { static propTypes = { @@ -52,7 +53,7 @@ export default class IntegrationManager extends React.Component { } onKeyDown = (ev) => { - if (ev.keyCode === 27) { // escape + if (ev.key === Key.ESCAPE) { ev.stopPropagation(); ev.preventDefault(); this.props.onFinished();