nefarius / ViGEmBus

Windows kernel-mode driver emulating well-known USB game controllers.
https://docs.nefarius.at/projects/ViGEm/
BSD 3-Clause "New" or "Revised" License
3.08k stars 284 forks source link

Add touchscreen support for the Dualshock 4 touchpad #11

Closed NeoTechni closed 3 years ago

NeoTechni commented 5 years ago

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?

saidsay-so commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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

Blackbird88 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

R I P This would be quite useful indeed

Davidobot commented 4 years ago

@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 commented 4 years ago

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

Davidobot commented 4 years ago

@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 commented 4 years ago

@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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

@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 commented 4 years ago

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 commented 4 years ago

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):

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

Davidobot commented 4 years ago

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 commented 4 years ago

image

Davidobot commented 4 years ago

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 commented 4 years ago

@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 commented 4 years ago

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 commented 4 years ago

image

Davidobot commented 4 years ago

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 commented 4 years ago

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

nefarius commented 4 years ago

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

So far so good 😎

Davidobot commented 4 years ago

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 commented 4 years ago

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 commented 3 years ago

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

nefarius commented 3 years ago

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

nefarius commented 3 years ago

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

nefarius commented 3 years ago

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