mirror of https://github.com/vector-im/riot-web
Add support for multiple key bindings provider
- This can be used to provide custom key bindings - Move default key bindings into its own filepull/21833/head
parent
ef7284e69d
commit
1cfb0e99d4
|
@ -0,0 +1,384 @@
|
||||||
|
import { AutocompleteAction, IKeyBindingsProvider, KeyBinding, MessageComposerAction, NavigationAction, RoomAction,
|
||||||
|
RoomListAction } from "./KeyBindingsManager";
|
||||||
|
import { isMac, Key } from "./Keyboard";
|
||||||
|
import SettingsStore from "./settings/SettingsStore";
|
||||||
|
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Note: the following two bindings also work with just HOME and END, add them here?
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
keyCombo: {
|
||||||
|
key: Key.ENTER,
|
||||||
|
ctrlOrCmd: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
bindings.push({
|
||||||
|
action: MessageComposerAction.NewLine,
|
||||||
|
keyCombo: {
|
||||||
|
key: Key.ENTER,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
bindings.push({
|
||||||
|
action: MessageComposerAction.Send,
|
||||||
|
keyCombo: {
|
||||||
|
key: Key.ENTER,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
bindings.push({
|
||||||
|
action: MessageComposerAction.NewLine,
|
||||||
|
keyCombo: {
|
||||||
|
key: Key.ENTER,
|
||||||
|
shiftKey: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (isMac) {
|
||||||
|
bindings.push({
|
||||||
|
action: MessageComposerAction.NewLine,
|
||||||
|
keyCombo: {
|
||||||
|
key: Key.ENTER,
|
||||||
|
altKey: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
const autocompleteBindings = (): KeyBinding<AutocompleteAction>[] => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
action: AutocompleteAction.ApplySelection,
|
||||||
|
keyCombo: {
|
||||||
|
key: Key.TAB,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: AutocompleteAction.ApplySelection,
|
||||||
|
keyCombo: {
|
||||||
|
key: Key.TAB,
|
||||||
|
ctrlKey: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: AutocompleteAction.ApplySelection,
|
||||||
|
keyCombo: {
|
||||||
|
key: Key.TAB,
|
||||||
|
shiftKey: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: AutocompleteAction.Cancel,
|
||||||
|
keyCombo: {
|
||||||
|
key: Key.ESCAPE,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: AutocompleteAction.PrevSelection,
|
||||||
|
keyCombo: {
|
||||||
|
key: Key.ARROW_UP,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: AutocompleteAction.NextSelection,
|
||||||
|
keyCombo: {
|
||||||
|
key: Key.ARROW_DOWN,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
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 roomBindings = (): KeyBinding<RoomAction>[] => {
|
||||||
|
const bindings = [
|
||||||
|
{
|
||||||
|
action: RoomAction.FocusRoomSearch,
|
||||||
|
keyCombo: {
|
||||||
|
key: Key.K,
|
||||||
|
ctrlOrCmd: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
if (SettingsStore.getValue('ctrlFForSearch')) {
|
||||||
|
bindings.push({
|
||||||
|
action: RoomAction.FocusSearch,
|
||||||
|
keyCombo: {
|
||||||
|
key: Key.F,
|
||||||
|
ctrlOrCmd: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return bindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
const navigationBindings = (): KeyBinding<NavigationAction>[] => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
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.ToggleShortCutDialog,
|
||||||
|
keyCombo: {
|
||||||
|
key: Key.SLASH,
|
||||||
|
ctrlOrCmd: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: NavigationAction.ToggleShortCutDialog,
|
||||||
|
keyCombo: {
|
||||||
|
key: Key.SLASH,
|
||||||
|
ctrlOrCmd: true,
|
||||||
|
shiftKey: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: NavigationAction.GoToHome,
|
||||||
|
keyCombo: {
|
||||||
|
key: Key.H,
|
||||||
|
ctrlOrCmd: true,
|
||||||
|
altKey: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const defaultBindingProvider: IKeyBindingsProvider = {
|
||||||
|
getMessageComposerBindings: messageComposerBindings,
|
||||||
|
getAutocompleteBindings: autocompleteBindings,
|
||||||
|
getRoomListBindings: roomListBindings,
|
||||||
|
getRoomBindings: roomBindings,
|
||||||
|
getNavigationBindings: navigationBindings,
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import { isMac, Key } from './Keyboard';
|
import { defaultBindingProvider } from './KeyBindingsDefaults';
|
||||||
import SettingsStore from './settings/SettingsStore';
|
import { isMac } from './Keyboard';
|
||||||
|
|
||||||
/** Actions for the chat message composer component */
|
/** Actions for the chat message composer component */
|
||||||
export enum MessageComposerAction {
|
export enum MessageComposerAction {
|
||||||
|
@ -124,371 +124,6 @@ export type KeyBinding<T extends string> = {
|
||||||
keyCombo: KeyCombo;
|
keyCombo: KeyCombo;
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// Note: the following two bindings also work with just HOME and END, add them here?
|
|
||||||
{
|
|
||||||
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,
|
|
||||||
keyCombo: {
|
|
||||||
key: Key.ENTER,
|
|
||||||
ctrlOrCmd: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
bindings.push({
|
|
||||||
action: MessageComposerAction.NewLine,
|
|
||||||
keyCombo: {
|
|
||||||
key: Key.ENTER,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
bindings.push({
|
|
||||||
action: MessageComposerAction.Send,
|
|
||||||
keyCombo: {
|
|
||||||
key: Key.ENTER,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
bindings.push({
|
|
||||||
action: MessageComposerAction.NewLine,
|
|
||||||
keyCombo: {
|
|
||||||
key: Key.ENTER,
|
|
||||||
shiftKey: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (isMac) {
|
|
||||||
bindings.push({
|
|
||||||
action: MessageComposerAction.NewLine,
|
|
||||||
keyCombo: {
|
|
||||||
key: Key.ENTER,
|
|
||||||
altKey: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bindings;
|
|
||||||
}
|
|
||||||
|
|
||||||
const autocompleteBindings = (): KeyBinding<AutocompleteAction>[] => {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
action: AutocompleteAction.ApplySelection,
|
|
||||||
keyCombo: {
|
|
||||||
key: Key.TAB,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
action: AutocompleteAction.ApplySelection,
|
|
||||||
keyCombo: {
|
|
||||||
key: Key.TAB,
|
|
||||||
ctrlKey: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
action: AutocompleteAction.ApplySelection,
|
|
||||||
keyCombo: {
|
|
||||||
key: Key.TAB,
|
|
||||||
shiftKey: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
action: AutocompleteAction.Cancel,
|
|
||||||
keyCombo: {
|
|
||||||
key: Key.ESCAPE,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
action: AutocompleteAction.PrevSelection,
|
|
||||||
keyCombo: {
|
|
||||||
key: Key.ARROW_UP,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
action: AutocompleteAction.NextSelection,
|
|
||||||
keyCombo: {
|
|
||||||
key: Key.ARROW_DOWN,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
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 roomBindings = (): KeyBinding<RoomAction>[] => {
|
|
||||||
const bindings = [
|
|
||||||
{
|
|
||||||
action: RoomAction.FocusRoomSearch,
|
|
||||||
keyCombo: {
|
|
||||||
key: Key.K,
|
|
||||||
ctrlOrCmd: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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.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,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
if (SettingsStore.getValue('ctrlFForSearch')) {
|
|
||||||
bindings.push({
|
|
||||||
action: RoomAction.FocusSearch,
|
|
||||||
keyCombo: {
|
|
||||||
key: Key.F,
|
|
||||||
ctrlOrCmd: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return bindings;
|
|
||||||
}
|
|
||||||
|
|
||||||
const navigationBindings = (): KeyBinding<NavigationAction>[] => {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
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.ToggleShortCutDialog,
|
|
||||||
keyCombo: {
|
|
||||||
key: Key.SLASH,
|
|
||||||
ctrlOrCmd: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
action: NavigationAction.ToggleShortCutDialog,
|
|
||||||
keyCombo: {
|
|
||||||
key: Key.SLASH,
|
|
||||||
ctrlOrCmd: true,
|
|
||||||
shiftKey: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
action: NavigationAction.GoToHome,
|
|
||||||
keyCombo: {
|
|
||||||
key: Key.H,
|
|
||||||
ctrlOrCmd: true,
|
|
||||||
altKey: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
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,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to check if a KeyboardEvent matches a KeyCombo
|
* Helper method to check if a KeyboardEvent matches a KeyCombo
|
||||||
*
|
*
|
||||||
|
@ -541,42 +176,63 @@ export function isKeyComboMatch(ev: KeyboardEvent | React.KeyboardEvent, combo:
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type KeyBindingGetter<T extends string> = () => KeyBinding<T>[];
|
||||||
|
|
||||||
|
export interface IKeyBindingsProvider {
|
||||||
|
getMessageComposerBindings: KeyBindingGetter<MessageComposerAction>;
|
||||||
|
getAutocompleteBindings: KeyBindingGetter<AutocompleteAction>;
|
||||||
|
getRoomListBindings: KeyBindingGetter<RoomListAction>;
|
||||||
|
getRoomBindings: KeyBindingGetter<RoomAction>;
|
||||||
|
getNavigationBindings: KeyBindingGetter<NavigationAction>;
|
||||||
|
}
|
||||||
|
|
||||||
export class KeyBindingsManager {
|
export class KeyBindingsManager {
|
||||||
|
/**
|
||||||
|
* List of key bindings providers.
|
||||||
|
*
|
||||||
|
* Key bindings from the first provider(s) in the list will have precedence over key bindings from later providers.
|
||||||
|
*
|
||||||
|
* To overwrite the default key bindings add a new providers before the default provider, e.g. a provider for
|
||||||
|
* customized key bindings.
|
||||||
|
*/
|
||||||
|
bindingsProviders: IKeyBindingsProvider[] = [
|
||||||
|
defaultBindingProvider,
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds a matching KeyAction for a given KeyboardEvent
|
* Finds a matching KeyAction for a given KeyboardEvent
|
||||||
*/
|
*/
|
||||||
private getAction<T extends string>(bindings: KeyBinding<T>[], ev: KeyboardEvent | React.KeyboardEvent)
|
private getAction<T extends string>(getters: KeyBindingGetter<T>[], ev: KeyboardEvent | React.KeyboardEvent)
|
||||||
: T | undefined {
|
: T | undefined {
|
||||||
const binding = bindings.find(it => isKeyComboMatch(ev, it.keyCombo, isMac));
|
for (const getter of getters) {
|
||||||
if (binding) {
|
const bindings = getter();
|
||||||
return binding.action;
|
const binding = bindings.find(it => isKeyComboMatch(ev, it.keyCombo, isMac));
|
||||||
|
if (binding) {
|
||||||
|
return binding.action;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
getMessageComposerAction(ev: KeyboardEvent | React.KeyboardEvent): MessageComposerAction | undefined {
|
getMessageComposerAction(ev: KeyboardEvent | React.KeyboardEvent): MessageComposerAction | undefined {
|
||||||
const bindings = messageComposerBindings();
|
return this.getAction(this.bindingsProviders.map(it => it.getMessageComposerBindings), ev);
|
||||||
return this.getAction(bindings, ev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getAutocompleteAction(ev: KeyboardEvent | React.KeyboardEvent): AutocompleteAction | undefined {
|
getAutocompleteAction(ev: KeyboardEvent | React.KeyboardEvent): AutocompleteAction | undefined {
|
||||||
const bindings = autocompleteBindings();
|
return this.getAction(this.bindingsProviders.map(it => it.getAutocompleteBindings), ev);
|
||||||
return this.getAction(bindings, ev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getRoomListAction(ev: KeyboardEvent | React.KeyboardEvent): RoomListAction | undefined {
|
getRoomListAction(ev: KeyboardEvent | React.KeyboardEvent): RoomListAction | undefined {
|
||||||
const bindings = roomListBindings();
|
return this.getAction(this.bindingsProviders.map(it => it.getRoomListBindings), ev);
|
||||||
return this.getAction(bindings, ev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getRoomAction(ev: KeyboardEvent | React.KeyboardEvent): RoomAction | undefined {
|
getRoomAction(ev: KeyboardEvent | React.KeyboardEvent): RoomAction | undefined {
|
||||||
const bindings = roomBindings();
|
return this.getAction(this.bindingsProviders.map(it => it.getRoomBindings), ev);
|
||||||
return this.getAction(bindings, ev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getNavigationAction(ev: KeyboardEvent | React.KeyboardEvent): NavigationAction | undefined {
|
getNavigationAction(ev: KeyboardEvent | React.KeyboardEvent): NavigationAction | undefined {
|
||||||
const bindings = navigationBindings();
|
return this.getAction(this.bindingsProviders.map(it => it.getNavigationBindings), ev);
|
||||||
return this.getAction(bindings, ev);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue