Pad Refactoring

Adds a window to setup multiple input types as once
All controllers are now handled by a single thread
[hcorion] evdev refactor
This commit is contained in:
RipleyTom 2017-08-15 14:03:07 +02:00 committed by Ani
parent a6ba7ed21c
commit 0457f23b13
28 changed files with 1776 additions and 1416 deletions

View File

@ -3,7 +3,7 @@
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/Cell/PPUModule.h" #include "Emu/Cell/PPUModule.h"
#include "Emu/Io/PadHandler.h" #include "pad_thread.h"
#include "cellPad.h" #include "cellPad.h"
extern logs::channel sys_io; extern logs::channel sys_io;
@ -12,7 +12,7 @@ s32 cellPadInit(u32 max_connect)
{ {
sys_io.warning("cellPadInit(max_connect=%d)", max_connect); sys_io.warning("cellPadInit(max_connect=%d)", max_connect);
const auto handler = fxm::import<PadHandlerBase>(Emu.GetCallbacks().get_pad_handler); const auto handler = fxm::import<pad_thread>(Emu.GetCallbacks().get_pad_handler);
if (!handler) if (!handler)
return CELL_PAD_ERROR_ALREADY_INITIALIZED; return CELL_PAD_ERROR_ALREADY_INITIALIZED;
@ -26,7 +26,7 @@ s32 cellPadEnd()
{ {
sys_io.notice("cellPadEnd()"); sys_io.notice("cellPadEnd()");
if (!fxm::remove<PadHandlerBase>()) if (!fxm::remove<pad_thread>())
return CELL_PAD_ERROR_UNINITIALIZED; return CELL_PAD_ERROR_UNINITIALIZED;
return CELL_OK; return CELL_OK;
@ -36,7 +36,7 @@ s32 cellPadClearBuf(u32 port_no)
{ {
sys_io.trace("cellPadClearBuf(port_no=%d)", port_no); sys_io.trace("cellPadClearBuf(port_no=%d)", port_no);
const auto handler = fxm::get<PadHandlerBase>(); const auto handler = fxm::get<pad_thread>();
if (!handler) if (!handler)
return CELL_PAD_ERROR_UNINITIALIZED; return CELL_PAD_ERROR_UNINITIALIZED;
@ -51,20 +51,20 @@ s32 cellPadClearBuf(u32 port_no)
//Set 'm_buffer_cleared' to force a resend of everything //Set 'm_buffer_cleared' to force a resend of everything
//might as well also reset everything in our pad 'buffer' to nothing as well //might as well also reset everything in our pad 'buffer' to nothing as well
std::vector<Pad>& pads = handler->GetPads(); auto& pads = handler->GetPads();
Pad& pad = pads[port_no]; auto pad = pads[port_no];
pad.m_buffer_cleared = true; pad->m_buffer_cleared = true;
pad.m_analog_left_x = pad.m_analog_left_y = pad.m_analog_right_x = pad.m_analog_right_y = 128; pad->m_analog_left_x = pad->m_analog_left_y = pad->m_analog_right_x = pad->m_analog_right_y = 128;
pad.m_digital_1 = pad.m_digital_2 = 0; pad->m_digital_1 = pad->m_digital_2 = 0;
pad.m_press_right = pad.m_press_left = pad.m_press_up = pad.m_press_down = 0; pad->m_press_right = pad->m_press_left = pad->m_press_up = pad->m_press_down = 0;
pad.m_press_triangle = pad.m_press_circle = pad.m_press_cross = pad.m_press_square = 0; pad->m_press_triangle = pad->m_press_circle = pad->m_press_cross = pad->m_press_square = 0;
pad.m_press_L1 = pad.m_press_L2 = pad.m_press_R1 = pad.m_press_R2 = 0; pad->m_press_L1 = pad->m_press_L2 = pad->m_press_R1 = pad->m_press_R2 = 0;
//~399 on sensor y is a level non moving controller //~399 on sensor y is a level non moving controller
pad.m_sensor_y = 399; pad->m_sensor_y = 399;
pad.m_sensor_x = pad.m_sensor_z = pad.m_sensor_g = 512; pad->m_sensor_x = pad->m_sensor_z = pad->m_sensor_g = 512;
return CELL_OK; return CELL_OK;
} }
@ -73,12 +73,12 @@ s32 cellPadGetData(u32 port_no, vm::ptr<CellPadData> data)
{ {
sys_io.trace("cellPadGetData(port_no=%d, data=*0x%x)", port_no, data); sys_io.trace("cellPadGetData(port_no=%d, data=*0x%x)", port_no, data);
const auto handler = fxm::get<PadHandlerBase>(); const auto handler = fxm::get<pad_thread>();
if (!handler) if (!handler)
return CELL_PAD_ERROR_UNINITIALIZED; return CELL_PAD_ERROR_UNINITIALIZED;
std::vector<Pad>& pads = handler->GetPads(); auto& pads = handler->GetPads();
const PadInfo& rinfo = handler->GetInfo(); const PadInfo& rinfo = handler->GetInfo();
@ -89,39 +89,39 @@ s32 cellPadGetData(u32 port_no, vm::ptr<CellPadData> data)
if (port_no >= rinfo.now_connect) if (port_no >= rinfo.now_connect)
return CELL_PAD_ERROR_NO_DEVICE; return CELL_PAD_ERROR_NO_DEVICE;
Pad& pad = pads[port_no]; auto pad = pads[port_no];
u16 d1Initial, d2Initial; u16 d1Initial, d2Initial;
d1Initial = pad.m_digital_1; d1Initial = pad->m_digital_1;
d2Initial = pad.m_digital_2; d2Initial = pad->m_digital_2;
bool btnChanged = false; bool btnChanged = false;
for(Button& button : pad.m_buttons) for(Button& button : pad->m_buttons)
{ {
//here we check btns, and set pad accordingly, //here we check btns, and set pad accordingly,
//if something changed, set btnChanged //if something changed, set btnChanged
if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL1) if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL1)
{ {
if (button.m_pressed) pad.m_digital_1 |= button.m_outKeyCode; if (button.m_pressed) pad->m_digital_1 |= button.m_outKeyCode;
else pad.m_digital_1 &= ~button.m_outKeyCode; else pad->m_digital_1 &= ~button.m_outKeyCode;
switch (button.m_outKeyCode) switch (button.m_outKeyCode)
{ {
case CELL_PAD_CTRL_LEFT: case CELL_PAD_CTRL_LEFT:
if (pad.m_press_left != button.m_value) btnChanged = true; if (pad->m_press_left != button.m_value) btnChanged = true;
pad.m_press_left = button.m_value; pad->m_press_left = button.m_value;
break; break;
case CELL_PAD_CTRL_DOWN: case CELL_PAD_CTRL_DOWN:
if (pad.m_press_down != button.m_value) btnChanged = true; if (pad->m_press_down != button.m_value) btnChanged = true;
pad.m_press_down = button.m_value; pad->m_press_down = button.m_value;
break; break;
case CELL_PAD_CTRL_RIGHT: case CELL_PAD_CTRL_RIGHT:
if (pad.m_press_right != button.m_value) btnChanged = true; if (pad->m_press_right != button.m_value) btnChanged = true;
pad.m_press_right = button.m_value; pad->m_press_right = button.m_value;
break; break;
case CELL_PAD_CTRL_UP: case CELL_PAD_CTRL_UP:
if (pad.m_press_up != button.m_value) btnChanged = true; if (pad->m_press_up != button.m_value) btnChanged = true;
pad.m_press_up = button.m_value; pad->m_press_up = button.m_value;
break; break;
//These arent pressure btns //These arent pressure btns
case CELL_PAD_CTRL_R3: case CELL_PAD_CTRL_R3:
@ -133,42 +133,42 @@ s32 cellPadGetData(u32 port_no, vm::ptr<CellPadData> data)
} }
else if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL2) else if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL2)
{ {
if (button.m_pressed) pad.m_digital_2 |= button.m_outKeyCode; if (button.m_pressed) pad->m_digital_2 |= button.m_outKeyCode;
else pad.m_digital_2 &= ~button.m_outKeyCode; else pad->m_digital_2 &= ~button.m_outKeyCode;
switch (button.m_outKeyCode) switch (button.m_outKeyCode)
{ {
case CELL_PAD_CTRL_SQUARE: case CELL_PAD_CTRL_SQUARE:
if (pad.m_press_square != button.m_value) btnChanged = true; if (pad->m_press_square != button.m_value) btnChanged = true;
pad.m_press_square = button.m_value; pad->m_press_square = button.m_value;
break; break;
case CELL_PAD_CTRL_CROSS: case CELL_PAD_CTRL_CROSS:
if (pad.m_press_cross != button.m_value) btnChanged = true; if (pad->m_press_cross != button.m_value) btnChanged = true;
pad.m_press_cross = button.m_value; pad->m_press_cross = button.m_value;
break; break;
case CELL_PAD_CTRL_CIRCLE: case CELL_PAD_CTRL_CIRCLE:
if (pad.m_press_circle != button.m_value) btnChanged = true; if (pad->m_press_circle != button.m_value) btnChanged = true;
pad.m_press_circle = button.m_value; pad->m_press_circle = button.m_value;
break; break;
case CELL_PAD_CTRL_TRIANGLE: case CELL_PAD_CTRL_TRIANGLE:
if (pad.m_press_triangle != button.m_value) btnChanged = true; if (pad->m_press_triangle != button.m_value) btnChanged = true;
pad.m_press_triangle = button.m_value; pad->m_press_triangle = button.m_value;
break; break;
case CELL_PAD_CTRL_R1: case CELL_PAD_CTRL_R1:
if (pad.m_press_R1 != button.m_value) btnChanged = true; if (pad->m_press_R1 != button.m_value) btnChanged = true;
pad.m_press_R1 = button.m_value; pad->m_press_R1 = button.m_value;
break; break;
case CELL_PAD_CTRL_L1: case CELL_PAD_CTRL_L1:
if (pad.m_press_L1 != button.m_value) btnChanged = true; if (pad->m_press_L1 != button.m_value) btnChanged = true;
pad.m_press_L1 = button.m_value; pad->m_press_L1 = button.m_value;
break; break;
case CELL_PAD_CTRL_R2: case CELL_PAD_CTRL_R2:
if (pad.m_press_R2 != button.m_value) btnChanged = true; if (pad->m_press_R2 != button.m_value) btnChanged = true;
pad.m_press_R2 = button.m_value; pad->m_press_R2 = button.m_value;
break; break;
case CELL_PAD_CTRL_L2: case CELL_PAD_CTRL_L2:
if (pad.m_press_L2 != button.m_value) btnChanged = true; if (pad->m_press_L2 != button.m_value) btnChanged = true;
pad.m_press_L2 = button.m_value; pad->m_press_L2 = button.m_value;
break; break;
default: break; default: break;
} }
@ -182,55 +182,55 @@ s32 cellPadGetData(u32 port_no, vm::ptr<CellPadData> data)
} }
} }
for (const AnalogStick& stick : pad.m_sticks) for (const AnalogStick& stick : pad->m_sticks)
{ {
switch (stick.m_offset) switch (stick.m_offset)
{ {
case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X: case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X:
if (pad.m_analog_left_x != stick.m_value) btnChanged = true; if (pad->m_analog_left_x != stick.m_value) btnChanged = true;
pad.m_analog_left_x = stick.m_value; pad->m_analog_left_x = stick.m_value;
break; break;
case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y: case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y:
if (pad.m_analog_left_y != stick.m_value) btnChanged = true; if (pad->m_analog_left_y != stick.m_value) btnChanged = true;
pad.m_analog_left_y = stick.m_value; pad->m_analog_left_y = stick.m_value;
break; break;
case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X: case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X:
if (pad.m_analog_right_x != stick.m_value) btnChanged = true; if (pad->m_analog_right_x != stick.m_value) btnChanged = true;
pad.m_analog_right_x = stick.m_value; pad->m_analog_right_x = stick.m_value;
break; break;
case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y: case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y:
if (pad.m_analog_right_y != stick.m_value) btnChanged = true; if (pad->m_analog_right_y != stick.m_value) btnChanged = true;
pad.m_analog_right_y = stick.m_value; pad->m_analog_right_y = stick.m_value;
break; break;
default: break; default: break;
} }
} }
for (const AnalogSensor& sensor : pad.m_sensors) for (const AnalogSensor& sensor : pad->m_sensors)
{ {
switch (sensor.m_offset) switch (sensor.m_offset)
{ {
case CELL_PAD_BTN_OFFSET_SENSOR_X: case CELL_PAD_BTN_OFFSET_SENSOR_X:
if (pad.m_sensor_x != sensor.m_value) btnChanged = true; if (pad->m_sensor_x != sensor.m_value) btnChanged = true;
pad.m_sensor_x = sensor.m_value; pad->m_sensor_x = sensor.m_value;
break; break;
case CELL_PAD_BTN_OFFSET_SENSOR_Y: case CELL_PAD_BTN_OFFSET_SENSOR_Y:
if (pad.m_sensor_y != sensor.m_value) btnChanged = true; if (pad->m_sensor_y != sensor.m_value) btnChanged = true;
pad.m_sensor_y = sensor.m_value; pad->m_sensor_y = sensor.m_value;
break; break;
case CELL_PAD_BTN_OFFSET_SENSOR_Z: case CELL_PAD_BTN_OFFSET_SENSOR_Z:
if (pad.m_sensor_z != sensor.m_value) btnChanged = true; if (pad->m_sensor_z != sensor.m_value) btnChanged = true;
pad.m_sensor_z = sensor.m_value; pad->m_sensor_z = sensor.m_value;
break; break;
case CELL_PAD_BTN_OFFSET_SENSOR_G: case CELL_PAD_BTN_OFFSET_SENSOR_G:
if (pad.m_sensor_g != sensor.m_value) btnChanged = true; if (pad->m_sensor_g != sensor.m_value) btnChanged = true;
pad.m_sensor_g = sensor.m_value; pad->m_sensor_g = sensor.m_value;
break; break;
default: break; default: break;
} }
} }
if (d1Initial != pad.m_digital_1 || d2Initial != pad.m_digital_2) if (d1Initial != pad->m_digital_1 || d2Initial != pad->m_digital_2)
{ {
btnChanged = true; btnChanged = true;
} }
@ -238,9 +238,9 @@ s32 cellPadGetData(u32 port_no, vm::ptr<CellPadData> data)
//not sure if this should officially change with capabilities/portsettings :( //not sure if this should officially change with capabilities/portsettings :(
data->len = 24; data->len = 24;
if (pad.m_buffer_cleared) if (pad->m_buffer_cleared)
{ {
pad.m_buffer_cleared = false; pad->m_buffer_cleared = false;
} }
else if (!btnChanged) else if (!btnChanged)
{ {
@ -250,28 +250,28 @@ s32 cellPadGetData(u32 port_no, vm::ptr<CellPadData> data)
// bits 15-8 reserved, 7-4 = 0x7, 3-0: data->len/2; // bits 15-8 reserved, 7-4 = 0x7, 3-0: data->len/2;
data->button[1] = (0x7 << 4) | std::min(data->len / 2, 15); data->button[1] = (0x7 << 4) | std::min(data->len / 2, 15);
//lets still send new data anyway, not sure whats expected still //lets still send new data anyway, not sure whats expected still
data->button[CELL_PAD_BTN_OFFSET_DIGITAL1] = pad.m_digital_1; data->button[CELL_PAD_BTN_OFFSET_DIGITAL1] = pad->m_digital_1;
data->button[CELL_PAD_BTN_OFFSET_DIGITAL2] = pad.m_digital_2; data->button[CELL_PAD_BTN_OFFSET_DIGITAL2] = pad->m_digital_2;
data->button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X] = pad.m_analog_right_x; data->button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X] = pad->m_analog_right_x;
data->button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y] = pad.m_analog_right_y; data->button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y] = pad->m_analog_right_y;
data->button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X] = pad.m_analog_left_x; data->button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X] = pad->m_analog_left_x;
data->button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y] = pad.m_analog_left_y; data->button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y] = pad->m_analog_left_y;
data->button[CELL_PAD_BTN_OFFSET_PRESS_RIGHT] = pad.m_press_right; data->button[CELL_PAD_BTN_OFFSET_PRESS_RIGHT] = pad->m_press_right;
data->button[CELL_PAD_BTN_OFFSET_PRESS_LEFT] = pad.m_press_left; data->button[CELL_PAD_BTN_OFFSET_PRESS_LEFT] = pad->m_press_left;
data->button[CELL_PAD_BTN_OFFSET_PRESS_UP] = pad.m_press_up; data->button[CELL_PAD_BTN_OFFSET_PRESS_UP] = pad->m_press_up;
data->button[CELL_PAD_BTN_OFFSET_PRESS_DOWN] = pad.m_press_down; data->button[CELL_PAD_BTN_OFFSET_PRESS_DOWN] = pad->m_press_down;
data->button[CELL_PAD_BTN_OFFSET_PRESS_TRIANGLE] = pad.m_press_triangle; data->button[CELL_PAD_BTN_OFFSET_PRESS_TRIANGLE] = pad->m_press_triangle;
data->button[CELL_PAD_BTN_OFFSET_PRESS_CIRCLE] = pad.m_press_circle; data->button[CELL_PAD_BTN_OFFSET_PRESS_CIRCLE] = pad->m_press_circle;
data->button[CELL_PAD_BTN_OFFSET_PRESS_CROSS] = pad.m_press_cross; data->button[CELL_PAD_BTN_OFFSET_PRESS_CROSS] = pad->m_press_cross;
data->button[CELL_PAD_BTN_OFFSET_PRESS_SQUARE] = pad.m_press_square; data->button[CELL_PAD_BTN_OFFSET_PRESS_SQUARE] = pad->m_press_square;
data->button[CELL_PAD_BTN_OFFSET_PRESS_L1] = pad.m_press_L1; data->button[CELL_PAD_BTN_OFFSET_PRESS_L1] = pad->m_press_L1;
data->button[CELL_PAD_BTN_OFFSET_PRESS_L2] = pad.m_press_L2; data->button[CELL_PAD_BTN_OFFSET_PRESS_L2] = pad->m_press_L2;
data->button[CELL_PAD_BTN_OFFSET_PRESS_R1] = pad.m_press_R1; data->button[CELL_PAD_BTN_OFFSET_PRESS_R1] = pad->m_press_R1;
data->button[CELL_PAD_BTN_OFFSET_PRESS_R2] = pad.m_press_R2; data->button[CELL_PAD_BTN_OFFSET_PRESS_R2] = pad->m_press_R2;
data->button[CELL_PAD_BTN_OFFSET_SENSOR_X] = pad.m_sensor_x; data->button[CELL_PAD_BTN_OFFSET_SENSOR_X] = pad->m_sensor_x;
data->button[CELL_PAD_BTN_OFFSET_SENSOR_Y] = pad.m_sensor_y; data->button[CELL_PAD_BTN_OFFSET_SENSOR_Y] = pad->m_sensor_y;
data->button[CELL_PAD_BTN_OFFSET_SENSOR_Z] = pad.m_sensor_z; data->button[CELL_PAD_BTN_OFFSET_SENSOR_Z] = pad->m_sensor_z;
data->button[CELL_PAD_BTN_OFFSET_SENSOR_G] = pad.m_sensor_g; data->button[CELL_PAD_BTN_OFFSET_SENSOR_G] = pad->m_sensor_g;
return CELL_OK; return CELL_OK;
} }
@ -280,7 +280,7 @@ s32 cellPadPeriphGetInfo(vm::ptr<CellPadPeriphInfo> info)
{ {
sys_io.trace("cellPadPeriphGetInfo(info=*0x%x)", info); sys_io.trace("cellPadPeriphGetInfo(info=*0x%x)", info);
const auto handler = fxm::get<PadHandlerBase>(); const auto handler = fxm::get<pad_thread>();
if (!handler) if (!handler)
return CELL_PAD_ERROR_UNINITIALIZED; return CELL_PAD_ERROR_UNINITIALIZED;
@ -293,7 +293,7 @@ s32 cellPadPeriphGetInfo(vm::ptr<CellPadPeriphInfo> info)
info->now_connect = rinfo.now_connect; info->now_connect = rinfo.now_connect;
info->system_info = rinfo.system_info; info->system_info = rinfo.system_info;
std::vector<Pad>& pads = handler->GetPads(); auto& pads = handler->GetPads();
// TODO: Support other types of controllers // TODO: Support other types of controllers
for (u32 i = 0; i < CELL_PAD_MAX_PORT_NUM; ++i) for (u32 i = 0; i < CELL_PAD_MAX_PORT_NUM; ++i)
@ -301,10 +301,10 @@ s32 cellPadPeriphGetInfo(vm::ptr<CellPadPeriphInfo> info)
if (i >= pads.size()) if (i >= pads.size())
break; break;
info->port_status[i] = pads[i].m_port_status; info->port_status[i] = pads[i]->m_port_status;
info->port_setting[i] = pads[i].m_port_setting; info->port_setting[i] = pads[i]->m_port_setting;
info->device_capability[i] = pads[i].m_device_capability; info->device_capability[i] = pads[i]->m_device_capability;
info->device_type[i] = pads[i].m_device_type; info->device_type[i] = pads[i]->m_device_type;
info->pclass_type[i] = CELL_PAD_PCLASS_TYPE_STANDARD; info->pclass_type[i] = CELL_PAD_PCLASS_TYPE_STANDARD;
info->pclass_profile[i] = 0x0; info->pclass_profile[i] = 0x0;
} }
@ -315,7 +315,7 @@ s32 cellPadPeriphGetInfo(vm::ptr<CellPadPeriphInfo> info)
s32 cellPadPeriphGetData(u32 port_no, vm::ptr<CellPadPeriphData> data) s32 cellPadPeriphGetData(u32 port_no, vm::ptr<CellPadPeriphData> data)
{ {
sys_io.trace("cellPadPeriphGetData(port_no=%d, data=*0x%x)", port_no, data); sys_io.trace("cellPadPeriphGetData(port_no=%d, data=*0x%x)", port_no, data);
const auto handler = fxm::get<PadHandlerBase>(); const auto handler = fxm::get<pad_thread>();
if (!handler) if (!handler)
return CELL_PAD_ERROR_UNINITIALIZED; return CELL_PAD_ERROR_UNINITIALIZED;
@ -342,7 +342,7 @@ s32 cellPadGetDataExtra(u32 port_no, vm::ptr<u32> device_type, vm::ptr<CellPadDa
{ {
sys_io.trace("cellPadGetDataExtra(port_no=%d, device_type=*0x%x, device_type=*0x%x)", port_no, device_type, data); sys_io.trace("cellPadGetDataExtra(port_no=%d, device_type=*0x%x, device_type=*0x%x)", port_no, device_type, data);
const auto handler = fxm::get<PadHandlerBase>(); const auto handler = fxm::get<pad_thread>();
if (!handler) if (!handler)
return CELL_PAD_ERROR_UNINITIALIZED; return CELL_PAD_ERROR_UNINITIALIZED;
@ -370,7 +370,7 @@ s32 cellPadSetActDirect(u32 port_no, vm::ptr<CellPadActParam> param)
{ {
sys_io.trace("cellPadSetActDirect(port_no=%d, param=*0x%x)", port_no, param); sys_io.trace("cellPadSetActDirect(port_no=%d, param=*0x%x)", port_no, param);
const auto handler = fxm::get<PadHandlerBase>(); const auto handler = fxm::get<pad_thread>();
if (!handler) if (!handler)
return CELL_PAD_ERROR_UNINITIALIZED; return CELL_PAD_ERROR_UNINITIALIZED;
@ -391,7 +391,7 @@ s32 cellPadGetInfo(vm::ptr<CellPadInfo> info)
{ {
sys_io.trace("cellPadGetInfo(info=*0x%x)", info); sys_io.trace("cellPadGetInfo(info=*0x%x)", info);
const auto handler = fxm::get<PadHandlerBase>(); const auto handler = fxm::get<pad_thread>();
if (!handler) if (!handler)
return CELL_PAD_ERROR_UNINITIALIZED; return CELL_PAD_ERROR_UNINITIALIZED;
@ -403,15 +403,15 @@ s32 cellPadGetInfo(vm::ptr<CellPadInfo> info)
info->now_connect = rinfo.now_connect; info->now_connect = rinfo.now_connect;
info->system_info = rinfo.system_info; info->system_info = rinfo.system_info;
std::vector<Pad>& pads = handler->GetPads(); auto& pads = handler->GetPads();
for (u32 i=0; i<CELL_MAX_PADS; ++i) for (u32 i=0; i<CELL_MAX_PADS; ++i)
{ {
if (i >= pads.size()) if (i >= pads.size())
break; break;
info->status[i] = pads[i].m_port_status; info->status[i] = pads[i]->m_port_status;
pads[i].m_port_status &= ~CELL_PAD_STATUS_ASSIGN_CHANGES; pads[i]->m_port_status &= ~CELL_PAD_STATUS_ASSIGN_CHANGES;
info->product_id[i] = 0x0268; info->product_id[i] = 0x0268;
info->vendor_id[i] = 0x054C; info->vendor_id[i] = 0x054C;
} }
@ -423,7 +423,7 @@ s32 cellPadGetInfo2(vm::ptr<CellPadInfo2> info)
{ {
sys_io.trace("cellPadGetInfo2(info=*0x%x)", info); sys_io.trace("cellPadGetInfo2(info=*0x%x)", info);
const auto handler = fxm::get<PadHandlerBase>(); const auto handler = fxm::get<pad_thread>();
if (!handler) if (!handler)
return CELL_PAD_ERROR_UNINITIALIZED; return CELL_PAD_ERROR_UNINITIALIZED;
@ -435,18 +435,18 @@ s32 cellPadGetInfo2(vm::ptr<CellPadInfo2> info)
info->now_connect = rinfo.now_connect; info->now_connect = rinfo.now_connect;
info->system_info = rinfo.system_info; info->system_info = rinfo.system_info;
std::vector<Pad>& pads = handler->GetPads(); auto& pads = handler->GetPads();
for (u32 i=0; i<CELL_PAD_MAX_PORT_NUM; ++i) for (u32 i=0; i<CELL_PAD_MAX_PORT_NUM; ++i)
{ {
if (i >= pads.size()) if (i >= pads.size())
break; break;
info->port_status[i] = pads[i].m_port_status; info->port_status[i] = pads[i]->m_port_status;
pads[i].m_port_status &= ~CELL_PAD_STATUS_ASSIGN_CHANGES; pads[i]->m_port_status &= ~CELL_PAD_STATUS_ASSIGN_CHANGES;
info->port_setting[i] = pads[i].m_port_setting; info->port_setting[i] = pads[i]->m_port_setting;
info->device_capability[i] = pads[i].m_device_capability; info->device_capability[i] = pads[i]->m_device_capability;
info->device_type[i] = pads[i].m_device_type; info->device_type[i] = pads[i]->m_device_type;
} }
return CELL_OK; return CELL_OK;
@ -456,7 +456,7 @@ s32 cellPadGetCapabilityInfo(u32 port_no, vm::ptr<CellCapabilityInfo> info)
{ {
sys_io.trace("cellPadGetCapabilityInfo(port_no=%d, data_addr:=0x%x)", port_no, info.addr()); sys_io.trace("cellPadGetCapabilityInfo(port_no=%d, data_addr:=0x%x)", port_no, info.addr());
const auto handler = fxm::get<PadHandlerBase>(); const auto handler = fxm::get<pad_thread>();
if (!handler) if (!handler)
return CELL_PAD_ERROR_UNINITIALIZED; return CELL_PAD_ERROR_UNINITIALIZED;
@ -468,10 +468,10 @@ s32 cellPadGetCapabilityInfo(u32 port_no, vm::ptr<CellCapabilityInfo> info)
if (port_no >= rinfo.now_connect) if (port_no >= rinfo.now_connect)
return CELL_PAD_ERROR_NO_DEVICE; return CELL_PAD_ERROR_NO_DEVICE;
const std::vector<Pad>& pads = handler->GetPads(); const auto& pads = handler->GetPads();
//Should return the same as device capability mask, psl1ght has it backwards in pad.h //Should return the same as device capability mask, psl1ght has it backwards in pad->h
info->info[0] = pads[port_no].m_device_capability; info->info[0] = pads[port_no]->m_device_capability;
return CELL_OK; return CELL_OK;
} }
@ -480,7 +480,7 @@ s32 cellPadSetPortSetting(u32 port_no, u32 port_setting)
{ {
sys_io.trace("cellPadSetPortSetting(port_no=%d, port_setting=0x%x)", port_no, port_setting); sys_io.trace("cellPadSetPortSetting(port_no=%d, port_setting=0x%x)", port_no, port_setting);
const auto handler = fxm::get<PadHandlerBase>(); const auto handler = fxm::get<pad_thread>();
if (!handler) if (!handler)
return CELL_PAD_ERROR_UNINITIALIZED; return CELL_PAD_ERROR_UNINITIALIZED;
@ -492,8 +492,8 @@ s32 cellPadSetPortSetting(u32 port_no, u32 port_setting)
if (port_no >= rinfo.now_connect) if (port_no >= rinfo.now_connect)
return CELL_PAD_ERROR_NO_DEVICE; return CELL_PAD_ERROR_NO_DEVICE;
std::vector<Pad>& pads = handler->GetPads(); auto& pads = handler->GetPads();
pads[port_no].m_port_setting = port_setting; pads[port_no]->m_port_setting = port_setting;
return CELL_OK; return CELL_OK;
} }
@ -502,7 +502,7 @@ s32 cellPadInfoPressMode(u32 port_no)
{ {
sys_io.trace("cellPadInfoPressMode(port_no=%d)", port_no); sys_io.trace("cellPadInfoPressMode(port_no=%d)", port_no);
const auto handler = fxm::get<PadHandlerBase>(); const auto handler = fxm::get<pad_thread>();
if (!handler) if (!handler)
return CELL_PAD_ERROR_UNINITIALIZED; return CELL_PAD_ERROR_UNINITIALIZED;
@ -514,16 +514,16 @@ s32 cellPadInfoPressMode(u32 port_no)
if (port_no >= rinfo.now_connect) if (port_no >= rinfo.now_connect)
return CELL_PAD_ERROR_NO_DEVICE; return CELL_PAD_ERROR_NO_DEVICE;
const std::vector<Pad>& pads = handler->GetPads(); const auto& pads = handler->GetPads();
return (pads[port_no].m_device_capability & CELL_PAD_CAPABILITY_PRESS_MODE) > 0; return (pads[port_no]->m_device_capability & CELL_PAD_CAPABILITY_PRESS_MODE) > 0;
} }
s32 cellPadInfoSensorMode(u32 port_no) s32 cellPadInfoSensorMode(u32 port_no)
{ {
sys_io.trace("cellPadInfoSensorMode(port_no=%d)", port_no); sys_io.trace("cellPadInfoSensorMode(port_no=%d)", port_no);
const auto handler = fxm::get<PadHandlerBase>(); const auto handler = fxm::get<pad_thread>();
if (!handler) if (!handler)
return CELL_PAD_ERROR_UNINITIALIZED; return CELL_PAD_ERROR_UNINITIALIZED;
@ -535,16 +535,16 @@ s32 cellPadInfoSensorMode(u32 port_no)
if (port_no >= rinfo.now_connect) if (port_no >= rinfo.now_connect)
return CELL_PAD_ERROR_NO_DEVICE; return CELL_PAD_ERROR_NO_DEVICE;
const std::vector<Pad>& pads = handler->GetPads(); const auto& pads = handler->GetPads();
return (pads[port_no].m_device_capability & CELL_PAD_CAPABILITY_SENSOR_MODE) > 0; return (pads[port_no]->m_device_capability & CELL_PAD_CAPABILITY_SENSOR_MODE) > 0;
} }
s32 cellPadSetPressMode(u32 port_no, u32 mode) s32 cellPadSetPressMode(u32 port_no, u32 mode)
{ {
sys_io.trace("cellPadSetPressMode(port_no=%d, mode=%d)", port_no, mode); sys_io.trace("cellPadSetPressMode(port_no=%d, mode=%d)", port_no, mode);
const auto handler = fxm::get<PadHandlerBase>(); const auto handler = fxm::get<pad_thread>();
if (!handler) if (!handler)
return CELL_PAD_ERROR_UNINITIALIZED; return CELL_PAD_ERROR_UNINITIALIZED;
@ -559,12 +559,12 @@ s32 cellPadSetPressMode(u32 port_no, u32 mode)
if (port_no >= rinfo.now_connect) if (port_no >= rinfo.now_connect)
return CELL_PAD_ERROR_NO_DEVICE; return CELL_PAD_ERROR_NO_DEVICE;
std::vector<Pad>& pads = handler->GetPads(); auto& pads = handler->GetPads();
if (mode) if (mode)
pads[port_no].m_port_setting |= CELL_PAD_SETTING_PRESS_ON; pads[port_no]->m_port_setting |= CELL_PAD_SETTING_PRESS_ON;
else else
pads[port_no].m_port_setting &= ~CELL_PAD_SETTING_PRESS_ON; pads[port_no]->m_port_setting &= ~CELL_PAD_SETTING_PRESS_ON;
return CELL_OK; return CELL_OK;
} }
@ -573,7 +573,7 @@ s32 cellPadSetSensorMode(u32 port_no, u32 mode)
{ {
sys_io.trace("cellPadSetSensorMode(port_no=%d, mode=%d)", port_no, mode); sys_io.trace("cellPadSetSensorMode(port_no=%d, mode=%d)", port_no, mode);
const auto handler = fxm::get<PadHandlerBase>(); const auto handler = fxm::get<pad_thread>();
if (!handler) if (!handler)
return CELL_PAD_ERROR_UNINITIALIZED; return CELL_PAD_ERROR_UNINITIALIZED;
@ -588,12 +588,12 @@ s32 cellPadSetSensorMode(u32 port_no, u32 mode)
if (port_no >= rinfo.now_connect) if (port_no >= rinfo.now_connect)
return CELL_PAD_ERROR_NO_DEVICE; return CELL_PAD_ERROR_NO_DEVICE;
std::vector<Pad>& pads = handler->GetPads(); auto& pads = handler->GetPads();
if (mode) if (mode)
pads[port_no].m_port_setting |= CELL_PAD_SETTING_SENSOR_ON; pads[port_no]->m_port_setting |= CELL_PAD_SETTING_SENSOR_ON;
else else
pads[port_no].m_port_setting &= ~CELL_PAD_SETTING_SENSOR_ON; pads[port_no]->m_port_setting &= ~CELL_PAD_SETTING_SENSOR_ON;
return CELL_OK; return CELL_OK;
} }
@ -602,7 +602,7 @@ s32 cellPadLddRegisterController()
{ {
sys_io.todo("cellPadLddRegisterController()"); sys_io.todo("cellPadLddRegisterController()");
const auto handler = fxm::get<PadHandlerBase>(); const auto handler = fxm::get<pad_thread>();
if (!handler) if (!handler)
return CELL_PAD_ERROR_UNINITIALIZED; return CELL_PAD_ERROR_UNINITIALIZED;
@ -614,7 +614,7 @@ s32 cellPadLddDataInsert(s32 handle, vm::ptr<CellPadData> data)
{ {
sys_io.todo("cellPadLddDataInsert(handle=%d, data=*0x%x)", handle, data); sys_io.todo("cellPadLddDataInsert(handle=%d, data=*0x%x)", handle, data);
const auto handler = fxm::get<PadHandlerBase>(); const auto handler = fxm::get<pad_thread>();
if (!handler) if (!handler)
return CELL_PAD_ERROR_UNINITIALIZED; return CELL_PAD_ERROR_UNINITIALIZED;
@ -626,7 +626,7 @@ s32 cellPadLddGetPortNo(s32 handle)
{ {
sys_io.todo("cellPadLddGetPortNo(handle=%d)", handle); sys_io.todo("cellPadLddGetPortNo(handle=%d)", handle);
const auto handler = fxm::get<PadHandlerBase>(); const auto handler = fxm::get<pad_thread>();
if (!handler) if (!handler)
return CELL_PAD_ERROR_UNINITIALIZED; return CELL_PAD_ERROR_UNINITIALIZED;
@ -638,7 +638,7 @@ s32 cellPadLddUnregisterController(s32 handle)
{ {
sys_io.todo("cellPadLddUnregisterController(handle=%d)", handle); sys_io.todo("cellPadLddUnregisterController(handle=%d)", handle);
const auto handler = fxm::get<PadHandlerBase>(); const auto handler = fxm::get<pad_thread>();
if (!handler) if (!handler)
return CELL_PAD_ERROR_UNINITIALIZED; return CELL_PAD_ERROR_UNINITIALIZED;

View File

@ -5,10 +5,25 @@
class NullPadHandler final : public PadHandlerBase class NullPadHandler final : public PadHandlerBase
{ {
public: public:
void Init(const u32 max_connect) override bool Init() override
{ {
memset(&m_info, 0, sizeof(PadInfo)); return true;
m_info.max_connect = max_connect;
m_pads.clear();
} }
std::vector<std::string> ListDevices() override
{
std::vector<std::string> nulllist;
nulllist.push_back("Default Null Device");
return nulllist;
}
bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) override
{
return true;
}
void ThreadProc() override
{
}
}; };

View File

@ -1,5 +1,9 @@
#pragma once #pragma once
#include <vector>
#include <memory>
#include "../../Utilities/types.h"
// TODO: HLE info (constants, structs, etc.) should not be available here // TODO: HLE info (constants, structs, etc.) should not be available here
enum PortStatus enum PortStatus
@ -190,6 +194,14 @@ struct Pad
u16 m_sensor_z; u16 m_sensor_z;
u16 m_sensor_g; u16 m_sensor_g;
void Init(u32 port_status, u32 port_setting, u32 device_capability, u32 device_type)
{
m_port_status = port_status;
m_port_setting = port_setting;
m_device_capability = device_capability;
m_device_type = device_type;
}
Pad(u32 port_status, u32 port_setting, u32 device_capability, u32 device_type) Pad(u32 port_status, u32 port_setting, u32 device_capability, u32 device_type)
: m_buffer_cleared(true) : m_buffer_cleared(true)
, m_port_status(port_status) , m_port_status(port_status)
@ -226,79 +238,23 @@ struct Pad
} }
}; };
struct PadInfo
{
u32 max_connect;
u32 now_connect;
u32 system_info;
};
class PadHandlerBase class PadHandlerBase
{ {
protected: protected:
PadInfo m_info; bool b_has_config = false;
std::vector<Pad> m_pads;
public: public:
virtual void Init(const u32 max_connect) = 0; virtual bool Init() { return true; };
virtual ~PadHandlerBase() = default; virtual ~PadHandlerBase() = default;
//Set value to set pressure/axi to certain level, otherwise 0/255 default //Does it have GUI Config?
void Key(const u32 code, bool pressed, u16 value=255) bool has_config() { return b_has_config; };
{ //Sets window to config the controller(optional)
for(Pad& pad : m_pads) virtual void ConfigController(std::string device) {};
{ //Return list of devices for that handler
for (Button& button : pad.m_buttons) virtual std::vector<std::string> ListDevices() = 0;
{ //Callback called during pad_thread::ThreadFunc
if (button.m_keyCode != code) virtual void ThreadProc() = 0;
continue; //Binds a Pad to a device
virtual bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) = 0;
if (value >= 256){ value = 255; }
//Todo: Is this flush necessary once games hit decent speeds?
if (button.m_pressed && !pressed)
{
button.m_flush = true;
}
else
{
button.m_pressed = pressed;
if (pressed)
button.m_value = value;
else
button.m_value = 0;
}
}
for(AnalogStick& stick : pad.m_sticks)
{
if (stick.m_keyCodeMax != code && stick.m_keyCodeMin != code)
continue;
//slightly less hack job for key based analog stick
// should also fix/make transitions when using keys smoother
// the logic here is that when a key is released,
// if we are at the opposite end of the axis, dont reset to middle
if (stick.m_keyCodeMax == code)
{
if (pressed) stick.m_value = 255;
else if (stick.m_value==0) stick.m_value = 0;
else stick.m_value = 128;
}
if (stick.m_keyCodeMin == code)
{
if (pressed) stick.m_value = 0;
else if (stick.m_value == 255) stick.m_value = 255;
else stick.m_value = 128;
}
}
}
}
virtual PadInfo& GetInfo() { return m_info; }
virtual std::vector<Pad>& GetPads() { return m_pads; }
virtual void SetRumble(const u32 pad, u8 largeMotor, bool smallMotor) {};
std::vector<Button>& GetButtons(const u32 pad) { return m_pads[pad].m_buttons; }
std::vector<AnalogStick>& GetSticks(const u32 pad) { return m_pads[pad].m_sticks; }
}; };

View File

@ -159,7 +159,7 @@ struct EmuCallbacks
std::function<void()> exit; std::function<void()> exit;
std::function<std::shared_ptr<class KeyboardHandlerBase>()> get_kb_handler; std::function<std::shared_ptr<class KeyboardHandlerBase>()> get_kb_handler;
std::function<std::shared_ptr<class MouseHandlerBase>()> get_mouse_handler; std::function<std::shared_ptr<class MouseHandlerBase>()> get_mouse_handler;
std::function<std::shared_ptr<class PadHandlerBase>()> get_pad_handler; std::function<std::shared_ptr<class pad_thread>()> get_pad_handler;
std::function<std::unique_ptr<class GSFrameBase>()> get_gs_frame; std::function<std::unique_ptr<class GSFrameBase>()> get_gs_frame;
std::function<std::shared_ptr<class GSRender>()> get_gs_render; std::function<std::shared_ptr<class GSRender>()> get_gs_render;
std::function<std::shared_ptr<class AudioThread>()> get_audio; std::function<std::shared_ptr<class AudioThread>()> get_audio;

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <string>
namespace vfs namespace vfs
{ {
// VFS type // VFS type

View File

@ -125,134 +125,18 @@ namespace
return (u32)(((u32)buf[0] << 0) + ((u32)buf[1] << 8) + ((u32)buf[2] << 16) + ((u32)buf[3] << 24)); return (u32)(((u32)buf[0] << 0) + ((u32)buf[1] << 8) + ((u32)buf[2] << 16) + ((u32)buf[3] << 24));
} }
} }
ds4_pad_handler::ds4_pad_handler() : is_init(false)
ds4_pad_handler::~ds4_pad_handler()
{ {
Close();
}
void ds4_pad_handler::Init(const u32 max_connect)
{
std::memset(&m_info, 0, sizeof m_info);
m_info.max_connect = max_connect;
for (u32 i = 0, max = std::min(max_connect, u32(MAX_GAMEPADS)); i != max; ++i)
{
m_pads.emplace_back(
CELL_PAD_STATUS_DISCONNECTED,
CELL_PAD_SETTING_PRESS_OFF | CELL_PAD_SETTING_SENSOR_OFF,
CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_HP_ANALOG_STICK | CELL_PAD_CAPABILITY_ACTUATOR | CELL_PAD_CAPABILITY_SENSOR_MODE,
CELL_PAD_DEV_TYPE_STANDARD
);
auto & pad = m_pads.back();
// 'keycode' here is just 0 as we have to manually calculate this
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, CELL_PAD_CTRL_L2);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, CELL_PAD_CTRL_R2);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, 0, CELL_PAD_CTRL_UP);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, 0, CELL_PAD_CTRL_DOWN);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, 0, CELL_PAD_CTRL_LEFT);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, 0, CELL_PAD_CTRL_RIGHT);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, CELL_PAD_CTRL_SQUARE);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, CELL_PAD_CTRL_CROSS);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, CELL_PAD_CTRL_CIRCLE);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, CELL_PAD_CTRL_TRIANGLE);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, CELL_PAD_CTRL_L1);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, CELL_PAD_CTRL_R1);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, 0, CELL_PAD_CTRL_SELECT);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, 0, CELL_PAD_CTRL_START);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, 0, CELL_PAD_CTRL_L3);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, 0, CELL_PAD_CTRL_R3);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved
pad.m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 512);
pad.m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 399);
pad.m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Z, 512);
pad.m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_G, 512);
pad.m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, 0, 0);
pad.m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, 0, 0);
pad.m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, 0, 0);
pad.m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, 0, 0);
pad.m_vibrateMotors.emplace_back(true, 0);
pad.m_vibrateMotors.emplace_back(false, 0);
}
ds4Thread = std::make_shared<ds4_thread>();
ds4Thread->on_init(ds4Thread);
}
PadInfo& ds4_pad_handler::GetInfo()
{
if (ds4Thread)
{
auto info = ds4Thread->GetConnectedControllers();
m_info.now_connect = 0;
int i = 0;
for (auto & pad : m_pads)
{
if (info[i])
{
m_info.now_connect++;
if (last_connection_status[i] == false)
pad.m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES;
last_connection_status[i] = true;
pad.m_port_status |= CELL_PAD_STATUS_CONNECTED;
}
else
{
if (last_connection_status[i] == true)
pad.m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES;
last_connection_status[i] = false;
pad.m_port_status &= ~CELL_PAD_STATUS_CONNECTED;
}
++i;
}
}
return m_info;
}
std::vector<Pad>& ds4_pad_handler::GetPads()
{
if (ds4Thread)
ProcessData();
return m_pads;
}
void ds4_pad_handler::Close()
{
if (ds4Thread)
ds4Thread.reset();
m_pads.clear();
} }
void ds4_pad_handler::ProcessData() void ds4_pad_handler::ProcessData()
{ {
for (auto &bind : bindings)
if (!ds4Thread)
return;
auto data = ds4Thread->GetControllerData();
int i = 0;
for (auto & pad : m_pads)
{ {
std::shared_ptr<DS4Device> device = bind.first;
auto buf = data[i]; auto pad = bind.second;
auto buf = device->padData;
// these are added with previous value and divided to 'smooth' out the readings // these are added with previous value and divided to 'smooth' out the readings
// the ds4 seems to rapidly flicker sometimes between two values and this seems to stop that // the ds4 seems to rapidly flicker sometimes between two values and this seems to stop that
@ -260,114 +144,114 @@ void ds4_pad_handler::ProcessData()
u16 lx, ly; u16 lx, ly;
//std::tie(lx, ly) = ConvertToSquarePoint(buf[1], buf[2]); //std::tie(lx, ly) = ConvertToSquarePoint(buf[1], buf[2]);
std::tie(lx, ly) = ConvertToSquirclePoint(buf[1], buf[2]); std::tie(lx, ly) = ConvertToSquirclePoint(buf[1], buf[2]);
pad.m_sticks[0].m_value = (lx + pad.m_sticks[0].m_value) / 2; // LX pad->m_sticks[0].m_value = (lx + pad->m_sticks[0].m_value) / 2; // LX
pad.m_sticks[1].m_value = (ly + pad.m_sticks[1].m_value) / 2; // LY pad->m_sticks[1].m_value = (ly + pad->m_sticks[1].m_value) / 2; // LY
u16 rx, ry; u16 rx, ry;
//std::tie(rx, ry) = ConvertToSquarePoint(buf[3], buf[4]); //std::tie(rx, ry) = ConvertToSquarePoint(buf[3], buf[4]);
std::tie(rx, ry) = ConvertToSquirclePoint(buf[3], buf[4]); std::tie(rx, ry) = ConvertToSquirclePoint(buf[3], buf[4]);
pad.m_sticks[2].m_value = (rx + pad.m_sticks[2].m_value) / 2; // RX pad->m_sticks[2].m_value = (rx + pad->m_sticks[2].m_value) / 2; // RX
pad.m_sticks[3].m_value = (ry + pad.m_sticks[3].m_value) / 2; // RY pad->m_sticks[3].m_value = (ry + pad->m_sticks[3].m_value) / 2; // RY
// l2 r2 // l2 r2
pad.m_buttons[0].m_pressed = buf[8] > 0; pad->m_buttons[0].m_pressed = buf[8] > 0;
pad.m_buttons[0].m_value = buf[8]; pad->m_buttons[0].m_value = buf[8];
pad.m_buttons[1].m_pressed = buf[9] > 0; pad->m_buttons[1].m_pressed = buf[9] > 0;
pad.m_buttons[1].m_value = buf[9]; pad->m_buttons[1].m_value = buf[9];
// bleh, dpad in buffer is stored in a different state // bleh, dpad in buffer is stored in a different state
u8 dpadState = buf[5] & 0xf; u8 dpadState = buf[5] & 0xf;
switch (dpadState) switch (dpadState)
{ {
case 0x08: // none pressed case 0x08: // none pressed
pad.m_buttons[2].m_pressed = false; pad->m_buttons[2].m_pressed = false;
pad.m_buttons[2].m_value = 0; pad->m_buttons[2].m_value = 0;
pad.m_buttons[3].m_pressed = false; pad->m_buttons[3].m_pressed = false;
pad.m_buttons[3].m_value = 0; pad->m_buttons[3].m_value = 0;
pad.m_buttons[4].m_pressed = false; pad->m_buttons[4].m_pressed = false;
pad.m_buttons[4].m_value = 0; pad->m_buttons[4].m_value = 0;
pad.m_buttons[5].m_pressed = false; pad->m_buttons[5].m_pressed = false;
pad.m_buttons[5].m_value = 0; pad->m_buttons[5].m_value = 0;
break; break;
case 0x07: // NW...left and up case 0x07: // NW...left and up
pad.m_buttons[2].m_pressed = true; pad->m_buttons[2].m_pressed = true;
pad.m_buttons[2].m_value = 255; pad->m_buttons[2].m_value = 255;
pad.m_buttons[3].m_pressed = false; pad->m_buttons[3].m_pressed = false;
pad.m_buttons[3].m_value = 0; pad->m_buttons[3].m_value = 0;
pad.m_buttons[4].m_pressed = true; pad->m_buttons[4].m_pressed = true;
pad.m_buttons[4].m_value = 255; pad->m_buttons[4].m_value = 255;
pad.m_buttons[5].m_pressed = false; pad->m_buttons[5].m_pressed = false;
pad.m_buttons[5].m_value = 0; pad->m_buttons[5].m_value = 0;
break; break;
case 0x06: // W..left case 0x06: // W..left
pad.m_buttons[2].m_pressed = false; pad->m_buttons[2].m_pressed = false;
pad.m_buttons[2].m_value = 0; pad->m_buttons[2].m_value = 0;
pad.m_buttons[3].m_pressed = false; pad->m_buttons[3].m_pressed = false;
pad.m_buttons[3].m_value = 0; pad->m_buttons[3].m_value = 0;
pad.m_buttons[4].m_pressed = true; pad->m_buttons[4].m_pressed = true;
pad.m_buttons[4].m_value = 255; pad->m_buttons[4].m_value = 255;
pad.m_buttons[5].m_pressed = false; pad->m_buttons[5].m_pressed = false;
pad.m_buttons[5].m_value = 0; pad->m_buttons[5].m_value = 0;
break; break;
case 0x05: // SW..left down case 0x05: // SW..left down
pad.m_buttons[2].m_pressed = false; pad->m_buttons[2].m_pressed = false;
pad.m_buttons[2].m_value = 0; pad->m_buttons[2].m_value = 0;
pad.m_buttons[3].m_pressed = true; pad->m_buttons[3].m_pressed = true;
pad.m_buttons[3].m_value = 255; pad->m_buttons[3].m_value = 255;
pad.m_buttons[4].m_pressed = true; pad->m_buttons[4].m_pressed = true;
pad.m_buttons[4].m_value = 255; pad->m_buttons[4].m_value = 255;
pad.m_buttons[5].m_pressed = false; pad->m_buttons[5].m_pressed = false;
pad.m_buttons[5].m_value = 0; pad->m_buttons[5].m_value = 0;
break; break;
case 0x04: // S..down case 0x04: // S..down
pad.m_buttons[2].m_pressed = false; pad->m_buttons[2].m_pressed = false;
pad.m_buttons[2].m_value = 0; pad->m_buttons[2].m_value = 0;
pad.m_buttons[3].m_pressed = true; pad->m_buttons[3].m_pressed = true;
pad.m_buttons[3].m_value = 255; pad->m_buttons[3].m_value = 255;
pad.m_buttons[4].m_pressed = false; pad->m_buttons[4].m_pressed = false;
pad.m_buttons[4].m_value = 0; pad->m_buttons[4].m_value = 0;
pad.m_buttons[5].m_pressed = false; pad->m_buttons[5].m_pressed = false;
pad.m_buttons[5].m_value = 0; pad->m_buttons[5].m_value = 0;
break; break;
case 0x03: // SE..down and right case 0x03: // SE..down and right
pad.m_buttons[2].m_pressed = false; pad->m_buttons[2].m_pressed = false;
pad.m_buttons[2].m_value = 0; pad->m_buttons[2].m_value = 0;
pad.m_buttons[3].m_pressed = true; pad->m_buttons[3].m_pressed = true;
pad.m_buttons[3].m_value = 255; pad->m_buttons[3].m_value = 255;
pad.m_buttons[4].m_pressed = false; pad->m_buttons[4].m_pressed = false;
pad.m_buttons[4].m_value = 0; pad->m_buttons[4].m_value = 0;
pad.m_buttons[5].m_pressed = true; pad->m_buttons[5].m_pressed = true;
pad.m_buttons[5].m_value = 255; pad->m_buttons[5].m_value = 255;
break; break;
case 0x02: // E... right case 0x02: // E... right
pad.m_buttons[2].m_pressed = false; pad->m_buttons[2].m_pressed = false;
pad.m_buttons[2].m_value = 0; pad->m_buttons[2].m_value = 0;
pad.m_buttons[3].m_pressed = false; pad->m_buttons[3].m_pressed = false;
pad.m_buttons[3].m_value = 0; pad->m_buttons[3].m_value = 0;
pad.m_buttons[4].m_pressed = false; pad->m_buttons[4].m_pressed = false;
pad.m_buttons[4].m_value = 0; pad->m_buttons[4].m_value = 0;
pad.m_buttons[5].m_pressed = true; pad->m_buttons[5].m_pressed = true;
pad.m_buttons[5].m_value = 255; pad->m_buttons[5].m_value = 255;
break; break;
case 0x01: // NE.. up right case 0x01: // NE.. up right
pad.m_buttons[2].m_pressed = true; pad->m_buttons[2].m_pressed = true;
pad.m_buttons[2].m_value = 255; pad->m_buttons[2].m_value = 255;
pad.m_buttons[3].m_pressed = false; pad->m_buttons[3].m_pressed = false;
pad.m_buttons[3].m_value = 0; pad->m_buttons[3].m_value = 0;
pad.m_buttons[4].m_pressed = false; pad->m_buttons[4].m_pressed = false;
pad.m_buttons[4].m_value = 0; pad->m_buttons[4].m_value = 0;
pad.m_buttons[5].m_pressed = true; pad->m_buttons[5].m_pressed = true;
pad.m_buttons[5].m_value = 255; pad->m_buttons[5].m_value = 255;
break; break;
case 0x00: // n.. up case 0x00: // n.. up
pad.m_buttons[2].m_pressed = true; pad->m_buttons[2].m_pressed = true;
pad.m_buttons[2].m_value = 255; pad->m_buttons[2].m_value = 255;
pad.m_buttons[3].m_pressed = false; pad->m_buttons[3].m_pressed = false;
pad.m_buttons[3].m_value = 0; pad->m_buttons[3].m_value = 0;
pad.m_buttons[4].m_pressed = false; pad->m_buttons[4].m_pressed = false;
pad.m_buttons[4].m_value = 0; pad->m_buttons[4].m_value = 0;
pad.m_buttons[5].m_pressed = false; pad->m_buttons[5].m_pressed = false;
pad.m_buttons[5].m_value = 0; pad->m_buttons[5].m_value = 0;
break; break;
default: default:
fmt::throw_exception("ds4 dpad state encountered unexpected input"); fmt::throw_exception("ds4 dpad state encountered unexpected input");
@ -377,31 +261,31 @@ void ds4_pad_handler::ProcessData()
for (int i = 4; i < 8; ++i) for (int i = 4; i < 8; ++i)
{ {
const bool pressed = ((buf[5] & (1 << i)) != 0); const bool pressed = ((buf[5] & (1 << i)) != 0);
pad.m_buttons[6 + i - 4].m_pressed = pressed; pad->m_buttons[6 + i - 4].m_pressed = pressed;
pad.m_buttons[6 + i - 4].m_value = pressed ? 255 : 0; pad->m_buttons[6 + i - 4].m_value = pressed ? 255 : 0;
} }
// L1, R1 // L1, R1
const bool l1press = ((buf[6] & (1 << 0)) != 0); const bool l1press = ((buf[6] & (1 << 0)) != 0);
pad.m_buttons[10].m_pressed = l1press; pad->m_buttons[10].m_pressed = l1press;
pad.m_buttons[10].m_value = l1press ? 255 : 0; pad->m_buttons[10].m_value = l1press ? 255 : 0;
const bool l2press = ((buf[6] & (1 << 1)) != 0); const bool l2press = ((buf[6] & (1 << 1)) != 0);
pad.m_buttons[11].m_pressed = l2press; pad->m_buttons[11].m_pressed = l2press;
pad.m_buttons[11].m_value = l2press ? 255 : 0; pad->m_buttons[11].m_value = l2press ? 255 : 0;
// select, start, l3, r3 // select, start, l3, r3
for (int i = 4; i < 8; ++i) for (int i = 4; i < 8; ++i)
{ {
const bool pressed = ((buf[6] & (1 << i)) != 0); const bool pressed = ((buf[6] & (1 << i)) != 0);
pad.m_buttons[12 + i - 4].m_pressed = pressed; pad->m_buttons[12 + i - 4].m_pressed = pressed;
pad.m_buttons[12 + i - 4].m_value = pressed ? 255 : 0; pad->m_buttons[12 + i - 4].m_value = pressed ? 255 : 0;
} }
#ifdef _WIN32 #ifdef _WIN32
for (int i = 6; i < 16; i++) for (int i = 6; i < 16; i++)
{ {
if (pad.m_buttons[i].m_pressed) if (pad->m_buttons[i].m_pressed)
{ {
SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
break; break;
@ -422,9 +306,9 @@ void ds4_pad_handler::ProcessData()
accelY = accelY * 113 + 512; accelY = accelY * 113 + 512;
accelZ = accelZ * 113 + 512; accelZ = accelZ * 113 + 512;
pad.m_sensors[0].m_value = Clamp0To1023(accelX); pad->m_sensors[0].m_value = Clamp0To1023(accelX);
pad.m_sensors[1].m_value = Clamp0To1023(accelY); pad->m_sensors[1].m_value = Clamp0To1023(accelY);
pad.m_sensors[2].m_value = Clamp0To1023(accelZ); pad->m_sensors[2].m_value = Clamp0To1023(accelZ);
// gyroX is yaw, which is all that we need // gyroX is yaw, which is all that we need
f32 gyroX = (((s16)((u16)(buf[16] << 8) | buf[15])) / static_cast<f32>(DS4_GYRO_RES_PER_DEG_S)) * -1; f32 gyroX = (((s16)((u16)(buf[16] << 8) | buf[15])) / static_cast<f32>(DS4_GYRO_RES_PER_DEG_S)) * -1;
@ -434,73 +318,25 @@ void ds4_pad_handler::ProcessData()
// convert to ds3 // convert to ds3
gyroX = gyroX * (123.f / 90.f) + 512; gyroX = gyroX * (123.f / 90.f) + 512;
pad.m_sensors[3].m_value = Clamp0To1023(gyroX); pad->m_sensors[3].m_value = Clamp0To1023(gyroX);
i++;
} }
} }
void ds4_pad_handler::SetRumble(const u32 pad, u8 largeMotor, bool smallMotor) void ds4_pad_handler::UpdateRumble()
{ {
if (pad > m_pads.size())
return;
m_pads[pad].m_vibrateMotors[0].m_value = largeMotor;
m_pads[pad].m_vibrateMotors[1].m_value = smallMotor ? 255 : 0;
if (!ds4Thread)
return;
ds4Thread->SetRumbleData(pad, largeMotor, smallMotor ? 255 : 0);
}
void ds4_thread::SetRumbleData(u32 port, u8 largeVibrate, u8 smallVibrate)
{
semaphore_lock lock(mutex);
// todo: give unique identifier to this instead of port // todo: give unique identifier to this instead of port
for (auto &bind : bindings)
{
std::shared_ptr<DS4Device> device = bind.first;
auto thepad = bind.second;
u32 i = 0; device->newVibrateData = device->largeVibrate != thepad->m_vibrateMotors[0].m_value || device->smallVibrate != (thepad->m_vibrateMotors[1].m_value ? 255 : 0);
for (auto & controller : controllers) device->largeVibrate = thepad->m_vibrateMotors[0].m_value;
{ device->smallVibrate = (thepad->m_vibrateMotors[1].m_value ? 255 : 0);
if (i == port)
{
controller.second.newVibrateData = controller.second.largeVibrate != largeVibrate || controller.second.smallVibrate != smallVibrate;
controller.second.largeVibrate = largeVibrate;
controller.second.smallVibrate = smallVibrate;
break;
}
++i;
} }
} }
std::array<bool, MAX_GAMEPADS> ds4_thread::GetConnectedControllers() bool ds4_pad_handler::GetCalibrationData(std::shared_ptr<DS4Device> ds4Dev)
{
std::array<bool, MAX_GAMEPADS> rtnData{};
int i = 0;
semaphore_lock lock(mutex);
for (const auto & cont : controllers)
rtnData[i++] = cont.second.hidDevice != nullptr;
return rtnData;
}
std::array<std::array<u8, 64>, MAX_GAMEPADS> ds4_thread::GetControllerData()
{
std::array<std::array<u8, 64>, MAX_GAMEPADS> rtnData;
int i = 0;
semaphore_lock lock(mutex);
for (const auto & data : padData)
rtnData[i++] = data;
return rtnData;
}
bool ds4_thread::GetCalibrationData(DS4Device* ds4Dev)
{ {
std::array<u8, 64> buf; std::array<u8, 64> buf;
if (ds4Dev->btCon) if (ds4Dev->btCon)
@ -588,11 +424,11 @@ bool ds4_thread::GetCalibrationData(DS4Device* ds4Dev)
return true; return true;
} }
void ds4_thread::CheckAddDevice(hid_device* hidDevice, hid_device_info* hidDevInfo) void ds4_pad_handler::CheckAddDevice(hid_device* hidDevice, hid_device_info* hidDevInfo)
{ {
std::string serial = ""; std::string serial = "";
DS4Device ds4Dev; std::shared_ptr<DS4Device> ds4Dev = std::make_shared<DS4Device>();
ds4Dev.hidDevice = hidDevice; ds4Dev->hidDevice = hidDevice;
// There isnt a nice 'portable' way with hidapi to detect bt vs wired as the pid/vid's are the same // There isnt a nice 'portable' way with hidapi to detect bt vs wired as the pid/vid's are the same
// Let's try getting 0x81 feature report, which should will return mac address on wired, and should error on bluetooth // Let's try getting 0x81 feature report, which should will return mac address on wired, and should error on bluetooth
std::array<u8, 64> buf{}; std::array<u8, 64> buf{};
@ -603,80 +439,45 @@ void ds4_thread::CheckAddDevice(hid_device* hidDevice, hid_device_info* hidDevIn
} }
else else
{ {
ds4Dev.btCon = true; ds4Dev->btCon = true;
std::wstring wSerial(hidDevInfo->serial_number); std::wstring wSerial(hidDevInfo->serial_number);
serial = std::string(wSerial.begin(), wSerial.end()); serial = std::string(wSerial.begin(), wSerial.end());
} }
if (!GetCalibrationData(&ds4Dev)) if (!GetCalibrationData(ds4Dev))
{ {
LOG_ERROR(HLE, "[DS4] Failed getting calibration data, ignoring controller!"); LOG_ERROR(HLE, "[DS4] Failed getting calibration data, ignoring controller!");
hid_close(hidDevice); hid_close(hidDevice);
return; return;
} }
ds4Dev.path = hidDevInfo->path; ds4Dev->path = hidDevInfo->path;
hid_set_nonblocking(hidDevice, 1); hid_set_nonblocking(hidDevice, 1);
controllers.emplace(serial, ds4Dev); controllers.emplace(serial, ds4Dev);
} }
void ds4_thread::on_init(const std::shared_ptr<void>& _this) ds4_pad_handler::~ds4_pad_handler()
{ {
const int res = hid_init(); for (auto& controller : controllers)
if (res != 0)
fmt::throw_exception("hidapi-init error.threadproc");
// get all the possible controllers at start
for (auto pid : ds4Pids)
{ {
hid_device_info* devInfo = hid_enumerate(DS4_VID, pid); if (controller.second->hidDevice)
hid_device_info* head = devInfo; hid_close(controller.second->hidDevice);
while (devInfo)
{
if (controllers.size() >= MAX_GAMEPADS)
break;
hid_device* dev = hid_open_path(devInfo->path);
if (dev)
CheckAddDevice(dev, devInfo);
devInfo = devInfo->next;
}
hid_free_enumeration(head);
}
if (controllers.size() == 0)
LOG_ERROR(HLE, "[DS4] No controllers found!");
else
LOG_SUCCESS(HLE, "[DS4] Controllers found: %d", controllers.size());
named_thread::on_init(_this);
}
ds4_thread::~ds4_thread()
{
for (auto & controller : controllers)
{
if (controller.second.hidDevice)
hid_close(controller.second.hidDevice);
} }
hid_exit(); hid_exit();
} }
void ds4_thread::SendVibrateData(const DS4Device& device) void ds4_pad_handler::SendVibrateData(const std::shared_ptr<DS4Device> device)
{ {
std::array<u8, 78> outputBuf{0}; std::array<u8, 78> outputBuf{0};
// write rumble state // write rumble state
if (device.btCon) if (device->btCon)
{ {
outputBuf[0] = 0x11; outputBuf[0] = 0x11;
outputBuf[1] = 0xC4; outputBuf[1] = 0xC4;
outputBuf[3] = 0x07; outputBuf[3] = 0x07;
outputBuf[6] = device.smallVibrate; outputBuf[6] = device->smallVibrate;
outputBuf[7] = device.largeVibrate; outputBuf[7] = device->largeVibrate;
outputBuf[8] = 0x00; // red outputBuf[8] = 0x00; // red
outputBuf[9] = 0x00; // green outputBuf[9] = 0x00; // green
outputBuf[10] = 0xff; // blue outputBuf[10] = 0xff; // blue
@ -690,86 +491,199 @@ void ds4_thread::SendVibrateData(const DS4Device& device)
outputBuf[76] = (crcCalc >> 16) & 0xFF; outputBuf[76] = (crcCalc >> 16) & 0xFF;
outputBuf[77] = (crcCalc >> 24) & 0xFF; outputBuf[77] = (crcCalc >> 24) & 0xFF;
hid_write_control(device.hidDevice, outputBuf.data(), DS4_OUTPUT_REPORT_0x11_SIZE); hid_write_control(device->hidDevice, outputBuf.data(), DS4_OUTPUT_REPORT_0x11_SIZE);
} }
else else
{ {
outputBuf[0] = 0x05; outputBuf[0] = 0x05;
outputBuf[1] = 0x07; outputBuf[1] = 0x07;
outputBuf[4] = device.smallVibrate; outputBuf[4] = device->smallVibrate;
outputBuf[5] = device.largeVibrate; outputBuf[5] = device->largeVibrate;
outputBuf[6] = 0x00; // red outputBuf[6] = 0x00; // red
outputBuf[7] = 0x00; // green outputBuf[7] = 0x00; // green
outputBuf[8] = 0xff; // blue outputBuf[8] = 0xff; // blue
hid_write(device.hidDevice, outputBuf.data(), DS4_OUTPUT_REPORT_0x05_SIZE); hid_write(device->hidDevice, outputBuf.data(), DS4_OUTPUT_REPORT_0x05_SIZE);
} }
} }
void ds4_thread::on_task() bool ds4_pad_handler::Init()
{ {
while (!Emu.IsStopped()) if (is_init) return true;
const int res = hid_init();
if (res != 0)
fmt::throw_exception("hidapi-init error.threadproc");
// get all the possible controllers at start
for (auto pid : ds4Pids)
{ {
if (Emu.IsPaused()) hid_device_info* devInfo = hid_enumerate(DS4_VID, pid);
hid_device_info* head = devInfo;
while (devInfo)
{ {
std::this_thread::sleep_for(10ms); if (controllers.size() >= MAX_GAMEPADS) break;
continue;
hid_device* dev = hid_open_path(devInfo->path);
if (dev) CheckAddDevice(dev, devInfo);
devInfo = devInfo->next;
}
hid_free_enumeration(head);
} }
u32 online = 0; if (controllers.size() == 0)
u32 i = 0; LOG_ERROR(HLE, "[DS4] No controllers found!");
else
LOG_SUCCESS(HLE, "[DS4] Controllers found: %d", controllers.size());
is_init = true;
return true;
}
std::vector<std::string> ds4_pad_handler::ListDevices()
{
std::vector<std::string> ds4_pads_list;
if (!Init()) return ds4_pads_list;
for (auto& pad : controllers)
{
ds4_pads_list.emplace_back("Ds4 Pad #" + pad.first);
}
return ds4_pads_list;
}
bool ds4_pad_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device)
{
size_t pos = device.find("Ds4 Pad #");
if (pos == std::string::npos) return false;
std::string pad_serial = device.substr(pos + 9);
std::shared_ptr<DS4Device> device_id = nullptr;
for (auto& cur_control : controllers)
{
if (pad_serial == cur_control.first)
{
device_id = cur_control.second;
break;
}
}
if (device_id == nullptr) return false;
pad->Init(
CELL_PAD_STATUS_CONNECTED,
CELL_PAD_SETTING_PRESS_OFF | CELL_PAD_SETTING_SENSOR_OFF,
CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_HP_ANALOG_STICK | CELL_PAD_CAPABILITY_ACTUATOR | CELL_PAD_CAPABILITY_SENSOR_MODE,
CELL_PAD_DEV_TYPE_STANDARD
);
// 'keycode' here is just 0 as we have to manually calculate this
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, CELL_PAD_CTRL_L2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, CELL_PAD_CTRL_R2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, 0, CELL_PAD_CTRL_UP);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, 0, CELL_PAD_CTRL_DOWN);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, 0, CELL_PAD_CTRL_LEFT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, 0, CELL_PAD_CTRL_RIGHT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, CELL_PAD_CTRL_SQUARE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, CELL_PAD_CTRL_CROSS);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, CELL_PAD_CTRL_CIRCLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, CELL_PAD_CTRL_TRIANGLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, CELL_PAD_CTRL_L1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, CELL_PAD_CTRL_R1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, 0, CELL_PAD_CTRL_SELECT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, 0, CELL_PAD_CTRL_START);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, 0, CELL_PAD_CTRL_L3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, 0, CELL_PAD_CTRL_R3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 512);
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 399);
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Z, 512);
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_G, 512);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, 0, 0);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, 0, 0);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, 0, 0);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, 0, 0);
pad->m_vibrateMotors.emplace_back(true, 0);
pad->m_vibrateMotors.emplace_back(false, 0);
bindings.emplace_back(device_id, pad);
}
void ds4_pad_handler::ThreadProc()
{
UpdateRumble();
std::array<u8, 78> buf{}; std::array<u8, 78> buf{};
for (auto &bind : bindings)
for (auto & controller : controllers)
{ {
semaphore_lock lock(mutex); std::shared_ptr<DS4Device> device = bind.first;
auto thepad = bind.second;
if (controller.second.hidDevice == nullptr) if (device->hidDevice == nullptr)
{ {
// try to reconnect // try to reconnect
hid_device* dev = hid_open_path(controller.second.path.c_str()); hid_device* dev = hid_open_path(device->path.c_str());
if (dev) if (dev)
{ {
hid_set_nonblocking(dev, 1); hid_set_nonblocking(dev, 1);
controller.second.hidDevice = dev; device->hidDevice = dev;
thepad->m_port_status = CELL_PAD_STATUS_CONNECTED|CELL_PAD_STATUS_ASSIGN_CHANGES;
} }
else else
{ {
// nope, not there // nope, not there
thepad->m_port_status = CELL_PAD_STATUS_DISCONNECTED|CELL_PAD_STATUS_ASSIGN_CHANGES;
continue; continue;
} }
} }
online++; const int res = hid_read(device->hidDevice, buf.data(), device->btCon ? 78 : 64);
const int res = hid_read(controller.second.hidDevice, buf.data(), controller.second.btCon ? 78 : 64);
if (res == -1) if (res == -1)
{ {
// looks like controller disconnected or read error, deal with it on next loop // looks like controller disconnected or read error, deal with it on next loop
hid_close(controller.second.hidDevice); hid_close(device->hidDevice);
controller.second.hidDevice = nullptr; device->hidDevice = nullptr;
continue; continue;
} }
if (device->newVibrateData)
{
SendVibrateData(device);
device->newVibrateData = false;
}
// no data? keep going // no data? keep going
if (res == 0) if (res == 0)
continue; continue;
// bt controller sends this until 0x02 feature report is sent back (happens on controller init/restart) // bt controller sends this until 0x02 feature report is sent back (happens on controller init/restart)
if (controller.second.btCon && buf[0] == 0x1) if (device->btCon && buf[0] == 0x1)
{ {
// tells controller to send 0x11 reports // tells controller to send 0x11 reports
std::array<u8, 64> buf{}; std::array<u8, 64> buf_error{};
buf[0] = 0x2; buf_error[0] = 0x2;
hid_get_feature_report(controller.second.hidDevice, buf.data(), buf.size()); hid_get_feature_report(device->hidDevice, buf_error.data(), buf_error.size());
continue; continue;
} }
int offset = 0; int offset = 0;
// check report and set offset // check report and set offset
if (controller.second.btCon && buf[0] == 0x11 && res == 78) if (device->btCon && buf[0] == 0x11 && res == 78)
{ {
offset = 2; offset = 2;
@ -783,7 +697,7 @@ void ds4_thread::on_task()
} }
} }
else if (!controller.second.btCon && buf[0] == 0x01 && res == 64) else if (!device->btCon && buf[0] == 0x01 && res == 64)
offset = 0; offset = 0;
else else
continue; continue;
@ -792,22 +706,13 @@ void ds4_thread::on_task()
for (int i = 0; i < DS4CalibIndex::COUNT; ++i) for (int i = 0; i < DS4CalibIndex::COUNT; ++i)
{ {
const s16 rawValue = GetS16LEData(&buf[calibOffset]); const s16 rawValue = GetS16LEData(&buf[calibOffset]);
const s16 calValue = ApplyCalibration(rawValue, controller.second.calibData[i]); const s16 calValue = ApplyCalibration(rawValue, device->calibData[i]);
buf[calibOffset++] = ((u16)calValue >> 0) & 0xFF; buf[calibOffset++] = ((u16)calValue >> 0) & 0xFF;
buf[calibOffset++] = ((u16)calValue >> 8) & 0xFF; buf[calibOffset++] = ((u16)calValue >> 8) & 0xFF;
} }
memcpy(padData[i].data(), &buf[offset], 64); memcpy(device->padData.data(), &buf[offset], 64);
if (controller.second.newVibrateData)
{
SendVibrateData(controller.second);
controller.second.newVibrateData = false;
} }
i++; ProcessData();
}
std::this_thread::sleep_for((online > 0) ? THREAD_SLEEP : THREAD_SLEEP_INACTIVE);
}
} }

