src/Input.cc
changeset 311 440763821484
parent 300 417183866f35
child 319 9f6a838d58c4
--- a/src/Input.cc	Mon Dec 08 21:15:52 2008 +0000
+++ b/src/Input.cc	Mon Dec 08 21:18:08 2008 +0000
@@ -1,44 +1,108 @@
-
-#define INPUT_CC
 
 #include "Input.hh"
-
-template <typename BitEnumType> struct InputKeymapEntry {
-    BitEnumType input;
-    int keycode1, keycode2;
-};
+#include "Config.hh"
 
 InputKeymapEntry<PlayerInputBit> INPUT_PLAYER_KEYMAP[] = {
-    {   INPUT_AIM_UP,       -CL_KEY_ENTER,      CL_KEY_UP       },
-    {   INPUT_AIM_DOWN,     -CL_KEY_ENTER,      CL_KEY_DOWN     },
-    {   INPUT_MOVE_LEFT,    -CL_KEY_ENTER,      CL_KEY_LEFT     },
-    {   INPUT_MOVE_RIGHT,   -CL_KEY_ENTER,      CL_KEY_RIGHT    },
-    {   INPUT_JUMP,         -CL_KEY_ENTER,      CL_KEY_RSHIFT   },
-    {   INPUT_DIG,          CL_KEY_LEFT,        CL_KEY_RIGHT    },
-    {   INPUT_SHOOT,        CL_KEY_RCONTROL,    0               },
-    {   INPUT_CHANGE_PREV,  CL_KEY_ENTER,       CL_KEY_LEFT     },
-    {   INPUT_CHANGE_NEXT,  CL_KEY_ENTER,       CL_KEY_RIGHT    },
-    {   INPUT_ROPE,         CL_KEY_ENTER,       CL_KEY_RSHIFT   },
-    {   INPUT_UNROPE,       -CL_KEY_ENTER,      CL_KEY_RSHIFT   },
-    {   INPUT_ROPE_UP,      CL_KEY_ENTER,       CL_KEY_UP       },
-    {   INPUT_ROPE_DOWN,    CL_KEY_ENTER,       CL_KEY_DOWN     },
-    {   INPUT_SUICIDE,      CL_KEY_LCONTROL,    CL_KEY_K        },
-    {   INPUT_NONE,         0,                  0               }
+    {   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_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_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_SUICIDE,      INPUT_FLAG_NOREPEAT,    { CL_KEY_LCONTROL,  CL_KEY_K        } },
+    {   INPUT_NONE,         0,                      { 0,                0               } }
 };
 
 InputKeymapEntry<GuiInputBit> INPUT_GUI_KEYMAP[] = {
-    {   GUI_INPUT_QUIT,             CL_KEY_ESCAPE,          0   },
-    {   GUI_INPUT_DISPLAY_WEAPON,   CL_KEY_ENTER,           0   },
-    {   GUI_INPUT_DEBUG_PLAYER,     CL_KEY_I,               0   },
+    {   GUI_INPUT_QUIT,             0,              { CL_KEY_ESCAPE,    0               } },
+    {   GUI_INPUT_DISPLAY_WEAPON,   0,              { CL_KEY_ENTER,     0               } },
+    {   GUI_INPUT_DEBUG_PLAYER,     0,              { CL_KEY_I,         0               } },
+    {   GUI_INPUT_NONE,             0,              { 0,                0,              } }
 };
 
-Input::Input (CL_InputDevice &keyboard) :
-    keyboard(keyboard)
+/*
+ * InputKeyRepeatEntry
+ */
+template <typename BitEnumType> 
+InputKeyRepeatEntry<BitEnumType>::InputKeyRepeatEntry (BitEnumType value, TimeMS expire) : 
+    value(value), expire(expire) 
 {
 
 }
