2015-02-08 14:08:26 +00:00
|
|
|
/* LilyPad - Pad plugin for PS2 Emulator
|
|
|
|
* Copyright (C) 2002-2015 PCSX2 Dev Team/ChickenLiver
|
|
|
|
*
|
|
|
|
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
|
|
|
* terms of the GNU Lesser General Public License as published by the Free
|
|
|
|
* Software Found- ation, either version 3 of the License, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
|
|
* details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "Global.h"
|
|
|
|
#include "InputManager.h"
|
|
|
|
#include "Linux/JoyEvdev.h"
|
|
|
|
#include "Linux/bitmaskros.h"
|
|
|
|
|
2016-09-04 12:16:34 +00:00
|
|
|
JoyEvdev::JoyEvdev(int fd, bool ds3, const wchar_t *id)
|
|
|
|
: Device(LNX_JOY, OTHER, id, id)
|
|
|
|
, m_fd(fd)
|
|
|
|
{
|
|
|
|
// XXX LNX_JOY => DS3 or ???
|
|
|
|
|
|
|
|
m_abs.clear();
|
|
|
|
m_btn.clear();
|
|
|
|
m_rel.clear();
|
|
|
|
int last = 0;
|
|
|
|
|
|
|
|
uint8_t abs_bitmap[nUcharsForNBits(ABS_CNT)] = {0};
|
|
|
|
uint8_t btn_bitmap[nUcharsForNBits(KEY_CNT)] = {0};
|
|
|
|
uint8_t rel_bitmap[nUcharsForNBits(REL_CNT)] = {0};
|
|
|
|
|
|
|
|
// Add buttons
|
|
|
|
if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(btn_bitmap)), btn_bitmap) >= 0) {
|
|
|
|
for (int bit = BTN_MISC; bit < KEY_CNT; bit++) {
|
|
|
|
if (testBit(bit, btn_bitmap)) {
|
|
|
|
AddPhysicalControl(PSHBTN, last, 0);
|
|
|
|
m_btn.push_back(bit);
|
|
|
|
last++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add Absolute axis
|
|
|
|
if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmap)), abs_bitmap) >= 0) {
|
|
|
|
for (int bit = 0; bit < ABS_CNT; bit++) {
|
|
|
|
ControlType type = ABSAXIS; // FIXME DS3
|
|
|
|
|
|
|
|
if (testBit(bit, abs_bitmap)) {
|
|
|
|
input_absinfo info;
|
|
|
|
if (ioctl(m_fd, EVIOCGABS(bit), &info) < 0) {
|
|
|
|
fprintf(stderr, "Invalid IOCTL EVIOCGID\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
AddPhysicalControl(ABSAXIS, last, 0);
|
|
|
|
last++;
|
|
|
|
if (std::abs(info.value - 127) < 2) {
|
|
|
|
fprintf(stderr, "HALF Axis info %d=>%d, current %d, flat %d, resolution %d\n", info.minimum, info.maximum, info.value, info.flat, info.resolution);
|
|
|
|
|
|
|
|
// Half axis must be split into 2 parts...
|
|
|
|
AddPhysicalControl(ABSAXIS, last, 0);
|
|
|
|
last++;
|
|
|
|
|
|
|
|
m_abs.push_back(abs_info(bit, info.minimum, info.value, type));
|
|
|
|
m_abs.push_back(abs_info(bit, info.value, info.maximum, type));
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "FULL Axis info %d=>%d, current %d, flat %d, resolution %d\n", info.minimum, info.maximum, info.value, info.flat, info.resolution);
|
|
|
|
|
|
|
|
m_abs.push_back(abs_info(bit, info.minimum, info.maximum, type));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add relative axis
|
|
|
|
if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmap)), rel_bitmap) >= 0) {
|
|
|
|
for (int bit = 0; bit < REL_CNT; bit++) {
|
|
|
|
if (testBit(bit, rel_bitmap)) {
|
|
|
|
AddPhysicalControl(RELAXIS, last, last);
|
|
|
|
m_rel.push_back(bit);
|
|
|
|
last++;
|
|
|
|
|
|
|
|
fprintf(stderr, "Add relative nb %d\n", bit);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr, "New device created. Found axe:%zu, buttons:%zu, m_rel:%zu\n\n", m_abs.size(), m_btn.size(), m_rel.size());
|
2015-02-08 14:08:26 +00:00
|
|
|
}
|
|
|
|
|
2016-09-04 12:16:34 +00:00
|
|
|
JoyEvdev::~JoyEvdev()
|
|
|
|
{
|
|
|
|
close(m_fd);
|
2015-02-08 14:08:26 +00:00
|
|
|
}
|
|
|
|
|
2016-09-04 12:16:34 +00:00
|
|
|
int JoyEvdev::Activate(InitInfo *args)
|
|
|
|
{
|
|
|
|
AllocState();
|
2015-02-08 14:08:26 +00:00
|
|
|
|
2016-09-04 12:16:34 +00:00
|
|
|
uint16_t size = m_abs.size() + m_rel.size() + m_btn.size();
|
|
|
|
memset(physicalControlState, 0, sizeof(int) * size);
|
2015-02-08 14:08:26 +00:00
|
|
|
|
2016-09-04 12:16:34 +00:00
|
|
|
active = 1;
|
|
|
|
return 1;
|
2015-02-08 14:08:26 +00:00
|
|
|
}
|
|
|
|
|
2016-09-04 12:16:34 +00:00
|
|
|
int JoyEvdev::Update()
|
|
|
|
{
|
2015-02-08 14:08:26 +00:00
|
|
|
struct input_event events[32];
|
2016-09-04 12:16:34 +00:00
|
|
|
int len;
|
|
|
|
int status = 0;
|
|
|
|
//fprintf(stderr, "Update was called\n");
|
|
|
|
|
|
|
|
// Do a big read to reduce kernel validation
|
2015-02-08 14:08:26 +00:00
|
|
|
while ((len = read(m_fd, events, (sizeof events))) > 0) {
|
2016-09-04 12:16:34 +00:00
|
|
|
int evt_nb = len / sizeof(input_event);
|
|
|
|
//fprintf(stderr, "Poll %d events available\n", evt_nb);
|
|
|
|
for (int i = 0; i < evt_nb; i++) {
|
|
|
|
switch (events[i].type) {
|
|
|
|
case EV_ABS: {
|
|
|
|
for (size_t idx = 0; idx < m_abs.size(); idx++) {
|
|
|
|
if (m_abs[idx].code == events[i].code) {
|
|
|
|
// XXX strict or not ?
|
|
|
|
if ((events[i].value >= m_abs[idx].min) && (events[i].value <= m_abs[idx].max)) {
|
|
|
|
// XXX FIX shitty api
|
|
|
|
int scale = m_abs[idx].scale(events[i].value);
|
|
|
|
fprintf(stderr, "axis value %d scaled to %d\n", events[i].value, scale);
|
|
|
|
physicalControlState[idx + m_btn.size()] = scale;
|
|
|
|
status = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
case EV_KEY: {
|
|
|
|
for (size_t idx = 0; idx < m_btn.size(); idx++) {
|
|
|
|
if (m_btn[idx] == events[i].code) {
|
|
|
|
fprintf(stderr, "Event KEY:%d detected with value %d\n", events[i].code, events[i].value);
|
|
|
|
physicalControlState[idx] = FULLY_DOWN * events[i].value;
|
|
|
|
status = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} break;
|
|
|
|
case EV_REL:
|
|
|
|
// XXX
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
2015-02-08 14:08:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-04 12:16:34 +00:00
|
|
|
static std::wstring CorrectJoySupport(int fd)
|
|
|
|
{
|
|
|
|
struct input_id id;
|
|
|
|
if (ioctl(fd, EVIOCGID, &id) < 0) {
|
|
|
|
fprintf(stderr, "Invalid IOCTL EVIOCGID\n");
|
|
|
|
return L"";
|
|
|
|
}
|
2015-02-08 14:08:26 +00:00
|
|
|
|
2016-09-04 12:16:34 +00:00
|
|
|
char dev_name[128];
|
|
|
|
if (ioctl(fd, EVIOCGNAME(128), dev_name) < 0) {
|
|
|
|
fprintf(stderr, "Invalid IOCTL EVIOCGNAME\n");
|
|
|
|
return L"";
|
|
|
|
}
|
2015-02-08 14:08:26 +00:00
|
|
|
|
2016-09-04 12:16:34 +00:00
|
|
|
fprintf(stderr, "Found input device => bustype:%x, vendor:%x, product:%x, version:%x\n", id.bustype, id.vendor, id.product, id.version);
|
|
|
|
fprintf(stderr, "\tName:%s\n", dev_name);
|
2015-02-08 14:08:26 +00:00
|
|
|
|
2016-09-04 12:16:34 +00:00
|
|
|
std::string s(dev_name);
|
|
|
|
return std::wstring(s.begin(), s.end());
|
2015-02-08 14:08:26 +00:00
|
|
|
}
|
|
|
|
|
2016-09-04 12:16:34 +00:00
|
|
|
void EnumJoystickEvdev()
|
|
|
|
{
|
|
|
|
// Technically it must be done with udev but another lib for
|
|
|
|
// avoid a loop is too much for me (even if udev is mandatory
|
|
|
|
// so maybe later)
|
|
|
|
std::string input_root("/dev/input/event");
|
|
|
|
for (int i = 0; i < 32; i++) {
|
|
|
|
std::string dev = input_root + std::to_string(i);
|
|
|
|
|
|
|
|
int fd = open(dev.c_str(), O_RDWR | O_NONBLOCK);
|
|
|
|
if (fd < 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::wstring id = CorrectJoySupport(fd);
|
|
|
|
if (id.size() != 0) {
|
|
|
|
bool ds3 = id.find(L"PLAYSTATION(R)3") != std::string::npos;
|
|
|
|
if (ds3) {
|
|
|
|
fprintf(stderr, "DS3 device detected !!!\n");
|
|
|
|
}
|
|
|
|
dm->AddDevice(new JoyEvdev(fd, ds3, id.c_str()));
|
|
|
|
} else if (fd >= 0)
|
|
|
|
close(fd);
|
|
|
|
}
|
2015-02-08 14:08:26 +00:00
|
|
|
}
|