diff --git a/TODO b/TODO index 100285a..ad12488 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,4 @@ -Pre Release Testing: +slPre Release Testing: ===================== * check the version number @@ -44,54 +44,10 @@ Stuff to do before 0.7.0 release: * AxisSensitivity filter has overflow issue -* add support for pairing the controller to the PC (or zero) - - --ps3-pair 00:00:00:00:00:00 - --ps3-pair-with-bluetooth - -* Playstation 3 controller support - - http://www.pabr.org/sixlinux/sixlinux.en.html - - http://www.motioninjoy.com/ - - - figure out what the remaining unknown bits mean: - - data from just pluging the controller in and out a few times - without much pause inbetween: - - Dualshock3: - // leaving controller plugged in for a longer time settles to this: - 00 00 03 ef 16 00 00 00 00 33 fc 77 01 de - - 00 00 03 ef 16 00 00 00 00 33 fc 77 01 de - 00 00 03 ef 16 00 00 00 00 33 fc 77 01 c0 - 00 00 02 ee 12 00 00 00 00 12 fc 77 01 de - ^^^^^ ^^^^^ - 00 00 01 ee 12 00 00 00 00 12 fc 77 01 de - 00 00 03 ef 16 00 00 00 00 11 fc 77 01 de - 00 00 03 ef 16 00 00 00 00 33 fc 77 01 de - 00 00 02 ee 12 00 00 00 00 12 fc 77 01 de - wrong ideas: bluetooth master id - - 00 00 01 ef 16 00 00 00 00 11 fc 77 01 c0 - 00 00 03 ef 16 00 00 00 00 11 fc 77 01 c0 - - SIXAXIS: - 00 00 06 ee 10 00 00 00 00 06 83 77 01 81 - 00 00 06 ee 10 00 00 00 00 06 83 77 01 - 00 00 06 ee 10 00 00 00 00 06 83 77 - - // taken from: http://www.pabr.org/sixlinux/sixlinux.en.html - 00 00 02 ee 10 00 00 00 00 02 b2 77 01 81 - - random guesses: bluetooth id, serial number, calibration data, - battery status - * fix the FIXME's * fix event output (have it pre-modifier or post-modifier?) -* fix --no-uinput - * need to hide/disable the toggle button from the UIButtonmap * move XBOX_BTN_UNKNOWN behind XBOX_BTN_MAX, so iteration can start @@ -101,13 +57,20 @@ Stuff to do before 0.7.0 release: Daemon Related Stuff ==================== +* currently device creation fails as all configurations are assigned + to the same virtual device + +* improve output on which uinput devices are created + +* fix --no-uinput + +* uinput must be thread safe + * implement --on-connect and --on-disconnect for the daemon - maybe have a more general event interface that allows to run stuff on configuration changes, controller plug-ins, etc. (notifiy area as example) - also supply useful information as argument -* uinput must be thread safe - * handle multiple controllers in a sane manner (requires cloning of modifier maps, also auto increment of "auto" device id's) @@ -155,12 +118,52 @@ List Output 1 hal daemon from Thomas Debouverie <debouverie_thomas@yahoo.fr> 1 Implemented --ui-buttonmap A=BTN_A@{device_id} ??!?!? -* improve output on which uinput devices are created - Stuff to do before 0.7.x release: ================================= +* Playstation 3 controller support + - http://www.pabr.org/sixlinux/sixlinux.en.html + - http://www.motioninjoy.com/ + + - figure out what the remaining unknown bits mean: + + data from just pluging the controller in and out a few times + without much pause inbetween: + + Dualshock3: + // leaving controller plugged in for a longer time settles to this: + 00 00 03 ef 16 00 00 00 00 33 fc 77 01 de + + 00 00 03 ef 16 00 00 00 00 33 fc 77 01 de + 00 00 03 ef 16 00 00 00 00 33 fc 77 01 c0 + 00 00 02 ee 12 00 00 00 00 12 fc 77 01 de + ^^^^^ ^^^^^ + 00 00 01 ee 12 00 00 00 00 12 fc 77 01 de + 00 00 03 ef 16 00 00 00 00 11 fc 77 01 de + 00 00 03 ef 16 00 00 00 00 33 fc 77 01 de + 00 00 02 ee 12 00 00 00 00 12 fc 77 01 de + wrong ideas: bluetooth master id + + 00 00 01 ef 16 00 00 00 00 11 fc 77 01 c0 + 00 00 03 ef 16 00 00 00 00 11 fc 77 01 c0 + + SIXAXIS: + 00 00 06 ee 10 00 00 00 00 06 83 77 01 81 + 00 00 06 ee 10 00 00 00 00 06 83 77 01 + 00 00 06 ee 10 00 00 00 00 06 83 77 + + // taken from: http://www.pabr.org/sixlinux/sixlinux.en.html + 00 00 02 ee 10 00 00 00 00 02 b2 77 01 81 + + random guesses: bluetooth id, serial number, calibration data, + battery status + +* add support for pairing the controller to the PC (or zero) + + --ps3-pair 00:00:00:00:00:00 + --ps3-pair-with-bluetooth + * allow named sections in INI files: [controller1/modifier] diff --git a/src/controller_config_set.cpp b/src/controller_config_set.cpp index 2b36ce1..9733cf0 100644 --- a/src/controller_config_set.cpp +++ b/src/controller_config_set.cpp @@ -18,6 +18,175 @@ #include "controller_config_set.hpp" +#include "uinput.hpp" +#include "options.hpp" +#include "log.hpp" + +#include "modifier/dpad_rotation_modifier.hpp" +#include "modifier/four_way_restrictor_modifier.hpp" +#include "modifier/square_axis_modifier.hpp" + +ControllerConfigSetPtr +ControllerConfigSet::create(uInput& uinput, const Options::ControllerConfigs& opts) +{ + ControllerConfigSetPtr m_config(new ControllerConfigSet); + + for(Options::ControllerConfigs::const_iterator i = opts.begin(); + i != opts.end(); ++i) + { + const ControllerOptions& ctrl_opt = i->second; + + ControllerConfigPtr config(new ControllerConfig(uinput, ctrl_opt)); + create_modifier(ctrl_opt, &config->get_modifier()); + m_config->add_config(config); + +#ifdef FIXME + // introspection of the config + std::cout << "==[[ Active Modifier ]]==" << std::endl; + for(std::vector<ModifierPtr>::iterator mod = config->get_modifier().begin(); + mod != config->get_modifier().end(); + ++mod) + { + std::cout << (*mod)->str() << std::endl; + } +#endif + } + + log_info << "UInput finish" << std::endl; + + // After all the ControllerConfig registered their events, finish up + // the device creation + uinput.finish(); + + return m_config; +} + +void +ControllerConfigSet::create_modifier(const ControllerOptions& opts, std::vector<ModifierPtr>* modifier) +{ + if (!opts.calibration_map.empty()) + { + boost::shared_ptr<AxismapModifier> axismap(new AxismapModifier); + + for(std::map<XboxAxis, AxisFilterPtr>::const_iterator i = opts.calibration_map.begin(); + i != opts.calibration_map.end(); + ++i) + { + axismap->add_filter(i->first, i->second); + } + + modifier->push_back(axismap); + } + + if (opts.deadzone) + { + boost::shared_ptr<AxismapModifier> axismap(new AxismapModifier); + + XboxAxis axes[] = { XBOX_AXIS_X1, + XBOX_AXIS_Y1, + + XBOX_AXIS_X2, + XBOX_AXIS_Y2 }; + + for(size_t i = 0; i < sizeof(axes)/sizeof(XboxAxis); ++i) + { + axismap->add_filter(axes[i], + AxisFilterPtr(new DeadzoneAxisFilter(-opts.deadzone, + opts.deadzone, + true))); + } + + modifier->push_back(axismap); + } + + if (opts.deadzone_trigger) + { + boost::shared_ptr<AxismapModifier> axismap(new AxismapModifier); + + XboxAxis axes[] = { XBOX_AXIS_LT, + XBOX_AXIS_RT }; + + for(size_t i = 0; i < sizeof(axes)/sizeof(XboxAxis); ++i) + { + axismap->add_filter(axes[i], + AxisFilterPtr(new DeadzoneAxisFilter(-opts.deadzone_trigger, + opts.deadzone_trigger, + true))); + } + + modifier->push_back(axismap); + } + + if (opts.square_axis) + { + modifier->push_back(ModifierPtr(new SquareAxisModifier(XBOX_AXIS_X1, XBOX_AXIS_Y1))); + modifier->push_back(ModifierPtr(new SquareAxisModifier(XBOX_AXIS_X2, XBOX_AXIS_Y2))); + } + + if (!opts.sensitivity_map.empty()) + { + boost::shared_ptr<AxismapModifier> axismap(new AxismapModifier); + + for(std::map<XboxAxis, AxisFilterPtr>::const_iterator i = opts.sensitivity_map.begin(); + i != opts.sensitivity_map.end(); ++i) + { + axismap->add_filter(i->first, i->second); + } + + modifier->push_back(axismap); + } + + if (opts.four_way_restrictor) + { + modifier->push_back(ModifierPtr(new FourWayRestrictorModifier(XBOX_AXIS_X1, XBOX_AXIS_Y1))); + modifier->push_back(ModifierPtr(new FourWayRestrictorModifier(XBOX_AXIS_X2, XBOX_AXIS_Y2))); + } + + if (!opts.relative_axis_map.empty()) + { + boost::shared_ptr<AxismapModifier> axismap(new AxismapModifier); + + for(std::map<XboxAxis, AxisFilterPtr>::const_iterator i = opts.relative_axis_map.begin(); + i != opts.relative_axis_map.end(); ++i) + { + axismap->add_filter(i->first, i->second); + } + + modifier->push_back(axismap); + } + + if (opts.dpad_rotation) + { + modifier->push_back(ModifierPtr(new DpadRotationModifier(opts.dpad_rotation))); + } + + if (!opts.autofire_map.empty()) + { + boost::shared_ptr<ButtonmapModifier> buttonmap(new ButtonmapModifier); + + for(std::map<XboxButton, ButtonFilterPtr>::const_iterator i = opts.autofire_map.begin(); + i != opts.autofire_map.end(); ++i) + { + buttonmap->add_filter(i->first, i->second); + } + + modifier->push_back(buttonmap); + } + + // axismap, buttonmap comes last, as otherwise they would mess up the button and axis names + if (!opts.buttonmap->empty()) + { + modifier->push_back(opts.buttonmap); + } + + if (!opts.axismap->empty()) + { + modifier->push_back(opts.axismap); + } + + modifier->insert(modifier->end(), opts.modifier.begin(), opts.modifier.end()); +} + ControllerConfigSet::ControllerConfigSet() : m_config(), m_current_config(0) diff --git a/src/controller_config_set.hpp b/src/controller_config_set.hpp index c58a406..96cc11f 100644 --- a/src/controller_config_set.hpp +++ b/src/controller_config_set.hpp @@ -19,10 +19,26 @@ #ifndef HEADER_XBOXDRV_CONTROLLER_CONFIG_SET_HPP #define HEADER_XBOXDRV_CONTROLLER_CONFIG_SET_HPP +#include <boost/shared_ptr.hpp> + #include "controller_config.hpp" +#include "options.hpp" + +class Options; +class uInput; +class ControllerConfigSet; + +typedef boost::shared_ptr<ControllerConfigSet> ControllerConfigSetPtr; class ControllerConfigSet { +public: + /** Creates a ControllerConfigSet from the Options object and connects it to uInput */ + static ControllerConfigSetPtr create(uInput& uinput, const Options::ControllerConfigs& opts); + +private: + static void create_modifier(const ControllerOptions& options, std::vector<ModifierPtr>* modifier); + private: std::vector<ControllerConfigPtr> m_config; int m_current_config; diff --git a/src/default_message_processor.cpp b/src/default_message_processor.cpp index 423b526..2b2e100 100644 --- a/src/default_message_processor.cpp +++ b/src/default_message_processor.cpp @@ -22,186 +22,24 @@ #include "options.hpp" #include "uinput.hpp" -#include "modifier/dpad_rotation_modifier.hpp" -#include "modifier/four_way_restrictor_modifier.hpp" -#include "modifier/square_axis_modifier.hpp" - -DefaultMessageProcessor::DefaultMessageProcessor(uInput& uinput, const Options& opts) : +DefaultMessageProcessor::DefaultMessageProcessor(uInput& uinput, ControllerConfigSetPtr config, + const Options& opts) : m_uinput(uinput), - m_config(), + m_config(config), m_oldmsg(), m_config_toggle_button(opts.config_toggle_button) { memset(&m_oldmsg, 0, sizeof(m_oldmsg)); - - // create ControllerConfigs - for(Options::ControllerSlots::const_iterator controller = opts.controller_slots.begin(); - controller != opts.controller_slots.end(); ++controller) - { - for(Options::ControllerConfigs::const_iterator i = controller->second.begin(); - i != controller->second.end(); ++i) - { - const ControllerOptions& ctrl_opt = i->second; - - ControllerConfigPtr config(new ControllerConfig(uinput, ctrl_opt)); - create_modifier(ctrl_opt, &config->get_modifier()); - m_config.add_config(config); - -#ifdef FIXME - // introspection of the config - std::cout << "==[[ Active Modifier ]]==" << std::endl; - for(std::vector<ModifierPtr>::iterator mod = config->get_modifier().begin(); - mod != config->get_modifier().end(); - ++mod) - { - std::cout << (*mod)->str() << std::endl; - } -#endif - } - } - - - log_info << "UInput finish" << std::endl; - - // After all the ControllerConfig registered their events, finish up - // the device creation - uinput.finish(); } DefaultMessageProcessor::~DefaultMessageProcessor() { } -void -DefaultMessageProcessor::create_modifier(const ControllerOptions& opts, std::vector<ModifierPtr>* modifier) -{ - if (!opts.calibration_map.empty()) - { - boost::shared_ptr<AxismapModifier> axismap(new AxismapModifier); - - for(std::map<XboxAxis, AxisFilterPtr>::const_iterator i = opts.calibration_map.begin(); - i != opts.calibration_map.end(); - ++i) - { - axismap->add_filter(i->first, i->second); - } - - modifier->push_back(axismap); - } - - if (opts.deadzone) - { - boost::shared_ptr<AxismapModifier> axismap(new AxismapModifier); - - XboxAxis axes[] = { XBOX_AXIS_X1, - XBOX_AXIS_Y1, - - XBOX_AXIS_X2, - XBOX_AXIS_Y2 }; - - for(size_t i = 0; i < sizeof(axes)/sizeof(XboxAxis); ++i) - { - axismap->add_filter(axes[i], - AxisFilterPtr(new DeadzoneAxisFilter(-opts.deadzone, - opts.deadzone, - true))); - } - - modifier->push_back(axismap); - } - - if (opts.deadzone_trigger) - { - boost::shared_ptr<AxismapModifier> axismap(new AxismapModifier); - - XboxAxis axes[] = { XBOX_AXIS_LT, - XBOX_AXIS_RT }; - - for(size_t i = 0; i < sizeof(axes)/sizeof(XboxAxis); ++i) - { - axismap->add_filter(axes[i], - AxisFilterPtr(new DeadzoneAxisFilter(-opts.deadzone_trigger, - opts.deadzone_trigger, - true))); - } - - modifier->push_back(axismap); - } - - if (opts.square_axis) - { - modifier->push_back(ModifierPtr(new SquareAxisModifier(XBOX_AXIS_X1, XBOX_AXIS_Y1))); - modifier->push_back(ModifierPtr(new SquareAxisModifier(XBOX_AXIS_X2, XBOX_AXIS_Y2))); - } - - if (!opts.sensitivity_map.empty()) - { - boost::shared_ptr<AxismapModifier> axismap(new AxismapModifier); - - for(std::map<XboxAxis, AxisFilterPtr>::const_iterator i = opts.sensitivity_map.begin(); - i != opts.sensitivity_map.end(); ++i) - { - axismap->add_filter(i->first, i->second); - } - - modifier->push_back(axismap); - } - - if (opts.four_way_restrictor) - { - modifier->push_back(ModifierPtr(new FourWayRestrictorModifier(XBOX_AXIS_X1, XBOX_AXIS_Y1))); - modifier->push_back(ModifierPtr(new FourWayRestrictorModifier(XBOX_AXIS_X2, XBOX_AXIS_Y2))); - } - - if (!opts.relative_axis_map.empty()) - { - boost::shared_ptr<AxismapModifier> axismap(new AxismapModifier); - - for(std::map<XboxAxis, AxisFilterPtr>::const_iterator i = opts.relative_axis_map.begin(); - i != opts.relative_axis_map.end(); ++i) - { - axismap->add_filter(i->first, i->second); - } - - modifier->push_back(axismap); - } - - if (opts.dpad_rotation) - { - modifier->push_back(ModifierPtr(new DpadRotationModifier(opts.dpad_rotation))); - } - - if (!opts.autofire_map.empty()) - { - boost::shared_ptr<ButtonmapModifier> buttonmap(new ButtonmapModifier); - - for(std::map<XboxButton, ButtonFilterPtr>::const_iterator i = opts.autofire_map.begin(); - i != opts.autofire_map.end(); ++i) - { - buttonmap->add_filter(i->first, i->second); - } - - modifier->push_back(buttonmap); - } - - // axismap, buttonmap comes last, as otherwise they would mess up the button and axis names - if (!opts.buttonmap->empty()) - { - modifier->push_back(opts.buttonmap); - } - - if (!opts.axismap->empty()) - { - modifier->push_back(opts.axismap); - } - - modifier->insert(modifier->end(), opts.modifier.begin(), opts.modifier.end()); -} - void DefaultMessageProcessor::send(const XboxGenericMsg& msg_in, int msec_delta) { - if (!m_config.empty()) + if (!m_config->empty()) { XboxGenericMsg msg = msg_in; @@ -214,24 +52,24 @@ DefaultMessageProcessor::send(const XboxGenericMsg& msg_in, int msec_delta) if (cur && cur != last) { // reset old mapping to zero to not get stuck keys/axis - m_config.get_config()->get_uinput().reset_all_outputs(); + m_config->get_config()->get_uinput().reset_all_outputs(); // switch to the next input mapping - m_config.next_config(); + m_config->next_config(); log_info << "Next Config" << std::endl; } } // run the controller message through all modifier - for(std::vector<ModifierPtr>::iterator i = m_config.get_config()->get_modifier().begin(); - i != m_config.get_config()->get_modifier().end(); + for(std::vector<ModifierPtr>::iterator i = m_config->get_config()->get_modifier().begin(); + i != m_config->get_config()->get_modifier().end(); ++i) { (*i)->update(msec_delta, msg); } - m_config.get_config()->get_uinput().update(msec_delta); + m_config->get_config()->get_uinput().update(msec_delta); // send current Xbox state to uinput if (memcmp(&msg, &m_oldmsg, sizeof(XboxGenericMsg)) != 0) @@ -242,7 +80,7 @@ DefaultMessageProcessor::send(const XboxGenericMsg& msg_in, int msec_delta) // too m_oldmsg = msg; - m_config.get_config()->get_uinput().send(msg); + m_config->get_config()->get_uinput().send(msg); } } } diff --git a/src/default_message_processor.hpp b/src/default_message_processor.hpp index 7418b35..2decadb 100644 --- a/src/default_message_processor.hpp +++ b/src/default_message_processor.hpp @@ -32,20 +32,18 @@ class DefaultMessageProcessor : public MessageProcessor { private: uInput& m_uinput; - ControllerConfigSet m_config; + ControllerConfigSetPtr m_config; XboxGenericMsg m_oldmsg; /// last data send to uinput XboxButton m_config_toggle_button; public: - DefaultMessageProcessor(uInput& uinput, const Options& opts); + DefaultMessageProcessor(uInput& uinput, ControllerConfigSetPtr config, + const Options& opts); ~DefaultMessageProcessor(); void send(const XboxGenericMsg& msg, int msec_delta); -private: - void create_modifier(const ControllerOptions& options, std::vector<ModifierPtr>* modifier); - private: DefaultMessageProcessor(const DefaultMessageProcessor&); DefaultMessageProcessor& operator=(const DefaultMessageProcessor&); diff --git a/src/linux_uinput.cpp b/src/linux_uinput.cpp index acce93f..0a4f342 100644 --- a/src/linux_uinput.cpp +++ b/src/linux_uinput.cpp @@ -24,6 +24,8 @@ #include <errno.h> #include <fcntl.h> +#include "evdev_helper.hpp" +#include "log.hpp" #include "force_feedback_handler.hpp" LinuxUinput::LinuxUinput(DeviceType device_type, const std::string& name_, uint16_t vendor_, uint16_t product_) : @@ -42,6 +44,8 @@ LinuxUinput::LinuxUinput(DeviceType device_type, const std::string& name_, uint1 ff_callback(), needs_sync(true) { + log_info << name << " " << vendor << ":" << product << std::endl; + std::fill_n(abs_lst, ABS_CNT, false); std::fill_n(rel_lst, REL_CNT, false); std::fill_n(key_lst, KEY_CNT, false); @@ -93,7 +97,7 @@ LinuxUinput::~LinuxUinput() void LinuxUinput::add_abs(uint16_t code, int min, int max, int fuzz, int flat) { - // std::cout << "add_abs: " << abs2str(code) << " (" << min << ", " << max << ") " << name << std::endl; + log_info << "add_abs: " << abs2str(code) << " (" << min << ", " << max << ") " << name << std::endl; if (!abs_lst[code]) { @@ -117,7 +121,7 @@ LinuxUinput::add_abs(uint16_t code, int min, int max, int fuzz, int flat) void LinuxUinput::add_rel(uint16_t code) { - // std::cout << "add_rel: " << rel2str(code) << " " << name << std::endl; + log_info << "add_rel: " << rel2str(code) << " " << name << std::endl; if (!rel_lst[code]) { @@ -136,7 +140,7 @@ LinuxUinput::add_rel(uint16_t code) void LinuxUinput::add_key(uint16_t code) { - // std::cout << "add_key: " << btn2str(code) << " " << name << std::endl; + log_info << "add_key: " << key2str(code) << " " << name << std::endl; if (!key_lst[code]) { @@ -220,14 +224,26 @@ LinuxUinput::finish() user_dev.id.vendor = vendor; user_dev.id.product = product; + log_info << "'" << user_dev.name << "' " << user_dev.id.vendor << ":" << user_dev.id.product << std::endl; + if (ff_bit) user_dev.ff_effects_max = ff_handler->get_max_effects(); //std::cout << "Finalizing uinput: '" << user_dev.name << "'" << std::endl; - if (write(fd, &user_dev, sizeof(user_dev)) < 0) - throw std::runtime_error("uinput:finish: " + name + ": " + strerror(errno)); + { + int write_ret = write(fd, &user_dev, sizeof(user_dev)); + if (write_ret < 0) + { + throw std::runtime_error("uinput:finish: " + name + ": " + strerror(errno)); + } + else + { + log_info << "write return value: " << write_ret << std::endl; + } + } + log_info << "finish" << std::endl; if (ioctl(fd, UI_DEV_CREATE)) { std::ostringstream out; diff --git a/src/options.cpp b/src/options.cpp index a755acc..1655820 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -92,6 +92,20 @@ Options::get_controller_slot() return controller_slots[controller_slot]; } +const Options::ControllerConfigs& +Options::get_controller_slot() const +{ + ControllerSlots::const_iterator it = controller_slots.find(controller_slot); + if (it == controller_slots.end()) + { + assert(!"shouldn't happen"); + } + else + { + return it->second; + } +} + ControllerOptions& Options::get_controller_options() { diff --git a/src/options.hpp b/src/options.hpp index 7f40c03..f6221b8 100644 --- a/src/options.hpp +++ b/src/options.hpp @@ -146,6 +146,7 @@ public: Options(); ControllerConfigs& get_controller_slot(); + const ControllerConfigs& get_controller_slot() const; /** Returns the currently active configuration */ ControllerOptions& get_controller_options(); diff --git a/src/xbox360_controller.cpp b/src/xbox360_controller.cpp index a96a3bf..d2f9deb 100644 --- a/src/xbox360_controller.cpp +++ b/src/xbox360_controller.cpp @@ -42,7 +42,7 @@ Xbox360Controller::Xbox360Controller(libusb_device* dev_, m_headset() { find_endpoints(); - if (true) // FIXME + if (false) { std::cout << "EP(IN): " << endpoint_in << std::endl; std::cout << "EP(OUT): " << endpoint_out << std::endl; @@ -207,7 +207,7 @@ Xbox360Controller::read(XboxGenericMsg& msg, bool verbose, int timeout) else if (ret != LIBUSB_SUCCESS) { // Error std::ostringstream str; - str << "Xbox360Controller: USBError: " << ret << "\n" << usb_strerror(ret); + str << "Xbox360Controller: libusb_interrupt_transfer(): " << usb_strerror(ret); throw std::runtime_error(str.str()); } else if (len == 0) diff --git a/src/xboxdrv.cpp b/src/xboxdrv.cpp index b550221..81d83b3 100644 --- a/src/xboxdrv.cpp +++ b/src/xboxdrv.cpp @@ -463,7 +463,8 @@ Xboxdrv::run_main(const Options& opts) global_exit_xboxdrv = false; - std::auto_ptr<MessageProcessor> message_proc(new DefaultMessageProcessor(*uinput, opts)); + ControllerConfigSetPtr config_set = ControllerConfigSet::create(*uinput, opts.get_controller_slot()); + std::auto_ptr<MessageProcessor> message_proc(new DefaultMessageProcessor(*uinput, config_set, opts)); XboxdrvThread loop(message_proc, controller, opts); loop.controller_loop(opts); diff --git a/src/xboxdrv_daemon.cpp b/src/xboxdrv_daemon.cpp index 341587a..052ee5c 100644 --- a/src/xboxdrv_daemon.cpp +++ b/src/xboxdrv_daemon.cpp @@ -33,7 +33,7 @@ extern bool global_exit_xboxdrv; XboxdrvDaemon::XboxdrvDaemon() : m_udev(0), m_monitor(0), - m_threads() + m_controller_slots() { m_udev = udev_new(); @@ -49,9 +49,10 @@ XboxdrvDaemon::XboxdrvDaemon() : XboxdrvDaemon::~XboxdrvDaemon() { - for(Threads::iterator i = m_threads.begin(); i != m_threads.end(); ++i) + for(ControllerSlots::iterator i = m_controller_slots.begin(); i != m_controller_slots.end(); ++i) { - delete *i; + delete i->thread; + i->thread = 0; } udev_monitor_unref(m_monitor); @@ -61,13 +62,20 @@ XboxdrvDaemon::~XboxdrvDaemon() void XboxdrvDaemon::cleanup_threads() { - size_t num_threads = m_threads.size(); - m_threads.erase(std::remove_if(m_threads.begin(), m_threads.end(), - boost::bind(&XboxdrvThread::try_join_thread, _1)), - m_threads.end()); - if (num_threads != m_threads.size()) + int count = 0; + + for(ControllerSlots::iterator i = m_controller_slots.begin(); i != m_controller_slots.end(); ++i) { - log_info << "cleaned up " << (num_threads - m_threads.size()) << " thread(s)" << std::endl; + if (i->thread) + { + i->thread->try_join_thread(); + count += 1; + } + } + + if (count > 0) + { + log_info << "cleaned up " << count << " thread(s)" << std::endl; } } @@ -173,6 +181,20 @@ XboxdrvDaemon::run(const Options& opts) std::cout << "Starting without uinput" << std::endl; } + { // create controller slots + int slot_count = 0; + + for(Options::ControllerSlots::const_iterator controller = opts.controller_slots.begin(); + controller != opts.controller_slots.end(); ++controller) + { + log_info << "creating slot: " << slot_count << std::endl; + m_controller_slots.push_back(ControllerSlot(ControllerConfigSet::create(*uinput, controller->second))); + slot_count += 1; + } + + log_info << "created " << m_controller_slots.size() << " controller slots" << std::endl; + } + // Setup udev monitor and enumerate m_monitor = udev_monitor_new_from_netlink(m_udev, "udev"); udev_monitor_filter_add_match_subsystem_devtype(m_monitor, "usb", "usb_device"); @@ -312,7 +334,8 @@ XboxdrvDaemon::print_info(struct udev_device* device) } void -XboxdrvDaemon::launch_xboxdrv(uInput* uinput, const XPadDevice& dev_type, const Options& opts, uint8_t busnum, uint8_t devnum) +XboxdrvDaemon::launch_xboxdrv(uInput* uinput, const XPadDevice& dev_type, const Options& opts, + uint8_t busnum, uint8_t devnum) { std::cout << "[XboxdrvDaemon] launching " << boost::format("%03d:%03d") % static_cast<int>(busnum) @@ -328,11 +351,20 @@ XboxdrvDaemon::launch_xboxdrv(uInput* uinput, const XPadDevice& dev_type, const } else { - std::auto_ptr<XboxGenericController> controller = XboxControllerFactory::create(dev_type, dev, opts); - std::auto_ptr<MessageProcessor> message_proc(new DefaultMessageProcessor(*uinput, opts)); - std::auto_ptr<XboxdrvThread> thread(new XboxdrvThread(message_proc, controller, opts)); - thread->start_thread(opts); - m_threads.push_back(thread.release()); + for(ControllerSlots::iterator i = m_controller_slots.begin(); i != m_controller_slots.end(); ++i) + { + if (i->thread == 0) + { + log_info << "found a free slot: " << (i - m_controller_slots.begin()) << std::endl; + + std::auto_ptr<XboxGenericController> controller = XboxControllerFactory::create(dev_type, dev, opts); + std::auto_ptr<MessageProcessor> message_proc(new DefaultMessageProcessor(*uinput, i->config, opts)); + std::auto_ptr<XboxdrvThread> thread(new XboxdrvThread(message_proc, controller, opts)); + thread->start_thread(opts); + i->thread = thread.release(); + break; + } + } } } diff --git a/src/xboxdrv_daemon.hpp b/src/xboxdrv_daemon.hpp index 04a3c5f..d08e0af 100644 --- a/src/xboxdrv_daemon.hpp +++ b/src/xboxdrv_daemon.hpp @@ -23,6 +23,8 @@ #include <stdint.h> #include <vector> +#include "controller_config_set.hpp" + class Options; class uInput; struct XPadDevice; @@ -33,8 +35,41 @@ class XboxdrvDaemon private: struct udev* m_udev; struct udev_monitor* m_monitor; - typedef std::vector<XboxdrvThread*> Threads; - Threads m_threads; + + struct ControllerSlot + { + ControllerConfigSetPtr config; + XboxdrvThread* thread; + + ControllerSlot() : + config(), + thread(0) + {} + + ControllerSlot(ControllerConfigSetPtr config_, + XboxdrvThread* thread_ = 0) : + config(config_), + thread(thread_) + {} + + ControllerSlot(const ControllerSlot& rhs) : + config(rhs.config), + thread(rhs.thread) + {} + + ControllerSlot& operator=(const ControllerSlot& rhs) + { + if (&rhs != this) + { + config = rhs.config; + thread = rhs.thread; + } + return *this; + } + }; + + typedef std::vector<ControllerSlot> ControllerSlots; + ControllerSlots m_controller_slots; public: XboxdrvDaemon(); diff --git a/src/xboxdrv_thread.hpp b/src/xboxdrv_thread.hpp index 2cae2f1..34d450e 100644 --- a/src/xboxdrv_thread.hpp +++ b/src/xboxdrv_thread.hpp @@ -30,6 +30,9 @@ class Options; class XboxGenericController; class MessageProcessor; +/** XboxdrvThread handles a single XboxGenericController controller + (optionally in a separate thread), reads it messages and passes it + to the MessageProcessor */ class XboxdrvThread // FIXME: find a better name, XboxdrvControllerLoop?! { private: