s32 cellPadGetInfo2(vm::ptr<CellPadInfo2> info) { sys_io.trace("cellPadGetInfo2(info=*0x%x)", info); const auto handler = fxm::get<PadHandlerBase>(); if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; const PadInfo& rinfo = handler->GetInfo(); info->max_connect = rinfo.max_connect; info->now_connect = rinfo.now_connect; info->system_info = rinfo.system_info; std::vector<Pad>& pads = handler->GetPads(); for (u32 i=0; i<CELL_PAD_MAX_PORT_NUM; ++i) { if (i >= pads.size()) break; info->port_status[i] = pads[i].m_port_status; pads[i].m_port_status &= ~CELL_PAD_STATUS_ASSIGN_CHANGES; info->port_setting[i] = pads[i].m_port_setting; info->device_capability[i] = pads[i].m_device_capability; info->device_type[i] = pads[i].m_device_type; } return CELL_OK; }
s32 cellPadGetInfo(vm::ptr<CellPadInfo> info) { sys_io.trace("cellPadGetInfo(info=*0x%x)", info); const auto handler = fxm::get<PadHandlerBase>(); if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; const PadInfo& rinfo = handler->GetInfo(); info->max_connect = rinfo.max_connect; info->now_connect = rinfo.now_connect; info->system_info = rinfo.system_info; std::vector<Pad>& pads = handler->GetPads(); for (u32 i=0; i<CELL_MAX_PADS; ++i) { if (i >= pads.size()) break; info->status[i] = pads[i].m_port_status; pads[i].m_port_status &= ~CELL_PAD_STATUS_ASSIGN_CHANGES; info->product_id[i] = 0x0268; info->vendor_id[i] = 0x054C; } return CELL_OK; }
error_code cellPadPeriphGetData(u32 port_no, vm::ptr<CellPadPeriphData> data) { sys_io.trace("cellPadPeriphGetData(port_no=%d, data=*0x%x)", port_no, data); const auto handler = fxm::get<pad_thread>(); if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; // port_no can only be 0-6 in this function if (port_no >= CELL_PAD_MAX_PORT_NUM || !data) return CELL_PAD_ERROR_INVALID_PARAMETER; const auto& pads = handler->GetPads(); if (port_no >= pads.size() || port_no >= handler->GetInfo().max_connect) return CELL_PAD_ERROR_NO_DEVICE; const auto pad = pads[port_no]; if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) return CELL_PAD_ERROR_NO_DEVICE; // todo: support for 'unique' controllers, which goes in offsets 24+ in padData data->pclass_type = CELL_PAD_PCLASS_TYPE_STANDARD; data->pclass_profile = 0x0; return cellPadGetData(port_no, vm::get_addr(&data->cellpad_data)); }
error_code cellPadGetRawData(u32 port_no, vm::ptr<CellPadData> data) { sys_io.todo("cellPadGetRawData(port_no=%d, data=*0x%x)", port_no, data); const auto handler = fxm::get<pad_thread>(); if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; if (port_no >= CELL_MAX_PADS || !data) return CELL_PAD_ERROR_INVALID_PARAMETER; const auto& pads = handler->GetPads(); if (port_no >= pads.size() || port_no >= handler->GetInfo().max_connect) return CELL_PAD_ERROR_NO_DEVICE; const auto pad = pads[port_no]; if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) return CELL_PAD_ERROR_NO_DEVICE; // ? return CELL_OK; }
error_code cellPadSetPortSetting(u32 port_no, u32 port_setting) { sys_io.trace("cellPadSetPortSetting(port_no=%d, port_setting=0x%x)", port_no, port_setting); const auto handler = fxm::get<pad_thread>(); if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; if (port_no >= CELL_MAX_PADS) return CELL_PAD_ERROR_INVALID_PARAMETER; const auto& pads = handler->GetPads(); // CELL_PAD_ERROR_NO_DEVICE is not returned in this case. // TODO: Set the setting regardless if (port_no >= pads.size() || port_no >= handler->GetInfo().max_connect) return CELL_OK; const auto pad = pads[port_no]; pad->m_port_setting = port_setting; // can also return CELL_PAD_ERROR_UNSUPPORTED_GAMEPAD return CELL_OK; }
error_code cellPadGetCapabilityInfo(u32 port_no, vm::ptr<CellPadCapabilityInfo> info) { sys_io.trace("cellPadGetCapabilityInfo(port_no=%d, data_addr:=0x%x)", port_no, info.addr()); const auto handler = fxm::get<pad_thread>(); if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; if (port_no >= CELL_MAX_PADS || !info) return CELL_PAD_ERROR_INVALID_PARAMETER; const auto& pads = handler->GetPads(); if (port_no >= pads.size() || port_no >= handler->GetInfo().max_connect) return CELL_PAD_ERROR_NO_DEVICE; const auto pad = pads[port_no]; if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) return CELL_PAD_ERROR_NO_DEVICE; // Should return the same as device capability mask, psl1ght has it backwards in pad->h info->info[port_no] = pad->m_device_capability; return CELL_OK; }
error_code cellPadGetInfo(vm::ptr<CellPadInfo> info) { sys_io.trace("cellPadGetInfo(info=*0x%x)", info); const auto handler = fxm::get<pad_thread>(); if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; if (!info) return CELL_PAD_ERROR_INVALID_PARAMETER; std::memset(info.get_ptr(), 0, sizeof(CellPadInfo)); const PadInfo& rinfo = handler->GetInfo(); info->max_connect = rinfo.max_connect; info->now_connect = rinfo.now_connect; info->system_info = rinfo.system_info; const auto& pads = handler->GetPads(); for (u32 i = 0; i < CELL_MAX_PADS; ++i) { if (i >= pads.size()) break; info->status[i] = pads[i]->m_port_status; pads[i]->m_port_status &= ~CELL_PAD_STATUS_ASSIGN_CHANGES; info->product_id[i] = 0x0268; info->vendor_id[i] = 0x054C; } return CELL_OK; }
error_code cellPadGetInfo2(vm::ptr<CellPadInfo2> info) { sys_io.trace("cellPadGetInfo2(info=*0x%x)", info); const auto handler = fxm::get<pad_thread>(); if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; if (!info) return CELL_PAD_ERROR_INVALID_PARAMETER; std::memset(info.get_ptr(), 0, sizeof(CellPadInfo2)); const PadInfo& rinfo = handler->GetInfo(); info->max_connect = rinfo.max_connect; info->now_connect = rinfo.now_connect; info->system_info = rinfo.system_info; const auto& pads = handler->GetPads(); for (u32 i = 0; i < CELL_PAD_MAX_PORT_NUM; ++i) { if (i >= pads.size()) break; info->port_status[i] = pads[i]->m_port_status; pads[i]->m_port_status &= ~CELL_PAD_STATUS_ASSIGN_CHANGES; info->port_setting[i] = pads[i]->m_port_setting; info->device_capability[i] = pads[i]->m_device_capability; info->device_type[i] = pads[i]->m_device_type; } return CELL_OK; }
error_code cellPadSetSensorMode(u32 port_no, u32 mode) { sys_io.trace("cellPadSetSensorMode(port_no=%d, mode=%d)", port_no, mode); const auto handler = fxm::get<pad_thread>(); if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; if (port_no >= CELL_MAX_PADS) return CELL_PAD_ERROR_INVALID_PARAMETER; const auto& pads = handler->GetPads(); // CELL_PAD_ERROR_NO_DEVICE is not returned in this case. // TODO: Set the setting regardless if (port_no >= pads.size() || port_no >= handler->GetInfo().max_connect) return CELL_OK; const auto pad = pads[port_no]; // TODO: find out if this is checked here or later or at all if (!(pad->m_device_capability & CELL_PAD_CAPABILITY_SENSOR_MODE)) return CELL_PAD_ERROR_UNSUPPORTED_GAMEPAD; if (mode) pad->m_port_setting |= CELL_PAD_SETTING_SENSOR_ON; else pad->m_port_setting &= ~CELL_PAD_SETTING_SENSOR_ON; return CELL_OK; }
error_code cellPadSetActDirect(u32 port_no, vm::ptr<CellPadActParam> param) { sys_io.trace("cellPadSetActDirect(port_no=%d, param=*0x%x)", port_no, param); const auto handler = fxm::get<pad_thread>(); if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; if (port_no >= CELL_MAX_PADS || !param) return CELL_PAD_ERROR_INVALID_PARAMETER; const auto& pads = handler->GetPads(); if (port_no >= pads.size() || port_no >= handler->GetInfo().max_connect) return CELL_PAD_ERROR_NO_DEVICE; const auto pad = pads[port_no]; if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) return CELL_PAD_ERROR_NO_DEVICE; // TODO: find out if this is checked here or later or at all if (!(pad->m_device_capability & CELL_PAD_CAPABILITY_ACTUATOR)) return CELL_PAD_ERROR_UNSUPPORTED_GAMEPAD; // make sure reserved bits are 0. Looks like this happens after checking the pad status for (int i = 0; i < 6; i++) if (param->reserved[i]) return CELL_PAD_ERROR_INVALID_PARAMETER; handler->SetRumble(port_no, param->motor[1], param->motor[0] > 0); return CELL_OK; }
s32 cellPadPeriphGetInfo(vm::ptr<CellPadPeriphInfo> info) { sys_io.trace("cellPadPeriphGetInfo(info=*0x%x)", info); const auto handler = fxm::get<PadHandlerBase>(); if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; const PadInfo& rinfo = handler->GetInfo(); info->max_connect = rinfo.max_connect; info->now_connect = rinfo.now_connect; info->system_info = rinfo.system_info; std::vector<Pad>& pads = handler->GetPads(); // TODO: Support other types of controllers for (u32 i = 0; i < CELL_PAD_MAX_PORT_NUM; ++i) { if (i >= pads.size()) break; info->port_status[i] = pads[i].m_port_status; info->port_setting[i] = pads[i].m_port_setting; info->device_capability[i] = pads[i].m_device_capability; info->device_type[i] = pads[i].m_device_type; info->pclass_type[i] = CELL_PAD_PCLASS_TYPE_STANDARD; info->pclass_profile[i] = 0x0; } return CELL_OK; }
s32 cellPadSetSensorMode(u32 port_no, u32 mode) { sys_io.trace("cellPadSetSensorMode(port_no=%d, mode=%d)", port_no, mode); const auto handler = fxm::get<PadHandlerBase>(); if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; if (mode != 0 && mode != 1) return CELL_PAD_ERROR_INVALID_PARAMETER; const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; if (port_no >= rinfo.now_connect) return CELL_PAD_ERROR_NO_DEVICE; std::vector<Pad>& pads = handler->GetPads(); if (mode) pads[port_no].m_port_setting |= CELL_PAD_SETTING_SENSOR_ON; else pads[port_no].m_port_setting &= ~CELL_PAD_SETTING_SENSOR_ON; return CELL_OK; }
s32 cellPadInfoSensorMode(u32 port_no) { sys_io.trace("cellPadInfoSensorMode(port_no=%d)", port_no); const auto handler = fxm::get<PadHandlerBase>(); if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; if (port_no >= rinfo.now_connect) return CELL_PAD_ERROR_NO_DEVICE; const std::vector<Pad>& pads = handler->GetPads(); return (pads[port_no].m_device_capability & CELL_PAD_CAPABILITY_SENSOR_MODE) > 0; }
s32 cellPadSetPortSetting(u32 port_no, u32 port_setting) { sys_io.trace("cellPadSetPortSetting(port_no=%d, port_setting=0x%x)", port_no, port_setting); const auto handler = fxm::get<PadHandlerBase>(); if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; if (port_no >= rinfo.now_connect) return CELL_PAD_ERROR_NO_DEVICE; std::vector<Pad>& pads = handler->GetPads(); pads[port_no].m_port_setting = port_setting; return CELL_OK; }
error_code cellPadClearBuf(u32 port_no) { sys_io.trace("cellPadClearBuf(port_no=%d)", port_no); const auto handler = fxm::get<pad_thread>(); if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; if (port_no >= CELL_MAX_PADS) return CELL_PAD_ERROR_INVALID_PARAMETER; const auto& pads = handler->GetPads(); if (port_no >= pads.size() || port_no >= handler->GetInfo().max_connect) return CELL_PAD_ERROR_NO_DEVICE; const auto pad = pads[port_no]; if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) return CELL_PAD_ERROR_NO_DEVICE; // Set 'm_buffer_cleared' to force a resend of everything // might as well also reset everything in our pad 'buffer' to nothing as well 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_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_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; // ~399 on sensor y is a level non moving controller pad->m_sensor_y = 399; pad->m_sensor_x = pad->m_sensor_z = pad->m_sensor_g = 512; return CELL_OK; }
error_code cellPadPeriphGetInfo(vm::ptr<CellPadPeriphInfo> info) { sys_io.trace("cellPadPeriphGetInfo(info=*0x%x)", info); const auto handler = fxm::get<pad_thread>(); if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; if (!info) return CELL_PAD_ERROR_INVALID_PARAMETER; const PadInfo& rinfo = handler->GetInfo(); std::memset(info.get_ptr(), 0, sizeof(CellPadPeriphInfo)); info->max_connect = rinfo.max_connect; info->now_connect = rinfo.now_connect; info->system_info = rinfo.system_info; const auto& pads = handler->GetPads(); // TODO: Support other types of controllers for (u32 i = 0; i < CELL_PAD_MAX_PORT_NUM; ++i) { if (i >= pads.size()) break; info->port_status[i] = pads[i]->m_port_status; pads[i]->m_port_status &= ~CELL_PAD_STATUS_ASSIGN_CHANGES; info->port_setting[i] = pads[i]->m_port_setting; info->device_capability[i] = pads[i]->m_device_capability; info->device_type[i] = pads[i]->m_device_type; info->pclass_type[i] = CELL_PAD_PCLASS_TYPE_STANDARD; info->pclass_profile[i] = 0x0; } return CELL_OK; }
s32 cellPadGetCapabilityInfo(u32 port_no, vm::ptr<CellCapabilityInfo> info) { sys_io.trace("cellPadGetCapabilityInfo(port_no=%d, data_addr:=0x%x)", port_no, info.addr()); const auto handler = fxm::get<PadHandlerBase>(); if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; if (port_no >= rinfo.now_connect) return CELL_PAD_ERROR_NO_DEVICE; const std::vector<Pad>& pads = handler->GetPads(); //Should return the same as device capability mask, psl1ght has it backwards in pad.h info->info[0] = pads[port_no].m_device_capability; return CELL_OK; }
s32 cellPadClearBuf(u32 port_no) { sys_io.trace("cellPadClearBuf(port_no=%d)", port_no); const auto handler = fxm::get<PadHandlerBase>(); if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; if (port_no >= rinfo.now_connect) return CELL_PAD_ERROR_NO_DEVICE; //Set 'm_buffer_cleared' to force a resend of everything //might as well also reset everything in our pad 'buffer' to nothing as well std::vector<Pad>& pads = handler->GetPads(); Pad& pad = pads[port_no]; 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_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_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; //~399 on sensor y is a level non moving controller pad.m_sensor_y = 399; pad.m_sensor_x = pad.m_sensor_z = pad.m_sensor_g = 512; return CELL_OK; }
/** * \brief Maps external Move controller data to DS3 input * Implementation detail: CellGemExtPortData's digital/analog fields map the same way as * libPad, so no translation is needed. * \param port_no DS3 port number to use * \param ext External data to modify * \return true on success, false if port_no controller is invalid */ static bool map_ext_to_ds3_input(const u32 port_no, CellGemExtPortData& ext) { const auto handler = fxm::get<pad_thread>(); if (!handler) { return false; } auto& pads = handler->GetPads(); const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) { return false; } //We have a choice here of NO_DEVICE or READ_FAILED...lets try no device for now if (port_no >= rinfo.now_connect) { return false; } auto pad = pads[port_no]; ext.status = 0; // CELL_GEM_EXT_CONNECTED | CELL_GEM_EXT_EXT0 | CELL_GEM_EXT_EXT1 ext.analog_left_x = pad->m_analog_left_x; ext.analog_left_y = pad->m_analog_left_y; ext.analog_right_x = pad->m_analog_right_x; ext.analog_right_y = pad->m_analog_right_y; ext.digital1 = pad->m_digital_1; ext.digital2 = pad->m_digital_2; return true; }
s32 cellPadInfoSensorMode(u32 port_no) { sys_io.trace("cellPadInfoSensorMode(port_no=%d)", port_no); const auto handler = fxm::get<pad_thread>(); if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; if (port_no >= CELL_MAX_PADS) return CELL_PAD_ERROR_INVALID_PARAMETER; const auto& pads = handler->GetPads(); if (port_no >= pads.size() || port_no >= handler->GetInfo().max_connect) return CELL_PAD_ERROR_NO_DEVICE; const auto pad = pads[port_no]; if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) return CELL_PAD_ERROR_NO_DEVICE; return (pad->m_device_capability & CELL_PAD_CAPABILITY_SENSOR_MODE) > 0; }
error_code cellPadGetDataExtra(u32 port_no, vm::ptr<u32> device_type, vm::ptr<CellPadData> data) { sys_io.trace("cellPadGetDataExtra(port_no=%d, device_type=*0x%x, data=*0x%x)", port_no, device_type, data); const auto handler = fxm::get<pad_thread>(); if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; if (port_no >= CELL_MAX_PADS || !data) return CELL_PAD_ERROR_INVALID_PARAMETER; const auto& pads = handler->GetPads(); if (port_no >= pads.size() || port_no >= handler->GetInfo().max_connect) return CELL_PAD_ERROR_NO_DEVICE; const auto pad = pads[port_no]; if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) return CELL_PAD_ERROR_NO_DEVICE; // TODO: This is used just to get data from a BD/CEC remote, // but if the port isnt a remote, device type is set to 0 and just regular cellPadGetData is returned if (device_type) // no error is returned on NULL { *device_type = 0; } // set BD data before just incase data->button[24] = 0x0; data->button[25] = 0x0; return cellPadGetData(port_no, data); }
/** * \brief Maps Move controller data (digital buttons, and analog Trigger data) to DS3 pad input. * Unavoidably buttons conflict with DS3 mappings, which is problematic for some games. * \param port_no DS3 port number to use * \param digital_buttons Bitmask filled with CELL_GEM_CTRL_* values * \param analog_t Analog value of Move's Trigger. Currently mapped to R2. * \return true on success, false if port_no controller is invalid */ static bool map_to_ds3_input(const u32 port_no, be_t<u16>& digital_buttons, be_t<u16>& analog_t) { const auto handler = fxm::get<pad_thread>(); if (!handler) { return false; } const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect || port_no >= rinfo.now_connect) { return false; } auto& pads = handler->GetPads(); auto pad = pads[port_no]; for (Button& button : pad->m_buttons) { //here we check btns, and set pad accordingly, if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL2) { if (button.m_pressed) pad->m_digital_2 |= button.m_outKeyCode; else pad->m_digital_2 &= ~button.m_outKeyCode; switch (button.m_outKeyCode) { case CELL_PAD_CTRL_SQUARE: pad->m_press_square = button.m_value; break; case CELL_PAD_CTRL_CROSS: pad->m_press_cross = button.m_value; break; case CELL_PAD_CTRL_CIRCLE: pad->m_press_circle = button.m_value; break; case CELL_PAD_CTRL_TRIANGLE: pad->m_press_triangle = button.m_value; break; case CELL_PAD_CTRL_R1: pad->m_press_R1 = button.m_value; break; case CELL_PAD_CTRL_L1: pad->m_press_L1 = button.m_value; break; case CELL_PAD_CTRL_R2: pad->m_press_R2 = button.m_value; break; case CELL_PAD_CTRL_L2: pad->m_press_L2 = button.m_value; break; default: break; } } if (button.m_flush) { button.m_pressed = false; button.m_flush = false; button.m_value = 0; } } memset(&digital_buttons, 0, sizeof(digital_buttons)); // map the Move key to R1 and the Trigger to R2 if (pad->m_press_R1) digital_buttons |= CELL_GEM_CTRL_MOVE; if (pad->m_press_R2) digital_buttons |= CELL_GEM_CTRL_T; if (pad->m_press_cross) digital_buttons |= CELL_GEM_CTRL_CROSS; if (pad->m_press_circle) digital_buttons |= CELL_GEM_CTRL_CIRCLE; if (pad->m_press_square) digital_buttons |= CELL_GEM_CTRL_SQUARE; if (pad->m_press_triangle) digital_buttons |= CELL_GEM_CTRL_TRIANGLE; if (pad->m_digital_1) digital_buttons |= CELL_GEM_CTRL_SELECT; if (pad->m_digital_2) digital_buttons |= CELL_GEM_CTRL_START; analog_t = pad->m_press_R2; return true; }
error_code cellPadGetData(u32 port_no, vm::ptr<CellPadData> data) { sys_io.trace("cellPadGetData(port_no=%d, data=*0x%x)", port_no, data); const auto handler = fxm::get<pad_thread>(); if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; if (port_no >= CELL_MAX_PADS || !data) return CELL_PAD_ERROR_INVALID_PARAMETER; const auto& pads = handler->GetPads(); if (port_no >= pads.size() || port_no >= handler->GetInfo().max_connect) return CELL_PAD_ERROR_NO_DEVICE; const auto pad = pads[port_no]; if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) return CELL_PAD_ERROR_NO_DEVICE; u16 d1Initial, d2Initial; d1Initial = pad->m_digital_1; d2Initial = pad->m_digital_2; bool btnChanged = false; for (Button& button : pad->m_buttons) { // here we check btns, and set pad accordingly, // if something changed, set btnChanged if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL1) { if (button.m_pressed) pad->m_digital_1 |= button.m_outKeyCode; else pad->m_digital_1 &= ~button.m_outKeyCode; switch (button.m_outKeyCode) { case CELL_PAD_CTRL_LEFT: if (pad->m_press_left != button.m_value) btnChanged = true; pad->m_press_left = button.m_value; break; case CELL_PAD_CTRL_DOWN: if (pad->m_press_down != button.m_value) btnChanged = true; pad->m_press_down = button.m_value; break; case CELL_PAD_CTRL_RIGHT: if (pad->m_press_right != button.m_value) btnChanged = true; pad->m_press_right = button.m_value; break; case CELL_PAD_CTRL_UP: if (pad->m_press_up != button.m_value) btnChanged = true; pad->m_press_up = button.m_value; break; // These arent pressure btns case CELL_PAD_CTRL_R3: case CELL_PAD_CTRL_L3: case CELL_PAD_CTRL_START: case CELL_PAD_CTRL_SELECT: default: break; } } else if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL2) { if (button.m_pressed) pad->m_digital_2 |= button.m_outKeyCode; else pad->m_digital_2 &= ~button.m_outKeyCode; switch (button.m_outKeyCode) { case CELL_PAD_CTRL_SQUARE: if (pad->m_press_square != button.m_value) btnChanged = true; pad->m_press_square = button.m_value; break; case CELL_PAD_CTRL_CROSS: if (pad->m_press_cross != button.m_value) btnChanged = true; pad->m_press_cross = button.m_value; break; case CELL_PAD_CTRL_CIRCLE: if (pad->m_press_circle != button.m_value) btnChanged = true; pad->m_press_circle = button.m_value; break; case CELL_PAD_CTRL_TRIANGLE: if (pad->m_press_triangle != button.m_value) btnChanged = true; pad->m_press_triangle = button.m_value; break; case CELL_PAD_CTRL_R1: if (pad->m_press_R1 != button.m_value) btnChanged = true; pad->m_press_R1 = button.m_value; break; case CELL_PAD_CTRL_L1: if (pad->m_press_L1 != button.m_value) btnChanged = true; pad->m_press_L1 = button.m_value; break; case CELL_PAD_CTRL_R2: if (pad->m_press_R2 != button.m_value) btnChanged = true; pad->m_press_R2 = button.m_value; break; case CELL_PAD_CTRL_L2: if (pad->m_press_L2 != button.m_value) btnChanged = true; pad->m_press_L2 = button.m_value; break; default: break; } } if (button.m_flush) { button.m_pressed = false; button.m_flush = false; button.m_value = 0; } } for (const AnalogStick& stick : pad->m_sticks) { switch (stick.m_offset) { case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X: if (pad->m_analog_left_x != stick.m_value) btnChanged = true; pad->m_analog_left_x = stick.m_value; break; case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y: if (pad->m_analog_left_y != stick.m_value) btnChanged = true; pad->m_analog_left_y = stick.m_value; break; case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X: if (pad->m_analog_right_x != stick.m_value) btnChanged = true; pad->m_analog_right_x = stick.m_value; break; case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y: if (pad->m_analog_right_y != stick.m_value) btnChanged = true; pad->m_analog_right_y = stick.m_value; break; default: break; } } for (const AnalogSensor& sensor : pad->m_sensors) { switch (sensor.m_offset) { case CELL_PAD_BTN_OFFSET_SENSOR_X: if (pad->m_sensor_x != sensor.m_value) btnChanged = true; pad->m_sensor_x = sensor.m_value; break; case CELL_PAD_BTN_OFFSET_SENSOR_Y: if (pad->m_sensor_y != sensor.m_value) btnChanged = true; pad->m_sensor_y = sensor.m_value; break; case CELL_PAD_BTN_OFFSET_SENSOR_Z: if (pad->m_sensor_z != sensor.m_value) btnChanged = true; pad->m_sensor_z = sensor.m_value; break; case CELL_PAD_BTN_OFFSET_SENSOR_G: if (pad->m_sensor_g != sensor.m_value) btnChanged = true; pad->m_sensor_g = sensor.m_value; break; default: break; } } if (d1Initial != pad->m_digital_1 || d2Initial != pad->m_digital_2) { btnChanged = true; } // the real hardware only fills the buffer up to "len" elements (16 bit each) if (pad->m_port_setting & CELL_PAD_SETTING_SENSOR_ON) { // report back new data every ~10 ms even if the input doesn't change // this is observed behaviour when using a Dualshock 3 controller static std::chrono::time_point<steady_clock> last_update[CELL_PAD_MAX_PORT_NUM] = { }; const std::chrono::time_point<steady_clock> now = steady_clock::now(); if (btnChanged || pad->m_buffer_cleared || (std::chrono::duration_cast<std::chrono::milliseconds>(now - last_update[port_no]).count() >= 10)) { data->len = CELL_PAD_LEN_CHANGE_SENSOR_ON; last_update[port_no] = now; } else { data->len = CELL_PAD_LEN_NO_CHANGE; } } else if (btnChanged || pad->m_buffer_cleared) { // only give back valid data if a controller state changed data->len = (pad->m_port_setting & CELL_PAD_SETTING_PRESS_ON) ? CELL_PAD_LEN_CHANGE_PRESS_ON : CELL_PAD_LEN_CHANGE_DEFAULT; } else { // report no state changes data->len = CELL_PAD_LEN_NO_CHANGE; } pad->m_buffer_cleared = false; // only update parts of the output struct depending on the controller setting if (data->len > CELL_PAD_LEN_NO_CHANGE) { memset(data->button, 0, sizeof(data->button)); data->button[0] = 0x0; // always 0 // 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[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_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_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_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_UP] = pad->m_press_up; data->button[CELL_PAD_BTN_OFFSET_PRESS_DOWN] = pad->m_press_down; } if (data->len >= CELL_PAD_LEN_CHANGE_PRESS_ON) { 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_CROSS] = pad->m_press_cross; 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_L2] = pad->m_press_L2; data->button[CELL_PAD_BTN_OFFSET_PRESS_R1] = pad->m_press_R1; data->button[CELL_PAD_BTN_OFFSET_PRESS_R2] = pad->m_press_R2; } if (data->len == CELL_PAD_LEN_CHANGE_SENSOR_ON) { 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_Z] = pad->m_sensor_z; data->button[CELL_PAD_BTN_OFFSET_SENSOR_G] = pad->m_sensor_g; } return CELL_OK; }
s32 user_interface::run_input_loop() { std::array<std::chrono::steady_clock::time_point, CELL_PAD_MAX_PORT_NUM> timestamp; timestamp.fill(std::chrono::steady_clock::now()); std::array<std::array<bool, pad_button::pad_button_max_enum>, CELL_PAD_MAX_PORT_NUM> button_state; for (auto& state : button_state) { state.fill(true); } input_timer.Start(); pad::SetIntercepted(true); while (!exit) { if (Emu.IsStopped()) return selection_code::canceled; std::this_thread::sleep_for(1ms); std::lock_guard lock(pad::g_pad_mutex); const auto handler = pad::get_current_handler(); const PadInfo& rinfo = handler->GetInfo(); if (Emu.IsPaused() || !rinfo.now_connect) { continue; } int pad_index = -1; for (const auto &pad : handler->GetPads()) { if (++pad_index >= CELL_PAD_MAX_PORT_NUM) { LOG_FATAL(RSX, "The native overlay cannot handle more than 7 pads! Current number of pads: %d", pad_index + 1); continue; } for (auto &button : pad->m_buttons) { u8 button_id = 255; if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL1) { switch (button.m_outKeyCode) { case CELL_PAD_CTRL_LEFT: button_id = pad_button::dpad_left; break; case CELL_PAD_CTRL_RIGHT: button_id = pad_button::dpad_right; break; case CELL_PAD_CTRL_DOWN: button_id = pad_button::dpad_down; break; case CELL_PAD_CTRL_UP: button_id = pad_button::dpad_up; break; case CELL_PAD_CTRL_SELECT: button_id = pad_button::select; break; case CELL_PAD_CTRL_START: button_id = pad_button::start; break; } } else if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL2) { switch (button.m_outKeyCode) { case CELL_PAD_CTRL_TRIANGLE: button_id = pad_button::triangle; break; case CELL_PAD_CTRL_CIRCLE: button_id = g_cfg.sys.enter_button_assignment == enter_button_assign::circle ? pad_button::cross : pad_button::circle; break; case CELL_PAD_CTRL_SQUARE: button_id = pad_button::square; break; case CELL_PAD_CTRL_CROSS: button_id = g_cfg.sys.enter_button_assignment == enter_button_assign::circle ? pad_button::circle : pad_button::cross; break; case CELL_PAD_CTRL_L1: button_id = pad_button::L1; break; case CELL_PAD_CTRL_R1: button_id = pad_button::R1; break; } } if (button_id < 255) { if (button.m_pressed) { if (button_id < 4) // d-pad button { if (!button_state[pad_index][button_id] || input_timer.GetMsSince(timestamp[pad_index]) > 400) { // d-pad button was not pressed, or was pressed more than 400ms ago timestamp[pad_index] = std::chrono::steady_clock::now(); on_button_pressed(static_cast<pad_button>(button_id)); } } else if (!button_state[pad_index][button_id]) { // button was not pressed on_button_pressed(static_cast<pad_button>(button_id)); } } button_state[pad_index][button_id] = button.m_pressed; } if (button.m_flush) { button.m_pressed = false; button.m_flush = false; button.m_value = 0; } if (exit) return 0; } } refresh(); } // Unreachable return 0; }
s32 cellPadGetData(u32 port_no, vm::ptr<CellPadData> data) { sys_io.trace("cellPadGetData(port_no=%d, data=*0x%x)", port_no, data); const auto handler = fxm::get<PadHandlerBase>(); if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; std::vector<Pad>& pads = handler->GetPads(); const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; //We have a choice here of NO_DEVICE or READ_FAILED...lets try no device for now if (port_no >= rinfo.now_connect) return CELL_PAD_ERROR_NO_DEVICE; Pad& pad = pads[port_no]; u16 d1Initial, d2Initial; d1Initial = pad.m_digital_1; d2Initial = pad.m_digital_2; bool btnChanged = false; for(Button& button : pad.m_buttons) { //here we check btns, and set pad accordingly, //if something changed, set btnChanged if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL1) { if (button.m_pressed) pad.m_digital_1 |= button.m_outKeyCode; else pad.m_digital_1 &= ~button.m_outKeyCode; switch (button.m_outKeyCode) { case CELL_PAD_CTRL_LEFT: if (pad.m_press_left != button.m_value) btnChanged = true; pad.m_press_left = button.m_value; break; case CELL_PAD_CTRL_DOWN: if (pad.m_press_down != button.m_value) btnChanged = true; pad.m_press_down = button.m_value; break; case CELL_PAD_CTRL_RIGHT: if (pad.m_press_right != button.m_value) btnChanged = true; pad.m_press_right = button.m_value; break; case CELL_PAD_CTRL_UP: if (pad.m_press_up != button.m_value) btnChanged = true; pad.m_press_up = button.m_value; break; //These arent pressure btns case CELL_PAD_CTRL_R3: case CELL_PAD_CTRL_L3: case CELL_PAD_CTRL_START: case CELL_PAD_CTRL_SELECT: default: break; } } else if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL2) { if (button.m_pressed) pad.m_digital_2 |= button.m_outKeyCode; else pad.m_digital_2 &= ~button.m_outKeyCode; switch (button.m_outKeyCode) { case CELL_PAD_CTRL_SQUARE: if (pad.m_press_square != button.m_value) btnChanged = true; pad.m_press_square = button.m_value; break; case CELL_PAD_CTRL_CROSS: if (pad.m_press_cross != button.m_value) btnChanged = true; pad.m_press_cross = button.m_value; break; case CELL_PAD_CTRL_CIRCLE: if (pad.m_press_circle != button.m_value) btnChanged = true; pad.m_press_circle = button.m_value; break; case CELL_PAD_CTRL_TRIANGLE: if (pad.m_press_triangle != button.m_value) btnChanged = true; pad.m_press_triangle = button.m_value; break; case CELL_PAD_CTRL_R1: if (pad.m_press_R1 != button.m_value) btnChanged = true; pad.m_press_R1 = button.m_value; break; case CELL_PAD_CTRL_L1: if (pad.m_press_L1 != button.m_value) btnChanged = true; pad.m_press_L1 = button.m_value; break; case CELL_PAD_CTRL_R2: if (pad.m_press_R2 != button.m_value) btnChanged = true; pad.m_press_R2 = button.m_value; break; case CELL_PAD_CTRL_L2: if (pad.m_press_L2 != button.m_value) btnChanged = true; pad.m_press_L2 = button.m_value; break; default: break; } } if(button.m_flush) { button.m_pressed = false; button.m_flush = false; button.m_value = 0; } } for (const AnalogStick& stick : pad.m_sticks) { switch (stick.m_offset) { case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X: if (pad.m_analog_left_x != stick.m_value) btnChanged = true; pad.m_analog_left_x = stick.m_value; break; case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y: if (pad.m_analog_left_y != stick.m_value) btnChanged = true; pad.m_analog_left_y = stick.m_value; break; case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X: if (pad.m_analog_right_x != stick.m_value) btnChanged = true; pad.m_analog_right_x = stick.m_value; break; case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y: if (pad.m_analog_right_y != stick.m_value) btnChanged = true; pad.m_analog_right_y = stick.m_value; break; default: break; } } for (const AnalogSensor& sensor : pad.m_sensors) { switch (sensor.m_offset) { case CELL_PAD_BTN_OFFSET_SENSOR_X: if (pad.m_sensor_x != sensor.m_value) btnChanged = true; pad.m_sensor_x = sensor.m_value; break; case CELL_PAD_BTN_OFFSET_SENSOR_Y: if (pad.m_sensor_y != sensor.m_value) btnChanged = true; pad.m_sensor_y = sensor.m_value; break; case CELL_PAD_BTN_OFFSET_SENSOR_Z: if (pad.m_sensor_z != sensor.m_value) btnChanged = true; pad.m_sensor_z = sensor.m_value; break; case CELL_PAD_BTN_OFFSET_SENSOR_G: if (pad.m_sensor_g != sensor.m_value) btnChanged = true; pad.m_sensor_g = sensor.m_value; break; default: break; } } if (d1Initial != pad.m_digital_1 || d2Initial != pad.m_digital_2) { btnChanged = true; } //not sure if this should officially change with capabilities/portsettings :( data->len = 24; if (pad.m_buffer_cleared) { pad.m_buffer_cleared = false; } else if (!btnChanged) { data->len = 0; } data->button[0] = 0x0; // always 0 // bits 15-8 reserved, 7-4 = 0x7, 3-0: data->len/2; data->button[1] = (0x7 << 4) | std::min(data->len / 2, 15) & 0xF; //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_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_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_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_LEFT] = pad.m_press_left; 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_TRIANGLE] = pad.m_press_triangle; 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_SQUARE] = pad.m_press_square; 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_R1] = pad.m_press_R1; 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_Y] = pad.m_sensor_y; data->button[CELL_PAD_BTN_OFFSET_SENSOR_Z] = pad.m_sensor_z; data->button[CELL_PAD_BTN_OFFSET_SENSOR_G] = pad.m_sensor_g; return CELL_OK; }