Skip to content

fix: late release single tap in touchscreen mode to fix clicking in some games#1212

Open
AndreVto wants to merge 4 commits intoutkarshdalal:masterfrom
AndreVto:touch-tap-fix
Open

fix: late release single tap in touchscreen mode to fix clicking in some games#1212
AndreVto wants to merge 4 commits intoutkarshdalal:masterfrom
AndreVto:touch-tap-fix

Conversation

@AndreVto
Copy link
Copy Markdown
Contributor

@AndreVto AndreVto commented Apr 14, 2026

Description

Delay the release button for the mouse click to fix single tap in Touchscreen Mode

I suspect this fixes the issue with Touchscreen Mode because a click down and up are being sent to games too quickly, likely reaching the game within the same frame window, so for example, if games do something like

if mouse click 1 is down
...
else if mouse click 1 is up
...

then click 1 up code is never executed

should fix these bug reports:
https://discord.com/channels/1378308569287622737/1482564848477929602
https://discord.com/channels/1378308569287622737/1490005595175125002
https://discord.com/channels/1378308569287622737/1479373032379125860

Recording

Screen_Recording_20260413_231514_GameNative.mp4

Checklist

  • If I have access to #code-changes, I have discussed this change there and it has been green-lighted. If I do not have access, I have still provided clear context in this PR. If I skip both, I accept that this change may face delays in review, may not be reviewed at all, or may be closed.
  • I have attached a recording of the change.
  • I have read and agree to the contribution guidelines in CONTRIBUTING.md.

Summary by cubic

Delay the left-click release after a single tap in Touchscreen Mode so down and up aren’t sent in the same frame. If a new tap starts within the delay window, immediately release the previous click.

  • Bug Fixes
    • On single tap up, schedule release with postDelayed(CLICK_DELAYED_TIME) via delayedPress in TouchpadView.handleTsUp; clear delayedPress after it runs; cursor move and press stay immediate.
    • On new tap down, flush any pending single-tap release by canceling delayedPress and injecting release in TouchpadView.handleTsDown (via flushPendingTapRelease).

Written for commit 218da26. Summary will update on new commits.

Summary by CodeRabbit

  • Bug Fixes
    • Improved touchpad tap behavior: the click release is now delayed to better distinguish taps from drags. Consecutive taps properly cancel or complete pending releases, reducing accidental double-clicks and improving responsiveness and reliability of single- and multi-tap interactions.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 14, 2026

📝 Walkthrough

Walkthrough

On touch up, simple taps now schedule a deferred left-click release via a delayed runnable; on touch down, any pending deferred release is flushed (cancelled and released immediately) before starting a new primary-finger down sequence.

Changes

Cohort / File(s) Summary
Touchpad tap/release flow
app/src/main/java/com/winlator/widget/TouchpadView.java
Tap-up handling now assigns delayedPress to a runnable that calls injectRelease(ACTION_LEFT_CLICK) and schedules it with postDelayed(..., CLICK_DELAYED_TIME) instead of immediate release. handleTsDown now calls flushPendingTapRelease() to cancel any pending delayedPress, inject its release immediately via removeCallbacks(...) + injectRelease(...), and clear delayedPress.

Sequence Diagram(s)

sequenceDiagram
    participant User as User
    participant TP as TouchpadView
    participant H as Handler/Looper
    participant I as InputInjector

    User->>TP: Finger DOWN
    TP->>TP: flushPendingTapRelease()
    alt delayedPress pending
        TP->>H: removeCallbacks(delayedPress)
        TP->>I: injectRelease(ACTION_LEFT_CLICK)
        TP->>TP: delayedPress = null
    end

    User->>TP: Finger UP (simple tap)
    TP->>TP: detect tap && !movedBeyondTapThreshold
    TP->>TP: delayedPress = () -> injectRelease(ACTION_LEFT_CLICK)
    TP->>H: postDelayed(delayedPress, CLICK_DELAYED_TIME)

    Note right of H: after delay
    H->>I: invoke delayedPress -> injectRelease(ACTION_LEFT_CLICK)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰
