From daf317db7a79a4c92880042125814ca942c3a6fa Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 6 Oct 2008 15:14:35 +0000 Subject: [PATCH] Normalize device axis ranges to [-1, 1] 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 | 16 +++++++++--- source/input/binarycontrol.h | 11 +++++++-- source/input/control.cpp | 28 +++++---------------- source/input/control.h | 5 ++-- source/input/device.h | 7 ++---- source/input/hub.cpp | 12 ++++++++- source/input/hub.h | 1 + source/input/mouse.cpp | 20 ++++++++++++--- source/input/mouse.h | 8 +++++- source/input/smoothcontrol.cpp | 45 ++++++++++++++++++++++++---------- source/input/smoothcontrol.h | 11 +++++++-- 11 files changed, 108 insertions(+), 56 deletions(-) diff --git a/source/input/binarycontrol.cpp b/source/input/binarycontrol.cpp index 9bf2408..371de3c 100644 --- a/source/input/binarycontrol.cpp +++ b/source/input/binarycontrol.cpp @@ -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(); diff --git a/source/input/binarycontrol.h b/source/input/binarycontrol.h index 44aaef4..4331f05 100644 --- a/source/input/binarycontrol.h +++ b/source/input/binarycontrol.h @@ -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: diff --git a/source/input/control.cpp b/source/input/control.cpp index 0519d8f..ffa0293 100644 --- a/source/input/control.cpp +++ b/source/input/control.cpp @@ -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) diff --git a/source/input/control.h b/source/input/control.h index 5b435dc..1d8c50a 100644 --- a/source/input/control.h +++ b/source/input/control.h @@ -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 diff --git a/source/input/device.h b/source/input/device.h index d1c96f2..ea41162 100644 --- a/source/input/device.h +++ b/source/input/device.h @@ -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 buttons; std::vector 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; diff --git a/source/input/hub.cpp b/source/input/hub.cpp index e696937..0bc818f 100644 --- a/source/input/hub.cpp +++ b/source/input/hub.cpp @@ -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); diff --git a/source/input/hub.h b/source/input/hub.h index 4385f27..e003342 100644 --- a/source/input/hub.h +++ b/source/input/hub.h @@ -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); diff --git a/source/input/mouse.cpp b/source/input/mouse.cpp index 931b204..0fbc940 100644 --- a/source/input/mouse.cpp +++ b/source/input/mouse.cpp @@ -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 diff --git a/source/input/mouse.h b/source/input/mouse.h index 8d5086f..84f9ce0 100644 --- a/source/input/mouse.h +++ b/source/input/mouse.h @@ -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); diff --git a/source/input/smoothcontrol.cpp b/source/input/smoothcontrol.cpp index 69dfacf..d45c953 100644 --- a/source/input/smoothcontrol.cpp +++ b/source/input/smoothcontrol.cpp @@ -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 diff --git a/source/input/smoothcontrol.h b/source/input/smoothcontrol.h index 26484a9..2e964bd 100644 --- a/source/input/smoothcontrol.h +++ b/source/input/smoothcontrol.h @@ -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; } -- 2.45.2