improve input handling further, ROPE_THROW and DIG don't repeat at all now
authorterom
Mon, 08 Dec 2008 22:28:51 +0000
changeset 319 9f6a838d58c4
parent 318 dca3c836edb2
child 320 cb33eca69b29
improve input handling further, ROPE_THROW and DIG don't repeat at all now
src/Input.cc
src/Input.hh
--- a/src/Input.cc	Mon Dec 08 22:23:14 2008 +0000
+++ b/src/Input.cc	Mon Dec 08 22:28:51 2008 +0000
@@ -1,21 +1,22 @@
 
 #include "Input.hh"
+#include "Engine.hh"
 #include "Config.hh"
 
 InputKeymapEntry<PlayerInputBit> INPUT_PLAYER_KEYMAP[] = {
-    {   INPUT_AIM_UP,       INPUT_FLAG_REPEAT,      { -CL_KEY_ENTER,    CL_KEY_UP       } },
-    {   INPUT_AIM_DOWN,     INPUT_FLAG_REPEAT,      { -CL_KEY_ENTER,    CL_KEY_DOWN     } },
-    {   INPUT_MOVE_LEFT,    INPUT_FLAG_REPEAT,      { -CL_KEY_ENTER,    CL_KEY_LEFT     } },
-    {   INPUT_MOVE_RIGHT,   INPUT_FLAG_REPEAT,      { -CL_KEY_ENTER,    CL_KEY_RIGHT    } },
-    {   INPUT_JUMP,         INPUT_FLAG_NOREPEAT,    { -CL_KEY_ENTER,    CL_KEY_RSHIFT   } },
+    {   INPUT_AIM_UP,       INPUT_FLAG_UNLIMITED,   { -CL_KEY_ENTER,    CL_KEY_UP       } },
+    {   INPUT_AIM_DOWN,     INPUT_FLAG_UNLIMITED,   { -CL_KEY_ENTER,    CL_KEY_DOWN     } },
+    {   INPUT_MOVE_LEFT,    INPUT_FLAG_UNLIMITED,   { -CL_KEY_ENTER,    CL_KEY_LEFT     } },
+    {   INPUT_MOVE_RIGHT,   INPUT_FLAG_UNLIMITED,   { -CL_KEY_ENTER,    CL_KEY_RIGHT    } },
+    {   INPUT_JUMP,         INPUT_FLAG_SLOWREPEAT,  { -CL_KEY_ENTER,    CL_KEY_RSHIFT   } },
     {   INPUT_DIG,          INPUT_FLAG_NOREPEAT,    { CL_KEY_LEFT,      CL_KEY_RIGHT    } },
-    {   INPUT_SHOOT,        INPUT_FLAG_REPEAT,      { CL_KEY_RCONTROL,  0               } },
-    {   INPUT_CHANGE_PREV,  INPUT_FLAG_NOREPEAT,    { CL_KEY_ENTER,     CL_KEY_LEFT     } },
-    {   INPUT_CHANGE_NEXT,  INPUT_FLAG_NOREPEAT,    { CL_KEY_ENTER,     CL_KEY_RIGHT    } },
+    {   INPUT_SHOOT,        INPUT_FLAG_UNLIMITED,   { CL_KEY_RCONTROL,  0               } },
+    {   INPUT_CHANGE_PREV,  INPUT_FLAG_SLOWREPEAT,  { CL_KEY_ENTER,     CL_KEY_LEFT     } },
+    {   INPUT_CHANGE_NEXT,  INPUT_FLAG_SLOWREPEAT,  { CL_KEY_ENTER,     CL_KEY_RIGHT    } },
     {   INPUT_ROPE,         INPUT_FLAG_NOREPEAT,    { CL_KEY_ENTER,     CL_KEY_RSHIFT   } },
-    {   INPUT_UNROPE,       INPUT_FLAG_NOREPEAT,    { -CL_KEY_ENTER,    CL_KEY_RSHIFT   } },
-    {   INPUT_ROPE_UP,      INPUT_FLAG_REPEAT,      { CL_KEY_ENTER,     CL_KEY_UP       } },
-    {   INPUT_ROPE_DOWN,    INPUT_FLAG_REPEAT,      { CL_KEY_ENTER,     CL_KEY_DOWN     } },
+    {   INPUT_UNROPE,       INPUT_FLAG_SLOWREPEAT,  { -CL_KEY_ENTER,    CL_KEY_RSHIFT   } },
+    {   INPUT_ROPE_UP,      INPUT_FLAG_UNLIMITED,   { CL_KEY_ENTER,     CL_KEY_UP       } },
+    {   INPUT_ROPE_DOWN,    INPUT_FLAG_UNLIMITED,   { CL_KEY_ENTER,     CL_KEY_DOWN     } },
     {   INPUT_SUICIDE,      INPUT_FLAG_NOREPEAT,    { CL_KEY_LCONTROL,  CL_KEY_K        } },
     {   INPUT_NONE,         0,                      { 0,                0               } }
 };
