Skip to content

Gamepad Controller Support for Stellarium Remote Control#4813

Open
kutaibaa-akraa wants to merge 17 commits intoStellarium:masterfrom
kutaibaa-akraa:master
Open

Gamepad Controller Support for Stellarium Remote Control#4813
kutaibaa-akraa wants to merge 17 commits intoStellarium:masterfrom
kutaibaa-akraa:master

Conversation

@kutaibaa-akraa
Copy link
Copy Markdown
Contributor

@kutaibaa-akraa kutaibaa-akraa commented Mar 11, 2026

Gamepad Controller Support for Stellarium Remote Control

Overview

This PR adds comprehensive gamepad controller support to the Stellarium Remote Control plugin, enabling users to control Stellarium using a wide range of popular game controllers. The implementation is based on the SDL Game Controller Database and supports over 20 different controller models from major manufacturers.

Supported Devices (Database Included)

The controller database includes mappings for:

Sony PlayStation

  • PS4 Controller (CUH-ZCT1E) - Tested and verified
  • PS4 Controller (v2) - Mapping included
  • PS5 DualSense Controller - Tested and verified
  • PS3 Controller - Mapping included

Microsoft Xbox

  • Xbox 360 Controller
  • Xbox One Controller
  • Xbox Series X|S Controller

Nintendo

  • Switch Pro Controller
  • Switch Joy-Con (Left)
  • Switch Joy-Con (Right)

Logitech

  • F310 Gamepad
  • F710 Wireless Gamepad
  • G29 Racing Wheel

8BitDo

  • SN30 Pro Controller
  • Pro 2 Controller

Razer

  • Raiju Mobile Controller
  • Wolverine Tournament Controller

Steam

  • Steam Controller
  • Steam Deck Controller

Generic

  • Generic USB Gamepad
  • Generic Bluetooth Gamepad

Features

Core Functionality

  • Multi-controller support: Database with 20+ controller mappings from SDL
  • Automatic device detection: Identifies controllers by USB vendor/product IDs
  • Joystick calibration: Eliminates drift with zero-point calibration
  • Full button remapping: All controller buttons can be assigned to Stellarium actions
  • Real-time control:
    • Left stick: Smooth view panning
    • Right stick vertical: Smooth zoom in/out
    • Shoulder buttons: Time speed control
    • Face buttons: Quick access to common functions
    • D-pad: Tab navigation and time control

User Interface

  • Controller Settings panel: Device info, calibration, sensitivity controls
  • Button Customization panel: Visual button mapping interface
  • Joystick preview: Real-time visual feedback of stick positions
  • Connection status: Clear indication of controller connection state

Technical Features

  • Settings persistence: All mappings and calibration saved to localStorage
  • Animation loop: 60fps polling with requestAnimationFrame
  • Deadzone handling: Configurable deadzone for precise control
  • Axis inversion: Optional X/Y axis inversion
  • Sensitivity adjustment: Per-stick sensitivity control

Files Modified/Added

webroot/js/ui/gpcontroller.js     # Main controller module (new)
webroot/gamepad.css            # Dedicated gamepad styles (new)
webroot/index.html                  # Added Gamepad Controller tab
webroot/js/main.js                  # Added module dependency
webroot/js/ui/mainui.js             # Added initialization

Testing Status

Tested and Verified

  • PS4 Controller (CUH-ZCT1E) on Windows 11
  • PS5 DualSense Controller on Windows 11
  • All core features: calibration, button mapping, joystick control

Mappings Included (Require Testing)

All other controller mappings are sourced from the SDL Game Controller Database and are theoretically correct, but require testing on actual hardware with different operating systems.

Known Limitations

  1. Analog Triggers (L2/R2): Currently function as digital buttons only. Future enhancement could add analog support for velocity-based actions.

  2. D-pad Implementation: Operates as separate buttons (standard behavior in most browsers). Some controllers may present D-pad as axes.

  3. Platform Differences: Axis mappings may vary between Windows, Linux, and macOS. The database includes Windows-tested mappings; Linux/macOS users may need custom adjustments.

  4. Browser Support: Requires browser with Gamepad API support (all modern browsers).

Future Enhancements

  • Full SDL database integration with dynamic loading
  • Analog trigger support for smooth zoom/scroll
  • Multiple controller profiles
  • Cross-platform testing and optimization
  • Community-driven mapping submissions

Installation Instructions

  1. Copy all files to the RemoteControl plugin webroot
  2. Ensure proper file structure:
    webroot/
    ├── js/
    │   ├── ui/
    │   │      └── gpcontroller.js 
    |     |       └── mainui.js
    │   └── main.js (modified)
    ├─── gamepad.css
    └── index.html (modified)
    
  3. Restart Stellarium and enable Remote Control plugin
  4. run localhost:8090 on your browser

Usage Guide

  1. Connect controller via USB or Bluetooth
  2. Open Remote Control interface
  3. Navigate to "Gamepad Controller" tab
  4. Click "Connect" - device should auto-detect
  5. Use calibration if joysticks show drift:
    • Click "Calibrate"
    • Move both sticks in circles
    • Press any button to finish
  6. Customize button mappings as desired
  7. Test controls in Stellarium

