This repository has been archived by the owner on Sep 11, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 833
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7e5de92
commit a17d585
Showing
15 changed files
with
435 additions
and
717 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
/* | ||
Copyright 2021 Clemens Zeidler | ||
Copyright 2022 Šimon Brandner <[email protected]> | ||
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,16 +28,16 @@ export type KeyCombo = { | |
key?: string; | ||
|
||
/** On PC: ctrl is pressed; on Mac: meta is pressed */ | ||
ctrlOrCmd?: boolean; | ||
ctrlOrCmdKey?: boolean; | ||
|
||
altKey?: boolean; | ||
ctrlKey?: boolean; | ||
metaKey?: boolean; | ||
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); | ||
} | ||
} | ||
|
Oops, something went wrong.