From: Mikko Rasa Date: Sat, 19 Nov 2022 22:05:12 +0000 (+0200) Subject: Add classes for storing and applying bindings to controls X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=7302a061c57602203895b616bf54d96269c677c6;p=libs%2Fgui.git Add classes for storing and applying bindings to controls --- diff --git a/source/input/bindings.cpp b/source/input/bindings.cpp new file mode 100644 index 0000000..85b5941 --- /dev/null +++ b/source/input/bindings.cpp @@ -0,0 +1,142 @@ +#include +#include "bindings.h" +#include "controlscheme.h" + +using namespace std; + +namespace Msp { +namespace Input { + +vector Bindings::resolve_devices(Device &dev) const +{ + vector resolved_devs; + resolved_devs.reserve(devices.size()); + for(vector::const_iterator i=devices.begin(); i!=devices.end(); ++i) + { + if(i->type!=UNSPECIFIED) + resolved_devs.push_back(dev.find_subdevice(i->type)); + else if(!i->name.empty()) + resolved_devs.push_back(dev.find_subdevice(i->name)); + else + resolved_devs.push_back(0); + } + return resolved_devs; +} + +bool Bindings::is_compatible(Device &dev) const +{ + vector resolved_devs = resolve_devices(dev); + for(vector::const_iterator i=resolved_devs.begin(); i!=resolved_devs.end(); ++i) + if(!*i) + return false; + return true; +} + +bool Bindings::apply_to(ControlScheme &control_scheme, Device &dev) +{ + vector resolved_devs = resolve_devices(dev); + bool applied = false; + for(vector::const_iterator i=bindings.begin(); i!=bindings.end(); ++i) + { + Control *ctrl = control_scheme.find(i->control); + Device *bdev = (i->devicedevice] : 0); + if(ctrl && bdev) + { + ctrl->set_source(*bdev, i->type, i->index); + applied = true; + } + } + + return applied; +} + + +DataFile::Loader::ActionMap Bindings::Loader::shared_actions; + +Bindings::Loader::Loader(Bindings &b): + ObjectLoader(b) +{ + set_actions(shared_actions); +} + +void Bindings::Loader::init_actions() +{ + add("binding", &Loader::binding); + add("device", &Loader::device_type); + add("device", &Loader::device_name); +} + +void Bindings::Loader::binding(const string &c) +{ + Binding bind; + bind.control = c; + load_sub(bind); + obj.bindings.push_back(bind); +} + +void Bindings::Loader::device_type(DeviceType t) +{ + DeviceRef dev; + dev.type = t; + obj.devices.push_back(dev); +} + +void Bindings::Loader::device_name(const string &n) +{ + DeviceRef dev; + dev.name = n; + obj.devices.push_back(dev); +} + + +DataFile::Loader::ActionMap Bindings::Binding::Loader::shared_actions; + +Bindings::Binding::Loader::Loader(Binding &b): + ObjectLoader(b) +{ + set_actions(shared_actions); +} + +void Bindings::Binding::Loader::init_actions() +{ + add("axis", &Loader::axis); + add("button", &Loader::button); + add("device", &Binding::device); + add("key", &Loader::key); +} + +void Bindings::Binding::Loader::axis(unsigned a, AxisSide s) +{ + obj.type = (s==NEGATIVE ? AXIS_NEG : AXIS_POS); + obj.index = a; +} + +void Bindings::Binding::Loader::button(unsigned b) +{ + obj.type = BUTTON; + obj.index = b; +} + + +void operator>>(const LexicalConverter &conv, Bindings::AxisSide &side) +{ + if(conv.get()=="POSITIVE") + side = Bindings::POSITIVE; + else if(conv.get()=="NEGATIVE") + side = Bindings::NEGATIVE; + else + throw lexical_error(format("conversion of '%s' to AxisSide", conv.get())); +} + +void operator<<(LexicalConverter &conv, Bindings::AxisSide side) +{ + switch(side) + { + case Bindings::POSITIVE: conv.result("POSITIVE"); break; + case Bindings::NEGATIVE: conv.result("NEGATIVE"); break; + default: conv.result(format("AxisSide(%#x)", static_cast(side))); + } +} + +} // namespace Input +} // namespace Msp; diff --git a/source/input/bindings.h b/source/input/bindings.h new file mode 100644 index 0000000..b73dc51 --- /dev/null +++ b/source/input/bindings.h @@ -0,0 +1,91 @@ +#ifndef MSP_INPUT_BINDINGS_H_ +#define MSP_INPUT_BINDINGS_H_ + +#include +#include +#include "control.h" +#include "device.h" +#include "keys.h" + +namespace Msp { +namespace Input { + +class ControlScheme; + +class Bindings +{ +public: + class Loader: public DataFile::ObjectLoader + { + private: + static ActionMap shared_actions; + + public: + Loader(Bindings &); + + private: + virtual void init_actions(); + + void binding(const std::string &); + void device_type(DeviceType); + void device_name(const std::string &); + }; + + struct DeviceRef + { + DeviceType type = UNSPECIFIED; + std::string name; + }; + +private: + enum AxisSide + { + POSITIVE, + NEGATIVE + }; + + friend void operator>>(const LexicalConverter &, AxisSide &); + friend void operator<<(LexicalConverter &, AxisSide); + +public: + struct Binding + { + class Loader: public DataFile::ObjectLoader + { + private: + static ActionMap shared_actions; + + public: + Loader(Binding &); + + private: + virtual void init_actions(); + + void axis(unsigned, AxisSide); + void button(unsigned); + void key(Key k) { button(k); } + }; + + std::string control; + unsigned device; + ControlSrcType type; + unsigned index; + }; + +private: + std::vector devices; + std::vector bindings; + +public: + const std::vector &get_devices() const { return devices; } + std::vector resolve_devices(Device &) const; + bool is_compatible(Device &) const; + const std::vector &get_bindings() const { return bindings; } + + bool apply_to(ControlScheme &, Device &); +}; + +} // namespace Input +} // namespace Msp + +#endif diff --git a/source/input/controlscheme.cpp b/source/input/controlscheme.cpp new file mode 100644 index 0000000..fe1c0eb --- /dev/null +++ b/source/input/controlscheme.cpp @@ -0,0 +1,33 @@ +#include +#include "control.h" +#include "controlscheme.h" + +using namespace std; + +namespace Msp { +namespace Input { + +void ControlScheme::add(const string &name, Control &ctrl) +{ + insert_unique(controls, name, &ctrl); +} + +Control &ControlScheme::get(const string &name) const +{ + return *get_item(controls, name); +} + +Control *ControlScheme::find(const string &name) const +{ + map::const_iterator i = controls.find(name); + return (i!=controls.end() ? i->second : 0); +} + +void ControlScheme::reset_edges() +{ + for(map::const_iterator i=controls.begin(); i!=controls.end(); ++i) + i->second->reset_edges(); +} + +} // namespace Input +} // namespace Msp diff --git a/source/input/controlscheme.h b/source/input/controlscheme.h new file mode 100644 index 0000000..dabcec2 --- /dev/null +++ b/source/input/controlscheme.h @@ -0,0 +1,32 @@ +#ifndef MSP_INPUT_CONTROLSCHEME_H_ +#define MSP_INPUT_CONTROLSCHEME_H_ + +#include +#include + +namespace Msp { +namespace Input { + +class Control; + +class ControlScheme +{ +private: + std::map controls; + +protected: + ControlScheme() = default; + + void add(const std::string &, Control &); +public: + Control &get(const std::string &) const; + Control *find(const std::string &) const; + const std::map &get_controls() const { return controls; } + + void reset_edges(); +}; + +} // namespace Input +} // namespace Msp + +#endif