This commit is contained in:
parent
7e5de9294c
commit
a17d585a12
15 changed files with 450 additions and 732 deletions
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
Copyright 2021 Clemens Zeidler
|
||||
Copyright 2022 Šimon Brandner <simon.bra.ag@gmail.com>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -14,127 +15,10 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { KeyBindingAction } from "./accessibility/KeyboardShortcuts";
|
||||
import { defaultBindingsProvider } from './KeyBindingsDefaults';
|
||||
import { isMac } from './Keyboard';
|
||||
|
||||
/** Actions for the chat message composer component */
|
||||
export enum MessageComposerAction {
|
||||
/** Send a message */
|
||||
Send = 'KeyBinding.sendMessageInComposer',
|
||||
/** Go backwards through the send history and use the message in composer view */
|
||||
SelectPrevSendHistory = 'KeyBinding.previousMessageInComposerHistory',
|
||||
/** Go forwards through the send history */
|
||||
SelectNextSendHistory = 'KeyBinding.nextMessageInComposerHistory',
|
||||
/** Start editing the user's last sent message */
|
||||
EditPrevMessage = 'KeyBinding.editPreviousMessage',
|
||||
/** Start editing the user's next sent message */
|
||||
EditNextMessage = 'KeyBinding.editNextMessage',
|
||||
/** Cancel editing a message or cancel replying to a message */
|
||||
CancelEditing = 'KeyBinding.cancelReplyInComposer',
|
||||
|
||||
/** Set bold format the current selection */
|
||||
FormatBold = 'KeyBinding.toggleBoldInComposer',
|
||||
/** Set italics format the current selection */
|
||||
FormatItalics = 'KeyBinding.toggleItalicsInComposer',
|
||||
/** Format the current selection as quote */
|
||||
FormatQuote = 'KeyBinding.toggleQuoteInComposer',
|
||||
/** Undo the last editing */
|
||||
EditUndo = 'KeyBinding.editUndoInComposer',
|
||||
/** Redo editing */
|
||||
EditRedo = 'KeyBinding.editRedoInComposer',
|
||||
/** Insert new line */
|
||||
NewLine = 'KeyBinding.newLineInComposer',
|
||||
/** Move the cursor to the start of the message */
|
||||
MoveCursorToStart = 'KeyBinding.jumpToStartInComposer',
|
||||
/** Move the cursor to the end of the message */
|
||||
MoveCursorToEnd = 'KeyBinding.jumpToEndInComposer',
|
||||
}
|
||||
|
||||
/** Actions for text editing autocompletion */
|
||||
export enum AutocompleteAction {
|
||||
/** Accepts chosen autocomplete selection */
|
||||
Complete = 'KeyBinding.completeAutocomplete',
|
||||
/** Accepts chosen autocomplete selection or,
|
||||
* if the autocompletion window is not shown, open the window and select the first selection */
|
||||
ForceComplete = 'KeyBinding.forceCompleteAutocomplete',
|
||||
/** Move to the previous autocomplete selection */
|
||||
PrevSelection = 'KeyBinding.previousOptionInAutoComplete',
|
||||
/** Move to the next autocomplete selection */
|
||||
NextSelection = 'KeyBinding.nextOptionInAutoComplete',
|
||||
/** Close the autocompletion window */
|
||||
Cancel = 'KeyBinding.cancelAutoComplete',
|
||||
}
|
||||
|
||||
/** Actions for the room list sidebar */
|
||||
export enum RoomListAction {
|
||||
/** Clear room list filter field */
|
||||
ClearSearch = 'KeyBinding.clearRoomFilter',
|
||||
/** Navigate up/down in the room list */
|
||||
PrevRoom = 'KeyBinding.downerRoom',
|
||||
/** Navigate down in the room list */
|
||||
NextRoom = 'KeyBinding.upperRoom',
|
||||
/** Select room from the room list */
|
||||
SelectRoom = 'KeyBinding.selectRoomInRoomList',
|
||||
/** Collapse room list section */
|
||||
CollapseSection = 'KeyBinding.collapseSectionInRoomList',
|
||||
/** Expand room list section, if already expanded, jump to first room in the selection */
|
||||
ExpandSection = 'KeyBinding.expandSectionInRoomList',
|
||||
}
|
||||
|
||||
/** Actions for the current room view */
|
||||
export enum RoomAction {
|
||||
/** Scroll up in the timeline */
|
||||
ScrollUp = 'KeyBinding.scrollUpInTimeline',
|
||||
/** Scroll down in the timeline */
|
||||
RoomScrollDown = 'KeyBinding.scrollDownInTimeline',
|
||||
/** Dismiss read marker and jump to bottom */
|
||||
DismissReadMarker = 'KeyBinding.dismissReadMarkerAndJumpToBottom',
|
||||
/** Jump to oldest unread message */
|
||||
JumpToOldestUnread = 'KeyBinding.jumpToOldestUnreadMessage',
|
||||
/** Upload a file */
|
||||
UploadFile = 'KeyBinding.uploadFileToRoom',
|
||||
/** Focus search message in a room (must be enabled) */
|
||||
FocusSearch = 'KeyBinding.searchInRoom',
|
||||
/** Jump to the first (downloaded) message in the room */
|
||||
JumpToFirstMessage = 'KeyBinding.jumpToFirstMessageInTimeline',
|
||||
/** Jump to the latest message in the room */
|
||||
JumpToLatestMessage = 'KeyBinding.jumpToLastMessageInTimeline',
|
||||
}
|
||||
|
||||
/** Actions for navigating do various menus, dialogs or screens */
|
||||
export enum NavigationAction {
|
||||
/** Jump to room search (search for a room) */
|
||||
FocusRoomSearch = 'KeyBinding.filterRooms',
|
||||
/** Toggle the space panel */
|
||||
ToggleSpacePanel = 'KeyBinding.toggleSpacePanel',
|
||||
/** Toggle the room side panel */
|
||||
ToggleRoomSidePanel = 'KeyBinding.toggleRightPanel',
|
||||
/** Toggle the user menu */
|
||||
ToggleUserMenu = 'KeyBinding.toggleTopLeftMenu',
|
||||
/** Toggle the short cut help dialog */
|
||||
OpenShortCutDialog = 'KeyBinding.showKeyBindingsSettings',
|
||||
/** Got to the Element home screen */
|
||||
GoToHome = 'KeyBinding.goToHomeView',
|
||||
/** Select prev room */
|
||||
SelectPrevRoom = 'KeyBinding.previousRoom',
|
||||
/** Select next room */
|
||||
SelectNextRoom = 'KeyBinding.nextRoom',
|
||||
/** Select prev room with unread messages */
|
||||
SelectPrevUnreadRoom = 'KeyBinding.previousUnreadRoom',
|
||||
/** Select next room with unread messages */
|
||||
SelectNextUnreadRoom = 'KeyBinding.nextUnreadRoom',
|
||||
}
|
||||
|
||||
/** Actions only available when labs are enabled */
|
||||
export enum LabsAction {
|
||||
/** Toggle visibility of hidden events */
|
||||
ToggleHiddenEventVisibility = 'KeyBinding.toggleHiddenEventVisibility',
|
||||
}
|
||||
|
||||
export type KeyBindingAction = (
|
||||
MessageComposerAction | AutocompleteAction | RoomListAction | RoomAction | NavigationAction | LabsAction
|
||||
);
|
||||
|
||||
/**
|
||||
* Represent a key combination.
|
||||
*
|
||||
|
@ -144,7 +28,7 @@ export type KeyCombo = {
|
|||
key?: string;
|
||||
|
||||
/** On PC: ctrl is pressed; on Mac: meta is pressed */
|
||||
ctrlOrCmd?: boolean;
|
||||
ctrlOrCmdKey?: boolean;
|
||||
|
||||
altKey?: boolean;
|
||||
ctrlKey?: boolean;
|
||||
|
@ -152,8 +36,8 @@ export type KeyCombo = {
|
|||
shiftKey?: boolean;
|
||||
};
|
||||
|
||||
export type KeyBinding<T extends string> = {
|
||||
action: T;
|
||||
export type KeyBinding = {
|
||||
action: KeyBindingAction;
|
||||
keyCombo: KeyCombo;
|
||||
};
|
||||
|
||||
|
@ -186,7 +70,7 @@ export function isKeyComboMatch(ev: KeyboardEvent | React.KeyboardEvent, combo:
|
|||
const evShift = ev.shiftKey ?? false;
|
||||
const evMeta = ev.metaKey ?? false;
|
||||
// When ctrlOrCmd is set, the keys need do evaluated differently on PC and Mac
|
||||
if (combo.ctrlOrCmd) {
|
||||
if (combo.ctrlOrCmdKey) {
|
||||
if (onMac) {
|
||||
if (!evMeta
|
||||
|| evCtrl !== comboCtrl
|
||||
|
@ -215,15 +99,10 @@ export function isKeyComboMatch(ev: KeyboardEvent | React.KeyboardEvent, combo:
|
|||
return true;
|
||||
}
|
||||
|
||||
export type KeyBindingGetter<T extends string> = () => KeyBinding<T>[];
|
||||
export type KeyBindingGetter = () => KeyBinding[];
|
||||
|
||||
export interface IKeyBindingsProvider {
|
||||
getMessageComposerBindings: KeyBindingGetter<MessageComposerAction>;
|
||||
getAutocompleteBindings: KeyBindingGetter<AutocompleteAction>;
|
||||
getRoomListBindings: KeyBindingGetter<RoomListAction>;
|
||||
getRoomBindings: KeyBindingGetter<RoomAction>;
|
||||
getNavigationBindings: KeyBindingGetter<NavigationAction>;
|
||||
getLabsBindings: KeyBindingGetter<LabsAction>;
|
||||
[key: string]: KeyBindingGetter;
|
||||
}
|
||||
|
||||
export class KeyBindingsManager {
|
||||
|
@ -242,10 +121,10 @@ export class KeyBindingsManager {
|
|||
/**
|
||||
* Finds a matching KeyAction for a given KeyboardEvent
|
||||
*/
|
||||
private getAction<T extends string>(
|
||||
getters: KeyBindingGetter<T>[],
|
||||
private getAction(
|
||||
getters: KeyBindingGetter[],
|
||||
ev: KeyboardEvent | React.KeyboardEvent,
|
||||
): T | undefined {
|
||||
): KeyBindingAction | undefined {
|
||||
for (const getter of getters) {
|
||||
const bindings = getter();
|
||||
const binding = bindings.find(it => isKeyComboMatch(ev, it.keyCombo, isMac));
|
||||
|
@ -256,27 +135,27 @@ export class KeyBindingsManager {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
getMessageComposerAction(ev: KeyboardEvent | React.KeyboardEvent): MessageComposerAction | undefined {
|
||||
getMessageComposerAction(ev: KeyboardEvent | React.KeyboardEvent): KeyBindingAction | undefined {
|
||||
return this.getAction(this.bindingsProviders.map(it => it.getMessageComposerBindings), ev);
|
||||
}
|
||||
|
||||
getAutocompleteAction(ev: KeyboardEvent | React.KeyboardEvent): AutocompleteAction | undefined {
|
||||
getAutocompleteAction(ev: KeyboardEvent | React.KeyboardEvent): KeyBindingAction | undefined {
|
||||
return this.getAction(this.bindingsProviders.map(it => it.getAutocompleteBindings), ev);
|
||||
}
|
||||
|
||||
getRoomListAction(ev: KeyboardEvent | React.KeyboardEvent): RoomListAction | undefined {
|
||||
getRoomListAction(ev: KeyboardEvent | React.KeyboardEvent): KeyBindingAction | undefined {
|
||||
return this.getAction(this.bindingsProviders.map(it => it.getRoomListBindings), ev);
|
||||
}
|
||||
|
||||
getRoomAction(ev: KeyboardEvent | React.KeyboardEvent): RoomAction | undefined {
|
||||
getRoomAction(ev: KeyboardEvent | React.KeyboardEvent): KeyBindingAction | undefined {
|
||||
return this.getAction(this.bindingsProviders.map(it => it.getRoomBindings), ev);
|
||||
}
|
||||
|
||||
getNavigationAction(ev: KeyboardEvent | React.KeyboardEvent): NavigationAction | undefined {
|
||||
getNavigationAction(ev: KeyboardEvent | React.KeyboardEvent): KeyBindingAction | undefined {
|
||||
return this.getAction(this.bindingsProviders.map(it => it.getNavigationBindings), ev);
|
||||
}
|
||||
|
||||
getLabsAction(ev: KeyboardEvent | React.KeyboardEvent): LabsAction | undefined {
|
||||
getLabsAction(ev: KeyboardEvent | React.KeyboardEvent): KeyBindingAction | undefined {
|
||||
return this.getAction(this.bindingsProviders.map(it => it.getLabsBindings), ev);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue