USB: Gametrak/RealPlay

This commit is contained in:
Florin9doi 2020-12-20 11:39:58 +02:00 committed by refractionpcsx2
parent 97727cae2c
commit c36666b4d4
10 changed files with 805 additions and 6 deletions

View File

@ -36,6 +36,10 @@ void RegisterDevice::Register()
inst.Add(DEVTYPE_HIDMOUSE, new DeviceProxy<usb_hid::HIDMouseDevice>()); inst.Add(DEVTYPE_HIDMOUSE, new DeviceProxy<usb_hid::HIDMouseDevice>());
inst.Add(DEVTYPE_RBKIT, new DeviceProxy<usb_pad::RBDrumKitDevice>()); inst.Add(DEVTYPE_RBKIT, new DeviceProxy<usb_pad::RBDrumKitDevice>());
inst.Add(DEVTYPE_BUZZ, new DeviceProxy<usb_pad::BuzzDevice>()); inst.Add(DEVTYPE_BUZZ, new DeviceProxy<usb_pad::BuzzDevice>());
#ifdef _WIN32
inst.Add(DEVTYPE_GAMETRAK, new DeviceProxy<usb_pad::GametrakDevice>());
inst.Add(DEVTYPE_REALPLAY, new DeviceProxy<usb_pad::RealPlayDevice>());
#endif
inst.Add(DEVTYPE_EYETOY, new DeviceProxy<usb_eyetoy::EyeToyWebCamDevice>()); inst.Add(DEVTYPE_EYETOY, new DeviceProxy<usb_eyetoy::EyeToyWebCamDevice>());
inst.Add(DEVTYPE_BEATMANIA_DADADA, new DeviceProxy<usb_hid::BeatManiaDevice>()); inst.Add(DEVTYPE_BEATMANIA_DADADA, new DeviceProxy<usb_hid::BeatManiaDevice>());
inst.Add(DEVTYPE_SEGA_SEAMIC, new DeviceProxy<usb_pad::SeamicDevice>()); inst.Add(DEVTYPE_SEGA_SEAMIC, new DeviceProxy<usb_pad::SeamicDevice>());

View File

@ -44,6 +44,8 @@ enum DeviceType
DEVTYPE_HIDMOUSE, DEVTYPE_HIDMOUSE,
DEVTYPE_RBKIT, DEVTYPE_RBKIT,
DEVTYPE_BUZZ, DEVTYPE_BUZZ,
DEVTYPE_GAMETRAK,
DEVTYPE_REALPLAY,
DEVTYPE_EYETOY, DEVTYPE_EYETOY,
DEVTYPE_BEATMANIA_DADADA, DEVTYPE_BEATMANIA_DADADA,
DEVTYPE_SEGA_SEAMIC, DEVTYPE_SEGA_SEAMIC,

View File

@ -1468,6 +1468,14 @@ namespace usb_pad
{ {
return DialogBoxParam(h.hInst, MAKEINTRESOURCE(IDD_DLG_KEYBOARDMANIA), h.hWnd, DxDialogProc, (LPARAM)&s); return DialogBoxParam(h.hInst, MAKEINTRESOURCE(IDD_DLG_KEYBOARDMANIA), h.hWnd, DxDialogProc, (LPARAM)&s);
} }
if (strcmp(dev_type, GametrakDevice::TypeName()) == 0)
{
return DialogBoxParam(h.hInst, MAKEINTRESOURCE(IDD_DLG_GAMETRAK), h.hWnd, DxDialogProc, (LPARAM)&s);
}
if (strcmp(dev_type, RealPlayDevice::TypeName()) == 0)
{
return DialogBoxParam(h.hInst, MAKEINTRESOURCE(IDD_DLG_REALPLAY), h.hWnd, DxDialogProc, (LPARAM)&s);
}
return DialogBoxParam(h.hInst, MAKEINTRESOURCE(IDD_DIALOG1), h.hWnd, DxDialogProc, (LPARAM)&s); return DialogBoxParam(h.hInst, MAKEINTRESOURCE(IDD_DIALOG1), h.hWnd, DxDialogProc, (LPARAM)&s);
} }

View File