View File

@ -5,13 +5,12 @@
#include "Utilities/CRC.h" #include "Utilities/CRC.h"
#include "hidapi.h" #include "hidapi.h"
#include <limits> #include <limits>
#include <unordered_map>
const u32 MAX_GAMEPADS = 7; const u32 MAX_GAMEPADS = 7;
class ds4_pad_handler final : public PadHandlerBase
class ds4_thread final : public named_thread
{ {
private:
enum DS4CalibIndex enum DS4CalibIndex
{ {
// gyro // gyro
@ -39,48 +38,45 @@ private:
std::string path{ "" }; std::string path{ "" };
bool btCon{ false }; bool btCon{ false };
std::array<DS4CalibData, DS4CalibIndex::COUNT> calibData; std::array<DS4CalibData, DS4CalibIndex::COUNT> calibData;
bool newVibrateData{true}; bool newVibrateData{ true };
u8 largeVibrate{0}; u8 largeVibrate{ 0 };
u8 smallVibrate{0}; u8 smallVibrate{ 0 };
std::array<u8, 64> padData;
}; };
const u16 DS4_VID = 0x054C; const u16 DS4_VID = 0x054C;
// pid's of connected ds4 // pid's of connected ds4
const std::array<u16, 3> ds4Pids = {{0xBA0, 0x5C4, 0x09CC }}; const std::array<u16, 3> ds4Pids = { { 0xBA0, 0x5C4, 0x09CC } };
// pseudo 'controller id' to keep track of unique controllers // pseudo 'controller id' to keep track of unique controllers
std::unordered_map<std::string, DS4Device> controllers; std::unordered_map<std::string, std::shared_ptr<DS4Device>> controllers;
std::array<std::array<u8, 64>, MAX_GAMEPADS> padData{};
void on_task() override;
std::string get_name() const override { return "DS4 Thread"; }
semaphore<> mutex;
CRCPP::CRC::Table<u32, 32> crcTable{ CRCPP::CRC::CRC_32() }; CRCPP::CRC::Table<u32, 32> crcTable{ CRCPP::CRC::CRC_32() };
public: public:
void on_init(const std::shared_ptr<void>&) override; ds4_pad_handler();
~ds4_pad_handler();
std::array<bool, MAX_GAMEPADS> GetConnectedControllers(); bool Init() override;
std::array<std::array<u8, 64>, MAX_GAMEPADS> GetControllerData(); std::vector<std::string> ListDevices() override;
bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) override;
void SetRumbleData(u32 port, u8 largeVibrate, u8 smallVibrate); void ThreadProc() override;
ds4_thread() = default;
~ds4_thread();
private: private:
bool GetCalibrationData(DS4Device* ds4Device); bool is_init;
// holds internal controller state change
std::array<bool, MAX_GAMEPADS> last_connection_status = {};
std::vector<std::pair<std::shared_ptr<DS4Device>, std::shared_ptr<Pad>>> bindings;
private:
void ProcessData();
void UpdateRumble();
bool GetCalibrationData(std::shared_ptr<DS4Device> ds4Device);
void CheckAddDevice(hid_device* hidDevice, hid_device_info* hidDevInfo); void CheckAddDevice(hid_device* hidDevice, hid_device_info* hidDevInfo);
void SendVibrateData(const DS4Device& device); void SendVibrateData(const std::shared_ptr<DS4Device> device);
inline s16 ApplyCalibration(s32 rawValue, const DS4CalibData& calibData) inline s16 ApplyCalibration(s32 rawValue, const DS4CalibData& calibData)
{ {
const s32 biased = rawValue - calibData.bias; const s32 biased = rawValue - calibData.bias;
@ -95,28 +91,3 @@ private:
else return static_cast<s16>(output); else return static_cast<s16>(output);
} }
}; };
class ds4_pad_handler final : public PadHandlerBase
{
public:
ds4_pad_handler() {}
~ds4_pad_handler();
void Init(const u32 max_connect) override;
void Close();
PadInfo& GetInfo() override;
std::vector<Pad>& GetPads() override;
void SetRumble(const u32 pad, u8 largeMotor, bool smallMotor) override;
private:
void ProcessData();
// holds internal controller state change
std::array<bool, MAX_GAMEPADS> last_connection_status = {};
std::shared_ptr<ds4_thread> ds4Thread;
};

