diff --git a/Common/UI/Root.cpp b/Common/UI/Root.cpp index de7c963749..24eeb93bd4 100644 --- a/Common/UI/Root.cpp +++ b/Common/UI/Root.cpp @@ -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; diff --git a/UI/GameBrowser.cpp b/UI/GameBrowser.cpp index 7ea5f65cf1..579518a9c1 100644 --- a/UI/GameBrowser.cpp +++ b/UI/GameBrowser.cpp @@ -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; diff --git a/UI/GameBrowser.h b/UI/GameBrowser.h index 02997a8c83..75ad56a646 100644 --- a/UI/GameBrowser.h +++ b/UI/GameBrowser.h @@ -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; diff --git a/UI/MiscViews.cpp b/UI/MiscViews.cpp index cb44651871..4267749028 100644 --- a/UI/MiscViews.cpp +++ b/UI/MiscViews.cpp @@ -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); diff --git a/Windows/RawInput.cpp b/Windows/RawInput.cpp index e820ca93a1..47a0392633 100644 --- a/Windows/RawInput.cpp +++ b/Windows/RawInput.cpp @@ -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; }