@ -1002,6 +1002,24 @@ namespace usb_pad
return ReadAxisFiltered(port, id); return ReadAxisFiltered(port, id);
} }
int32_t GetAxisControlUnfiltered(int port, ControlID id)
{
InputMapped im;
if (!GetInputMap(port, id, im))
return 0;
assert(im.index < g_pJoysticks.size());
if (im.index >= g_pJoysticks.size())
return 0;
LONG value = 0;
if (im.type == MT_AXIS)
{
value = g_pJoysticks[im.index]->GetAxis(im.mapped);
}
return value;
}
//set left/right ffb torque //set left/right ffb torque
HRESULT SetConstantForce(int port, LONG magnitude) HRESULT SetConstantForce(int port, LONG magnitude)
{ {

View File

@ -218,6 +218,7 @@ namespace usb_pad
LONG GetAxisValueFromOffset(int axis, const DIJOYSTATE2& j); LONG GetAxisValueFromOffset(int axis, const DIJOYSTATE2& j);
bool GetControl(int port, int id); bool GetControl(int port, int id);
float GetAxisControl(int port, ControlID id); float GetAxisControl(int port, ControlID id);
int32_t GetAxisControlUnfiltered(int port, ControlID id);
void CreateFFB(int port, LPDIRECTINPUTDEVICE8 device, DWORD axis); void CreateFFB(int port, LPDIRECTINPUTDEVICE8 device, DWORD axis);
bool FindFFDevice(int port); bool FindFFDevice(int port);
bool UpdateFFBSettings(int port, LPDIRECTINPUTDEVICE8 device); bool UpdateFFBSettings(int port, LPDIRECTINPUTDEVICE8 device);

View File

@ -57,8 +57,34 @@ namespace usb_pad
pad_copy_data(mType, buf, mWheelData); pad_copy_data(mType, buf, mWheelData);
return 5; return 5;
} }
else if (mType == WT_GAMETRAK_CONTROLLER)
if (mType == WT_KEYBOARDMANIA_CONTROLLER) {
mWheelData.buttons |= GetControl(mPort, CID_HATLEFT) << 4;
mWheelData.clutch = GetAxisControlUnfiltered(mPort, CID_STEERING) >> 4;
mWheelData.throttle = GetAxisControlUnfiltered(mPort, CID_STEERING_R) >> 4;
mWheelData.brake = GetAxisControlUnfiltered(mPort, CID_THROTTLE) >> 4;
mWheelData.hatswitch = GetAxisControlUnfiltered(mPort, CID_BRAKE) >> 4;
mWheelData.hat_horz = GetAxisControlUnfiltered(mPort, CID_HATUP) >> 4;
mWheelData.hat_vert = GetAxisControlUnfiltered(mPort, CID_HATDOWN) >> 4;
pad_copy_data(mType, buf, mWheelData);
return 16;
}
else if (mType >= WT_REALPLAY_RACING && mType <= WT_REALPLAY_POOL)
{
for (int i = 0; i < 8; i++)
{
if (GetControl(mPort, i))
{
mWheelData.buttons |= 1 << i;
}
}
mWheelData.clutch = GetAxisControlUnfiltered(mPort, CID_SQUARE) >> 4;
mWheelData.throttle = GetAxisControlUnfiltered(mPort, CID_TRIANGLE) >> 4;
mWheelData.brake = GetAxisControlUnfiltered(mPort, CID_CROSS) >> 4;
pad_copy_data(mType, buf, mWheelData);
return 19;
}
else if (mType == WT_KEYBOARDMANIA_CONTROLLER)
{ {
for (int i = 0; i < 31; i++) for (int i = 0; i < 31; i++)
{ {

View File

@ -6,6 +6,8 @@
#define IDOK2 2 #define IDOK2 2
#define IDD_DLG_BUZZ 114 #define IDD_DLG_BUZZ 114
#define IDD_DLG_KEYBOARDMANIA 115 #define IDD_DLG_KEYBOARDMANIA 115
#define IDD_DLG_GAMETRAK 116
#define IDD_DLG_REALPLAY 120
#define IDD_DIALOG1 202 #define IDD_DIALOG1 202
#define IDC_DEL0 1001 #define IDC_DEL0 1001
#define IDC_ASS0 1002 #define IDC_ASS0 1002
@ -194,7 +196,7 @@
// //
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 117 #define _APS_NEXT_RESOURCE_VALUE 121
#define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1137 #define _APS_NEXT_CONTROL_VALUE 1137
#define _APS_NEXT_SYMED_VALUE 101 #define _APS_NEXT_SYMED_VALUE 101

View File

@ -327,6 +327,60 @@ BEGIN
PUSHBUTTON "Cancel",IDCANCEL,525,140,50,15 PUSHBUTTON "Cancel",IDCANCEL,525,140,50,15
END END
IDD_DLG_GAMETRAK DIALOGEX 0, 0, 260, 115
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Gametrak"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
PUSHBUTTON "Left X",IDC_ASS0,10,40,50,14
PUSHBUTTON "Left Y",IDC_ASS1,70,40,50,14
PUSHBUTTON "Left Z",IDC_ASS2,40,10,50,14
PUSHBUTTON "Right X",IDC_ASS3,140,40,50,14
PUSHBUTTON "Right Y",IDC_ASS4,200,40,50,14
PUSHBUTTON "Right Z",IDC_ASS5,170,10,50,14
PUSHBUTTON "Foot Mat",IDC_ASS6,105,70,50,14
LTEXT "1/1/1/1",IDC_LABEL0,10,55,55,8
LTEXT "1/1/1/1",IDC_LABEL1,70,55,55,8
LTEXT "1/1/1/1",IDC_LABEL2,40,25,55,8
LTEXT "1/1/1/1",IDC_LABEL3,140,55,55,8
LTEXT "1/1/1/1",IDC_LABEL4,200,55,55,8
LTEXT "1/1/1/1",IDC_LABEL5,170,25,55,8
LTEXT "1/1/1/1",IDC_LABEL6,105,85,55,8
DEFPUSHBUTTON "OK",IDOK,145,95,50,14
PUSHBUTTON "Cancel",IDCANCEL,200,95,50,14
END
IDD_DLG_REALPLAY DIALOGEX 0, 0, 260, 151
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "RealPlay"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
PUSHBUTTON "Up",IDC_ASS0,40,10,50,14
PUSHBUTTON "Down",IDC_ASS1,40,70,50,14
PUSHBUTTON "Left",IDC_ASS2,10,40,50,14
PUSHBUTTON "Right",IDC_ASS3,70,40,50,14
PUSHBUTTON "Red",IDC_ASS4,170,10,50,14
PUSHBUTTON "Green",IDC_ASS5,170,70,50,14
PUSHBUTTON "Yellow",IDC_ASS6,140,40,50,14
PUSHBUTTON "Blue",IDC_ASS7,200,40,50,14
PUSHBUTTON "Accel X",IDC_ASS8,45,100,50,14
PUSHBUTTON "Accel Y",IDC_ASS9,105,100,50,14
PUSHBUTTON "Accel Z",IDC_ASS10,165,100,50,14
LTEXT "1/1/1/1",IDC_LABEL0,40,25,55,8
LTEXT "1/1/1/1",IDC_LABEL1,40,85,55,8
LTEXT "1/1/1/1",IDC_LABEL2,10,55,55,8
LTEXT "1/1/1/1",IDC_LABEL3,70,55,55,8
LTEXT "1/1/1/1",IDC_LABEL4,170,25,55,8
LTEXT "1/1/1/1",IDC_LABEL5,170,85,55,8
LTEXT "1/1/1/1",IDC_LABEL6,140,55,55,8
LTEXT "1/1/1/1",IDC_LABEL7,200,55,55,8
LTEXT "1/1/1/1",IDC_LABEL8,45,115,55,8
LTEXT "1/1/1/1",IDC_LABEL9,105,115,55,8
LTEXT "1/1/1/1",IDC_LABEL10,165,115,55,8
DEFPUSHBUTTON "OK",IDOK,145,130,50,14
PUSHBUTTON "Cancel",IDCANCEL,200,130,50,14
END
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// //
@ -351,6 +405,14 @@ BEGIN
IDD_DLG_KEYBOARDMANIA, DIALOG IDD_DLG_KEYBOARDMANIA, DIALOG
BEGIN BEGIN
END END
IDD_DLG_GAMETRAK, DIALOG
BEGIN
END
IDD_DLG_REALPLAY, DIALOG
BEGIN
END
END END
#endif // APSTUDIO_INVOKED #endif // APSTUDIO_INVOKED
@ -375,6 +437,16 @@ BEGIN
0 0
END END
IDD_DLG_GAMETRAK AFX_DIALOG_LAYOUT
BEGIN
0
END
IDD_DLG_REALPLAY AFX_DIALOG_LAYOUT
BEGIN
0
END
#endif // English (United States) resources #endif // English (United States) resources
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////

View File

@ -59,6 +59,16 @@ namespace usb_pad
"", "",
"KONAMI"}; "KONAMI"};
static const USBDescStrings gametrak_desc_strings = {
"",
"In2Games Ltd.",
"Game-Trak V1.3"};
static const USBDescStrings realplay_desc_strings = {
"",
"In2Games",
"Real Play"};
std::list<std::string> PadDevice::ListAPIs() std::list<std::string> PadDevice::ListAPIs()
{ {
return RegisterPad::instance().Names(); return RegisterPad::instance().Names();
@ -102,6 +112,26 @@ namespace usb_pad
return PadDevice::LongAPIName(name); return PadDevice::LongAPIName(name);
} }
std::list<std::string> GametrakDevice::ListAPIs()
{
return PadDevice::ListAPIs();
}
const TCHAR* GametrakDevice::LongAPIName(const std::string& name)
{
return PadDevice::LongAPIName(name);
}
std::list<std::string> RealPlayDevice::ListAPIs()
{
return PadDevice::ListAPIs();
}
const TCHAR* RealPlayDevice::LongAPIName(const std::string& name)
{
return PadDevice::LongAPIName(name);
}
#ifdef _DEBUG #ifdef _DEBUG
void PrintBits(void* data, int size) void PrintBits(void* data, int size)
{ {
@ -123,6 +153,19 @@ namespace usb_pad
#define DbgPrint(...) #define DbgPrint(...)
#endif //_DEBUG #endif //_DEBUG
uint32_t gametrak_compute_key(uint32_t* key)
{
uint32_t ret = 0;
ret = *key << 2 & 0xFC0000;
ret |= *key << 17 & 0x020000;
ret ^= *key << 16 & 0xFE0000;
ret |= *key & 0x010000;
ret |= *key >> 9 & 0x007F7F;
ret |= *key << 7 & 0x008080;
*key = ret;
return ret >> 16;
};
typedef struct PADState typedef struct PADState
{ {
USBDevice dev; USBDevice dev;
@ -134,6 +177,9 @@ namespace usb_pad
{ {
int dev_subtype; int dev_subtype;
} f; } f;
uint8_t gametrak_state;
uint32_t gametrak_key;
uint8_t realplay_state;
} PADState; } PADState;
typedef struct u_wheel_data_t typedef struct u_wheel_data_t
@ -192,6 +238,38 @@ namespace usb_pad
case USB_TOKEN_IN: case USB_TOKEN_IN:
if (devep == 1 && s->pad) if (devep == 1 && s->pad)
{ {
if (s->pad->Type() == WT_GAMETRAK_CONTROLLER)
{
if (s->gametrak_state == 0)
{
s->gametrak_state = 1;
const unsigned char secret[] = "Gametrak\0\0\0\0\0\0\0\0";
memcpy(data, secret, sizeof(secret));
usb_packet_copy(p, data, 16);
break;
}
else if (s->gametrak_state == 1)
{
s->pad->TokenIn(data, p->iov.size);
data[0x00] |= s->gametrak_key >> 16 & 1;
data[0x02] |= s->gametrak_key >> 17 & 1;
data[0x04] |= s->gametrak_key >> 18 & 1;
data[0x06] |= s->gametrak_key >> 19 & 1;
data[0x08] |= s->gametrak_key >> 20 & 1;
data[0x0A] |= s->gametrak_key >> 21 & 1;
usb_packet_copy(p, data, 16);
break;
}
}
else if (s->pad->Type() >= WT_REALPLAY_RACING && s->pad->Type() <= WT_REALPLAY_POOL)
{
s->pad->TokenIn(data, p->iov.size);
// simulate a slight move to avoid a game "protection" : controller disconnected
s->realplay_state = !s->realplay_state;
data[0] |= s->realplay_state;
usb_packet_copy(p, data, 19);
break;
}
ret = s->pad->TokenIn(data, p->iov.size); ret = s->pad->TokenIn(data, p->iov.size);
if (ret > 0) if (ret > 0)
usb_packet_copy(p, data, MIN(ret, (int)sizeof(data))); usb_packet_copy(p, data, MIN(ret, (int)sizeof(data)));
@ -260,11 +338,26 @@ namespace usb_pad
ret = sizeof(kbm_hid_report_descriptor); ret = sizeof(kbm_hid_report_descriptor);
memcpy(data, kbm_hid_report_descriptor, ret); memcpy(data, kbm_hid_report_descriptor, ret);
} }
else else if (t == WT_GENERIC)
{ {
ret = sizeof(pad_driving_force_hid_separate_report_descriptor); ret = sizeof(pad_driving_force_hid_separate_report_descriptor);
memcpy(data, pad_driving_force_hid_separate_report_descriptor, ret); memcpy(data, pad_driving_force_hid_separate_report_descriptor, ret);
} }
else if (t == WT_BUZZ_CONTROLLER)
{
ret = sizeof(buzz_hid_report_descriptor);
memcpy(data, buzz_hid_report_descriptor, ret);
}
else if (t == WT_GAMETRAK_CONTROLLER)
{
ret = sizeof(gametrak_hid_report_descriptor);
memcpy(data, gametrak_hid_report_descriptor, ret);
}
else if (t >= WT_REALPLAY_RACING && t <= WT_REALPLAY_POOL)
{
ret = sizeof(realplay_hid_report_descriptor);
memcpy(data, realplay_hid_report_descriptor, ret);
}
p->actual_length = ret; p->actual_length = ret;
break; break;
default: default:
@ -273,6 +366,30 @@ namespace usb_pad
break; break;
/* hid specific requests */ /* hid specific requests */
case SET_REPORT: case SET_REPORT:
if (t == WT_GAMETRAK_CONTROLLER)
{
const char secret[] = "Gametrak";
if (length == 8 && memcmp(data, secret, 8) == 0)
{
s->gametrak_state = 0;
s->gametrak_key = 0;
}
else if (length == 2)
{
if (data[0] == 0x45)
{
s->gametrak_key = data[1] << 16;
}
if ((s->gametrak_key >> 16) == data[1])
{
gametrak_compute_key(&s->gametrak_key);
}
else
{
fprintf(stderr, "gametrak error : own key = %02x, recv key = %02x\n", s->gametrak_key >> 16, data[1]);
}
}
}
// no idea, Rock Band 2 keeps spamming this // no idea, Rock Band 2 keeps spamming this
if (length > 0) if (length > 0)
{ {
@ -419,6 +536,38 @@ namespace usb_pad
buf[3] = (data.buttons >> 8) & 0xff; buf[3] = (data.buttons >> 8) & 0xff;
buf[4] = 0xf0 | ((data.buttons >> 16) & 0xf); buf[4] = 0xf0 | ((data.buttons >> 16) & 0xf);
break; break;
case WT_GAMETRAK_CONTROLLER:
memset(buf, 0, 16);
buf[0] = data.clutch & 0xfe;
buf[1] = data.clutch >> 8;
buf[2] = data.throttle & 0xfe;
buf[3] = data.throttle >> 8;
buf[4] = data.brake & 0xfe;
buf[5] = data.brake >> 8;
buf[6] = data.hatswitch & 0xfe;
buf[7] = data.hatswitch >> 8;
buf[8] = data.hat_horz & 0xfe;
buf[9] = data.hat_horz >> 8;
buf[10] = data.hat_vert & 0xfe;
buf[11] = data.hat_vert >> 8;
buf[12] = data.buttons;
break;
case WT_REALPLAY_RACING:
case WT_REALPLAY_SPHERE:
case WT_REALPLAY_GOLF:
case WT_REALPLAY_POOL:
memset(buf, 0, 19);
buf[0] = data.clutch & 0xfe;
buf[1] = data.clutch >> 8;
buf[2] = data.throttle & 0xff;
buf[3] = data.throttle >> 8;
buf[4] = data.brake & 0xff;
buf[5] = data.brake >> 8;
buf[14] = data.buttons;
break;
case WT_SEGA_SEAMIC: case WT_SEGA_SEAMIC:
buf[0] = data.steering & 0xFF; buf[0] = data.steering & 0xFF;
buf[1] = data.throttle & 0xFF; buf[1] = data.throttle & 0xFF;
@ -745,13 +894,13 @@ namespace usb_pad
if (!proxy) if (!proxy)
{ {
Console.WriteLn("Buzz: Invalid input API.\n"); Console.WriteLn("Buzz: Invalid input API.\n");
return NULL; return nullptr;
} }
Pad* pad = proxy->CreateObject(port, TypeName()); Pad* pad = proxy->CreateObject(port, TypeName());
if (!pad) if (!pad)
return NULL; return nullptr;
pad->Type(WT_BUZZ_CONTROLLER); pad->Type(WT_BUZZ_CONTROLLER);
PADState* s = new PADState(); PADState* s = new PADState();
@ -843,4 +992,156 @@ namespace usb_pad
return PadDevice::Freeze(mode, dev, data); return PadDevice::Freeze(mode, dev, data);
} }
// ---- Gametrak ----
USBDevice* GametrakDevice::CreateDevice(int port)
{
std::string varApi;
#ifdef _WIN32
std::wstring tmp;
LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, tmp);
varApi = wstr_to_str(tmp);
#else
LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, varApi);
#endif
PadProxyBase* proxy = RegisterPad::instance().Proxy(varApi);
if (!proxy)
{
Console.WriteLn("Gametrak: Invalid input API.");
return nullptr;
}
Pad* pad = proxy->CreateObject(port, TypeName());
if (!pad)
return nullptr;
pad->Type(WT_GAMETRAK_CONTROLLER);
PADState* s = new PADState();
s->desc.full = &s->desc_dev;
s->desc.str = gametrak_desc_strings;
if (usb_desc_parse_dev(gametrak_dev_descriptor, sizeof(gametrak_dev_descriptor), s->desc, s->desc_dev) < 0)
goto fail;
if (usb_desc_parse_config(gametrak_config_descriptor, sizeof(gametrak_config_descriptor), s->desc_dev) < 0)
goto fail;
s->f.dev_subtype = pad->Type();
s->pad = pad;
s->port = port;
s->dev.speed = USB_SPEED_FULL;
s->dev.klass.handle_attach = usb_desc_attach;
s->dev.klass.handle_reset = pad_handle_reset;
s->dev.klass.handle_control = pad_handle_control;
s->dev.klass.handle_data = pad_handle_data;
s->dev.klass.unrealize = pad_handle_destroy;
s->dev.klass.open = pad_open;
s->dev.klass.close = pad_close;
s->dev.klass.usb_desc = &s->desc;
s->dev.klass.product_desc = s->desc.str[2];
usb_desc_init(&s->dev);
usb_ep_init(&s->dev);
pad_handle_reset((USBDevice*)s);
return (USBDevice*)s;
fail:
pad_handle_destroy((USBDevice*)s);
return nullptr;
}
int GametrakDevice::Configure(int port, const std::string& api, void* data)
{
auto proxy = RegisterPad::instance().Proxy(api);
if (proxy)
return proxy->Configure(port, TypeName(), data);
return RESULT_CANCELED;
}
int GametrakDevice::Freeze(FreezeAction mode, USBDevice* dev, void* data)
{
return PadDevice::Freeze(mode, dev, data);
}
// ---- RealPlay ----
USBDevice* RealPlayDevice::CreateDevice(int port)
{
std::string varApi;
#ifdef _WIN32
std::wstring tmp;
LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, tmp);
varApi = wstr_to_str(tmp);
#else
LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, varApi);
#endif
PadProxyBase* proxy = RegisterPad::instance().Proxy(varApi);
if (!proxy)
{
Console.WriteLn("RealPlay: Invalid input API");
return nullptr;
}
Pad* pad = proxy->CreateObject(port, TypeName());
if (!pad)
return nullptr;
pad->Type((PS2WheelTypes)(WT_REALPLAY_RACING + GetSelectedSubtype(std::make_pair(port, TypeName()))));
PADState* s = new PADState();
s->desc.full = &s->desc_dev;
s->desc.str = realplay_desc_strings;
if (pad->Type() == WT_REALPLAY_RACING && usb_desc_parse_dev(realplay_racing_dev_descriptor, sizeof(realplay_racing_dev_descriptor), s->desc, s->desc_dev) < 0)
goto fail;
if (pad->Type() == WT_REALPLAY_SPHERE && usb_desc_parse_dev(realplay_sphere_dev_descriptor, sizeof(realplay_sphere_dev_descriptor), s->desc, s->desc_dev) < 0)
goto fail;
if (pad->Type() == WT_REALPLAY_GOLF && usb_desc_parse_dev(realplay_golf_dev_descriptor, sizeof(realplay_golf_dev_descriptor), s->desc, s->desc_dev) < 0)
goto fail;
if (pad->Type() == WT_REALPLAY_POOL && usb_desc_parse_dev(realplay_pool_dev_descriptor, sizeof(realplay_pool_dev_descriptor), s->desc, s->desc_dev) < 0)
goto fail;
if (usb_desc_parse_config(realplay_config_descriptor, sizeof(realplay_config_descriptor), s->desc_dev) < 0)
goto fail;
s->f.dev_subtype = pad->Type();
s->pad = pad;
s->port = port;
s->dev.speed = USB_SPEED_FULL;
s->dev.klass.handle_attach = usb_desc_attach;
s->dev.klass.handle_reset = pad_handle_reset;
s->dev.klass.handle_control = pad_handle_control;
s->dev.klass.handle_data = pad_handle_data;
s->dev.klass.unrealize = pad_handle_destroy;
s->dev.klass.open = pad_open;
s->dev.klass.close = pad_close;
s->dev.klass.usb_desc = &s->desc;
s->dev.klass.product_desc = s->desc.str[1];
usb_desc_init(&s->dev);
usb_ep_init(&s->dev);
pad_handle_reset((USBDevice*)s);
return (USBDevice*)s;
fail:
pad_handle_destroy((USBDevice*)s);
return nullptr;
}
int RealPlayDevice::Configure(int port, const std::string& api, void* data)
{
auto proxy = RegisterPad::instance().Proxy(api);
if (proxy)
return proxy->Configure(port, TypeName(), data);
return RESULT_CANCELED;
}
int RealPlayDevice::Freeze(FreezeAction mode, USBDevice* dev, void* data)
{
return PadDevice::Freeze(mode, dev, data);
}
} // namespace usb_pad } // namespace usb_pad

