mirror of https://github.com/PCSX2/pcsx2.git
USB: Add evdev support for keyboardmania
This commit is contained in:
parent
238da17196
commit
d0ada6b40a
|
@ -12,6 +12,8 @@
|
|||
* 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
|
||||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
GtkWidget* new_combobox(const char* label, GtkWidget* vbox, bool scrollable = false); // linux/config-gtk.cpp
|
||||
|
|
|
@ -189,7 +189,7 @@ static void configureApi(GtkWidget* widget, gpointer data)
|
|||
}
|
||||
}
|
||||
|
||||
GtkWidget* new_combobox(const char* label, GtkWidget* vbox)
|
||||
GtkWidget* new_combobox(const char* label, GtkWidget* vbox, bool scrollable)
|
||||
{
|
||||
GtkWidget *rs_hbox, *rs_label, *rs_cb;
|
||||
|
||||
|
@ -199,10 +199,16 @@ GtkWidget* new_combobox(const char* label, GtkWidget* vbox)
|
|||
rs_label = gtk_label_new(label);
|
||||
gtk_box_pack_start(GTK_BOX(rs_hbox), rs_label, FALSE, TRUE, 5);
|
||||
gtk_label_set_justify(GTK_LABEL(rs_label), GTK_JUSTIFY_RIGHT);
|
||||
gtk_misc_set_alignment(GTK_MISC(rs_label), 1, 0.5);
|
||||
|
||||
rs_cb = gtk_combo_box_text_new();
|
||||
gtk_box_pack_start(GTK_BOX(rs_hbox), rs_cb, TRUE, TRUE, 5);
|
||||
if (!scrollable)
|
||||
gtk_box_pack_start(GTK_BOX(rs_hbox), rs_cb, TRUE, TRUE, 5);
|
||||
else
|
||||
{
|
||||
GtkWidget* sw = gtk_scrolled_window_new(NULL, NULL);
|
||||
gtk_container_add(GTK_CONTAINER(sw), rs_cb);
|
||||
gtk_box_pack_start(GTK_BOX(rs_hbox), sw, TRUE, TRUE, 5);
|
||||
}
|
||||
return rs_cb;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,8 +35,6 @@
|
|||
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
GtkWidget* new_combobox(const char* label, GtkWidget* vbox); // src/linux/config-gtk.cpp
|
||||
|
||||
#define CLEAR(x) memset(&(x), 0, sizeof(x))
|
||||
|
||||
namespace usb_eyetoy
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
#include <cstdio>
|
||||
#include <sstream>
|
||||
|
||||
GtkWidget* new_combobox(const char* label, GtkWidget* vbox); // src/linux/config-gtk.cpp
|
||||
|
||||
namespace usb_hid
|
||||
{
|
||||
namespace evdev
|
||||
|
|
|
@ -19,8 +19,6 @@
|
|||
#include "USB/dynlink/pulse.h"
|
||||
#endif
|
||||
|
||||
GtkWidget* new_combobox(const char* label, GtkWidget* vbox); // src/linux/config-gtk.cpp
|
||||
|
||||
namespace usb_mic
|
||||
{
|
||||
namespace audiodev_pulse
|
||||
|
|
|
@ -1316,7 +1316,7 @@ namespace usb_pad
|
|||
INVERTFORCES[port] = SendDlgItemMessage(hWnd, IDC_CHECK1, BM_GETCHECK, 0, 0);
|
||||
useRamp = !!SendDlgItemMessage(hWnd, IDC_CHECK3, BM_GETCHECK, 0, 0);
|
||||
GAINZ[port][0] = SendMessage(GetDlgItem(hWnd, IDC_SLIDER4), TBM_GETPOS, 0, 0);
|
||||
FFMULTI[port][0] = SendMessage(GetDlgItem(hWnd, IDC_SLIDER5), TBM_GETPOS, 0, 0);
|
||||
FFMULTI[port][0] = SendMessage(GetDlgItem(hWnd, IDC_SLIDER5), TBM_GETPOS, 0, 0);
|
||||
}
|
||||
|
||||
void SaveDInputConfig(int port, const char* dev_type)
|
||||
|
@ -1460,11 +1460,11 @@ namespace usb_pad
|
|||
struct DXDlgSettings s;
|
||||
s.port = port;
|
||||
s.dev_type = dev_type;
|
||||
if (strcmp(dev_type, "buzz_device") == 0)
|
||||
if (strcmp(dev_type, BuzzDevice::TypeName()) == 0)
|
||||
{
|
||||
return DialogBoxParam(h.hInst, MAKEINTRESOURCE(IDD_DLG_BUZZ), h.hWnd, DxDialogProc, (LPARAM)&s);
|
||||
}
|
||||
if (strcmp(dev_type, "keyboardmania") == 0)
|
||||
if (strcmp(dev_type, KeyboardmaniaDevice::TypeName()) == 0)
|
||||
{
|
||||
return DialogBoxParam(h.hInst, MAKEINTRESOURCE(IDD_DLG_KEYBOARDMANIA), h.hWnd, DxDialogProc, (LPARAM)&s);
|
||||
}
|
||||
|
|
|
@ -279,8 +279,8 @@ namespace usb_pad
|
|||
"BRIGHTNESS_ZERO", /* linux:244 (KEY_BRIGHTNESS_ZERO) */
|
||||
"DISPLAY_OFF", /* linux:245 (KEY_DISPLAY_OFF) */
|
||||
"WIMAX", /* linux:246 (KEY_WIMAX) */
|
||||
"247", /* linux:247 (unnamed) */
|
||||
"248", /* linux:248 (unnamed) */
|
||||
"RFKILL", /* linux:247 (KEY_RFKILL) */
|
||||
"MICMUTE", /* linux:248 (KEY_MICMUTE) */
|
||||
"249", /* linux:249 (unnamed) */
|
||||
"250", /* linux:250 (unnamed) */
|
||||
"251", /* linux:251 (unnamed) */
|
||||
|
@ -556,15 +556,15 @@ namespace usb_pad
|
|||
"NUMERIC_9", /* linux:521 (KEY_NUMERIC_9) */
|
||||
"NUMERIC_STAR", /* linux:522 (KEY_NUMERIC_STAR) */
|
||||
"NUMERIC_POUND", /* linux:523 (KEY_NUMERIC_POUND) */
|
||||
"RFKILL", /* linux:524 (KEY_RFKILL) */
|
||||
"KEY_NUMERIC_A", /* linux:524 (KEY_NUMERIC_A) */
|
||||
};
|
||||
|
||||
static bool GetEventName(const char* dev_type, int map, int event, const char** name)
|
||||
static bool GetEventName(const char* dev_type, int map, int event, bool is_button, const char** name)
|
||||
{
|
||||
if (!name)
|
||||
return false;
|
||||
|
||||
if (map < JOY_STEERING || !strcmp(dev_type, BuzzDevice::TypeName()))
|
||||
if (is_button)
|
||||
{
|
||||
if (event < (int)key_to_str.size())
|
||||
{
|
||||
|
@ -593,7 +593,7 @@ namespace usb_pad
|
|||
};
|
||||
AxisValue axisVal[ABS_MAX + 1]{};
|
||||
unsigned long absbit[NBITS(ABS_MAX)]{};
|
||||
struct axis_correct abs_correct[ABS_MAX]{};
|
||||
axis_correct abs_correct[ABS_MAX]{};
|
||||
|
||||
inverted = false;
|
||||
|
||||
|
@ -616,9 +616,7 @@ namespace usb_pad
|
|||
while ((len = read(js.second.fd, &event, sizeof(event))) > 0)
|
||||
;
|
||||
|
||||
struct timeval timeout
|
||||
{
|
||||
};
|
||||
timeval timeout{};
|
||||
timeout.tv_sec = 5;
|
||||
int result = select(maxfd + 1, &fdset, NULL, NULL, &timeout);
|
||||
|
||||
|
@ -744,6 +742,8 @@ namespace usb_pad
|
|||
int ret = 0;
|
||||
if (!strcmp(dev_type, BuzzDevice::TypeName()))
|
||||
ret = GtkBuzzConfigure(port, dev_type, "Evdev Settings", evdev::APINAME, GTK_WINDOW(data), apicbs);
|
||||
else if (!strcmp(dev_type, KeyboardmaniaDevice::TypeName()))
|
||||
ret = GtkKeyboardmaniaConfigure(port, dev_type, "Evdev Settings", evdev::APINAME, GTK_WINDOW(data), apicbs);
|
||||
else
|
||||
ret = GtkPadConfigure(port, dev_type, "Evdev Settings", evdev::APINAME, GTK_WINDOW(data), apicbs);
|
||||
return ret;
|
||||
|
|
|
@ -108,7 +108,6 @@ namespace usb_pad
|
|||
}
|
||||
}
|
||||
}
|
||||
//quit:
|
||||
closedir(dirp);
|
||||
return false;
|
||||
}
|
||||
|
@ -151,7 +150,7 @@ namespace usb_pad
|
|||
str.clear();
|
||||
str.str("");
|
||||
str << EVDEV_DIR << dp->d_name;
|
||||
std::string path = str.str();
|
||||
const std::string path = str.str();
|
||||
|
||||
auto it = std::find_if(list_cache.begin(), list_cache.end(),
|
||||
[&path](evdev_device& dev) {
|
||||
|
@ -168,14 +167,14 @@ namespace usb_pad
|
|||
continue;
|
||||
}
|
||||
|
||||
//list_cache.push_back(std::make_pair(std::string(dp->d_name), path));
|
||||
|
||||
res = ioctl(fd, EVIOCGNAME(sizeof(buf)), buf);
|
||||
if (res < 0)
|
||||
Console.Warning("EVIOCGNAME");
|
||||
else
|
||||
{
|
||||
list_cache.push_back({buf, dp->d_name, path});
|
||||
evdev_device dev{buf, dp->d_name, path, {}};
|
||||
res = ioctl(fd, EVIOCGID, &dev.input_id);
|
||||
list_cache.push_back(dev);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
@ -183,7 +182,6 @@ namespace usb_pad
|
|||
}
|
||||
|
||||
list.assign(list_cache.begin(), list_cache.end());
|
||||
//quit:
|
||||
closedir(dirp);
|
||||
}
|
||||
|
||||
|
@ -220,7 +218,7 @@ namespace usb_pad
|
|||
//case ABS_Y: mWheelData.clutch = NORM(value, 0xFF); break; //no wheel on PS2 has one, afaik
|
||||
//case ABS_RX: mWheelData.axis_rx = NORM(event.value, 0xFF); break;
|
||||
case ABS_RY:
|
||||
//treat_me_like_ABS_RY:
|
||||
//treat_me_like_ABS_RY:
|
||||
mWheelData.throttle = 0xFF;
|
||||
mWheelData.brake = 0xFF;
|
||||
if (value < 0)
|
||||
|
@ -230,18 +228,10 @@ namespace usb_pad
|
|||
break;
|
||||
case 0x80 | JOY_THROTTLE:
|
||||
case ABS_Z:
|
||||
/*if (mIsGamepad)
|
||||
mWheelData.brake = 0xFF - NORM(value, 0xFF);
|
||||
else*/
|
||||
mWheelData.throttle = device.cfg.inverted[1] ? NORM(value, 0xFF) : 0xFF - NORM(value, 0xFF);
|
||||
break;
|
||||
case 0x80 | JOY_BRAKE:
|
||||
case ABS_RZ:
|
||||
/*if (mIsGamepad)
|
||||
mWheelData.throttle = 0xFF - NORM(value, 0xFF);
|
||||
else if (mIsDualAnalog)
|
||||
goto treat_me_like_ABS_RY;
|
||||
else*/
|
||||
mWheelData.brake = device.cfg.inverted[2] ? NORM(value, 0xFF) : 0xFF - NORM(value, 0xFF);
|
||||
break;
|
||||
|
||||
|
@ -323,9 +313,8 @@ namespace usb_pad
|
|||
break;
|
||||
|
||||
value = AxisCorrect(device.abs_correct[event.code], event.value);
|
||||
/*if (event.code == 0)
|
||||
event.code, device.axis_map[event.code] & ~0x80, event.value, value);
|
||||
*/
|
||||
//if (event.code == 0)
|
||||
// event.code, device.axis_map[event.code] & ~0x80, event.value, value);
|
||||
SetAxis(device, event.code, value);
|
||||
}
|
||||
break;
|
||||
|
@ -333,7 +322,7 @@ namespace usb_pad
|
|||
{
|
||||
code = device.btn_map[event.code] != (uint16_t)-1 ? device.btn_map[event.code] : event.code;
|
||||
|
||||
if (mType == WT_BUZZ_CONTROLLER)
|
||||
if (mType == WT_BUZZ_CONTROLLER || mType == WT_KEYBOARDMANIA_CONTROLLER)
|
||||
{
|
||||
if (device.btn_map[event.code] != (uint16_t)-1)
|
||||
{
|
||||
|
@ -568,7 +557,7 @@ namespace usb_pad
|
|||
}
|
||||
|
||||
if (joypath.empty() || !file_exists(joypath))
|
||||
goto quit;
|
||||
return 1;
|
||||
|
||||
int fd = -1;
|
||||
if ((fd = open(joypath.c_str(), O_RDWR | O_NONBLOCK)) < 0)
|
||||
|
@ -584,16 +573,6 @@ namespace usb_pad
|
|||
int pid, vid;
|
||||
if ((mUseRawFF = FindHidraw(evphys, hid_dev, &vid, &pid)))
|
||||
{
|
||||
|
||||
// For safety, only allow Logitech (classic ffb) devices
|
||||
if (vid != 0x046D /* Logitech */ /*|| info.bustype != BUS_USB*/
|
||||
|| pid == 0xc262 /* G920 hid mode */
|
||||
|| pid == 0xc261 /* G920 xbox mode */
|
||||
)
|
||||
{
|
||||
mUseRawFF = 0;
|
||||
}
|
||||
|
||||
// check if still using hidraw and run the thread
|
||||
if (mUseRawFF && !mWriterThreadIsRunning)
|
||||
{
|
||||
|
@ -637,13 +616,6 @@ namespace usb_pad
|
|||
continue;
|
||||
}
|
||||
|
||||
/*unsigned int version;
|
||||
if (ioctl(mHandle, EVIOCGVERSION, &version) < 0)
|
||||
{
|
||||
SysMessage("%s: Get version failed: %s\n", APINAME, strerror(errno));
|
||||
return false;
|
||||
}*/
|
||||
|
||||
int max_buttons = JOY_STEERING;
|
||||
switch (mType)
|
||||
{
|
||||
|
@ -651,8 +623,13 @@ namespace usb_pad
|
|||
LoadBuzzMappings(mDevType, mPort, it.id, device.cfg);
|
||||
max_buttons = 20;
|
||||
break;
|
||||
case WT_KEYBOARDMANIA_CONTROLLER:
|
||||
max_buttons = 31;
|
||||
LoadMappings(mDevType, mPort, it.id, max_buttons, 0, device.cfg);
|
||||
break;
|
||||
default:
|
||||
LoadMappings(mDevType, mPort, it.id, device.cfg);
|
||||
max_buttons = JOY_STEERING;
|
||||
LoadMappings(mDevType, mPort, it.id, max_buttons, 3, device.cfg);
|
||||
if (!LoadSetting(mDevType, mPort, APINAME, N_GAIN_ENABLED, b_gain))
|
||||
b_gain = 1;
|
||||
if (!LoadSetting(mDevType, mPort, APINAME, N_GAIN, gain))
|
||||
|
@ -715,12 +692,6 @@ namespace usb_pad
|
|||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
for (int i = 0; i < ABS_MAX; ++i)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i = BTN_JOYSTICK; i < KEY_MAX; ++i)
|
||||
{
|
||||
if (test_bit(i, keybit))
|
||||
|
@ -763,10 +734,6 @@ namespace usb_pad
|
|||
}
|
||||
|
||||
return 0;
|
||||
|
||||
quit:
|
||||
Close();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EvDevPad::Close()
|
||||
|
@ -776,9 +743,12 @@ namespace usb_pad
|
|||
|
||||
if (mHidHandle != -1)
|
||||
{
|
||||
uint8_t reset[7] = {0};
|
||||
reset[0] = 0xF3; //stop forces
|
||||
write(mHidHandle, reset, sizeof(reset));
|
||||
if (mType <= WT_GT_FORCE)
|
||||
{
|
||||
uint8_t reset[7] = {0};
|
||||
reset[0] = 0xF3; //stop forces
|
||||
write(mHidHandle, reset, sizeof(reset));
|
||||
}
|
||||
close(mHidHandle);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "shared.h"
|
||||
#include "USB/icon_buzz_24.h"
|
||||
#include "Utilities/Console.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
@ -29,37 +30,59 @@ namespace usb_pad
|
|||
using sys_clock = std::chrono::system_clock;
|
||||
using ms = std::chrono::milliseconds;
|
||||
|
||||
#define JOYTYPE "joytype"
|
||||
#define CFG "cfg"
|
||||
constexpr auto CONTROL = "control";
|
||||
constexpr auto CFG = "cfg";
|
||||
|
||||
bool LoadMappings(const char* dev_type, int port, const std::string& joyname, ConfigMapping& cfg)
|
||||
// Buttons from 0, axes after buttons
|
||||
bool LoadMappings(const char* dev_type, int port, const std::string& joyname, u32 max_buttons, u32 max_axes, ConfigMapping& cfg)
|
||||
{
|
||||
assert(JOY_MAPS_COUNT == countof(JoystickMapNames));
|
||||
std::stringstream str;
|
||||
const bool use_control_names = !strcmp(dev_type, PadDevice::TypeName());
|
||||
|
||||
if (joyname.empty())
|
||||
return false;
|
||||
|
||||
int j = 0;
|
||||
cfg.controls.resize(JOY_MAPS_COUNT);
|
||||
for (auto& i : cfg.controls)
|
||||
cfg.controls.resize(max_buttons + max_axes);
|
||||
for (u32 i = 0; i < max_buttons + max_axes; i++)
|
||||
{
|
||||
str.clear();
|
||||
str.str("");
|
||||
str << "map_" << JoystickMapNames[j++];
|
||||
if (i < max_buttons)
|
||||
{
|
||||
str << "button_";
|
||||
if (use_control_names && i < (u32)countof(JoystickMapNames))
|
||||
str << JoystickMapNames[i];
|
||||
else
|
||||
str << i;
|
||||
}
|
||||
else
|
||||
{
|
||||
str << "axis_";
|
||||
u32 axis = i - max_buttons;
|
||||
if (use_control_names && (JOY_STEERING + axis) < (u32)countof(JoystickMapNames))
|
||||
str << JoystickMapNames[JOY_STEERING + axis];
|
||||
else
|
||||
str << axis;
|
||||
}
|
||||
|
||||
const std::string& name = str.str();
|
||||
int32_t var;
|
||||
if (LoadSetting(dev_type, port, joyname, name.c_str(), var))
|
||||
i = var;
|
||||
cfg.controls[i] = var;
|
||||
else
|
||||
i = -1;
|
||||
cfg.controls[i] = -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
str.clear();
|
||||
str.str("");
|
||||
str << "inverted_" << JoystickMapNames[JOY_STEERING + i];
|
||||
str << "inverted_";
|
||||
if (use_control_names)
|
||||
str << JoystickMapNames[JOY_STEERING + i];
|
||||
else
|
||||
str << i;
|
||||
|
||||
{
|
||||
const std::string& name = str.str();
|
||||
if (!LoadSetting(dev_type, port, joyname, name.c_str(), cfg.inverted[i]))
|
||||
|
@ -68,7 +91,12 @@ namespace usb_pad
|
|||
|
||||
str.clear();
|
||||
str.str("");
|
||||
str << "initial_" << JoystickMapNames[JOY_STEERING + i];
|
||||
str << "initial_";
|
||||
if (use_control_names)
|
||||
str << JoystickMapNames[JOY_STEERING + i];
|
||||
else
|
||||
str << i;
|
||||
|
||||
{
|
||||
const std::string& name = str.str();
|
||||
if (!LoadSetting(dev_type, port, joyname, name.c_str(), cfg.initial[i]))
|
||||
|
@ -78,29 +106,58 @@ namespace usb_pad
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SaveMappings(const char* dev_type, int port, const std::string& joyname, const ConfigMapping& cfg)
|
||||
bool SaveMappings(const char* dev_type, int port, const std::string& joyname, u32 max_buttons, u32 max_axes, const ConfigMapping& cfg)
|
||||
{
|
||||
assert(JOY_MAPS_COUNT == countof(JoystickMapNames));
|
||||
if (joyname.empty() || cfg.controls.size() != JOY_MAPS_COUNT)
|
||||
if (joyname.empty() || cfg.controls.size() != max_buttons + max_axes)
|
||||
return false;
|
||||
|
||||
RemoveSection(dev_type, port, joyname);
|
||||
std::stringstream str;
|
||||
for (int i = 0; i < JOY_MAPS_COUNT; i++)
|
||||
const bool use_control_names = !strcmp(dev_type, PadDevice::TypeName());
|
||||
bool has_axes = false;
|
||||
|
||||
for (u32 i = 0; i < max_buttons + max_axes; i++)
|
||||
{
|
||||
str.clear();
|
||||
str.str("");
|
||||
str << "map_" << JoystickMapNames[i];
|
||||
if (i < max_buttons)
|
||||
{
|
||||
str << "button_";
|
||||
if (use_control_names && i < (u32)countof(JoystickMapNames))
|
||||
str << JoystickMapNames[i];
|
||||
else
|
||||
str << i;
|
||||
}
|
||||
else
|
||||
{
|
||||
str << "axis_";
|
||||
u32 axis = i - max_buttons;
|
||||
if (use_control_names && (JOY_STEERING + axis) < (u32)countof(JoystickMapNames))
|
||||
str << JoystickMapNames[JOY_STEERING + axis];
|
||||
else
|
||||
str << axis;
|
||||
}
|
||||
|
||||
const std::string& name = str.str();
|
||||
if (cfg.controls[i] >= 0 && !SaveSetting(dev_type, port, joyname, name.c_str(), static_cast<int32_t>(cfg.controls[i])))
|
||||
return false;
|
||||
if (cfg.controls[i] >= 0)
|
||||
{
|
||||
if (!SaveSetting(dev_type, port, joyname, name.c_str(), static_cast<int32_t>(cfg.controls[i])))
|
||||
return false;
|
||||
if (i >= max_buttons)
|
||||
has_axes = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
for (u32 i = 0; i < 3 && has_axes; i++)
|
||||
{
|
||||
str.clear();
|
||||
str.str("");
|
||||
str << "inverted_" << JoystickMapNames[JOY_STEERING + i];
|
||||
str << "inverted_";
|
||||
if (use_control_names)
|
||||
str << JoystickMapNames[JOY_STEERING + i];
|
||||
else
|
||||
str << i;
|
||||
|
||||
{
|
||||
const std::string& name = str.str();
|
||||
if (!SaveSetting(dev_type, port, joyname, name.c_str(), cfg.inverted[i]))
|
||||
|
@ -109,7 +166,12 @@ namespace usb_pad
|
|||
|
||||
str.clear();
|
||||
str.str("");
|
||||
str << "initial_" << JoystickMapNames[JOY_STEERING + i];
|
||||
str << "initial_";
|
||||
if (use_control_names)
|
||||
str << JoystickMapNames[JOY_STEERING + i];
|
||||
else
|
||||
str << i;
|
||||
|
||||
{
|
||||
const std::string& name = str.str();
|
||||
if (!SaveSetting(dev_type, port, joyname, name.c_str(), cfg.initial[i]))
|
||||
|
@ -169,48 +231,50 @@ namespace usb_pad
|
|||
static void refresh_store(ConfigData* cfg)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
std::string name;
|
||||
|
||||
gtk_list_store_clear(cfg->store);
|
||||
for (auto& it : cfg->jsconf)
|
||||
{
|
||||
for (int i = 0; /*i < JOY_MAPS_COUNT && */ i < (int)it.second.controls.size(); i++)
|
||||
for (size_t i = 0; i < it.second.controls.size(); i++)
|
||||
{
|
||||
if (it.second.controls[i] < 0)
|
||||
continue;
|
||||
|
||||
const char* pc_name = "Unknown";
|
||||
cfg->cb->get_event_name(cfg->dev_type, i, it.second.controls[i], &pc_name);
|
||||
bool is_button = (i < cfg->max_buttons);
|
||||
cfg->cb->get_event_name(cfg->dev_type, i, it.second.controls[i], is_button, &pc_name);
|
||||
|
||||
gtk_list_store_append(cfg->store, &iter);
|
||||
|
||||
if (!strcmp(cfg->dev_type, BuzzDevice::TypeName()))
|
||||
{
|
||||
|
||||
std::stringstream ss;
|
||||
ss << (1 + i / countof(buzz_map_names));
|
||||
ss << " ";
|
||||
ss << buzz_map_names[i % countof(buzz_map_names)];
|
||||
|
||||
std::string name = ss.str();
|
||||
|
||||
gtk_list_store_set(cfg->store, &iter,
|
||||
COL_NAME, it.first.c_str(),
|
||||
COL_PS2, name.c_str(),
|
||||
COL_PC, pc_name,
|
||||
COL_COLUMN_WIDTH, 50,
|
||||
COL_BINDING, i,
|
||||
-1);
|
||||
name = ss.str();
|
||||
}
|
||||
else if (!strcmp(cfg->dev_type, PadDevice::TypeName()))
|
||||
name = JoystickMapNames[i];
|
||||
else if (!strcmp(cfg->dev_type, KeyboardmaniaDevice::TypeName()))
|
||||
name = kbdmania_key_labels[i];
|
||||
else
|
||||
{
|
||||
gtk_list_store_set(cfg->store, &iter,
|
||||
COL_NAME, it.first.c_str(),
|
||||
COL_PS2, JoystickMapNames[i],
|
||||
COL_PC, pc_name,
|
||||
COL_COLUMN_WIDTH, 50,
|
||||
COL_BINDING, i,
|
||||
-1);
|
||||
std::stringstream ss;
|
||||
if (is_button)
|
||||
ss << "Button " << i;
|
||||
else
|
||||
ss << "Axis " << (i - cfg->max_buttons);
|
||||
name = ss.str();
|
||||
}
|
||||
|
||||
gtk_list_store_set(cfg->store, &iter,
|
||||
COL_NAME, it.first.c_str(),
|
||||
COL_PS2, name.c_str(),
|
||||
COL_PC, pc_name,
|
||||
COL_BINDING, i,
|
||||
-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -219,90 +283,52 @@ namespace usb_pad
|
|||
{
|
||||
gint idx = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
|
||||
//int port = reinterpret_cast<uintptr_t>(data);
|
||||
ConfigData* cfg = (ConfigData*)g_object_get_data(G_OBJECT(widget), CFG);
|
||||
ConfigData* cfg = reinterpret_cast<ConfigData*>(g_object_get_data(G_OBJECT(widget), CFG));
|
||||
|
||||
if (!cfg)
|
||||
return;
|
||||
|
||||
if (idx > -1)
|
||||
{
|
||||
std::string name = (cfg->joysticks.begin() + idx)->name;
|
||||
cfg->js_iter = (cfg->joysticks.begin() + idx);
|
||||
}
|
||||
}
|
||||
|
||||
static void button_clicked(GtkComboBox* widget, gpointer data)
|
||||
static void button_clicked(GtkWidget* widget, gpointer data)
|
||||
{
|
||||
int type = reinterpret_cast<uintptr_t>(g_object_get_data(G_OBJECT(widget), JOYTYPE));
|
||||
ConfigData* cfg = (ConfigData*)g_object_get_data(G_OBJECT(widget), CFG);
|
||||
u32 control = reinterpret_cast<uintptr_t>(g_object_get_data(G_OBJECT(widget), CONTROL));
|
||||
ConfigData* cfg = reinterpret_cast<ConfigData*>(g_object_get_data(G_OBJECT(widget), CFG));
|
||||
if (!cfg)
|
||||
return;
|
||||
|
||||
if (cfg /*&& type < cfg->mappings.size() && cfg->js_iter != cfg->joysticks.end()*/)
|
||||
int value, initial = 0;
|
||||
std::string dev_name;
|
||||
bool inverted = false;
|
||||
bool is_axis = (control >= cfg->max_buttons);
|
||||
|
||||
gtk_label_set_text(GTK_LABEL(cfg->label), "Polling for input for 5 seconds...");
|
||||
|
||||
// let label change its text
|
||||
while (gtk_events_pending())
|
||||
gtk_main_iteration_do(FALSE);
|
||||
|
||||
if (cfg->cb->poll(cfg->jsconf, dev_name, is_axis, value, inverted, initial))
|
||||
{
|
||||
int value, initial = 0;
|
||||
std::string dev_name;
|
||||
bool inverted = false;
|
||||
bool is_axis = (type >= JOY_STEERING && type <= JOY_BRAKE);
|
||||
auto it = std::find_if(cfg->jsconf.begin(), cfg->jsconf.end(),
|
||||
[&dev_name](MappingPair& i) -> bool {
|
||||
return i.first == dev_name;
|
||||
});
|
||||
|
||||
gtk_label_set_text(GTK_LABEL(cfg->label), "Polling for input for 5 seconds...");
|
||||
|
||||
// let label change its text
|
||||
while (gtk_events_pending())
|
||||
gtk_main_iteration_do(FALSE);
|
||||
|
||||
if (cfg->cb->poll(cfg->jsconf, dev_name, is_axis, value, inverted, initial))
|
||||
if (it != cfg->jsconf.end() && control < (u32)it->second.controls.size())
|
||||
{
|
||||
auto it = std::find_if(cfg->jsconf.begin(), cfg->jsconf.end(),
|
||||
[&dev_name](MappingPair& i) -> bool {
|
||||
return i.first == dev_name;
|
||||
});
|
||||
|
||||
if (it != cfg->jsconf.end() && type < (int)it->second.controls.size())
|
||||
it->second.controls[control] = value;
|
||||
if (is_axis && control - cfg->max_buttons < countof(it->second.inverted))
|
||||
{
|
||||
it->second.controls[type] = value;
|
||||
if (is_axis)
|
||||
{
|
||||
it->second.inverted[type - JOY_STEERING] = inverted;
|
||||
it->second.initial[type - JOY_STEERING] = initial;
|
||||
}
|
||||
refresh_store(cfg);
|
||||
it->second.inverted[control - cfg->max_buttons] = inverted;
|
||||
it->second.initial[control - cfg->max_buttons] = initial;
|
||||
}
|
||||
refresh_store(cfg);
|
||||
}
|
||||
gtk_label_set_text(GTK_LABEL(cfg->label), "");
|
||||
}
|
||||
}
|
||||
|
||||
static void button_clicked_buzz(GtkComboBox* widget, gpointer data)
|
||||
{
|
||||
int type = reinterpret_cast<uintptr_t>(g_object_get_data(G_OBJECT(widget), JOYTYPE));
|
||||
ConfigData* cfg = (ConfigData*)g_object_get_data(G_OBJECT(widget), CFG);
|
||||
|
||||
if (cfg /*&& type < cfg->mappings.size() && cfg->js_iter != cfg->joysticks.end()*/)
|
||||
{
|
||||
int value, initial = 0;
|
||||
std::string dev_name;
|
||||
bool inverted = false;
|
||||
|
||||
gtk_label_set_text(GTK_LABEL(cfg->label), "Polling for input for 5 seconds...");
|
||||
|
||||
// let label change its text
|
||||
while (gtk_events_pending())
|
||||
gtk_main_iteration_do(FALSE);
|
||||
|
||||
if (cfg->cb->poll(cfg->jsconf, dev_name, false, value, inverted, initial))
|
||||
{
|
||||
auto it = std::find_if(cfg->jsconf.begin(), cfg->jsconf.end(),
|
||||
[&dev_name](MappingPair& i) -> bool {
|
||||
return i.first == dev_name;
|
||||
});
|
||||
|
||||
if (it != cfg->jsconf.end() && type < (int)it->second.controls.size())
|
||||
{
|
||||
it->second.controls[type] = value;
|
||||
refresh_store(cfg);
|
||||
}
|
||||
}
|
||||
gtk_label_set_text(GTK_LABEL(cfg->label), "");
|
||||
}
|
||||
gtk_label_set_text(GTK_LABEL(cfg->label), "");
|
||||
}
|
||||
|
||||
// save references to row paths, automatically updated when store changes
|
||||
|
@ -349,13 +375,6 @@ namespace usb_pad
|
|||
|
||||
gtk_tree_selection_selected_foreach(sel, view_selected_foreach_func, &rr_list);
|
||||
|
||||
/* // single row selection
|
||||
GtkTreeIter iter;
|
||||
|
||||
if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
|
||||
view_selected_foreach_func(model, nullptr, &iter, cfg);
|
||||
}*/
|
||||
|
||||
GList* list = gtk_tree_selection_get_selected_rows(sel, &model);
|
||||
// remove rows from store pointed to by row references
|
||||
for (node = g_list_first(rr_list); node != nullptr; node = node->next)
|
||||
|
@ -364,14 +383,12 @@ namespace usb_pad
|
|||
if (path)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
|
||||
if (gtk_tree_model_get_iter(model, &iter, path))
|
||||
{
|
||||
view_remove_binding(model, &iter, cfg);
|
||||
//gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
g_list_free_full(rr_list, (GDestroyNotify)gtk_tree_row_reference_free);
|
||||
g_list_free_full(list, (GDestroyNotify)gtk_tree_path_free);
|
||||
|
@ -394,74 +411,50 @@ namespace usb_pad
|
|||
}
|
||||
}
|
||||
|
||||
int GtkPadConfigure(int port, const char* dev_type, const char* apititle, const char* apiname, GtkWindow* parent, ApiCallbacks& apicbs)
|
||||
static GtkWidget* make_dialog(GtkWindow* parent, const std::string& title, int w = 1200, int h = 700)
|
||||
{
|
||||
GtkWidget *ro_frame, *rs_cb;
|
||||
GtkWidget *main_hbox, *right_vbox, *left_vbox, *treeview;
|
||||
GtkWidget* button;
|
||||
|
||||
int fd;
|
||||
ConfigData cfg;
|
||||
|
||||
apicbs.populate(cfg.joysticks);
|
||||
|
||||
cfg.js_iter = cfg.joysticks.end();
|
||||
cfg.label = gtk_label_new("");
|
||||
cfg.store = gtk_list_store_new(NUM_COLS,
|
||||
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT);
|
||||
cfg.cb = &apicbs;
|
||||
cfg.dev_type = dev_type;
|
||||
|
||||
for (const auto& it : cfg.joysticks)
|
||||
{
|
||||
if ((fd = open(it.path.c_str(), O_RDONLY | O_NONBLOCK)) < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ConfigMapping c(fd);
|
||||
LoadMappings(cfg.dev_type, port, it.id, c);
|
||||
cfg.jsconf.push_back(std::make_pair(it.id, c));
|
||||
}
|
||||
|
||||
refresh_store(&cfg);
|
||||
|
||||
std::string path;
|
||||
LoadSetting(dev_type, port, apiname, N_JOYSTICK, path);
|
||||
|
||||
cfg.use_hidraw_ff_pt = false;
|
||||
bool is_evdev = (strncmp(apiname, "evdev", 5) == 0);
|
||||
if (is_evdev) //TODO idk about joydev
|
||||
{
|
||||
LoadSetting(dev_type, port, apiname, N_HIDRAW_FF_PT, cfg.use_hidraw_ff_pt);
|
||||
}
|
||||
|
||||
// ---------------------------
|
||||
std::string title = (port ? "Player One " : "Player Two ");
|
||||
title += apititle;
|
||||
|
||||
GtkWidget* dlg = gtk_dialog_new_with_buttons(
|
||||
auto dlg = gtk_dialog_new_with_buttons(
|
||||
title.c_str(), parent, GTK_DIALOG_MODAL,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OK, GTK_RESPONSE_OK,
|
||||
NULL);
|
||||
gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
|
||||
gtk_window_set_resizable(GTK_WINDOW(dlg), TRUE);
|
||||
gtk_window_set_default_size(GTK_WINDOW(dlg), 320, 240);
|
||||
|
||||
// ---------------------------
|
||||
GtkWidget* dlg_area_box = gtk_dialog_get_content_area(GTK_DIALOG(dlg));
|
||||
|
||||
main_hbox = gtk_hbox_new(FALSE, 5);
|
||||
gtk_container_add(GTK_CONTAINER(dlg_area_box), main_hbox);
|
||||
gtk_window_set_default_size(GTK_WINDOW(dlg), w, h);
|
||||
return dlg;
|
||||
}
|
||||
|
||||
static void create_panes(GtkWidget* container, GtkWidget*& left_vbox, GtkWidget*& right_vbox)
|
||||
{
|
||||
left_vbox = gtk_vbox_new(FALSE, 5);
|
||||
gtk_box_pack_start(GTK_BOX(main_hbox), left_vbox, TRUE, TRUE, 5);
|
||||
right_vbox = gtk_vbox_new(FALSE, 5);
|
||||
gtk_box_pack_start(GTK_BOX(main_hbox), right_vbox, TRUE, TRUE, 5);
|
||||
right_vbox = gtk_vbox_new(FALSE, 15);
|
||||
|
||||
// ---------------------------
|
||||
treeview = gtk_tree_view_new();
|
||||
#if 0
|
||||
GtkWidget* paned = gtk_hpaned_new();
|
||||
gtk_container_add(GTK_CONTAINER(container), paned);
|
||||
gtk_paned_add1(GTK_PANED(paned), left_vbox);
|
||||
|
||||
GtkWidget* sc_win = gtk_scrolled_window_new(NULL, NULL);
|
||||
gtk_container_add(GTK_CONTAINER(sc_win), right_vbox);
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sc_win), GTK_POLICY_AUTOMATIC,
|
||||
GTK_POLICY_AUTOMATIC);
|
||||
gtk_paned_add2(GTK_PANED(paned), sc_win);
|
||||
#else
|
||||
GtkWidget* hbox = gtk_hbox_new(FALSE, 5);
|
||||
gtk_container_add(GTK_CONTAINER(container), hbox);
|
||||
gtk_box_pack_start(GTK_BOX(hbox), left_vbox, TRUE, TRUE, 5);
|
||||
gtk_box_pack_start(GTK_BOX(hbox), right_vbox, TRUE, TRUE, 5);
|
||||
#endif
|
||||
#if GTK_CHECK_VERSION(3, 0, 0)
|
||||
gtk_widget_set_vexpand(left_vbox, TRUE);
|
||||
gtk_widget_set_valign(right_vbox, GTK_ALIGN_START);
|
||||
#endif
|
||||
}
|
||||
|
||||
static GtkWidget* make_mappings_treeview(int port, ConfigData& cfg, GtkWidget* container)
|
||||
{
|
||||
GtkWidget* button;
|
||||
auto treeview = gtk_tree_view_new();
|
||||
cfg.treeview = GTK_TREE_VIEW(treeview);
|
||||
auto selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
|
||||
gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
|
||||
|
@ -469,7 +462,7 @@ namespace usb_pad
|
|||
GtkCellRenderer* render = gtk_cell_renderer_text_new();
|
||||
|
||||
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview),
|
||||
-1, "Name", render, "text", COL_NAME, "width", COL_COLUMN_WIDTH, NULL);
|
||||
-1, "Name", render, "text", COL_NAME, NULL);
|
||||
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview),
|
||||
-1, "PS2", render, "text", COL_PS2, NULL);
|
||||
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview),
|
||||
|
@ -486,28 +479,86 @@ namespace usb_pad
|
|||
|
||||
GtkWidget* scwin = gtk_scrolled_window_new(NULL, NULL);
|
||||
gtk_container_add(GTK_CONTAINER(scwin), treeview);
|
||||
//gtk_scrolled_window_set_min_content_width(GTK_SCROLLED_WINDOW(scwin), 200);
|
||||
gtk_widget_set_size_request(GTK_WIDGET(scwin), 200, 100);
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scwin), GTK_POLICY_AUTOMATIC,
|
||||
GTK_POLICY_ALWAYS);
|
||||
gtk_box_pack_start(GTK_BOX(left_vbox), scwin, TRUE, TRUE, 5);
|
||||
GTK_POLICY_AUTOMATIC);
|
||||
gtk_box_pack_start(GTK_BOX(container), scwin, TRUE, TRUE, 5);
|
||||
|
||||
button = gtk_button_new_with_label("Clear binding");
|
||||
gtk_box_pack_start(GTK_BOX(left_vbox), button, FALSE, FALSE, 5);
|
||||
gtk_box_pack_start(GTK_BOX(container), button, FALSE, FALSE, 5);
|
||||
g_object_set_data(G_OBJECT(button), CFG, &cfg);
|
||||
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(clear_binding_clicked), reinterpret_cast<gpointer>(port));
|
||||
|
||||
button = gtk_button_new_with_label("Clear All");
|
||||
gtk_box_pack_start(GTK_BOX(left_vbox), button, FALSE, FALSE, 5);
|
||||
gtk_box_pack_start(GTK_BOX(container), button, FALSE, FALSE, 5);
|
||||
g_object_set_data(G_OBJECT(button), CFG, &cfg);
|
||||
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(clear_all_clicked), reinterpret_cast<gpointer>(port));
|
||||
return treeview;
|
||||
}
|
||||
|
||||
static void load_devices_mappings(ConfigData& cfg, const int port, ApiCallbacks& apicbs)
|
||||
{
|
||||
int fd;
|
||||
apicbs.populate(cfg.joysticks);
|
||||
|
||||
cfg.js_iter = cfg.joysticks.end();
|
||||
cfg.label = gtk_label_new("");
|
||||
cfg.store = gtk_list_store_new(NUM_COLS,
|
||||
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT);
|
||||
cfg.cb = &apicbs;
|
||||
|
||||
for (const auto& it : cfg.joysticks)
|
||||
{
|
||||
if ((fd = open(it.path.c_str(), O_RDONLY | O_NONBLOCK)) < 0)
|
||||
{
|
||||
Console.Warning("USB: failed to open '%s'", it.path.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
ConfigMapping c(fd);
|
||||
LoadMappings(cfg.dev_type, port, it.id, cfg.max_buttons, cfg.max_axes, c);
|
||||
cfg.jsconf.push_back(std::make_pair(it.id, c));
|
||||
}
|
||||
|
||||
refresh_store(&cfg);
|
||||
}
|
||||
|
||||
int GtkPadConfigure(int port, const char* dev_type, const char* apititle, const char* apiname, GtkWindow* parent, ApiCallbacks& apicbs)
|
||||
{
|
||||
GtkWidget *ro_frame, *rs_cb;
|
||||
GtkWidget *right_vbox, *left_vbox;
|
||||
GtkWidget* button;
|
||||
|
||||
ConfigData cfg{};
|
||||
cfg.dev_type = dev_type;
|
||||
cfg.max_axes = 3;
|
||||
cfg.max_buttons = JOY_STEERING; // 16
|
||||
load_devices_mappings(cfg, port, apicbs);
|
||||
|
||||
std::string path;
|
||||
LoadSetting(dev_type, port, apiname, N_JOYSTICK, path);
|
||||
|
||||
cfg.use_hidraw_ff_pt = false;
|
||||
bool is_evdev = (strncmp(apiname, "evdev", 5) == 0);
|
||||
if (is_evdev) //TODO idk about joydev
|
||||
{
|
||||
LoadSetting(dev_type, port, apiname, N_HIDRAW_FF_PT, cfg.use_hidraw_ff_pt);
|
||||
}
|
||||
|
||||
// ---------------------------
|
||||
const std::string title = std::string(port ? "Player One " : "Player Two ") + apititle;
|
||||
GtkWidget* dlg = make_dialog(parent, title);
|
||||
|
||||
// ---------------------------
|
||||
GtkWidget* dlg_area_box = gtk_dialog_get_content_area(GTK_DIALOG(dlg));
|
||||
create_panes(dlg_area_box, left_vbox, right_vbox);
|
||||
make_mappings_treeview(port, cfg, left_vbox);
|
||||
|
||||
// ---------------------------
|
||||
|
||||
// Remapping
|
||||
{
|
||||
GtkWidget* table = gtk_table_new(5, 7, true);
|
||||
GtkWidget* table = gtk_table_new(5, 7, TRUE);
|
||||
gtk_container_add(GTK_CONTAINER(right_vbox), table);
|
||||
//GtkAttachOptions opt = (GtkAttachOptions)(GTK_EXPAND | GTK_FILL); // default
|
||||
GtkAttachOptions opt = (GtkAttachOptions)(GTK_FILL);
|
||||
|
@ -551,7 +602,7 @@ namespace usb_pad
|
|||
GtkWidget* button = gtk_button_new_with_label(button_labels[i]);
|
||||
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_clicked), reinterpret_cast<gpointer>(port));
|
||||
|
||||
g_object_set_data(G_OBJECT(button), JOYTYPE, reinterpret_cast<gpointer>(button_pos[i].type));
|
||||
g_object_set_data(G_OBJECT(button), CONTROL, reinterpret_cast<gpointer>(button_pos[i].type));
|
||||
g_object_set_data(G_OBJECT(button), CFG, &cfg);
|
||||
|
||||
gtk_table_attach(GTK_TABLE(table), button,
|
||||
|
@ -565,19 +616,19 @@ namespace usb_pad
|
|||
|
||||
button = gtk_button_new_with_label("Steering");
|
||||
gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 5);
|
||||
g_object_set_data(G_OBJECT(button), JOYTYPE, reinterpret_cast<gpointer>(JOY_STEERING));
|
||||
g_object_set_data(G_OBJECT(button), CONTROL, reinterpret_cast<gpointer>(JOY_STEERING));
|
||||
g_object_set_data(G_OBJECT(button), CFG, &cfg);
|
||||
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_clicked), reinterpret_cast<gpointer>(port));
|
||||
|
||||
button = gtk_button_new_with_label("Throttle");
|
||||
gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 5);
|
||||
g_object_set_data(G_OBJECT(button), JOYTYPE, reinterpret_cast<gpointer>(JOY_THROTTLE));
|
||||
g_object_set_data(G_OBJECT(button), CONTROL, reinterpret_cast<gpointer>(JOY_THROTTLE));
|
||||
g_object_set_data(G_OBJECT(button), CFG, &cfg);
|
||||
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_clicked), reinterpret_cast<gpointer>(port));
|
||||
|
||||
button = gtk_button_new_with_label("Brake");
|
||||
gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 5);
|
||||
g_object_set_data(G_OBJECT(button), JOYTYPE, reinterpret_cast<gpointer>(JOY_BRAKE));
|
||||
g_object_set_data(G_OBJECT(button), CONTROL, reinterpret_cast<gpointer>(JOY_BRAKE));
|
||||
g_object_set_data(G_OBJECT(button), CFG, &cfg);
|
||||
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_clicked), reinterpret_cast<gpointer>(port));
|
||||
|
||||
|
@ -594,7 +645,7 @@ namespace usb_pad
|
|||
GtkWidget* ff_scales[2];
|
||||
int32_t ff_enabled[2];
|
||||
|
||||
GtkWidget* table = gtk_table_new(3, 2, true);
|
||||
GtkWidget* table = gtk_table_new(3, 2, TRUE);
|
||||
gtk_container_add(GTK_CONTAINER(ro_frame), table);
|
||||
gtk_table_set_homogeneous(GTK_TABLE(table), FALSE);
|
||||
GtkAttachOptions opt = (GtkAttachOptions)(GTK_EXPAND | GTK_FILL); // default
|
||||
|
@ -654,11 +705,15 @@ namespace usb_pad
|
|||
g_signal_connect(G_OBJECT(chk_btn), "toggled", G_CALLBACK(checkbox_toggled), reinterpret_cast<gboolean*>(&cfg.use_hidraw_ff_pt));
|
||||
gtk_box_pack_start(GTK_BOX(frame_vbox), chk_btn, FALSE, FALSE, 5);
|
||||
|
||||
rs_cb = new_combobox("Device:", frame_vbox);
|
||||
rs_cb = new_combobox("Device:", frame_vbox, true);
|
||||
|
||||
const std::vector<uint16_t> whitelist{PAD_LG_FFB_WHITELIST};
|
||||
int idx = 0, sel_idx = 0;
|
||||
for (auto& it : cfg.joysticks)
|
||||
{
|
||||
if (!(it.input_id.vendor == PAD_VID && std::find(whitelist.begin(), whitelist.end(), it.input_id.product) != whitelist.end()))
|
||||
continue;
|
||||
|
||||
std::stringstream str;
|
||||
str << it.name;
|
||||
if (!strcmp(apiname, "evdev") && !it.id.empty())
|
||||
|
@ -688,7 +743,7 @@ namespace usb_pad
|
|||
}
|
||||
|
||||
for (auto& it : cfg.jsconf)
|
||||
SaveMappings(dev_type, port, it.first, it.second);
|
||||
SaveMappings(dev_type, port, it.first, cfg.max_buttons, cfg.max_axes, it.second);
|
||||
|
||||
if (is_evdev)
|
||||
{
|
||||
|
@ -731,11 +786,10 @@ namespace usb_pad
|
|||
|
||||
int GtkBuzzConfigure(int port, const char* dev_type, const char* apititle, const char* apiname, GtkWindow* parent, ApiCallbacks& apicbs)
|
||||
{
|
||||
GtkWidget *main_hbox, *right_vbox, *left_vbox, *treeview;
|
||||
GtkWidget* button;
|
||||
GtkWidget *main_hbox, *right_vbox, *left_vbox;
|
||||
|
||||
int fd;
|
||||
ConfigData cfg;
|
||||
ConfigData cfg{};
|
||||
|
||||
apicbs.populate(cfg.joysticks);
|
||||
|
||||
|
@ -745,6 +799,8 @@ namespace usb_pad
|
|||
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT);
|
||||
cfg.cb = &apicbs;
|
||||
cfg.dev_type = dev_type;
|
||||
cfg.max_axes = 0;
|
||||
cfg.max_buttons = 20;
|
||||
|
||||
for (const auto& it : cfg.joysticks)
|
||||
{
|
||||
|
@ -762,17 +818,8 @@ namespace usb_pad
|
|||
refresh_store(&cfg);
|
||||
|
||||
// ---------------------------
|
||||
std::string title = "Buzz ";
|
||||
title += apititle;
|
||||
|
||||
GtkWidget* dlg = gtk_dialog_new_with_buttons(
|
||||
title.c_str(), parent, GTK_DIALOG_MODAL,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OK, GTK_RESPONSE_OK,
|
||||
NULL);
|
||||
gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
|
||||
gtk_window_set_resizable(GTK_WINDOW(dlg), TRUE);
|
||||
gtk_window_set_default_size(GTK_WINDOW(dlg), 320, 240);
|
||||
const std::string title = std::string("Buzz ") + apititle;
|
||||
GtkWidget* dlg = make_dialog(parent, title);
|
||||
|
||||
// ---------------------------
|
||||
GtkWidget* dlg_area_box = gtk_dialog_get_content_area(GTK_DIALOG(dlg));
|
||||
|
@ -781,56 +828,21 @@ namespace usb_pad
|
|||
gtk_container_add(GTK_CONTAINER(dlg_area_box), main_hbox);
|
||||
|
||||
left_vbox = gtk_vbox_new(FALSE, 5);
|
||||
gtk_box_pack_start(GTK_BOX(main_hbox), left_vbox, TRUE, TRUE, 5);
|
||||
right_vbox = gtk_vbox_new(FALSE, 5);
|
||||
gtk_box_pack_start(GTK_BOX(main_hbox), left_vbox, TRUE, TRUE, 5);
|
||||
gtk_box_pack_start(GTK_BOX(main_hbox), right_vbox, TRUE, TRUE, 5);
|
||||
|
||||
// ---------------------------
|
||||
treeview = gtk_tree_view_new();
|
||||
cfg.treeview = GTK_TREE_VIEW(treeview);
|
||||
auto selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
|
||||
gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
|
||||
make_mappings_treeview(port, cfg, left_vbox);
|
||||
|
||||
GtkCellRenderer* render = gtk_cell_renderer_text_new();
|
||||
|
||||
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview),
|
||||
-1, "Name", render, "text", COL_NAME, "width", COL_COLUMN_WIDTH, NULL);
|
||||
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview),
|
||||
-1, "PS2", render, "text", COL_PS2, NULL);
|
||||
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview),
|
||||
-1, "PC", render, "text", COL_PC, NULL);
|
||||
|
||||
gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(treeview), 0);
|
||||
|
||||
gtk_tree_view_column_set_resizable(gtk_tree_view_get_column(GTK_TREE_VIEW(treeview), 0), TRUE);
|
||||
gtk_tree_view_column_set_resizable(gtk_tree_view_get_column(GTK_TREE_VIEW(treeview), 1), TRUE);
|
||||
gtk_tree_view_column_set_resizable(gtk_tree_view_get_column(GTK_TREE_VIEW(treeview), 2), TRUE);
|
||||
|
||||
gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(cfg.store));
|
||||
g_object_unref(GTK_TREE_MODEL(cfg.store)); //treeview has its own ref
|
||||
|
||||
GtkWidget* scwin = gtk_scrolled_window_new(NULL, NULL);
|
||||
gtk_container_add(GTK_CONTAINER(scwin), treeview);
|
||||
gtk_widget_set_size_request(GTK_WIDGET(scwin), 200, 100);
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scwin), GTK_POLICY_AUTOMATIC,
|
||||
GTK_POLICY_ALWAYS);
|
||||
gtk_box_pack_start(GTK_BOX(left_vbox), scwin, TRUE, TRUE, 5);
|
||||
|
||||
button = gtk_button_new_with_label("Clear binding");
|
||||
gtk_box_pack_start(GTK_BOX(left_vbox), button, FALSE, FALSE, 5);
|
||||
g_object_set_data(G_OBJECT(button), CFG, &cfg);
|
||||
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(clear_binding_clicked), reinterpret_cast<gpointer>(port));
|
||||
|
||||
button = gtk_button_new_with_label("Clear All");
|
||||
gtk_box_pack_start(GTK_BOX(left_vbox), button, FALSE, FALSE, 5);
|
||||
g_object_set_data(G_OBJECT(button), CFG, &cfg);
|
||||
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(clear_all_clicked), reinterpret_cast<gpointer>(port));
|
||||
#if GTK_CHECK_VERSION(3, 0, 0)
|
||||
gtk_widget_set_vexpand(left_vbox, TRUE);
|
||||
#endif
|
||||
|
||||
// ---------------------------
|
||||
|
||||
// Remapping
|
||||
{
|
||||
GtkWidget* table = gtk_table_new(5, 4, true);
|
||||
GtkWidget* table = gtk_table_new(5, 4, TRUE);
|
||||
gtk_container_add(GTK_CONTAINER(right_vbox), table);
|
||||
GtkAttachOptions opt = (GtkAttachOptions)(GTK_EXPAND | GTK_FILL); // default
|
||||
|
||||
|
@ -877,9 +889,9 @@ namespace usb_pad
|
|||
if (GTK_IS_ALIGNMENT(children->data))
|
||||
gtk_alignment_set(GTK_ALIGNMENT(children->data), 0.0f, 0.5f, 0.2f, 0.f);
|
||||
|
||||
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_clicked_buzz), reinterpret_cast<gpointer>(port));
|
||||
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_clicked), reinterpret_cast<gpointer>(port));
|
||||
|
||||
g_object_set_data(G_OBJECT(button), JOYTYPE, reinterpret_cast<gpointer>(j * countof(buzz_btns) + buzz_btns[i]));
|
||||
g_object_set_data(G_OBJECT(button), CONTROL, reinterpret_cast<gpointer>(j * countof(buzz_btns) + buzz_btns[i]));
|
||||
g_object_set_data(G_OBJECT(button), CFG, &cfg);
|
||||
|
||||
gtk_table_attach(GTK_TABLE(table), button,
|
||||
|
@ -930,5 +942,178 @@ namespace usb_pad
|
|||
return ret;
|
||||
}
|
||||
|
||||
int GtkKeyboardmaniaConfigure(int port, const char* dev_type, const char* apititle, const char* apiname, GtkWindow* parent, ApiCallbacks& apicbs)
|
||||
{
|
||||
GtkWidget *right_vbox, *left_vbox;
|
||||
|
||||
ConfigData cfg{};
|
||||
cfg.dev_type = dev_type;
|
||||
cfg.max_buttons = 31;
|
||||
load_devices_mappings(cfg, port, apicbs);
|
||||
|
||||
// ---------------------------
|
||||
const std::string title = std::string("Keyboardmania ") + apititle;
|
||||
GtkWidget* dlg = make_dialog(parent, title);
|
||||
|
||||
// ---------------------------
|
||||
GtkWidget* dlg_area_box = gtk_dialog_get_content_area(GTK_DIALOG(dlg));
|
||||
create_panes(dlg_area_box, left_vbox, right_vbox);
|
||||
make_mappings_treeview(port, cfg, left_vbox);
|
||||
|
||||
// ---------------------------
|
||||
// Remapping
|
||||
{
|
||||
GtkWidget* table = gtk_table_new(5, 14, TRUE);
|
||||
gtk_container_add(GTK_CONTAINER(right_vbox), table);
|
||||
GtkAttachOptions opt = (GtkAttachOptions)(GTK_EXPAND | GTK_FILL); // default
|
||||
#if GTK_CHECK_VERSION(3, 0, 0)
|
||||
gtk_widget_set_halign(table, GTK_ALIGN_START);
|
||||
#endif
|
||||
|
||||
struct keys
|
||||
{
|
||||
u32 index;
|
||||
bool sharp;
|
||||
};
|
||||
|
||||
constexpr keys keys[]{
|
||||
{0, false},
|
||||
{1, true},
|
||||
{2, false},
|
||||
{3, true},
|
||||
{4, false},
|
||||
{5, false},
|
||||
{6, true},
|
||||
//{"padding", 7},
|
||||
{8, false},
|
||||
{9, true},
|
||||
{10, false},
|
||||
{11, true},
|
||||
{12, false},
|
||||
{13, false},
|
||||
//{"Select", 14},
|
||||
//{"padding", 15},
|
||||
{16, true},
|
||||
{17, false},
|
||||
{18, true},
|
||||
{19, false},
|
||||
{20, false},
|
||||
{21, true},
|
||||
//{"Start", 22},
|
||||
//{"padding", 23},
|
||||
{24, false},
|
||||
{25, true},
|
||||
{26, false},
|
||||
{27, true},
|
||||
{28, false},
|
||||
//{"Up", 29},
|
||||
//{"Down", 30},
|
||||
};
|
||||
|
||||
int attached = 0;
|
||||
int voffset = 0;
|
||||
for (auto& key : keys)
|
||||
{
|
||||
GtkWidget* button = gtk_button_new_with_label(kbdmania_key_labels[key.index]);
|
||||
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_clicked), reinterpret_cast<gpointer>(port));
|
||||
g_object_set_data(G_OBJECT(button), CONTROL, reinterpret_cast<gpointer>(key.index));
|
||||
g_object_set_data(G_OBJECT(button), CFG, &cfg);
|
||||
|
||||
// split into 2-by-2 rows
|
||||
if (attached > 6)
|
||||
{
|
||||
voffset = 2;
|
||||
attached = 0;
|
||||
}
|
||||
|
||||
if (!key.sharp)
|
||||
{
|
||||
gtk_table_attach(GTK_TABLE(table), button,
|
||||
attached * 2, 2 + attached * 2,
|
||||
1 + voffset, 2 + voffset,
|
||||
opt, opt, 5, 1);
|
||||
attached++;
|
||||
}
|
||||
else
|
||||
gtk_table_attach(GTK_TABLE(table), button,
|
||||
attached * 2 - 1, attached * 2 + 2 - 1,
|
||||
0 + voffset, 1 + voffset,
|
||||
opt, opt, 5, 1);
|
||||
}
|
||||
|
||||
GtkWidget *button, *frame_box, *frame;
|
||||
GtkWidget* frame_container = gtk_hbox_new(FALSE, 5);
|
||||
gtk_container_add(GTK_CONTAINER(right_vbox), frame_container);
|
||||
#if GTK_CHECK_VERSION(3, 0, 0)
|
||||
gtk_widget_set_valign(frame_container, GTK_ALIGN_START);
|
||||
#endif
|
||||
|
||||
frame = gtk_frame_new("Buttons");
|
||||
{
|
||||
frame_box = gtk_hbox_new(FALSE, 5);
|
||||
gtk_container_add(GTK_CONTAINER(frame), frame_box);
|
||||
gtk_box_pack_start(GTK_BOX(frame_container), frame, FALSE, FALSE, 5);
|
||||
|
||||
button = gtk_button_new_with_label("Start");
|
||||
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_clicked), reinterpret_cast<gpointer>(port));
|
||||
g_object_set_data(G_OBJECT(button), CONTROL, reinterpret_cast<gpointer>(22));
|
||||
g_object_set_data(G_OBJECT(button), CFG, &cfg);
|
||||
gtk_box_pack_start(GTK_BOX(frame_box), button, FALSE, FALSE, 5);
|
||||
|
||||
button = gtk_button_new_with_label("Select");
|
||||
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_clicked), reinterpret_cast<gpointer>(port));
|
||||
g_object_set_data(G_OBJECT(button), CONTROL, reinterpret_cast<gpointer>(14));
|
||||
g_object_set_data(G_OBJECT(button), CFG, &cfg);
|
||||
gtk_box_pack_start(GTK_BOX(frame_box), button, FALSE, FALSE, 5);
|
||||
}
|
||||
|
||||
frame = gtk_frame_new("Wheel");
|
||||
{
|
||||
frame_box = gtk_hbox_new(FALSE, 5);
|
||||
gtk_container_add(GTK_CONTAINER(frame), frame_box);
|
||||
gtk_box_pack_start(GTK_BOX(frame_container), frame, FALSE, FALSE, 5);
|
||||
|
||||
button = gtk_button_new_with_label("Up");
|
||||
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_clicked), reinterpret_cast<gpointer>(port));
|
||||
g_object_set_data(G_OBJECT(button), CONTROL, reinterpret_cast<gpointer>(29));
|
||||
g_object_set_data(G_OBJECT(button), CFG, &cfg);
|
||||
gtk_box_pack_start(GTK_BOX(frame_box), button, FALSE, FALSE, 5);
|
||||
|
||||
button = gtk_button_new_with_label("Down");
|
||||
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(button_clicked), reinterpret_cast<gpointer>(port));
|
||||
g_object_set_data(G_OBJECT(button), CONTROL, reinterpret_cast<gpointer>(30));
|
||||
g_object_set_data(G_OBJECT(button), CFG, &cfg);
|
||||
gtk_box_pack_start(GTK_BOX(frame_box), button, FALSE, FALSE, 5);
|
||||
}
|
||||
}
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(right_vbox), cfg.label, TRUE, TRUE, 5);
|
||||
|
||||
// ---------------------------
|
||||
gtk_widget_show_all(dlg);
|
||||
gint result = gtk_dialog_run(GTK_DIALOG(dlg));
|
||||
|
||||
int ret = RESULT_OK;
|
||||
if (result == GTK_RESPONSE_OK)
|
||||
{
|
||||
if (cfg.js_iter != cfg.joysticks.end())
|
||||
{
|
||||
if (!SaveSetting(dev_type, port, apiname, N_JOYSTICK, cfg.js_iter->path))
|
||||
ret = RESULT_FAILED;
|
||||
}
|
||||
|
||||
for (auto& it : cfg.jsconf)
|
||||
SaveMappings(dev_type, port, it.first, cfg.max_buttons, 0, it.second);
|
||||
}
|
||||
else
|
||||
ret = RESULT_CANCELED;
|
||||
|
||||
for (auto& it : cfg.jsconf)
|
||||
close(it.second.fd);
|
||||
|
||||
gtk_widget_destroy(dlg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace evdev
|
||||
} // namespace usb_pad
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#pragma once
|
||||
#include <linux/joystick.h>
|
||||
#include <unistd.h>
|
||||
#include "Pcsx2Types.h"
|
||||
#include "USB/gtk.h"
|
||||
#include "USB/usb-pad/padproxy.h"
|
||||
#include "USB/configuration.h"
|
||||
|
@ -31,10 +32,15 @@ struct evdev_device
|
|||
std::string name;
|
||||
std::string id;
|
||||
std::string path;
|
||||
struct {
|
||||
uint16_t bustype;
|
||||
uint16_t vendor;
|
||||
uint16_t product;
|
||||
uint16_t version;
|
||||
} input_id;
|
||||
};
|
||||
|
||||
typedef std::vector<evdev_device> device_list;
|
||||
GtkWidget* new_combobox(const char* label, GtkWidget* vbox);
|
||||
|
||||
namespace usb_pad
|
||||
{
|
||||
|
@ -46,7 +52,6 @@ namespace usb_pad
|
|||
COL_NAME = 0,
|
||||
COL_PS2,
|
||||
COL_PC,
|
||||
COL_COLUMN_WIDTH,
|
||||
COL_BINDING,
|
||||
NUM_COLS
|
||||
};
|
||||
|
@ -76,7 +81,7 @@ namespace usb_pad
|
|||
JOY_MAPS_COUNT
|
||||
};
|
||||
|
||||
static constexpr const char* JoystickMapNames[] = {
|
||||
constexpr const char* JoystickMapNames[]{
|
||||
"cross",
|
||||
"square",
|
||||
"circle",
|
||||
|
@ -95,9 +100,10 @@ namespace usb_pad
|
|||
"right",
|
||||
"steering",
|
||||
"throttle",
|
||||
"brake"};
|
||||
"brake",
|
||||
};
|
||||
|
||||
static constexpr const char* buzz_map_names[] = {
|
||||
constexpr const char* buzz_map_names[]{
|
||||
"red",
|
||||
"yellow",
|
||||
"green",
|
||||
|
@ -105,6 +111,40 @@ namespace usb_pad
|
|||
"blue",
|
||||
};
|
||||
|
||||
constexpr const char* kbdmania_key_labels[]{
|
||||
"C 1",
|
||||
"C# 1",
|
||||
"D 1",
|
||||
"D# 1",
|
||||
"E 1",
|
||||
"F 1",
|
||||
"F# 1",
|
||||
"",
|
||||
"G 1",
|
||||
"G# 1",
|
||||
"A 1",
|
||||
"A# 1",
|
||||
"B 1",
|
||||
"C 2",
|
||||
"Select",
|
||||
"",
|
||||
"C# 2",
|
||||
"D 2",
|
||||
"D# 2",
|
||||
"E 2",
|
||||
"F 2",
|
||||
"F# 2",
|
||||
"Start",
|
||||
"",
|
||||
"G 2",
|
||||
"G# 2",
|
||||
"A 2",
|
||||
"A# 2",
|
||||
"B 2",
|
||||
"Up",
|
||||
"Down",
|
||||
};
|
||||
|
||||
struct Point
|
||||
{
|
||||
int x;
|
||||
|
@ -128,7 +168,7 @@ namespace usb_pad
|
|||
|
||||
struct ApiCallbacks
|
||||
{
|
||||
bool (*get_event_name)(const char* dev_type, int map, int event, const char** name);
|
||||
bool (*get_event_name)(const char* dev_type, int map, int event, bool is_button, const char** name);
|
||||
void (*populate)(device_list& jsdata);
|
||||
bool (*poll)(const std::vector<std::pair<std::string, ConfigMapping>>& jsconf, std::string& dev_name, bool isaxis, int& value, bool& inverted, int& initial);
|
||||
};
|
||||
|
@ -145,6 +185,7 @@ namespace usb_pad
|
|||
ApiCallbacks* cb;
|
||||
int use_hidraw_ff_pt;
|
||||
const char* dev_type;
|
||||
u32 max_axes, max_buttons;
|
||||
};
|
||||
|
||||
struct axis_correct
|
||||
|
@ -167,8 +208,9 @@ namespace usb_pad
|
|||
|
||||
int GtkPadConfigure(int port, const char* dev_type, const char* title, const char* apiname, GtkWindow* parent, ApiCallbacks& apicbs);
|
||||
int GtkBuzzConfigure(int port, const char* dev_type, const char* title, const char* apiname, GtkWindow* parent, ApiCallbacks& apicbs);
|
||||
bool LoadMappings(const char* dev_type, int port, const std::string& joyname, ConfigMapping& cfg);
|
||||
bool SaveMappings(const char* dev_type, int port, const std::string& joyname, const ConfigMapping& cfg);
|
||||
int GtkKeyboardmaniaConfigure(int port, const char* dev_type, const char* apititle, const char* apiname, GtkWindow* parent, ApiCallbacks& apicbs);
|
||||
bool LoadMappings(const char* dev_type, int port, const std::string& joyname, u32 max_buttons, u32 max_axes, ConfigMapping& cfg);
|
||||
bool SaveMappings(const char* dev_type, int port, const std::string& joyname, u32 max_buttons, u32 max_axes, const ConfigMapping& cfg);
|
||||
bool LoadBuzzMappings(const char* dev_type, int port, const std::string& joyname, ConfigMapping& cfg);
|
||||
bool SaveBuzzMappings(const char* dev_type, int port, const std::string& joyname, const ConfigMapping& cfg);
|
||||
} // namespace evdev
|
||||
|
|
|
@ -32,10 +32,10 @@ namespace usb_pad
|
|||
#define JOYTYPE "joytype"
|
||||
#define CFG "cfg"
|
||||
|
||||
static bool GetEventName(const char* dev_type, int map, int event, const char** name)
|
||||
static bool GetEventName(const char* dev_type, int map, int event, bool is_button, const char** name)
|
||||
{
|
||||
static char buf[256] = {0};
|
||||
if (map < evdev::JOY_STEERING)
|
||||
if (is_button)
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "Button %d", event);
|
||||
}
|
||||
|
|
|
@ -73,7 +73,6 @@ namespace usb_pad
|
|||
close(fd);
|
||||
}
|
||||
}
|
||||
//quit:
|
||||
closedir(dirp);
|
||||
}
|
||||
|
||||
|
@ -381,7 +380,7 @@ namespace usb_pad
|
|||
continue;
|
||||
}
|
||||
|
||||
LoadMappings(mDevType, mPort, device.name, device.cfg);
|
||||
LoadMappings(mDevType, mPort, device.name, 3, 16, device.cfg);
|
||||
|
||||
// Axis Mapping
|
||||
if (ioctl(device.cfg.fd, JSIOCGAXMAP, device.axis_map) < 0)
|
||||
|
@ -394,16 +393,17 @@ namespace usb_pad
|
|||
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++)
|
||||
for (int k = 0; k < count; k++)
|
||||
{
|
||||
if (k == device.cfg.controls[i])
|
||||
for (int i = JOY_STEERING; i < JOY_MAPS_COUNT; i++)
|
||||
{
|
||||
device.axis_map[k] = 0x80 | i;
|
||||
if (i == JOY_STEERING)
|
||||
has_steering = true;
|
||||
if (k == device.cfg.controls[i])
|
||||
{
|
||||
device.axis_map[k] = 0x80 | i;
|
||||
if (i == JOY_STEERING)
|
||||
has_steering = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ namespace usb_pad
|
|||
"Logitech Buzz(tm) Controller V1",
|
||||
"",
|
||||
"Logitech"};
|
||||
|
||||
static const USBDescStrings kbm_desc_strings = {
|
||||
"",
|
||||
"USB Multipurpose Controller",
|
||||
|
@ -93,7 +94,7 @@ namespace usb_pad
|
|||
|
||||
std::list<std::string> KeyboardmaniaDevice::ListAPIs()
|
||||
{
|
||||
return PadDevice::ListAPIs();
|
||||
return {"evdev"};
|
||||
}
|
||||
|
||||
const TCHAR* KeyboardmaniaDevice::LongAPIName(const std::string& name)
|
||||
|
@ -319,7 +320,6 @@ namespace usb_pad
|
|||
s->pad->Close();
|
||||
}
|
||||
|
||||
|
||||
void pad_reset_data(generic_data_t* d)
|
||||
{
|
||||
memset(d, 0, sizeof(generic_data_t));
|
||||
|
@ -540,6 +540,28 @@ namespace usb_pad
|
|||
#endif
|
||||
}
|
||||
|
||||
static void pad_init(PADState* s, int port, Pad* pad)
|
||||
{
|
||||
s->f.dev_subtype = pad->Type();
|
||||
s->pad = pad;
|
||||
s->port = port;
|
||||
|
||||
s->dev.speed = USB_SPEED_FULL;
|
||||
s->dev.klass.handle_attach = usb_desc_attach;
|
||||
s->dev.klass.handle_reset = pad_handle_reset;
|
||||
s->dev.klass.handle_control = pad_handle_control;
|
||||
s->dev.klass.handle_data = pad_handle_data;
|
||||
s->dev.klass.unrealize = pad_handle_destroy;
|
||||
s->dev.klass.open = pad_open;
|
||||
s->dev.klass.close = pad_close;
|
||||
s->dev.klass.usb_desc = &s->desc;
|
||||
s->dev.klass.product_desc = nullptr;
|
||||
|
||||
usb_desc_init(&s->dev);
|
||||
usb_ep_init(&s->dev);
|
||||
pad_handle_reset((USBDevice*)s);
|
||||
}
|
||||
|
||||
USBDevice* PadDevice::CreateDevice(int port)
|
||||
{
|
||||
std::string varApi;
|
||||
|
@ -554,13 +576,13 @@ namespace usb_pad
|
|||
if (!proxy)
|
||||
{
|
||||
Console.WriteLn("USB: PAD: Invalid input API.\n");
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Pad* pad = proxy->CreateObject(port, TypeName());
|
||||
|
||||
if (!pad)
|
||||
return NULL;
|
||||
return nullptr;
|
||||
|
||||
pad->Type((PS2WheelTypes)GetSelectedSubtype(std::make_pair(port, TypeName())));
|
||||
PADState* s = new PADState();
|
||||
|
@ -610,23 +632,7 @@ namespace usb_pad
|
|||
if (usb_desc_parse_config(config_desc, config_desc_len, s->desc_dev) < 0)
|
||||
goto fail;
|
||||
|
||||
s->f.dev_subtype = pad->Type();
|
||||
s->pad = pad;
|
||||
s->dev.speed = USB_SPEED_FULL;
|
||||
s->dev.klass.handle_attach = usb_desc_attach;
|
||||
s->dev.klass.handle_reset = pad_handle_reset;
|
||||
s->dev.klass.handle_control = pad_handle_control;
|
||||
s->dev.klass.handle_data = pad_handle_data;
|
||||
s->dev.klass.unrealize = pad_handle_destroy;
|
||||
s->dev.klass.open = pad_open;
|
||||
s->dev.klass.close = pad_close;
|
||||
s->dev.klass.usb_desc = &s->desc;
|
||||
s->dev.klass.product_desc = s->desc.str[2]; //not really used
|
||||
s->port = port;
|
||||
|
||||
usb_desc_init(&s->dev);
|
||||
usb_ep_init(&s->dev);
|
||||
pad_handle_reset((USBDevice*)s);
|
||||
pad_init(s, port, pad);
|
||||
|
||||
return (USBDevice*)s;
|
||||
|
||||
|
@ -682,13 +688,13 @@ namespace usb_pad
|
|||
if (!proxy)
|
||||
{
|
||||
Console.WriteLn("RBDK: Invalid input API.\n");
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Pad* pad = proxy->CreateObject(port, TypeName());
|
||||
|
||||
if (!pad)
|
||||
return NULL;
|
||||
return nullptr;
|
||||
|
||||
pad->Type(WT_ROCKBAND1_DRUMKIT);
|
||||
PADState* s = new PADState();
|
||||
|
@ -701,23 +707,7 @@ namespace usb_pad
|
|||
if (usb_desc_parse_config(rb1_config_descriptor, sizeof(rb1_config_descriptor), s->desc_dev) < 0)
|
||||
goto fail;
|
||||
|
||||
s->f.dev_subtype = pad->Type();
|
||||
s->pad = pad;
|
||||
s->port = port;
|
||||
s->dev.speed = USB_SPEED_FULL;
|
||||
s->dev.klass.handle_attach = usb_desc_attach;
|
||||
s->dev.klass.handle_reset = pad_handle_reset;
|
||||
s->dev.klass.handle_control = pad_handle_control;
|
||||
s->dev.klass.handle_data = pad_handle_data;
|
||||
s->dev.klass.unrealize = pad_handle_destroy;
|
||||
s->dev.klass.open = pad_open;
|
||||
s->dev.klass.close = pad_close;
|
||||
s->dev.klass.usb_desc = &s->desc;
|
||||
s->dev.klass.product_desc = s->desc.str[2];
|
||||
|
||||
usb_desc_init(&s->dev);
|
||||
usb_ep_init(&s->dev);
|
||||
pad_handle_reset((USBDevice*)s);
|
||||
pad_init(s, port, pad);
|
||||
|
||||
return (USBDevice*)s;
|
||||
|
||||
|
@ -774,23 +764,7 @@ namespace usb_pad
|
|||
if (usb_desc_parse_config(buzz_config_descriptor, sizeof(buzz_config_descriptor), s->desc_dev) < 0)
|
||||
goto fail;
|
||||
|
||||
s->f.dev_subtype = pad->Type();
|
||||
s->pad = pad;
|
||||
s->port = port;
|
||||
s->dev.speed = USB_SPEED_FULL;
|
||||
s->dev.klass.handle_attach = usb_desc_attach;
|
||||
s->dev.klass.handle_reset = pad_handle_reset;
|
||||
s->dev.klass.handle_control = pad_handle_control;
|
||||
s->dev.klass.handle_data = pad_handle_data;
|
||||
s->dev.klass.unrealize = pad_handle_destroy;
|
||||
s->dev.klass.open = pad_open;
|
||||
s->dev.klass.close = pad_close;
|
||||
s->dev.klass.usb_desc = &s->desc;
|
||||
s->dev.klass.product_desc = s->desc.str[2];
|
||||
|
||||
usb_desc_init(&s->dev);
|
||||
usb_ep_init(&s->dev);
|
||||
pad_handle_reset((USBDevice*)s);
|
||||
pad_init(s, port, pad);
|
||||
|
||||
return (USBDevice*)s;
|
||||
|
||||
|
@ -828,13 +802,13 @@ namespace usb_pad
|
|||
if (!proxy)
|
||||
{
|
||||
Console.WriteLn("usb-pad: %s: Invalid input API.", TypeName());
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Pad* pad = proxy->CreateObject(port, TypeName());
|
||||
|
||||
if (!pad)
|
||||
return NULL;
|
||||
return nullptr;
|
||||
|
||||
pad->Type(WT_KEYBOARDMANIA_CONTROLLER);
|
||||
PADState* s = new PADState();
|
||||
|
@ -847,23 +821,7 @@ namespace usb_pad
|
|||
if (usb_desc_parse_config(kbm_config_descriptor, sizeof(kbm_config_descriptor), s->desc_dev) < 0)
|
||||
goto fail;
|
||||
|
||||
s->f.dev_subtype = pad->Type();
|
||||
s->pad = pad;
|
||||
s->port = port;
|
||||
s->dev.speed = USB_SPEED_FULL;
|
||||
s->dev.klass.handle_attach = usb_desc_attach;
|
||||
s->dev.klass.handle_reset = pad_handle_reset;
|
||||
s->dev.klass.handle_control = pad_handle_control;
|
||||
s->dev.klass.handle_data = pad_handle_data;
|
||||
s->dev.klass.unrealize = pad_handle_destroy;
|
||||
s->dev.klass.open = pad_open;
|
||||
s->dev.klass.close = pad_close;
|
||||
s->dev.klass.usb_desc = &s->desc;
|
||||
s->dev.klass.product_desc = s->desc.str[2];
|
||||
|
||||
usb_desc_init(&s->dev);
|
||||
usb_ep_init(&s->dev);
|
||||
pad_handle_reset((USBDevice*)s);
|
||||
pad_init(s, port, pad);
|
||||
|
||||
return (USBDevice*)s;
|
||||
|
||||
|
|
|
@ -109,7 +109,6 @@ namespace usb_pad
|
|||
{
|
||||
return {};
|
||||
}
|
||||
static void Initialize();
|
||||
};
|
||||
|
||||
class SeamicDevice
|
||||
|
@ -475,27 +474,30 @@ namespace usb_pad
|
|||
static const int HATS_8TO4[] = {PAD_HAT_N, PAD_HAT_E, PAD_HAT_S, PAD_HAT_W};
|
||||
|
||||
#define PAD_VID 0x046D
|
||||
#define PAD_PID 0xCA03 //black MOMO
|
||||
#define PAD_MOMO 0xCA03 //black MOMO
|
||||
#define GENERIC_PID 0xC294 //actually Driving Force aka PID that most logitech wheels initially report
|
||||
#define PID_DF 0xC294
|
||||
#define PID_DFP 0xC298 //SELECT + R3 + RIGHT SHIFT PADDLE (R1) ???
|
||||
#define PID_DFGT 0xC29A
|
||||
#define PID_FORMULA 0xC202 //Yellow Wingman Formula
|
||||
#define PID_FGP 0xC20E //Formula GP (maybe GT FORCE LPRC-1000)
|
||||
#define PID_FFGP 0xC293 // Formula Force GP
|
||||
#define PID_GTF 0xC293 // as is Formula Force GP
|
||||
#define PID_G25 0xC299 // OutRun 2 (jp) supports it apparently
|
||||
#define PID_FGP 0xC20E //Formula GP (maybe GT FORCE LPRC-1000)
|
||||
#define PID_FFGP 0xC293 // Formula Force GP
|
||||
#define PID_GTF 0xC293 // as is Formula Force GP
|
||||
#define PID_G25 0xC299 // OutRun 2 (jp) supports it apparently
|
||||
#define PID_G27 0xC29B
|
||||
#define MAX_BUTTONS 32
|
||||
#define MAX_AXES 7 //random 7: axes + hatswitch
|
||||
#define MAX_JOYS 32
|
||||
#define PAD_LG_FFB_WHITELIST \
|
||||
PAD_MOMO, PID_DF, PID_DFP, PID_DFGT, PID_FORMULA, PID_FGP, PID_FFGP, PID_GTF, PID_G25, PID_G27
|
||||
|
||||
/**
|
||||
linux hid-lg4ff.c
|
||||
http://www.spinics.net/lists/linux-input/msg16570.html
|
||||
Every Logitech wheel reports itself as generic Logitech Driving Force wheel (VID 046d, PID c294). This is done to ensure that the
|
||||
wheel will work on every USB HID-aware system even when no Logitech driver is available. It however limits the capabilities of the
|
||||
wheel - range is limited to 200 degrees, G25/G27 don't report the clutch pedal and there is only one combined axis for throttle and
|
||||
brake. The switch to native mode is done via hardware-specific command which is different for each wheel. When the wheel
|
||||
Every Logitech wheel reports itself as generic Logitech Driving Force wheel (VID 046d, PID c294). This is done to ensure that the
|
||||
wheel will work on every USB HID-aware system even when no Logitech driver is available. It however limits the capabilities of the
|
||||
wheel - range is limited to 200 degrees, G25/G27 don't report the clutch pedal and there is only one combined axis for throttle and
|
||||
brake. The switch to native mode is done via hardware-specific command which is different for each wheel. When the wheel
|
||||
receives such command, it simulates reconnect and reports to the OS with its actual PID.
|
||||
Currently not emulating reattachment. Any games that expect to?
|
||||
**/
|
||||
|
|
Loading…
Reference in New Issue