Some more work on ini file parsing and refactoring command line parsing
This commit is contained in:
parent
e1393fb40c
commit
96626bb5c0
15 changed files with 644 additions and 265 deletions
22
PROTOCOL
22
PROTOCOL
|
@ -79,8 +79,8 @@ Interface 0:
|
|||
Interface 1:
|
||||
Endpoint 3(in): Headset mic
|
||||
Endpoint 4(out): Headset phone
|
||||
Endpoint 5(in): UNKNOWN
|
||||
Endpoint 5(out): Information comes in when Headset gets plugged in
|
||||
Endpoint 5(in): Headset status information
|
||||
Endpoint 5(out): Headset configuration information
|
||||
Interface 2:
|
||||
Endpoint 6(in): Chatpad
|
||||
Interface 3:
|
||||
|
@ -92,6 +92,7 @@ len: 3 data: 0x01 0x03 0x0e // current LED status
|
|||
len: 3 data: 0x02 0x03 0x00 // UNKNOWN: maybe headset connection status or volume
|
||||
len: 3 data: 0x03 0x03 0x03 // Rumble Status (0x00 in the last pos means rumble is disabled, 0x03 is default)
|
||||
len: 3 data: 0x08 0x03 0x00 // Headset connection status (0x00 no headset, 0x02 headset)
|
||||
// also chatpad status, but requires sending 0x1f before its reported
|
||||
len: 20 data: 0x00 0x14 0x00 0x00 0x00 0x00 0x69 0xed 0x23 0xff 0x6b 0x00 0x15 0x03 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
len: 20 data: 0x00 0x14 0x00 0x00 0x00 0x00 0xfc 0xec 0x23 0xff 0x6b 0x00 0x15 0x03 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
|
||||
|
@ -188,20 +189,27 @@ len: 4 data: 0x00 0x04 0x00 0x00
|
|||
---------
|
||||
Sending to interface 1, endpoint 5:
|
||||
|
||||
This only works with the headset plugged in:
|
||||
This only works with the headset plugged in, these settings seem to be
|
||||
permanent, so handle with care:
|
||||
|
||||
0x00 0x03 0x0N -> { 0x05, 0x03, 0x0N } - sets something to N, with N [0, 1]
|
||||
0x01 0x03 0x0N -> { 0x01, 0x03, 0x0N } - sets something to N, with N [0, 1]
|
||||
0x02 0x03 0x0N -> { 0x02, 0x03, 0x0N } - sets something to N, with N [0, f]
|
||||
0x02 0x03 0x0N -> { 0x02, 0x03, 0x0N } - sets something to N, with N [0, f] (seems to be volume control)
|
||||
0x03 0x05 ???? -> { 0x03, 0x05, 0xff, 0x00, 0x00 } - doesn't seem to set anything, just reply
|
||||
0x04 ???? ????-> { 0x04, 0x03, 0xff } - doesn't seem to set anything, just reply
|
||||
|
||||
$ ./usbdebug 0x045e:0x028e
|
||||
listen 5
|
||||
send 5 0x00 0x03 0x01
|
||||
send 5 0x01 0x03 0x01
|
||||
send 5 0x02 0x03 0x0f
|
||||
|
||||
0x04 0x04 0x00 0x00 seems to cause status reply
|
||||
---------
|
||||
Plugging in a headset (interface 0, endpoint 1): len: 3 data: 0x08 0x03 0x00
|
||||
Pulling out a headset (interface 0, endpoint 1): len: 3 data: 0x08 0x03 0x02
|
||||
|
||||
|
||||
Headset sends with 8192 bytes per second
|
||||
The headset might be using isochronous transfer, neither bulk nor interrupt, libusb doesn't support that yet I think
|
||||
|
||||
|
@ -226,6 +234,10 @@ usb_control_msg()'s
|
|||
0x41 0x0 0x0a 0x02 # light circle
|
||||
0x41 0x0 0x0b 0x02 # light people
|
||||
0x41 0x0 0x0c 0x02 # light backlight leds
|
||||
0x41 0x0 0x0d 0x02 #
|
||||
0x41 0x0 0x0e 0x02 #
|
||||
0x41 0x0 0x0f 0x02 #
|
||||
0x41 0x0 0x10 0x02 # send at start
|
||||
0x41 0x0 0x11 0x02 # light capslock
|
||||
0x41 0x0 0x12 0x02 # light square
|
||||
0x41 0x0 0x13 0x02 # light square and capslock
|
||||
|
@ -233,7 +245,7 @@ usb_control_msg()'s
|
|||
0x41 0x0 0x15 0x02 # light capslock and circle
|
||||
0x41 0x0 0x16 0x02 # light circle and square
|
||||
0x41 0x0 0x17 0x02 # light circle, square and capslock
|
||||
0x41 0x0 0x18 0x02 #
|
||||
0x41 0x0 0x18 0x02 # send at start
|
||||
0x41 0x0 0x19 0x02 #
|
||||
0x41 0x0 0x1a 0x02 #
|
||||
0x41 0x0 0x1b 0x02 # makes led go on on a keypress
|
||||
|
|
20
TODO
20
TODO
|
@ -15,6 +15,26 @@ git push --tags
|
|||
Stuff to do before 0.6.0 release:
|
||||
=================================
|
||||
|
||||
* ini support
|
||||
|
||||
* endpoints can be taken directly from the usb configuration, thus
|
||||
avoiding issues with nummeric endpoints
|
||||
|
||||
* bcdDevice (product release version) seem to indicate type:
|
||||
|
||||
new controller with merged endpoints: bcdDevice: 0x0114
|
||||
old ones: 1.10
|
||||
|
||||
better way then to check for endpoints maybe
|
||||
|
||||
* give a hint in the documentation on how to do multi line comments:
|
||||
|
||||
xboxdrv \
|
||||
--buttonmap A=X,X=A `# swap A and X` \
|
||||
--buttonmap B=Y,Y=B `# swap B and Y`
|
||||
|
||||
* 045e:028f is the play&charge kit, give an error message when somebody tries to use that
|
||||
|
||||
* axis-min/max range must be transmitted to AxisEvent (maybe normalize to float)
|
||||
|
||||
* match by protocol not, just vendor/product, from xpad.c:
|
||||
|
|
|
@ -196,8 +196,8 @@ public:
|
|||
callback(data.get());
|
||||
}
|
||||
|
||||
// if (endpoint == 6)
|
||||
// std::cout << "Clear Halt: " << libusb_clear_halt(m_handle, endpoint) << std::endl;
|
||||
if (endpoint == 6)
|
||||
std::cout << "Clear Halt: " << libusb_clear_halt(m_handle, LIBUSB_ENDPOINT_IN | endpoint) << std::endl;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -614,16 +614,19 @@ button events will come out wrong.
|
|||
Changes the descriptive name the device will have
|
||||
.TP
|
||||
\*(T<\fB\-\-square\-axis\fR\*(T>
|
||||
The Xbox360 gamepad, as most other current day gamepads, features a
|
||||
circular movment range, which restricts the movement so that the
|
||||
distance to the center never gets beyond 1. This means that when you
|
||||
have the controller at the top/left the value reported is (0.7, 0.7)
|
||||
(i.e. length 1, angle 45) instead of (1,1). This behaviour is
|
||||
different then most classic joysticks, which had a square range and
|
||||
allowed x and y to be handled completly indepened.
|
||||
The Xbox360 gamepad, as most other current day gamepads,
|
||||
features a circular movement range, which restricts the
|
||||
movement so that the distance to the center never gets
|
||||
beyond 1. This means that when you have the controller
|
||||
at the top/left the value reported is (0.7, 0.7)
|
||||
(i.e. length 1, angle 45) instead of (1,1). This
|
||||
behaviour is different then most classic PC joysticks,
|
||||
which had a square range and would report (1,1) when
|
||||
hold in the top/left corner.
|
||||
|
||||
Some old games (i.e. DOS stuff) require a square movement range and
|
||||
will thus not function properly with the Xbox360 gamepad. Via the
|
||||
Some old games (i.e. mostly DOS stuff) require a
|
||||
square movement range and will not function properly
|
||||
with the Xbox360 gamepad. Via the
|
||||
\*(T<\fB\-\-square\-axis\fR\*(T> option you can work around this issue and diagonals will
|
||||
be reported as (1,1).
|
||||
.TP
|
||||
|
|
|
@ -13,10 +13,15 @@ static struct usb_device_id chatpad_table [] = {
|
|||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE (usb, chatpad_table);
|
||||
MODULE_DEVICE_TABLE(usb, chatpad_table);
|
||||
|
||||
//unsigned char init_sequence[] = { 0x1f, 0x1e, 0x1b, 0x1b, 0x1f, 0x18, 0x10, 0x13 };
|
||||
//unsigned char init_sequence[] = { 0x1f, 0x1b, 0x1b, 0x1f, 0x18, 0x10, 0x13 };
|
||||
unsigned char init_sequence[] = { 0x1f, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b };
|
||||
|
||||
struct usb_chatpad {
|
||||
struct usb_device* udev;
|
||||
struct usb_interface* intf;
|
||||
|
||||
struct urb* chatpad_urb;
|
||||
unsigned char* chatpad_idata;
|
||||
|
@ -28,11 +33,13 @@ struct usb_chatpad {
|
|||
struct delayed_work worker;
|
||||
|
||||
int ctrl_ready;
|
||||
int flip_flop;
|
||||
int counter;
|
||||
};
|
||||
|
||||
static void chatpad_chatpad_cb(struct urb *urb)
|
||||
static void chatpad_idata_cb(struct urb *urb)
|
||||
{
|
||||
struct usb_chatpad* chatpad = urb->context;
|
||||
|
||||
printk(KERN_INFO "chatpad_chatpad_cb()\n");
|
||||
switch (urb->status)
|
||||
{
|
||||
|
@ -59,6 +66,15 @@ static void chatpad_chatpad_cb(struct urb *urb)
|
|||
break;
|
||||
}
|
||||
|
||||
{
|
||||
//struct usb_endpoint_descriptor* ep = &chatpad->intf->cur_altsetting->endpoint[0].desc;
|
||||
//usb_reset_endpoint(urb->dev, usb_rcvintpipe(urb->dev, ep->bEndpointAddress));
|
||||
|
||||
//extern int usb_clear_halt(struct usb_device *dev, int pipe);
|
||||
int retval = usb_reset_configuration(chatpad->udev);
|
||||
printk(KERN_INFO "usb_reset(): %d\n", retval);
|
||||
}
|
||||
|
||||
{
|
||||
int retval = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (retval)
|
||||
|
@ -67,6 +83,39 @@ static void chatpad_chatpad_cb(struct urb *urb)
|
|||
}
|
||||
}
|
||||
|
||||
static void chatpad_control_cb(struct urb *urb)
|
||||
{
|
||||
struct usb_chatpad* chatpad = urb->context;
|
||||
|
||||
printk(KERN_INFO "chatpad_control_cb()\n");
|
||||
switch (urb->status)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
int i = 0;
|
||||
printk(KERN_INFO "chatpad_control_cb(): XXXX------------XXXXX %d - ", urb->actual_length);
|
||||
for(i = 0; i < urb->actual_length; ++i)
|
||||
{
|
||||
printk("0x%02x ", (int)(((unsigned char*)urb->transfer_buffer)[i]));
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case -ECONNRESET:
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN: // triggered when the module get unloaded or device disconnected
|
||||
printk(KERN_INFO "chatpad_chatpad_cb(): fail1 %d\n", urb->status);
|
||||
return;
|
||||
|
||||
default:
|
||||
printk(KERN_INFO "chatpad_chatpad_cb(): fail2 %d\n", urb->status);
|
||||
break;
|
||||
}
|
||||
|
||||
schedule_delayed_work(&chatpad->worker, msecs_to_jiffies(1000));
|
||||
}
|
||||
|
||||
static void chatpad_setup_chatpad_readloop(struct usb_chatpad* chatpad, struct usb_interface *intf)
|
||||
{
|
||||
printk(KERN_INFO "chatpad_setup_chatpad_readloop()\n");
|
||||
|
@ -83,7 +132,7 @@ static void chatpad_setup_chatpad_readloop(struct usb_chatpad* chatpad, struct u
|
|||
usb_fill_int_urb(chatpad->chatpad_urb, udev,
|
||||
usb_rcvintpipe(udev, ep->bEndpointAddress),
|
||||
chatpad->chatpad_idata, 32,
|
||||
chatpad_chatpad_cb, chatpad, ep->bInterval);
|
||||
chatpad_idata_cb, chatpad, ep->bInterval);
|
||||
|
||||
chatpad->chatpad_urb->transfer_dma = chatpad->chatpad_idata_dma;
|
||||
chatpad->chatpad_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
|
@ -126,41 +175,30 @@ static void chatpad_send_ctrl_msg(struct usb_chatpad* chatpad, int value)
|
|||
}
|
||||
}
|
||||
|
||||
static void chatpad_send_ctrl_msg_cb(struct urb *urb)
|
||||
{
|
||||
printk(KERN_INFO "chatpad_send_ctrl_msg_cb()\n");
|
||||
|
||||
switch (urb->status)
|
||||
{
|
||||
default:
|
||||
printk(KERN_INFO "chatpad_send_ctrl_msg_cb(): status = %d\n", urb->status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void chatpad_send_ctrl_msg_async(struct usb_chatpad* chatpad, int value)
|
||||
{
|
||||
printk(KERN_INFO "chatpad_sending: 0x%x\n", value);
|
||||
|
||||
chatpad->control_cr.bRequestType = USB_TYPE_VENDOR | USB_RECIP_INTERFACE;
|
||||
chatpad->control_cr.bRequest = USB_REQ_GET_STATUS;
|
||||
chatpad->control_cr.wValue = cpu_to_le16(value);
|
||||
chatpad->control_cr.wIndex = cpu_to_le16(2);
|
||||
chatpad->control_cr.wLength = cpu_to_le16(0);
|
||||
|
||||
// FIXME: must use different urb!
|
||||
usb_fill_control_urb(chatpad->control_urb,
|
||||
chatpad->udev,
|
||||
usb_sndctrlpipe(chatpad->udev, 0),
|
||||
(unsigned char*)&chatpad->control_cr,
|
||||
NULL, // transfer_buffer
|
||||
0, // buffer_length
|
||||
chatpad_send_ctrl_msg_cb,
|
||||
chatpad_control_cb,
|
||||
chatpad);
|
||||
|
||||
{
|
||||
int retval = usb_submit_urb(chatpad->control_urb, GFP_ATOMIC);
|
||||
if (retval)
|
||||
{
|
||||
printk(KERN_INFO "RETVAL: %d\n", retval);
|
||||
printk(KERN_INFO "chatpad_send_ctrl_msg_async: retval = %d\n", retval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -169,20 +207,17 @@ static void chatpad_chatpad_keepalive(struct work_struct *work)
|
|||
{
|
||||
struct usb_chatpad* chatpad = container_of(work, struct usb_chatpad, worker.work);
|
||||
|
||||
if (chatpad->flip_flop)
|
||||
if (chatpad->counter < sizeof(init_sequence))
|
||||
{
|
||||
printk(KERN_INFO "chatpad_sending: 0x1f()\n");
|
||||
chatpad_send_ctrl_msg(chatpad, 0x1f);
|
||||
chatpad_send_ctrl_msg_async(chatpad, init_sequence[chatpad->counter]);
|
||||
}
|
||||
else
|
||||
{
|
||||
printk(KERN_INFO "chatpad_sending: 0x1e()\n");
|
||||
chatpad_send_ctrl_msg(chatpad, 0x1e);
|
||||
chatpad_send_ctrl_msg_async(chatpad, (chatpad->counter % 2) ? 0x1f : 0x1e);
|
||||
}
|
||||
chatpad->counter += 1;
|
||||
|
||||
chatpad->flip_flop = !chatpad->flip_flop;
|
||||
|
||||
schedule_delayed_work(&chatpad->worker, msecs_to_jiffies(1000));
|
||||
printk(KERN_INFO "chatpad_chatpad_keepalive: waiting for reply\n");
|
||||
}
|
||||
|
||||
static void chatpad_setup_chatpad_keepalive(struct usb_chatpad* chatpad, struct usb_interface *intf)
|
||||
|
@ -202,6 +237,8 @@ static void chatpad_setup_chatpad_keepalive(struct usb_chatpad* chatpad, struct
|
|||
static int chatpad_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
|
||||
printk(KERN_INFO "chatpad_probe() -------------------------------------------------------------\n");
|
||||
|
||||
printk(KERN_INFO "chatpad_probe() called: %04x:%04x - %d - %d %d %d\n",
|
||||
(int)id->idVendor, (int)id->idProduct, intf->minor,
|
||||
|
@ -213,6 +250,7 @@ static int chatpad_probe(struct usb_interface *intf, const struct usb_device_id
|
|||
{
|
||||
struct usb_chatpad* chatpad = kzalloc(sizeof(struct usb_chatpad), GFP_KERNEL);
|
||||
chatpad->udev = udev;
|
||||
chatpad->intf = intf;
|
||||
usb_set_intfdata(intf, chatpad);
|
||||
|
||||
chatpad_setup_chatpad_readloop(chatpad, intf);
|
||||
|
@ -253,7 +291,7 @@ static struct usb_driver chatpad_driver = {
|
|||
};
|
||||
|
||||
static int __init usb_chatpad_init(void)
|
||||
{
|
||||
{
|
||||
// FIXME: called once for each interface?!
|
||||
int result = usb_register(&chatpad_driver);
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
@ -27,15 +28,16 @@
|
|||
|
||||
#include "arg_parser.hpp"
|
||||
#include "helper.hpp"
|
||||
#include "uinput_deviceid.hpp"
|
||||
#include "ini_schema_builder.hpp"
|
||||
#include "ini_parser.hpp"
|
||||
#include "options.hpp"
|
||||
#include "ini_schema.hpp"
|
||||
#include "uinput_deviceid.hpp"
|
||||
|
||||
#define RAISE_EXCEPTION(x) do { \
|
||||
std::ostringstream kiJk8f08d4oMX; \
|
||||
kiJk8f08d4oMX << x; \
|
||||
throw std::runtime_error(kiJk8f08d4oMX.str()); \
|
||||
} while(0)
|
||||
#define RAISE_EXCEPTION(x) do { \
|
||||
std::ostringstream kiJk8f08d4oMX; \
|
||||
kiJk8f08d4oMX << x; \
|
||||
throw std::runtime_error(kiJk8f08d4oMX.str()); \
|
||||
} while(0)
|
||||
|
||||
Options* g__options = 0;
|
||||
|
||||
|
@ -46,6 +48,8 @@ enum {
|
|||
OPTION_QUIET,
|
||||
OPTION_SILENT,
|
||||
OPTION_DAEMON,
|
||||
OPTION_CONFIG,
|
||||
OPTION_WRITE_CONFIG,
|
||||
OPTION_TEST_RUMBLE,
|
||||
OPTION_RUMBLE,
|
||||
OPTION_QUIT,
|
||||
|
@ -92,9 +96,16 @@ enum {
|
|||
};
|
||||
|
||||
CommandLineParser::CommandLineParser() :
|
||||
argp()
|
||||
m_argp(),
|
||||
m_ini()
|
||||
{
|
||||
argp
|
||||
init_argp();
|
||||
}
|
||||
|
||||
void
|
||||
CommandLineParser::init_argp()
|
||||
{
|
||||
m_argp
|
||||
.add_usage("[OPTION]...")
|
||||
.add_text("Xbox360 USB Gamepad Userspace Driver")
|
||||
.add_newline()
|
||||
|
@ -115,6 +126,8 @@ CommandLineParser::CommandLineParser() :
|
|||
.add_option(OPTION_NO_EXTRA_DEVICES, 0, "no-extra-devices", "", "Do not create keyboard and mouse devices, just use a single device")
|
||||
.add_option(OPTION_MIMIC_XPAD, 0, "mimic-xpad", "", "Causes xboxdrv to use the same axis and button names as the xpad kernel driver")
|
||||
.add_option(OPTION_DAEMON, 'D', "daemon", "", "run as daemon")
|
||||
.add_option(OPTION_CONFIG, 'c', "config", "FILE", "read configuration from FILE")
|
||||
.add_option(OPTION_WRITE_CONFIG, 0, "write-config", "FILE", "write an example configuration to FILE")
|
||||
.add_newline()
|
||||
|
||||
.add_text("Device Options: ")
|
||||
|
@ -163,7 +176,66 @@ CommandLineParser::CommandLineParser() :
|
|||
.add_newline()
|
||||
|
||||
.add_text("See README for more documentation and examples.")
|
||||
.add_text("Report bugs to Ingo Ruhnke <grumbel@gmx.de>");
|
||||
.add_text("Report bugs to Ingo Ruhnke <grumbel@gmx.de>");
|
||||
}
|
||||
|
||||
void
|
||||
CommandLineParser::init_ini(Options* opts)
|
||||
{
|
||||
m_ini.clear();
|
||||
|
||||
m_ini.section("xboxdrv")
|
||||
("verbose", &opts->verbose)
|
||||
("silent", &opts->silent)
|
||||
("quiet", &opts->quiet)
|
||||
("rumble", &opts->rumble)
|
||||
("led", &opts->led)
|
||||
("rumble-l", &opts->rumble_l)
|
||||
("rumble-r", &opts->rumble_r)
|
||||
("rumble-gain", &opts->rumble_gain)
|
||||
("controller-id", &opts->controller_id)
|
||||
("wireless-id", &opts->wireless_id)
|
||||
("instant-exit", &opts->instant_exit)
|
||||
("no-uinput", &opts->no_uinput)
|
||||
("detach-kernel-driver", &opts->detach_kernel_driver)
|
||||
("busid", &opts->busid)
|
||||
("devid", &opts->devid)
|
||||
("deadzone", &opts->deadzone)
|
||||
("deadzone-trigger", &opts->deadzone_trigger)
|
||||
("vendor-id", &opts->vendor_id)
|
||||
("product-id", &opts->product_id)
|
||||
|
||||
("square-axis", &opts->square_axis)
|
||||
("four-way-restrictor", &opts->four_way_restrictor)
|
||||
("dpad-rotation", &opts->dpad_rotation)
|
||||
("evdev-device", &opts->evdev_device);
|
||||
|
||||
m_ini.section("uinput")
|
||||
("device-name", &opts->uinput_config.device_name)
|
||||
("trigger-as-button", &opts->uinput_config.trigger_as_button)
|
||||
("trigger-as-zaxis", &opts->uinput_config.trigger_as_zaxis)
|
||||
("dpad-as-button", &opts->uinput_config.dpad_as_button)
|
||||
("dpad-only", &opts->uinput_config.dpad_only)
|
||||
("force-feedback", &opts->uinput_config.force_feedback)
|
||||
("extra-devices", &opts->uinput_config.extra_devices)
|
||||
// mimic_xpad()
|
||||
// btn_map
|
||||
// axis_map
|
||||
;
|
||||
|
||||
m_ini.section("ui-buttonmap", boost::bind(&CommandLineParser::set_ui_buttonmap, this, _1, _2));
|
||||
m_ini.section("ui-axismap", boost::bind(&CommandLineParser::set_ui_axismap, this, _1, _2));
|
||||
|
||||
m_ini.section("buttonmap", boost::bind(&CommandLineParser::set_buttonmap, this, _1, _2));
|
||||
m_ini.section("axismap", boost::bind(&CommandLineParser::set_axismap, this, _1, _2));
|
||||
|
||||
m_ini.section("autofire", boost::bind(&CommandLineParser::set_autofire, this, _1, _2));
|
||||
m_ini.section("relative-axis", boost::bind(&CommandLineParser::set_relative_axis, this, _1, _2));
|
||||
m_ini.section("calibration", boost::bind(&CommandLineParser::set_calibration, this, _1, _2));
|
||||
m_ini.section("axis-sensitivity", boost::bind(&CommandLineParser::set_calibration, this, _1, _2));
|
||||
|
||||
m_ini.section("evdev-absmap", boost::bind(&CommandLineParser::set_evdev_absmap, this, _1, _2));
|
||||
m_ini.section("evdev-keymap", boost::bind(&CommandLineParser::set_evdev_keymap, this, _1, _2));
|
||||
}
|
||||
|
||||
void set_ui_button_map(ButtonMap& ui_button_map, const std::string& str)
|
||||
|
@ -195,7 +267,8 @@ void set_ui_button_map(ButtonMap& ui_button_map, const std::string& str)
|
|||
}
|
||||
}
|
||||
|
||||
void set_ui_axis_map(AxisEvent* ui_axis_map, const std::string& str)
|
||||
void
|
||||
CommandLineParser::set_ui_axismap_from_string(const std::string& str)
|
||||
{
|
||||
std::string::size_type i = str.find_first_of('=');
|
||||
if (i == std::string::npos)
|
||||
|
@ -204,18 +277,9 @@ void set_ui_axis_map(AxisEvent* ui_axis_map, const std::string& str)
|
|||
}
|
||||
else
|
||||
{
|
||||
XboxAxis axis = string2axis(str.substr(0, i));
|
||||
AxisEvent event = AxisEvent::from_string(str.substr(i+1, str.size()-i));
|
||||
|
||||
if (axis != XBOX_AXIS_UNKNOWN)
|
||||
{
|
||||
ui_axis_map[axis] = event;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Couldn't convert string \"" + str + "\" to ui-axis-mapping");
|
||||
}
|
||||
}
|
||||
set_axismap(str.substr(0, i),
|
||||
str.substr(i+1, str.size()-i));
|
||||
}
|
||||
}
|
||||
|
||||
void set_evdev_absmap(std::map<int, XboxAxis>& absmap, const std::string& str)
|
||||
|
@ -233,10 +297,40 @@ void set_evdev_keymap(std::map<int, XboxButton>& keymap, const std::string& str)
|
|||
std::cout << "KEY: " << str2key(lhs) << std::endl;
|
||||
}
|
||||
|
||||
template<class C, class Func>
|
||||
void arg2vector2(const std::string& str, typename std::vector<C>& lst, Func func)
|
||||
{
|
||||
std::string::const_iterator start = str.begin();
|
||||
for(std::string::const_iterator i = str.begin(); i != str.end(); ++i)
|
||||
{
|
||||
if (*i == ',')
|
||||
{
|
||||
if (i != start)
|
||||
{
|
||||
std::string lhs, rhs;
|
||||
split_string_at(std::string(start, i), '=', &lhs, &rhs);
|
||||
lst.push_back(func(lhs, rhs));
|
||||
}
|
||||
|
||||
start = i+1;
|
||||
}
|
||||
}
|
||||
|
||||
if (start != str.end())
|
||||
{
|
||||
std::string lhs, rhs;
|
||||
split_string_at(std::string(start, str.end()), '=', &lhs, &rhs);
|
||||
lst.push_back(func(lhs, rhs));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CommandLineParser::parse_args(int argc, char** argv, Options* options)
|
||||
{
|
||||
ArgParser::ParsedOptions parsed = argp.parse_args(argc, argv);
|
||||
init_ini(options);
|
||||
m_options = options;
|
||||
|
||||
ArgParser::ParsedOptions parsed = m_argp.parse_args(argc, argv);
|
||||
|
||||
for(ArgParser::ParsedOptions::const_iterator i = parsed.begin(); i != parsed.end(); ++i)
|
||||
{
|
||||
|
@ -270,6 +364,43 @@ CommandLineParser::parse_args(int argc, char** argv, Options* options)
|
|||
opts.mode = Options::RUN_DAEMON;
|
||||
break;
|
||||
|
||||
case OPTION_WRITE_CONFIG:
|
||||
{
|
||||
opts.instant_exit = true;
|
||||
|
||||
std::ofstream out(opt.argument.c_str());
|
||||
if (!out)
|
||||
{
|
||||
std::ostringstream str;
|
||||
str << "Couldn't create " << opt.argument;
|
||||
throw std::runtime_error(str.str());
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: implement me
|
||||
m_ini.save(out);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OPTION_CONFIG:
|
||||
{
|
||||
std::ifstream in(opt.argument.c_str());
|
||||
if (!in)
|
||||
{
|
||||
std::ostringstream str;
|
||||
str << "Couldn't open " << opt.argument;
|
||||
throw std::runtime_error(str.str());
|
||||
}
|
||||
else
|
||||
{
|
||||
INISchemaBuilder builder(m_ini);
|
||||
INIParser parser(in, builder, opt.argument);
|
||||
parser.run();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OPTION_TEST_RUMBLE:
|
||||
opts.rumble = true;
|
||||
break;
|
||||
|
@ -359,11 +490,11 @@ CommandLineParser::parse_args(int argc, char** argv, Options* options)
|
|||
break;
|
||||
|
||||
case OPTION_BUTTONMAP:
|
||||
arg2vector(opt.argument, opts.button_map, &ButtonMapping::from_string);
|
||||
arg2vector2(opt.argument, opts.button_map, &ButtonMapping::from_string);
|
||||
break;
|
||||
|
||||
case OPTION_AXISMAP:
|
||||
arg2vector(opt.argument, opts.axis_map, &AxisMapping::from_string);
|
||||
arg2vector2(opt.argument, opts.axis_map, &AxisMapping::from_string);
|
||||
break;
|
||||
|
||||
case OPTION_NAME:
|
||||
|
@ -376,7 +507,7 @@ CommandLineParser::parse_args(int argc, char** argv, Options* options)
|
|||
break;
|
||||
|
||||
case OPTION_UI_AXISMAP:
|
||||
arg2apply(opt.argument, boost::bind(&set_ui_axis_map, opts.uinput_config.axis_map, _1));
|
||||
arg2apply(opt.argument, boost::bind(&CommandLineParser::set_ui_axismap_from_string, this, _1));
|
||||
break;
|
||||
|
||||
case OPTION_UI_BUTTONMAP:
|
||||
|
@ -387,12 +518,12 @@ CommandLineParser::parse_args(int argc, char** argv, Options* options)
|
|||
opts.uinput_config.dpad_as_button = true;
|
||||
opts.deadzone = 4000;
|
||||
opts.uinput_config.trigger_as_zaxis = true;
|
||||
arg2vector("-y2=y2,-trigger=trigger", opts.axis_map, &AxisMapping::from_string);
|
||||
arg2vector2("-y2=y2,-trigger=trigger", opts.axis_map, &AxisMapping::from_string);
|
||||
// send events only every 20msec, lower values cause a jumpy pointer
|
||||
arg2apply("x1=REL_X:15:20,y1=REL_Y:15:20,"
|
||||
"y2=REL_WHEEL:5:100,x2=REL_HWHEEL:5:100,"
|
||||
"trigger=REL_WHEEL:5:100",
|
||||
boost::bind(&set_ui_axis_map, opts.uinput_config.axis_map, _1));
|
||||
boost::bind(&CommandLineParser::set_ui_axismap_from_string, this, _1));
|
||||
arg2apply("a=BTN_LEFT,b=BTN_RIGHT,x=BTN_MIDDLE,y=KEY_ENTER,rb=KEY_PAGEDOWN,lb=KEY_PAGEUP,"
|
||||
"dl=KEY_LEFT,dr=KEY_RIGHT,du=KEY_UP,dd=KEY_DOWN,"
|
||||
"start=KEY_FORWARD,back=KEY_BACK,guide=KEY_ESC,"
|
||||
|
@ -409,11 +540,11 @@ CommandLineParser::parse_args(int argc, char** argv, Options* options)
|
|||
break;
|
||||
|
||||
case OPTION_EVDEV_ABSMAP:
|
||||
arg2apply(opt.argument, boost::bind(&set_evdev_absmap, boost::ref(opts.evdev_absmap), _1));
|
||||
arg2apply(opt.argument, boost::bind(&::set_evdev_absmap, boost::ref(opts.evdev_absmap), _1));
|
||||
break;
|
||||
|
||||
case OPTION_EVDEV_KEYMAP:
|
||||
arg2apply(opt.argument, boost::bind(&set_evdev_keymap, boost::ref(opts.evdev_keymap), _1));
|
||||
arg2apply(opt.argument, boost::bind(&::set_evdev_keymap, boost::ref(opts.evdev_keymap), _1));
|
||||
break;
|
||||
|
||||
case OPTION_ID:
|
||||
|
@ -469,19 +600,19 @@ CommandLineParser::parse_args(int argc, char** argv, Options* options)
|
|||
break;
|
||||
|
||||
case OPTION_AUTOFIRE:
|
||||
arg2vector(opt.argument, opts.autofire_map, &AutoFireMapping::from_string);
|
||||
arg2vector2(opt.argument, opts.autofire_map, &AutoFireMapping::from_string);
|
||||
break;
|
||||
|
||||
case OPTION_CALIBRARIOTION:
|
||||
arg2vector(opt.argument, opts.calibration_map, &CalibrationMapping::from_string);
|
||||
arg2vector2(opt.argument, opts.calibration_map, &CalibrationMapping::from_string);
|
||||
break;
|
||||
|
||||
case OPTION_RELATIVE_AXIS:
|
||||
arg2vector(opt.argument, opts.relative_axis_map, &RelativeAxisMapping::from_string);
|
||||
arg2vector2(opt.argument, opts.relative_axis_map, &RelativeAxisMapping::from_string);
|
||||
break;
|
||||
|
||||
case OPTION_AXIS_SENSITIVITY:
|
||||
arg2vector(opt.argument, opts.axis_sensitivity_map, &AxisSensitivityMapping::from_string);
|
||||
arg2vector2(opt.argument, opts.axis_sensitivity_map, &AxisSensitivityMapping::from_string);
|
||||
break;
|
||||
|
||||
case OPTION_FOUR_WAY_RESTRICTOR:
|
||||
|
@ -580,7 +711,7 @@ CommandLineParser::parse_args(int argc, char** argv, Options* options)
|
|||
void
|
||||
CommandLineParser::print_help() const
|
||||
{
|
||||
argp.print_help(std::cout);
|
||||
m_argp.print_help(std::cout);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -619,54 +750,98 @@ CommandLineParser::print_version() const
|
|||
}
|
||||
|
||||
void
|
||||
CommandLineParser::create_ini_schema()
|
||||
CommandLineParser::set_ui_axismap(const std::string& name, const std::string& value)
|
||||
{
|
||||
// INISchema ini;
|
||||
XboxAxis axis = string2axis(name);
|
||||
AxisEvent event = AxisEvent::from_string(value);
|
||||
if (axis != XBOX_AXIS_UNKNOWN)
|
||||
{
|
||||
m_options->uinput_config.axis_map[axis] = event;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Couldn't convert string \"" + name + "=" + value + "\" to ui-axis-mapping");
|
||||
}
|
||||
}
|
||||
|
||||
// ini.section("general")
|
||||
// ("verbose", &verbose)
|
||||
// ("silent", &silent)
|
||||
// ("quiet", &quiet)
|
||||
// ("rumble", &rumble)
|
||||
// ("led", &led)
|
||||
// ("rumble_l", &rumble_l)
|
||||
// ("rumble_r", &rumble_r)
|
||||
// ("rumble_gain", &rumble_gain)
|
||||
// ("controller-id", &controller_id)
|
||||
// ("wireless-id", &wireless_id)
|
||||
// ("instant-exit", &instant_exit)
|
||||
// ("no-uinput", &no_uinput)
|
||||
// ("detach-kernel-driver", &detach_kernel_driver);
|
||||
void
|
||||
CommandLineParser::set_ui_buttonmap(const std::string& name, const std::string& value)
|
||||
{
|
||||
std::string btn_str = name;
|
||||
ButtonEvent event = ButtonEvent::from_string(value);
|
||||
|
||||
// char busid[4];
|
||||
// char devid[4];
|
||||
// int deadzone;
|
||||
// int deadzone_trigger;
|
||||
std::string::size_type j = btn_str.find('+');
|
||||
if (j == std::string::npos)
|
||||
{
|
||||
XboxButton btn = string2btn(btn_str);
|
||||
|
||||
// int vendor_id;
|
||||
// int product_id;
|
||||
m_options->uinput_config.btn_map.bind(btn, event);
|
||||
}
|
||||
else
|
||||
{
|
||||
XboxButton shift = string2btn(btn_str.substr(0, j));
|
||||
XboxButton btn = string2btn(btn_str.substr(j+1));
|
||||
|
||||
// bool square_axis;
|
||||
// bool four_way_restrictor;
|
||||
// int dpad_rotation;
|
||||
// std::string evdev_device;
|
||||
m_options->uinput_config.btn_map.bind(shift, btn, event);
|
||||
}
|
||||
}
|
||||
|
||||
// uInputCfg uinput_config;
|
||||
//ini.section("ui-buttonmap", ui_buttonmap_cb);
|
||||
//ini.section("ui-axismap", ui_buttonmap_cb);
|
||||
void
|
||||
CommandLineParser::set_axismap(const std::string& name, const std::string& value)
|
||||
{
|
||||
XboxAxis axis = string2axis(name);
|
||||
AxisEvent event = AxisEvent::from_string(value);
|
||||
|
||||
if (axis != XBOX_AXIS_UNKNOWN)
|
||||
{
|
||||
m_options->uinput_config.axis_map[axis] = event;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Couldn't convert string \"" + value + "\" to ui-axis-mapping");
|
||||
}
|
||||
}
|
||||
|
||||
// std::vector<ButtonMapping> button_map;
|
||||
//ini.section("buttonmap", buttonmap_cb);
|
||||
void
|
||||
CommandLineParser::set_buttonmap(const std::string& name, const std::string& value)
|
||||
{
|
||||
m_options->button_map.push_back(ButtonMapping::from_string(name, value));
|
||||
}
|
||||
|
||||
// std::vector<AxisMapping> axis_map;
|
||||
//ini.section("axismap", axismap_cb);
|
||||
void
|
||||
CommandLineParser::set_evdev_absmap(const std::string& name, const std::string& value)
|
||||
{
|
||||
m_options->evdev_absmap[str2abs(name)] = string2axis(value);
|
||||
}
|
||||
|
||||
// std::vector<AutoFireMapping> autofire_map;
|
||||
// std::vector<RelativeAxisMapping> relative_axis_map;
|
||||
// std::vector<CalibrationMapping> calibration_map;
|
||||
// std::vector<AxisSensitivityMapping> axis_sensitivity_map;
|
||||
// std::map<int, XboxAxis> evdev_absmap;
|
||||
// std::map<int, XboxButton> evdev_keymap;
|
||||
void
|
||||
CommandLineParser::set_evdev_keymap(const std::string& name, const std::string& value)
|
||||
{
|
||||
m_options->evdev_keymap[str2key(name)] = string2btn(value);
|
||||
}
|
||||
|
||||
void
|
||||
CommandLineParser::set_relative_axis(const std::string& name, const std::string& value)
|
||||
{
|
||||
m_options->relative_axis_map.push_back(RelativeAxisMapping::from_string(name, value));
|
||||
}
|
||||
|
||||
void
|
||||
CommandLineParser::set_autofire(const std::string& name, const std::string& value)
|
||||
{
|
||||
m_options->autofire_map.push_back(AutoFireMapping::from_string(name, value));
|
||||
}
|
||||
|
||||
void
|
||||
CommandLineParser::set_calibration(const std::string& name, const std::string& value)
|
||||
{
|
||||
m_options->calibration_map.push_back(CalibrationMapping::from_string(name, value));
|
||||
}
|
||||
|
||||
void
|
||||
CommandLineParser::set_axis_sensitivity(const std::string& name, const std::string& value)
|
||||
{
|
||||
m_options->axis_sensitivity_map.push_back(AxisSensitivityMapping::from_string(name, value));
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -22,18 +22,21 @@
|
|||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "modifier.hpp"
|
||||
#include "xboxmsg.hpp"
|
||||
#include "uinput.hpp"
|
||||
#include "arg_parser.hpp"
|
||||
#include "ini_schema.hpp"
|
||||
#include "modifier.hpp"
|
||||
#include "uinput.hpp"
|
||||
#include "xboxmsg.hpp"
|
||||
|
||||
class Xboxdrv;
|
||||
|
||||
class CommandLineParser
|
||||
{
|
||||
public:
|
||||
ArgParser argp;
|
||||
|
||||
ArgParser m_argp;
|
||||
INISchema m_ini;
|
||||
Options* m_options;
|
||||
|
||||
public:
|
||||
CommandLineParser();
|
||||
|
||||
|
@ -42,7 +45,29 @@ public:
|
|||
void print_help() const;
|
||||
void print_led_help() const;
|
||||
void print_version() const;
|
||||
void create_ini_schema();
|
||||
void create_ini_schema(Options* opts);
|
||||
|
||||
private:
|
||||
void set_ui_axismap_from_string(const std::string& str);
|
||||
|
||||
private:
|
||||
void set_ui_axismap(const std::string& name, const std::string& value);
|
||||
void set_ui_buttonmap(const std::string& name, const std::string& value);
|
||||
|
||||
void set_axismap(const std::string& name, const std::string& value);
|
||||
void set_buttonmap(const std::string& name, const std::string& value);
|
||||
|
||||
void set_evdev_absmap(const std::string& name, const std::string& value);
|
||||
void set_evdev_keymap(const std::string& name, const std::string& value);
|
||||
|
||||
void set_relative_axis(const std::string& name, const std::string& value);
|
||||
void set_autofire(const std::string& name, const std::string& value);
|
||||
void set_calibration(const std::string& name, const std::string& value);
|
||||
void set_axis_sensitivity(const std::string& name, const std::string& value);
|
||||
|
||||
private:
|
||||
void init_argp();
|
||||
void init_ini(Options* opts);
|
||||
};
|
||||
|
||||
extern Options* g_options;
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#ifndef HEADER_XBOXDRV_INI_BUILDER_HPP
|
||||
#define HEADER_XBOXDRV_INI_BUILDER_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
class INIBuilder
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -18,10 +18,13 @@
|
|||
|
||||
#include "ini_schema.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
class INIPairSchema
|
||||
{
|
||||
public:
|
||||
virtual ~INIPairSchema() {}
|
||||
virtual std::string str() const = 0;
|
||||
};
|
||||
|
||||
class INIPairSchemaBool : public INIPairSchema
|
||||
|
@ -46,8 +49,20 @@ public:
|
|||
throw std::runtime_error("unable to convert '" + value + "' to bool");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::string str() const
|
||||
{
|
||||
if (m_data)
|
||||
{
|
||||
return "true";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "false";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class INIPairSchemaInt : public INIPairSchema
|
||||
{
|
||||
private:
|
||||
|
@ -59,8 +74,15 @@ public:
|
|||
{
|
||||
*m_data = atoi(value.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
std::string str() const
|
||||
{
|
||||
std::ostringstream str;
|
||||
str << *m_data;
|
||||
return str.str();
|
||||
}
|
||||
};
|
||||
|
||||
class INIPairSchemaFloat : public INIPairSchema
|
||||
{
|
||||
private:
|
||||
|
@ -72,8 +94,15 @@ public:
|
|||
{
|
||||
*m_data = atoi(value.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
std::string str() const
|
||||
{
|
||||
std::ostringstream str;
|
||||
str << *m_data;
|
||||
return str.str();
|
||||
}
|
||||
};
|
||||
|
||||
class INIPairSchemaString : public INIPairSchema
|
||||
{
|
||||
private:
|
||||
|
@ -85,8 +114,14 @@ public:
|
|||
{
|
||||
*m_data = value;
|
||||
}
|
||||
};
|
||||
|
||||
std::string str() const
|
||||
{
|
||||
// FIXME: implement proper escaping
|
||||
return *m_data;
|
||||
}
|
||||
};
|
||||
|
||||
class INIPairSchemaCallback : public INIPairSchema
|
||||
{
|
||||
private:
|
||||
|
@ -99,8 +134,14 @@ public:
|
|||
if (m_callback)
|
||||
m_callback(value);
|
||||
}
|
||||
};
|
||||
|
||||
std::string str() const
|
||||
{
|
||||
// FIXME: implement me
|
||||
return "<not implemented>";
|
||||
}
|
||||
};
|
||||
|
||||
INISchemaSection::INISchemaSection()
|
||||
{
|
||||
}
|
||||
|
@ -163,17 +204,33 @@ INISchemaSection::operator()(const std::string& name, boost::function<void (cons
|
|||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
INISchemaSection::save(std::ostream& out)
|
||||
{
|
||||
for(Schema::iterator i = m_schema.begin(); i != m_schema.end(); ++i)
|
||||
{
|
||||
out << i->first << " = " << i->second->str() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
INISchema::INISchema() :
|
||||
m_sections()
|
||||
{
|
||||
}
|
||||
|
||||
INISchema::~INISchema()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void
|
||||
INISchema::clear()
|
||||
{
|
||||
for(Sections::iterator i = m_sections.begin(); i != m_sections.end(); ++i)
|
||||
{
|
||||
delete i->second;
|
||||
}
|
||||
m_sections.clear();
|
||||
}
|
||||
|
||||
INISchemaSection&
|
||||
|
@ -205,4 +262,16 @@ INISchema::get_section(const std::string& name)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
INISchema::save(std::ostream& out)
|
||||
{
|
||||
for(Sections::iterator i = m_sections.begin(); i != m_sections.end(); ++i)
|
||||
{
|
||||
out << "[" << i->first << "]" << std::endl;
|
||||
i->second->save(out);
|
||||
out << std::endl;
|
||||
}
|
||||
out << "\n# EOF #" << std::endl;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -41,6 +41,8 @@ public:
|
|||
INISchemaSection& operator()(const std::string& name, std::string* value);
|
||||
INISchemaSection& operator()(const std::string& name, boost::function<void (const std::string&)> callback);
|
||||
|
||||
void save(std::ostream& out);
|
||||
|
||||
private:
|
||||
INISchemaSection& add(const std::string& name, INIPairSchema* schema);
|
||||
|
||||
|
@ -59,12 +61,16 @@ public:
|
|||
INISchema();
|
||||
~INISchema();
|
||||
|
||||
void clear();
|
||||
|
||||
INISchemaSection& section(const std::string& name,
|
||||
boost::function<void (const std::string&, const std::string&)> callback
|
||||
= boost::function<void (const std::string&, const std::string&)>());
|
||||
|
||||
INISchemaSection* get_section(const std::string& name);
|
||||
|
||||
void save(std::ostream& out);
|
||||
|
||||
private:
|
||||
INISchema(const INISchema&);
|
||||
INISchema& operator=(const INISchema&);
|
||||
|
|
36
src/ini_schema_builder.cpp
Normal file
36
src/ini_schema_builder.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
** Xbox360 USB Gamepad Userspace Driver
|
||||
** Copyright (C) 2010 Ingo Ruhnke <grumbel@gmx.de>
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ini_schema_builder.hpp"
|
||||
|
||||
INISchemaBuilder::INISchemaBuilder(const INISchema& schema) :
|
||||
m_schema(schema)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
INISchemaBuilder::send_section(const std::string& section)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
INISchemaBuilder::send_pair(const std::string& name, const std::string& value)
|
||||
{
|
||||
}
|
||||
|
||||
/* EOF */
|
44
src/ini_schema_builder.hpp
Normal file
44
src/ini_schema_builder.hpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
** Xbox360 USB Gamepad Userspace Driver
|
||||
** Copyright (C) 2010 Ingo Ruhnke <grumbel@gmx.de>
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef HEADER_XBOXDRV_INI_SCHEMA_BUILDER_HPP
|
||||
#define HEADER_XBOXDRV_INI_SCHEMA_BUILDER_HPP
|
||||
|
||||
#include "ini_builder.hpp"
|
||||
|
||||
class INISchema;
|
||||
|
||||
class INISchemaBuilder : public INIBuilder
|
||||
{
|
||||
private:
|
||||
const INISchema& m_schema;
|
||||
|
||||
public:
|
||||
INISchemaBuilder(const INISchema& schema);
|
||||
|
||||
void send_section(const std::string& section);
|
||||
void send_pair(const std::string& name, const std::string& value);
|
||||
|
||||
private:
|
||||
INISchemaBuilder(const INISchemaBuilder&);
|
||||
INISchemaBuilder& operator=(const INISchemaBuilder&);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* EOF */
|
205
src/modifier.cpp
205
src/modifier.cpp
|
@ -71,56 +71,47 @@ void apply_axis_map(XboxGenericMsg& msg, const std::vector<AxisMapping>& lst)
|
|||
msg = newmsg;
|
||||
}
|
||||
|
||||
CalibrationMapping CalibrationMapping::from_string(const std::string& str)
|
||||
CalibrationMapping CalibrationMapping::from_string(const std::string& lhs, const std::string& rhs)
|
||||
{
|
||||
std::string::size_type epos = str.find_first_of('=');
|
||||
if (epos == std::string::npos)
|
||||
{
|
||||
throw std::runtime_error("Couldn't convert string \"" + str + "\" to CalibrationMapping");
|
||||
}
|
||||
else
|
||||
{
|
||||
CalibrationMapping mapping;
|
||||
mapping.axis = string2axis(str.substr(0, epos));
|
||||
mapping.min = -32768;
|
||||
mapping.center = 0;
|
||||
mapping.max = 32767;
|
||||
CalibrationMapping mapping;
|
||||
mapping.axis = string2axis(lhs);
|
||||
mapping.min = -32768;
|
||||
mapping.center = 0;
|
||||
mapping.max = 32767;
|
||||
|
||||
boost::char_separator<char> sep(":", "", boost::keep_empty_tokens);
|
||||
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
|
||||
boost::char_separator<char> sep(":", "", boost::keep_empty_tokens);
|
||||
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
|
||||
|
||||
std::string rhs = str.substr(epos+1);
|
||||
tokenizer tokens(rhs, sep);
|
||||
int j = 0;
|
||||
for(tokenizer::iterator i = tokens.begin(); i != tokens.end(); ++i, ++j)
|
||||
tokenizer tokens(rhs, sep);
|
||||
int j = 0;
|
||||
for(tokenizer::iterator i = tokens.begin(); i != tokens.end(); ++i, ++j)
|
||||
{
|
||||
//std::cout << "Token: '" << *i << "'" << std::endl;
|
||||
|
||||
if (!i->empty())
|
||||
{
|
||||
//std::cout << "Token: '" << *i << "'" << std::endl;
|
||||
|
||||
if (!i->empty())
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
if (j == 0)
|
||||
mapping.min = boost::lexical_cast<int>(*i);
|
||||
else if (j == 1)
|
||||
mapping.center = boost::lexical_cast<int>(*i);
|
||||
else if (j == 2)
|
||||
mapping.max = boost::lexical_cast<int>(*i);
|
||||
else
|
||||
throw std::runtime_error("--calibration: to many arguments given, syntax is 'AXIS=MIN:CENTER:MAX': " + str);
|
||||
}
|
||||
catch(boost::bad_lexical_cast&)
|
||||
{
|
||||
throw std::runtime_error("--calibration: couldn't convert '" + *i + "' to int");
|
||||
}
|
||||
if (j == 0)
|
||||
mapping.min = boost::lexical_cast<int>(*i);
|
||||
else if (j == 1)
|
||||
mapping.center = boost::lexical_cast<int>(*i);
|
||||
else if (j == 2)
|
||||
mapping.max = boost::lexical_cast<int>(*i);
|
||||
else
|
||||
throw std::runtime_error("--calibration: to many arguments given, syntax is 'AXIS=MIN:CENTER:MAX'");
|
||||
}
|
||||
catch(boost::bad_lexical_cast&)
|
||||
{
|
||||
throw std::runtime_error("--calibration: couldn't convert '" + *i + "' to int");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(mapping.min <= mapping.center && mapping.center <= mapping.max))
|
||||
throw std::runtime_error("Order wrong 'AXIS=MIN:CENTER:MAX': " + str);
|
||||
if (!(mapping.min <= mapping.center && mapping.center <= mapping.max))
|
||||
throw std::runtime_error("Order wrong 'AXIS=MIN:CENTER:MAX'");
|
||||
|
||||
return mapping;
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
|
||||
static int clamp(int lhs, int rhs, int v)
|
||||
|
@ -146,119 +137,77 @@ void apply_calibration_map(XboxGenericMsg& msg, const std::vector<CalibrationMap
|
|||
}
|
||||
|
||||
ButtonMapping
|
||||
ButtonMapping::from_string(const std::string& str)
|
||||
ButtonMapping::from_string(const std::string& lhs, const std::string& rhs)
|
||||
{
|
||||
for(std::string::const_iterator i = str.begin(); i != str.end(); ++i)
|
||||
{
|
||||
if (*i == '=')
|
||||
{
|
||||
ButtonMapping mapping;
|
||||
mapping.lhs = string2btn(std::string(str.begin(), i));
|
||||
mapping.rhs = string2btn(std::string(i+1, str.end()));
|
||||
|
||||
return mapping;
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("Couldn't convert string \"" + str + "\" to button mapping");
|
||||
ButtonMapping mapping;
|
||||
mapping.lhs = string2btn(lhs);
|
||||
mapping.rhs = string2btn(rhs);
|
||||
return mapping;
|
||||
}
|
||||
|
||||
AxisMapping
|
||||
AxisMapping::from_string(const std::string& str)
|
||||
AxisMapping::from_string(const std::string& lhs, const std::string& rhs)
|
||||
{
|
||||
for(std::string::const_iterator i = str.begin(); i != str.end(); ++i)
|
||||
assert(!lhs.empty());
|
||||
assert(!rhs.empty());
|
||||
|
||||
AxisMapping mapping;
|
||||
|
||||
if (lhs[0] == '-')
|
||||
{
|
||||
if (*i == '=')
|
||||
{
|
||||
AxisMapping mapping;
|
||||
|
||||
std::string lhs(str.begin(), i);
|
||||
std::string rhs(i+1, str.end());
|
||||
|
||||
if (lhs.empty() || rhs.empty())
|
||||
throw std::runtime_error("Couldn't convert string \"" + str + "\" to axis mapping");
|
||||
|
||||
if (lhs[0] == '-')
|
||||
{
|
||||
mapping.invert = true;
|
||||
mapping.lhs = string2axis(lhs.substr(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
mapping.invert = false;
|
||||
mapping.lhs = string2axis(lhs);
|
||||
}
|
||||
|
||||
mapping.rhs = string2axis(rhs);
|
||||
|
||||
if (mapping.lhs == XBOX_AXIS_UNKNOWN ||
|
||||
mapping.rhs == XBOX_AXIS_UNKNOWN)
|
||||
throw std::runtime_error("Couldn't convert string \"" + str + "\" to axis mapping");
|
||||
|
||||
return mapping;
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("Couldn't convert string \"" + str + "\" to axis mapping");
|
||||
}
|
||||
|
||||
RelativeAxisMapping
|
||||
RelativeAxisMapping::from_string(const std::string& str)
|
||||
{
|
||||
/* Format of str: A={SPEED} */
|
||||
std::string::size_type i = str.find('=');
|
||||
if (i == std::string::npos)
|
||||
{
|
||||
throw std::runtime_error("Couldn't convert string \"" + str + "\" to RelativeAxisMapping");
|
||||
mapping.invert = true;
|
||||
mapping.lhs = string2axis(lhs.substr(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
RelativeAxisMapping mapping;
|
||||
mapping.axis = string2axis(str.substr(0, i));
|
||||
mapping.speed = boost::lexical_cast<int>(str.substr(i+1, str.size()-i));
|
||||
// FIXME: insert some error checking here
|
||||
return mapping;
|
||||
mapping.invert = false;
|
||||
mapping.lhs = string2axis(lhs);
|
||||
}
|
||||
|
||||
mapping.rhs = string2axis(rhs);
|
||||
|
||||
if (mapping.lhs == XBOX_AXIS_UNKNOWN ||
|
||||
mapping.rhs == XBOX_AXIS_UNKNOWN)
|
||||
throw std::runtime_error("Couldn't convert string \"" + lhs + "=" + rhs + "\" to axis mapping");
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
RelativeAxisMapping
|
||||
RelativeAxisMapping::from_string(const std::string& lhs, const std::string& rhs)
|
||||
{
|
||||
/* Format of str: A={SPEED} */
|
||||
RelativeAxisMapping mapping;
|
||||
mapping.axis = string2axis(lhs);
|
||||
mapping.speed = boost::lexical_cast<int>(rhs);
|
||||
// FIXME: insert some error checking here
|
||||
return mapping;
|
||||
}
|
||||
|
||||
AutoFireMapping
|
||||
AutoFireMapping::from_string(const std::string& str)
|
||||
AutoFireMapping::from_string(const std::string& lhs, const std::string& rhs)
|
||||
{
|
||||
/* Format of str: A={ON-DELAY}[:{OFF-DELAY}]
|
||||
Examples: A=10 or A=10:50
|
||||
if OFF-DELAY == nil then ON-DELAY = OFF-DELAY
|
||||
*/
|
||||
std::string::size_type i = str.find_first_of('=');
|
||||
if (i == std::string::npos)
|
||||
{
|
||||
throw std::runtime_error("Couldn't convert string \"" + str + "\" to AutoFireMapping");
|
||||
}
|
||||
else
|
||||
{
|
||||
AutoFireMapping mapping;
|
||||
mapping.button = string2btn(str.substr(0, i));
|
||||
mapping.frequency = boost::lexical_cast<int>(str.substr(i+1, str.size()-i).c_str());
|
||||
return mapping;
|
||||
}
|
||||
AutoFireMapping mapping;
|
||||
mapping.button = string2btn(lhs);
|
||||
mapping.frequency = boost::lexical_cast<int>(rhs);
|
||||
return mapping;
|
||||
}
|
||||
|
||||
AxisSensitivityMapping
|
||||
AxisSensitivityMapping::from_string(const std::string& str)
|
||||
AxisSensitivityMapping::from_string(const std::string& lhs, const std::string& rhs)
|
||||
{
|
||||
/*
|
||||
Format of str: X1=SENSITIVITY
|
||||
Example: X1=2.0
|
||||
*/
|
||||
std::string::size_type i = str.find_first_of('=');
|
||||
if (i == std::string::npos)
|
||||
{
|
||||
throw std::runtime_error("Couldn't convert string \"" + str + "\" to AxisSensitivityMapping");
|
||||
}
|
||||
else
|
||||
{
|
||||
AxisSensitivityMapping mapping;
|
||||
mapping.axis = string2axis(str.substr(0, i));
|
||||
mapping.sensitivity = boost::lexical_cast<float>(str.substr(i+1, str.size()-i).c_str());
|
||||
return mapping;
|
||||
}
|
||||
AxisSensitivityMapping mapping;
|
||||
mapping.axis = string2axis(lhs);
|
||||
mapping.sensitivity = boost::lexical_cast<float>(rhs);
|
||||
return mapping;
|
||||
}
|
||||
|
||||
void squarify_axis_(int16_t& x_inout, int16_t& y_inout)
|
||||
|
|
|
@ -27,14 +27,14 @@
|
|||
class Options;
|
||||
|
||||
struct ButtonMapping {
|
||||
static ButtonMapping from_string(const std::string& str);
|
||||
static ButtonMapping from_string(const std::string& lhs, const std::string& rhs);
|
||||
|
||||
XboxButton lhs;
|
||||
XboxButton rhs;
|
||||
};
|
||||
|
||||
struct AxisMapping {
|
||||
static AxisMapping from_string(const std::string& str);
|
||||
static AxisMapping from_string(const std::string& lhs, const std::string& rhs);
|
||||
|
||||
XboxAxis lhs;
|
||||
XboxAxis rhs;
|
||||
|
@ -42,21 +42,21 @@ struct AxisMapping {
|
|||
};
|
||||
|
||||
struct AutoFireMapping {
|
||||
static AutoFireMapping from_string(const std::string&);
|
||||
static AutoFireMapping from_string(const std::string& lhs, const std::string& rhs);
|
||||
|
||||
XboxButton button;
|
||||
int frequency;
|
||||
};
|
||||
|
||||
struct RelativeAxisMapping {
|
||||
static RelativeAxisMapping from_string(const std::string&);
|
||||
static RelativeAxisMapping from_string(const std::string& lhs, const std::string& rhs);
|
||||
|
||||
XboxAxis axis;
|
||||
int speed;
|
||||
};
|
||||
|
||||
struct CalibrationMapping {
|
||||
static CalibrationMapping from_string(const std::string&);
|
||||
static CalibrationMapping from_string(const std::string& lhs, const std::string& rhs);
|
||||
|
||||
XboxAxis axis;
|
||||
int min;
|
||||
|
@ -65,7 +65,7 @@ struct CalibrationMapping {
|
|||
};
|
||||
|
||||
struct AxisSensitivityMapping {
|
||||
static AxisSensitivityMapping from_string(const std::string&);
|
||||
static AxisSensitivityMapping from_string(const std::string& lhs, const std::string& rhs);
|
||||
|
||||
XboxAxis axis;
|
||||
float sensitivity;
|
||||
|
|
|
@ -29,8 +29,8 @@ class uInputCfg
|
|||
public:
|
||||
std::string device_name;
|
||||
bool trigger_as_button;
|
||||
bool dpad_as_button;
|
||||
bool trigger_as_zaxis;
|
||||
bool dpad_as_button;
|
||||
bool dpad_only;
|
||||
bool force_feedback;
|
||||
bool extra_devices;
|
||||
|
|
Loading…
Add table
Reference in a new issue