From 7ec53fa23a476eaf71d71cf30a77767c4bc4b226 Mon Sep 17 00:00:00 2001 From: Ingo Ruhnke <grumbel@gmx.de> Date: Tue, 25 Jan 2011 23:34:18 +0100 Subject: [PATCH] Splitted Options related stuff into separate files --- src/command_line_options.cpp | 12 ++++ src/controller_config.cpp | 1 + src/controller_config_set.cpp | 7 ++- src/controller_config_set.hpp | 2 +- src/controller_match_rule.cpp | 50 ++++++++++++++++ src/controller_match_rule.hpp | 58 ++++++++++++++++++ src/controller_options.cpp | 39 ++++++++++++ src/controller_options.hpp | 56 +++++++++++++++++ src/controller_slot_options.cpp | 69 +++++++++++++++++++++ src/controller_slot_options.hpp | 51 ++++++++++++++++ src/helper.cpp | 21 +++++++ src/helper.hpp | 2 + src/options.cpp | 103 ++++++++++++++++++++++++-------- src/options.hpp | 40 +++---------- src/xboxdrv_daemon.cpp | 3 +- src/xboxdrv_daemon.hpp | 7 +++ 16 files changed, 459 insertions(+), 62 deletions(-) create mode 100644 src/controller_match_rule.cpp create mode 100644 src/controller_match_rule.hpp create mode 100644 src/controller_options.cpp create mode 100644 src/controller_options.hpp create mode 100644 src/controller_slot_options.cpp create mode 100644 src/controller_slot_options.hpp diff --git a/src/command_line_options.cpp b/src/command_line_options.cpp index 4a9ef6c..bb97cd9 100644 --- a/src/command_line_options.cpp +++ b/src/command_line_options.cpp @@ -106,6 +106,8 @@ enum { OPTION_DETACH_KERNEL_DRIVER, OPTION_DAEMON_DETACH, OPTION_DAEMON_PID_FILE, + OPTION_DAEMON_MATCH, + OPTION_DAEMON_MATCH_GROUP, OPTION_HELP_DEVICES, OPTION_LIST_ALL, OPTION_LIST_ABS, @@ -167,6 +169,8 @@ CommandLineParser::init_argp() .add_option(OPTION_DAEMON_PID_FILE, 0, "pid-file", "FILE", "Write daemon pid to FILE") .add_option(OPTION_DAEMON_ON_CONNECT, 0, "on-connect", "FILE", "Launch EXE when a new controller is connected") .add_option(OPTION_DAEMON_ON_DISCONNECT, 0, "on-disconnect", "FILE", "Launch EXE when a controller is disconnected") + .add_option(OPTION_DAEMON_MATCH, 0, "match", "RULES", "Only allow controllers that match any of RULES") + //FIXME: .add_option(OPTION_DAEMON_MATCH_GROUP, 0, "match-group", "RULES", "Only allow controllers that match all of RULES") .add_newline() .add_text("Device Options: ") @@ -400,6 +404,14 @@ CommandLineParser::parse_args(int argc, char** argv, Options* options) opts.mode = Options::RUN_DAEMON; break; + case OPTION_DAEMON_MATCH: + opts.set_match(opt.argument); + break; + + case OPTION_DAEMON_MATCH_GROUP: + opts.set_match_group(opt.argument); + break; + case OPTION_WRITE_CONFIG: { opts.instant_exit = true; diff --git a/src/controller_config.cpp b/src/controller_config.cpp index aff158c..a92f428 100644 --- a/src/controller_config.cpp +++ b/src/controller_config.cpp @@ -18,6 +18,7 @@ #include "controller_config.hpp" +#include "controller_options.hpp" #include "options.hpp" ControllerConfig::ControllerConfig(UInput& uinput, int slot, bool extra_devices, const ControllerOptions& opts) : diff --git a/src/controller_config_set.cpp b/src/controller_config_set.cpp index c8fd81f..b53122c 100644 --- a/src/controller_config_set.cpp +++ b/src/controller_config_set.cpp @@ -19,18 +19,19 @@ #include "controller_config_set.hpp" #include "log.hpp" +#include "controller_options.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, int slot, bool extra_devices, const Options::ControllerConfigs& opts) +ControllerConfigSet::create(UInput& uinput, int slot, bool extra_devices, const ControllerSlotOptions& opts) { ControllerConfigSetPtr m_config(new ControllerConfigSet); - for(Options::ControllerConfigs::const_iterator i = opts.begin(); - i != opts.end(); ++i) + for(ControllerSlotOptions::Options::const_iterator i = opts.get_options().begin(); + i != opts.get_options().end(); ++i) { const ControllerOptions& ctrl_opt = i->second; diff --git a/src/controller_config_set.hpp b/src/controller_config_set.hpp index 1d47e3e..f813292 100644 --- a/src/controller_config_set.hpp +++ b/src/controller_config_set.hpp @@ -33,7 +33,7 @@ class ControllerConfigSet public: /** Creates a ControllerConfigSet from the Options object and connects it to UInput */ static ControllerConfigSetPtr create(UInput& uinput, int slot, bool extra_devices, - const Options::ControllerConfigs& opts); + const ControllerSlotOptions& opts); private: static void create_modifier(const ControllerOptions& options, std::vector<ModifierPtr>* modifier); diff --git a/src/controller_match_rule.cpp b/src/controller_match_rule.cpp new file mode 100644 index 0000000..aceb45d --- /dev/null +++ b/src/controller_match_rule.cpp @@ -0,0 +1,50 @@ +/* +** Xbox360 USB Gamepad Userspace Driver +** Copyright (C) 2011 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 "controller_match_rule.hpp" + +ControllerMatchRule +ControllerMatchRule::match_usb_id(int vendor, int product) +{ + ControllerMatchRule rule; + rule.m_type = kMatchUSBId; + rule.m_vendor = vendor; + rule.m_product = product; + return rule; +} + +ControllerMatchRule +ControllerMatchRule::match_usb_path(int bus, int dev) +{ + ControllerMatchRule rule; + rule.m_type = kMatchUSBPath; + rule.m_bus = bus; + rule.m_dev = dev; + return rule; +} + +ControllerMatchRule +ControllerMatchRule::match_evdev_path(const std::string& path) +{ + ControllerMatchRule rule; + rule.m_type = kMatchEvdevPath; + rule.m_path = path; + return rule; +} + +/* EOF */ diff --git a/src/controller_match_rule.hpp b/src/controller_match_rule.hpp new file mode 100644 index 0000000..c39278b --- /dev/null +++ b/src/controller_match_rule.hpp @@ -0,0 +1,58 @@ +/* +** Xbox360 USB Gamepad Userspace Driver +** Copyright (C) 2011 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_CONTROLLER_MATCH_RULE_HPP +#define HEADER_XBOXDRV_CONTROLLER_MATCH_RULE_HPP + +#include <string> + +class ControllerMatchRule +{ +public: + enum { + kMatchEverything, + kMatchUSBId, + kMatchUSBPath, + kMatchEvdevPath + } m_type; + + int m_bus; + int m_dev; + + int m_vendor; + int m_product; + + std::string m_path; + + ControllerMatchRule() : + m_type(kMatchEverything), + m_bus(), + m_dev(), + m_vendor(), + m_product(), + m_path() + {} + + static ControllerMatchRule match_usb_id(int vendor, int product); + static ControllerMatchRule match_usb_path(int bus, int dev); + static ControllerMatchRule match_evdev_path(const std::string& path); +}; + +#endif + +/* EOF */ diff --git a/src/controller_options.cpp b/src/controller_options.cpp new file mode 100644 index 0000000..85529ec --- /dev/null +++ b/src/controller_options.cpp @@ -0,0 +1,39 @@ +/* +** Xbox360 USB Gamepad Userspace Driver +** Copyright (C) 2011 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 "controller_options.hpp" + +ControllerOptions::ControllerOptions() : + uinput(), + modifier(), + buttonmap(new ButtonmapModifier), + axismap(new AxismapModifier), + deadzone(0), + deadzone_trigger(0), + square_axis(false), + four_way_restrictor(0), + dpad_rotation(0), + + calibration_map(), + sensitivity_map(), + relative_axis_map(), + autofire_map() +{ +} + +/* EOF */ diff --git a/src/controller_options.hpp b/src/controller_options.hpp new file mode 100644 index 0000000..ab8910d --- /dev/null +++ b/src/controller_options.hpp @@ -0,0 +1,56 @@ +/* +** Xbox360 USB Gamepad Userspace Driver +** Copyright (C) 2011 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_CONTROLLER_OPTIONS_HPP +#define HEADER_XBOXDRV_CONTROLLER_OPTIONS_HPP + +#include <vector> +#include <map> + +#include "uinput_options.hpp" + +#include "modifier/axismap_modifier.hpp" +#include "modifier/buttonmap_modifier.hpp" + +class ControllerOptions +{ +public: + ControllerOptions(); + + UInputOptions uinput; + std::vector<ModifierPtr> modifier; + + // everything below gets later converted into modifier + boost::shared_ptr<ButtonmapModifier> buttonmap; + boost::shared_ptr<AxismapModifier> axismap; + + int deadzone; + int deadzone_trigger; + bool square_axis; + bool four_way_restrictor; + int dpad_rotation; + + std::map<XboxAxis, AxisFilterPtr> calibration_map; + std::map<XboxAxis, AxisFilterPtr> sensitivity_map; + std::map<XboxAxis, AxisFilterPtr> relative_axis_map; + std::map<XboxButton, ButtonFilterPtr> autofire_map; +}; + +#endif + +/* EOF */ diff --git a/src/controller_slot_options.cpp b/src/controller_slot_options.cpp new file mode 100644 index 0000000..fff419c --- /dev/null +++ b/src/controller_slot_options.cpp @@ -0,0 +1,69 @@ +/* +** Xbox360 USB Gamepad Userspace Driver +** Copyright (C) 2011 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 "controller_slot_options.hpp" + +#include <stdexcept> + +#include "raise_exception.hpp" + +ControllerSlotOptions::ControllerSlotOptions() : + m_options(), + m_match_rules() +{ +} + +ControllerOptions& +ControllerSlotOptions::get_options(int num) +{ + return m_options[num]; +} + +const ControllerOptions& +ControllerSlotOptions::get_options(int num) const +{ + std::map<int, ControllerOptions>::const_iterator it = m_options.find(num); + if (it == m_options.end()) + { + raise_exception(std::runtime_error, "illegal option: " << num); + } + else + { + return it->second; + } +} + +void +ControllerSlotOptions::add_match_rule(const ControllerMatchRule& rule) +{ + m_match_rules.push_back(rule); +} + +const std::vector<ControllerMatchRule>& +ControllerSlotOptions::get_match_rules() const +{ + return m_match_rules; +} + +const std::map<int, ControllerOptions>& +ControllerSlotOptions::get_options() const +{ + return m_options; +} + +/* EOF */ diff --git a/src/controller_slot_options.hpp b/src/controller_slot_options.hpp new file mode 100644 index 0000000..1e848f6 --- /dev/null +++ b/src/controller_slot_options.hpp @@ -0,0 +1,51 @@ +/* +** Xbox360 USB Gamepad Userspace Driver +** Copyright (C) 2011 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_CONTROLLER_SLOT_OPTIONS_HPP +#define HEADER_XBOXDRV_CONTROLLER_SLOT_OPTIONS_HPP + +#include <map> +#include <vector> + +#include "controller_options.hpp" +#include "controller_match_rule.hpp" + +class ControllerSlotOptions +{ +public: + typedef std::map<int, ControllerOptions> Options; + +public: + ControllerSlotOptions(); + + void add_match_rule(const ControllerMatchRule& rule); + + ControllerOptions& get_options(int num); + const ControllerOptions& get_options(int num) const; + + const std::vector<ControllerMatchRule>& get_match_rules() const; + const std::map<int, ControllerOptions>& get_options() const; + +private: + std::map<int, ControllerOptions> m_options; + std::vector<ControllerMatchRule> m_match_rules; +}; + +#endif + +/* EOF */ diff --git a/src/helper.cpp b/src/helper.cpp index 9f9e07f..d43d103 100644 --- a/src/helper.cpp +++ b/src/helper.cpp @@ -22,8 +22,29 @@ #include <boost/format.hpp> #include <boost/tokenizer.hpp> #include <boost/lexical_cast.hpp> +#include <stdio.h> #include <sys/time.h> #include <sys/ioctl.h> +#include <stdexcept> + +#include "raise_exception.hpp" + +int hexstr2int(const std::string& str) +{ + unsigned int value = 0; + if (sscanf(str.c_str(), "%x", &value) == 1) + { + return value; + } + else if (sscanf(str.c_str(), "0x%x", &value) == 1) + { + return value; + } + else + { + raise_exception(std::runtime_error, "couldn't convert '" << str << "' to int"); + } +} std::string raw2str(uint8_t* data, int len) { diff --git a/src/helper.hpp b/src/helper.hpp index 89c0516..19c610f 100644 --- a/src/helper.hpp +++ b/src/helper.hpp @@ -21,6 +21,8 @@ #include <boost/function.hpp> +int hexstr2int(const std::string& str); + std::string raw2str(uint8_t* buffer, int len); std::string to_lower(const std::string &str); bool is_number(const std::string& str); diff --git a/src/options.cpp b/src/options.cpp index 8e1e84f..e4008f8 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -18,26 +18,14 @@ #include "options.hpp" +#include <boost/tokenizer.hpp> +#include <boost/bind.hpp> + +#include "helper.hpp" +#include "raise_exception.hpp" + Options* g_options; -ControllerOptions::ControllerOptions() : - uinput(), - modifier(), - buttonmap(new ButtonmapModifier), - axismap(new AxismapModifier), - deadzone(0), - deadzone_trigger(0), - square_axis(false), - four_way_restrictor(0), - dpad_rotation(0), - - calibration_map(), - sensitivity_map(), - relative_axis_map(), - autofire_map() -{ -} - Options::Options() : mode(RUN_DEFAULT), verbose(false), @@ -84,16 +72,16 @@ Options::Options() : extra_devices(true) { // create the entry if not already available - controller_slots[controller_slot][config_slot]; + controller_slots[controller_slot].get_options(config_slot); } -Options::ControllerConfigs& +ControllerSlotOptions& Options::get_controller_slot() { return controller_slots[controller_slot]; } -const Options::ControllerConfigs& +const ControllerSlotOptions& Options::get_controller_slot() const { ControllerSlots::const_iterator it = controller_slots.find(controller_slot); @@ -110,7 +98,7 @@ Options::get_controller_slot() const ControllerOptions& Options::get_controller_options() { - return controller_slots[controller_slot][config_slot]; + return controller_slots[controller_slot].get_options(config_slot); } const ControllerOptions& @@ -123,8 +111,8 @@ Options::get_controller_options() const } else { - ControllerConfigs::const_iterator cfg = it->second.find(config_slot); - if (cfg == it->second.end()) + ControllerSlotOptions::Options::const_iterator cfg = it->second.get_options().find(config_slot); + if (cfg == it->second.get_options().end()) { assert(!"shouldn't happen either"); } @@ -142,7 +130,7 @@ Options::next_controller() config_slot = 0; // create the entry if not already available - controller_slots[controller_slot][config_slot]; + controller_slots[controller_slot].get_options(config_slot); } void @@ -157,7 +145,7 @@ Options::next_config() } // create the entry if not already available - controller_slots[controller_slot][config_slot]; + controller_slots[controller_slot].get_options(config_slot); } void @@ -211,4 +199,67 @@ Options::set_mimic_xpad() get_controller_options().uinput.mimic_xpad(); } +void +Options::add_match(const std::string& lhs, const std::string& rhs) +{ + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + tokenizer tokens(rhs, boost::char_separator<char>(":", "", boost::keep_empty_tokens)); + std::vector<std::string> args(tokens.begin(), tokens.end()); + + if (lhs == "usbid") + { + if (args.size() != 2) + { + raise_exception(std::runtime_error, "usbid requires VENDOR:PRODUCT argument"); + } + else + { + int vendor = hexstr2int(args[0]); + int product = hexstr2int(args[1]); + get_controller_slot().add_match_rule(ControllerMatchRule::match_usb_id(vendor, product)); + } + } + else if (lhs == "usbpath") + { + if (args.size() != 2) + { + raise_exception(std::runtime_error, "usbpath requires BUS:DEV argument"); + } + else + { + int bus = boost::lexical_cast<int>(args[0]); + int dev = boost::lexical_cast<int>(args[1]); + get_controller_slot().add_match_rule(ControllerMatchRule::match_usb_path(bus, dev)); + } + } + else if (lhs == "evdev") + { + if (args.size() != 1) + { + raise_exception(std::runtime_error, "evdev rule requires PATH argument"); + } + else + { + get_controller_slot().add_match_rule(ControllerMatchRule::match_evdev_path(args[0])); + } + } + else + { + raise_exception(std::runtime_error, "'" << lhs << "' not a valid match rule name"); + } +} + +void +Options::set_match(const std::string& str) +{ + process_name_value_string(str, boost::bind(&Options::add_match, this, _1, _2)); +} + +void +Options::set_match_group(const std::string& str) +{ + // FIXME: not implied + assert(!"not implemented"); +} + /* EOF */ diff --git a/src/options.hpp b/src/options.hpp index 4d96555..a1d25dd 100644 --- a/src/options.hpp +++ b/src/options.hpp @@ -23,37 +23,12 @@ #include <map> #include <vector> +#include "controller_options.hpp" +#include "controller_slot_options.hpp" #include "evdev_absmap.hpp" #include "uinput_options.hpp" #include "xpad_device.hpp" -#include "modifier/axismap_modifier.hpp" -#include "modifier/buttonmap_modifier.hpp" - -class ControllerOptions -{ -public: - ControllerOptions(); - - UInputOptions uinput; - std::vector<ModifierPtr> modifier; - - // everything below gets later converted into modifier - boost::shared_ptr<ButtonmapModifier> buttonmap; - boost::shared_ptr<AxismapModifier> axismap; - - int deadzone; - int deadzone_trigger; - bool square_axis; - bool four_way_restrictor; - int dpad_rotation; - - std::map<XboxAxis, AxisFilterPtr> calibration_map; - std::map<XboxAxis, AxisFilterPtr> sensitivity_map; - std::map<XboxAxis, AxisFilterPtr> relative_axis_map; - std::map<XboxButton, ButtonFilterPtr> autofire_map; -}; - class Options { public: @@ -111,8 +86,7 @@ public: std::map<int, XboxButton> evdev_keymap; // controller options - typedef std::map<int, ControllerOptions> ControllerConfigs; - typedef std::map<int, ControllerConfigs> ControllerSlots; + typedef std::map<int, ControllerSlotOptions> ControllerSlots; ControllerSlots controller_slots; // chatpad options @@ -146,8 +120,8 @@ public: public: Options(); - ControllerConfigs& get_controller_slot(); - const ControllerConfigs& get_controller_slot() const; + ControllerSlotOptions& get_controller_slot(); + const ControllerSlotOptions& get_controller_slot() const; /** Returns the currently active configuration */ ControllerOptions& get_controller_options(); @@ -165,6 +139,10 @@ public: void set_dpad_only(); void set_force_feedback(); void set_mimic_xpad(); + + void add_match(const std::string& lhs, const std::string& rhs); + void set_match(const std::string& str); + void set_match_group(const std::string& str); }; extern Options* g_options; diff --git a/src/xboxdrv_daemon.cpp b/src/xboxdrv_daemon.cpp index b76b922..b9a0dc9 100644 --- a/src/xboxdrv_daemon.cpp +++ b/src/xboxdrv_daemon.cpp @@ -214,7 +214,8 @@ XboxdrvDaemon::run_real(const Options& opts) log_info << "creating slot: " << slot_count << std::endl; m_controller_slots.push_back(ControllerSlot(ControllerConfigSet::create(*uinput, slot_count, opts.extra_devices, - controller->second))); + controller->second), + controller->second.get_match_rules())); slot_count += 1; } diff --git a/src/xboxdrv_daemon.hpp b/src/xboxdrv_daemon.hpp index 8f24bed..21c666e 100644 --- a/src/xboxdrv_daemon.hpp +++ b/src/xboxdrv_daemon.hpp @@ -24,6 +24,7 @@ #include <vector> #include "controller_config_set.hpp" +#include "controller_match_rule.hpp" class Options; class UInput; @@ -39,21 +40,26 @@ private: struct ControllerSlot { ControllerConfigSetPtr config; + std::vector<ControllerMatchRule> match; XboxdrvThread* thread; ControllerSlot() : config(), + match(), thread(0) {} ControllerSlot(ControllerConfigSetPtr config_, + std::vector<ControllerMatchRule> match_, XboxdrvThread* thread_ = 0) : config(config_), + match(match_), thread(thread_) {} ControllerSlot(const ControllerSlot& rhs) : config(rhs.config), + match(rhs.match), thread(rhs.thread) {} @@ -62,6 +68,7 @@ private: if (&rhs != this) { config = rhs.config; + match = rhs.match; thread = rhs.thread; } return *this;