Skip to content
This repository has been archived by the owner on Nov 2, 2023. It is now read-only.

Add touchscreen support for the Dualshock 4 touchpad #11

Closed
NeoTechni opened this issue Mar 7, 2019 · 31 comments
Closed

Add touchscreen support for the Dualshock 4 touchpad #11

NeoTechni opened this issue Mar 7, 2019 · 31 comments
Assignees
Labels
enhancement New feature or request

Comments

@NeoTechni
Copy link

I use ViGEm for using a tablet with game controls for remote play, which is better than Vita except clicking the touchscreen doesn't send touchpad events to the PS4. Could you please add this?

@nefarius nefarius added the enhancement New feature or request label Mar 8, 2019
@nefarius nefarius self-assigned this Mar 8, 2019
@saidsay-so
Copy link

Hi!
Is there any news for this feature ? I need it for a project and I made some changes in my branch which can maybe help you.

@nefarius
Copy link
Owner

No news. Driver needs to be modified as well for this, probably API-breaking changes for existing users, a new round of testing, WHQL etc. this isn't trivial to implement and currently not promising with my available resources.

@fortheart23
Copy link

Hi!
Is there any news for this feature ? I need it for a project and I made some changes in my branch which can maybe help you.

Hi) Can you please add the ability to emulate the full touch pad and gyro, for playstation now?

@saidsay-so
Copy link

Oh crap, I thought that only the report needed changes. I understand now if you can't implement it.

@Blackbird88
Copy link

I thought I was going crazy when RPCS3 didn't detect any gyro movement from the Virtual DS4 so yeah this would be really useful!

@nefarius
Copy link
Owner

See my previous comments. I'm aware this is a useful request but I don't have the capacity nor the motivation to touch this in the near future.

@NyaomiDEV
Copy link

R I P
This would be quite useful indeed

@Davidobot
Copy link

@musikid @nefarius
I managed to implement (and test) gyro + accel passthrough. It required just changing the structure of the DS4Report. I just recompiled the Bus with the new Common.h and it worked perfectly.

