Click stability: only a hand controller's press starts it

The 3D mouse drives SteamVR's laser through the ft_pointer virtual
controller, so its events reach the screens the same way a controller's
do. The filter held every press, which turned the mouse's short drags
(selecting a character or two, nudging a slider) into clicks. Mark
button events from hand controllers and start the filter only on those.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
DeeJanuzandClaude Opus 5.5 committed 2026-10-01 23:19:58 -06:00
1 parent ba6ccdfbd1
commit 540d8c425c
5 files changed
+17 -7

No files matched your search

+6 -4
View File
@@ -6,10 +6,12 @@ zone delivers the click at the original position, even if the hand moved during
release. Moving outside the zone begins a normal drag immediately; returning to
the zone does not turn it back into a click. There is no hold-duration timer.
This filters overlay pointer content events on desktop monitors only. Native mouse
input, SteamVR UI, separate screen grab bars and floating-app title-bar carrying
are unaffected. Multi-button gestures keep their existing behavior. A motion
onto another desktop monitor starts a drag; cross-monitor motion is not stabilized.
This filters overlay pointer content events on desktop monitors only, and only
presses from hand controllers start it. The 3D mouse (whose laser comes from the
`ft_pointer` virtual controller), SteamVR UI, separate screen grab bars and
floating-app title-bar carrying are unaffected. Multi-button gestures keep their
existing behavior. A motion onto another desktop monitor starts a drag;
cross-monitor motion is not stabilized.
CLI (runtime preferences, reset to 8 on desktop restart):
+3 -2
View File
@@ -11,7 +11,8 @@ struct ft_controller_click {
unsigned long suppressed, clicks, drags;
};
// Hold the desktop position at press time until movement exceeds a logical-pixel
// radius. No timer, delayed button-down, or change to native mouse input.
// radius. No timer or delayed button-down. Only a hand controller's press starts
// it: the 3D mouse drives a laser too, and its short drags must stay drags.
static inline bool ft_controller_click_filter(struct ft_controller_click *c,
struct ft_event *e, double scale) {
if (e->type == FT_BUTTON && e->button >= BTN_LEFT && e->button < BTN_LEFT+8) {
@@ -19,7 +20,7 @@ static inline bool ft_controller_click_filter(struct ft_controller_click *c,
if (e->pressed) c->buttons |= bit; else c->buttons &= ~bit;
}
if (e->type == FT_BUTTON && e->pressed) {
if (e->button == BTN_LEFT && !c->held && c->threshold > 0) {
if (e->button == BTN_LEFT && e->controller && !c->held && c->threshold > 0) {
c->held = true; c->dragging = false; c->screen = e->screen;
c->x = e->x; c->y = e->y; c->radius = c->threshold * scale;
} else if (e->button != BTN_LEFT) {
+6 -1
View File
@@ -1,7 +1,7 @@
#include <assert.h>
#include "../controller-click.h"
static struct ft_event event(enum ft_event_type t, bool down, double x, double y) {
return (struct ft_event){.type=t,.screen=0,.button=BTN_LEFT,.pressed=down,.x=x,.y=y};
return (struct ft_event){.type=t,.screen=0,.button=BTN_LEFT,.pressed=down,.controller=true,.x=x,.y=y};
}
int main(void) {
struct ft_controller_click c={.threshold=8};
@@ -34,4 +34,9 @@ int main(void) {
e=event(FT_BUTTON,true,100,100);ft_controller_click_filter(&c,&e,1);
e=event(FT_BUTTON,true,100,100);e.button=BTN_RIGHT;ft_controller_click_filter(&c,&e,1);
assert(!c.held);
// The 3D mouse's laser: a short drag stays a drag, and the release stays where it was.
e=event(FT_BUTTON,true,100,100);e.controller=false;assert(ft_controller_click_filter(&c,&e,1) && !c.held);
e=event(FT_MOTION,false,104,100);assert(ft_controller_click_filter(&c,&e,1));
e=event(FT_BUTTON,false,106,100);e.controller=false;
assert(ft_controller_click_filter(&c,&e,1) && e.x==106 && c.clicks==2 && c.suppressed==1);
}
+1
View File
@@ -1741,6 +1741,7 @@ void ft_vr_poll(void (*handle)(const struct ft_event *, void *), void *data) {
e.type = FT_BUTTON;
e.button = LinuxButton(ev.data.mouse.button);
e.pressed = ev.eventType == vr::VREvent_MouseButtonDown;
e.controller = IsHandController(ev.trackedDeviceIndex);
at();
if (!e.pressed && s.titleCarry) e.x = s.carryX, e.y = s.carryY, s.titleCarry = false;
if (e.pressed) {
+1
View File
@@ -25,6 +25,7 @@ struct ft_event {
double x, y; // FT_MOTION: buffer pixels from the top left
uint32_t button; // FT_BUTTON: linux BTN_*
bool pressed;
bool controller; // FT_BUTTON: from a hand controller's laser (not the 3D mouse's)
double dx, dy; // FT_SCROLL: notches (positive dy: scroll down)
uint32_t key; // FT_KEY: linux KEY_* from our keyboard (pressed: down or up)
};