Restructured how ControllerMatchRule's work, implemented --match-group
This commit is contained in:
parent
dd02607153
commit
e92a50979f
8 changed files with 217 additions and 149 deletions
|
@ -228,7 +228,7 @@ CommandLineParser::init_argp()
|
|||
.add_option(OPTION_CONTROLLER_SLOT, 0, "controller-slot", "N", "Use controller slot N")
|
||||
.add_option(OPTION_NEXT_CONTROLLER, 0, "next-controller", "", "Create a new controller entry")
|
||||
.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_option(OPTION_DAEMON_MATCH_GROUP, 0, "match-group", "RULES", "Only allow controllers that match all of RULES")
|
||||
.add_newline()
|
||||
|
||||
.add_text("Config Slot Options: ")
|
||||
|
|
|
@ -19,12 +19,80 @@
|
|||
#include "controller_match_rule.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
#include <boost/tokenizer.hpp>
|
||||
|
||||
#include "raise_exception.hpp"
|
||||
|
||||
class ControllerMatchRuleProperty : public ControllerMatchRule
|
||||
{
|
||||
private:
|
||||
std::string m_name;
|
||||
std::string m_value;
|
||||
|
||||
public:
|
||||
ControllerMatchRuleProperty(const std::string& name,
|
||||
const std::string& value) :
|
||||
m_name(name),
|
||||
m_value(value)
|
||||
{}
|
||||
|
||||
bool match(udev_device* device) const
|
||||
{
|
||||
const char* str = udev_device_get_property_value(device, m_name.c_str());
|
||||
|
||||
log_debug("matching property '" << m_name << "' with value '" << (str?str:"(null)") <<
|
||||
"' against '" << m_value);
|
||||
|
||||
if (!str)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (m_value == str);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ControllerMatchRuleGroup::ControllerMatchRuleGroup() :
|
||||
m_rules()
|
||||
{}
|
||||
|
||||
void
|
||||
ControllerMatchRuleGroup::add_rule(ControllerMatchRulePtr rule)
|
||||
{
|
||||
m_rules.push_back(rule);
|
||||
}
|
||||
|
||||
void
|
||||
ControllerMatchRuleGroup::add_rule_from_string(const std::string& lhs, const std::string& rhs)
|
||||
{
|
||||
m_rules.push_back(ControllerMatchRule::from_string(lhs, rhs));
|
||||
}
|
||||
|
||||
bool
|
||||
ControllerMatchRule::match(int vendor, int product,
|
||||
int bus, int dev,
|
||||
const char* serial) const
|
||||
ControllerMatchRuleGroup::match(udev_device* device) const
|
||||
{
|
||||
log_debug("matching group rule");
|
||||
for(Rules::const_iterator i = m_rules.begin(); i != m_rules.end(); ++i)
|
||||
{
|
||||
if (!(*i)->match(device))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ControllerMatchRule::match(udev_device* device) const
|
||||
{
|
||||
assert(!"implement me");
|
||||
return false;
|
||||
#if 0
|
||||
const char* serial = udev_device_get_property_value(device, "ID_SERIAL_SHORT");
|
||||
|
||||
|
||||
switch(m_type)
|
||||
{
|
||||
case kMatchEverything:
|
||||
|
@ -47,44 +115,108 @@ ControllerMatchRule::match(int vendor, int product,
|
|||
assert(!"never reached");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ControllerMatchRule
|
||||
ControllerMatchRule::create_usb_id(int vendor, int product)
|
||||
|
||||
ControllerMatchRulePtr
|
||||
ControllerMatchRule::from_string(const std::string& lhs,
|
||||
const std::string& rhs)
|
||||
{
|
||||
ControllerMatchRule rule;
|
||||
rule.m_type = kMatchUSBId;
|
||||
rule.m_vendor = vendor;
|
||||
rule.m_product = product;
|
||||
return rule;
|
||||
}
|
||||
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());
|
||||
|
||||
ControllerMatchRule
|
||||
ControllerMatchRule::create_usb_path(int bus, int dev)
|
||||
{
|
||||
ControllerMatchRule rule;
|
||||
rule.m_type = kMatchUSBPath;
|
||||
rule.m_bus = bus;
|
||||
rule.m_dev = dev;
|
||||
return rule;
|
||||
if (lhs == "usbid")
|
||||
{
|
||||
if (args.size() != 2)
|
||||
{
|
||||
raise_exception(std::runtime_error, "usbid requires VENDOR:PRODUCT argument");
|
||||
}
|
||||
else
|
||||
{
|
||||
boost::shared_ptr<ControllerMatchRuleGroup> group(new ControllerMatchRuleGroup);
|
||||
|
||||
group->add_rule(ControllerMatchRulePtr(new ControllerMatchRuleProperty("ID_VENDOR_ID", args[0])));
|
||||
group->add_rule(ControllerMatchRulePtr(new ControllerMatchRuleProperty("ID_MODEL_ID", args[1])));
|
||||
|
||||
return group;
|
||||
}
|
||||
}
|
||||
else if (lhs == "vendor")
|
||||
{
|
||||
if (args.size() != 1)
|
||||
{
|
||||
raise_exception(std::runtime_error, "vendor requires an argument");
|
||||
}
|
||||
else
|
||||
{
|
||||
return ControllerMatchRulePtr(new ControllerMatchRuleProperty("ID_VENDOR_ID", args[0]));
|
||||
}
|
||||
}
|
||||
else if (lhs == "property")
|
||||
{
|
||||
if (args.size() != 1)
|
||||
{
|
||||
raise_exception(std::runtime_error, "property two arguments");
|
||||
}
|
||||
else
|
||||
{
|
||||
return ControllerMatchRulePtr(new ControllerMatchRuleProperty(args[0], args[1]));
|
||||
}
|
||||
}
|
||||
else if (lhs == "product")
|
||||
{
|
||||
if (args.size() != 1)
|
||||
{
|
||||
raise_exception(std::runtime_error, "product requires an argument");
|
||||
}
|
||||
else
|
||||
{
|
||||
return ControllerMatchRulePtr(new ControllerMatchRuleProperty("ID_MODEL_ID", args[0]));
|
||||
}
|
||||
}
|
||||
else if (lhs == "usbpath")
|
||||
{
|
||||
if (args.size() != 2)
|
||||
{
|
||||
raise_exception(std::runtime_error, "usbpath requires BUS:DEV argument");
|
||||
}
|
||||
else
|
||||
{
|
||||
boost::shared_ptr<ControllerMatchRuleGroup> group(new ControllerMatchRuleGroup);
|
||||
|
||||
group->add_rule(ControllerMatchRulePtr(new ControllerMatchRuleProperty("BUSNUM", args[0])));
|
||||
group->add_rule(ControllerMatchRulePtr(new ControllerMatchRuleProperty("DEVNUM", args[1])));
|
||||
|
||||
return group;
|
||||
}
|
||||
}
|
||||
else if (lhs == "usbserial")
|
||||
{
|
||||
if (args.size() != 1)
|
||||
{
|
||||
raise_exception(std::runtime_error, "usbserial rule requires SERIAL argument");
|
||||
}
|
||||
else
|
||||
{
|
||||
return ControllerMatchRulePtr(new ControllerMatchRuleProperty("ID_SERIAL_SHORT", args[0]));
|
||||
}
|
||||
}
|
||||
else if (lhs == "evdev")
|
||||
{
|
||||
if (args.size() != 1)
|
||||
{
|
||||
raise_exception(std::runtime_error, "evdev rule requires PATH argument");
|
||||
}
|
||||
else
|
||||
{
|
||||
raise_exception(std::runtime_error, "evdev rule not yet implemented");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
raise_exception(std::runtime_error, "'" << lhs << "' not a valid match rule name");
|
||||
}
|
||||
}
|
||||
|
||||
ControllerMatchRule
|
||||
ControllerMatchRule::create_usb_serial(const std::string& serial)
|
||||
{
|
||||
ControllerMatchRule rule;
|
||||
rule.m_type = kMatchUSBSerial;
|
||||
rule.m_serial = serial;
|
||||
return rule;
|
||||
}
|
||||
|
||||
ControllerMatchRule
|
||||
ControllerMatchRule::create_evdev_path(const std::string& path)
|
||||
{
|
||||
ControllerMatchRule rule;
|
||||
rule.m_type = kMatchEvdevPath;
|
||||
rule.m_path = path;
|
||||
return rule;
|
||||
}
|
||||
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -19,49 +19,42 @@
|
|||
#ifndef HEADER_XBOXDRV_CONTROLLER_MATCH_RULE_HPP
|
||||
#define HEADER_XBOXDRV_CONTROLLER_MATCH_RULE_HPP
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <libudev.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct udev_device;
|
||||
class ControllerMatchRule;
|
||||
typedef boost::shared_ptr<ControllerMatchRule> ControllerMatchRulePtr;
|
||||
|
||||
class ControllerMatchRule
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
kMatchEverything,
|
||||
kMatchUSBId,
|
||||
kMatchUSBPath,
|
||||
kMatchUSBSerial,
|
||||
kMatchEvdevPath
|
||||
} m_type;
|
||||
static ControllerMatchRulePtr from_string(const std::string& lhs,
|
||||
const std::string& rhs);
|
||||
|
||||
int m_bus;
|
||||
int m_dev;
|
||||
|
||||
int m_vendor;
|
||||
int m_product;
|
||||
public:
|
||||
ControllerMatchRule() {}
|
||||
virtual ~ControllerMatchRule() {}
|
||||
|
||||
std::string m_path;
|
||||
|
||||
std::string m_serial;
|
||||
|
||||
ControllerMatchRule() :
|
||||
m_type(kMatchEverything),
|
||||
m_bus(),
|
||||
m_dev(),
|
||||
m_vendor(),
|
||||
m_product(),
|
||||
m_path(),
|
||||
m_serial()
|
||||
{}
|
||||
|
||||
bool match(int vendor, int product,
|
||||
int bus, int dev,
|
||||
const char* serial) const;
|
||||
|
||||
static ControllerMatchRule create_usb_id(int vendor, int product);
|
||||
static ControllerMatchRule create_usb_path(int bus, int dev);
|
||||
static ControllerMatchRule create_usb_serial(const std::string& serial);
|
||||
static ControllerMatchRule create_evdev_path(const std::string& path);
|
||||
virtual bool match(udev_device* device) const =0;
|
||||
};
|
||||
|
||||
class ControllerMatchRuleGroup : public ControllerMatchRule
|
||||
{
|
||||
private:
|
||||
typedef std::vector<ControllerMatchRulePtr> Rules;
|
||||
Rules m_rules;
|
||||
|
||||
public:
|
||||
ControllerMatchRuleGroup();
|
||||
|
||||
void add_rule(ControllerMatchRulePtr rule);
|
||||
void add_rule_from_string(const std::string& lhs, const std::string& rhs);
|
||||
bool match(udev_device* device) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -50,12 +50,12 @@ ControllerSlotOptions::get_options(int num) const
|
|||
}
|
||||
|
||||
void
|
||||
ControllerSlotOptions::add_match_rule(const ControllerMatchRule& rule)
|
||||
ControllerSlotOptions::add_match_rule(ControllerMatchRulePtr rule)
|
||||
{
|
||||
m_match_rules.push_back(rule);
|
||||
}
|
||||
|
||||
const std::vector<ControllerMatchRule>&
|
||||
const std::vector<ControllerMatchRulePtr>&
|
||||
ControllerSlotOptions::get_match_rules() const
|
||||
{
|
||||
return m_match_rules;
|
||||
|
|
|
@ -33,12 +33,12 @@ public:
|
|||
public:
|
||||
ControllerSlotOptions();
|
||||
|
||||
void add_match_rule(const ControllerMatchRule& rule);
|
||||
void add_match_rule(ControllerMatchRulePtr rule);
|
||||
|
||||
ControllerOptions& get_options(int num);
|
||||
const ControllerOptions& get_options(int num) const;
|
||||
|
||||
const std::vector<ControllerMatchRule>& get_match_rules() const;
|
||||
const std::vector<ControllerMatchRulePtr>& get_match_rules() const;
|
||||
const std::map<int, ControllerOptions>& get_options() const;
|
||||
|
||||
void set_force_feedback(bool value) { m_force_feedback = value; }
|
||||
|
@ -48,7 +48,7 @@ public:
|
|||
|
||||
private:
|
||||
std::map<int, ControllerOptions> m_options;
|
||||
std::vector<ControllerMatchRule> m_match_rules;
|
||||
std::vector<ControllerMatchRulePtr> m_match_rules;
|
||||
bool m_force_feedback;
|
||||
};
|
||||
|
||||
|
|
|
@ -239,62 +239,7 @@ Options::set_quiet()
|
|||
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::create_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::create_usb_path(bus, dev));
|
||||
}
|
||||
}
|
||||
else if (lhs == "usbserial")
|
||||
{
|
||||
if (args.size() != 1)
|
||||
{
|
||||
raise_exception(std::runtime_error, "usbserial rule requires SERIAL argument");
|
||||
}
|
||||
else
|
||||
{
|
||||
get_controller_slot().add_match_rule(ControllerMatchRule::create_usb_serial(args[0]));
|
||||
}
|
||||
}
|
||||
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::create_evdev_path(args[0]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
raise_exception(std::runtime_error, "'" << lhs << "' not a valid match rule name");
|
||||
}
|
||||
get_controller_slot().add_match_rule(ControllerMatchRule::from_string(lhs, rhs));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -306,8 +251,11 @@ Options::set_match(const std::string& str)
|
|||
void
|
||||
Options::set_match_group(const std::string& str)
|
||||
{
|
||||
// FIXME: not implied
|
||||
assert(!"not implemented");
|
||||
boost::shared_ptr<ControllerMatchRuleGroup> group(new ControllerMatchRuleGroup);
|
||||
|
||||
process_name_value_string(str, boost::bind(&ControllerMatchRuleGroup::add_rule_from_string, group, _1, _2));
|
||||
|
||||
get_controller_slot().add_match_rule(group);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -166,9 +166,7 @@ XboxdrvDaemon::process_match(const Options& opts, struct udev_device* device)
|
|||
}
|
||||
else
|
||||
{
|
||||
const char* serial = udev_device_get_property_value(device, "ID_SERIAL_SHORT");
|
||||
|
||||
ControllerSlot* slot = find_free_slot(vendor, product, bus, dev, serial);
|
||||
ControllerSlot* slot = find_free_slot(device);
|
||||
if (!slot)
|
||||
{
|
||||
log_error("no free controller slot found, controller will be ignored");
|
||||
|
@ -431,9 +429,7 @@ XboxdrvDaemon::print_info(struct udev_device* device)
|
|||
}
|
||||
|
||||
XboxdrvDaemon::ControllerSlot*
|
||||
XboxdrvDaemon::find_free_slot(uint16_t vendor, uint16_t product,
|
||||
int bus, int dev,
|
||||
const char* serial) const
|
||||
XboxdrvDaemon::find_free_slot(udev_device* dev) const
|
||||
{
|
||||
// first pass, look for slots where the rules match the given vendor:product, bus:dev
|
||||
for(ControllerSlots::const_iterator i = m_controller_slots.begin(); i != m_controller_slots.end(); ++i)
|
||||
|
@ -441,9 +437,9 @@ XboxdrvDaemon::find_free_slot(uint16_t vendor, uint16_t product,
|
|||
if (i->thread == 0)
|
||||
{
|
||||
// found a free slot, check if the rules match
|
||||
for(std::vector<ControllerMatchRule>::const_iterator rule = i->rules.begin(); rule != i->rules.end(); ++rule)
|
||||
for(std::vector<ControllerMatchRulePtr>::const_iterator rule = i->rules.begin(); rule != i->rules.end(); ++rule)
|
||||
{
|
||||
if (rule->match(vendor, product, bus, dev, serial))
|
||||
if ((*rule)->match(dev))
|
||||
{
|
||||
// FIXME: ugly const_cast
|
||||
return const_cast<ControllerSlot*>(&(*i));
|
||||
|
|
|
@ -38,7 +38,7 @@ private:
|
|||
{
|
||||
int id;
|
||||
ControllerSlotConfigPtr config;
|
||||
std::vector<ControllerMatchRule> rules;
|
||||
std::vector<ControllerMatchRulePtr> rules;
|
||||
XboxdrvThread* thread;
|
||||
|
||||
ControllerSlot() :
|
||||
|
@ -50,7 +50,7 @@ private:
|
|||
|
||||
ControllerSlot(int id_,
|
||||
ControllerSlotConfigPtr config_,
|
||||
std::vector<ControllerMatchRule> rules_,
|
||||
std::vector<ControllerMatchRulePtr> rules_,
|
||||
XboxdrvThread* thread_ = 0) :
|
||||
id(id_),
|
||||
config(config_),
|
||||
|
@ -97,8 +97,7 @@ private:
|
|||
|
||||
void run_loop(const Options& opts);
|
||||
|
||||
ControllerSlot* find_free_slot(uint16_t vendor, uint16_t product,
|
||||
int bus, int dev, const char* serial) const;
|
||||
ControllerSlot* find_free_slot(udev_device* dev) const;
|
||||
|
||||
void cleanup_threads();
|
||||
void process_match(const Options& opts, struct udev_device* device);
|
||||
|
|
Loading…
Reference in a new issue