Skip to content

Conversation

@clansty
Copy link
Member

@clansty clansty commented Jan 22, 2026

Note

Adds PDX exclusive touch support and refactors touch handling

  • New PdxTouch with config for radius, optional serial1p/serial2p, and per-player device startup using VID/PID and PDX report parsing
  • Refactors to ExclusiveTouchBase: per-device USB setup, interface claim/release, read thread, finger state tracking, and registration via TouchStatusProvider
  • Updates TouchSensorMapper.ParseTouchPoint to handle radius more robustly (circle-edge/interior checks when radius > 0, point-in-polygon when 0)

Removes previous static config-driven ExclusiveTouch implementation in favor of instance-based design.

Written by Cursor Bugbot for commit 0e69ffc. This will update automatically on new commits. Configure here.

@gemini-code-assist
Copy link

Summary of Changes

Hello @clansty, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors the touch input system, transitioning from a monolithic static class to an extensible, object-oriented design. The primary goal is to enable robust support for multiple distinct touch devices, particularly for "PDX ExclusiveTouch" panels, by abstracting common touch handling logic and providing a concrete implementation for specific hardware. This change enhances configurability, allowing users to specify devices for individual players and improving the accuracy of touch detection through refined sensor mapping.

Highlights

  • Refactored ExclusiveTouch to ExclusiveTouchBase: The core touch handling logic has been moved to an abstract base class, making it reusable and extensible for different touch device types. This involves converting static members to instance members and abstracting device-specific parsing.
  • Introduced PdxTouch for PDX Devices: A new class PdxTouch is added, inheriting from ExclusiveTouchBase, to specifically handle PDX touch panel input, including its unique data parsing and configuration.
  • Configurable Multi-Player Support: The system now supports configuring and initializing separate touch devices for Player 1 and Player 2 using serial numbers, or automatically detecting a single device if no serial numbers are specified.
  • Improved Touch Sensor Mapping Logic: The TouchSensorMapper now more precisely handles touch point detection based on a configurable radius, differentiating between points with and without a radius for polygon intersection checks.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a significant and well-executed refactoring by creating a reusable ExclusiveTouchBase for handling touch input from various devices, demonstrated by the new PdxTouch implementation. The changes are a solid improvement for supporting multi-player setups. I have a few suggestions to enhance the code's clarity and robustness, mainly concerning the device initialization logic and ensuring resources are properly cleaned up on application exit.

Comment on lines +51 to +60
Application.quitting += () =>
{
IUsbDevice wholeDevice = device as IUsbDevice;
var tmpDevice = device;
device = null;
if (wholeDevice != null)
{
wholeDevice.SetConfiguration(configuration1p);
wholeDevice.ClaimInterface(interfaceNumber1p);
}
touchSensorMappers[0] = new TouchSensorMapper(minX1p, minY1p, maxX1p, maxY1p, radius1p, flip1p);
Application.quitting += () =>
{
devices[0] = null;
if (wholeDevice != null)
{
wholeDevice.ReleaseInterface(interfaceNumber1p);
}
device.Close();
};

allFingerPoints[0] = new TouchPoint[256];
for (int i = 0; i < 256; i++)
{
allFingerPoints[0][i] = new TouchPoint();
wholeDevice.ReleaseInterface(interfaceNumber);
}
tmpDevice.Close();
};

Choose a reason for hiding this comment

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

medium

In the Application.quitting event handler, if wholeDevice.ReleaseInterface(interfaceNumber) throws an exception, tmpDevice.Close() will not be called, which could lead to an unclosed resource. It's safer to wrap the resource release logic in a try...finally block to guarantee that Close() is always called.

            Application.quitting += () =>
            {
                var tmpDevice = device;
                device = null;
                try
                {
                    if (wholeDevice != null)
                    {
                        wholeDevice.ReleaseInterface(interfaceNumber);
                    }
                }
                finally
                {
                    tmpDevice.Close();
                }
            };

Comment on lines +21 to +38
public static void OnBeforePatch()
{
if (string.IsNullOrWhiteSpace(serial1p) && string.IsNullOrWhiteSpace(serial2p))
{
devices[0] = new PdxTouchDevice(0, null);
devices[0].Start();
}
if (!string.IsNullOrWhiteSpace(serial1p))
{
devices[0] = new PdxTouchDevice(0, serial1p);
devices[0].Start();
}
if (!string.IsNullOrWhiteSpace(serial2p))
{
devices[1] = new PdxTouchDevice(1, serial2p);
devices[1].Start();
}
}

Choose a reason for hiding this comment

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

medium

The logic for initializing devices in OnBeforePatch is a bit complex to follow due to multiple, non-exclusive if statements. This can be simplified into a more readable and maintainable structure that achieves the same result but is clearer about its intent.

    public static void OnBeforePatch()
    {
        // Initialize 1P device if serial1p is provided, or if no serials are provided at all (auto-detect mode).
        // This logic does not initialize 1P if only 2P serial is provided, matching original behavior.
        if (!string.IsNullOrWhiteSpace(serial1p) || string.IsNullOrWhiteSpace(serial2p))
        {
            devices[0] = new PdxTouchDevice(0, serial1p);
            devices[0].Start();
        }

        // Initialize 2P device if serial2p is provided.
        if (!string.IsNullOrWhiteSpace(serial2p))
        {
            devices[1] = new PdxTouchDevice(1, serial2p);
            devices[1].Start();
        }
    }

Copy link
Member Author

Choose a reason for hiding this comment

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

这样岂不是更绕

}
}

private class PdxTouchDevice(int playerNo, string serialNumber) : ExclusiveTouchBase(playerNo, vid: 0x3356, pid: 0x3003, serialNumber, configuration: 1, interfaceNumber: 1, ReadEndpointID.Ep02, packetSize: 64, minX: 18432, minY: 0, maxX: 0, maxY: 32767, flip: true, radius)

Choose a reason for hiding this comment

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

medium

The constructor call for ExclusiveTouchBase uses several magic numbers for device-specific parameters (VID, PID, coordinates, etc.). To improve readability and maintainability, consider defining these as named constants within the PdxTouchDevice class and using them in the constructor call.

cursor[bot]

This comment was marked as outdated.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

var finder = new UsbDeviceFinder(vid1p, pid1p, serialNumber);
var device = UsbDevice.OpenUsbDevice(finder);
if (device == null)
MelonLogger.Msg("[ExclusiveTouch] Cannot connect 1P");
Copy link

Choose a reason for hiding this comment

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

Error message always shows "1P" regardless of player

Low Severity

The error message "[ExclusiveTouch] Cannot connect 1P" is hardcoded and will display "1P" even when attempting to connect a 2P device. The class has access to playerNo parameter which could be used to display the correct player number, as done elsewhere in the code (line 85 uses {playerNo + 1}P).

Fix in Cursor Fix in Web

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.

2 participants