Pull Request Checklist

  • Code follows Stellarium's JavaScript style guidelines
  • All functions documented with JSDoc comments
  • Tested on Windows with PS4/PS5 controllers
  • No conflicts with existing Remote Control functionality
  • UI maintains consistent Stellarium theme
  • Settings persist across sessions
  • Graceful fallback when no controller connected

Notes for Reviewers

This implementation focuses on stability and usability rather than complete universal compatibility. The controller database is included but only PS4/PS5 have been fully tested. Other mappings are provided as a foundation for community testing and future enhancement.
A future version could integrate the complete SDL database dynamically, but that requires more extensive cross-platform testing and a different architectural approach.

Testing Help Needed: If you have access to any of the listed controllers on Linux or macOS, please test and report any mapping issues.

Screenshots

connected API Disconnected

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • This change requires a documentation update
  • Housekeeping

How Has This Been Tested?

Test Configuration:

  • Operating system: <Windows, 10>

Checklist:

  • My code follows the code style of this project.
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation (header file)
  • I have updated the respective chapter in the Stellarium User Guide
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

added  comprehensive gamepad controller support to the Stellarium Remote Control plugin, enabling users to control Stellarium using a wide range of popular game controllers. The implementation is based on the SDL Game Controller Database and supports over 20 different controller models from major manufacturers.

webroot/
├── js/
│   ├── ui/
│   │   └── gpcontroller.js (new)
│   └── main.js (modified)
├── css/
│   └── gamepad.css (new)
└── index.html (modified)
@alex-w alex-w added this to Plugin Mar 11, 2026
@github-project-automation github-project-automation bot moved this to Backlog in Plugin Mar 11, 2026
@alex-w alex-w added subsystem: plugins The issue is related to plugins of planetarium... purpose: interoperability Interoperability issues labels Mar 11, 2026
@gzotti
Copy link
Copy Markdown
Member

gzotti commented Mar 11, 2026

Trying to load the common RemoteControl web browser interface in Firefox, but it does not go beyond "Please wait, loading".

Should it still work without any new controller? I just have a tiny Rii BT keyboard (actually I have trouble to connect via bluetooth, but its USB dongle works) which however works like any wireless keyboard. It might be nice to get the second "cursor key wheel" (showing volume and speed control for media playing) operational for Scenery3D, though.

Copy link
Copy Markdown
Member

@alex-w alex-w left a comment

Choose a reason for hiding this comment

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

Why jQuery 3.6.0 is hardcoded here by the fact?

Fixed

@alex-w
Copy link
Copy Markdown
Member

alex-w commented Mar 11, 2026

Right Stick (zooming) is not working

@kutaibaa-akraa
Copy link
Copy Markdown
Contributor Author

kutaibaa-akraa commented Mar 11, 2026

Trying to load the common RemoteControl web browser interface in Firefox, but it does not go beyond "Please wait, loading".

Regarding the loading issue where the interface doesn't proceed beyond "Please wait, loading", could you please:
. Can you Share the console output here please.
. Confirm that all expected UI files are loading correctly (main.js, gpcontroller.js, etc.)
This will help identify if the issue is a missing file reference, a syntax error, or something else.

Should it still work without any new controller?

yes . please report your console.

@alex-w
Copy link
Copy Markdown
Member

alex-w commented Mar 11, 2026

Trying to load the common RemoteControl web browser interface in Firefox, but it does not go beyond "Please wait, loading".

Regarding the loading issue where the interface doesn't proceed beyond "Please wait, loading", could you please: . Can you Share the console output here please. . Confirm that all expected UI files are loading correctly (main.js, gpcontroller.js, etc.) This will help identify if the issue is a missing file reference, a syntax error, or something else.

Should it still work without any new controller? >
yes . please report your console.

Loading issue is fixed now

@gzotti
Copy link
Copy Markdown
Member

gzotti commented Mar 11, 2026

I confirm it loads again, and some test clicks in the existing UI still works. My Rii keyboard is not connected though, so I cannot test it with existing hardware. But I won't object merge as long as it does not break things. But @kutaibaa-akraa should be committed to support it for at least a year or so, and fix/finetune whatever bug reports come in. I will try some Android gamepad app...

EDIT: DroidJoy did it. Tested a few minutes, seems to work well. I am not used to such devices, though, so details may evade me.

@alex-w alex-w moved this from Backlog to In progress in Plugin Mar 12, 2026
@kutaibaa-akraa
Copy link
Copy Markdown
Contributor Author

kutaibaa-akraa commented Mar 12, 2026

Right Stick (zooming) is not working

To help diagnose your right stick issue, please send the following information:

. From the console window (F12), find and paste these lines:

  • The line starting with "Full ID:"
  • The line starting with "OS:"
  • The line starting with "USB IDs:"
  • The line starting with "Axes mapping:"

Example of required information:

Full ID: 054c-0ce6-DualSense Wireless Controller
OS: windows
USB IDs: 054c:0ce6
Axes mapping: { leftX: 0, leftY: 1, rightX: 2, rightY: 5, l2: 3, r2: 4 }

When moving right stick UP: image zooms OUT (opposite of expected)
Operating System: Windows 11

Open gpcontroller.js

Locate and open the file webroot/js/ui/gpcontroller.js in a text editor.

