| 
									
										
										
										
											2021-09-29 16:23:06 -04:00
										 |  |  | // Copyright 2021 Signal Messenger, LLC
 | 
					
						
							|  |  |  | // SPDX-License-Identifier: AGPL-3.0-only
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-15 14:51:58 -04:00
										 |  |  | import { useCallback, useEffect } from 'react'; | 
					
						
							| 
									
										
										
										
											2021-09-29 16:23:06 -04:00
										 |  |  | import { get } from 'lodash'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 15:21:51 -07:00
										 |  |  | import * as KeyboardLayout from '../services/keyboardLayout'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 16:23:06 -04:00
										 |  |  | type KeyboardShortcutHandlerType = (ev: KeyboardEvent) => boolean; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function isCmdOrCtrl(ev: KeyboardEvent): boolean { | 
					
						
							|  |  |  |   const { ctrlKey, metaKey } = ev; | 
					
						
							|  |  |  |   const commandKey = get(window, 'platform') === 'darwin' && metaKey; | 
					
						
							|  |  |  |   const controlKey = get(window, 'platform') !== 'darwin' && ctrlKey; | 
					
						
							|  |  |  |   return commandKey || controlKey; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-10 14:14:08 -04:00
										 |  |  | function isCtrlOrAlt(ev: KeyboardEvent): boolean { | 
					
						
							|  |  |  |   const { altKey, ctrlKey } = ev; | 
					
						
							|  |  |  |   const controlKey = get(window, 'platform') === 'darwin' && ctrlKey; | 
					
						
							|  |  |  |   const theAltKey = get(window, 'platform') !== 'darwin' && altKey; | 
					
						
							|  |  |  |   return controlKey || theAltKey; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function useActiveCallShortcuts( | 
					
						
							| 
									
										
										
										
											2022-08-16 16:52:09 -07:00
										 |  |  |   hangUp: (reason: string) => unknown | 
					
						
							| 
									
										
										
										
											2022-05-10 14:14:08 -04:00
										 |  |  | ): KeyboardShortcutHandlerType { | 
					
						
							|  |  |  |   return useCallback( | 
					
						
							|  |  |  |     ev => { | 
					
						
							|  |  |  |       const { shiftKey } = ev; | 
					
						
							|  |  |  |       const key = KeyboardLayout.lookup(ev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (isCtrlOrAlt(ev) && shiftKey && (key === 'e' || key === 'E')) { | 
					
						
							|  |  |  |         ev.preventDefault(); | 
					
						
							|  |  |  |         ev.stopPropagation(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-16 16:52:09 -07:00
										 |  |  |         hangUp('Keyboard shortcut'); | 
					
						
							| 
									
										
										
										
											2022-05-10 14:14:08 -04:00
										 |  |  |         return true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     [hangUp] | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function useIncomingCallShortcuts( | 
					
						
							|  |  |  |   acceptAudioCall: () => unknown, | 
					
						
							|  |  |  |   acceptVideoCall: () => unknown, | 
					
						
							|  |  |  |   declineCall: () => unknown | 
					
						
							|  |  |  | ): KeyboardShortcutHandlerType { | 
					
						
							|  |  |  |   return useCallback( | 
					
						
							|  |  |  |     ev => { | 
					
						
							|  |  |  |       const { shiftKey } = ev; | 
					
						
							|  |  |  |       const key = KeyboardLayout.lookup(ev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (isCtrlOrAlt(ev) && shiftKey && (key === 'v' || key === 'V')) { | 
					
						
							|  |  |  |         ev.preventDefault(); | 
					
						
							|  |  |  |         ev.stopPropagation(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         acceptVideoCall(); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (isCtrlOrAlt(ev) && shiftKey && (key === 'a' || key === 'A')) { | 
					
						
							|  |  |  |         ev.preventDefault(); | 
					
						
							|  |  |  |         ev.stopPropagation(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         acceptAudioCall(); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (isCtrlOrAlt(ev) && shiftKey && (key === 'd' || key === 'D')) { | 
					
						
							|  |  |  |         ev.preventDefault(); | 
					
						
							|  |  |  |         ev.stopPropagation(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         declineCall(); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     [acceptAudioCall, acceptVideoCall, declineCall] | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function useStartCallShortcuts( | 
					
						
							|  |  |  |   startAudioCall: () => unknown, | 
					
						
							|  |  |  |   startVideoCall: () => unknown | 
					
						
							|  |  |  | ): KeyboardShortcutHandlerType { | 
					
						
							|  |  |  |   return useCallback( | 
					
						
							|  |  |  |     ev => { | 
					
						
							|  |  |  |       const { shiftKey } = ev; | 
					
						
							|  |  |  |       const key = KeyboardLayout.lookup(ev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (isCtrlOrAlt(ev) && shiftKey && (key === 'c' || key === 'C')) { | 
					
						
							|  |  |  |         ev.preventDefault(); | 
					
						
							|  |  |  |         ev.stopPropagation(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         startAudioCall(); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (isCtrlOrAlt(ev) && shiftKey && (key === 'y' || key === 'Y')) { | 
					
						
							|  |  |  |         ev.preventDefault(); | 
					
						
							|  |  |  |         ev.stopPropagation(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         startVideoCall(); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     [startAudioCall, startVideoCall] | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-15 14:51:58 -04:00
										 |  |  | export function useStartRecordingShortcut( | 
					
						
							| 
									
										
										
										
											2021-09-29 16:23:06 -04:00
										 |  |  |   startAudioRecording: () => unknown | 
					
						
							|  |  |  | ): KeyboardShortcutHandlerType { | 
					
						
							| 
									
										
										
										
											2021-10-15 14:51:58 -04:00
										 |  |  |   return useCallback( | 
					
						
							|  |  |  |     ev => { | 
					
						
							|  |  |  |       const { shiftKey } = ev; | 
					
						
							|  |  |  |       const key = KeyboardLayout.lookup(ev); | 
					
						
							| 
									
										
										
										
											2021-09-29 15:21:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-15 14:51:58 -04:00
										 |  |  |       if (isCmdOrCtrl(ev) && shiftKey && (key === 'v' || key === 'V')) { | 
					
						
							|  |  |  |         ev.preventDefault(); | 
					
						
							|  |  |  |         ev.stopPropagation(); | 
					
						
							| 
									
										
										
										
											2021-09-29 16:23:06 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-15 14:51:58 -04:00
										 |  |  |         startAudioRecording(); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-09-29 16:23:06 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-15 14:51:58 -04:00
										 |  |  |       return false; | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     [startAudioRecording] | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function useAttachFileShortcut( | 
					
						
							|  |  |  |   attachFile: () => unknown | 
					
						
							|  |  |  | ): KeyboardShortcutHandlerType { | 
					
						
							|  |  |  |   return useCallback( | 
					
						
							|  |  |  |     ev => { | 
					
						
							|  |  |  |       const { shiftKey } = ev; | 
					
						
							|  |  |  |       const key = KeyboardLayout.lookup(ev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (isCmdOrCtrl(ev) && !shiftKey && (key === 'u' || key === 'U')) { | 
					
						
							|  |  |  |         ev.preventDefault(); | 
					
						
							|  |  |  |         ev.stopPropagation(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         attachFile(); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-09-29 16:23:06 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-15 14:51:58 -04:00
										 |  |  |       return false; | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     [attachFile] | 
					
						
							|  |  |  |   ); | 
					
						
							| 
									
										
										
										
											2021-09-29 16:23:06 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-02 19:40:33 -05:00
										 |  |  | export function useToggleReactionPicker( | 
					
						
							|  |  |  |   handleReact: () => unknown | 
					
						
							|  |  |  | ): KeyboardShortcutHandlerType { | 
					
						
							|  |  |  |   return useCallback( | 
					
						
							|  |  |  |     ev => { | 
					
						
							|  |  |  |       const { shiftKey } = ev; | 
					
						
							|  |  |  |       const key = KeyboardLayout.lookup(ev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (isCmdOrCtrl(ev) && shiftKey && (key === 'e' || key === 'E')) { | 
					
						
							|  |  |  |         ev.preventDefault(); | 
					
						
							|  |  |  |         ev.stopPropagation(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         handleReact(); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     [handleReact] | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 16:23:06 -04:00
										 |  |  | export function useKeyboardShortcuts( | 
					
						
							|  |  |  |   ...eventHandlers: Array<KeyboardShortcutHandlerType> | 
					
						
							|  |  |  | ): void { | 
					
						
							|  |  |  |   useEffect(() => { | 
					
						
							|  |  |  |     function handleKeydown(ev: KeyboardEvent): void { | 
					
						
							|  |  |  |       eventHandlers.some(eventHandler => eventHandler(ev)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     document.addEventListener('keydown', handleKeydown); | 
					
						
							|  |  |  |     return () => { | 
					
						
							|  |  |  |       document.removeEventListener('keydown', handleKeydown); | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   }, [eventHandlers]); | 
					
						
							|  |  |  | } |