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 SettingsStore from './settings/SettingsStore'; | ||||
| import { defaultBindingProvider } from './KeyBindingsDefaults'; | ||||
| import { isMac } from './Keyboard'; | ||||
| 
 | ||||
| /** Actions for the chat message composer component */ | ||||
| export enum MessageComposerAction { | ||||
|  | @ -124,371 +124,6 @@ export type KeyBinding<T extends string> = { | |||
|     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 | ||||
|  * | ||||
|  | @ -541,42 +176,63 @@ export function isKeyComboMatch(ev: KeyboardEvent | React.KeyboardEvent, combo: | |||
| 
 | ||||
|     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 { | ||||
|     /** | ||||
|      * 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 | ||||
|      */ | ||||
|     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 { | ||||
|         const binding = bindings.find(it => isKeyComboMatch(ev, it.keyCombo, isMac)); | ||||
|         if (binding) { | ||||
|             return binding.action; | ||||
|         for (const getter of getters) { | ||||
|             const bindings = getter(); | ||||
|             const binding = bindings.find(it => isKeyComboMatch(ev, it.keyCombo, isMac)); | ||||
|             if (binding) { | ||||
|                 return binding.action; | ||||
|             } | ||||
|         } | ||||
|         return undefined; | ||||
|     } | ||||
| 
 | ||||
|     getMessageComposerAction(ev: KeyboardEvent | React.KeyboardEvent): MessageComposerAction | undefined { | ||||
|         const bindings = messageComposerBindings(); | ||||
|         return this.getAction(bindings, ev); | ||||
|         return this.getAction(this.bindingsProviders.map(it => it.getMessageComposerBindings), ev); | ||||
|     } | ||||
| 
 | ||||
|     getAutocompleteAction(ev: KeyboardEvent | React.KeyboardEvent): AutocompleteAction | undefined { | ||||
|         const bindings = autocompleteBindings(); | ||||
|         return this.getAction(bindings, ev); | ||||
|         return this.getAction(this.bindingsProviders.map(it => it.getAutocompleteBindings), ev); | ||||
|     } | ||||
| 
 | ||||
|     getRoomListAction(ev: KeyboardEvent | React.KeyboardEvent): RoomListAction | undefined { | ||||
|         const bindings = roomListBindings(); | ||||
|         return this.getAction(bindings, ev); | ||||
|         return this.getAction(this.bindingsProviders.map(it => it.getRoomListBindings), ev); | ||||
|     } | ||||
| 
 | ||||
|     getRoomAction(ev: KeyboardEvent | React.KeyboardEvent): RoomAction | undefined { | ||||
|         const bindings = roomBindings(); | ||||
|         return this.getAction(bindings, ev); | ||||
|         return this.getAction(this.bindingsProviders.map(it => it.getRoomBindings), ev); | ||||
|     } | ||||
| 
 | ||||
|     getNavigationAction(ev: KeyboardEvent | React.KeyboardEvent): NavigationAction | undefined { | ||||
|         const bindings = navigationBindings(); | ||||
|         return this.getAction(bindings, ev); | ||||
|         return this.getAction(this.bindingsProviders.map(it => it.getNavigationBindings), ev); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Clemens Zeidler
						Clemens Zeidler