View File

@ -15,22 +15,12 @@
evdev_joystick_config g_evdev_joystick_config; evdev_joystick_config g_evdev_joystick_config;
namespace
{
const u32 THREAD_SLEEP_USEC = 100;
const u32 THREAD_SLEEP_INACTIVE_USEC = 1000000;
const u32 READ_TIMEOUT = 10;
const u32 THREAD_TIMEOUT_USEC = 1000000;
}
evdev_joystick_handler::evdev_joystick_handler() {} evdev_joystick_handler::evdev_joystick_handler() {}
evdev_joystick_handler::~evdev_joystick_handler() { Close(); } evdev_joystick_handler::~evdev_joystick_handler() { Close(); }
void evdev_joystick_handler::Init(const u32 max_connect) bool evdev_joystick_handler::Init()
{ {
std::memset(&m_info, 0, sizeof m_info);
g_evdev_joystick_config.load(); g_evdev_joystick_config.load();
axistrigger = static_cast<bool>(g_evdev_joystick_config.axistrigger); axistrigger = static_cast<bool>(g_evdev_joystick_config.axistrigger);
@ -40,90 +30,13 @@ void evdev_joystick_handler::Init(const u32 max_connect)
revaxis.emplace_back(g_evdev_joystick_config.rxreverse); revaxis.emplace_back(g_evdev_joystick_config.rxreverse);
revaxis.emplace_back(g_evdev_joystick_config.ryreverse); revaxis.emplace_back(g_evdev_joystick_config.ryreverse);
fs::dir devdir{"/dev/input/"}; return true;
fs::dir_entry et;
while (devdir.read(et))
{
// Check if the entry starts with event (a 5-letter word)
if (et.name.size() > 5 && et.name.compare(0, 5,"event") == 0)
{
int fd = open(("/dev/input/" + et.name).c_str(), O_RDONLY|O_NONBLOCK);
struct libevdev *dev = NULL;
int rc = 1;
rc = libevdev_new_from_fd(fd, &dev);
if (rc < 0)
{
// If it's just a bad file descriptor, don't bother logging, but otherwise, log it.
if (rc == -9)
LOG_WARNING(GENERAL, "Failed to connect to device at %s, the error was: %s", "/dev/input/" + et.name, strerror(-rc));
continue;
}
if (libevdev_has_event_type(dev, EV_KEY) &&
libevdev_has_event_code(dev, EV_ABS, ABS_X) &&
libevdev_has_event_code(dev, EV_ABS, ABS_Y))
{
// It's a joystick.
joy_paths.emplace_back(fmt::format("/dev/input/%s", et.name));
}
}
}
m_info.max_connect = std::min(max_connect, static_cast<u32>(joy_paths.size()));
for (u32 i = 0; i < m_info.max_connect; ++i)
{
joy_devs.push_back(nullptr);
joy_axis_maps.emplace_back(ABS_RZ - ABS_X, -1);
joy_axis.emplace_back(ABS_RZ - ABS_X, -1);
joy_button_maps.emplace_back(KEY_MAX - BTN_JOYSTICK, -1);
joy_hat_ids.emplace_back(-1);
m_pads.emplace_back(
CELL_PAD_STATUS_DISCONNECTED,
CELL_PAD_SETTING_PRESS_OFF | CELL_PAD_SETTING_SENSOR_OFF,
CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE,
CELL_PAD_DEV_TYPE_STANDARD
);
auto& pad = m_pads.back();
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_evdev_joystick_config.triangle, CELL_PAD_CTRL_TRIANGLE);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_evdev_joystick_config.circle, CELL_PAD_CTRL_CIRCLE);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_evdev_joystick_config.cross, CELL_PAD_CTRL_CROSS);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_evdev_joystick_config.square, CELL_PAD_CTRL_SQUARE);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_evdev_joystick_config.l2, CELL_PAD_CTRL_L2);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_evdev_joystick_config.r2, CELL_PAD_CTRL_R2);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_evdev_joystick_config.l1, CELL_PAD_CTRL_L1);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_evdev_joystick_config.r1, CELL_PAD_CTRL_R1);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_evdev_joystick_config.start, CELL_PAD_CTRL_START);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_evdev_joystick_config.select, CELL_PAD_CTRL_SELECT);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_evdev_joystick_config.l3, CELL_PAD_CTRL_L3);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_evdev_joystick_config.r3, CELL_PAD_CTRL_R3);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_evdev_joystick_config.up, CELL_PAD_CTRL_UP);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_evdev_joystick_config.down, CELL_PAD_CTRL_DOWN);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_evdev_joystick_config.left, CELL_PAD_CTRL_LEFT);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_evdev_joystick_config.right, CELL_PAD_CTRL_RIGHT);
pad.m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X+g_evdev_joystick_config.lxstick, 0, 0);
pad.m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X+g_evdev_joystick_config.lystick, 0, 0);
pad.m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X+g_evdev_joystick_config.rxstick, 0, 0);
pad.m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X+g_evdev_joystick_config.rystick, 0, 0);
}
update_devs();
active.store(true);
joy_thread.reset(new std::thread(std::bind(&evdev_joystick_handler::thread_func, this)));
} }
void evdev_joystick_handler::update_devs() void evdev_joystick_handler::update_devs()
{ {
int connected=0; for (u32 i = 0; i < joy_devs.size(); ++i)
try_open_dev(i);
for (u32 i = 0; i < m_info.max_connect; ++i)
if (try_open_dev(i)) ++connected;
m_info.now_connect = connected;
} }
inline u16 Clamp0To255(f32 input) inline u16 Clamp0To255(f32 input)
@ -169,14 +82,14 @@ bool evdev_joystick_handler::try_open_dev(u32 index)
if (was_connected) if (was_connected)
{ {
// It was disconnected. // It was disconnected.
m_pads[index].m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES; pads[index]->m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES;
int fd = libevdev_get_fd(dev); int fd = libevdev_get_fd(dev);
libevdev_free(dev); libevdev_free(dev);
close(fd); close(fd);
dev = nullptr; dev = nullptr;
} }
m_pads[index].m_port_status &= ~CELL_PAD_STATUS_CONNECTED; pads[index]->m_port_status &= ~CELL_PAD_STATUS_CONNECTED;
LOG_ERROR(GENERAL, "Joystick %s is not present or accessible [previous status: %d]", path.c_str(), LOG_ERROR(GENERAL, "Joystick %s is not present or accessible [previous status: %d]", path.c_str(),
was_connected ? 1 : 0); was_connected ? 1 : 0);
return false; return false;
@ -203,8 +116,8 @@ bool evdev_joystick_handler::try_open_dev(u32 index)
if (!was_connected) if (!was_connected)
// Connection status changed from disconnected to connected. // Connection status changed from disconnected to connected.
m_pads[index].m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES; pads[index]->m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES;
m_pads[index].m_port_status |= CELL_PAD_STATUS_CONNECTED; pads[index]->m_port_status |= CELL_PAD_STATUS_CONNECTED;
int buttons=0; int buttons=0;
for (int i=BTN_JOYSTICK; i<KEY_MAX; i++) for (int i=BTN_JOYSTICK; i<KEY_MAX; i++)
@ -244,19 +157,6 @@ bool evdev_joystick_handler::try_open_dev(u32 index)
void evdev_joystick_handler::Close() void evdev_joystick_handler::Close()
{ {
if (active.load())
{
active.store(false);
if (!dead.load())
{
usleep(THREAD_TIMEOUT_USEC);
if (!dead.load())
LOG_ERROR(GENERAL, "EvdevJoystick thread could not stop within %d microseconds", THREAD_TIMEOUT_USEC);
}
}
joy_thread->detach();
for (auto& dev : joy_devs) for (auto& dev : joy_devs)
{ {
if (dev != nullptr) if (dev != nullptr)
@ -290,15 +190,149 @@ int evdev_joystick_handler::scale_axis(int axis, int value)
} }
} }
void evdev_joystick_handler::thread_func() std::vector<std::string> evdev_joystick_handler::ListDevices()
{ {
while (active) Init();
std::vector<std::string> evdev_joystick_list;
fs::dir devdir{"/dev/input/"};
fs::dir_entry et;
while (devdir.read(et))
{ {
// Check if the entry starts with event (a 5-letter word)
if (et.name.size() > 5 && et.name.compare(0, 5,"event") == 0)
{
int fd = open(("/dev/input/" + et.name).c_str(), O_RDONLY|O_NONBLOCK);
struct libevdev *dev = NULL;
int rc = 1;
rc = libevdev_new_from_fd(fd, &dev);
if (rc < 0)
{
// If it's just a bad file descriptor, don't bother logging, but otherwise, log it.
if (rc != -9)
LOG_WARNING(GENERAL, "Failed to connect to device at %s, the error was: %s", "/dev/input/" + et.name, strerror(-rc));
libevdev_free(dev);
close(fd);
continue;
}
if (libevdev_has_event_type(dev, EV_KEY) &&
libevdev_has_event_code(dev, EV_ABS, ABS_X) &&
libevdev_has_event_code(dev, EV_ABS, ABS_Y))
{
// It's a joystick.
evdev_joystick_list.push_back(libevdev_get_name(dev));
}
libevdev_free(dev);
close(fd);
}
}
return evdev_joystick_list;
}
bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device)
{
Init();
// Now we need to find the device with the same name, and make sure not to grab any duplicates.
fs::dir devdir{"/dev/input/"};
fs::dir_entry et;
while (devdir.read(et))
{
// Check if the entry starts with event (a 5-letter word)
if (et.name.size() > 5 && et.name.compare(0, 5,"event") == 0)
{
int fd = open(("/dev/input/" + et.name).c_str(), O_RDONLY|O_NONBLOCK);
struct libevdev *dev = NULL;
int rc = 1;
rc = libevdev_new_from_fd(fd, &dev);
if (rc < 0)
{
// If it's just a bad file descriptor, don't bother logging, but otherwise, log it.
if (rc != -9)
LOG_WARNING(GENERAL, "Failed to connect to device at %s, the error was: %s", "/dev/input/" + et.name, strerror(-rc));
libevdev_free(dev);
close(fd);
continue;
}
const std::string name = libevdev_get_name(dev);
if (libevdev_has_event_type(dev, EV_KEY) &&
libevdev_has_event_code(dev, EV_ABS, ABS_X) &&
libevdev_has_event_code(dev, EV_ABS, ABS_Y) &&
name == device)
{
// It's a joystick.
// Now let's make sure we don't already have this one.
bool alreadyIn = false;
for (int i = 0; i < joy_paths.size(); i++)
if (joy_paths[i] == fmt::format("/dev/input/%s", et.name))
{
alreadyIn = true;
break;
}
if (alreadyIn == true)
{
libevdev_free(dev);
close(fd);
continue;
}
// Alright, now that we've confirmed we haven't added this joystick yet, les do dis.
joy_paths.emplace_back(fmt::format("/dev/input/%s", et.name));
}
libevdev_free(dev);
close(fd);
}
}
joy_devs.push_back(nullptr);
joy_axis_maps.emplace_back(ABS_RZ - ABS_X, -1);
joy_axis.emplace_back(ABS_RZ - ABS_X, -1);
joy_button_maps.emplace_back(KEY_MAX - BTN_JOYSTICK, -1);
joy_hat_ids.emplace_back(-1);
pad->Init(
CELL_PAD_STATUS_DISCONNECTED,
CELL_PAD_SETTING_PRESS_OFF | CELL_PAD_SETTING_SENSOR_OFF,
CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE,
CELL_PAD_DEV_TYPE_STANDARD
);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_evdev_joystick_config.triangle, CELL_PAD_CTRL_TRIANGLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_evdev_joystick_config.circle, CELL_PAD_CTRL_CIRCLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_evdev_joystick_config.cross, CELL_PAD_CTRL_CROSS);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_evdev_joystick_config.square, CELL_PAD_CTRL_SQUARE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_evdev_joystick_config.l2, CELL_PAD_CTRL_L2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_evdev_joystick_config.r2, CELL_PAD_CTRL_R2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_evdev_joystick_config.l1, CELL_PAD_CTRL_L1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_evdev_joystick_config.r1, CELL_PAD_CTRL_R1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_evdev_joystick_config.start, CELL_PAD_CTRL_START);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_evdev_joystick_config.select, CELL_PAD_CTRL_SELECT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_evdev_joystick_config.l3, CELL_PAD_CTRL_L3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_evdev_joystick_config.r3, CELL_PAD_CTRL_R3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_evdev_joystick_config.up, CELL_PAD_CTRL_UP);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_evdev_joystick_config.down, CELL_PAD_CTRL_DOWN);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_evdev_joystick_config.left, CELL_PAD_CTRL_LEFT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_evdev_joystick_config.right, CELL_PAD_CTRL_RIGHT);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X+g_evdev_joystick_config.lxstick, 0, 0);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X+g_evdev_joystick_config.lystick, 0, 0);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X+g_evdev_joystick_config.rxstick, 0, 0);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X+g_evdev_joystick_config.rystick, 0, 0);
pad->m_vibrateMotors.emplace_back(true, 0);
pad->m_vibrateMotors.emplace_back(false, 0);
pads.emplace_back(pad);
update_devs();
return true;
}
void evdev_joystick_handler::ThreadProc()
{
update_devs(); update_devs();
for (int i=0; i<joy_devs.size(); i++) for (int i=0; i<joy_devs.size(); i++)
{ {
auto& pad = m_pads[i]; auto pad = pads[i];
auto& dev = joy_devs[i]; auto& dev = joy_devs[i];
if (dev == nullptr) continue; if (dev == nullptr) continue;
@ -345,9 +379,9 @@ void evdev_joystick_handler::thread_func()
} }
auto which_button = std::find_if( auto which_button = std::find_if(
pad.m_buttons.begin(), pad.m_buttons.end(), pad->m_buttons.begin(), pad->m_buttons.end(),
[&](const Button& bt) { return bt.m_keyCode == button_code; }); [&](const Button& bt) { return bt.m_keyCode == button_code; });
if (which_button == pad.m_buttons.end()) if (which_button == pad->m_buttons.end())
{ {
LOG_ERROR(GENERAL, "Joystick #%d sent button event for unmapped button %d", i, evt.code); LOG_ERROR(GENERAL, "Joystick #%d sent button event for unmapped button %d", i, evt.code);
break; break;
@ -370,7 +404,7 @@ void evdev_joystick_handler::thread_func()
int source_axis = hat == joy_hat_ids[i] ? EVDEV_DPAD_HAT_AXIS_X : EVDEV_DPAD_HAT_AXIS_Y; int source_axis = hat == joy_hat_ids[i] ? EVDEV_DPAD_HAT_AXIS_X : EVDEV_DPAD_HAT_AXIS_Y;
for (Button& bt : pad.m_buttons) for (Button& bt : pad->m_buttons)
{ {
if (bt.m_keyCode != source_axis) continue; if (bt.m_keyCode != source_axis) continue;
@ -419,9 +453,9 @@ void evdev_joystick_handler::thread_func()
} }
auto which_button = std::find_if( auto which_button = std::find_if(
pad.m_buttons.begin(), pad.m_buttons.end(), pad->m_buttons.begin(), pad->m_buttons.end(),
[&](const Button& bt) { return bt.m_outKeyCode == which_trigger; }); [&](const Button& bt) { return bt.m_outKeyCode == which_trigger; });
if (which_button == pad.m_buttons.end()) if (which_button == pad->m_buttons.end())
{ {
LOG_ERROR(GENERAL, "Joystick #%d's pad has no trigger %d", i, which_trigger); LOG_ERROR(GENERAL, "Joystick #%d's pad has no trigger %d", i, which_trigger);
break; break;
@ -435,7 +469,7 @@ void evdev_joystick_handler::thread_func()
{ {
int axis = joy_axis_maps[i][evt.code - ABS_X]; int axis = joy_axis_maps[i][evt.code - ABS_X];
if (axis > pad.m_sticks.size()) if (axis > pad->m_sticks.size())
{ {
LOG_ERROR(GENERAL, "Joystick #%d sent axis event for invalid axis %d", i, axis); LOG_ERROR(GENERAL, "Joystick #%d sent axis event for invalid axis %d", i, axis);
break; break;
@ -448,25 +482,25 @@ void evdev_joystick_handler::thread_func()
{ {
int Xaxis = joy_axis_maps[i][ABS_X]; int Xaxis = joy_axis_maps[i][ABS_X];
int Yaxis = joy_axis_maps[i][ABS_Y]; int Yaxis = joy_axis_maps[i][ABS_Y];
pad.m_sticks[Xaxis].m_value = scale_axis(ABS_X, joy_axis[i][Xaxis]); pad->m_sticks[Xaxis].m_value = scale_axis(ABS_X, joy_axis[i][Xaxis]);
pad.m_sticks[Yaxis].m_value = scale_axis(ABS_Y, joy_axis[i][Yaxis]); pad->m_sticks[Yaxis].m_value = scale_axis(ABS_Y, joy_axis[i][Yaxis]);
std::tie(pad.m_sticks[Xaxis].m_value, pad.m_sticks[Yaxis].m_value) = std::tie(pad->m_sticks[Xaxis].m_value, pad->m_sticks[Yaxis].m_value) =
ConvertToSquirclePoint(pad.m_sticks[Xaxis].m_value, pad.m_sticks[Yaxis].m_value); ConvertToSquirclePoint(pad->m_sticks[Xaxis].m_value, pad->m_sticks[Yaxis].m_value);
} }
else else
{ {
int Xaxis = joy_axis_maps[i][ABS_RX]; int Xaxis = joy_axis_maps[i][ABS_RX];
int Yaxis = joy_axis_maps[i][ABS_RY]; int Yaxis = joy_axis_maps[i][ABS_RY];
pad.m_sticks[Xaxis].m_value = scale_axis(ABS_RX, joy_axis[i][Xaxis]); pad->m_sticks[Xaxis].m_value = scale_axis(ABS_RX, joy_axis[i][Xaxis]);
pad.m_sticks[Yaxis].m_value = scale_axis(ABS_RY, joy_axis[i][Yaxis]); pad->m_sticks[Yaxis].m_value = scale_axis(ABS_RY, joy_axis[i][Yaxis]);
std::tie(pad.m_sticks[Xaxis].m_value, pad.m_sticks[Yaxis].m_value) = std::tie(pad->m_sticks[Xaxis].m_value, pad->m_sticks[Yaxis].m_value) =
ConvertToSquirclePoint(pad.m_sticks[Xaxis].m_value, pad.m_sticks[Yaxis].m_value); ConvertToSquirclePoint(pad->m_sticks[Xaxis].m_value, pad->m_sticks[Yaxis].m_value);
} }
} }
else else
pad.m_sticks[axis].m_value = scale_axis(evt.code, evt.value); pad->m_sticks[axis].m_value = scale_axis(evt.code, evt.value);
} }
break; break;
default: default:
@ -474,12 +508,6 @@ void evdev_joystick_handler::thread_func()
break; break;
} }
} }
int to_sleep = m_info.now_connect > 0 ? THREAD_SLEEP_USEC : THREAD_SLEEP_INACTIVE_USEC;
usleep(to_sleep);
}
dead = true;
} }
#endif #endif

View File

@ -70,7 +70,10 @@ public:
evdev_joystick_handler(); evdev_joystick_handler();
~evdev_joystick_handler(); ~evdev_joystick_handler();
void Init(const u32 max_connect) override; bool Init() override;
std::vector<std::string> ListDevices() override;
bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) override;
void ThreadProc() override;
void Close(); void Close();
private: private:
@ -78,11 +81,9 @@ private:
std::tuple<u16, u16> ConvertToSquirclePoint(u16 inX, u16 inY); std::tuple<u16, u16> ConvertToSquirclePoint(u16 inX, u16 inY);
bool try_open_dev(u32 index); bool try_open_dev(u32 index);
int scale_axis(int axis, int value); int scale_axis(int axis, int value);
void thread_func();
std::unique_ptr<std::thread> joy_thread;
mutable atomic_t<bool> active{false}, dead{false};
std::vector<std::string> joy_paths; std::vector<std::string> joy_paths;
std::vector<std::shared_ptr<Pad>> pads;
std::vector<libevdev*> joy_devs; std::vector<libevdev*> joy_devs;
std::vector<std::vector<int>> joy_button_maps; std::vector<std::vector<int>> joy_button_maps;
std::vector<std::vector<int>> joy_axis_maps; std::vector<std::vector<int>> joy_axis_maps;