Find Your Device in the Database

Search for the device name that appears in the UI. For example:

// ========== Sony PlayStation 5 DualSense ==========
'sony_ps5_dualsense': {
    id: 'sony_ps5_dualsense',
    name: 'Sony PlayStation 5 DualSense Controller',
    // ... other properties
    axes: { leftX: 0, leftY: 1, rightX: 2, rightY: 5, l2: 3, r2: 4 },
    // ...
},

Modify the rightY Value

Change the rightY value from 5 to 3 (or vice versa based on your testing):

Before:

axes: { leftX: 0, leftY: 1, rightX: 2, rightY: 5, l2: 3, r2: 4 }

After:

axes: { leftX: 0, leftY: 1, rightX: 2, rightY: 3, l2: 3, r2: 4 }

Save and Refresh

Save the file and reload the Remote Control page.


Why This Works

Different operating systems and browsers may read axes differently:

  • On Windows: rightY is often 5
  • On Linux: rightY is often 3
  • On macOS: rightY may be 4

This manual adjustment lets you test which value works best for your specific device and operating system.


@gzotti
Copy link
Copy Markdown
Member

gzotti commented Mar 12, 2026

All this technical info should please also go into the User Guide, section 13.5.3 (before Remote Control API). If you have trouble with LaTeX formatting we can surely help, but not with the detailed knowledge!

However, also the DOM issue noted above must be fixed.

@alex-w
Copy link
Copy Markdown
Member

alex-w commented Mar 12, 2026

It's a Defender Omega, which work as Microsoft Xbox 360 pad (idVendor=045e, idProduct=028e). Operating system is linux. In Remote Contgrol plugin it has device name: Microsoft Xbox 360 Controller (045e:028e).

axes: { leftX: 0, leftY: 1, rightX: 2, rightY: 3, l2: 4, r2: 5 }

Changing the rightY value from 3 to 5 (or vice versa) does not effects.

In Remote Control plugin Right Stick moves by horizontal, but not vertical.

@kutaibaa-akraa
Copy link
Copy Markdown
Contributor Author

It's a Defender Omega, which work as Microsoft Xbox 360 pad (idVendor=045e, idProduct=028e). Operating system is linux. In Remote Contgrol plugin it has device name: Microsoft Xbox 360 Controller (045e:028e).

axes: { leftX: 0, leftY: 1, rightX: 2, rightY: 3, l2: 4, r2: 5 }

Changing the rightY value from 3 to 5 (or vice versa) does not effects.

In Remote Control plugin Right Stick moves by horizontal, but not vertical.

Hi alex-w,

Thank you for the detailed information. This is very helpful. The issue is likely because on Linux, the axis mapping for your controller (which reports as an Xbox 360 controller) might be different from our current database entry.

To find the correct mapping, could you please do a quick test?

  1. Go to one of these online gamepad tester websites (they are safe and run only in your browser):

  2. Connect your "Defender Omega" controller and move only the Right Stick in all four directions (up, down, left, right).

  3. Watch the "Axes" section on the website and tell me:

    • Which axis number changes when you move the stick UP and DOWN? (e.g., Axis 3, Axis 4, etc.)
    • Which axis number changes when you move the stick LEFT and RIGHT?

This information will tell us the exact value that should be set for rightY in the code for your specific setup. Currently, our code might be using the wrong axis (like 3 or 5) for the vertical movement.

Once you provide these numbers, we can create a specific mapping for Linux users with this controller.

Thanks for your help with debugging!

@alex-w
Copy link
Copy Markdown
Member

alex-w commented Mar 13, 2026

Movements of Right Stick: Up/Down - Axis 3, Left/Right - Axis 2

@alex-w
Copy link
Copy Markdown
Member

alex-w commented Mar 13, 2026

OK, I found source of issue - this part of gpcontroller.js is not needed apparently:

// Special adjustments for Xbox controllers
if (deviceId.includes('xbox')) {
    switch(os) {
        case 'linux':
            axes.rightY = 4;  // Linux may use axis 4 for right Y
            break;
    }
}

@alex-w
Copy link
Copy Markdown
Member

alex-w commented Mar 14, 2026

The button “Connect” isn’t working apparently

@kutaibaa-akraa kutaibaa-akraa changed the title # Gamepad Controller Support for Stellarium Remote Control Gamepad Controller Support for Stellarium Remote Control Mar 15, 2026
@kutaibaa-akraa
Copy link
Copy Markdown
Contributor Author

OK, I found source of issue - this part of gpcontroller.js is not needed apparently:

// Special adjustments for Xbox controllers
if (deviceId.includes('xbox')) {
    switch(os) {
        case 'linux':
            axes.rightY = 4;  // Linux may use axis 4 for right Y
            break;
    }
}

Thank you, alex-w, for this detailed debugging and for finding the root cause. Your investigation into the axis mapping issue perfectly illustrates the core reason we moved away from the static database approach.

You are absolutely right. The old code's attempt to apply OS-specific overrides for controllers (like the Xbox adjustment you pointed out) is brittle. It assumes we can predict how every browser and OS combination will enumerate the axes, which is impossible to maintain. Your discovery that the line axes.rightY = 4; was the problem, and that the correct value is 3, proves this point exactly.