I tapped a beat, then held my paw,
A promise set — not one to thaw.
Old hops cancelled, then one made new,
A patient click, delayed and true.
Hooray, a gentle hopping view.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: delaying the release of a single tap in touchscreen mode to fix clicking issues in games.
Description check ✅ Passed The PR description covers the key sections of the template: it provides a clear description of the change and its rationale, includes a recording/link, and has a partially completed checklist.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/src/main/java/com/winlator/widget/TouchpadView.java`:
- Around line 774-775: A pending delayedPress Runnable may be left queued and
fire into a subsequent gesture; before assigning and posting a new delayedPress
in TouchpadView, cancel any previous one by calling
removeCallbacks(delayedPress) (if delayedPress is non-null) then assign
delayedPress = () -> injectRelease(TouchGestureConfig.ACTION_LEFT_CLICK) and
postDelayed(delayedPress, CLICK_DELAYED_TIME); this ensures stale LEFTUP
callbacks are removed before scheduling a new tap-release.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0b3713a5-ba2f-45c9-8794-c08d764d88bc

📥 Commits

Reviewing files that changed from the base of the PR and between a29bb89 and 0a69e9f.

📒 Files selected for processing (1)
  • app/src/main/java/com/winlator/widget/TouchpadView.java

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="app/src/main/java/com/winlator/widget/TouchpadView.java">

<violation number="1" location="app/src/main/java/com/winlator/widget/TouchpadView.java:775">
P2: Delayed single-tap release is posted without canceling prior pending release callbacks, which can emit stale/out-of-order LEFTUP events during subsequent gestures.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread app/src/main/java/com/winlator/widget/TouchpadView.java
@AndreVto AndreVto marked this pull request as draft April 14, 2026 02:35
@AndreVto AndreVto marked this pull request as ready for review April 14, 2026 02:44
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
app/src/main/java/com/winlator/widget/TouchpadView.java (1)

772-777: ⚠️ Potential issue | 🟠 Major

Drain pending delayed release at next finger-down, not only on simple-tap UP.

At Line 772, the previous delayed release is only canceled when the next gesture also reaches this simple-tap path. A tap→drag (or tap→long-press) can still be interrupted by a stale queued LEFTUP firing mid-gesture.

Proposed fix
@@
     private void handleTsDown(MotionEvent event) {
+        // Flush any pending delayed tap-release from previous gesture
+        if (delayedPress != null) {
+            removeCallbacks(delayedPress);
+            injectRelease(TouchGestureConfig.ACTION_LEFT_CLICK);
+            delayedPress = null;
+        }
+
         float[] pt = XForm.transformPoint(xform, event.getX(), event.getY());
@@
         if (gestureConfig.getTapEnabled() && !movedBeyondTapThreshold) {
             if (delayedPress != null) {
                 // If there's a new single tap within 'CLICK_DELAYED_TIME' ms
                 // Immediately release the previous down click
                 removeCallbacks(delayedPress);
                 injectRelease(TouchGestureConfig.ACTION_LEFT_CLICK);
+                delayedPress = null;
             }
             moveCursorTo((int) pt[0], (int) pt[1]);
             injectClick(TouchGestureConfig.ACTION_LEFT_CLICK);
             delayedPress = () -> injectRelease(TouchGestureConfig.ACTION_LEFT_CLICK);
             postDelayed(delayedPress, CLICK_DELAYED_TIME);
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/winlator/widget/TouchpadView.java` around lines 772 -
777, A pending delayed release (delayedPress) is only canceled in the simple-tap
UP path, which allows a queued LEFTUP to fire during subsequent gestures
(tap→drag/long-press); fix by draining/canceling that pending release as soon as
a new finger-down begins: inside TouchpadView's finger-down handler (e.g., the
onTouchEvent / ACTION_DOWN path or onDown method) check if delayedPress != null,
call removeCallbacks(delayedPress), call
injectRelease(TouchGestureConfig.ACTION_LEFT_CLICK) to immediately clear the
stale press, and set delayedPress = null so no stale LEFTUP can fire
mid-gesture.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/src/main/java/com/winlator/widget/TouchpadView.java`:
- Around line 780-781: The Runnable stored in delayedPress is left non-null
after it runs, causing stale-state pre-release behavior; update the lambda
assigned to delayedPress (the Runnable posted via postDelayed with
CLICK_DELAYED_TIME that calls injectRelease) to clear the field when it executes
(e.g., set delayedPress = null immediately before/after calling injectRelease)
and optionally remove any pending callbacks via removeCallbacks(delayedPress)
when cancelling, so delayedPress correctly reflects lifecycle and doesn't
trigger later pre-release logic.

---

Duplicate comments:
In `@app/src/main/java/com/winlator/widget/TouchpadView.java`:
- Around line 772-777: A pending delayed release (delayedPress) is only canceled
in the simple-tap UP path, which allows a queued LEFTUP to fire during
subsequent gestures (tap→drag/long-press); fix by draining/canceling that
pending release as soon as a new finger-down begins: inside TouchpadView's
finger-down handler (e.g., the onTouchEvent / ACTION_DOWN path or onDown method)
check if delayedPress != null, call removeCallbacks(delayedPress), call
injectRelease(TouchGestureConfig.ACTION_LEFT_CLICK) to immediately clear the
stale press, and set delayedPress = null so no stale LEFTUP can fire
mid-gesture.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4c819887-0f81-4eb2-850e-7d01375d9857

📥 Commits

Reviewing files that changed from the base of the PR and between 0a69e9f and bf4206c.

📒 Files selected for processing (1)
  • app/src/main/java/com/winlator/widget/TouchpadView.java

Comment thread app/src/main/java/com/winlator/widget/TouchpadView.java Outdated
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="app/src/main/java/com/winlator/widget/TouchpadView.java">

<violation number="1" location="app/src/main/java/com/winlator/widget/TouchpadView.java:780">
P2: `delayedPress` is used as a pending callback flag but never cleared after execution, so later taps can trigger unintended extra release events.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread app/src/main/java/com/winlator/widget/TouchpadView.java Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/src/main/java/com/winlator/widget/TouchpadView.java`:
- Around line 772-784: The delayedPress runnable can leave the left button
logically down across gestures; add a flushPendingTapRelease() helper that
checks delayedPress, calls removeCallbacks(delayedPress),
injectRelease(TouchGestureConfig.ACTION_LEFT_CLICK), and sets delayedPress =
null, and invoke flushPendingTapRelease() at the start of handleTsDown() (before
moveCursorTo()/drag logic) so any pending release is drained immediately when a
new ACTION_DOWN begins; keep the existing delayedPress creation/postDelayed and
CLICK_DELAYED_TIME behavior unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0742a296-b038-43fe-bff6-9e39cb7c6f42

📥 Commits

Reviewing files that changed from the base of the PR and between bf4206c and 4ec7482.

📒 Files selected for processing (1)
  • app/src/main/java/com/winlator/widget/TouchpadView.java

Comment thread app/src/main/java/com/winlator/widget/TouchpadView.java Outdated
@AndreVto AndreVto marked this pull request as draft April 14, 2026 03:06
@AndreVto
Copy link
Copy Markdown
Contributor Author

@Nightwalker743 let me know if you want to take this PR, I'm not too familiar with the touchscreen mode code and the bots keeps hitting my code changes lol

@AndreVto AndreVto marked this pull request as ready for review April 16, 2026 16:08
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 1 file

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant