Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linux: add support for more virtual input devices #2261

Closed
wants to merge 7 commits into from

Conversation

ABeltramo
Copy link
Collaborator

@ABeltramo ABeltramo commented Mar 14, 2024

Description

This is still a draft, please let me know if something is not working

Added support for the followings new virtual devices:

  • Nintendo Switch pro joypad
  • DualSense (PS5) joypad, including:
    • Gyroscope
    • Accelerometer
    • Touchpad
    • LED
    • Battery status
    • Force feedback? (is this supported in Moonlight already? I have to check..)
    • Microphone and Headset jack? (we should be able to plug into that as well, to be checked..)

And generally completely refactored all virtual input code using inputtino as a library

Requirements

The DualSense implementation requires access to /dev/uhid, (more on this later..) this is easily done by setting the right permissions, similar to how we deal with udev already:

First we’ll add our user to the input group:

sudo usermod -a -G input $USER

Then we add an udev rule to allow access to /dev/uhid:

echo 'KERNEL=="uhid", GROUP="input", MODE="0660"' | sudo tee /etc/udev/rules.d/99-uhid.rules

Finally, we have to make sure that the uhid kernel module is loaded at boot:

echo "uhid" | sudo tee /etc/modules-load.d/uhid.conf

Code details

The main file is src/platform/linux/inputtino.cpp I've kept the original input.cpp so that we can easily compare the two implementations and possibly add what's missing but the idea would be to completely replace that implementation with this. To switch from one implementation to the other you can just set the Cmake variable -DSUNSHINE_USE_INPUTTINO=OFF.

Unfortunately we have to deal with uhid in order to properly emulate gyro, acceleration and touchpad; there's a bit of a rationale into why this is not possible with udev here. This might be a deal breaker for you guys but I hope it's not; if that's the case, we can still emulate a PS5 joypad using udev without supporting gyro and acceleration.

I think bringing in uhid has also other benefits, since it sits at a lower level than uinput, we can really emulate any kind of usb device and possibly even completely integrate usb over IP if this will ever be considered as an addition to the protocol.

As for the code itself, Inputtino has got unit tests using libinput for mouse, keyboard, pen and touchscreen and SDL2 for testing joypads. These aren't complete (yet) but should cover most of the codebase.

Future plans

  • I'd like to give it a go at implementing gyro and acceleration support for a Nintendo joypad too.
  • Ideally, since we are emulating the real joystick USB messages, this should also be a good foundation for a Windows virtual driver implementation. I know nothing about this but I'd like to do more research on it and possibly add a multiplatform implementation to inputtino.
    • I know of the EV license and all the requirements, for some reason it's hard to convince companies to invest in this without a functioning prototype first 😅
  • Add support for trackpads in Moonlight? Generally it seems to not be the same as a touchscreen: it moves relatively instead of absolutely and has got different gestures.

What's missing?

Most notably the XTest fallback that is present in input.cpp if this is something that is used we can easily add it here as well.
Everything else should be implemented, please let me know if something is missing or misbeaving.

I'm probably forgetting something else..

Issues Fixed or Closed

Might help with #1720

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 not work as expected)
  • Dependency update (updates to dependencies)
  • Documentation update (changes to documentation)
  • Repository update (changes to repository files, e.g. .github/...)

Checklist

  • My code follows the style guidelines 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 added or updated the in code docstring/documentation-blocks for new or existing methods/components

Branch Updates

LizardByte requires that branches be up-to-date before merging. This means that after any PR is merged, this branch
must be updated before it can be merged. You must also
Allow edits from maintainers.

  • I want maintainers to keep my branch updated

.gitmodules Outdated Show resolved Hide resolved
.gitmodules Outdated Show resolved Hide resolved
cmake/compile_definitions/linux.cmake Outdated Show resolved Hide resolved
src/platform/linux/inputtino.cpp Outdated Show resolved Hide resolved
};