@@ -44,6 +45,9 @@
 
 template <typename BitEnumType> 
 bool InputKeyRepeatEntry<BitEnumType>::updateExpired (TimeMS dt) {
+    if (expire == 0)
+        return false;
+
     expire -= dt;
 
     return (expire <= 0);
@@ -60,8 +64,21 @@
 }
 
 template <typename BitEnumType> 
-void InputKeyRepeatQueue<BitEnumType>::push (BitEnumType bit) {
-    list.push_back(InputKeyRepeatEntry<BitEnumType>(bit, expire));
+void InputKeyRepeatQueue<BitEnumType>::push (BitEnumType bit, bool expire) {
+    list.push_back(InputKeyRepeatEntry<BitEnumType>(bit, expire ? this->expire : 0));
+}
+
+template <typename BitEnumType> 
+void InputKeyRepeatQueue<BitEnumType>::forget (BitEnumType bit) {
+    // go through the list, looking for it
+    for (list_iterator it = list.begin(); it != list.end(); it++) {
+        if (it->value == bit) {
+            // found, erase it and return
+            list.erase(it);
+            
+            return;
+        }
+    }
 }
 
 template <typename BitEnumType> 
@@ -95,6 +112,7 @@
     keyboard(keyboard), 
     keymap(keymap), 
     value(0), 
+    prev_value(0),
     dt(0),
     queue(keyrepeat_expire)
 {
@@ -125,6 +143,9 @@
 
 template <typename BitEnumType, typename BitMaskType> 
 void InputHandler<BitEnumType, BitMaskType>::update (TimeMS dt) {
+    // all bits that are held down, even those ignored
+    BitMaskType raw_value = 0;
+
     // update the key-repeat queue
     queue.update(dt);
 
@@ -132,20 +153,41 @@
     for (InputKeymapEntry<BitEnumType> *e = keymap; e->input != 0; e++) {
         // check if we've got the correct keycodes
         if (checkKeycode(e->keycodes[0]) && checkKeycode(e->keycodes[1])) {
-            // should we do keyrepeats?
-            if (e->flags & INPUT_FLAG_NOREPEAT) {
-                // if it's in the queue, ignore, else add it
-                if (queue.find(e->input))
+            // set raw_value
+            raw_value |= e->input;
+
+            if (e->flags & INPUT_FLAG_SLOWREPEAT) {
+                // repeat, but slowly
+                if (!(prev_value & e->input)) {
+                    // we've released the key earlier, move it to the back of the queue
+                    queue.forget(e->input);
+                    queue.push(e->input);
+
+                } else if (queue.find(e->input)) {
+                    // it's still in the queue, so ignore, but set it in ignore_value
                     continue;
-                else
+
+                } else {
+                    // ok, but add it to the queue
                     queue.push(e->input);
+                }
+
+            } else if (e->flags & INPUT_FLAG_NOREPEAT) {
+                // do not repeat at all
+                if (prev_value & e->input) {
+                    // ignore repeats
+                    continue;
+                }
             }
 
-            // set bit in mask
+            // set bit in masks
             this->value |= e->input;
         }
     }
 
+    // update prev_value, also adding ignored values
+    prev_value = raw_value;
+
     // then increment our dt
     this->dt += dt;
 }
--- a/src/Input.hh	Mon Dec 08 22:23:14 2008 +0000
+++ b/src/Input.hh	Mon Dec 08 22:28:51 2008 +0000
@@ -15,8 +15,21 @@
  */
 enum InputFlagBits {
     /** Default */
-    INPUT_FLAG_REPEAT   = 0x0000,
-    INPUT_FLAG_NOREPEAT = 0x0001,
+
+    /**
+     * 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,
 };
 
 /**
@@ -104,6 +117,10 @@
  */
 template <typename BitEnumType> struct InputKeyRepeatEntry {
         BitEnumType value;
+
+        /**
+         * The remaining expire time. If this is zero, it never expires
+         */
         TimeMS expire;
 
     public:
@@ -115,7 +132,8 @@
         bool operator< (const struct InputKeyRepeatEntry &other);
         
         /**
-         * Decrements expire, returning true if it has now expired, false otherwise
+         * Decrements expire, returning true if it has now expired, false otherwise. Always returns false if expire is
+         * zero.
          */
         bool updateExpired (TimeMS dt);
 };
@@ -141,9 +159,17 @@
         InputKeyRepeatQueue (TimeMS expire);
         
         /**
-         * Push a new input bit onto the queue
+         * 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);
+        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
@@ -177,6 +203,11 @@
         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;