View File

@ -111,6 +111,54 @@ namespace usb_pad
} }
}; };
class GametrakDevice
{
public:
virtual ~GametrakDevice() {}
static USBDevice* CreateDevice(int port);
static const TCHAR* Name()
{
return TEXT("Gametrak Device");
}
static const char* TypeName()
{
return "gametrak_device";
}
static std::list<std::string> ListAPIs();
static const TCHAR* LongAPIName(const std::string& name);
static int Configure(int port, const std::string& api, void* data);
static int Freeze(FreezeAction mode, USBDevice* dev, void* data);
static std::vector<std::string> SubTypes()
{
return std::vector<std::string>();
}
static void Initialize();
};
class RealPlayDevice
{
public:
virtual ~RealPlayDevice() {}
static USBDevice* CreateDevice(int port);
static const TCHAR* Name()
{
return TEXT("RealPlay Device");
}
static const char* TypeName()
{
return "realplay_device";
}
static std::list<std::string> ListAPIs();
static const TCHAR* LongAPIName(const std::string& name);
static int Configure(int port, const std::string& api, void* data);
static int Freeze(FreezeAction mode, USBDevice* dev, void* data);
static std::vector<std::string> SubTypes()
{
return {"RealPlay Racing", "RealPlay Sphere", "RealPlay Golf", "RealPlay Pool"};
}
static void Initialize();
};
class SeamicDevice class SeamicDevice
{ {
public: public:
@ -205,6 +253,11 @@ namespace usb_pad
WT_GT_FORCE, //formula gp WT_GT_FORCE, //formula gp
WT_ROCKBAND1_DRUMKIT, WT_ROCKBAND1_DRUMKIT,
WT_BUZZ_CONTROLLER, WT_BUZZ_CONTROLLER,
WT_GAMETRAK_CONTROLLER,
WT_REALPLAY_RACING,
WT_REALPLAY_SPHERE,
WT_REALPLAY_GOLF,
WT_REALPLAY_POOL,
WT_SEGA_SEAMIC, WT_SEGA_SEAMIC,
WT_KEYBOARDMANIA_CONTROLLER, WT_KEYBOARDMANIA_CONTROLLER,
}; };
@ -1455,6 +1508,318 @@ namespace usb_pad
0xc0 // END_COLLECTION 0xc0 // END_COLLECTION
}; };
//////////////
// GameTrak //
//////////////
// Product ID :
// 0x0982 - PlayStation 2
// 0x0984 - ???
static uint8_t gametrak_dev_descriptor[] = {
0x12, // bLength
0x01, // bDescriptorType (Device)
0x10, 0x01, // bcdUSB 1.10
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x08, // bMaxPacketSize0 8
0xB7, 0x14, // idVendor 0x14B7
0x82, 0x09, // idProduct 0x0982
0x01, 0x00, // bcdDevice 0.01
0x01, // iManufacturer (String Index)
0x02, // iProduct (String Index)
0x00, // iSerialNumber (String Index)
0x01, // bNumConfigurations 1
};
static const uint8_t gametrak_config_descriptor[] = {
0x09, // bLength
0x02, // bDescriptorType (Configuration)
0x22, 0x00, // wTotalLength 34
0x01, // bNumInterfaces 1
0x01, // bConfigurationValue
0x00, // iConfiguration (String Index)
0x80, // bmAttributes
0x0A, // bMaxPower 20mA
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x00, // bInterfaceNumber 0
0x00, // bAlternateSetting
0x01, // bNumEndpoints 1
0x03, // bInterfaceClass
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x09, // bLength
0x21, // bDescriptorType (HID)
0x01, 0x01, // bcdHID 1.01
0x00, // bCountryCode
0x01, // bNumDescriptors
0x22, // bDescriptorType[0] (HID)
0x7A, 0x00, // wDescriptorLength[0] 122
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x81, // bEndpointAddress (IN/D2H)
0x03, // bmAttributes (Interrupt)
0x10, 0x00, // wMaxPacketSize 16
0x0A, // bInterval 10 (unit depends on device speed)
};
static const uint8_t gametrak_hid_report_descriptor[] = {
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x04, // Usage (Joystick)
0xA1, 0x01, // Collection (Application)
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection (Physical)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x32, // Usage (Z)
0x09, 0x33, // Usage (Rx)
0x09, 0x34, // Usage (Ry)
0x09, 0x35, // Usage (Rz)
0x16, 0x00, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x0F, // Logical Maximum (4095)
0x36, 0x00, 0x00, // Physical Minimum (0)
0x46, 0xFF, 0x0F, // Physical Maximum (4095)
0x66, 0x00, 0x00, // Unit (None)
0x75, 0x10, // Report Size (16)
0x95, 0x06, // Report Count (6)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0x09, 0x39, // Usage (Hat switch)
0x15, 0x01, // Logical Minimum (1)
0x25, 0x08, // Logical Maximum (8)
0x35, 0x00, // Physical Minimum (0)
0x46, 0x3B, 0x01, // Physical Maximum (315)
0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x0C, // Usage Maximum (0x0C)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x0C, // Report Count (12)
0x55, 0x00, // Unit Exponent (0)
0x65, 0x00, // Unit (None)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x08, // Report Size (8)
0x95, 0x02, // Report Count (2)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x08, // Usage Page (LEDs)
0x09, 0x43, // Usage (Slow Blink On Time)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x35, 0x00, // Physical Minimum (0)
0x46, 0xFF, 0x00, // Physical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x91, 0x82, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile)
0x09, 0x44, // Usage (Slow Blink Off Time)
0x91, 0x82, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile)
0x09, 0x45, // Usage (Fast Blink On Time)
0x91, 0x82, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile)
0x09, 0x46, // Usage (Fast Blink Off Time)
0x91, 0x82, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile)
0xC0, // End Collection
};
//////////////
// RealPlay //
//////////////
// Product ID :
// Racing - 0x09B2
// Sphere - 0x09B3
// Golf - 0x09B5
// Pool - 0x09B6
// RealPlay Golf is dumped from a real controller.
// The others were force-brutted to be accepted by games - they may be inaccurate.
static const uint8_t realplay_racing_dev_descriptor[] = {
0x12, // bLength
0x01, // bDescriptorType (Device)
0x00, 0x02, // bcdUSB 2.00
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x40, // bMaxPacketSize0 64
0xB7, 0x14, // idVendor 0x14B7
0xB2, 0x09, // idProduct 0x09B2
0x00, 0x01, // bcdDevice 2.00
0x01, // iManufacturer (String Index)
0x02, // iProduct (String Index)
0x00, // iSerialNumber (String Index)
0x01, // bNumConfigurations 1
};
static const uint8_t realplay_sphere_dev_descriptor[] = {
0x12, // bLength
0x01, // bDescriptorType (Device)
0x00, 0x02, // bcdUSB 2.00
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x40, // bMaxPacketSize0 64
0xB7, 0x14, // idVendor 0x14B7
0xB3, 0x09, // idProduct 0x09B3
0x00, 0x01, // bcdDevice 2.00
0x01, // iManufacturer (String Index)
0x02, // iProduct (String Index)
0x00, // iSerialNumber (String Index)
0x01, // bNumConfigurations 1
};
static const uint8_t realplay_golf_dev_descriptor[] = {
0x12, // bLength
0x01, // bDescriptorType (Device)
0x00, 0x02, // bcdUSB 2.00
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x40, // bMaxPacketSize0 64
0xB7, 0x14, // idVendor 0x14B7
0xB5, 0x09, // idProduct 0x09B5
0x00, 0x01, // bcdDevice 2.00
0x01, // iManufacturer (String Index)
0x02, // iProduct (String Index)
0x00, // iSerialNumber (String Index)
0x01, // bNumConfigurations 1
};
static const uint8_t realplay_pool_dev_descriptor[] = {
0x12, // bLength
0x01, // bDescriptorType (Device)
0x00, 0x02, // bcdUSB 2.00
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x40, // bMaxPacketSize0 64
0xB7, 0x14, // idVendor 0x14B7
0xB6, 0x09, // idProduct 0x09B6
0x00, 0x01, // bcdDevice 2.00
0x01, // iManufacturer (String Index)
0x02, // iProduct (String Index)
0x00, // iSerialNumber (String Index)
0x01, // bNumConfigurations 1
};
static const uint8_t realplay_config_descriptor[] = {
0x09, // bLength
0x02, // bDescriptorType (Configuration)
0x29, 0x00, // wTotalLength 41
0x01, // bNumInterfaces 1
0x01, // bConfigurationValue
0x00, // iConfiguration (String Index)
0x80, // bmAttributes
0x32, // bMaxPower 100mA
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x00, // bInterfaceNumber 0
0x00, // bAlternateSetting
0x02, // bNumEndpoints 2
0x03, // bInterfaceClass
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x09, // bLength
0x21, // bDescriptorType (HID)
0x11, 0x01, // bcdHID 1.11
0x00, // bCountryCode
0x01, // bNumDescriptors
0x22, // bDescriptorType[0] (HID)
0x85, 0x00, // wDescriptorLength[0] 133
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x02, // bEndpointAddress (OUT/H2D)
0x03, // bmAttributes (Interrupt)
0x40, 0x00, // wMaxPacketSize 64
0x0A, // bInterval 10 (unit depends on device speed)
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x81, // bEndpointAddress (IN/D2H)
0x03, // bmAttributes (Interrupt)
0x40, 0x00, // wMaxPacketSize 64
0x0A, // bInterval 10 (unit depends on device speed)
};
static const uint8_t realplay_hid_report_descriptor[] = {
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x05, // Usage (Game Pad)
0xA1, 0x01, // Collection (Application)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x0F, // Logical Maximum (4095)
0x35, 0x00, // Physical Minimum (0)
0x46, 0xFF, 0x0F, // Physical Maximum (4095)
0x09, 0x30, // Usage (X)
0x75, 0x0C, // Report Size (12)
0x95, 0x01, // Report Count (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x01, // Report Size (1)
0x95, 0x04, // Report Count (4)
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x31, // Usage (Y)
0x75, 0x0C, // Report Size (12)
0x95, 0x01, // Report Count (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x01, // Report Size (1)
0x95, 0x04, // Report Count (4)
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x32, // Usage (Z)
0x75, 0x0C, // Report Size (12)
0x95, 0x01, // Report Count (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x01, // Report Size (1)
0x95, 0x04, // Report Count (4)
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
0x09, 0x20, // Usage (0x20)
0x09, 0x21, // Usage (0x21)
0x09, 0x22, // Usage (0x22)
0x09, 0x23, // Usage (0x23)
0x09, 0x24, // Usage (0x24)
0x09, 0x25, // Usage (0x25)
0x09, 0x26, // Usage (0x26)
0x09, 0x27, // Usage (0x27)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x46, 0xFF, 0x00, // Physical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x08, // Report Count (8)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x35, 0x00, // Physical Minimum (0)
0x45, 0x01, // Physical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x08, // Usage Maximum (0x08)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
0x09, 0x28, // Usage (0x28)
0x09, 0x29, // Usage (0x29)
0x09, 0x2A, // Usage (0x2A)
0x09, 0x2B, // Usage (0x2B)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x46, 0xFF, 0x00, // Physical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x04, // Report Count (4)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
};
struct dfp_buttons_t struct dfp_buttons_t
{ {
uint16_t cross : 1; uint16_t cross : 1;