mirror of https://github.com/PCSX2/pcsx2.git
USB: Remove joydev support
This commit is contained in:
parent
d0ada6b40a
commit
2925077169
|
@ -403,8 +403,6 @@ set(pcsx2USBSources
|
||||||
USB/shared/ringbuffer.cpp
|
USB/shared/ringbuffer.cpp
|
||||||
USB/icon_buzz_24.cpp
|
USB/icon_buzz_24.cpp
|
||||||
USB/usb-msd/usb-msd-gtk.cpp
|
USB/usb-msd/usb-msd-gtk.cpp
|
||||||
USB/usb-pad/joydev/joydev.cpp
|
|
||||||
USB/usb-pad/joydev/joydev-gtk.cpp
|
|
||||||
USB/usb-pad/evdev/shared-gtk.cpp
|
USB/usb-pad/evdev/shared-gtk.cpp
|
||||||
USB/usb-pad/evdev/evdev-ff.cpp
|
USB/usb-pad/evdev/evdev-ff.cpp
|
||||||
USB/usb-pad/evdev/evdev.cpp
|
USB/usb-pad/evdev/evdev.cpp
|
||||||
|
@ -468,7 +466,6 @@ set(pcsx2USBHeaders
|
||||||
USB/linux/util.h
|
USB/linux/util.h
|
||||||
USB/gtk.h
|
USB/gtk.h
|
||||||
USB/icon_buzz_24.h
|
USB/icon_buzz_24.h
|
||||||
USB/usb-pad/joydev/joydev.h
|
|
||||||
USB/usb-pad/evdev/shared.h
|
USB/usb-pad/evdev/shared.h
|
||||||
USB/usb-pad/evdev/evdev.h
|
USB/usb-pad/evdev/evdev.h
|
||||||
USB/usb-pad/evdev/evdev-ff.h
|
USB/usb-pad/evdev/evdev-ff.h
|
||||||
|
|
|
@ -15,11 +15,9 @@
|
||||||
|
|
||||||
#include "padproxy.h"
|
#include "padproxy.h"
|
||||||
#include "evdev/evdev.h"
|
#include "evdev/evdev.h"
|
||||||
#include "joydev/joydev.h"
|
|
||||||
|
|
||||||
void usb_pad::RegisterPad::Register()
|
void usb_pad::RegisterPad::Register()
|
||||||
{
|
{
|
||||||
auto& inst = RegisterPad::instance();
|
auto& inst = RegisterPad::instance();
|
||||||
inst.Add("evdev", new PadProxy<evdev::EvDevPad>());
|
inst.Add("evdev", new PadProxy<evdev::EvDevPad>());
|
||||||
inst.Add("joydev", new PadProxy<joydev::JoyDevPad>());
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -540,7 +540,7 @@ namespace usb_pad
|
||||||
|
|
||||||
cfg.use_hidraw_ff_pt = false;
|
cfg.use_hidraw_ff_pt = false;
|
||||||
bool is_evdev = (strncmp(apiname, "evdev", 5) == 0);
|
bool is_evdev = (strncmp(apiname, "evdev", 5) == 0);
|
||||||
if (is_evdev) //TODO idk about joydev
|
if (is_evdev)
|
||||||
{
|
{
|
||||||
LoadSetting(dev_type, port, apiname, N_HIDRAW_FF_PT, cfg.use_hidraw_ff_pt);
|
LoadSetting(dev_type, port, apiname, N_HIDRAW_FF_PT, cfg.use_hidraw_ff_pt);
|
||||||
}
|
}
|
||||||
|
@ -716,7 +716,7 @@ namespace usb_pad
|
||||||
|
|
||||||
std::stringstream str;
|
std::stringstream str;
|
||||||
str << it.name;
|
str << it.name;
|
||||||
if (!strcmp(apiname, "evdev") && !it.id.empty())
|
if (!it.id.empty())
|
||||||
str << " [" << it.id << "]";
|
str << " [" << it.id << "]";
|
||||||
|
|
||||||
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(rs_cb), str.str().c_str());
|
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(rs_cb), str.str().c_str());
|
||||||
|
|
|
@ -1,178 +0,0 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
|
||||||
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
|
||||||
*
|
|
||||||
* 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 "joydev.h"
|
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <thread>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sstream>
|
|
||||||
#include "USB/gtk.h"
|
|
||||||
|
|
||||||
namespace usb_pad
|
|
||||||
{
|
|
||||||
namespace joydev
|
|
||||||
{
|
|
||||||
|
|
||||||
using sys_clock = std::chrono::system_clock;
|
|
||||||
using ms = std::chrono::milliseconds;
|
|
||||||
|
|
||||||
#define JOYTYPE "joytype"
|
|
||||||
#define CFG "cfg"
|
|
||||||
|
|
||||||
static bool GetEventName(const char* dev_type, int map, int event, bool is_button, const char** name)
|
|
||||||
{
|
|
||||||
static char buf[256] = {0};
|
|
||||||
if (is_button)
|
|
||||||
{
|
|
||||||
snprintf(buf, sizeof(buf), "Button %d", event);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// assuming that PS2 axes are always mapped to PC axes
|
|
||||||
snprintf(buf, sizeof(buf), "Axis %d", event);
|
|
||||||
}
|
|
||||||
*name = buf;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool PollInput(const std::vector<std::pair<std::string, usb_pad::evdev::ConfigMapping>>& fds, std::string& dev_name, bool isaxis, int& value, bool& inverted, int& initial)
|
|
||||||
{
|
|
||||||
int event_fd = -1;
|
|
||||||
ssize_t len;
|
|
||||||
struct js_event event;
|
|
||||||
|
|
||||||
fd_set fdset;
|
|
||||||
int maxfd = -1;
|
|
||||||
|
|
||||||
FD_ZERO(&fdset);
|
|
||||||
for (const auto& js : fds)
|
|
||||||
{
|
|
||||||
FD_SET(js.second.fd, &fdset);
|
|
||||||
if (maxfd < js.second.fd)
|
|
||||||
maxfd = js.second.fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
inverted = false;
|
|
||||||
|
|
||||||
// empty event queues
|
|
||||||
for (const auto& js : fds)
|
|
||||||
while ((len = read(js.second.fd, &event, sizeof(event))) > 0)
|
|
||||||
;
|
|
||||||
|
|
||||||
struct axis_value
|
|
||||||
{
|
|
||||||
int16_t value;
|
|
||||||
bool initial;
|
|
||||||
};
|
|
||||||
axis_value axisVal[ABS_MAX + 1] = {0};
|
|
||||||
|
|
||||||
struct timeval timeout
|
|
||||||
{
|
|
||||||
};
|
|
||||||
timeout.tv_sec = 5;
|
|
||||||
int result = select(maxfd + 1, &fdset, NULL, NULL, &timeout);
|
|
||||||
|
|
||||||
if (!result)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (result == -1)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& js : fds)
|
|
||||||
{
|
|
||||||
if (FD_ISSET(js.second.fd, &fdset))
|
|
||||||
{
|
|
||||||
event_fd = js.second.fd;
|
|
||||||
dev_name = js.first;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event_fd == -1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto last = sys_clock::now();
|
|
||||||
//Non-blocking read sets len to -1 and errno to EAGAIN if no new data
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
auto dur = std::chrono::duration_cast<ms>(sys_clock::now() - last).count();
|
|
||||||
if (dur > 5000)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if ((len = read(event_fd, &event, sizeof(event))) > -1 && (len == sizeof(event)))
|
|
||||||
{
|
|
||||||
if (isaxis && event.type == JS_EVENT_AXIS)
|
|
||||||
{
|
|
||||||
auto& val = axisVal[event.number];
|
|
||||||
|
|
||||||
if (!val.initial)
|
|
||||||
{
|
|
||||||
val.value = event.value;
|
|
||||||
val.initial = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int diff = event.value - val.value;
|
|
||||||
if (std::abs(diff) > 2047)
|
|
||||||
{
|
|
||||||
value = event.number;
|
|
||||||
inverted = (diff < 0);
|
|
||||||
initial = val.value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!isaxis && event.type == JS_EVENT_BUTTON)
|
|
||||||
{
|
|
||||||
if (event.value)
|
|
||||||
{
|
|
||||||
value = event.number;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (errno != EAGAIN)
|
|
||||||
{
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
while (gtk_events_pending())
|
|
||||||
gtk_main_iteration_do(FALSE);
|
|
||||||
std::this_thread::sleep_for(ms(1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
error:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int JoyDevPad::Configure(int port, const char* dev_type, void* data)
|
|
||||||
{
|
|
||||||
if (!strcmp(dev_type, BuzzDevice::TypeName()))
|
|
||||||
return RESULT_CANCELED;
|
|
||||||
|
|
||||||
evdev::ApiCallbacks apicbs{GetEventName, EnumerateDevices, PollInput};
|
|
||||||
int ret = evdev::GtkPadConfigure(port, dev_type, "Joydev Settings", joydev::APINAME, GTK_WINDOW(data), apicbs);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace joydev
|
|
||||||
} // namespace usb_pad
|
|
|
@ -1,497 +0,0 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
|
||||||
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
|
||||||
*
|
|
||||||
* 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 "joydev.h"
|
|
||||||
#include "USB/linux/util.h"
|
|
||||||
#include "Utilities/Console.h"
|
|
||||||
#include <cassert>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
namespace usb_pad
|
|
||||||
{
|
|
||||||
namespace joydev
|
|
||||||
{
|
|
||||||
|
|
||||||
using namespace evdev;
|
|
||||||
|
|
||||||
#define NORM(x, n) (((uint32_t)(32768 + x) * n) / 0xFFFF)
|
|
||||||
#define NORM2(x, n) (((uint32_t)(32768 + x) * n) / 0x7FFF)
|
|
||||||
|
|
||||||
void EnumerateDevices(device_list& list)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
int res;
|
|
||||||
char buf[256];
|
|
||||||
|
|
||||||
std::stringstream str;
|
|
||||||
struct dirent* dp;
|
|
||||||
|
|
||||||
DIR* dirp = opendir("/dev/input/");
|
|
||||||
if (!dirp)
|
|
||||||
{
|
|
||||||
Console.Warning("Error opening /dev/input/");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((dp = readdir(dirp)))
|
|
||||||
{
|
|
||||||
if (strncmp(dp->d_name, "js", 2) == 0)
|
|
||||||
{
|
|
||||||
|
|
||||||
str.clear();
|
|
||||||
str.str("");
|
|
||||||
str << "/dev/input/" << dp->d_name;
|
|
||||||
const std::string& path = str.str();
|
|
||||||
fd = open(path.c_str(), O_RDONLY | O_NONBLOCK);
|
|
||||||
|
|
||||||
if (fd < 0)
|
|
||||||
{
|
|
||||||
Console.Warning("Joydev: Unable to open device: %s", path.c_str());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = ioctl(fd, JSIOCGNAME(sizeof(buf)), buf);
|
|
||||||
if (res < 0)
|
|
||||||
Console.Warning("JSIOCGNAME");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
list.push_back({buf, buf, path});
|
|
||||||
}
|
|
||||||
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closedir(dirp);
|
|
||||||
}
|
|
||||||
|
|
||||||
int JoyDevPad::TokenIn(uint8_t* buf, int buflen)
|
|
||||||
{
|
|
||||||
ssize_t len;
|
|
||||||
struct js_event events[32];
|
|
||||||
fd_set fds;
|
|
||||||
int maxfd;
|
|
||||||
|
|
||||||
int range = range_max(mType);
|
|
||||||
|
|
||||||
FD_ZERO(&fds);
|
|
||||||
maxfd = -1;
|
|
||||||
|
|
||||||
for (auto& device : mDevices)
|
|
||||||
{
|
|
||||||
FD_SET(device.cfg.fd, &fds);
|
|
||||||
if (maxfd < device.cfg.fd)
|
|
||||||
maxfd = device.cfg.fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct timeval timeout;
|
|
||||||
timeout.tv_usec = timeout.tv_sec = 0; // 0 - return from select immediately
|
|
||||||
int result = select(maxfd + 1, &fds, NULL, NULL, &timeout);
|
|
||||||
|
|
||||||
if (result <= 0)
|
|
||||||
{
|
|
||||||
return USB_RET_NAK; // If no new data, NAK it
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& device : mDevices)
|
|
||||||
{
|
|
||||||
if (!FD_ISSET(device.cfg.fd, &fds))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Non-blocking read sets len to -1 and errno to EAGAIN if no new data
|
|
||||||
while ((len = read(device.cfg.fd, &events, sizeof(events))) > -1)
|
|
||||||
{
|
|
||||||
len /= sizeof(events[0]);
|
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
js_event& event = events[i];
|
|
||||||
if ((event.type & ~JS_EVENT_INIT) == JS_EVENT_AXIS)
|
|
||||||
{
|
|
||||||
switch (device.axis_map[event.number])
|
|
||||||
{
|
|
||||||
case 0x80 | JOY_STEERING:
|
|
||||||
case ABS_X:
|
|
||||||
mWheelData.steering = device.cfg.inverted[0] ? range - NORM(event.value, range) : NORM(event.value, range);
|
|
||||||
break;
|
|
||||||
case ABS_Y:
|
|
||||||
mWheelData.clutch = NORM(event.value, 0xFF);
|
|
||||||
break;
|
|
||||||
//case ABS_RX: mWheelData.axis_rx = NORM(event.value, 0xFF); break;
|
|
||||||
case ABS_RY:
|
|
||||||
treat_me_like_ABS_RY:
|
|
||||||
mWheelData.throttle = 0xFF;
|
|
||||||
mWheelData.brake = 0xFF;
|
|
||||||
if (event.value < 0)
|
|
||||||
mWheelData.throttle = NORM2(event.value, 0xFF);
|
|
||||||
else
|
|
||||||
mWheelData.brake = NORM2(-event.value, 0xFF);
|
|
||||||
break;
|
|
||||||
case 0x80 | JOY_THROTTLE:
|
|
||||||
case ABS_Z:
|
|
||||||
if (device.is_gamepad)
|
|
||||||
mWheelData.brake = 0xFF - NORM(event.value, 0xFF);
|
|
||||||
else
|
|
||||||
mWheelData.throttle = device.cfg.inverted[1] ? NORM(event.value, 0xFF) : 0xFF - NORM(event.value, 0xFF);
|
|
||||||
break;
|
|
||||||
case 0x80 | JOY_BRAKE:
|
|
||||||
case ABS_RZ:
|
|
||||||
if (device.is_gamepad)
|
|
||||||
mWheelData.throttle = 0xFF - NORM(event.value, 0xFF);
|
|
||||||
else if (device.is_dualanalog)
|
|
||||||
goto treat_me_like_ABS_RY;
|
|
||||||
else
|
|
||||||
mWheelData.brake = device.cfg.inverted[2] ? NORM(event.value, 0xFF) : 0xFF - NORM(event.value, 0xFF);
|
|
||||||
break;
|
|
||||||
|
|
||||||
//FIXME hatswitch mapping maybe
|
|
||||||
case ABS_HAT0X:
|
|
||||||
case ABS_HAT1X:
|
|
||||||
case ABS_HAT2X:
|
|
||||||
case ABS_HAT3X:
|
|
||||||
if (event.value < 0) //left usually
|
|
||||||
mWheelData.hat_horz = PAD_HAT_W;
|
|
||||||
else if (event.value > 0) //right
|
|
||||||
mWheelData.hat_horz = PAD_HAT_E;
|
|
||||||
else
|
|
||||||
mWheelData.hat_horz = PAD_HAT_COUNT;
|
|
||||||
break;
|
|
||||||
case ABS_HAT0Y:
|
|
||||||
case ABS_HAT1Y:
|
|
||||||
case ABS_HAT2Y:
|
|
||||||
case ABS_HAT3Y:
|
|
||||||
if (event.value < 0) //up usually
|
|
||||||
mWheelData.hat_vert = PAD_HAT_N;
|
|
||||||
else if (event.value > 0) //down
|
|
||||||
mWheelData.hat_vert = PAD_HAT_S;
|
|
||||||
else
|
|
||||||
mWheelData.hat_vert = PAD_HAT_COUNT;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((event.type & ~JS_EVENT_INIT) == JS_EVENT_BUTTON)
|
|
||||||
{
|
|
||||||
PS2Buttons button = PAD_BUTTON_COUNT;
|
|
||||||
if (device.btn_map[event.number] >= (0x8000 | JOY_CROSS) &&
|
|
||||||
device.btn_map[event.number] <= (0x8000 | JOY_L3))
|
|
||||||
{
|
|
||||||
button = (PS2Buttons)(device.btn_map[event.number] & ~0x8000);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (device.btn_map[event.number] >= BTN_TRIGGER &&
|
|
||||||
device.btn_map[event.number] < BTN_BASE5)
|
|
||||||
{
|
|
||||||
button = (PS2Buttons)(device.btn_map[event.number] - BTN_TRIGGER);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Map to xbox360ish controller
|
|
||||||
switch (device.btn_map[event.number])
|
|
||||||
{
|
|
||||||
// Digital hatswitch
|
|
||||||
case 0x8000 | JOY_LEFT:
|
|
||||||
mWheelData.hat_horz = PAD_HAT_W;
|
|
||||||
break;
|
|
||||||
case 0x8000 | JOY_RIGHT:
|
|
||||||
mWheelData.hat_horz = PAD_HAT_E;
|
|
||||||
break;
|
|
||||||
case 0x8000 | JOY_UP:
|
|
||||||
mWheelData.hat_vert = PAD_HAT_N;
|
|
||||||
break;
|
|
||||||
case 0x8000 | JOY_DOWN:
|
|
||||||
mWheelData.hat_vert = PAD_HAT_S;
|
|
||||||
break;
|
|
||||||
case BTN_WEST:
|
|
||||||
button = PAD_SQUARE;
|
|
||||||
break;
|
|
||||||
case BTN_NORTH:
|
|
||||||
button = PAD_TRIANGLE;
|
|
||||||
break;
|
|
||||||
case BTN_EAST:
|
|
||||||
button = PAD_CIRCLE;
|
|
||||||
break;
|
|
||||||
case BTN_SOUTH:
|
|
||||||
button = PAD_CROSS;
|
|
||||||
break;
|
|
||||||
case BTN_SELECT:
|
|
||||||
button = PAD_SELECT;
|
|
||||||
break;
|
|
||||||
case BTN_START:
|
|
||||||
button = PAD_START;
|
|
||||||
break;
|
|
||||||
case BTN_TR:
|
|
||||||
button = PAD_R1;
|
|
||||||
break;
|
|
||||||
case BTN_TL:
|
|
||||||
button = PAD_L1;
|
|
||||||
break;
|
|
||||||
case BTN_THUMBR:
|
|
||||||
button = PAD_R2;
|
|
||||||
break;
|
|
||||||
case BTN_THUMBL:
|
|
||||||
button = PAD_L2;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//if (button != PAD_BUTTON_COUNT)
|
|
||||||
{
|
|
||||||
if (event.value)
|
|
||||||
mWheelData.buttons |= 1 << convert_wt_btn(mType, button); //on
|
|
||||||
else
|
|
||||||
mWheelData.buttons &= ~(1 << convert_wt_btn(mType, button)); //off
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len <= 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (mWheelData.hat_vert)
|
|
||||||
{
|
|
||||||
case PAD_HAT_N:
|
|
||||||
switch (mWheelData.hat_horz)
|
|
||||||
{
|
|
||||||
case PAD_HAT_W:
|
|
||||||
mWheelData.hatswitch = PAD_HAT_NW;
|
|
||||||
break;
|
|
||||||
case PAD_HAT_E:
|
|
||||||
mWheelData.hatswitch = PAD_HAT_NE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
mWheelData.hatswitch = PAD_HAT_N;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PAD_HAT_S:
|
|
||||||
switch (mWheelData.hat_horz)
|
|
||||||
{
|
|
||||||
case PAD_HAT_W:
|
|
||||||
mWheelData.hatswitch = PAD_HAT_SW;
|
|
||||||
break;
|
|
||||||
case PAD_HAT_E:
|
|
||||||
mWheelData.hatswitch = PAD_HAT_SE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
mWheelData.hatswitch = PAD_HAT_S;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
mWheelData.hatswitch = mWheelData.hat_horz;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
pad_copy_data(mType, buf, mWheelData);
|
|
||||||
return buflen;
|
|
||||||
}
|
|
||||||
|
|
||||||
int JoyDevPad::TokenOut(const uint8_t* data, int len)
|
|
||||||
{
|
|
||||||
const ff_data* ffdata = (const ff_data*)data;
|
|
||||||
bool hires = (mType == WT_DRIVING_FORCE_PRO);
|
|
||||||
ParseFFData(ffdata, hires);
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
int JoyDevPad::Open()
|
|
||||||
{
|
|
||||||
device_list device_list;
|
|
||||||
bool has_steering;
|
|
||||||
int count;
|
|
||||||
int32_t b_gain, gain, b_ac, ac;
|
|
||||||
memset(&mWheelData, 0, sizeof(wheel_data_t));
|
|
||||||
|
|
||||||
// Setting to unpressed
|
|
||||||
mWheelData.steering = 0x3FF >> 1;
|
|
||||||
mWheelData.clutch = 0xFF;
|
|
||||||
mWheelData.throttle = 0xFF;
|
|
||||||
mWheelData.brake = 0xFF;
|
|
||||||
mWheelData.hatswitch = 0x8;
|
|
||||||
mWheelData.hat_horz = 0x8;
|
|
||||||
mWheelData.hat_vert = 0x8;
|
|
||||||
|
|
||||||
mHandleFF = -1;
|
|
||||||
|
|
||||||
std::string joypath;
|
|
||||||
/*if (!LoadSetting(mDevType, mPort, APINAME, N_JOYSTICK, joypath))
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
EnumerateDevices(device_list);
|
|
||||||
|
|
||||||
if (!LoadSetting(mDevType, mPort, APINAME, N_GAIN_ENABLED, b_gain))
|
|
||||||
b_gain = 1;
|
|
||||||
if (!LoadSetting(mDevType, mPort, APINAME, N_GAIN, gain))
|
|
||||||
gain = 100;
|
|
||||||
if (!LoadSetting(mDevType, mPort, APINAME, N_AUTOCENTER_MANAGED, b_ac))
|
|
||||||
b_ac = 1;
|
|
||||||
if (!LoadSetting(mDevType, mPort, APINAME, N_AUTOCENTER, ac))
|
|
||||||
ac = 100;
|
|
||||||
|
|
||||||
for (const auto& it : device_list)
|
|
||||||
{
|
|
||||||
has_steering = false;
|
|
||||||
mDevices.push_back({});
|
|
||||||
|
|
||||||
struct device_data& device = mDevices.back();
|
|
||||||
device.name = it.name;
|
|
||||||
|
|
||||||
if ((device.cfg.fd = open(it.path.c_str(), O_RDWR | O_NONBLOCK)) < 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//int flags = fcntl(device.fd, F_GETFL, 0);
|
|
||||||
//fcntl(device.fd, F_SETFL, flags | O_NONBLOCK);
|
|
||||||
|
|
||||||
unsigned int version;
|
|
||||||
if (ioctl(device.cfg.fd, JSIOCGVERSION, &version) < 0)
|
|
||||||
{
|
|
||||||
SysMessage("%s: Get version failed: %s\n", APINAME, strerror(errno));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version < 0x010000)
|
|
||||||
{
|
|
||||||
SysMessage("%s: Driver version 0x%X is too old\n", APINAME, version);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
LoadMappings(mDevType, mPort, device.name, 3, 16, device.cfg);
|
|
||||||
|
|
||||||
// Axis Mapping
|
|
||||||
if (ioctl(device.cfg.fd, JSIOCGAXMAP, device.axis_map) < 0)
|
|
||||||
{
|
|
||||||
SysMessage("%s: Axis mapping failed: %s\n", APINAME, strerror(errno));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (ioctl(device.cfg.fd, JSIOCGAXES, &(count)) >= 0)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
for (int k = 0; k < count; k++)
|
|
||||||
{
|
|
||||||
for (int i = JOY_STEERING; i < JOY_MAPS_COUNT; i++)
|
|
||||||
{
|
|
||||||
if (k == device.cfg.controls[i])
|
|
||||||
{
|
|
||||||
device.axis_map[k] = 0x80 | i;
|
|
||||||
if (i == JOY_STEERING)
|
|
||||||
has_steering = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Button Mapping
|
|
||||||
if (ioctl(device.cfg.fd, JSIOCGBTNMAP, device.btn_map) < 0)
|
|
||||||
{
|
|
||||||
SysMessage("%s: Button mapping failed: %s\n", APINAME, strerror(errno));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (ioctl(device.cfg.fd, JSIOCGBUTTONS, &(count)) >= 0)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
if (device.btn_map[i] == BTN_GAMEPAD)
|
|
||||||
device.is_gamepad = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!device.is_gamepad) //TODO Don't remap if gamepad?
|
|
||||||
for (int k = 0; k < count; k++)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < JOY_STEERING; i++)
|
|
||||||
{
|
|
||||||
if (k == device.cfg.controls[i])
|
|
||||||
device.btn_map[k] = 0x8000 | i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::stringstream event;
|
|
||||||
int index = 0;
|
|
||||||
const char* tmp = it.path.c_str();
|
|
||||||
while (*tmp && !isdigit(*tmp))
|
|
||||||
tmp++;
|
|
||||||
|
|
||||||
sscanf(tmp, "%d", &index);
|
|
||||||
|
|
||||||
//TODO kernel limit is 32?
|
|
||||||
for (int j = 0; j <= 99; j++)
|
|
||||||
{
|
|
||||||
event.clear();
|
|
||||||
event.str(std::string());
|
|
||||||
/* Try to discover the corresponding event number */
|
|
||||||
event << "/sys/class/input/js" << index << "/device/event" << j;
|
|
||||||
if (dir_exists(event.str()))
|
|
||||||
{
|
|
||||||
|
|
||||||
event.clear();
|
|
||||||
event.str(std::string());
|
|
||||||
event << "/dev/input/event" << j;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mFFdev && has_steering)
|
|
||||||
{
|
|
||||||
if ((mHandleFF = open(event.str().c_str(), /*O_WRONLY*/ O_RDWR)) < 0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else
|
|
||||||
mFFdev = new evdev::EvdevFF(mHandleFF, b_gain, gain, b_ac, ac);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int JoyDevPad::Close()
|
|
||||||
{
|
|
||||||
delete mFFdev;
|
|
||||||
mFFdev = nullptr;
|
|
||||||
|
|
||||||
if (mHandleFF != -1)
|
|
||||||
close(mHandleFF);
|
|
||||||
|
|
||||||
mHandleFF = -1;
|
|
||||||
for (auto& it : mDevices)
|
|
||||||
{
|
|
||||||
close(it.cfg.fd);
|
|
||||||
it.cfg.fd = -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace joydev
|
|
||||||
} // namespace usb_pad
|
|
|
@ -1,84 +0,0 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
|
||||||
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
|
||||||
*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "USB/linux/util.h"
|
|
||||||
#include "USB/usb-pad/evdev/evdev-ff.h"
|
|
||||||
#include "USB/usb-pad/evdev/shared.h"
|
|
||||||
#include "Utilities/Console.h"
|
|
||||||
|
|
||||||
namespace usb_pad
|
|
||||||
{
|
|
||||||
namespace joydev
|
|
||||||
{
|
|
||||||
|
|
||||||
void EnumerateDevices(device_list& list);
|
|
||||||
|
|
||||||
static constexpr const char* APINAME = "joydev";
|
|
||||||
|
|
||||||
class JoyDevPad : public Pad
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
JoyDevPad(int port, const char* dev_type)
|
|
||||||
: Pad(port, dev_type)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~JoyDevPad() { Close(); }
|
|
||||||
int Open();
|
|
||||||
int Close();
|
|
||||||
int TokenIn(uint8_t* buf, int len);
|
|
||||||
int TokenOut(const uint8_t* data, int len);
|
|
||||||
int Reset() { return 0; }
|
|
||||||
|
|
||||||
static const TCHAR* Name()
|
|
||||||
{
|
|
||||||
return "Joydev";
|
|
||||||
}
|
|
||||||
|
|
||||||
static int Configure(int port, const char* dev_type, void* data);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
int mHandleFF = -1;
|
|
||||||
struct wheel_data_t mWheelData
|
|
||||||
{
|
|
||||||
};
|
|
||||||
std::vector<evdev::device_data> mDevices;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <size_t _Size>
|
|
||||||
bool GetJoystickName(const std::string& path, char (&name)[_Size])
|
|
||||||
{
|
|
||||||
int fd = 0;
|
|
||||||
if ((fd = open(path.c_str(), O_RDONLY)) < 0)
|
|
||||||
{
|
|
||||||
Console.Warning("Cannot open %s\n", path.c_str());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (ioctl(fd, JSIOCGNAME(_Size), name) < -1)
|
|
||||||
{
|
|
||||||
Console.Warning("Cannot get controller's name\n");
|
|
||||||
close(fd);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace joydev
|
|
||||||
} // namespace usb_pad
|
|
Loading…
Reference in New Issue