The new approach using the raw browser Gamepad API is fundamentally different and, as you've just demonstrated, far more robust. Here's why:

  1. Raw Data is the Truth: The browser gives us the raw, unmodified axis and button states. Instead of forcing a controller into a preconceived mapping (like "an Xbox controller on Linux should use axis 4 for right Y"), we now present the actual data to the user.

  2. Visual Debugging: The new interface includes a "Live Input" panel that displays the raw values for every single button and axis. When you moved the right stick and saw "Axis 3" change in the online tester, that same information is now visible directly in the Stellarium Remote Control tab. This makes debugging issues like this one trivial.

  3. User Empowerment: The old system required users to edit code or rely on developers to create special cases. The new system lets users (or testers like you) instantly see the live data. If an axis isn't mapped correctly for a specific game on a specific OS, the user can immediately identify the correct axis number from our own UI and report it, or in the future, potentially remap it themselves.

  4. Future-Proof: The Gamepad API is a web standard. By using it directly, we stop playing "whack-a-mole" with platform-specific quirks. We let the browser handle the low-level translation, and we just read the standardized result.

Your finding that the static override was wrong and that the raw axis value 3 is correct is a perfect, real-world validation of this new philosophy. The previous approach would have required a code change and a new PR. With the new approach, the system already shows the correct data; we just needed to remove the faulty assumption that was overriding it.

Thank you again for your thorough testing and for helping us make the controller support more reliable for everyone. The next step would be to ensure the base mapping for your "Defender Omega" (recognized as an Xbox 360 controller) is correct in the generic database, using the raw values you've identified (Right X: Axis 2, Right Y: Axis 3).

Please let me know if you encounter any other inconsistencies. The goal is for the "Live Input" panel to always show you exactly what the controller is doing, making any further configuration completely transparent.

@kutaibaa-akraa
Copy link
Copy Markdown
Contributor Author

kutaibaa-akraa commented Mar 18, 2026


Self-Critical Reflection: Reinventing the Approach with the Browser's Built-in Gamepad API

This reflection explains why the initial approach, based on integrating the SDL Game Controller Database, was fundamentally misdirected for a web application, and why the new implementation using the W3C Gamepad API is the correct path.

The Fundamental Misunderstanding

The first implementation attempted to use the SDL Game Controller Database, a community-sourced project designed for native applications built with SDL2/SDL3. This was an attractive idea because the database contains mappings for thousands of controllers. However, it failed to recognize a critical architectural boundary: SDL is a native library for compiled applications, not a standard for web browsers.

The integration approach was flawed for three reasons:

  1. It Reinvented Existing Work: We were essentially trying to replicate something that browser vendors have already spent years implementing, testing, and standardizing.
  2. It Was Brittle and Unmaintainable: Any change in OS, browser version, or controller firmware could break our static mappings, requiring constant manual updates to our code.
  3. It Solved the Wrong Problem: The challenge was not the lack of a controller database, but how to reliably access and interpret raw hardware input within the constraints of a web page.

The Browser's Native Solution: The Gamepad API

The new approach leverages the W3C Gamepad API, which is the correct, standards-based solution for web applications. The browser vendors (Mozilla, Google, Apple, Microsoft) have already done the heavy lifting for us. They have built the low-level, platform-specific code to interface with various operating systems and present a unified, consistent API to JavaScript.

Let's look at the evidence from the Firefox source code to see what is actually happening under the hood:

  1. Platform-Specific Implementations: Firefox does not rely on a single, static database. Instead, it has separate, well-defined modules for each major operating system to handle the raw input:

    • linux/LinuxGamepad.cpp: Uses udev and evdev to read raw events from the Linux kernel's input subsystem.
    • windows/WindowsGamepad.cpp: Uses native Windows APIs like XInput and DirectInput.
    • mac/ (implied): Uses IOKit and other macOS frameworks.
  2. The Remapping Layer: Firefox includes a sophisticated remapping engine, defined in GamepadRemapping.h and GamepadRemapping.cpp. This code does not use the SDL database. It contains its own logic to map the raw, OS-specific input events into the standard Gamepad API layout.

  3. A Unified API: The classes like Gamepad, GamepadButton, and GamepadManager present a clean, abstracted interface. When we call navigator.getGamepads(), we receive data that has already been processed, interpreted, and normalized by the browser's own extensive codebase.

Visual Proof: The New Interface in Action

The new interface provides complete transparency into controller input, making debugging and configuration intuitive:

Live Input Panel - Complete Visibility

The left panel shows real-time data from every button and axis on your controller. This is the raw data from the browser's Gamepad API, with no assumptions or pre-mappings applied:

live input

Figure 1: The Live Input panel displays all buttons and axes in real-time. Pressed buttons light up green, and axis values update continuously.

Button Customization - Full Control

The right panel allows complete remapping of every button to any Stellarium action, organized in a clean two-column layout:

button customization

Figure 2: Button customization with all Stellarium actions available in dropdown menus. Each controller can have its own unique mapping.

Calibration and Settings

The calibration section provides precise control over joystick behavior:

calibration

Figure 3: Calibration controls including deadzone, sensitivity, and axis inversion. The joystick preview shows real-time stick positions.