View File

@ -4,20 +4,79 @@
#include <QApplication> #include <QApplication>
#include "rpcs3qt/pad_settings_dialog.h"
keyboard_pad_config g_kbpad_config; keyboard_pad_config g_kbpad_config;
void keyboard_pad_handler::Init(const u32 max_connect) bool keyboard_pad_handler::Init()
{ {
memset(&m_info, 0, sizeof(PadInfo)); return true;
m_info.max_connect = max_connect;
LoadSettings();
m_info.now_connect = std::min(m_pads.size(), (size_t)max_connect);
} }
keyboard_pad_handler::keyboard_pad_handler() : QObject() keyboard_pad_handler::keyboard_pad_handler() : QObject()
{ {
b_has_config = true;
} }
void keyboard_pad_handler::ConfigController(std::string device)
{
pad_settings_dialog dlg(this);
dlg.exec();
}
void keyboard_pad_handler::Key(const u32 code, bool pressed, u16 value)
{
for (auto pad : bindings)
{
for (Button& button : pad->m_buttons)
{
if (button.m_keyCode != code)
continue;
if (value >= 256) { value = 255; }
//Todo: Is this flush necessary once games hit decent speeds?
if (button.m_pressed && !pressed)
{
button.m_flush = true;
}
else
{
button.m_pressed = pressed;
if (pressed)
button.m_value = value;
else
button.m_value = 0;
}
}
for (AnalogStick& stick : pad->m_sticks)
{
if (stick.m_keyCodeMax != code && stick.m_keyCodeMin != code)
continue;
//slightly less hack job for key based analog stick
// should also fix/make transitions when using keys smoother
// the logic here is that when a key is released,
// if we are at the opposite end of the axis, dont reset to middle
if (stick.m_keyCodeMax == code)
{
if (pressed) stick.m_value = 255;
else if (stick.m_value == 0) stick.m_value = 0;
else stick.m_value = 128;
}
if (stick.m_keyCodeMin == code)
{
if (pressed) stick.m_value = 0;
else if (stick.m_value == 255) stick.m_value = 255;
else stick.m_value = 128;
}
}
}
}
bool keyboard_pad_handler::eventFilter(QObject* target, QEvent* ev) bool keyboard_pad_handler::eventFilter(QObject* target, QEvent* ev)
{ {
// !m_target is for future proofing when gsrender isn't automatically initialized on load. // !m_target is for future proofing when gsrender isn't automatically initialized on load.
@ -108,37 +167,56 @@ void keyboard_pad_handler::keyReleaseEvent(QKeyEvent* event)
event->ignore(); event->ignore();
} }
void keyboard_pad_handler::LoadSettings() std::vector<std::string> keyboard_pad_handler::ListDevices()
{ {
std::vector<std::string> list_devices;
list_devices.push_back("Keyboard");
return list_devices;
}
bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device)
{
if (device != "Keyboard") return false;
g_kbpad_config.load(); g_kbpad_config.load();
//Fixed assign change, default is both sensor and press off //Fixed assign change, default is both sensor and press off
m_pads.emplace_back( pad->Init(
CELL_PAD_STATUS_CONNECTED | CELL_PAD_STATUS_ASSIGN_CHANGES, CELL_PAD_STATUS_CONNECTED | CELL_PAD_STATUS_ASSIGN_CHANGES,
CELL_PAD_SETTING_PRESS_OFF | CELL_PAD_SETTING_SENSOR_OFF, CELL_PAD_SETTING_PRESS_OFF | CELL_PAD_SETTING_SENSOR_OFF,
CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE, CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE,
CELL_PAD_DEV_TYPE_STANDARD); CELL_PAD_DEV_TYPE_STANDARD
);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.left, CELL_PAD_CTRL_LEFT); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.left, CELL_PAD_CTRL_LEFT);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.down, CELL_PAD_CTRL_DOWN); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.down, CELL_PAD_CTRL_DOWN);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.right, CELL_PAD_CTRL_RIGHT); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.right, CELL_PAD_CTRL_RIGHT);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.up, CELL_PAD_CTRL_UP); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.up, CELL_PAD_CTRL_UP);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.start, CELL_PAD_CTRL_START); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.start, CELL_PAD_CTRL_START);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.r3, CELL_PAD_CTRL_R3); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.r3, CELL_PAD_CTRL_R3);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.l3, CELL_PAD_CTRL_L3); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.l3, CELL_PAD_CTRL_L3);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.select, CELL_PAD_CTRL_SELECT); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.select, CELL_PAD_CTRL_SELECT);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.square, CELL_PAD_CTRL_SQUARE); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.square, CELL_PAD_CTRL_SQUARE);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.cross, CELL_PAD_CTRL_CROSS); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.cross, CELL_PAD_CTRL_CROSS);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.circle, CELL_PAD_CTRL_CIRCLE); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.circle, CELL_PAD_CTRL_CIRCLE);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.triangle, CELL_PAD_CTRL_TRIANGLE); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.triangle, CELL_PAD_CTRL_TRIANGLE);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.r1, CELL_PAD_CTRL_R1); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.r1, CELL_PAD_CTRL_R1);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.l1, CELL_PAD_CTRL_L1); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.l1, CELL_PAD_CTRL_L1);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.r2, CELL_PAD_CTRL_R2); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.r2, CELL_PAD_CTRL_R2);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.l2, CELL_PAD_CTRL_L2); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.l2, CELL_PAD_CTRL_L2);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, g_kbpad_config.left_stick_left, g_kbpad_config.left_stick_right);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, g_kbpad_config.left_stick_up, g_kbpad_config.left_stick_down);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, g_kbpad_config.right_stick_left, g_kbpad_config.right_stick_right);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, g_kbpad_config.right_stick_up, g_kbpad_config.right_stick_down);
bindings.push_back(pad);
return true;
}
void keyboard_pad_handler::ThreadProc()
{
m_pads[0].m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, g_kbpad_config.left_stick_left, g_kbpad_config.left_stick_right);
m_pads[0].m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, g_kbpad_config.left_stick_up, g_kbpad_config.left_stick_down);
m_pads[0].m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, g_kbpad_config.right_stick_left, g_kbpad_config.right_stick_right);
m_pads[0].m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, g_kbpad_config.right_stick_up, g_kbpad_config.right_stick_down);
} }