int
alloc_gamepad(input_t &input, const gamepad_id_t &id, const gamepad_arrival_t &metadata, feedback_queue_t feedback_queue) {
Copy link
Member

Choose a reason for hiding this comment

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

The gamepad options will need be exposed in the config ui.

https://github.com/LizardByte/Sunshine/blob/8316f44e10f3f6ef27fc27b3ef6e69f359b1b667/src_assets/common/assets/web/config.html#L141C1-L150C15

Can probably become (untested).

        <!-- Emulated Gamepad Type -->
        <div class="mb-3" v-if="config.controller === 'enabled' && (platform === 'windows' || platform === 'linux')">
          <label for="gamepad" class="form-label">Emulated Gamepad Type</label>
          <select id="gamepad" class="form-select" v-model="config.gamepad">
            <option value="auto">Automatic</option>
            <option value="ds4">DS4 (PS4)</option>
            <option value="switch" v-if="platform === 'linux'">Nintendo Pro (Switch)</option>
            <option value="x360">X360 (Xbox 360)</option>
          </select>
          <div class="form-text">Choose which type of gamepad to emulate on the host</div>
        </div>


if (config::input.gamepad == "x360"sv) {
BOOST_LOG(info) << "Gamepad " << id.globalIndex << " will be Xbox 360 controller (manual selection)"sv;
selectedGamepadType = XboxOneWired;
Copy link
Member

Choose a reason for hiding this comment

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

Should we add an option for xbox-one instead of using x360?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I wasn't sure how this was handled in the UI so I've re-used what was already defined there. Ideally we should also add the Nintendo joypad which is now present with this PR.
I should look further into this..

Copy link
Member

Choose a reason for hiding this comment

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

I think my comment here should be enough to help with the UI.

I also notice you have ds4 and ps4 under supported_gamepads (and we have that in our Windows input file as well)... I'm not sure what the difference is, but ps4 doesn't appear to be exposed in the UI.

src/platform/linux/inputtino.cpp Show resolved Hide resolved
@ReenigneArcher
Copy link
Member

Homebrew is failing due to the name of your default branch. If you make your default nightly that error will go away.

@ReenigneArcher
Copy link
Member

ReenigneArcher commented Mar 19, 2024

libudev isn't being found for all the linux builds. We have udev. On Ubuntu it says this depends on libudev so there might be an issue with searching for it in inputtino?

@ABeltramo
Copy link
Collaborator Author

Yep, libudev is used by inputtino, I thought it was already a dependency of libevdev, but it looks like that's not the case. I can easily make it optional since it's only used for an utility method that is not needed for Sunshine.

Copy link
Member

@ReenigneArcher ReenigneArcher left a comment

Choose a reason for hiding this comment

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

A few documentation suggestions...

<p class="mb-0">
Sunshine emulates an Xbox 360 or DS4 controller. Use nearly any
controller on your Moonlight client!<br>
<small>
<ul>
<li>DS4 emulation is only available on Windows.</li>
<li>Gamepad emulation is not currently supported on macOS.</li>
</ul>
</small>
</p>

Could be updated to:

                                            <p class="mb-0">
                                                Sunshine emulates an Xbox, DS4, or Nintendo Switch controller. Use nearly any
                                                controller on your Moonlight client!<br>
                                                <small>
                                                  <ul>
                                                    <li>Switch emulation is only available on Linux.</li>
                                                    <li>Gamepad emulation is not currently supported on macOS.</li>
                                                  </ul>
                                                </small>
                                            </p>

`gamepad <https://localhost:47990/config/#gamepad>`__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
**Description**
The type of gamepad to emulate on the host.
.. caution:: Applies to Windows only.
**Choices**
.. table::
:widths: auto
===== ===========
Value Description
===== ===========
auto Selected based on information from client
x360 Xbox 360 controller
ds4 DualShock 4 controller (PS4)
===== ===========
**Default**
``auto``
**Example**
.. code-block:: text
gamepad = auto

Could be updated to:

`gamepad <https://localhost:47990/config/#gamepad>`__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

**Description**
   The type of gamepad to emulate on the host.

   .. attention:: Gamepad is not supported on macOS.

**Choices**

.. table::
   :widths: auto

   =====     ===========
   Value     Description
   =====     ===========
   auto      Selected based on information from client
   x360      Xbox 360 controller
   ds4       DualShock 4 controller (PS4)
   switch    Nintendo Switch (Linux only)
   =====     ===========

**Default**
   ``auto``

**Example**
   .. code-block:: text

      gamepad = auto

@ABeltramo

This comment was marked as resolved.

@ReenigneArcher

This comment was marked as resolved.

@ABeltramo

This comment was marked as resolved.

This comment was marked as resolved.

@ReenigneArcher

This comment was marked as resolved.

@ReenigneArcher

This comment was marked as resolved.

@ABeltramo ABeltramo closed this Mar 28, 2024
@ABeltramo ABeltramo deleted the inputtino branch March 28, 2024 16:19
@ReenigneArcher

This comment was marked as resolved.

@ABeltramo

This comment was marked as resolved.

@ReenigneArcher

This comment was marked as resolved.

@ABeltramo

This comment was marked as resolved.

@ReenigneArcher

This comment was marked as resolved.

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