Handheld Companion Documentation

repository·main·Indexed 21 days ago

https://github.com/valkirie/handheldcompanion

A touch-optimized utility for Windows 10/11 handheld gaming computers. Features include gyro motion control, virtual controller emulation (Xbox 360/DS4), a QuickTools overlay for managing TDP and brightness, gamepad remapping, and a 3D controller overlay for streaming. Supports a wide range of hardware including Steam Deck, ASUS ROG Ally, Lenovo Legion Go, and MSI Claw. Includes documentation for hidapi.net and neptune-hidapi.net for interacting with HID devices and Steam Deck controllers in .NET projects.

Tokens
8.3K
Snippets
6
Records
51
Agent score
82%

What's inside Handheld Companion

  1. Overview of Handheld Companion features

    main

    Handheld Companion is a touch-optimized GUI designed to enhance the handheld gaming experience on Windows 10/11. Key features include:

    • Motion Control (Gyro): Uses the device's IMU (Gyroscope/Accelerometer) or external sensors for racing, 1st/3rd person gaming, and emulator support.
    • QuickTools Overlay: A summonable menu for on-the-fly adjustments of TDP, brightness, resolution, screen frequency, hotkeys, and motion control profiles.
    • Virtual Controller Simulation: Emulates Microsoft Xbox 360 and Sony DualShock 4 controllers.
    • Profile System: Automatically detects active games and applies specific settings.
    • Gamepad Remapping: Maps gamepad inputs to mouse/keyboard and allows deadzone adjustments for joysticks and triggers.
    • PS Remote Play Support: Enables DS4 controller support including motion and touchpad functionality.
    • 3D Controller Overlay: A visual 3D model showing real-time button presses, joystick positions, and device motion, useful for stream recordings.
    • Virtual Touchpad: Mimics a DualShock 4 physical touchpad for compatibility with PS Now, PS Remote Play, and Steam games using touchpads.
  2. Use hidapi.net to interact with HID devices

    main

    To use hidapi.net, you must ensure your target platform is set to x64. Failure to do so will result in an error when attempting to import the underlying DLL.

    To interact with a device:

    1. Instantiate a HidDevice using its Vendor ID (VID) and Product ID (PID).
    2. Call OpenDevice() to establish a connection (returns false if unsuccessful).
    3. Subscribe to the OnInputReceived event to handle incoming data.
    4. Call BeginRead() to start the asynchronous reading process.
    HidDevice device = new HidDevice(0x28de, 0x1205); //Vendor ID and Product ID of the HID Device.
    
    bool result = device.OpenDevice(); //will return false if not successful.
    
    device.OnInputReceived += Device_OnInputReceived; //attach event listener for incoming data
    device.BeginRead(); //Start reading
  3. Use QuickTools overlay for on-the-fly adjustments

    main

    The QuickTools overlay allows you to adjust system settings without leaving your game. It can be summoned using a user-defined button combination (including special keys on supported devices).

    Adjustable settings include:

    • TDP (Global and Profile-specific)
    • Brightness
    • Screen Resolution and Frequency (Hz)
    • Framelimiter
    • Volume
    • Powermode control
    • Battery level
    • Motion control profile settings

    The window can be aligned to the left, right, or set to float.

  4. Use the 3D Controller overlay for streaming

    main

    The 3D Controller overlay displays a virtual model that showcases real-time device motion and all button interactions (individual presses, joystick, and trigger positions). This is ideal for stream recordings.

    Available 3D models include:

    • Emulated controllers (DualShock 4, Xbox 360)
    • Xbox One controller
    • Fisher-Price controller
    • Machenike HG510
    • 8BitDo Lite 2
    • Nintendo 64
    • PlayStation DualSense
    • PlayStation DualShock 4
    • Steam Deck
  5. Setup neptune-hidapi.net in a .NET project

    main

    To use the Steam Deck Controller (Neptune) HID Api Library in your .NET project, follow these steps:

    1. Download Binaries: Download the .dll files from the project's releases section.
    2. Add to Project: Copy the .dll files to the root directory of your project.
    3. Configure Build Output: In your IDE, right-click the files, select Settings, and set them to "Always copy to output dir".
    4. Target x64 Platform: Ensure your project is built for the x64 platform. If it is not, go to Build > Configuration manager and create a new configuration for x64.
  6. Use NeptuneController to read Steam Deck inputs

    main

    The NeptuneController class is the primary interface for interacting with the Steam Deck controller.

    Key Workflow:

    1. Instantiate: Create a new NeptuneController object.
    2. Subscribe to Events: Attach a handler to the OnControllerInputReceived event to receive real-time input updates.
    3. Configure Mode: Set LizardModeEnabled to true if you want to enable Mouse and Keyboard emulation.
    4. Open Device: Call .Open() to initialize the connection to the controller hardware.
    5. Access Data: Once opened, you can access properties like SerialNumber. Input data is provided via NeptuneControllerInputEventArgs, which contains ButtonState and AxesState.

    Example Implementation:

    using System;
    
    namespace neptune_hidapi.net
    {
        internal class Program
        {
            static void Main(string[] args)
            {
                NeptuneController controller = new NeptuneController();
                controller.OnControllerInputReceived += Controller_OnControllerInputReceived;
                controller.LizardModeEnabled = true; // Mouse and Keyboard emulation enabled.
                controller.Open(); // Open the controller device.
                
                // Serial number is only available after Open()
                Console.WriteLine($"Controller Serial: {controller.SerialNumber}"); 
                Console.ReadLine();
            }
    
            private static void Controller_OnControllerInputReceived(object sender, NeptuneControllerInputEventArgs e)
            {
                // Access buttons via e.State.ButtonState.Buttons
                foreach (var btn in e.State.ButtonState.Buttons)
                {
                    Console.WriteLine($"{btn}: {e.State.ButtonState[btn]}");
                }
    
                // Access axes via e.State.AxesState.Axes
                foreach (var axis in e.State.AxesState.Axes)
                {
                    Console.WriteLine($"{axis}: {e.State.AxesState[axis]}");
                }
            }
        }
    }
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace neptune_hidapi.net
    {
        internal class Program
        {
            static void Main(string[] args)
            {
                NeptuneController controller = new NeptuneController();
                controller.OnControllerInputReceived += Controller_OnControllerInputReceived;
                controller.LizardModeEnabled = true; //Mouse and Keyboard emulation enabled.
                controller.Open(); //Open the controller device.
                Console.WriteLine($"Controller Serial: {controller.SerialNumber}"); // Output the serial number. Only available once device has been opened.
                Console.ReadLine();
            }
    
            static DateTime lastUpdate = DateTime.Now;
    
            private static void Controller_OnControllerInputReceived(object sender, NeptuneControllerInputEventArgs e)
            {
                if ((DateTime.Now - lastUpdate).TotalMilliseconds > 100)
                {
                    Console.CursorTop = 0;
                    Console.CursorLeft = 0;
                    foreach (var btn in e.State.ButtonState.Buttons)
                    {
                        Console.WriteLine($"{btn}: {e.State.ButtonState[btn]}      ");
                    }
                    foreach (var axis in e.State.AxesState.Axes)
                    {
                        Console.WriteLine($"{axis}: {e.State.AxesState[axis]}      ");
                    }
                    lastUpdate = DateTime.Now;
                }
            }
        }
    }
  7. Supported hardware and systems

    main

    Supported Operating Systems

    • Windows 10 / Windows 11 (x86 and amd64)

    Supported Devices (Examples)

    • ASUS ROG Ally / ROG Ally X / ROG Z13
    • Lenovo Legion Go / Legion Go S
    • MSI Claw (all generations)
    • Steam Deck (all models)
    • AYA Neo (all models, including Next, Air, 2, KUN, Flip, Slide)
    • ONEXPLAYER (X1, OneXFly, 2, 2 Pro, MINI)
    • GPD WIN (Max 2, 2, 3, 4, Mini)
    • ZOTAC Gaming Zone
    • AOKZOE (A1, A1 Pro, A2)
    • Ayn Loki

    Supported Sensors

    • Bosch BMI160 (and similar)
    • USB IMU (GY-USB002)
  8. Swap between screens with SwapScreenCommands

    main

    The SwapScreenCommands function allows you to move the currently focused window from its current screen to another available screen.

    Behavior:

    1. It identifies the currently foreground window.
    2. It determines which screen that window is currently on.
    3. It finds the first available screen that does not match the current screen's DeviceName.
    4. If another screen is found, it moves the window to that screen and applies the WindowPositions.Maximize setting, then brings the window to the foreground.

    Requirements:

    • This command requires at least two screens to be connected (Screen.AllScreens.Length > 1).
    • It is designed to trigger on a key release (OnKeyUp = true).
  9. Manage QuickTools visibility and navigation via QuickToolsCommands

    main

    The QuickToolsCommands class allows for toggling the visibility of the OverlayQuickTools and navigating to specific pages within the overlay. When executed, it toggles the overlay's visibility and, if the overlay becomes visible, navigates to a page determined by the PageIndex property.

    The PageIndex property determines which page the overlay navigates to upon becoming visible:

    • 0: (Default/Current) No specific page navigation (empty tag).
    • 1: QuickHomePage
    • 2: QuickDevicePage
    • 3: QuickProfilesPage
    • 4: QuickApplicationsPage