blob: ba337f26d7b1018308fedc2d19c958b08dd19a32 [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 SLTGamepadDescriptor[] = {
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x04, // Usage (Joystick)
0xA1, 0x01, // Collection (Application)
0xA1, 0x02, // Collection (Logical)
0x75, 0x08, // Report Size (8)
0x95, 0x05, // Report Count (5)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x35, 0x00, // Physical Minimum (0)
0x46, 0xFF, 0x00, // Physical Maximum (255)
0x09, 0x30, // Usage (X)
0x09, 0x30, // Usage (X)
0x09, 0x30, // Usage (X)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
// (5) 1 byte axes (yes, it replicates the X axis 4 times) - Total 5 bytes.
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x25, 0x07, // Logical Maximum (7)
0x46, 0x3B, 0x01, // Physical Maximum (315)
0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter)
0x09, 0x00, // Usage (Undefined)
// 4 bits, unknown - Total (5) bytes (4) bits
0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
0x65, 0x00, // Unit (None)
0x75, 0x01, // Report Size (1)
0x95, 0x0A, // Report Count (10)
0x25, 0x01, // Logical Maximum (1)
0x45, 0x01, // Physical Maximum (1)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x0A, // Usage Maximum (0x0A)
// (10) 1-bit buttons - Total (6) bytes (6) bits
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
0x75, 0x01, // Report Size (1)
0x95, 0x0A, // Report Count (10)
0x25, 0x01, // Logical Maximum (1)
0x45, 0x01, // Physical Maximum (1)
0x09, 0x01, // Usage (0x01)
// (10) vendor defined bits - Total (8) bytes
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0xA1, 0x02, // Collection (Logical)
0x75, 0x08, // Report Size (8)
0x95, 0x04, // Report Count (4)
0x46, 0xFF, 0x00, // Physical Maximum (255)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x09, 0x02, // Usage (0x02)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
0xC0, // End Collection
};
const size_t SLTGamepadButtonCount = 10;
const size_t SLTGamepadAxisCount = 5;
const size_t SLTGamepadReportSize = 8;
const char* SLTGamepadName = "Virtual Shenzhen Longshengwei Technology Gamepad";
// Report layout:
// |Axis1| |Axis2| |Axis3| |Axis4| |Axis5| |b1-b4| |b5-b10| |0|
static void publishReportCallback(Vector<float>& buttonValues, Vector<float>& axisValues, HIDUserDevice *userDevice)
{
uint8_t reportData[SLTGamepadReportSize];
// First 3 report bytes are constant, no matter what the values of axis 0, 1, or 2 are.
reportData[0] = 0x01;
reportData[1] = 0x7f;
reportData[2] = 0x7f;
for (size_t i = 3; i < SLTGamepadAxisCount; ++i) {
if (axisValues[i] <= -0.5)
reportData[i] = 0x00;
else if (axisValues[i] >= 0.5)
reportData[i] = 0xff;
else
reportData[i] = 0x7f;
}
// The final 3 bytes of the report have the following layout:
// (Note, button 7 and button 8 do not physically exist on the device and tehrefore can never get activated)
// |b4|b3|b2|b1|1|1|1|1| |0|0|b6|b5|0|0|ba|b9| |0|0|0|0|0|0|0|0|
uint8_t buttonByte = 0x0f;
long buttonBit;
for (size_t i = 0; i < 4; ++i) {
buttonBit = lround(buttonValues[i]);
buttonByte |= buttonBit << (4 + i);
}
reportData[5] = buttonByte;
buttonByte = 0;
buttonByte |= lround(buttonValues[4]) << 4;
buttonByte |= lround(buttonValues[5]) << 5;
buttonByte |= lround(buttonValues[8]);
buttonByte |= lround(buttonValues[9]) << 1;
reportData[6] = buttonByte;
reportData[7] = 0x00;
auto nsReportData = adoptNS([[NSData alloc] initWithBytes:reportData length:SLTGamepadReportSize]);
[userDevice handleReport:nsReportData.get() error:nil];
}
GamepadMapping VirtualGamepad::shenzhenLongshengweiTechnologyGamepadMapping()
{
return {
SLTGamepadDescriptor,
sizeof(SLTGamepadDescriptor),
SLTGamepadName,
HIDVendorID::ShenzhenLongshengweiTechnology,
HIDProductID::Gamepad,
SLTGamepadButtonCount,
SLTGamepadAxisCount,
publishReportCallback
};
}
} // namespace TestWebKitAPI
#endif // USE(APPLE_INTERNAL_SDK)