mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-25 18:05:12 -04:00
Reconcile a LEFT release missed while unfocused on focus regain
Non-Windows only reconciled while focused AND captured; focus loss drops capture, so a release outside the window left activation_down_ stuck. Decision moved to LocalMousePolicy::sync_left (tested).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit f012cf1693)
This commit is contained in:
@@ -149,6 +149,10 @@ bool LocalMousePolicy::control(uint64_t t, uint64_t now, MouseControl control,
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void LocalMousePolicy::sync_left(uint64_t now, bool physically_down) {
|
||||
if (!physically_down && activation_down_)
|
||||
control(0, now, MouseControl::Left, false, false);
|
||||
}
|
||||
void LocalMousePolicy::motion(uint64_t t, uint64_t now, double dx, double dy) {
|
||||
if (!captured_) return;
|
||||
if (!allowed() || !std::isfinite(dx) || !std::isfinite(dy) ||
|
||||
|
||||
@@ -25,6 +25,8 @@ public:
|
||||
void reset();
|
||||
void update(uint64_t now, LocalMouseHost host);
|
||||
bool control(uint64_t t, uint64_t now, MouseControl control, bool down, bool repeat);
|
||||
// Reconcile a LEFT release the host never delivered (e.g. made while unfocused).
|
||||
void sync_left(uint64_t now, bool physically_down);
|
||||
void motion(uint64_t t, uint64_t now, double dx, double dy);
|
||||
void sample(uint64_t now, uint8_t& rx, uint8_t& ry);
|
||||
bool captured() const { return captured_; }
|
||||
|
||||
@@ -105,16 +105,16 @@ void psx_local_mouse_begin(SDL_Window* window, bool live) {
|
||||
update(now_ns());
|
||||
// Windows global state survives focus clearing SDL's cached window state.
|
||||
// Other backends may not support global mouse polling (e.g. Wayland), so
|
||||
// there catch a lost release only while focused and captured. Neither path
|
||||
// manufactures a down or unblocks a held activation across focus loss.
|
||||
// there reconcile whenever focused (captured or not), so a release made
|
||||
// while unfocused is caught on focus regain. Neither path manufactures a
|
||||
// down or unblocks a held activation across focus loss.
|
||||
#if defined(_WIN32)
|
||||
const bool left_released = !(SDL_GetGlobalMouseState(nullptr, nullptr) & SDL_BUTTON(SDL_BUTTON_LEFT));
|
||||
const bool left_down = (SDL_GetGlobalMouseState(nullptr, nullptr) & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0;
|
||||
state().sync_left(now_ns(), left_down);
|
||||
#else
|
||||
const bool left_released = host_.focused && state().captured() &&
|
||||
!(SDL_GetMouseState(nullptr, nullptr) & SDL_BUTTON(SDL_BUTTON_LEFT));
|
||||
if (host_.focused)
|
||||
state().sync_left(now_ns(), (SDL_GetMouseState(nullptr, nullptr) & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0);
|
||||
#endif
|
||||
if (left_released)
|
||||
state().control(0, now_ns(), psx::MouseControl::Left, false, false);
|
||||
// Catch a lost hold release, including one made outside the game window.
|
||||
const auto hold = state().hold_control();
|
||||
bool down = false;
|
||||
|
||||
@@ -240,6 +240,27 @@ int main() {
|
||||
batch.sample(33*Ms,x,y);CHECK(x==128 && y==128);batch.clear();
|
||||
}
|
||||
|
||||
// LEFT released while unfocused is never delivered; reconcile on regain so
|
||||
// the next click activates. A still-held button is not a new activation.
|
||||
{
|
||||
psx::LocalMousePolicy lost({nullptr,capture,suppress,notice});
|
||||
CHECK(lost.install(&callbacks));
|
||||
const uint64_t base=9000*Ms;
|
||||
lost.update(base,host);
|
||||
CHECK(lost.control(base,base,psx::MouseControl::Left,true,false) && lost.captured());
|
||||
auto away=host;away.focused=false;
|
||||
lost.update(base+10*Ms,away);CHECK(!lost.captured());
|
||||
lost.update(base+20*Ms,host);
|
||||
lost.sync_left(base+20*Ms,true);
|
||||
CHECK(!lost.control(base+21*Ms,base+21*Ms,psx::MouseControl::Left,true,false));
|
||||
lost.sync_left(base+22*Ms,false);
|
||||
lost.update(base+23*Ms,host);
|
||||
CHECK(lost.control(base+23*Ms,base+23*Ms,psx::MouseControl::Left,true,false));
|
||||
CHECK(lost.captured());
|
||||
lost.sync_left(base+24*Ms,true);CHECK(lost.captured()); // down: no-op
|
||||
lost.clear();
|
||||
}
|
||||
|
||||
policy.reset();host.hold_conflict=false;capture_ok=false;CHECK(acquire());CHECK(!policy.captured());
|
||||
const unsigned failure_notices=notices;CHECK(acquire());CHECK(notices==failure_notices);
|
||||
policy.clear(); CHECK(!policy.installed() && !policy.captured());
|
||||
|
||||
Reference in New Issue
Block a user