Game browser: Backspace goes up a directory, Windows raw input flags key repeats

With no type-to-search active, Backspace goes to the parent directory. Never
on a repeat, so holding it doesn't climb to the root. Not every platform
flags repeats, so the browser also tracks whether it's held.

Windows raw input now flags auto-repeated key downs as IS_REPEAT, like
Android and UWP, and forgets the held keys it releases on losing focus. The
UI drops OS repeats of a key it's already repeating itself, so held arrows
don't double up (they were dropped before too, a step later).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-10-19 11:36:30 +02:00
1 parent 193dd01c32
commit b0382ed91a
5 files changed
+36 -3

No files matched your search

+12
View File
@@ -257,6 +257,18 @@ static bool KeyToFocusMove(const KeyInput &key, FocusMove *move) {
KeyEventResult KeyEventToFocusMoves(const KeyInput &key) {
KeyEventResult retval = KeyEventResult::PASS_THROUGH;
// The OS's own repeats of a key we're already repeating (see ProcessHeldKeys) would double
// up with ours, in a text field for example.
if ((key.flags & KeyInputFlags::DOWN) && (key.flags & KeyInputFlags::IS_REPEAT) && !heldKeys.empty()) {
HeldKey hk;
hk.key = key.keyCode;
hk.deviceId = key.deviceId;
hk.triggerTime = 0.0; // irrelevant
hk.move = FocusMove::NEXT; // irrelevant, not part of the comparison
if (heldKeys.find(hk) != heldKeys.end()) {
return KeyEventResult::IGNORE_KEY;
}
}
// Ignore repeats for focus moves.
if ((key.flags & KeyInputFlags::DOWN) && !(key.flags & KeyInputFlags::IS_REPEAT)) {
FocusMove move;
+16
View File
@@ -781,6 +781,22 @@ bool GameBrowser::Key(const KeyInput &input) {
}
}
// Backspace with no search going also goes to the parent directory, as in file managers. Never on
// a repeat, or holding it would climb to the root (or carry on up after clearing a search). Not
// every platform flags repeats, so this also tracks whether it's held.
if (input.keyCode == NKCODE_DEL && input.deviceId == DEVICE_ID_KEYBOARD) {
if (input.flags & KeyInputFlags::UP) {
backspaceHeld_ = false;
} else if (input.flags & KeyInputFlags::DOWN) {
const bool repeat = backspaceHeld_ || (input.flags & KeyInputFlags::IS_REPEAT);
backspaceHeld_ = true;
if (!repeat && search_.searchFilter.empty() && (browseFlags_ & BrowseFlags::NAVIGATE) && path_.CanNavigateUp()) {
NavigateUp();
return true;
}
}
}
bool retval = LinearLayout::Key(input);
if (retval) {
return true;
+1
View File
@@ -90,6 +90,7 @@ private:
Path focusPath_;
// Set when entering a directory, for Refresh to focus its first entry.
bool focusFirstItem_ = false;
bool backspaceHeld_ = false;
bool listingPending_ = false;
bool refreshPending_ = false;
float lastScale_ = 1.0f;
+1 -2
View File
@@ -507,9 +507,8 @@ bool ViewSearch::Key(UI::ViewGroup *viewGroup, const KeyInput &input) {
// TODO: Restore focus state here.
UI::EnableFocusMovement(false);
}
} else {
// Empty search filter. Navigate upwards on backspace?
}
// With an empty filter, it's up to the owner (the game browser goes up a directory).
} else if (!searchFilter.empty() && input.keyCode == NKCODE_ESCAPE) {
searchFilter.clear();
ApplySearchFilter(viewGroup, false);
+6 -1
View File
@@ -264,8 +264,11 @@ namespace WindowsRawInput {
key.keyCode = GetTrueVKey(raw->data.keyboard);
if (key.keyCode) {
// Windows auto-repeats a held key as more key downs. Flag them, like other platforms do.
if (!keyboardKeysDown.insert(key.keyCode).second) {
key.flags |= KeyInputFlags::IS_REPEAT;
}
NativeKey(key);
keyboardKeysDown.insert(key.keyCode);
}
} else if (raw->data.keyboard.Message == WM_KEYUP || raw->data.keyboard.Message == WM_SYSKEYUP) {
// A key released while Alt is held comes as WM_SYSKEYUP.
@@ -434,6 +437,8 @@ namespace WindowsRawInput {
key.keyCode = *i;
NativeKey(key);
}
// Or the next press of one would count as a repeat.
keyboardKeysDown.clear();
focused = false;
}