]> git.tdb.fi Git - libs/gui.git/commitdiff
Normalize device axis ranges to [-1, 1]
authorMikko Rasa <tdb@tdb.fi>
Mon, 6 Oct 2008 15:14:35 +0000 (15:14 +0000)
committerMikko Rasa <tdb@tdb.fi>
Mon, 6 Oct 2008 15:14:35 +0000 (15:14 +0000)
Make dead zone and threshold control-specific
Disable Control copy-c'tor and operator= as non-sensible
Properly support dead zone and threshold in SmoothControl
Implement get_axis_name in Mouse and Hub

source/input/binarycontrol.cpp
source/input/binarycontrol.h
source/input/control.cpp
source/input/control.h
source/input/device.h
source/input/hub.cpp
source/input/hub.h
source/input/mouse.cpp
source/input/mouse.h
source/input/smoothcontrol.cpp
source/input/smoothcontrol.h

index 9bf24083850630981ca75656a91af319df84827f..371de3c19f1a518afae93e7d329c3968c8c7a175 100644 (file)
@@ -12,19 +12,27 @@ namespace Msp {
 namespace Input {
 
 BinaryControl::BinaryControl():
-       state(false)
+       state(false),
+       threshold(0.5)
 { }
 
 BinaryControl::BinaryControl(const ControlSource &s):
        Control(s),
-       state(false)
+       state(false),
+       threshold(0.5)
 { }
 
 BinaryControl::BinaryControl(Device &d, ControlSrcType t, unsigned i):
        Control(d, t, i),
-       state(false)
+       state(false),
+       threshold(0.5)
 { }
 
+void BinaryControl::set_threshold(float t)
+{
+       threshold=t;
+}
+
 void BinaryControl::on_press()
 {
        if(!state)
@@ -45,7 +53,7 @@ void BinaryControl::on_release()
 
 void BinaryControl::on_motion(float value, float)
 {
-       if(value>src.dev->get_axis_threshold())
+       if(value>threshold)
                on_press();
        else
                on_release();
index 44aaef4214b98ddd0153aeb359f52a1e3a94c39e..4331f05aa94371b8337ce3ffc1b97fc748c7805c 100644 (file)
@@ -15,8 +15,7 @@ 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).
+is considered to be active when its value is within 10% of the end of the axis.
 */
 class BinaryControl: public Control
 {
@@ -26,11 +25,19 @@ public:
 
 private:
        bool state;
+       float threshold;
 
 public:
        BinaryControl();
        BinaryControl(const ControlSource &);
        BinaryControl(Device &, ControlSrcType, unsigned);
+
+       /**
+       Sets the threshold between states for axis sources.  No effect on button
+       sources
+       */
+       void set_threshold(float);
+
        bool get_state() const { return state; }
 
 private:
index 0519d8fe42117a1f7304a3daa30fbefbce787f6d..ffa02932f7db9c3b3159c45ab589d2c2f434ae1e 100644 (file)
@@ -29,8 +29,10 @@ std::string ControlSource::str() const
 {
        if(type==BUTTON)
                return dev->get_button_name(index);
-       else if(type==AXIS_POS || type==AXIS_NEG)
-               return dev->get_axis_name(index);
+       else if(type==AXIS_POS)
+               return dev->get_axis_name(index)+" +";
+       else if(type==AXIS_NEG)
+               return dev->get_axis_name(index)+" -";
        else if(type==NONE)
                return "None";
 
@@ -54,24 +56,6 @@ Control::Control(Device &d, ControlSrcType t, unsigned i):
        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();
@@ -146,9 +130,9 @@ void Control::axis_motion(unsigned i, float v, float r)
        if(capture_dev)
        {
                ControlSrcType type=NONE;
-               if(v<-src.dev->get_axis_threshold())
+               if(v<-0.9)
                        type=AXIS_NEG;
-               else if(v>src.dev->get_axis_threshold())
+               else if(v>0.9)
                        type=AXIS_POS;
 
                if(type!=NONE)
index 5b435dcf0a1f478ee0994657998bd87e09eaec9e..1d8c50a06bd84040dc17f50c155b1997a733c0c2 100644 (file)
@@ -61,9 +61,7 @@ protected:
        Control();
        Control(const ControlSource &);
        Control(Device &, ControlSrcType, unsigned);
-       Control(const Control &);
 public:
-       Control &operator=(const Control &);
        virtual ~Control() { }
 
        void capture(Device &);
@@ -81,6 +79,9 @@ private:
        void button_press(unsigned);
        void button_release(unsigned);
        void axis_motion(unsigned, float, float);
+
+       Control(const Control &);
+       Control &operator=(const Control &);
 };
 
 } // namespace Input
index d1c96f23be04e890d56755bc2ef55b4043c5aa8b..ea41162bb2afa8aa7417f2096f08348a504126dd 100644 (file)
@@ -17,8 +17,8 @@ namespace Input {
 
 /**
 Base class for input devices.  Input devices have two types of controls:
-buttons and axes.  Buttons are either on or off.  Axes have a floating-point
-value, with range depending on the device.
+buttons and axes.  Buttons are either on or off.  Axes have a floating point
+value in the range [-1, 1].
 */
 class Device
 {
@@ -31,8 +31,6 @@ protected:
        std::string name;
        std::vector<char>  buttons;
        std::vector<float> axes;
-       float axis_threshold;
-       float axis_dead_zone;
 
        Device() { }
 public:
@@ -40,7 +38,6 @@ public:
        const std::string &get_name() const { return name; }
        bool  get_button_state(unsigned) const;
        float get_axis_value(unsigned) const;
-       float get_axis_threshold() const { return axis_threshold; }
 
        virtual std::string get_button_name(unsigned) const;
        virtual std::string get_axis_name(unsigned) const;
index e6969372f9240c728d6b15deeb2f0f591caefe98..0bc818f1adac6e28fdda21a9afdfd639dc8dada3 100644 (file)
@@ -30,13 +30,23 @@ unsigned Hub::attach(Device &dev)
 std::string Hub::get_button_name(unsigned btn) const
 {
        unsigned dev_index=btn>>12;
-       if(dev_index>devices.size())
+       if(dev_index>=devices.size())
                throw InvalidParameterValue("Button does not exist");
 
        const Device &dev=*devices[dev_index];
        return dev.get_name()+": "+dev.get_button_name(btn&0xFFF);
 }
 
+std::string Hub::get_axis_name(unsigned axis) const
+{
+       unsigned dev_index=axis>>12;
+       if(dev_index>=devices.size())
+               throw InvalidParameterValue("Axis does not exist");
+
+       const Device &dev=*devices[dev_index];
+       return dev.get_name()+": "+dev.get_axis_name(axis&0xFFF);
+}
+
 void Hub::button_press(unsigned btn, unsigned index)
 {
        set_button_state((index<<12) | (btn&0xFFF), true, true);
index 4385f27742e83588e59cf686b88a5dd653d33bdc..e003342007703e8cdf619b40e85294485305235e 100644 (file)
@@ -35,6 +35,7 @@ public:
        unsigned attach(Device &dev);
 
        virtual std::string get_button_name(unsigned) const;
+       virtual std::string get_axis_name(unsigned) const;
 protected:
        void button_press(unsigned, unsigned);
        void button_release(unsigned, unsigned);
index 931b204f8a2655805f18509259ffc5c3781587ea..0fbc940f144b23537495cf99825db4b3e09fbc8b 100644 (file)
@@ -12,8 +12,7 @@ namespace Msp {
 namespace Input {
 
 Mouse::Mouse(Graphics::Window &w):
-       window(w),
-       axis_scale(0.01)
+       window(w)
 {
        name="Mouse";
 
@@ -44,6 +43,19 @@ std::string Mouse::get_button_name(unsigned btn) const
        }
 }
 
+std::string Mouse::get_axis_name(unsigned axis) const
+{
+       switch(axis)
+       {
+       case 0:
+               return "X axis";
+       case 1:
+               return "Y axis";
+       default:
+               return format("Axis %d", axis);
+       };
+}
+
 void Mouse::button_press(int, int, unsigned btn, unsigned)
 {
        set_button_state(btn, true, true);
@@ -56,8 +68,8 @@ void Mouse::button_release(int, int, unsigned btn, unsigned)
 
 void Mouse::pointer_motion(int x, int y)
 {
-       set_axis_value(0, x*axis_scale, true);
-       set_axis_value(1, y*axis_scale, true);
+       set_axis_value(0, x*2.0f/window.get_width()-1.0f, true);
+       set_axis_value(1, 1.0f-y*2.0f/window.get_height(), true);
 }
 
 } // namespace Input
index 8d5086f2d11654c7423dda2995d38e6d68d4a6b8..84f9ce0c87b49f4b7c54f5c046c3596501346e13 100644 (file)
@@ -14,15 +14,21 @@ Distributed under the LGPL
 namespace Msp {
 namespace Input {
 
+/**
+Mouse device.  Receives events from a Graphics::Window and presents them in a
+uniform way.
+
+Note: Y axis grows upwards.
+*/
 class Mouse: public Device
 {
 private:
        Graphics::Window &window;
-       float axis_scale;
 
 public:
        Mouse(Graphics::Window &);
        virtual std::string get_button_name(unsigned) const;
+       virtual std::string get_axis_name(unsigned) const;
 private:
        void button_press(int, int, unsigned, unsigned);
        void button_release(int, int, unsigned, unsigned);
index 69dfacf955049f38000f170cd45e8aa91ddaefe0..d45c9536d5e3a5b586f7d28b27e42d8a629d2ecd 100644 (file)
@@ -12,31 +12,40 @@ namespace Input {
 
 SmoothControl::SmoothControl():
        value(0),
-       paired_ctrl(0)
+       paired_ctrl(0),
+       dead_zone(0.1),
+       threshold(0.9)
 { }
 
 SmoothControl::SmoothControl(const ControlSource &s):
        Control(s),
        value(0),
-       paired_ctrl(0)
+       paired_ctrl(0),
+       dead_zone(0.1),
+       threshold(0.9)
 { }
 
 SmoothControl::SmoothControl(Device &d, ControlSrcType t, unsigned i):
        Control(d, t, i),
        value(0),
-       paired_ctrl(0)
+       paired_ctrl(0),
+       dead_zone(0.1),
+       threshold(0.9)
 { }
 
-SmoothControl &SmoothControl::operator=(const SmoothControl &sc)
+SmoothControl::~SmoothControl()
 {
-       Control::operator=(sc);
+       pair(0);
+}
 
-       return *this;
+void SmoothControl::set_dead_zone(float d)
+{
+       dead_zone=d;
 }
 
-SmoothControl::~SmoothControl()
+void SmoothControl::set_threshold(float t)
 {
-       pair(0);
+       threshold=t;
 }
 
 void SmoothControl::pair(SmoothControl *ctrl)
@@ -68,13 +77,23 @@ void SmoothControl::on_release()
                on_motion(0, -value);
 }
 
-void SmoothControl::on_motion(float v, float)
+void SmoothControl::on_motion(float v, float r)
 {
-       value=v;
+       if(v<-threshold)
+               value=-1;
+       else if(v>threshold)
+               value=1;
+       else if(v<-dead_zone)
+               value=(v+dead_zone)/(threshold-dead_zone);
+       else if(v>dead_zone)
+               value=(v-dead_zone)/(threshold-dead_zone);
+       else
+               value=0;
+
        signal_motion.emit(value);
-       
-       if(paired_ctrl && paired_ctrl->get_value()!=-value)
-               paired_ctrl->on_motion(-value, -value-paired_ctrl->get_value());
+
+       if(paired_ctrl && (v>0 || (v==0 && paired_ctrl->value!=0)))
+               paired_ctrl->on_motion(-v, -r);
 }
 
 } // namespace Input
index 26484a912c4a2b0615a47bc45d0b6376a919d4db..2e964bd32c62784cb9370e7cfa34cec69b27d6c5 100644 (file)
@@ -19,7 +19,7 @@ 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.
+controls are bound to the opposite sides of the same axis.
 */
 class SmoothControl: public Control
 {
@@ -29,14 +29,21 @@ public:
 private:
        float value;
        SmoothControl *paired_ctrl;
+       float dead_zone;
+       float threshold;
 
 public:
        SmoothControl();
        SmoothControl(const ControlSource &);
        SmoothControl(Device &, ControlSrcType, unsigned);
-       SmoothControl &operator=(const SmoothControl &);
        virtual ~SmoothControl();
 
+       /// Sets the dead zone value.  Any value below this will be treated as 0.
+       void set_dead_zone(float);
+
+       /// Sets the max-out threshold.  Any value above this will be treated as 1.
+       void set_threshold(float);
+
        void pair(SmoothControl *ctrl);
        float get_value() const { return value; }