diff --git a/fluxer_app/src/features/input/state/InputKeybind.ts b/fluxer_app/src/features/input/state/InputKeybind.ts index a211e2c72..48039dcfa 100644 --- a/fluxer_app/src/features/input/state/InputKeybind.ts +++ b/fluxer_app/src/features/input/state/InputKeybind.ts @@ -114,12 +114,14 @@ import { } from '@app/features/input/state/KeybindResolution'; import { DEFAULT_KEYBOARD_SHORTCUTS_OVERLAY_COMBO, - getKeyboardShortcutsOverlayComboForCurrentLayout, + DEFAULT_START_DM_CALL_COMBO, + getKeyboardLayoutDefaultCombosForCurrentLayout, keyCombosEqual, SHIFTED_SLASH_FALLBACK_KEYBOARD_SHORTCUTS_OVERLAY_COMBO, } from '@app/features/input/utils/KeyboardShortcutLayoutUtils'; import AppStorage from '@app/features/platform/state/PersistentStorage'; import {awaitHydration, makePersistent} from '@app/features/platform/utils/MobXPersistence'; +import {isApplePlatform} from '@app/features/platform/utils/PlatformHelpers'; import {initializeStore} from '@app/features/platform/utils/StoreInitialization'; import {makeSyncedField} from '@app/features/user/state/SyncedField'; import UserSettings from '@app/features/user/state/UserSettings'; @@ -222,6 +224,7 @@ const createBuiltinDisableMarker = ( const getDefaultKeybinds = ( i18n: KeybindLabelI18n, keyboardShortcutsOverlayCombo: KeyCombo = DEFAULT_KEYBOARD_SHORTCUTS_OVERLAY_COMBO, + startDmCallCombo: KeyCombo = DEFAULT_START_DM_CALL_COMBO, ): ReadonlyArray => [ { @@ -360,7 +363,7 @@ const getDefaultKeybinds = ( { action: 'nav_history_back', label: i18n._(MOVE_BACK_THROUGH_VIEWED_CHANNEL_HISTORY_DESCRIPTOR), - combo: {key: '[', ctrlOrMeta: true}, + combo: isApplePlatform() ? {key: '[', ctrlOrMeta: true} : {key: 'ArrowLeft', alt: true}, ignoreWhileTyping: true, editableFocusBehavior: 'allow', section: 'navigation', @@ -368,7 +371,7 @@ const getDefaultKeybinds = ( { action: 'nav_history_forward', label: i18n._(MOVE_FORWARD_THROUGH_VIEWED_CHANNEL_HISTORY_DESCRIPTOR), - combo: {key: ']', ctrlOrMeta: true}, + combo: isApplePlatform() ? {key: ']', ctrlOrMeta: true} : {key: 'ArrowRight', alt: true}, ignoreWhileTyping: true, editableFocusBehavior: 'allow', section: 'navigation', @@ -412,13 +415,13 @@ const getDefaultKeybinds = ( { action: 'nav_guild_tab_prev', label: i18n._(SWITCH_TO_PREVIOUS_COMMUNITY_OR_DMS_DESCRIPTOR), - combo: {key: 'Tab', ctrlOrMeta: true, shift: true}, + combo: {key: 'Tab', ctrl: true, shift: true}, section: 'navigation', }, { action: 'nav_guild_tab_next', label: i18n._(SWITCH_TO_NEXT_COMMUNITY_OR_DMS_DESCRIPTOR), - combo: {key: 'Tab', ctrlOrMeta: true}, + combo: {key: 'Tab', ctrl: true}, section: 'navigation', }, { @@ -666,7 +669,7 @@ const getDefaultKeybinds = ( { action: 'voice_start_dm_call', label: i18n._(START_A_CALL_IN_A_DM_OR_GROUP_DESCRIPTOR), - combo: {key: '`', code: 'Backquote', ctrl: true}, + combo: {...startDmCallCombo}, section: 'voice_and_video', }, { @@ -899,6 +902,7 @@ class Keybind { private i18n: I18n | null = null; private initialized = false; private keyboardShortcutsOverlayCombo: KeyCombo = {...DEFAULT_KEYBOARD_SHORTCUTS_OVERLAY_COMBO}; + private startDmCallCombo: KeyCombo = {...DEFAULT_START_DM_CALL_COMBO}; private holdSources = new HoldSources(() => this.pushToTalkReleaseDelay); constructor() { @@ -1011,9 +1015,10 @@ class Keybind { async refreshKeyboardShortcutLayout(): Promise { try { - const combo = await getKeyboardShortcutsOverlayComboForCurrentLayout(); - if (!combo) return; - this.setKeyboardShortcutsOverlayCombo(combo); + const combos = await getKeyboardLayoutDefaultCombosForCurrentLayout(); + if (!combos) return; + this.setKeyboardShortcutsOverlayCombo(combos.keyboardShortcutsOverlay); + this.setStartDmCallCombo(combos.startDmCall); } catch {} } @@ -1028,8 +1033,15 @@ class Keybind { }); } + private setStartDmCallCombo(combo: KeyCombo): void { + if (keyCombosEqual(this.startDmCallCombo, combo)) return; + runInAction(() => { + this.startDmCallCombo = {...combo}; + }); + } + private get defaultKeybinds(): ReadonlyArray { - return getDefaultKeybinds(this.getLabelI18n(), this.keyboardShortcutsOverlayCombo); + return getDefaultKeybinds(this.getLabelI18n(), this.keyboardShortcutsOverlayCombo, this.startDmCallCombo); } private get runtimeDispatchDefaults(): ReadonlyArray { diff --git a/fluxer_app/src/features/input/utils/KeybindUtils.ts b/fluxer_app/src/features/input/utils/KeybindUtils.ts index 05e6f7010..c3b9a11aa 100644 --- a/fluxer_app/src/features/input/utils/KeybindUtils.ts +++ b/fluxer_app/src/features/input/utils/KeybindUtils.ts @@ -211,6 +211,7 @@ export function formatPrimaryKeySymbol(i18n: I18n, rawKey: string): string { if (rawKey === 'Enter' || rawKey === 'Return') return isMacPlatform() ? '⏎' : i18n._(ENTER_DESCRIPTOR); if (rawKey === 'Tab') return i18n._(TAB_DESCRIPTOR); if (rawKey === 'Backquote' || rawKey === '`') return '`'; + if (rawKey === 'Quote') return "'"; if (rawKey === '[' || rawKey === ']') return rawKey; if (/^Key[A-Z]$/.test(rawKey)) return rawKey.slice(3); if (/^Digit[0-9]$/.test(rawKey)) return rawKey.slice(5); diff --git a/fluxer_app/src/features/input/utils/KeyboardShortcutLayoutUtils.ts b/fluxer_app/src/features/input/utils/KeyboardShortcutLayoutUtils.ts index dcb7ce88e..c0b13ccdd 100644 --- a/fluxer_app/src/features/input/utils/KeyboardShortcutLayoutUtils.ts +++ b/fluxer_app/src/features/input/utils/KeyboardShortcutLayoutUtils.ts @@ -1,6 +1,7 @@ // SPDX-License-Identifier: AGPL-3.0-or-later import type {KeyCombo} from '@app/features/input/state/InputKeybind'; +import {isPrintableShortcutKey} from '@fluxer/desktop_ipc/src/GlobalShortcutKeyNames'; interface KeyboardLayoutMapReader { get(code: string): string | undefined; @@ -18,6 +19,12 @@ export interface KeyboardShortcutsOverlayFallbackEvent { export const DEFAULT_KEYBOARD_SHORTCUTS_OVERLAY_COMBO: KeyCombo = {key: '/', ctrlOrMeta: true}; export const SHIFTED_SLASH_FALLBACK_KEYBOARD_SHORTCUTS_OVERLAY_COMBO: KeyCombo = {key: '.', ctrlOrMeta: true}; +export const DEFAULT_START_DM_CALL_COMBO: KeyCombo = {key: '', code: 'Quote', ctrl: true}; + +interface KeyboardLayoutDefaultCombos { + keyboardShortcutsOverlay: KeyCombo; + startDmCall: KeyCombo; +} const NON_NUMPAD_PRINTABLE_LAYOUT_CODES = [ 'Backquote', @@ -110,16 +117,25 @@ function getKeyboardShortcutsOverlayComboForLayoutMap(layoutMap: KeyboardLayoutM return copyKeyCombo(SHIFTED_SLASH_FALLBACK_KEYBOARD_SHORTCUTS_OVERLAY_COMBO); } +function getStartDmCallComboForLayoutMap(layoutMap: KeyboardLayoutMapReader): KeyCombo { + const key = layoutMap.get('Quote'); + if (!isPrintableShortcutKey(key)) return copyKeyCombo(DEFAULT_START_DM_CALL_COMBO); + return {...DEFAULT_START_DM_CALL_COMBO, key}; +} + function getNavigatorKeyboardLayoutProvider(): KeyboardLayoutProvider | null { if (typeof navigator === 'undefined') return null; return (navigator as NavigatorWithKeyboardLayout).keyboard ?? null; } -export async function getKeyboardShortcutsOverlayComboForCurrentLayout(): Promise { +export async function getKeyboardLayoutDefaultCombosForCurrentLayout(): Promise { const keyboard = getNavigatorKeyboardLayoutProvider(); if (typeof keyboard?.getLayoutMap !== 'function') return null; const layoutMap = await keyboard.getLayoutMap(); - return getKeyboardShortcutsOverlayComboForLayoutMap(layoutMap); + return { + keyboardShortcutsOverlay: getKeyboardShortcutsOverlayComboForLayoutMap(layoutMap), + startDmCall: getStartDmCallComboForLayoutMap(layoutMap), + }; } export function shouldUseKeyboardShortcutsOverlayFallbackFromEvent(