--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Graphics/Input.cc Thu Jan 22 00:02:53 2009 +0200
@@ -0,0 +1,246 @@
+
+#include "Input.hh"
+#include "../Error.hh"
+#include "../Config.hh"
+
+#include <cassert>
+
+namespace graphics
+{
+
+InputKeymapEntry<PlayerInputBit> INPUT_PLAYER_KEYMAP[] = {
+ { 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_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_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 } }
+};
+
+InputKeymapEntry<GuiInputBit> INPUT_GUI_KEYMAP[] = {
+ { 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_TOGGLE_FULLSCREEN, INPUT_FLAG_NOREPEAT,{ CL_KEY_LCONTROL, CL_KEY_F } },
+ { GUI_INPUT_NONE, 0, { 0, 0, } }
+};
+
+/*
+ * 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) {
+ if (expire == 0)
+ return false;
+
+ 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, 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>
+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();
+
+ // go through each entry, updateExpired and remove if expired
+ while (it != list.end()) {
+ if (it->updateExpired(dt))
+ it = list.erase(it);
+ else
+ it++;
+ }
+}
+
+template <typename BitEnumType>
+void InputKeyRepeatQueue<BitEnumType>::clear (void) {
+ // just clear our list of events
+ list.clear();
+}
+
+/*
+ * 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),
+ prev_value(0),
+ dt(0),
+ queue(keyrepeat_expire),
+ _enabled(false)
+{
+
+}
+
+template <typename BitEnumType, typename BitMaskType>
+bool InputHandler<BitEnumType, BitMaskType>::checkKeycode (int keycode) {
+ if (keycode > 0)
+ return keyboard.get_keycode(keycode);
+
+ else if (keycode < 0)
+ return !keyboard.get_keycode(-keycode);
+
+ else // == 0
+ return true;
+}
+
+template <typename BitEnumType, typename BitMaskType>
+void InputHandler<BitEnumType, BitMaskType>::update (TimeMS dt) {
+ // ignore if not enabled
+ if (!_enabled)
+ return;
+
+ // all bits that are held down, even those ignored
+ BitMaskType raw_value = 0;
+
+ // 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])) {
+ // 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 {
+ // 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 masks
+ this->value |= e->input;
+ }
+ }
+
+ // update prev_value, also adding ignored values
+ prev_value = raw_value;
+
+ // then increment our dt
+ this->dt += dt;
+}
+
+template <typename BitEnumType, typename BitMaskType>
+void InputHandler<BitEnumType, BitMaskType>::readValue (BitMaskType &mask, TimeMS &dt) {
+ // throw exception if disabled
+ if (!_enabled)
+ throw Error("InputHandler is disabled");
+
+ // copy to args
+ mask = this->value;
+ dt = this->dt;
+
+ this->value = 0;
+ this->dt = 0;
+}
+
+/**
+ * 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) {
+ GuiInput mask;
+ TimeMS dt;
+
+ gui.readValue(mask, dt);
+
+ return mask;
+}
+
+}