Multiple Device Support

The interface now supports multiple controllers simultaneously, with a device switcher:

multiple devices

Figure 4: Multiple connected controllers can be switched between, each with its own mappings and calibration.

Why This Approach is Superior

Feature SDL Database Approach (Old) W3C Gamepad API Approach (New)
Source of Truth Static, external text file Browser's dynamic mapping logic
Maintenance Burden Ours - constant updates needed Browser vendor's responsibility
Adaptability Low - requires database updates High - works with new controllers immediately
Platform Handling Manual mapping per OS Automatic - browser handles it
Debugging Opaque - no visibility Transparent - live data visible
Future-Proofing Poor - brittle and outdated Excellent - living web standard

The Moment of Discovery

The critical insight came when debugging a user's issue with a Defender Omega controller on Linux. The old code's OS-specific override (axes.rightY = 4;) was incorrect. The raw data from the browser showed the right stick's vertical movement on Axis 3, not Axis 4 or 5 as our database assumed.

With the new interface, this was immediately visible in the Live Input panel. No code changes, no database updates—just clear, transparent data.

Conclusion: A Necessary Pivot

The initial SDL-based approach was a well-intentioned but ultimately misguided attempt to solve a problem that browser vendors had already solved. The pivot to the W3C Gamepad API was not just a change in code; it was a fundamental shift in architecture. We moved from trying to manually interpret raw hardware signals in JavaScript, to trusting the browser's native, well-tested, and continuously maintained implementation.

This aligns our project with web standards, drastically reduces our maintenance burden, and provides a more robust and future-proof solution for Stellarium users. The new interface gives users complete visibility and control, making the system transparent and adaptable to any controller on any platform.


Note: The screenshots above demonstrate the actual working implementation. The interface maintains Stellarium's visual style while providing powerful new functionality.

@kutaibaa-akraa
Copy link
Copy Markdown
Contributor Author

full view new code

@kutaibaa-akraa
Copy link
Copy Markdown
Contributor Author

Subject: Gamepad Controller - Smooth Movement/Zoom Fix

Hi Alex,

For much smoother controller movement and zoom, please apply these two quick fixes:

1. File: /api/viewcontrol.js - Line 38

Change timeout from 250 to 100:

// In function move(x, y) - line 38
// FROM:
}, 250); //repeat each 250ms to avoid Stellarium thinking the interface crashed

// TO:
}, 100); //repeat each 100ms

2. File: /api/viewcontrol.js - Lines 60 & 74
Change both timeouts from 250 to 50:

// In fovServerUpdate() - line 60
fovTimeout = setTimeout(fovServerUpdate, 50);

// In fovServerUpdate() - line 74  
fovTimeout = setTimeout(fovServerUpdate, 50);

These changes eliminate the choppiness and provide a smooth, continuous movement and zoom experience with the gamepad.

@alex-w
Copy link
Copy Markdown
Member

alex-w commented Mar 23, 2026

@kutaibaa-akraa everything works now, except [Scan] button (the device are connected after pressing any button)

@gzotti what about changes of timeouts?

@gzotti

This comment was marked as resolved.

@alex-w

This comment was marked as resolved.

@10110111

This comment was marked as resolved.

@alex-w

This comment was marked as resolved.

@gzotti

This comment was marked as resolved.

@alex-w

This comment was marked as resolved.

@kutaibaa-akraa

This comment was marked as off-topic.

@alex-w
Copy link
Copy Markdown
Member

alex-w commented Mar 24, 2026

@kutaibaa-akraa oops, why you’re marked your latest comment as offtopic? It looks like great improvement for the feature…

@kutaibaa-akraa
Copy link
Copy Markdown
Contributor Author

@kutaibaa-akraa oops, why you’re marked your latest comment as offtopic? It looks like great improvement for the feature…

I will carry out these developments, but I want to verify them while ensuring they are ok 100%, and I will return to the report and suggestions I mentioned.

@kutaibaa-akraa
Copy link
Copy Markdown
Contributor Author

@kutaibaa-akraa everything works now, except [Scan] button (the device are connected after pressing any button)

Thank you for testing and for this feedback. The button behavior has been revised. In the initial implementation, the button was labeled "Connect" but its function was actually to scan for already-connected controllers rather than to establish a connection. This was misleading.

In the final version, the button has been renamed to "Scan" and its functionality has been enhanced:

  1. Visual feedback during scanning (button text changes to "Scanning...", disabled state, animated pulse effect)
  2. Force scan of all currently connected gamepads via navigator.getGamepads()
  3. Detection of recently connected devices that may not have triggered the gamepadconnected event
  4. User notification showing number of controllers found

