blob: ead11fae7cae396c3921e98a069e42c1a37b0c5b [file] [log] [blame]
/*
* Copyright (C) 2020 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "config.h"
#import "VirtualGamepad.h"
#if USE(APPLE_INTERNAL_SDK)
#import <HID/HIDUserDevice.h>
namespace TestWebKitAPI {
const uint8_t Dualshock4Descriptor[] = {
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x05, // Usage (Game Pad)
0xA1, 0x01, // Collection (Application)
// Report ID - Total (1) byte
0x85, 0x01, // Report ID (1)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x32, // Usage (Z)
0x09, 0x35, // Usage (Rz)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x04, // Report Count (4)
// (4) Axes at 1 byte each - Total (5) bytes
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x39, // Usage (Hat switch)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x07, // Logical Maximum (7)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
// 4-bits for Hatswitch - Total (5) bytes (4) bits
0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x0E, // Usage Maximum (0x0E)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x0E, // Report Count (14)
// 14 buttons - Total (7) bytes (2) bits
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x06, // Report Size (6)
0x95, 0x01, // Report Count (1)
// 6-bits padding - Total (8) bytes
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x33, // Usage (Rx)
0x09, 0x34, // Usage (Ry)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x02, // Report Count (2)
// (2) axes 1 byte each - Total (10) bytes
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x04, 0xFF, // Usage Page (Vendor Defined 0xFF04)
0x85, 0x02, // Report ID (2)
0x09, 0x24, // Usage (0x24)
0x95, 0x24, // Report Count (36)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA3, // Report ID (-93)
0x09, 0x25, // Usage (0x25)
0x95, 0x30, // Report Count (48)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x05, // Report ID (5)
0x09, 0x26, // Usage (0x26)
0x95, 0x28, // Report Count (40)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x06, // Report ID (6)
0x09, 0x27, // Usage (0x27)
0x95, 0x34, // Report Count (52)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x07, // Report ID (7)
0x09, 0x28, // Usage (0x28)
0x95, 0x30, // Report Count (48)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x08, // Report ID (8)
0x09, 0x29, // Usage (0x29)
0x95, 0x2F, // Report Count (47)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x09, // Report ID (9)
0x09, 0x2A, // Usage (0x2A)
0x95, 0x13, // Report Count (19)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x06, 0x03, 0xFF, // Usage Page (Vendor Defined 0xFF03)
0x85, 0x03, // Report ID (3)
0x09, 0x21, // Usage (0x21)
0x95, 0x26, // Report Count (38)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x04, // Report ID (4)
0x09, 0x22, // Usage (0x22)
0x95, 0x2E, // Report Count (46)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF0, // Report ID (-16)
0x09, 0x47, // Usage (0x47)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF1, // Report ID (-15)
0x09, 0x48, // Usage (0x48)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF2, // Report ID (-14)
0x09, 0x49, // Usage (0x49)
0x95, 0x0F, // Report Count (15)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
0x85, 0x11, // Report ID (17)
0x09, 0x20, // Usage (0x20)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x4D, // Report Count (77)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x21, // Usage (0x21)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x12, // Report ID (18)
0x09, 0x22, // Usage (0x22)
0x95, 0x8D, // Report Count (-115)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x23, // Usage (0x23)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x13, // Report ID (19)
0x09, 0x24, // Usage (0x24)
0x95, 0xCD, // Report Count (-51)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x25, // Usage (0x25)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x14, // Report ID (20)
0x09, 0x26, // Usage (0x26)
0x96, 0x0D, 0x01, // Report Count (269)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x27, // Usage (0x27)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x15, // Report ID (21)
0x09, 0x28, // Usage (0x28)
0x96, 0x4D, 0x01, // Report Count (333)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x29, // Usage (0x29)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x16, // Report ID (22)
0x09, 0x2A, // Usage (0x2A)
0x96, 0x8D, 0x01, // Report Count (397)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x2B, // Usage (0x2B)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x17, // Report ID (23)
0x09, 0x2C, // Usage (0x2C)
0x96, 0xCD, 0x01, // Report Count (461)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x2D, // Usage (0x2D)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x18, // Report ID (24)
0x09, 0x2E, // Usage (0x2E)
0x96, 0x0D, 0x02, // Report Count (525)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x2F, // Usage (0x2F)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x19, // Report ID (25)
0x09, 0x30, // Usage (0x30)
0x96, 0x22, 0x02, // Report Count (546)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x31, // Usage (0x31)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x06, 0x80, 0xFF, // Usage Page (Vendor Defined 0xFF80)
0x85, 0x82, // Report ID (-126)
0x09, 0x22, // Usage (0x22)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x83, // Report ID (-125)
0x09, 0x23, // Usage (0x23)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x84, // Report ID (-124)
0x09, 0x24, // Usage (0x24)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x90, // Report ID (-112)
0x09, 0x30, // Usage (0x30)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x91, // Report ID (-111)
0x09, 0x31, // Usage (0x31)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x92, // Report ID (-110)
0x09, 0x32, // Usage (0x32)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x93, // Report ID (-109)
0x09, 0x33, // Usage (0x33)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x94, // Report ID (-108)
0x09, 0x34, // Usage (0x34)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA0, // Report ID (-96)
0x09, 0x40, // Usage (0x40)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA4, // Report ID (-92)
0x09, 0x44, // Usage (0x44)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA7, // Report ID (-89)
0x09, 0x45, // Usage (0x45)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA8, // Report ID (-88)
0x09, 0x45, // Usage (0x45)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA9, // Report ID (-87)
0x09, 0x45, // Usage (0x45)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xAA, // Report ID (-86)
0x09, 0x45, // Usage (0x45)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xAB, // Report ID (-85)
0x09, 0x45, // Usage (0x45)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xAC, // Report ID (-84)
0x09, 0x45, // Usage (0x45)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xAD, // Report ID (-83)
0x09, 0x45, // Usage (0x45)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xB3, // Report ID (-77)
0x09, 0x45, // Usage (0x45)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xB4, // Report ID (-76)
0x09, 0x46, // Usage (0x46)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xB5, // Report ID (-75)
0x09, 0x47, // Usage (0x47)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xD0, // Report ID (-48)
0x09, 0x40, // Usage (0x40)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xD4, // Report ID (-44)
0x09, 0x44, // Usage (0x44)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
};
// FIXME: Hatswitch is not yet addressable by test
const size_t Dualshock4ButtonCount = 14;
const size_t Dualshock4AxisCount = 6;
const size_t Dualshock4ReportSize = 10;
const char* Dualshock4Name = "Virtual Dualshock4";
// Report layout:
// |ReportID| |Axis1| |Axis2| |Axis3| |Axis4| |b1-b4 high, HS low| |b5-b12| |b13-b14| |Axis5| |Axis6|
static void publishReportCallback(Vector<float>& buttonValues, Vector<float>& axisValues, HIDUserDevice *userDevice)
{
uint8_t reportData[Dualshock4ReportSize];
size_t reportIndex = 0;
// Report ID
reportData[reportIndex++] = 0x01;
// First 4 axes (1 byte each)
for (size_t i = 0; i < 4; ++i)
reportData[reportIndex++] = (uint8_t)(axisValues[i] * 255);
// The hatswitch, 14 buttons, and 6 bits of padding take up 3 bytes
// The bit layout is as follows:
// |b4|b3|b2|b1|hs|hs|hs|hs| |bc|bb|ba|b9|b8|b7|b6|b5| |0|0|0|0|0|0|be|bd|
// For now, always leave the hatswitch in the neutral position of "8"
uint8_t buttonByte = 0x08;
long buttonBit;
for (size_t i = 0; i < 4; ++i) {
buttonBit = lround(buttonValues[i]);
buttonByte |= buttonBit << (4 + i);
}
reportData[reportIndex++] = buttonByte;
buttonByte = 0x00;
for (size_t i = 4; i < 12; ++i) {
buttonBit = lround(buttonValues[i]);
buttonByte |= buttonBit << (i - 4);
}
reportData[reportIndex++] = buttonByte;
buttonByte = 0x00;
for (size_t i = 12; i < 13; ++i) {
buttonBit = lround(buttonValues[i]);
buttonByte |= buttonBit << (i - 12);
}
reportData[reportIndex++] = buttonByte;
// Final 2 axes (1 byte each)
for (size_t i = 4; i < 5; ++i)
reportData[reportIndex++] = (uint8_t)(axisValues[i] * 255);
auto nsReportData = adoptNS([[NSData alloc] initWithBytes:reportData length:Dualshock4ReportSize]);
[userDevice handleReport:nsReportData.get() error:nil];
}
GamepadMapping VirtualGamepad::sonyDualshock4Mapping()
{
return {
Dualshock4Descriptor,
sizeof(Dualshock4Descriptor),
Dualshock4Name,
HIDVendorID::Sony,
HIDProductID::Dualshock4_1,
Dualshock4ButtonCount,
Dualshock4AxisCount,
publishReportCallback
};
}
} // namespace TestWebKitAPI
#endif // USE(APPLE_INTERNAL_SDK)