[RE] file-pad: opt-in Keystroke REPEAT, at the SDL driver's own constants
Some checks failed
Orchestrator / Lint (push) Failing after 1m49s
Orchestrator / Commit Message Validation (push) Has been skipped
Orchestrator / Windows (x86-64) (push) Has been skipped
Orchestrator / Linux (x86-64) (push) Has been skipped
Orchestrator / Create Release (push) Has been skipped
Some checks failed
Orchestrator / Lint (push) Failing after 1m49s
Orchestrator / Commit Message Validation (push) Has been skipped
Orchestrator / Windows (x86-64) (push) Has been skipped
Orchestrator / Linux (x86-64) (push) Has been skipped
Orchestrator / Create Release (push) Has been skipped
The instrument behind the F1 menu-repeat measurement. It was uncommitted for a day while the numbers it produced were already shipping in the port. The file driver deliberately emits exactly one event per press -- repeat is what makes scripted menu steps overshoot -- so it structurally could not show whether the GAME repeats a held direction. Measured through it, a held (down) moved the cursor once and never again, at any hold length. That is a property of the driver, not of the game, and the page that recorded it said so. `--pad_file_repeat` opts in, off by default, so no existing script changes. It reuses the SDL driver's Waiting/Repeating state machine and its constants VERBATIM (HID_SDL_REPEAT_DELAY=400, HID_SDL_REPEAT_RATE=100, guest-time ms) rather than re-deriving them -- the point is to be a fair stand-in for a real controller, and a re-derived constant would only measure our own arithmetic. With it, the cursor cycled the whole 5-item menu for as long as the button was held: 19 distinct positions, 12 frames to the first repeat, 4 frames between the rest, at 29.87 fps guest. ⚠️ The 4-frame interval is NOT the 100ms constant that drives it (100ms is ~3 frames). The game consumes drained keystrokes at its own per-frame pace. The 400ms delay, by contrast, comes back as 402ms -- that confirms the instrument, not the game. docs/re/f1-repeat-measured-via-driver-patch.md in the Sylpheed repo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -93,6 +93,12 @@ DEFINE_string(pad_file, "/tmp/xenia_pad.txt",
|
||||
"as `press=A,START lt=0 rt=255 lx=0 ly=0`. Absent keys are "
|
||||
"neutral, a missing file means no input.",
|
||||
"HID");
|
||||
DEFINE_bool(pad_file_repeat, false,
|
||||
"RE aid: opt in to Keystroke REPEAT events on `--hid=file`, using "
|
||||
"the SDL driver's exact 400ms/100ms guest-time constants. Off by "
|
||||
"default -- every existing scripted script wants one event per "
|
||||
"press, and repeat is what makes menu steps overshoot.",
|
||||
"HID");
|
||||
|
||||
DEFINE_path(
|
||||
storage_root, "",
|
||||
|
||||
@@ -46,12 +46,14 @@
|
||||
#include <string>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "xenia/base/clock.h"
|
||||
#include "xenia/base/cvar.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/hid/input_driver.h"
|
||||
#include "xenia/ui/virtual_key.h"
|
||||
|
||||
DECLARE_string(pad_file);
|
||||
DECLARE_bool(pad_file_repeat);
|
||||
|
||||
namespace xe {
|
||||
namespace hid {
|
||||
@@ -138,8 +140,9 @@ class FileInputDriver final : public InputDriver {
|
||||
//
|
||||
// One event per call, edge triggered: KEYUPs for everything released, then
|
||||
// KEYDOWNs for everything pressed, exactly as the SDL driver orders them.
|
||||
// Deliberately NO auto-repeat — scripted input wants precisely one event per
|
||||
// press, and repeat is what makes menu steps overshoot.
|
||||
// NO auto-repeat by default — scripted input wants precisely one event per
|
||||
// press, and repeat is what makes menu steps overshoot. `--pad_file_repeat`
|
||||
// opts in, below, for the one experiment that specifically needs it.
|
||||
X_RESULT GetKeystroke(uint32_t user_index, uint32_t flags,
|
||||
X_INPUT_KEYSTROKE* out_keystroke) override {
|
||||
const bool user_any = user_index == 0xFF || user_index == 0xFFFFFFFFu;
|
||||
@@ -172,6 +175,32 @@ class FileInputDriver final : public InputDriver {
|
||||
uint16_t(ui::VirtualKey::kXInputPadY),
|
||||
};
|
||||
|
||||
// RE aid: opt-in REPEAT, matching the SDL driver's Waiting/Repeating
|
||||
// state machine and its exact constants (sdl_input_driver.h:
|
||||
// HID_SDL_REPEAT_DELAY=400, HID_SDL_REPEAT_RATE=100, guest-time
|
||||
// milliseconds) verbatim -- not re-derived -- so a measurement through
|
||||
// this driver is a fair stand-in for what a real controller produces.
|
||||
// Checked BEFORE the edge scan below, same order the SDL driver uses.
|
||||
if (cvars::pad_file_repeat) {
|
||||
const int64_t guest_now = Clock::QueryGuestUptimeMillis();
|
||||
if (repeat_state_ == RepeatState::kWaiting &&
|
||||
repeat_time_ms_ + kRepeatDelayMs < guest_now) {
|
||||
repeat_state_ = RepeatState::kRepeating;
|
||||
}
|
||||
if (repeat_state_ == RepeatState::kRepeating &&
|
||||
repeat_time_ms_ + kRepeatRateMs < guest_now) {
|
||||
repeat_time_ms_ = guest_now;
|
||||
out_keystroke->virtual_key = kVk[repeat_bit_];
|
||||
out_keystroke->unicode = 0;
|
||||
out_keystroke->user_index = 0;
|
||||
out_keystroke->hid_code = 0;
|
||||
out_keystroke->flags = static_cast<uint16_t>(
|
||||
X_INPUT_KEYSTROKE_KEYDOWN | X_INPUT_KEYSTROKE_REPEAT);
|
||||
XELOGI("[file-pad] keystroke vk={:04X} repeat", kVk[repeat_bit_]);
|
||||
return X_ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
const uint16_t changed = static_cast<uint16_t>(buttons_ ^ reported_);
|
||||
if (!changed) {
|
||||
return X_ERROR_EMPTY;
|
||||
@@ -189,6 +218,15 @@ class FileInputDriver final : public InputDriver {
|
||||
}
|
||||
reported_ = static_cast<uint16_t>(pressed ? (reported_ | bit)
|
||||
: (reported_ & ~bit));
|
||||
if (cvars::pad_file_repeat) {
|
||||
if (pressed) {
|
||||
repeat_state_ = RepeatState::kWaiting;
|
||||
repeat_bit_ = i;
|
||||
repeat_time_ms_ = Clock::QueryGuestUptimeMillis();
|
||||
} else if (repeat_bit_ == i) {
|
||||
repeat_state_ = RepeatState::kIdle;
|
||||
}
|
||||
}
|
||||
out_keystroke->virtual_key = kVk[i];
|
||||
out_keystroke->unicode = 0;
|
||||
out_keystroke->flags =
|
||||
@@ -327,6 +365,15 @@ class FileInputDriver final : public InputDriver {
|
||||
time_t mtime_sec_ = 0;
|
||||
long mtime_nsec_ = -1;
|
||||
off_t size_ = -1;
|
||||
|
||||
// RE aid: `--pad_file_repeat` state, unused unless that cvar is set. Single
|
||||
// slot -- like the SDL driver, only the most recently pressed bit repeats.
|
||||
enum class RepeatState { kIdle, kWaiting, kRepeating };
|
||||
static constexpr int64_t kRepeatDelayMs = 400; // == HID_SDL_REPEAT_DELAY
|
||||
static constexpr int64_t kRepeatRateMs = 100; // == HID_SDL_REPEAT_RATE
|
||||
RepeatState repeat_state_ = RepeatState::kIdle;
|
||||
uint8_t repeat_bit_ = 0;
|
||||
int64_t repeat_time_ms_ = 0;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<InputDriver> Create(xe::ui::Window* window,
|
||||
|
||||
Reference in New Issue
Block a user