src/Graphics/Input.hh
branchnew_graphics
changeset 414 cede5463b845
parent 389 e74c1820fbd2
child 416 38cba347a3a9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Graphics/Input.hh	Thu Jan 22 00:02:53 2009 +0200
@@ -0,0 +1,338 @@
+#ifndef GRAPHICS_INPUT_HH
+#define GRAPHICS_INPUT_HH
+
+#include "../Input.hh"
+#include "../Timer.hh"
+#include "../Types.hh"
+
+#include <ClanLib/Display/input_device.h>
+#include <ClanLib/Display/keys.h>
+
+#include <list>
+
+namespace graphics
+{
+
+/**
+ * Flags to control input behaviour
+ */
+enum InputFlagBits {
+    /** Default */
+
+    /**
+     * The bit is not limited, i.e. it is set every time if it's present
+     */
+    INPUT_FLAG_UNLIMITED    = 0x0000,
+
+    /**
+     * The bit is repeat-limited using INPUT_REPEAT_DELAY
+     */
+    INPUT_FLAG_SLOWREPEAT   = 0x0001,
+
+    /**
+     * The bit is repeat-limited using an infinite delay, i.e. you must release the key to trigger it again
+     */
+    INPUT_FLAG_NOREPEAT     = 0x0002,
+};
+
+
+/**
+ * The bits used in the GuiInput bitmask, each represents something handled locally by Graphics.
+ */
+enum GuiInputBit {
+    GUI_INPUT_NONE              = 0x0000,
+
+    GUI_INPUT_QUIT              = 0x0001,
+    GUI_INPUT_DISPLAY_WEAPON    = 0x0002,
+    GUI_INPUT_DEBUG_PLAYER      = 0x0004,
+
+    GUI_INPUT_TOGGLE_FULLSCREEN = 0x0008,
+};
+
+/**
+ * Bitmask of InputFlagBits
+ */
+typedef uint8_t InputFlags;
+
+/**
+ * Bitmask for GuiInputBits
+ *
+ * @see GuiInputBit
+ */
+typedef uint16_t GuiInput;
+
+/**
+ * Keymap definition struct
+ */
+template <typename BitEnumType> struct InputKeymapEntry {
+    /**
+     * The input bit to set if present
+     */
+    BitEnumType input;
+
+    /**
+     * Flags to use
+     *
+     * @see InputFlagBits
+     */
+    InputFlags flags;
+
+    /**
+     * Up to two keycodes to check
+     */
+    int keycodes[2];
+};
+
+
+/**
+ * A InputKeyRepeatQueue entry, this contains the input bit value itself, and then the remaining expire time
+ */
+template <typename BitEnumType> struct InputKeyRepeatEntry {
+        BitEnumType value;
+
+        /**
+         * The remaining expire time. If this is zero, it never expires
+         */
+        TimeMS expire;
+
+    public:
+        InputKeyRepeatEntry (BitEnumType value, TimeMS expire);
+        
+        /**
+         * Since priority_queue always gives the greatest item, the one with the longest expire is the least item
+         */
+        bool operator< (const struct InputKeyRepeatEntry &other);
+        
+        /**
+         * Decrements expire, returning true if it has now expired, false otherwise. Always returns false if expire is
+         * zero.
+         */
+        bool updateExpired (TimeMS dt);
+};
+
+/**
+ * A InputKeyRepeatQueue maintains a list of InputKeyRepeatEntry's, lets you add new input values, find old ones,
+ * and update the list
+ */
+template <typename BitEnumType> class InputKeyRepeatQueue {
+    private:
+        TimeMS expire;
+
+        typedef InputKeyRepeatEntry<BitEnumType> entry_type;
+
+        std::list<entry_type> list;
+
+        typedef typename std::list<entry_type>::iterator list_iterator;
+
+    public:
+        /**
+         * Constructs this queue to contain entries with the given expiry time
+         */
+        InputKeyRepeatQueue (TimeMS expire);
+        
+        /**
+         * Push a new input bit onto the queue.
+         *
+         * If expire is true, the bit will automatically expire after our expire time, otherwise, it iwll never expire
+         * until forget()'d
+         */
+        void push (BitEnumType bit, bool expire = true);
+
+        /**
+         * Remove any entry for the given bit
+         */
+        void forget (BitEnumType bit);
+
+        /**
+         * Checks if the given input is in the queue
+         */
+        bool find (BitEnumType bit);
+        
+        /**
+         * Updates the list, removing expired items
+         */
+        void update (TimeMS dt);
+
+        /**
+         * Clear the queue completely
+         */
+        void clear (void);
+};
+
+/**
+ * An InputHandler uses an InputKeymapEntry to maintain a BitMaskType of current inputs
+ */
+template <typename BitEnumType, typename BitMaskType> class InputHandler {
+    private:
+        /**
+         * The keyboard that we read input from
+         */
+        CL_InputDevice &keyboard;
+        
+        /**
+         * The keymap that we use
+         */
+        InputKeymapEntry<BitEnumType> *keymap;
+        
+        /**
+         * The current bitmask value
+         */
+        BitMaskType value;
+
+        /**
+         * The previous value, used to detect key-up. This also includes keys that were filtered out
+         */
+        BitMaskType prev_value;
+
+        /**
+         * How long the bitmask was held...
+         */
+        TimeMS dt;
+        
+        /**
+         * The KeyRepeatQueue
+         */
+        InputKeyRepeatQueue<BitEnumType> queue;
+
+        /**
+         * Are we enabled or not?
+         */
+        bool _enabled;
+    
+    public:
+        /**
+         * Constructs the InputHandler using the given keyboard, keymap and key-repeat expire time.
+         *
+         * The InputHandler is initially disabled, and must be enabled using enable() for use. 
+         */
+        InputHandler (CL_InputDevice &keyboard, InputKeymapEntry<BitEnumType> *keymap, TimeMS keyrepeat_expire);
+    
+    private: 
+        /**
+         * Returns true if the keycode is valid, false if not.
+         *
+         * A positive keycode requires that the keycode be active, a negative keycode that the keycode be inactive,
+         * and a zero keycode always returns true.
+         *
+         * @param keycode A positive keycode to check that it's set, negative keycode to check that it's not set, or zero
+         * @returns bool true if positive+set/negavtive+notset/zero, false otherwise
+         */
+        bool checkKeycode (int keycode);
+    
+    public:
+        /**
+         * Updates the keyrepeat queue
+         */
+        void update (TimeMS dt);
+
+        /**
+         * Reads the current input mask value and length into mask and dt, and reset ours to zero.
+         *
+         * It is an error to attempt to read input while disabled.
+         *
+         * @param mask our BitMaskType value is returned using this
+         * @param dt how long the input was held for
+         */
+        void readValue (BitMaskType &mask, TimeMS &dt);
+        
+        /**
+         * Enables this input handler, collecting bits in value
+         */
+        void enable (void);
+
+        /**
+         * Disables this input handler, zeroing any state, so that enable() works cleanly
+         */
+        void disable (void);
+
+        /**
+         * Current enable/disable state
+         */
+        bool enabled (void) const { return _enabled; }
+};
+
+/**
+ * Handles reading input from a keyboard and mapping it to PlayerInput/GuiInput bitmasks
+ */
+class Input {
+    protected:
+        /**
+         * The keyboard device that we use
+         */
+        CL_InputDevice &keyboard;
+
+        /**
+         * Our update timer
+         */
+        Timer update_timer;
+
+        CL_SlotContainer slots;
+    
+    public:        
+        /**
+         * Our PlayerInput
+         */
+        InputHandler<PlayerInputBit, PlayerInput> player;
+        
+        /**
+         * Our GuiInput
+         */
+        InputHandler<GuiInputBit, GuiInput> gui;
+
+    public:
+        /**
+         * Build the input handler using the given keyboard and the default keymaps
+         */
+        Input (CL_InputDevice &keyboard);
+
+    public:
+        /**
+         * Reads the current PlayerInput value via mask, and the length of the input via dt
+         */
+        void readPlayerInput (PlayerInput &mask, TimeMS &dt);
+
+        /**
+         * Reads the current GuiInput mask and returns it
+         */
+        GuiInput readGuiInput (void);
+};
+
+}
+
+
+
+
+/*
+ * Public template class method definitions
+ */
+#include <cassert>
+
+namespace graphics
+{
+
+template <typename BitEnumType, typename BitMaskType> 
+void InputHandler<BitEnumType, BitMaskType>::enable (void) {
+    // sanity-check
+    assert(!_enabled);
+
+    // update state
+    _enabled = true;
+}
+
+template <typename BitEnumType, typename BitMaskType> 
+void InputHandler<BitEnumType, BitMaskType>::disable (void) {
+    // sanity-check
+    assert(_enabled);
+
+    // update state
+    value = prev_value = 0;
+    _enabled = false;
+
+    // and clear keyrepeat list
+    queue.clear();
+}
+       
+
+}
+
+#endif