]> git.tdb.fi Git - libs/gui.git/commitdiff
Add a control layer suitable for games
authorMikko Rasa <tdb@tdb.fi>
Wed, 26 Sep 2007 17:00:10 +0000 (17:00 +0000)
committerMikko Rasa <tdb@tdb.fi>
Wed, 26 Sep 2007 17:00:10 +0000 (17:00 +0000)
source/binarycontrol.cpp [new file with mode: 0644]
source/binarycontrol.h [new file with mode: 0644]
source/control.cpp [new file with mode: 0644]
source/control.h [new file with mode: 0644]
source/inputdevice.cpp
source/inputdevice.h
source/inputhub.cpp
source/smoothcontrol.cpp [new file with mode: 0644]
source/smoothcontrol.h [new file with mode: 0644]

diff --git a/source/binarycontrol.cpp b/source/binarycontrol.cpp
new file mode 100644 (file)
index 0000000..daafd95
--- /dev/null
@@ -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 (file)
index 0000000..44aaef4
--- /dev/null
@@ -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<void> signal_press;
+       sigc::signal<void> 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 (file)
index 0000000..8fa2848
--- /dev/null
@@ -0,0 +1,146 @@
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include <msp/core/error.h>
+#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 (file)
index 0000000..97e2be5
--- /dev/null
@@ -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 <sigc++/signal.h>
+#include <sigc++/trackable.h>
+
+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<void> 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
index f0f9aac0a8a156f2b955ee9e012b20b9a8774890..e994d9fc3021052fbf29fd2bd7e785ce50de0ae6 100644 (file)
@@ -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;
index 60b25e928ba4c7e62fa38380fc9e9b5c03ad6c56..4dd002291599cb3766c38337fa451dbf86c2622e 100644 (file)
@@ -29,11 +29,15 @@ public:
 protected:
        std::vector<char>  buttons;
        std::vector<float> 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);
index d2fc863a200df4e5179448d0b9fef3d67aafde7d..27a340a134015433e19cace7ed65824f784558ef 100644 (file)
@@ -1,3 +1,10 @@
+/* $Id$
+
+This file is part of libmspgbase
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
 #include <sigc++/bind.h>
 #include "inputhub.h"
 
diff --git a/source/smoothcontrol.cpp b/source/smoothcontrol.cpp
new file mode 100644 (file)
index 0000000..e878ed8
--- /dev/null
@@ -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 (file)
index 0000000..3c41d1c
--- /dev/null
@@ -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<void, float> 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