View File

@ -56,16 +56,25 @@ struct keyboard_pad_config final : cfg::node
class keyboard_pad_handler final : public QObject, public PadHandlerBase class keyboard_pad_handler final : public QObject, public PadHandlerBase
{ {
public: public:
virtual void Init(const u32 max_connect) override; bool Init() override;
keyboard_pad_handler(); keyboard_pad_handler();
void SetTargetWindow(QWindow* target); void SetTargetWindow(QWindow* target);
void keyPressEvent(QKeyEvent* event); void keyPressEvent(QKeyEvent* event);
void keyReleaseEvent(QKeyEvent* event); void keyReleaseEvent(QKeyEvent* event);
void LoadSettings();
bool eventFilter(QObject* obj, QEvent* ev) override; bool eventFilter(QObject* obj, QEvent* ev) override;
std::vector<std::string> ListDevices() override;
bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) override;
void ThreadProc() override;
void ConfigController(std::string device) override;
protected:
void Key(const u32 code, bool pressed, u16 value = 255);
private: private:
QWindow* m_target = nullptr; QWindow* m_target = nullptr;
std::vector<std::shared_ptr<Pad>> bindings;
}; };

View File

@ -16,17 +16,18 @@ namespace {
} }
mm_joystick_handler::mm_joystick_handler() : active(false), thread(nullptr) mm_joystick_handler::mm_joystick_handler() : is_init(false)
{ {
} }
mm_joystick_handler::~mm_joystick_handler() mm_joystick_handler::~mm_joystick_handler()
{ {
Close();
} }
void mm_joystick_handler::Init(const u32 max_connect) bool mm_joystick_handler::Init()
{ {
if (is_init) return true;
supportedJoysticks = joyGetNumDevs(); supportedJoysticks = joyGetNumDevs();
if (supportedJoysticks > 0) if (supportedJoysticks > 0)
{ {
@ -36,141 +37,120 @@ void mm_joystick_handler::Init(const u32 max_connect)
{ {
LOG_ERROR(GENERAL, "Driver doesn't support Joysticks"); LOG_ERROR(GENERAL, "Driver doesn't support Joysticks");
} }
js_info.dwSize = sizeof(js_info); js_info.dwSize = sizeof(js_info);
js_info.dwFlags = JOY_RETURNALL; js_info.dwFlags = JOY_RETURNALL;
joyGetDevCaps(JOYSTICKID1, &js_caps, sizeof(js_caps)); joyGetDevCaps(JOYSTICKID1, &js_caps, sizeof(js_caps));
bool JoyPresent = (joyGetPosEx(JOYSTICKID1, &js_info) == JOYERR_NOERROR); bool JoyPresent = (joyGetPosEx(JOYSTICKID1, &js_info) == JOYERR_NOERROR);
if (JoyPresent) if (!JoyPresent)
{ {
LOG_NOTICE(GENERAL, "Found connected joystick with %u buttons and %u axes", js_caps.wNumButtons,js_caps.wNumAxes); LOG_ERROR(GENERAL, "Joystick not found");
LOG_NOTICE(GENERAL, "Axes info %u %u %u %u %u %u %u %u", js_caps.wXmin, js_caps.wXmax,js_caps.wYmin,js_caps.wYmax,js_caps.wZmin,js_caps.wZmax,js_caps.wRmin,js_caps.wRmax); return false;
std::memset(&m_info, 0, sizeof m_info); }
m_info.max_connect = max_connect;
is_init = true;
return true;
}
std::vector<std::string> mm_joystick_handler::ListDevices()
{
std::vector<std::string> mm_pad_list;
if (!Init()) return mm_pad_list;
mm_pad_list.push_back("MMJoy Pad");
return mm_pad_list;
}
bool mm_joystick_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device)
{
if (!Init()) return false;
for (u32 i = 0, max = std::min(max_connect, u32(1)); i != max; ++i)
{
g_mmjoystick_config.load(); g_mmjoystick_config.load();
m_pads.emplace_back(
pad->Init(
CELL_PAD_STATUS_DISCONNECTED, CELL_PAD_STATUS_DISCONNECTED,
CELL_PAD_SETTING_PRESS_OFF | CELL_PAD_SETTING_SENSOR_OFF, CELL_PAD_SETTING_PRESS_OFF | CELL_PAD_SETTING_SENSOR_OFF,
CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE, CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE,
CELL_PAD_DEV_TYPE_STANDARD CELL_PAD_DEV_TYPE_STANDARD
); );
auto & pad = m_pads.back();
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_mmjoystick_config.triangle, CELL_PAD_CTRL_TRIANGLE); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_mmjoystick_config.triangle, CELL_PAD_CTRL_TRIANGLE);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_mmjoystick_config.circle, CELL_PAD_CTRL_CIRCLE); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_mmjoystick_config.circle, CELL_PAD_CTRL_CIRCLE);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_mmjoystick_config.cross, CELL_PAD_CTRL_CROSS); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_mmjoystick_config.cross, CELL_PAD_CTRL_CROSS);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_mmjoystick_config.square, CELL_PAD_CTRL_SQUARE); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_mmjoystick_config.square, CELL_PAD_CTRL_SQUARE);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_mmjoystick_config.l2, CELL_PAD_CTRL_L2); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_mmjoystick_config.l2, CELL_PAD_CTRL_L2);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_mmjoystick_config.r2, CELL_PAD_CTRL_R2); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_mmjoystick_config.r2, CELL_PAD_CTRL_R2);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_mmjoystick_config.l1, CELL_PAD_CTRL_L1); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_mmjoystick_config.l1, CELL_PAD_CTRL_L1);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_mmjoystick_config.r1, CELL_PAD_CTRL_R1); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_mmjoystick_config.r1, CELL_PAD_CTRL_R1);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_mmjoystick_config.start, CELL_PAD_CTRL_START); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_mmjoystick_config.start, CELL_PAD_CTRL_START);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_mmjoystick_config.select, CELL_PAD_CTRL_SELECT); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_mmjoystick_config.select, CELL_PAD_CTRL_SELECT);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_mmjoystick_config.l3, CELL_PAD_CTRL_L3); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_mmjoystick_config.l3, CELL_PAD_CTRL_L3);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_mmjoystick_config.r3, CELL_PAD_CTRL_R3); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_mmjoystick_config.r3, CELL_PAD_CTRL_R3);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, JOY_POVFORWARD, CELL_PAD_CTRL_UP); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, JOY_POVFORWARD, CELL_PAD_CTRL_UP);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, JOY_POVBACKWARD, CELL_PAD_CTRL_DOWN); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, JOY_POVBACKWARD, CELL_PAD_CTRL_DOWN);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, JOY_POVLEFT, CELL_PAD_CTRL_LEFT); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, JOY_POVLEFT, CELL_PAD_CTRL_LEFT);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, JOY_POVRIGHT, CELL_PAD_CTRL_RIGHT); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, JOY_POVRIGHT, CELL_PAD_CTRL_RIGHT);
pad.m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, 0, 0); pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, 0, 0);
pad.m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, 0, 0); pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, 0, 0);
pad.m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, 0, 0); pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, 0, 0);
pad.m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, 0, 0); pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, 0, 0);
active = true; bindings.push_back(pad);
thread = CreateThread(NULL, 0, &mm_joystick_handler::ThreadProcProxy, this, 0, NULL);
} return true;
}
else
{
LOG_ERROR(GENERAL, "Joystick not found");
}
} }
void mm_joystick_handler::Close() void mm_joystick_handler::ThreadProc()
{ {
if (active)
{
if (thread)
{
active = false;
if (WaitForSingleObject(thread, THREAD_TIMEOUT) != WAIT_OBJECT_0)
LOG_ERROR(GENERAL, "MMJoystick thread could not stop within %d milliseconds", (u32)THREAD_TIMEOUT);
thread = nullptr;
}
}
m_pads.clear();
}
DWORD mm_joystick_handler::ThreadProcedure()
{
// holds internal controller state change
std::array<bool, CELL_PAD_MAX_PORT_NUM> last_connection_status = {};
while (active)
{
MMRESULT status; MMRESULT status;
DWORD online = 0; DWORD online = 0;
for (DWORD i = 0; i != m_pads.size(); ++i) for (u32 i = 0; i != bindings.size(); ++i)
{ {
auto pad = bindings[i];
auto & pad = m_pads[i]; status = joyGetPosEx(JOYSTICKID1, &js_info);
status =joyGetPosEx(JOYSTICKID1, &js_info);
switch (status) switch (status)
{ {
case JOYERR_UNPLUGGED: case JOYERR_UNPLUGGED:
if (last_connection_status[i] == true) if (last_connection_status[i] == true)
pad.m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES; pad->m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES;
last_connection_status[i] = false; last_connection_status[i] = false;
pad.m_port_status &= ~CELL_PAD_STATUS_CONNECTED; pad->m_port_status &= ~CELL_PAD_STATUS_CONNECTED;
break; break;
case JOYERR_NOERROR: case JOYERR_NOERROR:
++online; ++online;
if (last_connection_status[i] == false) if (last_connection_status[i] == false)
pad.m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES; pad->m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES;
last_connection_status[i] = true; last_connection_status[i] = true;
pad.m_port_status |= CELL_PAD_STATUS_CONNECTED; pad->m_port_status |= CELL_PAD_STATUS_CONNECTED;
for (DWORD j = 0; j <= 12; j++) for (DWORD j = 0; j <= 12; j++)
{ {
bool pressed = js_info.dwButtons & pad.m_buttons[j].m_keyCode; bool pressed = js_info.dwButtons & pad->m_buttons[j].m_keyCode;
pad.m_buttons[j].m_pressed = pressed; pad->m_buttons[j].m_pressed = pressed;
pad.m_buttons[j].m_value = pressed ? 255 : 0; pad->m_buttons[j].m_value = pressed ? 255 : 0;
} }
for (DWORD j = 13; j <= 16; j++)//POV aka digital pad for (DWORD j = 13; j <= 16; j++)//POV aka digital pad
{ {
bool pressed = js_info.dwPOV == pad.m_buttons[j].m_keyCode; bool pressed = js_info.dwPOV == pad->m_buttons[j].m_keyCode;
pad.m_buttons[j].m_pressed = pressed; pad->m_buttons[j].m_pressed = pressed;
pad.m_buttons[j].m_value = pressed ? 255 : 0; pad->m_buttons[j].m_value = pressed ? 255 : 0;
} }
pad.m_sticks[0].m_value = ConvertAxis(js_info.dwXpos); pad->m_sticks[0].m_value = ConvertAxis(js_info.dwXpos);
pad.m_sticks[1].m_value = ConvertAxis(js_info.dwYpos); pad->m_sticks[1].m_value = ConvertAxis(js_info.dwYpos);
pad.m_sticks[2].m_value = ConvertAxis(js_info.dwZpos); pad->m_sticks[2].m_value = ConvertAxis(js_info.dwZpos);
pad.m_sticks[3].m_value = ConvertAxis(js_info.dwRpos); pad->m_sticks[3].m_value = ConvertAxis(js_info.dwRpos);
break; break;
} }
} }
Sleep((online > 0) ? THREAD_SLEEP : THREAD_SLEEP_INACTIVE);
m_info.now_connect = online;
}
return 0;
}
DWORD WINAPI mm_joystick_handler::ThreadProcProxy(LPVOID parameter)
{
return reinterpret_cast<mm_joystick_handler *>(parameter)->ThreadProcedure();
} }
#endif #endif

View File

@ -56,17 +56,19 @@ public:
mm_joystick_handler(); mm_joystick_handler();
~mm_joystick_handler(); ~mm_joystick_handler();
void Init(const u32 max_connect) override; bool Init() override;
void Close();
std::vector<std::string> ListDevices() override;
private: bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) override;
DWORD ThreadProcedure(); void ThreadProc() override;
static DWORD WINAPI ThreadProcProxy(LPVOID parameter);
private: private:
bool is_init;
u32 supportedJoysticks; u32 supportedJoysticks;
mutable bool active;
HANDLE thread;
JOYINFOEX js_info; JOYINFOEX js_info;
JOYCAPS js_caps; JOYCAPS js_caps;
std::vector<std::shared_ptr<Pad>> bindings;
std::array<bool, 7> last_connection_status = {};
}; };

121
rpcs3/pad_thread.cpp Normal file
View File

@ -0,0 +1,121 @@
#include "pad_thread.h"
#include "rpcs3qt/gamepads_settings_dialog.h"
#include "../ds4_pad_handler.h"
#ifdef _WIN32
#include "../xinput_pad_handler.h"
#include "../mm_joystick_handler.h"
#elif HAVE_LIBEVDEV
#include "../evdev_joystick_handler.h"
#endif
#include "../keyboard_pad_handler.h"
#include "../Emu/Io/Null/NullPadHandler.h"
pad_thread::pad_thread(void *_curthread, void *_curwindow) : curthread(_curthread), curwindow(_curwindow)
{
}
pad_thread::~pad_thread()
{
active = false;
thread->join();
handlers.clear();
}
void pad_thread::Init(const u32 max_connect)
{
std::memset(&m_info, 0, sizeof(m_info));
m_info.max_connect = max_connect;
m_info.now_connect = std::min(max_connect, (u32)7); // max 7 pads
input_cfg.load();
std::shared_ptr<keyboard_pad_handler> keyptr;
//Always have a Null Pad Handler
std::shared_ptr<NullPadHandler> nullpad = std::make_shared<NullPadHandler>();
handlers.emplace(pad_handler::null, nullpad);
for (u32 i = 0; i < m_info.now_connect; i++)
{
std::shared_ptr<PadHandlerBase> cur_pad_handler;
if (handlers.count(input_cfg.player_input[i]) != 0)
{
cur_pad_handler = handlers[input_cfg.player_input[i]];
}
else
{
switch (input_cfg.player_input[i])
{
case pad_handler::keyboard:
keyptr = std::make_shared<keyboard_pad_handler>();
keyptr->moveToThread((QThread *)curthread);
keyptr->SetTargetWindow((QWindow *)curwindow);
cur_pad_handler = keyptr;
break;
case pad_handler::ds4:
cur_pad_handler = std::make_shared<ds4_pad_handler>();
break;
#ifdef _MSC_VER
case pad_handler::xinput:
cur_pad_handler = std::make_shared<xinput_pad_handler>();
break;
#endif
#ifdef _WIN32
case pad_handler::mm:
cur_pad_handler = std::make_shared<mm_joystick_handler>();
break;
#endif
#ifdef HAVE_LIBEVDEV
case pad_handler::evdev:
cur_pad_handler = std::make_shared<evdev_joystick_handler>();
break;
#endif
}
handlers.emplace(input_cfg.player_input[i], cur_pad_handler);
}
cur_pad_handler->Init();
m_pads.push_back(std::make_shared<Pad>(
CELL_PAD_STATUS_DISCONNECTED,
CELL_PAD_SETTING_PRESS_OFF | CELL_PAD_SETTING_SENSOR_OFF,
CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_ACTUATOR,
CELL_PAD_DEV_TYPE_STANDARD));
if (cur_pad_handler->bindPadToDevice(m_pads.back(), input_cfg.player_device[i]->to_string()) == false)
{
//Failed to bind the device to cur_pad_handler so binds to NullPadHandler
LOG_ERROR(GENERAL, "Failed to bind device %s to handler %s", input_cfg.player_device[i]->to_string(), input_cfg.player_input[i].to_string());
nullpad->bindPadToDevice(m_pads.back(), input_cfg.player_device[i]->to_string());
}
}
thread = std::make_shared<std::thread>(&pad_thread::ThreadFunc, this);
}
void pad_thread::SetRumble(const u32 pad, u8 largeMotor, bool smallMotor) {
if (pad > m_pads.size())
return;
if (m_pads[pad]->m_vibrateMotors.size() >= 2)
{
m_pads[pad]->m_vibrateMotors[0].m_value = largeMotor;
m_pads[pad]->m_vibrateMotors[1].m_value = smallMotor ? 255 : 0;
}
}
void pad_thread::ThreadFunc()
{
active = true;
while (active)
{
for (auto& cur_pad_handler : handlers)
{
cur_pad_handler.second->ThreadProc();
}
std::this_thread::sleep_for(1ms);
}
}

43
rpcs3/pad_thread.h Normal file
View File

@ -0,0 +1,43 @@
#pragma once
#include <map>
#include <thread>
#include "Emu/System.h"
#include "../Utilities/types.h"
#include "Emu/Io/PadHandler.h"
struct PadInfo
{
u32 max_connect;
u32 now_connect;
u32 system_info;
};
class pad_thread
{
public:
pad_thread(void *_curthread, void *_curwindow); //void * instead of QThread * and QWindow * because of include in emucore
~pad_thread();
void Init(const u32 max_connect);
PadInfo& GetInfo() { return m_info; }
std::vector<std::shared_ptr<Pad>>& GetPads() { return m_pads; }
void SetRumble(const u32 pad, u8 largeMotor, bool smallMotor);
protected:
void ThreadFunc();
//List of all handlers
std::map<pad_handler, std::shared_ptr<PadHandlerBase>> handlers;
//Used for pad_handler::keyboard
void *curthread;
void *curwindow;
PadInfo m_info;
std::vector<std::shared_ptr<Pad>> m_pads;
bool active;
std::shared_ptr<std::thread> thread;
};

View File

@ -347,6 +347,7 @@
<ClCompile Include="keyboard_pad_handler.cpp" /> <ClCompile Include="keyboard_pad_handler.cpp" />
<ClCompile Include="main.cpp" /> <ClCompile Include="main.cpp" />
<ClCompile Include="mm_joystick_handler.cpp" /> <ClCompile Include="mm_joystick_handler.cpp" />
<ClCompile Include="pad_thread.cpp" />
<ClCompile Include="QTGeneratedFiles\Debug - LLVM\moc_about_dialog.cpp"> <ClCompile Include="QTGeneratedFiles\Debug - LLVM\moc_about_dialog.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@ -878,6 +879,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">true</ExcludedFromBuild>
</ClCompile> </ClCompile>
<ClCompile Include="rpcs3qt\about_dialog.cpp" /> <ClCompile Include="rpcs3qt\about_dialog.cpp" />
<ClCompile Include="rpcs3qt\gamepads_settings_dialog.cpp" />
<ClCompile Include="rpcs3qt\game_list_grid.cpp" /> <ClCompile Include="rpcs3qt\game_list_grid.cpp" />
<ClCompile Include="rpcs3qt\game_list_grid_delegate.cpp" /> <ClCompile Include="rpcs3qt\game_list_grid_delegate.cpp" />
<ClCompile Include="rpcs3qt\save_data_info_dialog.cpp" /> <ClCompile Include="rpcs3qt\save_data_info_dialog.cpp" />
@ -1220,6 +1222,7 @@
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs> <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_QUICK_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DLLVM_AVAILABLE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE "-I.\..\Vulkan\Vulkan-LoaderAndValidationLayers\include" "-I.\.." "-I.\..\3rdparty\minidx12\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtQuick" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)\." "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(NOINHERIT)\."</Command> <Command Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_QUICK_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DLLVM_AVAILABLE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE "-I.\..\Vulkan\Vulkan-LoaderAndValidationLayers\include" "-I.\.." "-I.\..\3rdparty\minidx12\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtQuick" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)\." "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(NOINHERIT)\."</Command>
</CustomBuild> </CustomBuild>
<ClInclude Include="pad_thread.h" />
<ClInclude Include="QTGeneratedFiles\ui_about_dialog.h" /> <ClInclude Include="QTGeneratedFiles\ui_about_dialog.h" />
<ClInclude Include="QTGeneratedFiles\ui_main_window.h" /> <ClInclude Include="QTGeneratedFiles\ui_main_window.h" />
<ClInclude Include="QTGeneratedFiles\ui_pad_settings_dialog.h" /> <ClInclude Include="QTGeneratedFiles\ui_pad_settings_dialog.h" />
@ -1243,6 +1246,7 @@
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs> <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_QUICK_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DLLVM_AVAILABLE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE "-I.\..\Vulkan\Vulkan-LoaderAndValidationLayers\include" "-I.\.." "-I.\..\3rdparty\minidx12\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtQuick" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)\." "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras"</Command> <Command Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_QUICK_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DLLVM_AVAILABLE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE "-I.\..\Vulkan\Vulkan-LoaderAndValidationLayers\include" "-I.\.." "-I.\..\3rdparty\minidx12\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtQuick" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)\." "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras"</Command>
</CustomBuild> </CustomBuild>
<ClInclude Include="rpcs3qt\gamepads_settings_dialog.h" />
<ClInclude Include="rpcs3qt\game_list.h" /> <ClInclude Include="rpcs3qt\game_list.h" />
<ClInclude Include="rpcs3qt\game_list_grid_delegate.h" /> <ClInclude Include="rpcs3qt\game_list_grid_delegate.h" />
<ClInclude Include="resource.h" /> <ClInclude Include="resource.h" />