+
+template <typename BitEnumType> 
+bool InputKeyRepeatEntry<BitEnumType>::operator< (const struct InputKeyRepeatEntry &other) {
+    return other.expire > expire;
+}
+
+template <typename BitEnumType> 
+bool InputKeyRepeatEntry<BitEnumType>::updateExpired (TimeMS dt) {
+    expire -= dt;
+
+    return (expire <= 0);
+}
+
+/*
+ * InputKeyRepeatQueue
+ */
+template <typename BitEnumType> 
+InputKeyRepeatQueue<BitEnumType>::InputKeyRepeatQueue (TimeMS expire) :
+    expire(expire)
+{
+
+}
+
+template <typename BitEnumType> 
+void InputKeyRepeatQueue<BitEnumType>::push (BitEnumType bit) {
+    list.push_back(InputKeyRepeatEntry<BitEnumType>(bit, expire));
+}
+
+template <typename BitEnumType> 
+bool InputKeyRepeatQueue<BitEnumType>::find (BitEnumType bit) {
+    for (list_iterator it = list.begin(); it != list.end(); it++) {
+        if (it->value == bit)
+            return true;
+    }
+
+    return false;
+}
+
+template <typename BitEnumType> 
+void InputKeyRepeatQueue<BitEnumType>::update (TimeMS dt) {
+    list_iterator it = list.begin();
     
-bool Input::checkKeycode (int keycode) {
+    // go through each entry, updateExpired and remove if expired
+    while (it != list.end()) {
+        if (it->updateExpired(dt))
+            it = list.erase(it);
+        else
+            it++;
+    }
+}
+
+/*
+ * InputHandler
+ */
+template <typename BitEnumType, typename BitMaskType> 
+InputHandler<BitEnumType, BitMaskType>::InputHandler (CL_InputDevice &keyboard, InputKeymapEntry<BitEnumType> *keymap, TimeMS keyrepeat_expire) :
+    keyboard(keyboard), 
+    keymap(keymap), 
+    value(0), 
+    dt(0),
+    queue(keyrepeat_expire)
+{
+
+}
+
+template <typename BitEnumType, typename BitMaskType> 
+bool InputHandler<BitEnumType, BitMaskType>::checkKeycode (int keycode) {
     if (keycode > 0)
         return keyboard.get_keycode(keycode);
 
@@ -48,23 +112,71 @@
     else // == 0
         return true;
 }
-
-template <typename BitEnumType, typename BitMaskType> BitMaskType Input::buildMask (InputKeymapEntry<BitEnumType> *keymap) {
-    BitMaskType input_mask = 0;
+        
+template <typename BitEnumType, typename BitMaskType> 
+void InputHandler<BitEnumType, BitMaskType>::readValue (BitMaskType &mask, TimeMS &dt) {
+    // copy to args
+    mask = this->value;
+    dt = this->dt;
 
-    for (InputKeymapEntry<BitEnumType> *e = keymap; (e->keycode1 || e->keycode2) && e->input; e++) {
-        if (checkKeycode(e->keycode1) && checkKeycode(e->keycode2))
-            input_mask |= e->input;
-    }
-    
-    return input_mask;
+    this->value = 0;
+    this->dt = 0;
 }
 
-PlayerInput Input::readPlayerInput (void) {
-    return buildMask<PlayerInputBit, PlayerInput>(INPUT_PLAYER_KEYMAP);
+template <typename BitEnumType, typename BitMaskType> 
+void InputHandler<BitEnumType, BitMaskType>::update (TimeMS dt) {
+    // update the key-repeat queue
+    queue.update(dt);
+
+    // then go through the keymap
+    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))
+                    continue;
+                else
+                    queue.push(e->input);
+            }
+
+            // set bit in mask
+            this->value |= e->input;
+        }
+    }
+
+    // then increment our dt
+    this->dt += dt;
+}
+
+/**
+ * Input
+ */
+Input::Input (CL_InputDevice &keyboard) :
+    keyboard(keyboard),
+    update_timer(INPUT_POLL_INTERVAL),
+    player(keyboard, INPUT_PLAYER_KEYMAP, INPUT_REPEAT_DELAY),
+    gui(keyboard, INPUT_GUI_KEYMAP, INPUT_REPEAT_DELAY)
+{
+    // connect timer 
+    slots.connect(update_timer.sig_tick(), &player, &InputHandler<PlayerInputBit, PlayerInput>::update);
+    slots.connect(update_timer.sig_tick(), &gui, &InputHandler<GuiInputBit, GuiInput>::update);
+
+    // enable timer
+    update_timer.start();
+}
+
+void Input::readPlayerInput (PlayerInput &mask, TimeMS &dt) {
+    player.readValue(mask, dt);
 }
 
 GuiInput Input::readGuiInput (void) {
-    return buildMask<GuiInputBit, GuiInput>(INPUT_GUI_KEYMAP);
+    GuiInput mask;
+    TimeMS dt;
+
+    gui.readValue(mask, dt);
+
+    return mask;
 }