From eb9a95ca4acbbdbc6c17acd6b8a135deab906f39 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Wed, 26 Sep 2007 17:00:10 +0000 Subject: [PATCH] Add a control layer suitable for games --- source/binarycontrol.cpp | 55 +++++++++++++++ source/binarycontrol.h | 45 ++++++++++++ source/control.cpp | 146 +++++++++++++++++++++++++++++++++++++++ source/control.h | 85 +++++++++++++++++++++++ source/inputdevice.cpp | 4 +- source/inputdevice.h | 8 ++- source/inputhub.cpp | 7 ++ source/smoothcontrol.cpp | 67 ++++++++++++++++++ source/smoothcontrol.h | 50 ++++++++++++++ 9 files changed, 463 insertions(+), 4 deletions(-) create mode 100644 source/binarycontrol.cpp create mode 100644 source/binarycontrol.h create mode 100644 source/control.cpp create mode 100644 source/control.h create mode 100644 source/smoothcontrol.cpp create mode 100644 source/smoothcontrol.h diff --git a/source/binarycontrol.cpp b/source/binarycontrol.cpp new file mode 100644 index 0000000..daafd95 --- /dev/null +++ b/source/binarycontrol.cpp @@ -0,0 +1,55 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#include "binarycontrol.h" +#include "inputdevice.h" + +namespace Msp { +namespace Input { + +BinaryControl::BinaryControl(): + state(false) +{ } + +BinaryControl::BinaryControl(const ControlSource &s): + Control(s), + state(false) +{ } + +BinaryControl::BinaryControl(Device &d, ControlSrcType t, unsigned i): + Control(d, t, i), + state(false) +{ } + +void BinaryControl::on_press() +{ + if(!state) + { + state=true; + signal_press.emit(); + } +} + +void BinaryControl::on_release() +{ + if(state) + { + state=false; + signal_release.emit(); + } +} + +void BinaryControl::on_motion(float value, float) +{ + if(value>src.dev->get_axis_threshold()) + on_press(); + else + on_release(); +} + +} // namespace Input +} // namespace Msp diff --git a/source/binarycontrol.h b/source/binarycontrol.h new file mode 100644 index 0000000..44aaef4 --- /dev/null +++ b/source/binarycontrol.h @@ -0,0 +1,45 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef MSP_GBASE_BINARYCONTROL_H_ +#define MSP_GBASE_BINARYCONTROL_H_ + +#include "control.h" + +namespace Msp { +namespace Input { + +/** +A control with two possible states. Button state is mapped directly. An axis +is considered to be active when its value is above a threshold (defined by the +input device). +*/ +class BinaryControl: public Control +{ +public: + sigc::signal signal_press; + sigc::signal signal_release; + +private: + bool state; + +public: + BinaryControl(); + BinaryControl(const ControlSource &); + BinaryControl(Device &, ControlSrcType, unsigned); + bool get_state() const { return state; } + +private: + virtual void on_press(); + virtual void on_release(); + virtual void on_motion(float, float); +}; + +} // namespace Input +} // namespace Msp + +#endif diff --git a/source/control.cpp b/source/control.cpp new file mode 100644 index 0000000..8fa2848 --- /dev/null +++ b/source/control.cpp @@ -0,0 +1,146 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#include +#include "control.h" +#include "inputdevice.h" + +namespace Msp { +namespace Input { + +ControlSource::ControlSource(): + dev(0), + type(NONE), + index(0) +{ } + +ControlSource::ControlSource(Device &d, ControlSrcType t, unsigned i): + dev(&d), + type(t), + index(i) +{ } + + +Control::Control(): + capture_dev(0) +{ } + +Control::Control(const ControlSource &s): + src(s), + capture_dev(0) +{ } + +Control::Control(Device &d, ControlSrcType t, unsigned i): + src(d, t, i), + capture_dev(0) +{ + connect_signals(); +} + +Control::Control(const Control &c): + trackable(c), + src(c.src), + capture_dev(0) +{ + connect_signals(); +} + +Control &Control::operator=(const Control &c) +{ + notify_callbacks(); + src=c.src; + capture_dev=0; + connect_signals(); + + return *this; +} + +void Control::capture(Device &d) +{ + notify_callbacks(); + capture_dev=&d; + capture_dev->signal_button_press.connect(sigc::mem_fun(this, &Control::button_press)); + capture_dev->signal_axis_motion.connect(sigc::mem_fun(this, &Control::axis_motion)); +} + +void Control::cancel_capture() +{ + notify_callbacks(); + capture_dev=0; + connect_signals(); +} + +void Control::connect_signals() +{ + switch(src.type) + { + case NONE: + break; + case BUTTON: + src.dev->signal_button_press.connect(sigc::mem_fun(this, &Control::button_press)); + src.dev->signal_button_release.connect(sigc::mem_fun(this, &Control::button_release)); + break; + case AXIS_POS: + case AXIS_NEG: + src.dev->signal_axis_motion.connect(sigc::mem_fun(this, &Control::axis_motion)); + break; + default: + throw Exception("Invalid source in Control"); + } +} + +void Control::button_press(unsigned i) +{ + if(capture_dev) + { + src.dev=capture_dev; + src.type=BUTTON; + src.index=i; + + notify_callbacks(); + capture_dev=0; + connect_signals(); + capture_complete.emit(); + } + else if(src.type==BUTTON && i==src.index) + on_press(); +} + +void Control::button_release(unsigned i) +{ + if(src.type==BUTTON && i==src.index) + on_release(); +} + +void Control::axis_motion(unsigned i, float v, float r) +{ + if(capture_dev) + { + ControlSrcType type=NONE; + if(v<-src.dev->get_axis_threshold()) + type=AXIS_NEG; + else if(v>src.dev->get_axis_threshold()) + type=AXIS_POS; + + if(type!=NONE) + { + src.dev=capture_dev; + src.type=type; + src.index=i; + notify_callbacks(); + connect_signals(); + capture_complete.emit(); + } + } + else if(src.type==AXIS_POS && i==src.index && v>=0) + on_motion(v, r); + else if(src.type==AXIS_NEG && i==src.index && v<=0) + on_motion(-v, -r); +} + +} // namespace Input +} // namespace Msp diff --git a/source/control.h b/source/control.h new file mode 100644 index 0000000..97e2be5 --- /dev/null +++ b/source/control.h @@ -0,0 +1,85 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef MSP_GBASE_CONTROL_H_ +#define MSP_GBASE_CONTROL_H_ + +#include +#include + +namespace Msp { +namespace Input { + +class Device; + +enum ControlSrcType +{ + NONE, + BUTTON, + AXIS_POS, + AXIS_NEG +}; + +/** +Specifies the source of a control. This provides a way for setting sources for +different types of controls in a uniform way. +*/ +struct ControlSource +{ + Device *dev; + ControlSrcType type; + unsigned index; + + ControlSource(); + ControlSource(Device &, ControlSrcType, unsigned); +}; + +/** +Provides further abstraction on top of input devices. There are two types of +controls currently defined: BinaryControl and SmoothControl. + +A control uses either a button or half of an axis (positive or negative) as its +source. How the source values are interpreted depends on the exact type of the +control. Controls also support interactive binding by capturing a button press +or axis motion. +*/ +class Control: public sigc::trackable +{ +public: + sigc::signal capture_complete; + +protected: + ControlSource src; + Device *capture_dev; + + Control(); + Control(const ControlSource &); + Control(Device &, ControlSrcType, unsigned); + Control(const Control &); +public: + Control &operator=(const Control &); + virtual ~Control() { } + + void capture(Device &); + void cancel_capture(); + const ControlSource &get_source() const { return src; } +protected: + virtual void on_press() =0; + virtual void on_release() =0; + virtual void on_motion(float, float) =0; + +private: + void connect_signals(); + void button_press(unsigned); + void button_release(unsigned); + void axis_motion(unsigned, float, float); +}; + +} // namespace Input +} // namespace Msp + +#endif diff --git a/source/inputdevice.cpp b/source/inputdevice.cpp index f0f9aac..e994d9f 100644 --- a/source/inputdevice.cpp +++ b/source/inputdevice.cpp @@ -10,7 +10,7 @@ Distributed under the LGPL namespace Msp { namespace Input { -bool Device::get_button_state(unsigned btn) +bool Device::get_button_state(unsigned btn) const { if(btn>buttons.size()) return false; @@ -18,7 +18,7 @@ bool Device::get_button_state(unsigned btn) return buttons[btn]; } -float Device::get_axis_value(unsigned axis) +float Device::get_axis_value(unsigned axis) const { if(axis>axes.size()) return 0; diff --git a/source/inputdevice.h b/source/inputdevice.h index 60b25e9..4dd0022 100644 --- a/source/inputdevice.h +++ b/source/inputdevice.h @@ -29,11 +29,15 @@ public: protected: std::vector buttons; std::vector axes; + float axis_threshold; + float axis_dead_zone; + Device() { } public: virtual ~Device() { } - bool get_button_state(unsigned); - float get_axis_value(unsigned); + bool get_button_state(unsigned) const; + float get_axis_value(unsigned) const; + float get_axis_threshold() const { return axis_threshold; } protected: void set_button_state(unsigned, bool, bool); void set_axis_value(unsigned, float, bool); diff --git a/source/inputhub.cpp b/source/inputhub.cpp index d2fc863..27a340a 100644 --- a/source/inputhub.cpp +++ b/source/inputhub.cpp @@ -1,3 +1,10 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + #include #include "inputhub.h" diff --git a/source/smoothcontrol.cpp b/source/smoothcontrol.cpp new file mode 100644 index 0000000..e878ed8 --- /dev/null +++ b/source/smoothcontrol.cpp @@ -0,0 +1,67 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#include "smoothcontrol.h" + +namespace Msp { +namespace Input { + +SmoothControl::SmoothControl(): + value(0), + paired_ctrl(0) +{ } + +SmoothControl::SmoothControl(const ControlSource &s): + Control(s), + value(0), + paired_ctrl(0) +{ } + +SmoothControl::SmoothControl(Device &d, ControlSrcType t, unsigned i): + Control(d, t, i), + value(0), + paired_ctrl(0) +{ } + +void SmoothControl::pair(SmoothControl *ctrl) +{ + if(ctrl==paired_ctrl) + return; + + if(paired_ctrl) + { + paired_ctrl=0; + paired_ctrl->pair(0); + } + + paired_ctrl=ctrl; + + if(paired_ctrl) + paired_ctrl->pair(this); +} + +void SmoothControl::on_press() +{ + on_motion(1, 1-value); +} + +void SmoothControl::on_release() +{ + on_motion(0, -value); +} + +void SmoothControl::on_motion(float v, float) +{ + value=v; + signal_motion.emit(value); + + if(paired_ctrl) + paired_ctrl->signal_motion.emit(-value); +} + +} // namespace Input +} // namespace Msp diff --git a/source/smoothcontrol.h b/source/smoothcontrol.h new file mode 100644 index 0000000..3c41d1c --- /dev/null +++ b/source/smoothcontrol.h @@ -0,0 +1,50 @@ +/* $Id$ + +This file is part of libmspgbase +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef MSP_GBASE_SMOOTHCONTROL_H_ +#define MSP_GBASE_SMOOTHCONTROL_H_ + +#include "control.h" + +namespace Msp { +namespace Input { + +/** +A control with a continuous range of values. A button is treated as either 1 +or 0. Axis values are mapped to absolute value. + +Two smooth controls can also be paired to each other. Motion on one control of +the pair will cause negative motion on the other. This works best when the +controls are bound to the opposite sides of the same joystick axis. +*/ +class SmoothControl: public Control +{ +public: + sigc::signal signal_motion; + +private: + float value; + SmoothControl *paired_ctrl; + +public: + SmoothControl(); + SmoothControl(const ControlSource &); + SmoothControl(Device &, ControlSrcType, unsigned); + + void pair(SmoothControl *ctrl); + float get_value() const { return value; } + +private: + virtual void on_press(); + virtual void on_release(); + virtual void on_motion(float, float); +}; + +} // namespace Input +} // namespace Msp + +#endif -- 2.45.2