Skip to content

Commit

Permalink
Merge branch 'fork/mapringg/mac-shortcuts'
Browse files Browse the repository at this point in the history
  • Loading branch information
enricoros committed Jul 7, 2024
2 parents 3a44f70 + b126372 commit 95aa0da
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 114 deletions.
4 changes: 2 additions & 2 deletions src/apps/chat/AppChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { useCapabilityTextToImage } from '~/modules/t2i/t2i.client';

import { ConfirmationModal } from '~/common/components/ConfirmationModal';
import { ConversationsManager } from '~/common/chats/ConversationsManager';
import { GlobalShortcutItem, ShortcutKeyName, useGlobalShortcuts } from '~/common/components/useGlobalShortcut';
import { GlobalShortcutDefinition, ShortcutKeyName, useGlobalShortcuts } from '~/common/components/useGlobalShortcuts';
import { PanelResizeInset } from '~/common/components/panes/GoodPanelResizeHandler';
import { PreferencesTab, useOptimaLayout, usePluggableOptimaLayout } from '~/common/layout/optima/useOptimaLayout';
import { ScrollToBottom } from '~/common/scroll-to-bottom/ScrollToBottom';
Expand Down Expand Up @@ -397,7 +397,7 @@ export function AppChat() {
openLlmOptions(chatLLMId);
}, [openLlmOptions]);