View File

@ -494,6 +494,12 @@
<ClCompile Include="QTGeneratedFiles\Debug - LLVM\moc_save_manager_dialog.cpp"> <ClCompile Include="QTGeneratedFiles\Debug - LLVM\moc_save_manager_dialog.cpp">
<Filter>Generated Files\Debug - LLVM</Filter> <Filter>Generated Files\Debug - LLVM</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="pad_thread.cpp">
<Filter>Io</Filter>
</ClCompile>
<ClCompile Include="rpcs3qt\gamepads_settings_dialog.cpp">
<Filter>Gui</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="\rpcs3qt\*.h"> <ClInclude Include="\rpcs3qt\*.h">
@ -550,6 +556,12 @@
<ClInclude Include="rpcs3qt\save_data_dialog.h"> <ClInclude Include="rpcs3qt\save_data_dialog.h">
<Filter>Gui\saves</Filter> <Filter>Gui\saves</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="pad_thread.h">
<Filter>Io</Filter>
</ClInclude>
<ClInclude Include="rpcs3qt\gamepads_settings_dialog.h">
<Filter>Gui</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="debug\moc_predefs.h.cbt"> <CustomBuild Include="debug\moc_predefs.h.cbt">

View File

@ -31,6 +31,8 @@
#include "evdev_joystick_handler.h" #include "evdev_joystick_handler.h"
#endif #endif
#include "pad_thread.h"
#include "Emu/RSX/Null/NullGSRender.h" #include "Emu/RSX/Null/NullGSRender.h"
#include "Emu/RSX/GL/GLGSRender.h" #include "Emu/RSX/GL/GLGSRender.h"
@ -140,30 +142,9 @@ void rpcs3_app::InitializeCallbacks()
} }
}; };
callbacks.get_pad_handler = [this]() -> std::shared_ptr<PadHandlerBase> callbacks.get_pad_handler = [this]() -> std::shared_ptr<pad_thread>
{ {
switch (pad_handler type = g_cfg.io.pad) return std::make_shared<pad_thread>(thread(), gameWindow);
{
case pad_handler::null: return std::make_shared<NullPadHandler>();
case pad_handler::keyboard:
{
keyboard_pad_handler* ret = new keyboard_pad_handler();
ret->moveToThread(thread());
ret->SetTargetWindow(gameWindow);
return std::shared_ptr<PadHandlerBase>(ret);
}
case pad_handler::ds4: return std::make_shared<ds4_pad_handler>();
#ifdef _MSC_VER
case pad_handler::xinput: return std::make_shared<xinput_pad_handler>();
#endif
#ifdef _WIN32
case pad_handler::mm: return std::make_shared<mm_joystick_handler>();
#endif
#ifdef HAVE_LIBEVDEV
case pad_handler::evdev: return std::make_shared<evdev_joystick_handler>();
#endif
default: fmt::throw_exception("Invalid pad handler: %s", type);
}
}; };
callbacks.get_gs_frame = [this]() -> std::unique_ptr<GSFrameBase> callbacks.get_gs_frame = [this]() -> std::unique_ptr<GSFrameBase>

View File

@ -0,0 +1,229 @@
#include "gamepads_settings_dialog.h"
#include "../Emu/Io/PadHandler.h"
#include "../ds4_pad_handler.h"
#ifdef _WIN32
#include "../xinput_pad_handler.h"
#include "../mm_joystick_handler.h"
#elif HAVE_LIBEVDEV
#include "../evdev_joystick_handler.h"
#endif
#include "../keyboard_pad_handler.h"
#include "../Emu/Io/Null/NullPadHandler.h"
#include "../Emu/System.h"
input_config input_cfg;
gamepads_settings_dialog::gamepads_settings_dialog(QWidget* parent)
: QDialog(parent)
{
setWindowTitle(tr("Gamepads Settings"));
QVBoxLayout *dialog_layout = new QVBoxLayout();
QHBoxLayout *all_players = new QHBoxLayout();
input_cfg.from_default();
input_cfg.load();
auto fill_device_combo = [](QComboBox *combo)
{
std::vector<std::string> str_inputs = input_cfg.player_input[0].to_list();
for (int index = 0; index < str_inputs.size(); index++)
{
combo->addItem(str_inputs[index].c_str());
}
};
for (int i = 0; i < 7; i++)
{
QGroupBox *grp_player = new QGroupBox(QString(tr("Player %1").arg(i+1)));
QVBoxLayout *ppad_layout = new QVBoxLayout();
co_inputtype[i] = new QComboBox();
fill_device_combo(co_inputtype[i]);
ppad_layout->addWidget(co_inputtype[i]);
co_deviceID[i] = new QComboBox();
co_deviceID[i]->setEnabled(false);
ppad_layout->addWidget(co_deviceID[i]);
QHBoxLayout *button_layout = new QHBoxLayout();
bu_config[i] = new QPushButton(tr("Config"));
bu_config[i]->setEnabled(false);
button_layout->addSpacing(bu_config[i]->sizeHint().width()*0.50f);
button_layout->addWidget(bu_config[i]);
button_layout->addSpacing(bu_config[i]->sizeHint().width()*0.50f);
ppad_layout->addLayout(button_layout);
grp_player->setLayout(ppad_layout);
all_players->addWidget(grp_player);
if (i == 3)
{
dialog_layout->addLayout(all_players);
all_players = new QHBoxLayout();
all_players->addStretch();
}
}
all_players->addStretch();
dialog_layout->addLayout(all_players);
QHBoxLayout *buttons_layout = new QHBoxLayout();
QPushButton *ok_button = new QPushButton(tr("OK"));
buttons_layout->addWidget(ok_button);
QPushButton *cancel_button = new QPushButton(tr("Cancel"));
buttons_layout->addWidget(cancel_button);
buttons_layout->addStretch();
dialog_layout->addLayout(buttons_layout);
setLayout(dialog_layout);
layout()->setSizeConstraint(QLayout::SetFixedSize);
//Set the values from config
for (int i = 0; i < 7; i++)
{
for (int j = 0; j < co_inputtype[i]->count(); j++)
{
if (co_inputtype[i]->itemText(j).toStdString() == input_cfg.player_input[i].to_string())
{
co_inputtype[i]->setCurrentIndex(j);
ChangeInputType(i);
break;
}
}
for (int j = 0; j < co_deviceID[i]->count(); j++)
{
if (co_deviceID[i]->itemText(j).toStdString() == input_cfg.player_device[i]->to_string())
{
co_deviceID[i]->setCurrentIndex(j);
ChangeDevice(i);
break;
}
}
}
for (int i = 0; i < 7; i++)
{
connect(co_inputtype[i], &QComboBox::currentTextChanged, [=] { ChangeInputType(i); });
connect(co_deviceID[i], &QComboBox::currentTextChanged, [=] { ChangeDevice(i); });
connect(bu_config[i], &QAbstractButton::clicked, [=] { ClickConfigButton(i); });
}
connect(ok_button, &QPushButton::pressed, this, &gamepads_settings_dialog::SaveExit);
connect(cancel_button, &QPushButton::pressed, this, &gamepads_settings_dialog::CancelExit);
}
void gamepads_settings_dialog::SaveExit()
{
//Check for invalid selection
for (int i = 0; i < 7; i++)
{
if (co_deviceID[i]->currentData() == -1)
{
input_cfg.player_input[i].from_default();
input_cfg.player_device[i]->from_default();
}
}
input_cfg.save();
QDialog::accept();
}
void gamepads_settings_dialog::CancelExit()
{
//Reloads config from file or defaults
input_cfg.from_default();
input_cfg.load();
QDialog::accept();
}
void gamepads_settings_dialog::ChangeDevice(int player)
{
bool success;
success = input_cfg.player_device[player]->from_string(co_deviceID[player]->currentText().toStdString());
if (!success)
{
//Something went wrong
LOG_ERROR(GENERAL, "Failed to convert device string:%s", co_deviceID[player]->currentText().toStdString().c_str());
return;
}
}
std::shared_ptr<PadHandlerBase> gamepads_settings_dialog::GetHandler(pad_handler type)
{
std::shared_ptr<PadHandlerBase> ret_handler;
switch (type)
{
case pad_handler::null:
ret_handler = std::make_unique<NullPadHandler>();
break;
case pad_handler::keyboard:
ret_handler = std::make_unique<keyboard_pad_handler>();
break;
case pad_handler::ds4:
ret_handler = std::make_unique<ds4_pad_handler>();
break;
#ifdef _MSC_VER
case pad_handler::xinput:
ret_handler = std::make_unique<xinput_pad_handler>();
break;
#endif
#ifdef _WIN32
case pad_handler::mm:
ret_handler = std::make_unique<mm_joystick_handler>();
break;
#endif
#ifdef HAVE_LIBEVDEV
case pad_handler::evdev:
ret_handler = std::make_unique<evdev_joystick_handler>();
break;
#endif
}
return ret_handler;
}
void gamepads_settings_dialog::ChangeInputType(int player)
{
bool success;
success = input_cfg.player_input[player].from_string(co_inputtype[player]->currentText().toStdString());
if (!success)
{
//Something went wrong
LOG_ERROR(GENERAL, "Failed to convert input string:%s", co_inputtype[player]->currentText().toStdString().c_str());
return;
}
std::shared_ptr<PadHandlerBase> cur_pad_handler = GetHandler(input_cfg.player_input[player]);
std::vector<std::string> list_devices = cur_pad_handler->ListDevices();
co_deviceID[player]->clear();
for (int i = 0; i < list_devices.size(); i++) co_deviceID[player]->addItem(list_devices[i].c_str(), i);
if (list_devices.size() == 0)
{
co_deviceID[player]->addItem(tr("No Device Detected"), -1);
co_deviceID[player]->setEnabled(false);
}
else
{
co_deviceID[player]->setEnabled(true);
}
bu_config[player]->setEnabled(cur_pad_handler->has_config());
}
void gamepads_settings_dialog::ClickConfigButton(int player)
{
std::shared_ptr<PadHandlerBase> cur_pad_handler = GetHandler(input_cfg.player_input[player]);
if (cur_pad_handler->has_config()) cur_pad_handler->ConfigController(*input_cfg.player_device[player]);
}

View File

@ -0,0 +1,78 @@
#pragma once
#include <QDialog>
#include <QVBoxLayout>
#include <QGroupBox>
#include <QComboBox>
#include <QPushButton>
#include "../Emu/System.h"
#include "../../Utilities/Config.h"
#include "../../Utilities/File.h"
#include "../Emu/Io/PadHandler.h"
struct input_config final : cfg::node
{
const std::string cfg_name = fs::get_config_dir() + "/config_input.yml";
cfg::_enum<pad_handler> player_input[7]{
{ this, "Player 1 Input", pad_handler::keyboard },
{ this, "Player 2 Input", pad_handler::null },
{ this, "Player 3 Input", pad_handler::null },
{ this, "Player 4 Input", pad_handler::null },
{ this, "Player 5 Input", pad_handler::null },
{ this, "Player 6 Input", pad_handler::null },
{ this, "Player 7 Input", pad_handler::null } };
cfg::string player1{ this, "Player 1 Device", "Keyboard" };
cfg::string player2{ this, "Player 2 Device", "Default Null Device" };
cfg::string player3{ this, "Player 3 Device", "Default Null Device" };
cfg::string player4{ this, "Player 4 Device", "Default Null Device" };
cfg::string player5{ this, "Player 5 Device", "Default Null Device" };
cfg::string player6{ this, "Player 6 Device", "Default Null Device" };
cfg::string player7{ this, "Player 7 Device", "Default Null Device" };
cfg::string *player_device[7]{ &player1, &player2, &player3, &player4, &player5, &player6, &player7 }; // Thanks gcc!
bool load()
{
if (fs::file cfg_file{ cfg_name, fs::read })
{
return from_string(cfg_file.to_string());
}
return false;
}
void save()
{
fs::file(cfg_name, fs::rewrite).write(to_string());
}
bool exist()
{
return fs::is_file(cfg_name);
}
};
extern input_config input_cfg;
class gamepads_settings_dialog : public QDialog
{
protected:
std::shared_ptr<PadHandlerBase> GetHandler(pad_handler type);
void ChangeInputType(int player);
void ChangeDevice(int player);
void ClickConfigButton(int player);
void SaveExit();
void CancelExit();
protected:
QComboBox *co_inputtype[7];
QComboBox *co_deviceID[7];
QPushButton *bu_config[7];
public:
gamepads_settings_dialog(QWidget* parent);
~gamepads_settings_dialog() = default;
};

View File

@ -24,6 +24,7 @@
#include "main_window.h" #include "main_window.h"
#include "emu_settings.h" #include "emu_settings.h"
#include "about_dialog.h" #include "about_dialog.h"
#include "gamepads_settings_dialog.h"
#include <thread> #include <thread>
@ -1168,9 +1169,9 @@ void main_window::CreateConnects()
connect(ui->confIOAct, &QAction::triggered, [=]() { openSettings(3); }); connect(ui->confIOAct, &QAction::triggered, [=]() { openSettings(3); });
connect(ui->confSystemAct, &QAction::triggered, [=]() { openSettings(4); }); connect(ui->confSystemAct, &QAction::triggered, [=]() { openSettings(4); });
connect(ui->confPadAct, &QAction::triggered, this, [=] connect(ui->confPadsAct, &QAction::triggered, this, [=]
{ {
pad_settings_dialog dlg(guiSettings, this); gamepads_settings_dialog dlg(this);
dlg.exec(); dlg.exec();
}); });
@ -1369,7 +1370,7 @@ void main_window::CreateConnects()
} }
}); });
connect(ui->toolbar_controls, &QAction::triggered, [=]() { pad_settings_dialog dlg(guiSettings, this); dlg.exec(); }); connect(ui->toolbar_controls, &QAction::triggered, [=]() { gamepads_settings_dialog dlg(this); dlg.exec(); });
connect(ui->toolbar_config, &QAction::triggered, [=]() { openSettings(0); }); connect(ui->toolbar_config, &QAction::triggered, [=]() { openSettings(0); });
connect(ui->toolbar_list, &QAction::triggered, [=]() { ui->setlistModeListAct->trigger(); }); connect(ui->toolbar_list, &QAction::triggered, [=]() { ui->setlistModeListAct->trigger(); });
connect(ui->toolbar_grid, &QAction::triggered, [=]() { ui->setlistModeGridAct->trigger(); }); connect(ui->toolbar_grid, &QAction::triggered, [=]() { ui->setlistModeGridAct->trigger(); });

View File

@ -141,7 +141,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1058</width> <width>1058</width>
<height>26</height> <height>21</height>
</rect> </rect>
</property> </property>
<property name="contextMenuPolicy"> <property name="contextMenuPolicy">
@ -192,7 +192,7 @@
<addaction name="confCPUAct"/> <addaction name="confCPUAct"/>
<addaction name="confGPUAct"/> <addaction name="confGPUAct"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="confPadAct"/> <addaction name="confPadsAct"/>
<addaction name="confAudioAct"/> <addaction name="confAudioAct"/>
<addaction name="confIOAct"/> <addaction name="confIOAct"/>
<addaction name="confSystemAct"/> <addaction name="confSystemAct"/>
@ -419,9 +419,12 @@
<string>Configure Graphics</string> <string>Configure Graphics</string>
</property> </property>
</action> </action>
<action name="confPadAct"> <action name="confPadsAct">
<property name="text"> <property name="text">
<string>Keyboard</string> <string>Pads</string>
</property>
<property name="iconText">
<string>Pads</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Configure Controls</string> <string>Configure Controls</string>
@ -803,10 +806,13 @@
<normaloff>:/Icons/controls.png</normaloff>:/Icons/controls.png</iconset> <normaloff>:/Icons/controls.png</normaloff>:/Icons/controls.png</iconset>
</property> </property>
<property name="text"> <property name="text">
<string>Keyboard</string> <string>Controls</string>
</property>
<property name="iconText">
<string>Controls</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Configure keyboard</string> <string>Configure controls</string>
</property> </property>
</action> </action>
<action name="toolbar_snap"> <action name="toolbar_snap">

View File

@ -18,7 +18,7 @@ static const int PadButtonWidth = 60;
extern keyboard_pad_config g_kbpad_config; extern keyboard_pad_config g_kbpad_config;
pad_settings_dialog::pad_settings_dialog(std::shared_ptr<gui_settings> gui_settings, QWidget *parent) : QDialog(parent), ui(new Ui::pad_settings_dialog) pad_settings_dialog::pad_settings_dialog(keyboard_pad_handler *keyhandler, QWidget *parent) : QDialog(parent), ui(new Ui::pad_settings_dialog)
{ {
ui->setupUi(this); ui->setupUi(this);
@ -67,7 +67,9 @@ pad_settings_dialog::pad_settings_dialog(std::shared_ptr<gui_settings> gui_setti
g_kbpad_config.load(); g_kbpad_config.load();
UpdateLabel(); UpdateLabel();
ui->l_controller->setPixmap(gui_settings->colorizedPixmap(*ui->l_controller->pixmap(), QColor(), GUI::get_Label_Color("l_controller"), false, true)); gui_settings settings(this);
ui->l_controller->setPixmap(settings.colorizedPixmap(*ui->l_controller->pixmap(), QColor(), GUI::get_Label_Color("l_controller"), false, true));
ui->l_controller->setMaximumSize(ui->gb_description->sizeHint().width(), ui->l_controller->maximumHeight() * ui->gb_description->sizeHint().width() / ui->l_controller->maximumWidth()); ui->l_controller->setMaximumSize(ui->gb_description->sizeHint().width(), ui->l_controller->maximumHeight() * ui->gb_description->sizeHint().width() / ui->l_controller->maximumWidth());
layout()->setSizeConstraint(QLayout::SetFixedSize); layout()->setSizeConstraint(QLayout::SetFixedSize);
} }
@ -271,49 +273,6 @@ void pad_settings_dialog::RunTimer(const u32 seconds, const u32 id)
} }
} }
void pad_settings_dialog::Init(const u32 max_connect)
{
memset(&m_info, 0, sizeof(PadInfo));
m_info.max_connect = max_connect;
LoadSettings();
m_info.now_connect = std::min((u32)m_pads.size(), max_connect);
}
void pad_settings_dialog::LoadSettings()
{
g_kbpad_config.load();
//Fixed assign change, default is both sensor and press off
m_pads.emplace_back(
CELL_PAD_STATUS_CONNECTED | CELL_PAD_STATUS_ASSIGN_CHANGES,
CELL_PAD_SETTING_PRESS_OFF | CELL_PAD_SETTING_SENSOR_OFF,
CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE,
CELL_PAD_DEV_TYPE_STANDARD);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.left, CELL_PAD_CTRL_LEFT);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.down, CELL_PAD_CTRL_DOWN);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.right, CELL_PAD_CTRL_RIGHT);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.up, CELL_PAD_CTRL_UP);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.start, CELL_PAD_CTRL_START);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.r3, CELL_PAD_CTRL_R3);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.l3, CELL_PAD_CTRL_L3);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, g_kbpad_config.select, CELL_PAD_CTRL_SELECT);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.square, CELL_PAD_CTRL_SQUARE);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.cross, CELL_PAD_CTRL_CROSS);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.circle, CELL_PAD_CTRL_CIRCLE);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.triangle, CELL_PAD_CTRL_TRIANGLE);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.r1, CELL_PAD_CTRL_R1);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.l1, CELL_PAD_CTRL_L1);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.r2, CELL_PAD_CTRL_R2);
m_pads[0].m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, g_kbpad_config.l2, CELL_PAD_CTRL_L2);
m_pads[0].m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, g_kbpad_config.left_stick_left, g_kbpad_config.left_stick_right);
m_pads[0].m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, g_kbpad_config.left_stick_up, g_kbpad_config.left_stick_down);
m_pads[0].m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, g_kbpad_config.right_stick_left, g_kbpad_config.right_stick_right);
m_pads[0].m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, g_kbpad_config.right_stick_up, g_kbpad_config.right_stick_down);
}
const QString pad_settings_dialog::GetKeyName(const u32 keyCode) const QString pad_settings_dialog::GetKeyName(const u32 keyCode)
{ {
//TODO what about numpad? //TODO what about numpad?

View File

@ -54,7 +54,7 @@ namespace Ui
class pad_settings_dialog; class pad_settings_dialog;
} }
class pad_settings_dialog : public QDialog, PadHandlerBase class pad_settings_dialog : public QDialog
{ {
Q_OBJECT Q_OBJECT
@ -67,17 +67,15 @@ private:
bool m_key_pressed; bool m_key_pressed;
QAction *onButtonClickedAct; QAction *onButtonClickedAct;
Ui::pad_settings_dialog *ui; Ui::pad_settings_dialog *ui;
keyboard_pad_handler* keyhdlr;
public: public:
// TODO get Init to work explicit pad_settings_dialog(keyboard_pad_handler* keyhandler, QWidget *parent = nullptr);
virtual void Init(const u32 max_connect) override;
explicit pad_settings_dialog(std::shared_ptr<gui_settings> gui_settings, QWidget *parent = 0);
~pad_settings_dialog(); ~pad_settings_dialog();
void keyPressEvent(QKeyEvent *keyEvent) override; void keyPressEvent(QKeyEvent *keyEvent) override;
void UpdateLabel(); void UpdateLabel();
void UpdateTimerLabel(const u32 id); void UpdateTimerLabel(const u32 id);
void SwitchButtons(const bool IsEnabled); void SwitchButtons(const bool IsEnabled);
void RunTimer(const u32 seconds, const u32 id); void RunTimer(const u32 seconds, const u32 id);
void LoadSettings();
const QString GetKeyName(const u32 keyCode); const QString GetKeyName(const u32 keyCode);
}; };

