Change Page Up/Page Down hotkeys to require Alt modifier key (#39427)

This commit is contained in:
diondiondion 2026-06-15 12:24:08 +02:00 committed by Claire
parent dc53b0e077
commit 01d03d67a8
3 changed files with 47 additions and 7 deletions

View File

@ -1,6 +1,6 @@
import { useEffect, useRef } from 'react';
import { normalizeKey, isKeyboardEvent } from './utils';
import { normalizeKey, isKeyboardEvent, matchesKeyCode } from './utils';
/**
* In case of multiple hotkeys matching the pressed key(s),
@ -55,6 +55,30 @@ function any(...keys: string[]): KeyMatcher {
});
}
/**
* Matches any matcher function out of those provided
*/
function anyMatcher(...matchers: KeyMatcher[]): KeyMatcher {
return (event) => {
let match: ReturnType<KeyMatcher> | undefined;
for (const matcher of matchers) {
const matcherResult = matcher(event);
if (matcherResult.isMatch) {
match = matcherResult;
break;
}
}
return (
match ?? {
isMatch: false,
priority: hotkeyPriority.singleKey,
}
);
};
}
/**
* Matches a single key combined with the option/alt modifier
*/
@ -62,7 +86,7 @@ function optionPlus(key: string): KeyMatcher {
return (event) => ({
// Matching against event.code here as alt combos are often
// mapped to other characters
isMatch: event.altKey && event.code === `Key${key.toUpperCase()}`,
isMatch: event.altKey && matchesKeyCode(key, event.code),
priority: hotkeyPriority.combo,
});
}
@ -109,8 +133,8 @@ const hotkeyMatcherMap = {
mention: just('m'),
open: any('enter', 'o'),
openProfile: just('p'),
moveDown: any('j', 'pagedown'),
moveUp: any('k', 'pageup'),
moveDown: anyMatcher(just('j'), optionPlus('pagedown')),
moveUp: anyMatcher(just('k'), optionPlus('pageup')),
moveToTop: just('0'),
toggleHidden: just('x'),
toggleSensitive: just('h'),
@ -188,7 +212,7 @@ export function useHotkeys<T extends HTMLElement>(handlers: HandlerMap) {
if (shouldHandleEvent) {
const matchCandidates: {
// A candidate will be have an undefined handler if it's matched,
// A candidate can have an undefined handler if it's matched,
// but handled in a parent component rather than this one.
handler: HandlerFunction | undefined;
priority: number;

View File

@ -2,6 +2,9 @@ export function isKeyboardEvent(event: Event): event is KeyboardEvent {
return 'key' in event;
}
/**
* Normalises key values to consistent lowercase strings
*/
export function normalizeKey(key: string): string {
const lowerKey = key.toLowerCase();
@ -27,3 +30,16 @@ export function normalizeKey(key: string): string {
return lowerKey;
}
}
/**
* Compare whether a key matches an `event.code` value,
* with support for single-letter keys (which are otherwise
* represented with a `Key` prefix, e.g. `m` is `KeyM`).
*/
export function matchesKeyCode(key: string, code: string) {
if (key.length === 1) {
return code === `Key${key.toUpperCase()}`;
} else {
return code.toLowerCase() === key.toLowerCase();
}
}

View File

@ -88,11 +88,11 @@ class KeyboardShortcuts extends ImmutablePureComponent {
<td><FormattedMessage id='keyboard_shortcuts.toggle_sensitivity' defaultMessage='to show/hide media' /></td>
</tr>
<tr>
<td><kbd>k</kbd>, <FormattedMessage id='keyboard_shortcuts.keys.page_up' defaultMessage='Page Up' tagName='kbd' /></td>
<td><kbd>k</kbd>, <FormattedMessage id='keyboard_shortcuts.keys.alt' defaultMessage='Alt' tagName='kbd' />+<FormattedMessage id='keyboard_shortcuts.keys.page_up' defaultMessage='Page Up' tagName='kbd' /></td>
<td><FormattedMessage id='keyboard_shortcuts.up' defaultMessage='to move up in the list' /></td>
</tr>
<tr>
<td><kbd>j</kbd>, <FormattedMessage id='keyboard_shortcuts.keys.page_down' defaultMessage='Page Down' tagName='kbd' /></td>
<td><kbd>j</kbd>, <FormattedMessage id='keyboard_shortcuts.keys.alt' defaultMessage='Alt' tagName='kbd' />+<FormattedMessage id='keyboard_shortcuts.keys.page_down' defaultMessage='Page Down' tagName='kbd' /></td>
<td><FormattedMessage id='keyboard_shortcuts.down' defaultMessage='to move down in the list' /></td>
</tr>
<tr>