The updated code (version 2.5.0 I'll introduce it later) now properly reflects the button's purpose: it forces a device scan and refreshes the device list. The button is located in the status bar next to the connection indicator, providing a clear way to manually refresh the controller list if needed.

@kutaibaa-akraa
Copy link
Copy Markdown
Contributor Author

Final Gamepad Controller Implementation - Ready for Submission

Summary of Completed Work

I am now ready to submit the final, complete version of the gamepad controller feature. The code has been thoroughly tested and includes all the enhancements discussed:

Key Improvements

1. Scan Button Resolution

The "Connect" button has been redesigned as a "Scan" button with full visual feedback. It now actively polls for connected controllers, displays a scanning animation, and shows the number of devices found. This resolves the previous issue where the button appeared non-functional.

2. Vibration Control Enhancement

The vibration feature has been expanded from a simple checkbox to a complete control system. Users can now enable/disable vibration and adjust intensity using a slider, with a test button to verify the effect before applying it to button presses.

3. Live Input Monitor

A new live input panel provides real-time visibility into raw controller data. Users can see every button and axis value exactly as reported by the browser, making debugging and configuration transparent. This eliminates the need for external testing tools.

4. Expanded Action Library

The number of available Stellarium actions has been significantly increased, now covering educational presentation features including view directions, zoom levels, notable stars, deep sky objects, constellation highlighting, time jumps, and season demonstrations.

5. Profile Import/Export

Complete profile management allows users to export their button mappings and calibration settings as JSON files, and import them for backup, sharing between installations, or restoring configurations after changes.

6. Multi-Controller Support

The system handles multiple controllers simultaneously, with independent profiles for each device. A device selector allows switching between connected controllers, and each device maintains its own mappings and calibration.

7. Standards Compliance

The implementation fully adheres to the W3C Gamepad API standard, eliminating the brittle static database approach. This ensures compatibility with future browsers and controllers without requiring code updates.

8. Plugin Support Architecture

The system dynamically detects and integrates with Stellarium plugins (ArchaeoLines, Scenery3d, ExoPlanets, NavStars, MeteorShowers, Quasars, Pulsars). When a plugin is loaded, its actions automatically appear in the button customization dropdowns. When a plugin is not loaded, its actions and associated UI elements are removed, maintaining a clean interface.

9. Additional Features

  • Joystick Calibration: Compensates for hardware drift by calculating center offsets
  • Real-time Preview: Canvas-based joystick position visualization
  • Sensitivity Controls: Independent adjustment for movement and zoom speed
  • Deadzone Configuration: Configurable threshold to prevent unintended input
  • Axis Inversion: Optional X/Y axis reversal for user preference
  • Server Connection Resilience: Polling stops when connection is lost and resumes automatically
  • Responsive Interface: Adapts to different screen sizes while maintaining Stellarium's visual theme

Testing Confirmation

The final code has been tested with:

  • PS5 DualSense (Windows, Chrome)
  • PS4 Controller (Windows, Chrome)
  • Generic XInput controller (Windows, Chrome/Firefox)
  • All core features verified

Question for Reviewers

Should I open a new pull request or update the existing #4813?

Please advise on your preference. If you prefer a new PR, I will close this one and open a fresh one with the complete, final code. If you prefer to keep this PR, I will force-push the final version to the same branch. Either approach works for me.

I am prepared to support this feature going forward as requested, and will address any bug reports that arise.


Please let me know whether to update this PR or open a new one.


Screenshots

localhost_8090__2026_03_27_12_01_11

Figuer: Gamepad tab with a connected PS5 controller showing the settings panel, live joystick preview, Live Input Monitor panel, and populated button customization area.

@alex-w
Copy link
Copy Markdown
Member

alex-w commented Mar 27, 2026

Should I open a new pull request or update the existing #4813?

Just update current PR

@gzotti
Copy link
Copy Markdown
Member

gzotti commented Mar 27, 2026

It sounds really interesting, however we still have to finalize 26.1. We should keep this PR. I think, as it's one new feature, squash&merge will be the final strategy, or would you keep separate commits to trace some development phases? In the latter case, you should rebase and prepare the cleaned-up commits (if needed) and force-push. However, as said, I have no time before April to go into detailed views.

You have edited index.html. Not sure if the new interfaces should also appear in the tablet-size tablet7in.html? (The tablet interface is more for presenters in front of a big screen, so not sure if the gamepad configs are relevant. )

@kutaibaa-akraa
Copy link
Copy Markdown
Contributor Author

It sounds really interesting, however we still have to finalize 26.1. We should keep this PR. I think, as it's one new feature, squash&merge will be the final strategy, or would you keep separate commits to trace some development phases? In the latter case, you should rebase and prepare the cleaned-up commits (if needed) and force-push. However, as said, I have no time before April to go into detailed views.

You have edited index.html. Not sure if the new interfaces should also appear in the tablet-size tablet7in.html? (The tablet interface is more for presenters in front of a big screen, so not sure if the gamepad configs are relevant. )

Thank you for the feedback and for confirming the PR will be kept. I understand the timing constraints for 26.1.

Regarding the tablet7in.html interface: I have now added the Gamepad Controller tab to it as well, following the same structure as index.html. The interface was tested using browser developer tools with device emulation (iPad) and by manually resizing the browser window. The layout adapts correctly to smaller screen sizes using the existing responsive CSS.

I will keep this PR open and continue with the current branch. Please let me know if you would like me to rebase or squash the commits before the final merge.

I am ready to support this feature going forward and will address any bug reports after release.

localhost_8090_tablet7in html(iPad Pro)

Figuer: Tested on Chrome with device emulation (iPad Pro).

The Gamepad Controller tab is now included in the tablet7in.html interface and displays correctly. The layout adapts responsively to tablet screen dimensions while maintaining full functionality.

Complete gamepad controller implementation v2.5.0

- Full W3C Gamepad API compliance
- Live Input Monitor for real-time debugging
- Enhanced Scan button with visual feedback
- Improved responsiveness with optimized timeouts
- Complete button customization interface
- Profile import/export functionality
- Responsive CSS matching Stellarium theme
- Added tablet7in.html support
When a controller is disconnected, the Live Input Monitor previously
continued to display stale button and axis values. This caused
confusion as the data appeared frozen rather than showing the
disconnected state.

Changes:
- Add null/undefined checks in updateLiveInputDisplay() to detect
  when no controller is connected
- Display "No controller connected" message in Buttons, Axes,
  and Device Information panels when no active device exists
- Call updateLiveInputDisplay() in setActiveDevice() when switching
  to null device
- Call updateLiveInputDisplay() in gamepaddisconnected event handler
- Add fallback messages in updateButtonsDisplay() and
  updateAxesDisplay() when gamepad data is unavailable

This ensures the Live Input Monitor reflects the actual connection
state, matching the behavior of the Button Customization panel
which already clears when no device is connected.
The "search_hercules_cluster" action previously targeted the Hercules
Galaxy Cluster (Abell 2151) instead of the intended globular cluster
M13. This was confusing as M13 is the more commonly referenced object.

Changes:
- Add special case in handleSearchAction to map "hercules_cluster" to "M13"
- Update display name to "Center on Star Cluster in Hercules (M13)" for clarity

Now pressing the button correctly centers on the Great Hercules Globular
Cluster (Messier 13) as expected.
Replaces instant camera jumps with smooth 3-second transitions for all view direction actions (North, South, East, West, Zenith, Nadir).
Previously used rc.postCmd("/api/main/view") which instantly changed the view direction. Now uses core.moveToAltAzi() with a duration parameter for gradual movement, matching the existing stelssc buttons in the web interface.
Changes:
- view_north: core.moveToAltAzi(0, 180, 3)
- view_south: core.moveToAltAzi(0, 0, 3)
- view_east:  core.moveToAltAzi(0, 90, 3)
- view_west:  core.moveToAltAzi(0, 270, 3)
- view_zenith: core.moveToAltAzi(90, 0, )
- view_nadir:  core.moveToAltAzi(-90, 0, 3)

This provides a more natural and visually pleasing experience when navigating between cardinal directions during presentations.
… offset

Replaces instant zoom and viewport offset changes with smooth 3-second
transitions for all zoom levels and viewport offset presets.
Previously used viewcontrol.setFOV() and propApi.setStelPropQueued()
which changed values instantly. Now uses StelMovementMgr.zoomTo() and
StelMovementMgr.moveViewport() with duration parameter for gradual
movement, matching the existing stelssc buttons in the web interface.

Changes:
- Zoom levels: StelMovementMgr.zoomTo(value, 3)
  - All zoom presets (0.1° to 180°) now transition smoothly over 3 seconds
- Viewport offset: StelMovementMgr.moveViewport(0, value, 3)
  - All offset presets (-50% to +100%) now transition smoothly over 3 seconds

This provides a more natural and visually pleasing experience when
adjusting zoom and viewport during presentations.
Adds Sun, Moon, Uranus, Neptune, and Pluto to the list of searchable
solar system objects for the gamepad controller.

Previously only Mercury, Venus, Mars, Jupiter, and Saturn were available.
Now includes all major solar system bodies for comprehensive educational
presentations.

New objects:
- Sun
- Moon
- Uranus
- Neptune
- Pluto

All objects use the same search mechanism as existing planets,
centering on the target with the configured selection mode.
Converts constellation highlight actions from one-shot to toggle mode.

First press: isolates and highlights the selected constellation
Second press: clears isolation and shows all constellations

This provides more intuitive control during presentations, allowing
users to easily toggle between isolated constellation views and
the full sky view without needing a separate "clear" button.

Changes:
- Check current isolation state and selected object
- If same constellation is already highlighted, clear it
- Otherwise, apply highlight with isolation enabled
- Maintains proper feedback notifications for both states
…UI layout

Major improvements to Gamepad Controller module:

1. Live Input Monitor Enhancement:
   - Replaced simple grid with 4-column compact button layout for better space utilization
   - Added visual meter bars for axes display showing real-time analog values
   - Implemented color-coded feedback (green for positive, red for negative axes)
   - Added device information panel with OS and browser detection
   - Improved responsive design for mobile and tablet devices

2. Zoom Inversion Feature:
   - Added "Invert Y-Axis (Zoom stick)" checkbox for right stick zoom control
   - Implemented zoom inversion logic that affects both zoom behavior and canvas preview
   - Canvas now visually reflects inverted Y-axis movement while Live Input Monitor continues to show raw values
   - Added zoomInvertY setting to persistent storage

3. UI Layout Reorganization:
   - Restructured Joystick Preview section with cleaner separation
   - Added current direction display below left stick showing real-time movement direction (North, South, East, West, etc.) with speed indicator
   - Moved Current FOV display below right stick for consistent layout
   - Grouped axis inversion checkboxes together for better organization
   - Reduced overall spacing and padding for more compact interface
   - Improved responsive behavior across all screen sizes

Files modified:
- gamepad.css: Added styles for live input buttons, axis meters, joystick info panel, and responsive grid layouts
- gpcontroller.js: Added zoomInvertY setting, updateCurrentDirection() method, enhanced updateButtonsDisplay() and updateAxesDisplay() with visual meters, modified updateStickPreview() to respect zoom inversion visually
- index.html&tablet7in.html: Reorganized joystick preview section with direction display, added zoom invert checkbox, restructured live input panel layout

Version: 2.5.0 → 2.6.0
Fix FOV synchronization between gamepad zoom control and main interface:

- Add $viewFovSlider reference to update main FOV slider directly
- Update view_fov_text immediately when zooming with gamepad
- Extend zoom range to match viewcontrol.js (0.001389° to 360°)
- Add zoomInvertY to persistent settings storage
- Listen to fovChanged event for proper synchronization

This resolves the issue where zooming with the right stick would
cause choppy movement and desynchronization between the gamepad
display and the main FOV slider/text in the View tab.

Files modified:
- webroot/js/ui/gpcontroller.js
Fix FOV display synchronization when using button mappings that modify zoom:

- Update currentFov immediately when reset_zoom action is triggered
- Ensure updateFovDisplay() updates both gamepad panel and main view tab
- Synchronize view_fov_text and view_fov slider on every FOV change
- Maintain proper FOV range (0.001389° to 360°) across all components
- Add JSDoc documentation for init() function

This resolves the issue where pressing a button mapped to "Reset zoom"
would not update the FOV display in the gamepad panel or the main view tab.

Files modified:
- webroot/js/ui/gpcontroller.js
…sponsive design

This commit introduces comprehensive UI improvements to the Gamepad Controller
module, focusing on visual consistency with Stellarium's original styling,
enhanced responsive behavior across all device sizes, and improved device
information display.

Key Improvements:

**Styling & Visual Consistency (gamepad.css)**
- Updated all text colors to match Stellarium's original style: headers, labels,
  and section titles now use black (#000000) for better readability
- Maintained existing color scheme for action names and help text for visual hierarchy
- Improved background consistency across all gamepad tabs to match main Stellarium theme
- Enhanced button dropdown styling with proper optgroup and option colors

**Device Information Enhancements (index.html & gpcontroller.js)**
- Added button and axis count display in device info card showing actual hardware capabilities
- Dynamic updates reflect real-time device specifications when controller is connected
- Improved device identification with clear display of button/axis counts (format: "16 / 4")

**Joystick Preview Layout (index.html)**
- Reorganized joystick preview into proper two-column layout that remains side-by-side
  on tablets and larger screens (>700px)
- Each joystick now contains its own inversion controls within its card:
  - Left stick: Invert X and Invert Y options
  - Right stick: Invert Y (Zoom stick) option
- Improved canvas rendering with proper crosshair centering and accurate stick positioning
- Added visual feedback for checkbox states with green accent when enabled

**Canvas Rendering Fix (gpcontroller.js)**
- Fixed updateStickPreview function to use actual canvas dimensions instead of CSS dimensions
- Corrected crosshair and center point positioning for accurate joystick visualization
- Added proper stick position clamping within canvas boundaries
- Implemented radius calculation based on actual canvas size for consistent display
- Dynamic update of button/axis counts in device info during polling

**Comprehensive Responsive Design**
- Desktop (1400px+): Optimized panel widths and font sizes
- Standard screens (1025-1399px): Balanced layout with reduced spacing
- Tablet landscape (769-1024px): Compact fonts and adjusted button groups
- Tablet portrait (481-768px): Column-stacked layout with condensed spacing
- Mobile phones (320-480px): Minimal padding, reduced font sizes for all elements

**Slider & Control Improvements**
- Reduced spacing between slider rows for compact display
- Adjusted font sizes and min-widths for better small screen compatibility
- Optimized vibration intensity row visibility and spacing
- Improved checkbox groups with tighter spacing on mobile

**Live Input Monitor Enhancements**
- Consistent background styling matching main gamepad panel
- Responsive button grid: 4 columns on desktop, 3 on medium, 2 on tablet, 1 on mobile
- Adjusted font sizes and meter heights for better readability on all devices
- Optimized device info display with column wrapping

**Button Customization Panel**
- Reduced internal spacing for more compact presentation
- Adjusted dropdown font sizes for better readability
- Improved button group headers and item spacing for small screens
- Maintained dropdown styling with black text for options and optgroups

**Calibration Section**
- Consistent styling with black headers
- Improved responsive layout for calibration buttons on mobile
- Better spacing for calibration values grid

This update ensures the Gamepad Controller tab now matches Stellarium's
visual identity while providing a seamless experience across all devices
from desktop monitors to mobile phones. Users can now see detailed device
information including button and axis counts directly in the interface.

Files modified:
- index.html (joystick preview structure + device info enhancements)
- gamepad.css (complete responsive styling overhaul)
- gpcontroller.js (canvas rendering fix + button/axis count display)
- tablet7in.html (optional tablet layout adjustments)

Version: 2.6.0
Date: 2026-04-01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

purpose: interoperability Interoperability issues subsystem: plugins The issue is related to plugins of planetarium...

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

5 participants