View File

@ -585,9 +585,6 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> xSettings, const
// Comboboxes // Comboboxes
xemu_settings->EnhanceComboBox(ui->padHandlerBox, emu_settings::PadHandler);
ui->padHandlerBox->setToolTip(json_input["padHandlerBox"].toString());
xemu_settings->EnhanceComboBox(ui->keyboardHandlerBox, emu_settings::KeyboardHandler); xemu_settings->EnhanceComboBox(ui->keyboardHandlerBox, emu_settings::KeyboardHandler);
ui->keyboardHandlerBox->setToolTip(json_input["keyboardHandlerBox"].toString()); ui->keyboardHandlerBox->setToolTip(json_input["keyboardHandlerBox"].toString());

View File

@ -655,13 +655,13 @@
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_10"> <layout class="QHBoxLayout" name="horizontalLayout_10">
<item> <item>
<widget class="QGroupBox" name="groupBox_52"> <widget class="QGroupBox" name="groupBox_51">
<property name="title"> <property name="title">
<string>Controller Handler</string> <string>Keyboard Handler</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_29"> <layout class="QVBoxLayout" name="verticalLayout_27">
<item> <item>
<widget class="QComboBox" name="padHandlerBox"/> <widget class="QComboBox" name="keyboardHandlerBox"/>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -683,13 +683,13 @@
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_11"> <layout class="QHBoxLayout" name="horizontalLayout_11">
<item> <item>
<widget class="QGroupBox" name="groupBox_51"> <widget class="QGroupBox" name="groupBox_53">
<property name="title"> <property name="title">
<string>Keyboard Handler</string> <string>Mouse Handler</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_27"> <layout class="QVBoxLayout" name="verticalLayout_28">
<item> <item>
<widget class="QComboBox" name="keyboardHandlerBox"/> <widget class="QComboBox" name="mouseHandlerBox"/>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -710,18 +710,6 @@
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_12"> <layout class="QHBoxLayout" name="horizontalLayout_12">
<item>
<widget class="QGroupBox" name="groupBox_53">
<property name="title">
<string>Mouse Handler</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_28">
<item>
<widget class="QComboBox" name="mouseHandlerBox"/>
</item>
</layout>
</widget>
</item>
<item> <item>
<widget class="QWidget" name="widget_3" native="true"/> <widget class="QWidget" name="widget_3" native="true"/>
</item> </item>

View File

@ -34,7 +34,7 @@ namespace {
} }
} }
xinput_pad_handler::xinput_pad_handler() : active(false), thread(nullptr), library(nullptr), xinputGetState(nullptr), xinputEnable(nullptr), xinputSetState(nullptr) xinput_pad_handler::xinput_pad_handler() : library(nullptr), xinputGetState(nullptr), xinputEnable(nullptr), xinputSetState(nullptr), is_init(false)
{ {
} }
@ -43,8 +43,10 @@ xinput_pad_handler::~xinput_pad_handler()
Close(); Close();
} }
void xinput_pad_handler::Init(const u32 max_connect) bool xinput_pad_handler::Init()
{ {
if (is_init) return true;
for (auto it : LIBRARY_FILENAMES) for (auto it : LIBRARY_FILENAMES)
{ {
library = LoadLibrary(it); library = LoadLibrary(it);
@ -61,6 +63,7 @@ void xinput_pad_handler::Init(const u32 max_connect)
if (xinputEnable && xinputGetState && xinputSetState) if (xinputEnable && xinputGetState && xinputSetState)
{ {
is_init = true;
break; break;
} }
@ -71,48 +74,7 @@ void xinput_pad_handler::Init(const u32 max_connect)
} }
} }
if (library) if (!is_init) return false;
{
std::memset(&m_info, 0, sizeof m_info);
m_info.max_connect = max_connect;
for (u32 i = 0, max = std::min(max_connect, u32(MAX_GAMEPADS)); i != max; ++i)
{
m_pads.emplace_back(
CELL_PAD_STATUS_DISCONNECTED,
CELL_PAD_SETTING_PRESS_OFF | CELL_PAD_SETTING_SENSOR_OFF,
CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_ACTUATOR,
CELL_PAD_DEV_TYPE_STANDARD
);
auto & pad = m_pads.back();
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_DPAD_UP, CELL_PAD_CTRL_UP);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_DPAD_DOWN, CELL_PAD_CTRL_DOWN);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_DPAD_LEFT, CELL_PAD_CTRL_LEFT);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_DPAD_RIGHT, CELL_PAD_CTRL_RIGHT);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_START, CELL_PAD_CTRL_START);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_BACK, CELL_PAD_CTRL_SELECT);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_LEFT_THUMB, CELL_PAD_CTRL_L3);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_RIGHT_THUMB, CELL_PAD_CTRL_R3);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, XINPUT_GAMEPAD_LEFT_SHOULDER, CELL_PAD_CTRL_L1);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, XINPUT_GAMEPAD_RIGHT_SHOULDER, CELL_PAD_CTRL_R1);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, XINPUT_GAMEPAD_GUIDE, 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, XINPUT_GAMEPAD_A, CELL_PAD_CTRL_CROSS);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, XINPUT_GAMEPAD_B, CELL_PAD_CTRL_CIRCLE);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, XINPUT_GAMEPAD_X, CELL_PAD_CTRL_SQUARE);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, XINPUT_GAMEPAD_Y, CELL_PAD_CTRL_TRIANGLE);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, CELL_PAD_CTRL_L2);
pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, CELL_PAD_CTRL_R2);
pad.m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, 0, 0);
pad.m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, 0, 0);
pad.m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, 0, 0);
pad.m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, 0, 0);
pad.m_vibrateMotors.emplace_back(true, 0);
pad.m_vibrateMotors.emplace_back(false, 0);
}
xinput_cfg.load(); xinput_cfg.load();
if (!xinput_cfg.exist()) xinput_cfg.save(); if (!xinput_cfg.exist()) xinput_cfg.save();
@ -121,38 +83,18 @@ void xinput_pad_handler::Init(const u32 max_connect)
left_stick_deadzone = xinput_cfg.lstickdeadzone; left_stick_deadzone = xinput_cfg.lstickdeadzone;
right_stick_deadzone = xinput_cfg.rstickdeadzone; right_stick_deadzone = xinput_cfg.rstickdeadzone;
active = true; return true;
thread = CreateThread(NULL, 0, &xinput_pad_handler::ThreadProcProxy, this, 0, NULL);
}
}
void xinput_pad_handler::SetRumble(const u32 pad, u8 largeMotor, bool smallMotor) {
if (pad > m_pads.size())
return;
m_pads[pad].m_vibrateMotors[0].m_value = largeMotor;
m_pads[pad].m_vibrateMotors[1].m_value = smallMotor ? 255 : 0;
} }
void xinput_pad_handler::Close() void xinput_pad_handler::Close()
{ {
if (library) if (library)
{ {
if (thread)
{
active = false;
if (WaitForSingleObject(thread, THREAD_TIMEOUT) != WAIT_OBJECT_0)
LOG_ERROR(HLE, "XInput thread could not stop within %d milliseconds", (u32)THREAD_TIMEOUT);
thread = nullptr;
}
FreeLibrary(library); FreeLibrary(library);
library = nullptr; library = nullptr;
xinputGetState = nullptr; xinputGetState = nullptr;
xinputEnable = nullptr; xinputEnable = nullptr;
} }
m_pads.clear();
} }
std::tuple<u16, u16> xinput_pad_handler::ConvertToSquirclePoint(u16 inX, u16 inY) std::tuple<u16, u16> xinput_pad_handler::ConvertToSquirclePoint(u16 inX, u16 inY)
@ -176,58 +118,50 @@ std::tuple<u16, u16> xinput_pad_handler::ConvertToSquirclePoint(u16 inX, u16 inY
return std::tuple<u16, u16>(newX, newY); return std::tuple<u16, u16>(newX, newY);
} }
DWORD xinput_pad_handler::ThreadProcedure() void xinput_pad_handler::ThreadProc()
{ {
// holds internal controller state change for (u32 index = 0; index != bindings.size(); index++)
std::array<bool, MAX_GAMEPADS> last_connection_status = {};
while (active)
{ {
XINPUT_STATE state; auto padnum = bindings[index].first;
DWORD result; auto pad = bindings[index].second;
DWORD online = 0;
for (DWORD i = 0; i != m_pads.size(); ++i) result = (*xinputGetState)(padnum, &state);
{
auto & pad = m_pads[i];
result = (*xinputGetState)(i, &state);
switch (result) switch (result)
{ {
case ERROR_DEVICE_NOT_CONNECTED: case ERROR_DEVICE_NOT_CONNECTED:
if (last_connection_status[i] == true) if (last_connection_status[padnum] == true)
pad.m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES; pad->m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES;
last_connection_status[i] = false; last_connection_status[padnum] = false;
pad.m_port_status &= ~CELL_PAD_STATUS_CONNECTED; pad->m_port_status &= ~CELL_PAD_STATUS_CONNECTED;
break; break;
case ERROR_SUCCESS: case ERROR_SUCCESS:
++online; ++online;
if (last_connection_status[i] == false) if (last_connection_status[padnum] == false)
pad.m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES; pad->m_port_status |= CELL_PAD_STATUS_ASSIGN_CHANGES;
last_connection_status[i] = true; last_connection_status[padnum] = true;
pad.m_port_status |= CELL_PAD_STATUS_CONNECTED; pad->m_port_status |= CELL_PAD_STATUS_CONNECTED;
for (DWORD j = 0; j != XINPUT_GAMEPAD_BUTTONS; ++j) for (DWORD j = 0; j != XINPUT_GAMEPAD_BUTTONS; ++j)
{ {
bool pressed = state.Gamepad.wButtons & (1 << j); bool pressed = state.Gamepad.wButtons & (1 << j);
pad.m_buttons[j].m_pressed = pressed; pad->m_buttons[j].m_pressed = pressed;
pad.m_buttons[j].m_value = pressed ? 255 : 0; pad->m_buttons[j].m_value = pressed ? 255 : 0;
} }
for (int i = 6; i < 16; i++) for (int i = 6; i < 16; i++)
{ {
if (pad.m_buttons[i].m_pressed) if (pad->m_buttons[i].m_pressed)
{ {
SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
break; break;
} }
} }
pad.m_buttons[XINPUT_GAMEPAD_BUTTONS].m_pressed = state.Gamepad.bLeftTrigger > 0; pad->m_buttons[XINPUT_GAMEPAD_BUTTONS].m_pressed = state.Gamepad.bLeftTrigger > 0;
pad.m_buttons[XINPUT_GAMEPAD_BUTTONS].m_value = state.Gamepad.bLeftTrigger; pad->m_buttons[XINPUT_GAMEPAD_BUTTONS].m_value = state.Gamepad.bLeftTrigger;
pad.m_buttons[XINPUT_GAMEPAD_BUTTONS + 1].m_pressed = state.Gamepad.bRightTrigger > 0; pad->m_buttons[XINPUT_GAMEPAD_BUTTONS + 1].m_pressed = state.Gamepad.bRightTrigger > 0;
pad.m_buttons[XINPUT_GAMEPAD_BUTTONS + 1].m_value = state.Gamepad.bRightTrigger; pad->m_buttons[XINPUT_GAMEPAD_BUTTONS + 1].m_value = state.Gamepad.bRightTrigger;
float LX, LY, RX, RY; float LX, LY, RX, RY;
@ -262,38 +196,92 @@ DWORD xinput_pad_handler::ThreadProcedure()
normalize_input(LX, LY, left_stick_deadzone); normalize_input(LX, LY, left_stick_deadzone);
normalize_input(RX, RY, right_stick_deadzone); normalize_input(RX, RY, right_stick_deadzone);
pad.m_sticks[0].m_value = ConvertAxis(LX); pad->m_sticks[0].m_value = ConvertAxis(LX);
pad.m_sticks[1].m_value = 255 - ConvertAxis(LY); pad->m_sticks[1].m_value = 255 - ConvertAxis(LY);
pad.m_sticks[2].m_value = ConvertAxis(RX); pad->m_sticks[2].m_value = ConvertAxis(RX);
pad.m_sticks[3].m_value = 255 - ConvertAxis(RY); pad->m_sticks[3].m_value = 255 - ConvertAxis(RY);
if (squircle_factor != 0.f) if (squircle_factor != 0.f)
{ {
std::tie(pad.m_sticks[0].m_value, pad.m_sticks[1].m_value) = ConvertToSquirclePoint(pad.m_sticks[0].m_value, pad.m_sticks[1].m_value); std::tie(pad->m_sticks[0].m_value, pad->m_sticks[1].m_value) = ConvertToSquirclePoint(pad->m_sticks[0].m_value, pad->m_sticks[1].m_value);
std::tie(pad.m_sticks[2].m_value, pad.m_sticks[3].m_value) = ConvertToSquirclePoint(pad.m_sticks[2].m_value, pad.m_sticks[3].m_value); std::tie(pad->m_sticks[2].m_value, pad->m_sticks[3].m_value) = ConvertToSquirclePoint(pad->m_sticks[2].m_value, pad->m_sticks[3].m_value);
} }
XINPUT_VIBRATION vibrate; XINPUT_VIBRATION vibrate;
vibrate.wLeftMotorSpeed = pad.m_vibrateMotors[0].m_value * 257; vibrate.wLeftMotorSpeed = pad->m_vibrateMotors[0].m_value * 257;
vibrate.wRightMotorSpeed = pad.m_vibrateMotors[1].m_value * 257; vibrate.wRightMotorSpeed = pad->m_vibrateMotors[1].m_value * 257;
(*xinputSetState)(i, &vibrate); (*xinputSetState)(padnum, &vibrate);
break; break;
} }
} }
m_info.now_connect = online;
Sleep((online > 0) ? THREAD_SLEEP : THREAD_SLEEP_INACTIVE);
}
return 0;
} }
DWORD WINAPI xinput_pad_handler::ThreadProcProxy(LPVOID parameter) std::vector<std::string> xinput_pad_handler::ListDevices()
{ {
return reinterpret_cast<xinput_pad_handler *>(parameter)->ThreadProcedure(); std::vector<std::string> xinput_pads_list;
if (!Init()) return xinput_pads_list;
for (DWORD i = 0; i < MAX_GAMEPADS; i++)
{
XINPUT_STATE state;
DWORD result = (*xinputGetState)(i, &state);
if (result == ERROR_SUCCESS)
{
xinput_pads_list.push_back(fmt::format("Xinput Pad #%d", i));
}
}
return xinput_pads_list;
}
bool xinput_pad_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device)
{
//Convert device string to u32 representing xinput device number
u32 device_number = 0;
size_t pos = device.find("Xinput Pad #");
if (pos != std::string::npos) device_number = std::stoul(device.substr(pos + 12));
if (pos == std::string::npos || device_number >= MAX_GAMEPADS) return false;
pad->Init(
CELL_PAD_STATUS_DISCONNECTED,
CELL_PAD_SETTING_PRESS_OFF | CELL_PAD_SETTING_SENSOR_OFF,
CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_ACTUATOR,
CELL_PAD_DEV_TYPE_STANDARD
);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_DPAD_UP, CELL_PAD_CTRL_UP);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_DPAD_DOWN, CELL_PAD_CTRL_DOWN);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_DPAD_LEFT, CELL_PAD_CTRL_LEFT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_DPAD_RIGHT, CELL_PAD_CTRL_RIGHT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_START, CELL_PAD_CTRL_START);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_BACK, CELL_PAD_CTRL_SELECT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_LEFT_THUMB, CELL_PAD_CTRL_L3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_RIGHT_THUMB, CELL_PAD_CTRL_R3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, XINPUT_GAMEPAD_LEFT_SHOULDER, CELL_PAD_CTRL_L1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, XINPUT_GAMEPAD_RIGHT_SHOULDER, CELL_PAD_CTRL_R1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, XINPUT_GAMEPAD_GUIDE, 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, XINPUT_GAMEPAD_A, CELL_PAD_CTRL_CROSS);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, XINPUT_GAMEPAD_B, CELL_PAD_CTRL_CIRCLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, XINPUT_GAMEPAD_X, CELL_PAD_CTRL_SQUARE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, XINPUT_GAMEPAD_Y, CELL_PAD_CTRL_TRIANGLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, CELL_PAD_CTRL_L2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, CELL_PAD_CTRL_R2);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, 0, 0);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, 0, 0);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, 0, 0);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, 0, 0);
pad->m_vibrateMotors.emplace_back(true, 0);
pad->m_vibrateMotors.emplace_back(false, 0);
bindings.emplace_back(device_number, pad);
} }
#endif #endif

View File

@ -3,6 +3,7 @@
#include "Utilities/Config.h" #include "Utilities/Config.h"
#include "Emu/Io/PadHandler.h" #include "Emu/Io/PadHandler.h"
#define NOMINMAX
#include <Windows.h> #include <Windows.h>
#include <Xinput.h> #include <Xinput.h>
@ -41,10 +42,13 @@ public:
xinput_pad_handler(); xinput_pad_handler();
~xinput_pad_handler(); ~xinput_pad_handler();
void Init(const u32 max_connect) override; bool Init() override;
void SetRumble(const u32 pad, u8 largeMotor, bool smallMotor) override;
void Close(); void Close();
std::vector<std::string> ListDevices() override;
bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) override;
void ThreadProc() override;
private: private:
typedef void (WINAPI * PFN_XINPUTENABLE)(BOOL); typedef void (WINAPI * PFN_XINPUTENABLE)(BOOL);
typedef DWORD (WINAPI * PFN_XINPUTGETSTATE)(DWORD, XINPUT_STATE *); typedef DWORD (WINAPI * PFN_XINPUTGETSTATE)(DWORD, XINPUT_STATE *);
@ -52,19 +56,23 @@ private:
private: private:
std::tuple<u16, u16> ConvertToSquirclePoint(u16 inX, u16 inY); std::tuple<u16, u16> ConvertToSquirclePoint(u16 inX, u16 inY);
DWORD ThreadProcedure();
static DWORD WINAPI ThreadProcProxy(LPVOID parameter);
private: private:
mutable bool active; bool is_init;
float squircle_factor; float squircle_factor;
u32 left_stick_deadzone, right_stick_deadzone; u32 left_stick_deadzone, right_stick_deadzone;
HANDLE thread;
HMODULE library; HMODULE library;
PFN_XINPUTGETSTATE xinputGetState; PFN_XINPUTGETSTATE xinputGetState;
PFN_XINPUTSETSTATE xinputSetState; PFN_XINPUTSETSTATE xinputSetState;
PFN_XINPUTENABLE xinputEnable; PFN_XINPUTENABLE xinputEnable;
std::vector<std::pair<u32, std::shared_ptr<Pad>>> bindings;
std::array<bool, 7> last_connection_status = {};
// holds internal controller state change
XINPUT_STATE state;
DWORD result;
DWORD online = 0;
}; };
extern xinput_config xinput_cfg; extern xinput_config xinput_cfg;