There is meant to be another byte (//BYTE bBatteryLvl;) according to the HID report but it seems ViGEm was either inserting something there already (or some other magic). So I found that that specific HID structure worked.

To test this, I implemented two new methods - SetIMUValue and SetTimestampValue into ViGEm.NET and then used them in my project BetterJoy. I ran tests using a modified version of DS4Windows that allowed emulated controllers to be picked up, and then visualised the gyro/accel in PadTest.

The test setup works quite well, so it would be viable to test and implement the touch API through this as well. DS4Windows has the full DS4 report break-down.

@nefarius
Copy link
Owner

@Davidobot nice work! Now I just need a way to not completely nuke backwards compatibility... 🤔

@Davidobot
Copy link

@nefarius I was toying around with the idea of having a separate 'special' DS4Report structure that gets appended onto the main DS4Report. There are quite a few references to DS4Report in the code though, so I'll have to carefully comb through that.

I was wondering - do you know why there is no need for the bBatteryLvl offset? According to all HID report documentation I read, there must be a single byte to indicate battery level there. Does the Bus splice the byte in? If so, do you know where in the code it happens?

@nefarius
Copy link
Owner

@Davidobot actually despite the report structure coming in from the API being shorter, I actually initialize the full size report with default values so it matches the size in the HID Report Descriptor.

If we compare your modification to this documentation of the report structure, there should be a 3 byte padding required separating the Right Trigger byte and the Gyro X byte.

If we ignore the remaining data, the report structure of yours with the battery commented out has a size of 23 bytes (ignoring the one always reserved for Report ID), which according to the docs would be one missing.

Are you sure you're testing with the version that has the battery commented out? Happened to me a lot debugging outdated binaries and wondering WTF was going on 😆

@nefarius
Copy link
Owner

I looked into the unspeakable horrors of the past and it appears that battery level info sits at byte 30 (like with the DS3).

@Davidobot
Copy link

If we compare your modification to this documentation of the report structure, there should be a 3 byte padding required separating the Right Trigger byte and the Gyro X byte.

Yup! I have a USHORT wTimestamp; between the right trigger and gyro.

If we ignore the remaining data, the report structure of yours with the battery commented out has a size of 23 bytes (ignoring the one always reserved for Report ID), which according to the docs would be one missing.

Are you sure you're testing with the version that has the battery commented out? Happened to me a lot debugging outdated binaries and wondering WTF was going on 😆

I just looked over it again, and sure enough, if I have the battery byte there between the timestamp and gyroX, then I start getting offset errors (as in assigning to gyroZ will actually change accelX when looking at the report).

I looked into the unspeakable horrors of the past and it appears that battery level info sits at byte 30 (like with the DS3).

That does indeed seem to be the case, judging by DS4Windows as well. Strange - does that mean the report layout on eleccelerator is wrong? Though the gyro/accel data does indeed seem to start at byte 13 (not 12), so there is something at 12, but it's not being read at least in DS4Windows.

I'll dump the reports that the Bus sends and the ones DS4Windows picks up. To see what is going on with that missing byte.

@saidsay-so
Copy link

saidsay-so commented Apr 23, 2020

@Davidobot FWIW, I got the report by comparing with Linux HID driver parsing. It seems that the report provided by Eleccelerator is wrong.
Also, I don't know if it will be useful, but I tried to add some functions for the touchpad (here), which I didn't test since I'm not using Windows anymore.

@nefarius
Copy link
Owner

If in doubt I'd trust the Linux sources, I did that too after abandoning the SCP sources wich were full of misleading legacy sections.

According to them, Gyro X is indeed read at byte 13, as seen here.

@nefarius
Copy link
Owner

nefarius commented Apr 23, 2020

I've quickly captured a DS4 Rev1 USB HID Input Report how it looks on the wire (report data in bold):

0000   1b 00 a0 d9 16 ba 8a d7 ff ff 00 00 00 00 09 00   ................
0010   01 02 00 03 00 84 01 40 00 00 00 01 80 82 7f 7f   .......@........
0020   08 00 94 00 00 5b 58 06 5d fb 3e fc f6 fa 9c 05   .....[X.].>.....
0030   b3 18 e9 eb 00 00 00 00 00 12 00 00 01 af 02 48   ...............H
0040   d3 06 80 00 00 00 00 80 00 00 00 80 00 00 00 00   ................
0050   80 00 00 00 80 00 00 00 00 80 00                  ...........

Where it looks like that byte 13 is indeed the correct offset (careful with endianness):

  • Gyro X: 5d fb
  • Gyro Y: 3e fc
  • Gyro Z: f6 fa
  • Accel X: 9c 05
  • Accel Y: b3 18
  • Accel Z: e9 eb

Byte 30 is battery level with value 0x12 (charging, low battery). Currently ViGEmBus always reports fully charged.

@Davidobot
Copy link

Ah, figured out why removing that battery byte made the gyro/accel data line up properly. There is an off-by-one error (somewhy) in transposing the data from DS4Report into the buffer. ie after the trigger bytes there is a single always-0 byte, and THEN the extra 7 elements get copied in.

So the report it outputs looks like this

...<bTriggerR> <mysterious 0 byte> <wTimestamp><wGyroX>...
      byte 9        10               11, 12    13,14    

Not sure where this comes from as the DS4_Report in Common.h (used for both the driver and client) doesn't have this blank space.

@nefarius
Copy link
Owner

image

@Davidobot
Copy link

Davidobot commented Apr 23, 2020

Are you ready to hear even more curious findings?

Whenever wTimestamp is a SHORT or USHORT, then the magic always-0 byte is there. If you replace the wTimestamp with two bytes BYTE bTimestamp1 and bTimestamp2 then the always-0 byte is no longer there. ¯\_(ツ)_/¯

I honestly thought I was going crazy, but testing this multiple times I am convinced this is the case. wButtons doesn't have the same thing happening to it. Moreover, when it's

USHORT wTimestamp;
SHORT wGyroX;...

There is no gap. When I introduce BYTE bBatteryLvl between the USHORT and SHORT, then the next SHORT also has a magic 0 in front of it.

Here's a (bad) diagram of what's happening:
image

It seems whenever there is a change between types, then there is a gap. Only sometimes though. Wtf is going on 🤔

@nefarius
Copy link
Owner

@Davidobot hihi, it's hidden in plain sight 😆

Tell you what, add #include <pshpack1.h> before and #include <poppack.h> after the the report struct, recompile and observe 🙂

(Hint: the compiler outsmarted us)

@Davidobot
Copy link

Why of course! This is great revision for my Programming in C and C++ course haha... This fixed it. I may as well go ahead and implement the touch API as well right now. If you're breaking an API, might as well do it majorly.

@nefarius
Copy link
Owner

image

@Davidobot
Copy link

Davidobot commented Apr 26, 2020

Bam, implemented and tested the touch data segments. Code here. This means that ViGEm can now fully emulate the full HID USB packet!

Since this is USB, there is a max of 3 touch packets at any one time. You can set the current one with DS4_SET_TOUCHPAD and "preset" (ie copy current into old and increment packet counter) with DS4_PRESET_TOUCHPAD.

eg (setting all 3 touchdata packets, for both fingers):

DS4_SET_TOUCHPAD(&report, true, 0, 0, 1, true);
DS4_SET_TOUCHPAD(&report, false, 138, 644, 1, false);
DS4_PRESET_TOUCHPAD(&report);
DS4_SET_TOUCHPAD(&report, true, 139, 644, 2, false);
DS4_SET_TOUCHPAD(&report, false, 0, 0, 2, true);
DS4_PRESET_TOUCHPAD(&report);
DS4_SET_TOUCHPAD(&report, true, 0, 0, 3, true);
DS4_SET_TOUCHPAD(&report, false, 138, 644, 3, false);

EDIT: Added and tested .NET bindings.

@nefarius I'd love to see this integrated into the main master project. Do you need to do any clean-up or anything else?

@nefarius
Copy link
Owner

Great work, I have an idea on how to integrate while maintaining backwards compatibility, I'll keep you posted.

@nefarius
Copy link
Owner

nefarius commented May 5, 2020

So here's the first draft of my plan/suggestion (backwards compatibility with existing software in mind):

  • Introduce your modified struct as additional DS4_REPORT_EX
  • Introduce additional API function vigem_target_ds4_update_ex accepting said struct
  • Reuse same I/O control code, but adapt payload size check to distinguish between "old/existing" and "new"
  • Polish types
  • Test
  • Cry because WHQL procedure is PITA
  • Publish & profit

So far so good 😎

@Davidobot
Copy link

Nice! I was playing around with a very similar idea (/w additional struct) but didn't get too far because I 'm not too familiar with the Bus and what I would have to edit to get it working properly.

I'll give it another shot if I find the time. Thanks!

@nefarius
Copy link
Owner

nefarius commented May 5, 2020

For now it would be help enough if you could simply thoroughly test what you've built, the rest I can take a spin on. Be my guest on Discord if that helps.

@Aniles95
Copy link

Aniles95 commented Oct 3, 2020

@nefarius Hey i have been desperately searching for the link for V 1.17. i cannot find any help?

@nefarius
Copy link
Owner

nefarius commented Oct 3, 2020

There is none. It's work-in-progress 🙄

@nefarius
Copy link
Owner

Need to merge the SDK and .NET lib branches to master, then this issue is done ✨

@nefarius
Copy link
Owner

It's done and live for both native and managed SDK.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

8 participants