const shortcuts = React.useMemo((): GlobalShortcutItem[] => [
const shortcuts = React.useMemo((): GlobalShortcutDefinition[] => [
// focused conversation
['b', true, true, false, handleMessageBeamLastInFocusedPane],
['r', true, true, false, handleMessageRegenerateLastInFocusedPane],
Expand Down
4 changes: 2 additions & 2 deletions src/apps/chat/components/ChatBarAltBeam.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { BeamStoreApi, useBeamStore } from '~/modules/beam/store-beam.hooks';
import { ConfirmationModal } from '~/common/components/ConfirmationModal';
import { GoodTooltip } from '~/common/components/GoodTooltip';
import { KeyStroke } from '~/common/components/KeyStroke';
import { ShortcutKeyName, useGlobalShortcut } from '~/common/components/useGlobalShortcut';
import { ShortcutKeyName, useGlobalShortcuts } from '~/common/components/useGlobalShortcuts';
import { animationBackgroundBeamGather, animationColorBeamScatterINV, animationEnterBelow } from '~/common/util/animUtils';


Expand Down Expand Up @@ -59,7 +59,7 @@ export function ChatBarAltBeam(props: {


// intercept esc this beam is focused
useGlobalShortcut(ShortcutKeyName.Esc, false, false, false, handleCloseBeam);
useGlobalShortcuts([[ShortcutKeyName.Esc, false, false, false, handleCloseBeam]]);


return (
Expand Down
6 changes: 3 additions & 3 deletions src/apps/chat/components/ChatMessageList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type { DiagramConfig } from '~/modules/aifn/digrams/DiagramsModal';
import type { ConversationHandler } from '~/common/chats/ConversationHandler';
import { InlineError } from '~/common/components/InlineError';
import { PreferencesTab, useOptimaLayout } from '~/common/layout/optima/useOptimaLayout';
import { ShortcutKeyName, useGlobalShortcut } from '~/common/components/useGlobalShortcut';
import { ShortcutKeyName, useGlobalShortcuts } from '~/common/components/useGlobalShortcuts';
import { createDMessage, DConversationId, DMessage, DMessageUserFlag, getConversation, messageToggleUserFlag, useChatStore } from '~/common/state/store-chats';
import { useBrowserTranslationWarning } from '~/common/components/useIsBrowserTranslating';
import { useCapabilityElevenLabs } from '~/common/components/useCapabilities';
Expand Down Expand Up @@ -186,9 +186,9 @@ export function ChatMessageList(props: {
setSelectedMessages(new Set());
};

useGlobalShortcut(props.isMessageSelectionMode && ShortcutKeyName.Esc, false, false, false, () => {
useGlobalShortcuts([[props.isMessageSelectionMode && ShortcutKeyName.Esc, false, false, false, () => {
props.setIsMessageSelectionMode(false);
});
}]]);


// text-diff functionality: only diff the last message and when it's complete (not typing), and they're similar in size
Expand Down
6 changes: 3 additions & 3 deletions src/apps/chat/components/composer/Composer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import { supportsScreenCapture } from '~/common/util/screenCaptureUtils';
import { useAppStateStore } from '~/common/state/store-appstate';
import { useChatOverlayStore } from '~/common/chats/store-chat-overlay-vanilla';
import { useDebouncer } from '~/common/components/useDebouncer';
import { useGlobalShortcut } from '~/common/components/useGlobalShortcut';
import { useGlobalShortcuts } from '~/common/components/useGlobalShortcuts';
import { useUICounter, useUIPreferencesStore } from '~/common/state/store-ui';
import { useUXLabsStore } from '~/common/state/store-ux-labs';

Expand Down Expand Up @@ -399,7 +399,7 @@ export function Composer(props: {
const { isSpeechEnabled, isSpeechError, isRecordingAudio, isRecordingSpeech, toggleRecording } =
useSpeechRecognition(onSpeechResultCallback, chatMicTimeoutMs || 2000);

useGlobalShortcut('m', true, false, false, toggleRecording);
useGlobalShortcuts([['m', true, false, false, toggleRecording]]);

const micIsRunning = !!speechInterimResult;
const micContinuationTrigger = micContinuation && !micIsRunning && !assistantAbortible && !isSpeechError;
Expand Down Expand Up @@ -451,7 +451,7 @@ export function Composer(props: {
}
}, [attachAppendFile]);

useGlobalShortcut(supportsClipboardRead ? 'v' : false, true, true, false, attachAppendClipboardItems);
useGlobalShortcuts([[supportsClipboardRead ? 'v' : false, true, true, false, attachAppendClipboardItems]]);

const handleAttachmentInlineText = React.useCallback((attachmentId: AttachmentId) => {
setComposeText(currentText => {
Expand Down
53 changes: 27 additions & 26 deletions src/apps/settings-modal/ShortcutsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,38 @@ import * as React from 'react';
import { BlocksRenderer } from '~/modules/blocks/BlocksRenderer';

import { GoodModal } from '~/common/components/GoodModal';
import { isMacUser } from '~/common/util/pwaUtils';
import { platformAwareKeystrokes } from '~/common/components/KeyStroke';
import { useIsMobile } from '~/common/components/useMatchMedia';


const shortcutsMd = platformAwareKeystrokes(`
| Shortcut | Description |
|---------------------|-------------------------------------------------|
| **Edit** | |
| Shift + Enter | Newline |
| Alt + Enter | Append (no response) |
| Ctrl + Shift + B | **Beam** last message |
| Ctrl + Shift + R | **Regenerate** last message |
| Ctrl + Shift + V | Attach clipboard (better than Ctrl + V) |
| Ctrl + M | Microphone (voice typing) |
| **Chats** | |
| Ctrl + O | Open Chat File ... |
| Ctrl + S | Save Chat File ... |
| Ctrl + Alt + N | **New** chat |
| Ctrl + Alt + X | **Reset** chat |
| Ctrl + Alt + D | **Delete** chat |
| Ctrl + Alt + B | **Branch** chat |
| Ctrl + Alt + Left | **Previous** chat (in history) |
| Ctrl + Alt + Right | **Next** chat (in history) |
| **Settings** | |
| Ctrl + Shift + P | ⚙️ Preferences |
| Ctrl + Shift + M | 🧠 Models |
| Ctrl + Shift + O | 💬 Options (current Chat Model) |
| Ctrl + Shift + + | Increase Text Size |
| Ctrl + Shift + - | Decrease Text Size |
| Ctrl + Shift + ? | Shortcuts |
| Shortcut | Description |
|-----------------------------------------|-------------------------------------------------|
| **Edit** | |
| Shift + Enter | Newline |
| Alt + Enter | Append (no response) |
| Ctrl + Shift + B | **Beam** last message |
| Ctrl + Shift + R | **Regenerate** last message |
| Ctrl + Shift + V | Attach clipboard (better than Ctrl + V) |
| Ctrl + M | Microphone (voice typing) |
| **Chats** | |
| Ctrl + O | Open Chat ... |
| Ctrl + S | Save Chat ... |
| Ctrl + ${isMacUser ? '' : 'Alt +'} N | **New** chat |
| Ctrl + ${isMacUser ? '' : 'Alt +'} X | **Reset** chat |
| Ctrl + ${isMacUser ? '' : 'Alt +'} D | **Delete** chat |
| Ctrl + ${isMacUser ? '' : 'Alt +'} B | **Branch** chat |
| Ctrl + Alt + Left | **Previous** chat (in history) |
| Ctrl + Alt + Right | **Next** chat (in history) |
| **Settings** | |
| Ctrl + Shift + P | ⚙️ Preferences |
| Ctrl + Shift + M | 🧠 Models |
| Ctrl + Shift + O | 💬 Options (current Chat Model) |
| Ctrl + Shift + + | Increase Text Size |
| Ctrl + Shift + - | Decrease Text Size |
| Ctrl + Shift + ${isMacUser ? '/' : '?'} | Shortcuts |
`).trim();

Expand All @@ -55,4 +56,4 @@ export function ShortcutsModal(props: { onClose: () => void }) {
/>
</GoodModal>
);
}
}
4 changes: 2 additions & 2 deletions src/common/components/ExplainerCarousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { BlocksRenderer } from '~/modules/blocks/BlocksRenderer';

import { AgiSquircleIcon } from '~/common/components/icons/AgiSquircleIcon';
import { ChatBeamIcon } from '~/common/components/icons/ChatBeamIcon';
import { GlobalShortcutItem, ShortcutKeyName, useGlobalShortcuts } from '~/common/components/useGlobalShortcut';
import { GlobalShortcutDefinition, ShortcutKeyName, useGlobalShortcuts } from '~/common/components/useGlobalShortcuts';
import { hasGoogleAnalytics } from '~/common/components/GoogleAnalytics';
import { useIsMobile } from '~/common/components/useMatchMedia';
import { animationTextShadowLimey } from '~/common/util/animUtils';
Expand Down Expand Up @@ -159,7 +159,7 @@ export function ExplainerCarousel(props: {
}, [props.explainerId]);


const shortcuts = React.useMemo((): GlobalShortcutItem[] => [
const shortcuts = React.useMemo((): GlobalShortcutDefinition[] => [
[ShortcutKeyName.Left, false, false, false, handlePrevPage],
[ShortcutKeyName.Right, false, false, false, handleNextPage],
], [handleNextPage, handlePrevPage]);
Expand Down
2 changes: 1 addition & 1 deletion src/common/components/KeyStroke.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { isMacUser } from '~/common/util/pwaUtils';
export function platformAwareKeystrokes(text: string) {
return isMacUser
? text
.replaceAll('Ctrl', '' /* Command */)
.replaceAll('Ctrl', '' /* Control */)
.replaceAll('Alt', '⌥' /* Option */)
.replaceAll('Shift', '⇧')
// Optional: Replace "Enter" with "Return" if you want to align with Mac keyboard labeling
Expand Down
72 changes: 0 additions & 72 deletions src/common/components/useGlobalShortcut.ts

This file was deleted.

44 changes: 44 additions & 0 deletions src/common/components/useGlobalShortcuts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import * as React from 'react';

import { isMacUser } from '../util/pwaUtils';


export const ShortcutKeyName = {
Esc: 'Escape',
Left: 'ArrowLeft',
Right: 'ArrowRight',
};

export type GlobalShortcutDefinition = [key: string | false, useCtrl: boolean, useShift: boolean, useAltForNonMac: boolean, action: () => void];

/**
* Registers multiple global keyboard shortcuts -> function mappings.
*
* Important notes below:
* - [MAC only] the Alt key is ignored even if defined in the shortcut
* - [MAC only] are not using the command key at the moment, as it interfered with browser shortcuts
* - stabilize the shortcuts definition (e.g. React.useMemo()) to avoid re-registering the shortcuts at every render
*
*/
export const useGlobalShortcuts = (shortcuts: GlobalShortcutDefinition[]) => {
React.useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
for (const [key, useCtrl, useShift, useAltForNonMac, action] of shortcuts) {
if (
key &&
(useCtrl === event.ctrlKey) &&
(useShift === event.shiftKey) &&
(isMacUser /* Mac users won't need the Alt keys */ || useAltForNonMac === event.altKey) &&
event.key.toLowerCase() === key.toLowerCase()
) {
event.preventDefault();
event.stopPropagation();
action();
break;
}
}
};
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, [shortcuts]);
};
7 changes: 4 additions & 3 deletions src/common/layout/optima/useOptimaLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import * as React from 'react';

import type { DLLMId } from '~/modules/llms/store-llms';

import { GlobalShortcutItem, useGlobalShortcuts } from '~/common/components/useGlobalShortcut';
import { GlobalShortcutDefinition, useGlobalShortcuts } from '~/common/components/useGlobalShortcuts';
import { isMacUser } from '~/common/util/pwaUtils';


const DEBUG_OPTIMA_LAYOUT_PLUGGING = false;
Expand Down Expand Up @@ -114,8 +115,8 @@ export function OptimaLayoutProvider(props: { children: React.ReactNode }) {


// global shortcuts for Optima
const shortcuts = React.useMemo((): GlobalShortcutItem[] => [
['?', true, true, false, actions.openShortcuts],
const shortcuts = React.useMemo((): GlobalShortcutDefinition[] => [
[isMacUser ? '/' : '?', true, true, false, actions.openShortcuts],
['m', true, true, false, actions.openModelsSetup],
['p', true, true, false, actions.openPreferencesTab],
], [actions]);
Expand Down

0 comments on commit 95aa0da

Please sign in to comment.