parent
7e5de9294c
commit
a17d585a12
|
@ -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,134 +15,55 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
AutocompleteAction,
|
||||
IKeyBindingsProvider,
|
||||
KeyBinding,
|
||||
MessageComposerAction,
|
||||
NavigationAction,
|
||||
RoomAction,
|
||||
RoomListAction,
|
||||
LabsAction,
|
||||
} from "./KeyBindingsManager";
|
||||
import { isMac, Key } from "./Keyboard";
|
||||
import SettingsStore from "./settings/SettingsStore";
|
||||
import SdkConfig from "./SdkConfig";
|
||||
import {
|
||||
IKeyBindingsProvider,
|
||||
KeyBinding,
|
||||
KeyCombo,
|
||||
} from "./KeyBindingsManager";
|
||||
import {
|
||||
CATEGORIES,
|
||||
CategoryName,
|
||||
getCustomizableShortcuts,
|
||||
KeyBindingAction,
|
||||
} from "./accessibility/KeyboardShortcuts";
|
||||
|
||||
export const getBindingsByCategory = (
|
||||
category: CategoryName,
|
||||
): KeyBinding[] => {
|
||||
return CATEGORIES[category].settingNames.reduce((bindings, name) => {
|
||||
const value = getCustomizableShortcuts()[name]?.default;
|
||||
if (value) {
|
||||
bindings.push({
|
||||
action: name as KeyBindingAction,
|
||||
keyCombo: value as KeyCombo,
|
||||
});
|
||||
}
|
||||
return bindings;
|
||||
}, []);
|
||||
};
|
||||
|
||||
const messageComposerBindings = (): KeyBinding[] => {
|
||||
const bindings = getBindingsByCategory(CategoryName.COMPOSER);
|
||||
|
||||
const messageComposerBindings = (): KeyBinding<MessageComposerAction>[] => {
|
||||
const bindings: KeyBinding<MessageComposerAction>[] = [
|
||||
{
|
||||
action: MessageComposerAction.SelectPrevSendHistory,
|
||||
keyCombo: {
|
||||
key: Key.ARROW_UP,
|
||||
altKey: true,
|
||||
ctrlKey: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: MessageComposerAction.SelectNextSendHistory,
|
||||
keyCombo: {
|
||||
key: Key.ARROW_DOWN,
|
||||
altKey: true,
|
||||
ctrlKey: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: MessageComposerAction.EditPrevMessage,
|
||||
keyCombo: {
|
||||
key: Key.ARROW_UP,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: MessageComposerAction.EditNextMessage,
|
||||
keyCombo: {
|
||||
key: Key.ARROW_DOWN,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: MessageComposerAction.CancelEditing,
|
||||
keyCombo: {
|
||||
key: Key.ESCAPE,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: MessageComposerAction.FormatBold,
|
||||
keyCombo: {
|
||||
key: Key.B,
|
||||
ctrlOrCmd: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: MessageComposerAction.FormatItalics,
|
||||
keyCombo: {
|
||||
key: Key.I,
|
||||
ctrlOrCmd: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: MessageComposerAction.FormatQuote,
|
||||
keyCombo: {
|
||||
key: Key.GREATER_THAN,
|
||||
ctrlOrCmd: true,
|
||||
shiftKey: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: MessageComposerAction.EditUndo,
|
||||
keyCombo: {
|
||||
key: Key.Z,
|
||||
ctrlOrCmd: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: MessageComposerAction.MoveCursorToStart,
|
||||
keyCombo: {
|
||||
key: Key.HOME,
|
||||
ctrlOrCmd: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: MessageComposerAction.MoveCursorToEnd,
|
||||
keyCombo: {
|
||||
key: Key.END,
|
||||
ctrlOrCmd: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
if (isMac) {
|
||||
bindings.push({
|
||||
action: MessageComposerAction.EditRedo,
|
||||
keyCombo: {
|
||||
key: Key.Z,
|
||||
ctrlOrCmd: true,
|
||||
shiftKey: true,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
bindings.push({
|
||||
action: MessageComposerAction.EditRedo,
|
||||
keyCombo: {
|
||||
key: Key.Y,
|
||||
ctrlOrCmd: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
if (SettingsStore.getValue('MessageComposerInput.ctrlEnterToSend')) {
|
||||
bindings.push({
|
||||
action: MessageComposerAction.Send,
|
||||
action: KeyBindingAction.SendMessage,
|
||||
keyCombo: {
|
||||
key: Key.ENTER,
|
||||
ctrlOrCmd: true,
|
||||
ctrlOrCmdKey: true,
|
||||
},
|
||||
});
|
||||
bindings.push({
|
||||
action: MessageComposerAction.NewLine,
|
||||
action: KeyBindingAction.NewLine,
|
||||
keyCombo: {
|
||||
key: Key.ENTER,
|
||||
},
|
||||
});
|
||||
bindings.push({
|
||||
action: MessageComposerAction.NewLine,
|
||||
action: KeyBindingAction.NewLine,
|
||||
keyCombo: {
|
||||
key: Key.ENTER,
|
||||
shiftKey: true,
|
||||
|
@ -149,13 +71,13 @@ const messageComposerBindings = (): KeyBinding<MessageComposerAction>[] => {
|
|||
});
|
||||
} else {
|
||||
bindings.push({
|
||||
action: MessageComposerAction.Send,
|
||||
action: KeyBindingAction.SendMessage,
|
||||
keyCombo: {
|
||||
key: Key.ENTER,
|
||||
},
|
||||
});
|
||||
bindings.push({
|
||||
action: MessageComposerAction.NewLine,
|
||||
action: KeyBindingAction.NewLine,
|
||||
keyCombo: {
|
||||
key: Key.ENTER,
|
||||
shiftKey: true,
|
||||
|
@ -163,7 +85,7 @@ const messageComposerBindings = (): KeyBinding<MessageComposerAction>[] => {
|
|||
});
|
||||
if (isMac) {
|
||||
bindings.push({
|
||||
action: MessageComposerAction.NewLine,
|
||||
action: KeyBindingAction.NewLine,
|
||||
keyCombo: {
|
||||
key: Key.ENTER,
|
||||
altKey: true,
|
||||
|
@ -171,156 +93,56 @@ const messageComposerBindings = (): KeyBinding<MessageComposerAction>[] => {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
return bindings;
|
||||
};
|
||||
|
||||
const autocompleteBindings = (): KeyBinding<AutocompleteAction>[] => {
|
||||
return [
|
||||
{
|
||||
action: AutocompleteAction.ForceComplete,
|
||||
keyCombo: {
|
||||
key: Key.TAB,
|
||||
},
|
||||
const autocompleteBindings = (): KeyBinding[] => {
|
||||
const bindings = getBindingsByCategory(CategoryName.AUTOCOMPLETE);
|
||||
|
||||
bindings.push({
|
||||
action: KeyBindingAction.ForceCompleteAutocomplete,
|
||||
keyCombo: {
|
||||
key: Key.TAB,
|
||||
},
|
||||
{
|
||||
action: AutocompleteAction.ForceComplete,
|
||||
keyCombo: {
|
||||
key: Key.TAB,
|
||||
ctrlKey: true,
|
||||
},
|
||||
});
|
||||
bindings.push({
|
||||
action: KeyBindingAction.ForceCompleteAutocomplete,
|
||||
keyCombo: {
|
||||
key: Key.TAB,
|
||||
ctrlKey: true,
|
||||
},
|
||||
{
|
||||
action: AutocompleteAction.Complete,
|
||||
keyCombo: {
|
||||
key: Key.ENTER,
|
||||
},
|
||||
});
|
||||
bindings.push({
|
||||
action: KeyBindingAction.CompleteAutocomplete,
|
||||
keyCombo: {
|
||||
key: Key.ENTER,
|
||||
},
|
||||
{
|
||||
action: AutocompleteAction.Complete,
|
||||
keyCombo: {
|
||||
key: Key.ENTER,
|
||||
ctrlKey: true,
|
||||
},
|
||||
});
|
||||
bindings.push({
|
||||
action: KeyBindingAction.CompleteAutocomplete,
|
||||
keyCombo: {
|
||||
key: Key.ENTER,
|
||||
ctrlKey: true,
|
||||
},
|
||||
{
|
||||
action: AutocompleteAction.Cancel,
|
||||
keyCombo: {
|
||||
key: Key.ESCAPE,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: AutocompleteAction.PrevSelection,
|
||||
keyCombo: {
|
||||
key: Key.ARROW_UP,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: AutocompleteAction.NextSelection,
|
||||
keyCombo: {
|
||||
key: Key.ARROW_DOWN,
|
||||
},
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
return bindings;
|
||||
};
|
||||
|
||||
const roomListBindings = (): KeyBinding<RoomListAction>[] => {
|
||||
return [
|
||||
{
|
||||
action: RoomListAction.ClearSearch,
|
||||
keyCombo: {
|
||||
key: Key.ESCAPE,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: RoomListAction.PrevRoom,
|
||||
keyCombo: {
|
||||
key: Key.ARROW_UP,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: RoomListAction.NextRoom,
|
||||
keyCombo: {
|
||||
key: Key.ARROW_DOWN,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: RoomListAction.SelectRoom,
|
||||
keyCombo: {
|
||||
key: Key.ENTER,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: RoomListAction.CollapseSection,
|
||||
keyCombo: {
|
||||
key: Key.ARROW_LEFT,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: RoomListAction.ExpandSection,
|
||||
keyCombo: {
|
||||
key: Key.ARROW_RIGHT,
|
||||
},
|
||||
},
|
||||
];
|
||||
const roomListBindings = (): KeyBinding[] => {
|
||||
return getBindingsByCategory(CategoryName.ROOM_LIST);
|
||||
};
|
||||
|
||||
const roomBindings = (): KeyBinding<RoomAction>[] => {
|
||||
const bindings: KeyBinding<RoomAction>[] = [
|
||||
{
|
||||
action: RoomAction.ScrollUp,
|
||||
keyCombo: {
|
||||
key: Key.PAGE_UP,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: RoomAction.RoomScrollDown,
|
||||
keyCombo: {
|
||||
key: Key.PAGE_DOWN,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: RoomAction.DismissReadMarker,
|
||||
keyCombo: {
|
||||
key: Key.ESCAPE,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: RoomAction.JumpToOldestUnread,
|
||||
keyCombo: {
|
||||
key: Key.PAGE_UP,
|
||||
shiftKey: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: RoomAction.UploadFile,
|
||||
keyCombo: {
|
||||
key: Key.U,
|
||||
ctrlOrCmd: true,
|
||||
shiftKey: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: RoomAction.JumpToFirstMessage,
|
||||
keyCombo: {
|
||||
key: Key.HOME,
|
||||
ctrlKey: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: RoomAction.JumpToLatestMessage,
|
||||
keyCombo: {
|
||||
key: Key.END,
|
||||
ctrlKey: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
const roomBindings = (): KeyBinding[] => {
|
||||
const bindings = getBindingsByCategory(CategoryName.ROOM);
|
||||
|
||||
if (SettingsStore.getValue('ctrlFForSearch')) {
|
||||
bindings.push({
|
||||
action: RoomAction.FocusSearch,
|
||||
action: KeyBindingAction.SearchInRoom,
|
||||
keyCombo: {
|
||||
key: Key.F,
|
||||
ctrlOrCmd: true,
|
||||
ctrlOrCmdKey: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -328,113 +150,14 @@ const roomBindings = (): KeyBinding<RoomAction>[] => {
|
|||
return bindings;
|
||||
};
|
||||
|
||||
const navigationBindings = (): KeyBinding<NavigationAction>[] => {
|
||||
return [
|
||||
{
|
||||
action: NavigationAction.FocusRoomSearch,
|
||||
keyCombo: {
|
||||
key: Key.K,
|
||||
ctrlOrCmd: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: NavigationAction.ToggleSpacePanel,
|
||||
keyCombo: {
|
||||
key: Key.D,
|
||||
ctrlOrCmd: true,
|
||||
shiftKey: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: NavigationAction.ToggleRoomSidePanel,
|
||||
keyCombo: {
|
||||
key: Key.PERIOD,
|
||||
ctrlOrCmd: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: NavigationAction.ToggleUserMenu,
|
||||
// Ideally this would be CTRL+P for "Profile", but that's
|
||||
// taken by the print dialog. CTRL+I for "Information"
|
||||
// was previously chosen but conflicted with italics in
|
||||
// composer, so CTRL+` it is
|
||||
keyCombo: {
|
||||
key: Key.BACKTICK,
|
||||
ctrlOrCmd: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: NavigationAction.OpenShortCutDialog,
|
||||
keyCombo: {
|
||||
key: Key.SLASH,
|
||||
ctrlOrCmd: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: NavigationAction.OpenShortCutDialog,
|
||||
keyCombo: {
|
||||
key: Key.SLASH,
|
||||
ctrlOrCmd: true,
|
||||
shiftKey: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: NavigationAction.GoToHome,
|
||||
keyCombo: {
|
||||
key: Key.H,
|
||||
ctrlOrCmd: true,
|
||||
altKey: !isMac,
|
||||
shiftKey: isMac,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: NavigationAction.SelectPrevRoom,
|
||||
keyCombo: {
|
||||
key: Key.ARROW_UP,
|
||||
altKey: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: NavigationAction.SelectNextRoom,
|
||||
keyCombo: {
|
||||
key: Key.ARROW_DOWN,
|
||||
altKey: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: NavigationAction.SelectPrevUnreadRoom,
|
||||
keyCombo: {
|
||||
key: Key.ARROW_UP,
|
||||
altKey: true,
|
||||
shiftKey: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
action: NavigationAction.SelectNextUnreadRoom,
|
||||
keyCombo: {
|
||||
key: Key.ARROW_DOWN,
|
||||
altKey: true,
|
||||
shiftKey: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
const navigationBindings = (): KeyBinding[] => {
|
||||
return getBindingsByCategory(CategoryName.NAVIGATION);
|
||||
};
|
||||
|
||||
const labsBindings = (): KeyBinding<LabsAction>[] => {
|
||||
if (!SdkConfig.get()['showLabsSettings']) {
|
||||
return [];
|
||||
}
|
||||
const labsBindings = (): KeyBinding[] => {
|
||||
if (!SdkConfig.get()['showLabsSettings']) return [];
|
||||
|
||||
return [
|
||||
{
|
||||
action: LabsAction.ToggleHiddenEventVisibility,
|
||||
keyCombo: {
|
||||
key: Key.H,
|
||||
ctrlOrCmd: true,
|
||||
shiftKey: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
return getBindingsByCategory(CategoryName.LABS);
|
||||
};
|
||||
|
||||
export const defaultBindingsProvider: IKeyBindingsProvider = {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,15 +19,104 @@ import { _td } from "../languageHandler";
|
|||
import { isMac, Key } from "../Keyboard";
|
||||
import { ISetting } from "../settings/Settings";
|
||||
import SettingsStore from "../settings/SettingsStore";
|
||||
import {
|
||||
AutocompleteAction,
|
||||
KeyBindingAction,
|
||||
LabsAction,
|
||||
MessageComposerAction,
|
||||
NavigationAction,
|
||||
RoomAction,
|
||||
RoomListAction,
|
||||
} from "../KeyBindingsManager";
|
||||
|
||||
export enum KeyBindingAction {
|
||||
/** Send a message */
|
||||
SendMessage = '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 */
|
||||
CancelReplyOrEdit = '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',
|
||||
|
||||
/** Accepts chosen autocomplete selection */
|
||||
CompleteAutocomplete = 'KeyBinding.completeAutocomplete',
|
||||
/** Accepts chosen autocomplete selection or,
|
||||
* if the autocompletion window is not shown, open the window and select the first selection */
|
||||
ForceCompleteAutocomplete = 'KeyBinding.forceCompleteAutocomplete',
|
||||
/** Move to the previous autocomplete selection */
|
||||
PrevSelectionInAutocomplete = 'KeyBinding.previousOptionInAutoComplete',
|
||||
/** Move to the next autocomplete selection */
|
||||
NextSelectionInAutocomplete = 'KeyBinding.nextOptionInAutoComplete',
|
||||
/** Close the autocompletion window */
|
||||
CancelAutocomplete = 'KeyBinding.cancelAutoComplete',
|
||||
|
||||
/** Clear room list filter field */
|
||||
ClearRoomFilter = '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 */
|
||||
SelectRoomInRoomList = 'KeyBinding.selectRoomInRoomList',
|
||||
/** Collapse room list section */
|
||||
CollapseRoomListSection = 'KeyBinding.collapseSectionInRoomList',
|
||||
/** Expand room list section, if already expanded, jump to first room in the selection */
|
||||
ExpandRoomListSection = 'KeyBinding.expandSectionInRoomList',
|
||||
|
||||
/** Scroll up in the timeline */
|
||||
ScrollUp = 'KeyBinding.scrollUpInTimeline',
|
||||
/** Scroll down in the timeline */
|
||||
ScrollDown = '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) */
|
||||
SearchInRoom = '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',
|
||||
|
||||
/** Jump to room search (search for a room) */
|
||||
FilterRooms = '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 */
|
||||
ShowKeyboardSettings = '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',
|
||||
|
||||
/** Toggle visibility of hidden events */
|
||||
ToggleHiddenEventVisibility = 'KeyBinding.toggleHiddenEventVisibility',
|
||||
}
|
||||
|
||||
type IKeyboardShortcuts = {
|
||||
// TODO: We should figure out what to do with the keyboard shortcuts that are not handled by KeybindingManager
|
||||
|
@ -81,20 +170,20 @@ export const CATEGORIES: Record<CategoryName, ICategory> = {
|
|||
[CategoryName.COMPOSER]: {
|
||||
categoryLabel: _td("Composer"),
|
||||
settingNames: [
|
||||
MessageComposerAction.Send,
|
||||
MessageComposerAction.FormatBold,
|
||||
MessageComposerAction.FormatItalics,
|
||||
MessageComposerAction.FormatQuote,
|
||||
MessageComposerAction.NewLine,
|
||||
MessageComposerAction.CancelEditing,
|
||||
MessageComposerAction.EditNextMessage,
|
||||
MessageComposerAction.EditPrevMessage,
|
||||
MessageComposerAction.MoveCursorToStart,
|
||||
MessageComposerAction.MoveCursorToEnd,
|
||||
MessageComposerAction.SelectNextSendHistory,
|
||||
MessageComposerAction.EditPrevMessage,
|
||||
MessageComposerAction.EditUndo,
|
||||
MessageComposerAction.EditRedo,
|
||||
KeyBindingAction.SendMessage,
|
||||
KeyBindingAction.NewLine,
|
||||
KeyBindingAction.FormatBold,
|
||||
KeyBindingAction.FormatItalics,
|
||||
KeyBindingAction.FormatQuote,
|
||||
KeyBindingAction.EditUndo,
|
||||
KeyBindingAction.EditRedo,
|
||||
KeyBindingAction.MoveCursorToStart,
|
||||
KeyBindingAction.MoveCursorToEnd,
|
||||
KeyBindingAction.CancelReplyOrEdit,
|
||||
KeyBindingAction.EditNextMessage,
|
||||
KeyBindingAction.EditPrevMessage,
|
||||
KeyBindingAction.SelectNextSendHistory,
|
||||
KeyBindingAction.SelectPrevSendHistory,
|
||||
],
|
||||
}, [CategoryName.CALLS]: {
|
||||
categoryLabel: _td("Calls"),
|
||||
|
@ -105,54 +194,54 @@ export const CATEGORIES: Record<CategoryName, ICategory> = {
|
|||
}, [CategoryName.ROOM]: {
|
||||
categoryLabel: _td("Room"),
|
||||
settingNames: [
|
||||
RoomAction.DismissReadMarker,
|
||||
RoomAction.JumpToOldestUnread,
|
||||
RoomAction.UploadFile,
|
||||
RoomAction.FocusSearch,
|
||||
RoomAction.ScrollUp,
|
||||
RoomAction.RoomScrollDown,
|
||||
RoomAction.JumpToFirstMessage,
|
||||
RoomAction.JumpToLatestMessage,
|
||||
KeyBindingAction.SearchInRoom,
|
||||
KeyBindingAction.UploadFile,
|
||||
KeyBindingAction.DismissReadMarker,
|
||||
KeyBindingAction.JumpToOldestUnread,
|
||||
KeyBindingAction.ScrollUp,
|
||||
KeyBindingAction.ScrollDown,
|
||||
KeyBindingAction.JumpToFirstMessage,
|
||||
KeyBindingAction.JumpToLatestMessage,
|
||||
],
|
||||
}, [CategoryName.ROOM_LIST]: {
|
||||
categoryLabel: _td("Room List"),
|
||||
settingNames: [
|
||||
RoomListAction.SelectRoom,
|
||||
RoomListAction.CollapseSection,
|
||||
RoomListAction.ExpandSection,
|
||||
RoomListAction.ClearSearch,
|
||||
RoomListAction.NextRoom,
|
||||
RoomListAction.PrevRoom,
|
||||
KeyBindingAction.SelectRoomInRoomList,
|
||||
KeyBindingAction.ClearRoomFilter,
|
||||
KeyBindingAction.CollapseRoomListSection,
|
||||
KeyBindingAction.ExpandRoomListSection,
|
||||
KeyBindingAction.NextRoom,
|
||||
KeyBindingAction.PrevRoom,
|
||||
],
|
||||
}, [CategoryName.NAVIGATION]: {
|
||||
categoryLabel: _td("Navigation"),
|
||||
settingNames: [
|
||||
NavigationAction.ToggleUserMenu,
|
||||
KeyBindingAction.ToggleUserMenu,
|
||||
"KeyBinding.closeDialogOrContextMenu",
|
||||
"KeyBinding.activateSelectedButton",
|
||||
NavigationAction.ToggleRoomSidePanel,
|
||||
NavigationAction.OpenShortCutDialog,
|
||||
NavigationAction.GoToHome,
|
||||
NavigationAction.SelectNextUnreadRoom,
|
||||
NavigationAction.SelectPrevUnreadRoom,
|
||||
NavigationAction.SelectNextRoom,
|
||||
NavigationAction.SelectPrevRoom,
|
||||
NavigationAction.ToggleSpacePanel,
|
||||
NavigationAction.FocusRoomSearch,
|
||||
KeyBindingAction.ToggleRoomSidePanel,
|
||||
KeyBindingAction.ToggleSpacePanel,
|
||||
KeyBindingAction.ShowKeyboardSettings,
|
||||
KeyBindingAction.GoToHome,
|
||||
KeyBindingAction.FilterRooms,
|
||||
KeyBindingAction.SelectNextUnreadRoom,
|
||||
KeyBindingAction.SelectPrevUnreadRoom,
|
||||
KeyBindingAction.SelectNextRoom,
|
||||
KeyBindingAction.SelectPrevRoom,
|
||||
],
|
||||
}, [CategoryName.AUTOCOMPLETE]: {
|
||||
categoryLabel: _td("Autocomplete"),
|
||||
settingNames: [
|
||||
AutocompleteAction.Cancel,
|
||||
AutocompleteAction.NextSelection,
|
||||
AutocompleteAction.PrevSelection,
|
||||
AutocompleteAction.Complete,
|
||||
AutocompleteAction.ForceComplete,
|
||||
KeyBindingAction.CancelAutocomplete,
|
||||
KeyBindingAction.NextSelectionInAutocomplete,
|
||||
KeyBindingAction.PrevSelectionInAutocomplete,
|
||||
KeyBindingAction.CompleteAutocomplete,
|
||||
KeyBindingAction.ForceCompleteAutocomplete,
|
||||
],
|
||||
}, [CategoryName.LABS]: {
|
||||
categoryLabel: _td("Labs"),
|
||||
settingNames: [
|
||||
LabsAction.ToggleHiddenEventVisibility,
|
||||
KeyBindingAction.ToggleHiddenEventVisibility,
|
||||
],
|
||||
},
|
||||
};
|
||||
|
@ -161,73 +250,73 @@ export const CATEGORIES: Record<CategoryName, ICategory> = {
|
|||
// to implement customizable keyboard shortcuts
|
||||
// TODO: TravisR will fix this nightmare when the new version of the SettingsStore becomes a thing
|
||||
const KEYBOARD_SHORTCUTS: IKeyboardShortcuts = {
|
||||
[MessageComposerAction.FormatBold]: {
|
||||
[KeyBindingAction.FormatBold]: {
|
||||
default: {
|
||||
ctrlOrCmdKey: true,
|
||||
key: Key.B,
|
||||
},
|
||||
displayName: _td("Toggle Bold"),
|
||||
},
|
||||
[MessageComposerAction.FormatItalics]: {
|
||||
[KeyBindingAction.FormatItalics]: {
|
||||
default: {
|
||||
ctrlOrCmdKey: true,
|
||||
key: Key.I,
|
||||
},
|
||||
displayName: _td("Toggle Italics"),
|
||||
},
|
||||
[MessageComposerAction.FormatQuote]: {
|
||||
[KeyBindingAction.FormatQuote]: {
|
||||
default: {
|
||||
ctrlOrCmdKey: true,
|
||||
key: Key.GREATER_THAN,
|
||||
},
|
||||
displayName: _td("Toggle Quote"),
|
||||
},
|
||||
[MessageComposerAction.CancelEditing]: {
|
||||
[KeyBindingAction.CancelReplyOrEdit]: {
|
||||
default: {
|
||||
key: Key.ESCAPE,
|
||||
},
|
||||
displayName: _td("Cancel replying to a message"),
|
||||
},
|
||||
[MessageComposerAction.EditNextMessage]: {
|
||||
default: {
|
||||
key: Key.ARROW_UP,
|
||||
},
|
||||
displayName: _td("Navigate to next message to edit"),
|
||||
},
|
||||
[MessageComposerAction.EditPrevMessage]: {
|
||||
[KeyBindingAction.EditNextMessage]: {
|
||||
default: {
|
||||
key: Key.ARROW_DOWN,
|
||||
},
|
||||
displayName: _td("Navigate to next message to edit"),
|
||||
},
|
||||
[KeyBindingAction.EditPrevMessage]: {
|
||||
default: {
|
||||
key: Key.ARROW_UP,
|
||||
},
|
||||
displayName: _td("Navigate to previous message to edit"),
|
||||
},
|
||||
[MessageComposerAction.MoveCursorToStart]: {
|
||||
[KeyBindingAction.MoveCursorToStart]: {
|
||||
default: {
|
||||
ctrlOrCmdKey: true,
|
||||
key: Key.HOME,
|
||||
},
|
||||
displayName: _td("Jump to start of the composer"),
|
||||
},
|
||||
[MessageComposerAction.MoveCursorToEnd]: {
|
||||
[KeyBindingAction.MoveCursorToEnd]: {
|
||||
default: {
|
||||
ctrlOrCmdKey: true,
|
||||
key: Key.END,
|
||||
},
|
||||
displayName: _td("Jump to end of the composer"),
|
||||
},
|
||||
[MessageComposerAction.SelectNextSendHistory]: {
|
||||
default: {
|
||||
altKey: true,
|
||||
ctrlKey: true,
|
||||
key: Key.ARROW_UP,
|
||||
},
|
||||
displayName: _td("Navigate to next message in composer history"),
|
||||
},
|
||||
[MessageComposerAction.SelectPrevSendHistory]: {
|
||||
[KeyBindingAction.SelectNextSendHistory]: {
|
||||
default: {
|
||||
altKey: true,
|
||||
ctrlKey: true,
|
||||
key: Key.ARROW_DOWN,
|
||||
},
|
||||
displayName: _td("Navigate to next message in composer history"),
|
||||
},
|
||||
[KeyBindingAction.SelectPrevSendHistory]: {
|
||||
default: {
|
||||
altKey: true,
|
||||
ctrlKey: true,
|
||||
key: Key.ARROW_UP,
|
||||
},
|
||||
displayName: _td("Navigate to previous message in composer history"),
|
||||
},
|
||||
"KeyBinding.toggleMicInCall": {
|
||||
|
@ -244,20 +333,20 @@ const KEYBOARD_SHORTCUTS: IKeyboardShortcuts = {
|
|||
},
|
||||
displayName: _td("Toggle webcam on/off"),
|
||||
},
|
||||
[RoomAction.DismissReadMarker]: {
|
||||
[KeyBindingAction.DismissReadMarker]: {
|
||||
default: {
|
||||
key: Key.ESCAPE,
|
||||
},
|
||||
displayName: _td("Dismiss read marker and jump to bottom"),
|
||||
},
|
||||
[RoomAction.JumpToOldestUnread]: {
|
||||
[KeyBindingAction.JumpToOldestUnread]: {
|
||||
default: {
|
||||
shiftKey: true,
|
||||
key: Key.PAGE_UP,
|
||||
},
|
||||
displayName: _td("Jump to oldest unread message"),
|
||||
},
|
||||
[RoomAction.UploadFile]: {
|
||||
[KeyBindingAction.UploadFile]: {
|
||||
default: {
|
||||
ctrlOrCmdKey: true,
|
||||
shiftKey: true,
|
||||
|
@ -265,102 +354,83 @@ const KEYBOARD_SHORTCUTS: IKeyboardShortcuts = {
|
|||
},
|
||||
displayName: _td("Upload a file"),
|
||||
},
|
||||
[RoomAction.FocusSearch]: {
|
||||
default: {
|
||||
ctrlOrCmdKey: true,
|
||||
key: Key.F,
|
||||
},
|
||||
displayName: _td("Search (must be enabled)"),
|
||||
},
|
||||
[RoomAction.ScrollUp]: {
|
||||
[KeyBindingAction.ScrollUp]: {
|
||||
default: {
|
||||
key: Key.PAGE_UP,
|
||||
},
|
||||
displayName: _td("Scroll up in the timeline"),
|
||||
},
|
||||
[RoomAction.RoomScrollDown]: {
|
||||
[KeyBindingAction.ScrollDown]: {
|
||||
default: {
|
||||
key: Key.PAGE_DOWN,
|
||||
},
|
||||
displayName: _td("Scroll down in the timeline"),
|
||||
},
|
||||
[NavigationAction.FocusRoomSearch]: {
|
||||
[KeyBindingAction.FilterRooms]: {
|
||||
default: {
|
||||
ctrlOrCmdKey: true,
|
||||
key: Key.K,
|
||||
},
|
||||
displayName: _td("Jump to room search"),
|
||||
},
|
||||
[RoomListAction.SelectRoom]: {
|
||||
[KeyBindingAction.SelectRoomInRoomList]: {
|
||||
default: {
|
||||
key: Key.ENTER,
|
||||
},
|
||||
displayName: _td("Select room from the room list"),
|
||||
},
|
||||
[RoomListAction.CollapseSection]: {
|
||||
[KeyBindingAction.CollapseRoomListSection]: {
|
||||
default: {
|
||||
key: Key.ARROW_LEFT,
|
||||
},
|
||||
displayName: _td("Collapse room list section"),
|
||||
},
|
||||
[RoomListAction.ExpandSection]: {
|
||||
[KeyBindingAction.ExpandRoomListSection]: {
|
||||
default: {
|
||||
key: Key.ARROW_RIGHT,
|
||||
},
|
||||
displayName: _td("Expand room list section"),
|
||||
},
|
||||
[RoomListAction.ClearSearch]: {
|
||||
[KeyBindingAction.ClearRoomFilter]: {
|
||||
default: {
|
||||
key: Key.ESCAPE,
|
||||
},
|
||||
displayName: _td("Clear room list filter field"),
|
||||
},
|
||||
[RoomListAction.NextRoom]: {
|
||||
default: {
|
||||
key: Key.ARROW_UP,
|
||||
},
|
||||
displayName: _td("Navigate up in the room list"),
|
||||
},
|
||||
[RoomListAction.PrevRoom]: {
|
||||
[KeyBindingAction.NextRoom]: {
|
||||
default: {
|
||||
key: Key.ARROW_DOWN,
|
||||
},
|
||||
displayName: _td("Navigate up in the room list"),
|
||||
},
|
||||
[KeyBindingAction.PrevRoom]: {
|
||||
default: {
|
||||
key: Key.ARROW_UP,
|
||||
},
|
||||
displayName: _td("Navigate down in the room list"),
|
||||
},
|
||||
[NavigationAction.ToggleUserMenu]: {
|
||||
[KeyBindingAction.ToggleUserMenu]: {
|
||||
default: {
|
||||
ctrlOrCmdKey: true,
|
||||
key: Key.BACKTICK,
|
||||
},
|
||||
displayName: _td("Toggle the top left menu"),
|
||||
},
|
||||
"KeyBinding.closeDialogOrContextMenu": {
|
||||
default: {
|
||||
key: Key.ESCAPE,
|
||||
},
|
||||
displayName: _td("Close dialog or context menu"),
|
||||
},
|
||||
"KeyBinding.activateSelectedButton": {
|
||||
default: {
|
||||
key: Key.ENTER,
|
||||
},
|
||||
displayName: _td("Activate selected button"),
|
||||
},
|
||||
[NavigationAction.ToggleRoomSidePanel]: {
|
||||
[KeyBindingAction.ToggleRoomSidePanel]: {
|
||||
default: {
|
||||
ctrlOrCmdKey: true,
|
||||
key: Key.PERIOD,
|
||||
},
|
||||
displayName: _td("Toggle right panel"),
|
||||
},
|
||||
[NavigationAction.OpenShortCutDialog]: {
|
||||
[KeyBindingAction.ShowKeyboardSettings]: {
|
||||
default: {
|
||||
ctrlOrCmdKey: true,
|
||||
key: Key.SLASH,
|
||||
},
|
||||
displayName: _td("Open this settings tab"),
|
||||
},
|
||||
[NavigationAction.GoToHome]: {
|
||||
[KeyBindingAction.GoToHome]: {
|
||||
default: {
|
||||
ctrlOrCmdKey: true,
|
||||
altKey: !isMac,
|
||||
|
@ -369,55 +439,55 @@ const KEYBOARD_SHORTCUTS: IKeyboardShortcuts = {
|
|||
},
|
||||
displayName: _td("Go to Home View"),
|
||||
},
|
||||
[NavigationAction.SelectNextUnreadRoom]: {
|
||||
[KeyBindingAction.SelectNextUnreadRoom]: {
|
||||
default: {
|
||||
shiftKey: true,
|
||||
altKey: true,
|
||||
key: Key.ARROW_UP,
|
||||
key: Key.ARROW_DOWN,
|
||||
},
|
||||
displayName: _td("Next unread room or DM"),
|
||||
},
|
||||
[NavigationAction.SelectPrevUnreadRoom]: {
|
||||
[KeyBindingAction.SelectPrevUnreadRoom]: {
|
||||
default: {
|
||||
shiftKey: true,
|
||||
altKey: true,
|
||||
key: Key.ARROW_DOWN,
|
||||
key: Key.ARROW_UP,
|
||||
},
|
||||
displayName: _td("Previous unread room or DM"),
|
||||
},
|
||||
[NavigationAction.SelectNextRoom]: {
|
||||
[KeyBindingAction.SelectNextRoom]: {
|
||||
default: {
|
||||
altKey: true,
|
||||
key: Key.ARROW_DOWN,
|
||||
},
|
||||
displayName: _td("Next room or DM"),
|
||||
},
|
||||
[KeyBindingAction.SelectPrevRoom]: {
|
||||
default: {
|
||||
altKey: true,
|
||||
key: Key.ARROW_UP,
|
||||
},
|
||||
displayName: _td("Next room or DM"),
|
||||
},
|
||||
[NavigationAction.SelectPrevRoom]: {
|
||||
default: {
|
||||
altKey: true,
|
||||
key: Key.ARROW_DOWN,
|
||||
},
|
||||
displayName: _td("Previous room or DM"),
|
||||
},
|
||||
[AutocompleteAction.Cancel]: {
|
||||
[KeyBindingAction.CancelAutocomplete]: {
|
||||
default: {
|
||||
key: Key.ESCAPE,
|
||||
},
|
||||
displayName: _td("Cancel autocomplete"),
|
||||
},
|
||||
[AutocompleteAction.NextSelection]: {
|
||||
default: {
|
||||
key: Key.ARROW_UP,
|
||||
},
|
||||
displayName: _td("Next autocomplete suggestion"),
|
||||
},
|
||||
[AutocompleteAction.PrevSelection]: {
|
||||
[KeyBindingAction.NextSelectionInAutocomplete]: {
|
||||
default: {
|
||||
key: Key.ARROW_DOWN,
|
||||
},
|
||||
displayName: _td("Next autocomplete suggestion"),
|
||||
},
|
||||
[KeyBindingAction.PrevSelectionInAutocomplete]: {
|
||||
default: {
|
||||
key: Key.ARROW_UP,
|
||||
},
|
||||
displayName: _td("Previous autocomplete suggestion"),
|
||||
},
|
||||
[NavigationAction.ToggleSpacePanel]: {
|
||||
[KeyBindingAction.ToggleSpacePanel]: {
|
||||
default: {
|
||||
ctrlOrCmdKey: true,
|
||||
shiftKey: true,
|
||||
|
@ -425,7 +495,7 @@ const KEYBOARD_SHORTCUTS: IKeyboardShortcuts = {
|
|||
},
|
||||
displayName: _td("Toggle space panel"),
|
||||
},
|
||||
[LabsAction.ToggleHiddenEventVisibility]: {
|
||||
[KeyBindingAction.ToggleHiddenEventVisibility]: {
|
||||
default: {
|
||||
ctrlOrCmdKey: true,
|
||||
shiftKey: true,
|
||||
|
@ -433,61 +503,86 @@ const KEYBOARD_SHORTCUTS: IKeyboardShortcuts = {
|
|||
},
|
||||
displayName: _td("Toggle hidden event visibility"),
|
||||
},
|
||||
[RoomAction.JumpToFirstMessage]: {
|
||||
[KeyBindingAction.JumpToFirstMessage]: {
|
||||
default: {
|
||||
key: Key.HOME,
|
||||
ctrlKey: true,
|
||||
},
|
||||
displayName: _td("Jump to first message"),
|
||||
},
|
||||
[RoomAction.JumpToOldestUnread]: {
|
||||
[KeyBindingAction.JumpToOldestUnread]: {
|
||||
default: {
|
||||
key: Key.END,
|
||||
ctrlKey: true,
|
||||
},
|
||||
displayName: _td("Jump to last message"),
|
||||
},
|
||||
[MessageComposerAction.EditUndo]: {
|
||||
[KeyBindingAction.EditUndo]: {
|
||||
default: {
|
||||
key: Key.Z,
|
||||
ctrlOrCmdKey: true,
|
||||
},
|
||||
displayName: _td("Undo edit"),
|
||||
},
|
||||
[AutocompleteAction.Complete]: {
|
||||
default: {
|
||||
key: Key.ENTER,
|
||||
},
|
||||
displayName: _td("Complete"),
|
||||
},
|
||||
[AutocompleteAction.ForceComplete]: {
|
||||
default: {
|
||||
key: Key.TAB,
|
||||
},
|
||||
displayName: _td("Force complete"),
|
||||
},
|
||||
};
|
||||
|
||||
export const getKeyboardShortcuts = (): IKeyboardShortcuts => {
|
||||
const keyboardShortcuts = KEYBOARD_SHORTCUTS;
|
||||
// XXX: These have to be manually mirrored in KeyBindingDefaults
|
||||
const getNonCustomizableShortcuts = (): IKeyboardShortcuts => {
|
||||
const ctrlEnterToSend = SettingsStore.getValue('MessageComposerInput.ctrlEnterToSend');
|
||||
|
||||
keyboardShortcuts[MessageComposerAction.Send] = {
|
||||
default: {
|
||||
key: Key.ENTER,
|
||||
ctrlOrCmdKey: ctrlEnterToSend,
|
||||
return {
|
||||
[KeyBindingAction.SendMessage]: {
|
||||
default: {
|
||||
key: Key.ENTER,
|
||||
ctrlOrCmdKey: ctrlEnterToSend,
|
||||
},
|
||||
displayName: _td("Send message"),
|
||||
},
|
||||
displayName: _td("Send message"),
|
||||
[KeyBindingAction.NewLine]: {
|
||||
default: {
|
||||
key: Key.ENTER,
|
||||
shiftKey: !ctrlEnterToSend,
|
||||
},
|
||||
displayName: _td("New line"),
|
||||
},
|
||||
[KeyBindingAction.CompleteAutocomplete]: {
|
||||
default: {
|
||||
key: Key.ENTER,
|
||||
},
|
||||
displayName: _td("Complete"),
|
||||
},
|
||||
[KeyBindingAction.ForceCompleteAutocomplete]: {
|
||||
default: {
|
||||
key: Key.TAB,
|
||||
},
|
||||
displayName: _td("Force complete"),
|
||||
},
|
||||
[KeyBindingAction.SearchInRoom]: {
|
||||
default: {
|
||||
ctrlOrCmdKey: true,
|
||||
key: Key.F,
|
||||
},
|
||||
displayName: _td("Search (must be enabled)"),
|
||||
},
|
||||
"KeyBinding.closeDialogOrContextMenu": {
|
||||
default: {
|
||||
key: Key.ESCAPE,
|
||||
},
|
||||
displayName: _td("Close dialog or context menu"),
|
||||
},
|
||||
"KeyBinding.activateSelectedButton": {
|
||||
default: {
|
||||
key: Key.ENTER,
|
||||
},
|
||||
displayName: _td("Activate selected button"),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
keyboardShortcuts[MessageComposerAction.NewLine] = {
|
||||
default: {
|
||||
key: Key.ENTER,
|
||||
shiftKey: !ctrlEnterToSend,
|
||||
},
|
||||
displayName: _td("New line"),
|
||||
};
|
||||
keyboardShortcuts[MessageComposerAction.EditRedo] = {
|
||||
export const getCustomizableShortcuts = (): IKeyboardShortcuts => {
|
||||
const keyboardShortcuts = KEYBOARD_SHORTCUTS;
|
||||
|
||||
keyboardShortcuts[KeyBindingAction.EditRedo] = {
|
||||
default: {
|
||||
key: isMac ? Key.Z : Key.Y,
|
||||
ctrlOrCmdKey: true,
|
||||
|
@ -499,6 +594,19 @@ export const getKeyboardShortcuts = (): IKeyboardShortcuts => {
|
|||
return keyboardShortcuts;
|
||||
};
|
||||
|
||||
export const getKeyboardShortcuts = (): IKeyboardShortcuts => {
|
||||
const entries = [
|
||||
...Object.entries(getNonCustomizableShortcuts()),
|
||||
...Object.entries(getCustomizableShortcuts()),
|
||||
];
|
||||
|
||||
const keyboardShortcuts: IKeyboardShortcuts = {};
|
||||
for (const [key, value] of entries) {
|
||||
keyboardShortcuts[key] = value;
|
||||
}
|
||||
return keyboardShortcuts;
|
||||
};
|
||||
|
||||
export const registerShortcut = (shortcutName: string, categoryName: CategoryName, shortcut: ISetting): void => {
|
||||
KEYBOARD_SHORTCUTS[shortcutName] = shortcut;
|
||||
CATEGORIES[categoryName].settingNames.push(shortcutName);
|
||||
|
|
|
@ -31,7 +31,7 @@ import LeftPanelWidget from "./LeftPanelWidget";
|
|||
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||
import SpaceStore from "../../stores/spaces/SpaceStore";
|
||||
import { MetaSpace, SpaceKey, UPDATE_SELECTED_SPACE } from "../../stores/spaces";
|
||||
import { getKeyBindingsManager, RoomListAction } from "../../KeyBindingsManager";
|
||||
import { getKeyBindingsManager } from "../../KeyBindingsManager";
|
||||
import UIStore from "../../stores/UIStore";
|
||||
import { findSiblingElement, IState as IRovingTabIndexState } from "../../accessibility/RovingTabIndex";
|
||||
import RoomListHeader from "../views/rooms/RoomListHeader";
|
||||
|
@ -44,6 +44,7 @@ import IndicatorScrollbar from "./IndicatorScrollbar";
|
|||
import RoomBreadcrumbs from "../views/rooms/RoomBreadcrumbs";
|
||||
import SettingsStore from "../../settings/SettingsStore";
|
||||
import UserMenu from "./UserMenu";
|
||||
import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
|
||||
|
||||
interface IProps {
|
||||
isMinimized: boolean;
|
||||
|
@ -296,7 +297,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
|||
|
||||
const action = getKeyBindingsManager().getRoomListAction(ev);
|
||||
switch (action) {
|
||||
case RoomListAction.NextRoom:
|
||||
case KeyBindingAction.NextRoom:
|
||||
if (!state) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
|
@ -304,7 +305,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
|||
}
|
||||
break;
|
||||
|
||||
case RoomListAction.PrevRoom:
|
||||
case KeyBindingAction.PrevRoom:
|
||||
if (state && state.activeRef === findSiblingElement(state.refs, 0)) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
|
|
|
@ -48,7 +48,7 @@ import { IOOBData, IThreepidInvite } from "../../stores/ThreepidInviteStore";
|
|||
import Modal from "../../Modal";
|
||||
import { ICollapseConfig } from "../../resizer/distributors/collapse";
|
||||
import HostSignupContainer from '../views/host_signup/HostSignupContainer';
|
||||
import { getKeyBindingsManager, NavigationAction, RoomAction, LabsAction } from '../../KeyBindingsManager';
|
||||
import { getKeyBindingsManager } from '../../KeyBindingsManager';
|
||||
import { IOpts } from "../../createRoom";
|
||||
import SpacePanel from "../views/spaces/SpacePanel";
|
||||
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||
|
@ -71,6 +71,7 @@ import { UserTab } from "../views/dialogs/UserSettingsDialog";
|
|||
import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload";
|
||||
import RightPanelStore from '../../stores/right-panel/RightPanelStore';
|
||||
import { TimelineRenderingType } from "../../contexts/RoomContext";
|
||||
import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
|
||||
|
||||
// We need to fetch each pinned message individually (if we don't already have it)
|
||||
// so each pinned message may trigger a request. Limit the number per room for sanity.
|
||||
|
@ -447,15 +448,15 @@ class LoggedInView extends React.Component<IProps, IState> {
|
|||
|
||||
const roomAction = getKeyBindingsManager().getRoomAction(ev);
|
||||
switch (roomAction) {
|
||||
case RoomAction.ScrollUp:
|
||||
case RoomAction.RoomScrollDown:
|
||||
case RoomAction.JumpToFirstMessage:
|
||||
case RoomAction.JumpToLatestMessage:
|
||||
case KeyBindingAction.ScrollUp:
|
||||
case KeyBindingAction.ScrollDown:
|
||||
case KeyBindingAction.JumpToFirstMessage:
|
||||
case KeyBindingAction.JumpToLatestMessage:
|
||||
// pass the event down to the scroll panel
|
||||
this.onScrollKeyPressed(ev);
|
||||
handled = true;
|
||||
break;
|
||||
case RoomAction.FocusSearch:
|
||||
case KeyBindingAction.SearchInRoom:
|
||||
dis.dispatch({
|
||||
action: 'focus_search',
|
||||
});
|
||||
|
@ -470,41 +471,41 @@ class LoggedInView extends React.Component<IProps, IState> {
|
|||
|
||||
const navAction = getKeyBindingsManager().getNavigationAction(ev);
|
||||
switch (navAction) {
|
||||
case NavigationAction.FocusRoomSearch:
|
||||
case KeyBindingAction.FilterRooms:
|
||||
dis.dispatch({
|
||||
action: 'focus_room_filter',
|
||||
});
|
||||
handled = true;
|
||||
break;
|
||||
case NavigationAction.ToggleUserMenu:
|
||||
case KeyBindingAction.ToggleUserMenu:
|
||||
dis.fire(Action.ToggleUserMenu);
|
||||
handled = true;
|
||||
break;
|
||||
case NavigationAction.OpenShortCutDialog:
|
||||
case KeyBindingAction.ShowKeyboardSettings:
|
||||
dis.dispatch<OpenToTabPayload>({
|
||||
action: Action.ViewUserSettings,
|
||||
initialTabId: UserTab.Keyboard,
|
||||
});
|
||||
handled = true;
|
||||
break;
|
||||
case NavigationAction.GoToHome:
|
||||
case KeyBindingAction.GoToHome:
|
||||
dis.dispatch({
|
||||
action: 'view_home_page',
|
||||
});
|
||||
Modal.closeCurrentModal("homeKeyboardShortcut");
|
||||
handled = true;
|
||||
break;
|
||||
case NavigationAction.ToggleSpacePanel:
|
||||
case KeyBindingAction.ToggleSpacePanel:
|
||||
dis.fire(Action.ToggleSpacePanel);
|
||||
handled = true;
|
||||
break;
|
||||
case NavigationAction.ToggleRoomSidePanel:
|
||||
case KeyBindingAction.ToggleRoomSidePanel:
|
||||
if (this.props.page_type === "room_view" || this.props.page_type === "group_view") {
|
||||
RightPanelStore.instance.togglePanel();
|
||||
handled = true;
|
||||
}
|
||||
break;
|
||||
case NavigationAction.SelectPrevRoom:
|
||||
case KeyBindingAction.SelectPrevRoom:
|
||||
dis.dispatch<ViewRoomDeltaPayload>({
|
||||
action: Action.ViewRoomDelta,
|
||||
delta: -1,
|
||||
|
@ -512,7 +513,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
|||
});
|
||||
handled = true;
|
||||
break;
|
||||
case NavigationAction.SelectNextRoom:
|
||||
case KeyBindingAction.SelectNextRoom:
|
||||
dis.dispatch<ViewRoomDeltaPayload>({
|
||||
action: Action.ViewRoomDelta,
|
||||
delta: 1,
|
||||
|
@ -520,14 +521,14 @@ class LoggedInView extends React.Component<IProps, IState> {
|
|||
});
|
||||
handled = true;
|
||||
break;
|
||||
case NavigationAction.SelectPrevUnreadRoom:
|
||||
case KeyBindingAction.SelectPrevUnreadRoom:
|
||||
dis.dispatch<ViewRoomDeltaPayload>({
|
||||
action: Action.ViewRoomDelta,
|
||||
delta: -1,
|
||||
unread: true,
|
||||
});
|
||||
break;
|
||||
case NavigationAction.SelectNextUnreadRoom:
|
||||
case KeyBindingAction.SelectNextUnreadRoom:
|
||||
dis.dispatch<ViewRoomDeltaPayload>({
|
||||
action: Action.ViewRoomDelta,
|
||||
delta: 1,
|
||||
|
@ -543,7 +544,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
|||
if (!handled) {
|
||||
const labsAction = getKeyBindingsManager().getLabsAction(ev);
|
||||
switch (labsAction) {
|
||||
case LabsAction.ToggleHiddenEventVisibility: {
|
||||
case KeyBindingAction.ToggleHiddenEventVisibility: {
|
||||
const hiddenEventVisibility = SettingsStore.getValueAt(
|
||||
SettingLevel.DEVICE,
|
||||
'showHiddenEventsInTimeline',
|
||||
|
|
|
@ -25,7 +25,7 @@ import AccessibleButton from "../views/elements/AccessibleButton";
|
|||
import { Action } from "../../dispatcher/actions";
|
||||
import RoomListStore from "../../stores/room-list/RoomListStore";
|
||||
import { NameFilterCondition } from "../../stores/room-list/filters/NameFilterCondition";
|
||||
import { getKeyBindingsManager, RoomListAction } from "../../KeyBindingsManager";
|
||||
import { getKeyBindingsManager } from "../../KeyBindingsManager";
|
||||
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||
import SpaceStore from "../../stores/spaces/SpaceStore";
|
||||
import { UPDATE_SELECTED_SPACE } from "../../stores/spaces";
|
||||
|
@ -33,7 +33,7 @@ import { isMac, Key } from "../../Keyboard";
|
|||
import SettingsStore from "../../settings/SettingsStore";
|
||||
import Modal from "../../Modal";
|
||||
import SpotlightDialog from "../views/dialogs/SpotlightDialog";
|
||||
import { ALTERNATE_KEY_NAME } from "../../accessibility/KeyboardShortcuts";
|
||||
import { ALTERNATE_KEY_NAME, KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
|
||||
|
||||
interface IProps {
|
||||
isMinimized: boolean;
|
||||
|
@ -141,11 +141,11 @@ export default class RoomSearch extends React.PureComponent<IProps, IState> {
|
|||
private onKeyDown = (ev: React.KeyboardEvent) => {
|
||||
const action = getKeyBindingsManager().getRoomListAction(ev);
|
||||
switch (action) {
|
||||
case RoomListAction.ClearSearch:
|
||||
case KeyBindingAction.ClearRoomFilter:
|
||||
this.clearInput();
|
||||
defaultDispatcher.fire(Action.FocusSendMessageComposer);
|
||||
break;
|
||||
case RoomListAction.SelectRoom: {
|
||||
case KeyBindingAction.SelectRoomInRoomList: {
|
||||
const shouldClear = this.props.onSelectRoom();
|
||||
if (shouldClear) {
|
||||
// wrap in set immediate to delay it so that we don't clear the filter & then change room
|
||||
|
|
|
@ -79,7 +79,7 @@ import Notifier from "../../Notifier";
|
|||
import { showToast as showNotificationsToast } from "../../toasts/DesktopNotificationsToast";
|
||||
import { RoomNotificationStateStore } from "../../stores/notifications/RoomNotificationStateStore";
|
||||
import { Container, WidgetLayoutStore } from "../../stores/widgets/WidgetLayoutStore";
|
||||
import { getKeyBindingsManager, RoomAction } from '../../KeyBindingsManager';
|
||||
import { getKeyBindingsManager } from '../../KeyBindingsManager';
|
||||
import { objectHasDiff } from "../../utils/objects";
|
||||
import SpaceRoomView from "./SpaceRoomView";
|
||||
import { IOpts } from "../../createRoom";
|
||||
|
@ -100,6 +100,7 @@ import { ComposerType } from "../../dispatcher/payloads/ComposerInsertPayload";
|
|||
import AppsDrawer from '../views/rooms/AppsDrawer';
|
||||
import { RightPanelPhases } from '../../stores/right-panel/RightPanelStorePhases';
|
||||
import { ActionPayload } from "../../dispatcher/payloads";
|
||||
import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
|
||||
|
||||
const DEBUG = false;
|
||||
let debuglog = function(msg: string) {};
|
||||
|
@ -797,16 +798,16 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
|
||||
const action = getKeyBindingsManager().getRoomAction(ev);
|
||||
switch (action) {
|
||||
case RoomAction.DismissReadMarker:
|
||||
case KeyBindingAction.DismissReadMarker:
|
||||
this.messagePanel.forgetReadMarker();
|
||||
this.jumpToLiveTimeline();
|
||||
handled = true;
|
||||
break;
|
||||
case RoomAction.JumpToOldestUnread:
|
||||
case KeyBindingAction.JumpToOldestUnread:
|
||||
this.jumpToReadMarker();
|
||||
handled = true;
|
||||
break;
|
||||
case RoomAction.UploadFile:
|
||||
case KeyBindingAction.UploadFile:
|
||||
dis.dispatch({ action: "upload_file" }, true);
|
||||
handled = true;
|
||||
break;
|
||||
|
|
|
@ -20,8 +20,9 @@ import { logger } from "matrix-js-sdk/src/logger";
|
|||
import Timer from '../../utils/Timer';
|
||||
import AutoHideScrollbar from "./AutoHideScrollbar";
|
||||
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||
import { getKeyBindingsManager, RoomAction } from "../../KeyBindingsManager";
|
||||
import { getKeyBindingsManager } from "../../KeyBindingsManager";
|
||||
import ResizeNotifier from "../../utils/ResizeNotifier";
|
||||
import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
|
||||
|
||||
const DEBUG_SCROLL = false;
|
||||
|
||||
|
@ -592,19 +593,19 @@ export default class ScrollPanel extends React.Component<IProps> {
|
|||
let isScrolling = false;
|
||||
const roomAction = getKeyBindingsManager().getRoomAction(ev);
|
||||
switch (roomAction) {
|
||||
case RoomAction.ScrollUp:
|
||||
case KeyBindingAction.ScrollUp:
|
||||
this.scrollRelative(-1);
|
||||
isScrolling = true;
|
||||
break;
|
||||
case RoomAction.RoomScrollDown:
|
||||
case KeyBindingAction.ScrollDown:
|
||||
this.scrollRelative(1);
|
||||
isScrolling = true;
|
||||
break;
|
||||
case RoomAction.JumpToFirstMessage:
|
||||
case KeyBindingAction.JumpToFirstMessage:
|
||||
this.scrollToTop();
|
||||
isScrolling = true;
|
||||
break;
|
||||
case RoomAction.JumpToLatestMessage:
|
||||
case KeyBindingAction.JumpToLatestMessage:
|
||||
this.scrollToBottom();
|
||||
isScrolling = true;
|
||||
break;
|
||||
|
|
|
@ -48,9 +48,9 @@ import { IDiff } from "../../../editor/diff";
|
|||
import AutocompleteWrapperModel from "../../../editor/autocomplete";
|
||||
import DocumentPosition from "../../../editor/position";
|
||||
import { ICompletion } from "../../../autocomplete/Autocompleter";
|
||||
import { AutocompleteAction, getKeyBindingsManager, MessageComposerAction } from '../../../KeyBindingsManager';
|
||||
import { getKeyBindingsManager } from '../../../KeyBindingsManager';
|
||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
import { ALTERNATE_KEY_NAME } from '../../../accessibility/KeyboardShortcuts';
|
||||
import { ALTERNATE_KEY_NAME, KeyBindingAction } from '../../../accessibility/KeyboardShortcuts';
|
||||
import { _t } from "../../../languageHandler";
|
||||
|
||||
// matches emoticons which follow the start of a line or whitespace
|
||||
|
@ -483,29 +483,29 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
if (model.autoComplete?.hasCompletions()) {
|
||||
const autoComplete = model.autoComplete;
|
||||
switch (autocompleteAction) {
|
||||
case AutocompleteAction.ForceComplete:
|
||||
case AutocompleteAction.Complete:
|
||||
case KeyBindingAction.ForceCompleteAutocomplete:
|
||||
case KeyBindingAction.CompleteAutocomplete:
|
||||
this.historyManager.ensureLastChangesPushed(this.props.model);
|
||||
this.modifiedFlag = true;
|
||||
autoComplete.confirmCompletion();
|
||||
handled = true;
|
||||
break;
|
||||
case AutocompleteAction.PrevSelection:
|
||||
case KeyBindingAction.PrevSelectionInAutocomplete:
|
||||
autoComplete.selectPreviousSelection();
|
||||
handled = true;
|
||||
break;
|
||||
case AutocompleteAction.NextSelection:
|
||||
case KeyBindingAction.NextSelectionInAutocomplete:
|
||||
autoComplete.selectNextSelection();
|
||||
handled = true;
|
||||
break;
|
||||
case AutocompleteAction.Cancel:
|
||||
case KeyBindingAction.CancelAutocomplete:
|
||||
autoComplete.onEscape(event);
|
||||
handled = true;
|
||||
break;
|
||||
default:
|
||||
return; // don't preventDefault on anything else
|
||||
}
|
||||
} else if (autocompleteAction === AutocompleteAction.ForceComplete && !this.state.showVisualBell) {
|
||||
} else if (autocompleteAction === KeyBindingAction.ForceCompleteAutocomplete && !this.state.showVisualBell) {
|
||||
// there is no current autocomplete window, try to open it
|
||||
this.tabCompleteName();
|
||||
handled = true;
|
||||
|
@ -521,19 +521,19 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
|
||||
const action = getKeyBindingsManager().getMessageComposerAction(event);
|
||||
switch (action) {
|
||||
case MessageComposerAction.FormatBold:
|
||||
case KeyBindingAction.FormatBold:
|
||||
this.onFormatAction(Formatting.Bold);
|
||||
handled = true;
|
||||
break;
|
||||
case MessageComposerAction.FormatItalics:
|
||||
case KeyBindingAction.FormatItalics:
|
||||
this.onFormatAction(Formatting.Italics);
|
||||
handled = true;
|
||||
break;
|
||||
case MessageComposerAction.FormatQuote:
|
||||
case KeyBindingAction.FormatQuote:
|
||||
this.onFormatAction(Formatting.Quote);
|
||||
handled = true;
|
||||
break;
|
||||
case MessageComposerAction.EditRedo:
|
||||
case KeyBindingAction.EditRedo:
|
||||
if (this.historyManager.canRedo()) {
|
||||
const { parts, caret } = this.historyManager.redo();
|
||||
// pass matching inputType so historyManager doesn't push echo
|
||||
|
@ -542,7 +542,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
}
|
||||
handled = true;
|
||||
break;
|
||||
case MessageComposerAction.EditUndo:
|
||||
case KeyBindingAction.EditUndo:
|
||||
if (this.historyManager.canUndo()) {
|
||||
const { parts, caret } = this.historyManager.undo(this.props.model);
|
||||
// pass matching inputType so historyManager doesn't push echo
|
||||
|
@ -551,18 +551,18 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
}
|
||||
handled = true;
|
||||
break;
|
||||
case MessageComposerAction.NewLine:
|
||||
case KeyBindingAction.NewLine:
|
||||
this.insertText("\n");
|
||||
handled = true;
|
||||
break;
|
||||
case MessageComposerAction.MoveCursorToStart:
|
||||
case KeyBindingAction.MoveCursorToStart:
|
||||
setSelection(this.editorRef.current, model, {
|
||||
index: 0,
|
||||
offset: 0,
|
||||
});
|
||||
handled = true;
|
||||
break;
|
||||
case MessageComposerAction.MoveCursorToEnd:
|
||||
case KeyBindingAction.MoveCursorToEnd:
|
||||
setSelection(this.editorRef.current, model, {
|
||||
index: model.parts.length - 1,
|
||||
offset: model.parts[model.parts.length - 1].text.length,
|
||||
|
|
|
@ -34,7 +34,7 @@ import BasicMessageComposer, { REGEX_EMOTICON } from "./BasicMessageComposer";
|
|||
import { CommandCategories } from '../../../SlashCommands';
|
||||
import { Action } from "../../../dispatcher/actions";
|
||||
import CountlyAnalytics from "../../../CountlyAnalytics";
|
||||
import { getKeyBindingsManager, MessageComposerAction } from '../../../KeyBindingsManager';
|
||||
import { getKeyBindingsManager } from '../../../KeyBindingsManager';
|
||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
import SendHistoryManager from '../../../SendHistoryManager';
|
||||
import { ActionPayload } from "../../../dispatcher/payloads";
|
||||
|
@ -45,6 +45,7 @@ import { withMatrixClientHOC, MatrixClientProps } from '../../../contexts/Matrix
|
|||
import RoomContext from '../../../contexts/RoomContext';
|
||||
import { ComposerType } from "../../../dispatcher/payloads/ComposerInsertPayload";
|
||||
import { getSlashCommand, isSlashCommand, runSlashCommand, shouldSendAnyway } from "../../../editor/commands";
|
||||
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
|
||||
|
||||
function getHtmlReplyFallback(mxEvent: MatrixEvent): string {
|
||||
const html = mxEvent.getContent().formatted_body;
|
||||
|
@ -156,16 +157,16 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
|
|||
}
|
||||
const action = getKeyBindingsManager().getMessageComposerAction(event);
|
||||
switch (action) {
|
||||
case MessageComposerAction.Send:
|
||||
case KeyBindingAction.SendMessage:
|
||||
this.sendEdit();
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
break;
|
||||
case MessageComposerAction.CancelEditing:
|
||||
case KeyBindingAction.CancelReplyOrEdit:
|
||||
event.stopPropagation();
|
||||
this.cancelEdit();
|
||||
break;
|
||||
case MessageComposerAction.EditPrevMessage: {
|
||||
case KeyBindingAction.EditPrevMessage: {
|
||||
if (this.editorRef.current?.isModified() || !this.editorRef.current?.isCaretAtStart()) {
|
||||
return;
|
||||
}
|
||||
|
@ -184,7 +185,7 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
|
|||
}
|
||||
break;
|
||||
}
|
||||
case MessageComposerAction.EditNextMessage: {
|
||||
case KeyBindingAction.EditNextMessage: {
|
||||
if (this.editorRef.current?.isModified() || !this.editorRef.current?.isCaretAtEnd()) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -54,8 +54,9 @@ import { arrayFastClone, arrayHasOrderChange } from "../../../utils/arrays";
|
|||
import { objectExcluding, objectHasDiff } from "../../../utils/objects";
|
||||
import ExtraTile from "./ExtraTile";
|
||||
import { ListNotificationState } from "../../../stores/notifications/ListNotificationState";
|
||||
import { getKeyBindingsManager, RoomListAction } from "../../../KeyBindingsManager";
|
||||
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
|
||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
|
||||
|
||||
const SHOW_N_BUTTON_HEIGHT = 28; // As defined by CSS
|
||||
const RESIZE_HANDLE_HEIGHT = 4; // As defined by CSS
|
||||
|
@ -474,14 +475,14 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
private onHeaderKeyDown = (ev: React.KeyboardEvent) => {
|
||||
const action = getKeyBindingsManager().getRoomListAction(ev);
|
||||
switch (action) {
|
||||
case RoomListAction.CollapseSection:
|
||||
case KeyBindingAction.CollapseRoomListSection:
|
||||
ev.stopPropagation();
|
||||
if (this.state.isExpanded) {
|
||||
// Collapse the room sublist if it isn't already
|
||||
this.toggleCollapsed();
|
||||
}
|
||||
break;
|
||||
case RoomListAction.ExpandSection: {
|
||||
case KeyBindingAction.ExpandRoomListSection: {
|
||||
ev.stopPropagation();
|
||||
if (!this.state.isExpanded) {
|
||||
// Expand the room sublist if it isn't already
|
||||
|
|
|
@ -46,7 +46,7 @@ import { containsEmoji } from "../../../effects/utils";
|
|||
import { CHAT_EFFECTS } from '../../../effects';
|
||||
import CountlyAnalytics from "../../../CountlyAnalytics";
|
||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||
import { getKeyBindingsManager, MessageComposerAction } from '../../../KeyBindingsManager';
|
||||
import { getKeyBindingsManager } from '../../../KeyBindingsManager';
|
||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
import SettingsStore from '../../../settings/SettingsStore';
|
||||
import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
|
||||
|
@ -56,6 +56,7 @@ import RoomContext, { TimelineRenderingType } from '../../../contexts/RoomContex
|
|||
import DocumentPosition from "../../../editor/position";
|
||||
import { ComposerType } from "../../../dispatcher/payloads/ComposerInsertPayload";
|
||||
import { getSlashCommand, isSlashCommand, runSlashCommand, shouldSendAnyway } from "../../../editor/commands";
|
||||
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
|
||||
|
||||
interface IAddReplyOpts {
|
||||
permalinkCreator?: RoomPermalinkCreator;
|
||||
|
@ -221,21 +222,21 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
|
|||
const replyingToThread = this.props.relation?.key === RelationType.Thread;
|
||||
const action = getKeyBindingsManager().getMessageComposerAction(event);
|
||||
switch (action) {
|
||||
case MessageComposerAction.Send:
|
||||
case KeyBindingAction.SendMessage:
|
||||
this.sendMessage();
|
||||
event.preventDefault();
|
||||
break;
|
||||
case MessageComposerAction.SelectPrevSendHistory:
|
||||
case MessageComposerAction.SelectNextSendHistory: {
|
||||
case KeyBindingAction.SelectPrevSendHistory:
|
||||
case KeyBindingAction.SelectNextSendHistory: {
|
||||
// Try select composer history
|
||||
const selected = this.selectSendHistory(action === MessageComposerAction.SelectPrevSendHistory);
|
||||
const selected = this.selectSendHistory(action === KeyBindingAction.SelectPrevSendHistory);
|
||||
if (selected) {
|
||||
// We're selecting history, so prevent the key event from doing anything else
|
||||
event.preventDefault();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MessageComposerAction.EditPrevMessage:
|
||||
case KeyBindingAction.EditPrevMessage:
|
||||
// selection must be collapsed and caret at start
|
||||
if (this.editorRef.current?.isSelectionCollapsed() && this.editorRef.current?.isCaretAtStart()) {
|
||||
const events =
|
||||
|
@ -256,7 +257,7 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
|
|||
}
|
||||
}
|
||||
break;
|
||||
case MessageComposerAction.CancelEditing:
|
||||
case KeyBindingAction.CancelReplyOrEdit:
|
||||
dis.dispatch({
|
||||
action: 'reply_to_event',
|
||||
event: null,
|
||||
|
|
|
@ -37,11 +37,12 @@ import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
|||
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
|
||||
import { StaticNotificationState } from "../../../stores/notifications/StaticNotificationState";
|
||||
import { NotificationColor } from "../../../stores/notifications/NotificationColor";
|
||||
import { getKeyBindingsManager, RoomListAction } from "../../../KeyBindingsManager";
|
||||
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
|
||||
import { NotificationState } from "../../../stores/notifications/NotificationState";
|
||||
import SpaceContextMenu from "../context_menus/SpaceContextMenu";
|
||||
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
||||
import { useRovingTabIndex } from "../../../accessibility/RovingTabIndex";
|
||||
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
|
||||
|
||||
interface IButtonProps extends Omit<ComponentProps<typeof AccessibleTooltipButton>, "title" | "onClick"> {
|
||||
space?: Room;
|
||||
|
@ -234,7 +235,7 @@ export class SpaceItem extends React.PureComponent<IItemProps, IItemState> {
|
|||
const action = getKeyBindingsManager().getRoomListAction(ev);
|
||||
const hasChildren = this.state.childSpaces?.length;
|
||||
switch (action) {
|
||||
case RoomListAction.CollapseSection:
|
||||
case KeyBindingAction.CollapseRoomListSection:
|
||||
if (hasChildren && !this.isCollapsed) {
|
||||
this.toggleCollapse(ev);
|
||||
} else {
|
||||
|
@ -244,7 +245,7 @@ export class SpaceItem extends React.PureComponent<IItemProps, IItemState> {
|
|||
}
|
||||
break;
|
||||
|
||||
case RoomListAction.ExpandSection:
|
||||
case KeyBindingAction.ExpandRoomListSection:
|
||||
if (hasChildren) {
|
||||
if (this.isCollapsed) {
|
||||
this.toggleCollapse(ev);
|
||||
|
|
|
@ -3397,7 +3397,6 @@
|
|||
"Dismiss read marker and jump to bottom": "Dismiss read marker and jump to bottom",
|
||||
"Jump to oldest unread message": "Jump to oldest unread message",
|
||||
"Upload a file": "Upload a file",
|
||||
"Search (must be enabled)": "Search (must be enabled)",
|
||||
"Scroll up in the timeline": "Scroll up in the timeline",
|
||||
"Scroll down in the timeline": "Scroll down in the timeline",
|
||||
"Jump to room search": "Jump to room search",
|
||||
|
@ -3408,8 +3407,6 @@
|
|||
"Navigate up in the room list": "Navigate up in the room list",
|
||||
"Navigate down in the room list": "Navigate down in the room list",
|
||||
"Toggle the top left menu": "Toggle the top left menu",
|
||||
"Close dialog or context menu": "Close dialog or context menu",
|
||||
"Activate selected button": "Activate selected button",
|
||||
"Toggle right panel": "Toggle right panel",
|
||||
"Open this settings tab": "Open this settings tab",
|
||||
"Go to Home View": "Go to Home View",
|
||||
|
@ -3425,7 +3422,10 @@
|
|||
"Jump to first message": "Jump to first message",
|
||||
"Jump to last message": "Jump to last message",
|
||||
"Undo edit": "Undo edit",
|
||||
"Force complete": "Force complete",
|
||||
"New line": "New line",
|
||||
"Force complete": "Force complete",
|
||||
"Search (must be enabled)": "Search (must be enabled)",
|
||||
"Close dialog or context menu": "Close dialog or context menu",
|
||||
"Activate selected button": "Activate selected button",
|
||||
"Redo edit": "Redo edit"
|
||||
}
|
||||
|
|
|
@ -123,7 +123,7 @@ describe('KeyBindingsManager', () => {
|
|||
it('should match ctrlOrMeta key combo', () => {
|
||||
const combo: KeyCombo = {
|
||||
key: 'k',
|
||||
ctrlOrCmd: true,
|
||||
ctrlOrCmdKey: true,
|
||||
};
|
||||
// PC:
|
||||
expect(isKeyComboMatch(mockKeyEvent('k', { ctrlKey: true }), combo, false)).toBe(true);
|
||||
|
@ -138,7 +138,7 @@ describe('KeyBindingsManager', () => {
|
|||
it('should match advanced ctrlOrMeta key combo', () => {
|
||||
const combo: KeyCombo = {
|
||||
key: 'k',
|
||||
ctrlOrCmd: true,
|
||||
ctrlOrCmdKey: true,
|
||||
altKey: true,
|
||||
};
|
||||
// PC:
|
||||
|
|
Loading…
Reference in New Issue