port Input to new Graphics, still a bit hacky, but everything seems to work now
--- a/src/GameState.hh Wed Jan 21 23:25:29 2009 +0200
+++ b/src/GameState.hh Thu Jan 22 00:02:53 2009 +0200
@@ -4,10 +4,9 @@
class GameState;
#include "PhysicsWorld.hh"
+#include "Terrain.hh"
#include "Player.hh"
#include "Projectile.hh"
-#include "Rope.hh"
-#include "Input.hh"
#include "Config.hh"
#include "Graphics/Drawable.hh"
--- a/src/Graphics/Display.cc Wed Jan 21 23:25:29 2009 +0200
+++ b/src/Graphics/Display.cc Thu Jan 22 00:02:53 2009 +0200
@@ -60,7 +60,7 @@
view->resize(PixelArea(0, 0, get_width(), get_height()));
}
-void Display::toggle_fullscreen (void) {
+void Display::toggleFullscreen (void) {
if (is_fullscreen()) {
// enter windowed mode
set_windowed();
--- a/src/Graphics/Display.hh Wed Jan 21 23:25:29 2009 +0200
+++ b/src/Graphics/Display.hh Thu Jan 22 00:02:53 2009 +0200
@@ -92,7 +92,7 @@
/**
* Shift back and forth between fullscreen and windowed mode, retaining resolutions
*/
- void toggle_fullscreen (void);
+ void toggleFullscreen (void);
private:
/**
--- a/src/Graphics/GameView.cc Wed Jan 21 23:25:29 2009 +0200
+++ b/src/Graphics/GameView.cc Thu Jan 22 00:02:53 2009 +0200
@@ -18,6 +18,9 @@
// insert message
message_view.add_message(CL_Color::white, "Hello World!");
+
+ // enable GUI input
+ graphics->input.gui.enable();
}
void GameView::setPlayer (LocalPlayer *player) {
@@ -28,8 +31,37 @@
// build the info_view as well
info_view = new PlayerInfoView(getInfoViewArea(), player);
+
+ // enable player input
+ graphics->input.player.enable();
}
+void GameView::handleInput (GuiInput flags, TimeMS dt) {
+ // ignore timing info
+ (void) dt;
+
+ // update our flags
+ this->flags = flags;
+
+ // quit?
+ if (flags & GUI_INPUT_QUIT) {
+ graphics->engine.stop();
+ return;
+ }
+
+ // dump player debug info on stderr
+ if ((flags & GUI_INPUT_DEBUG_PLAYER) && player) {
+ player->printDebugInfo();
+
+ message_view.add_message(CL_Color::green, "...");
+ }
+
+ // toggle fullscreen?
+ if (flags & GUI_INPUT_TOGGLE_FULLSCREEN)
+ graphics->display.toggleFullscreen();
+}
+
+
/*
* Helper function for Camera
*/
@@ -49,6 +81,19 @@
void GameView::draw (Display &display) {
CL_GraphicContext *gc = display.get_gc();
+
+ // XXX: these should not be done from here
+ handleInput(graphics->input.readGuiInput(), 0);
+
+ // XXX: this should /really/ be somewhere else
+ if (player) {
+ PlayerInput input;
+ TimeMS dt;
+
+ graphics->input.readPlayerInput(input, dt);
+
+ player->handleInput(input, dt);
+ }
// calculate camera
PixelCoordinate camera(0, 0);
--- a/src/Graphics/GameView.hh Wed Jan 21 23:25:29 2009 +0200
+++ b/src/Graphics/GameView.hh Thu Jan 22 00:02:53 2009 +0200
@@ -4,15 +4,17 @@
#include "Drawable.hh"
#include "PlayerInfoView.hh"
#include "MessageView.hh"
+#include "Input.hh"
#include "../GameState.hh"
-#include "../Input.hh"
namespace graphics
{
/**
- * This is the main in-game view, which is what the player sees when they are playing
+ * This is the main in-game view, which is what the player sees when they are playing.
+ *
+ * This enables graphics->input.gui/player
*/
class GameView : public View {
protected:
@@ -63,6 +65,11 @@
return PixelArea(400, area.bottom - 100, area.right, area.bottom);
}
+ /**
+ * Handle GUI input
+ */
+ void handleInput (GuiInput flags, TimeMS dt);
+
public:
/**
--- a/src/Graphics/Graphics.cc Wed Jan 21 23:25:29 2009 +0200
+++ b/src/Graphics/Graphics.cc Thu Jan 22 00:02:53 2009 +0200
@@ -10,8 +10,11 @@
Graphics *graphics = NULL;
Graphics::Graphics (Engine &engine, CL_ResourceManager &resources, const DisplayConfig &display_config) :
+ engine(engine), display(display_config),
// display must be set up before fonts, due to implicit CL_DisplayWindow
- engine(engine), display(display_config), fonts(resources)
+ fonts(resources),
+ // get the InputContext from display
+ input(display.get_ic()->get_keyboard())
{
assert(!graphics);
--- a/src/Graphics/Graphics.hh Wed Jan 21 23:25:29 2009 +0200
+++ b/src/Graphics/Graphics.hh Thu Jan 22 00:02:53 2009 +0200
@@ -11,6 +11,7 @@
#include "../Engine.hh"
#include "Display.hh"
#include "FontManager.hh"
+#include "Input.hh"
#include "GameView.hh"
namespace graphics
@@ -35,6 +36,13 @@
* For loading fonts
*/
FontManager fonts;
+
+ /**
+ * Input handling
+ *
+ * XXX: move Input class into this?
+ */
+ Input input;
/**
* Initialize the graphics subsystem
--- /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;
+}
+
+}
--- /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
--- a/src/Input.cc Wed Jan 21 23:25:29 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,225 +0,0 @@
-
-#include "Input.hh"
-#include "Engine.hh"
-#include "Config.hh"
-
-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++;
- }
-}
-
-/*
- * 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)
-{
-
-}
-
-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>::readValue (BitMaskType &mask, TimeMS &dt) {
- // copy to args
- mask = this->value;
- dt = this->dt;
-
- this->value = 0;
- this->dt = 0;
-}
-
-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);
-
- // 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;
-}
-
-/**
- * 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;
-}
-
--- a/src/Input.hh Wed Jan 21 23:25:29 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,301 +0,0 @@
-#ifndef INPUT_HH
-#define INPUT_HH
-
-#include "Timer.hh"
-#include "Types.hh"
-
-#include <ClanLib/Display/input_device.h>
-#include <ClanLib/Display/keys.h>
-#include <queue>
-
-// const TimeMS INPUT_INTERVAL_MS = 20;
-
-/**
- * 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 PlayerInput bitmask, each represents a separate action handled by LocalPlayer::handleInput.
- *
- * @see LocalPlayer::handleInput
- */
-enum PlayerInputBit {
- INPUT_NONE = 0x0000,
-
- INPUT_AIM_UP = 0x0001,
- INPUT_AIM_DOWN = 0x0002,
-
- INPUT_MOVE_LEFT = 0x0004,
- INPUT_MOVE_RIGHT = 0x0008,
-
- INPUT_JUMP = 0x0010,
- INPUT_DIG = 0x0020,
- INPUT_SHOOT = 0x0040,
- INPUT_CHANGE_NEXT = 0x0080,
- INPUT_CHANGE_PREV = 0x0100,
- INPUT_ROPE = 0x0200,
- INPUT_UNROPE = 0x0400,
- INPUT_ROPE_UP = 0x0800,
- INPUT_ROPE_DOWN = 0x1000,
-
- INPUT_SUICIDE = 0x2000,
-};
-
-/**
- * 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 of PlayerInputBits
- *
- * @see PlayerInputBit
- */
-typedef uint16_t PlayerInput;
-
-/**
- * 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);
-};
-
-/**
- * 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;
-
- public:
- /**
- * Constructs the InputHandler using the given keyboard, keymap and key-repeat expire time
- */
- 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
- *
- * @param mask our BitMaskType value is returned using this
- * @param dt how long the input was held for
- */
- void readValue (BitMaskType &mask, TimeMS &dt);
-
-};
-
-/**
- * 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;
-
- /**
- * 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);
-};
-
-#endif
--- a/src/Player.hh Wed Jan 21 23:25:29 2009 +0200
+++ b/src/Player.hh Thu Jan 22 00:02:53 2009 +0200
@@ -9,9 +9,9 @@
#include "Projectile.hh"
#include "GameState.hh"
#include "PhysicsObject.hh"
-#include "Input.hh"
#include "Rope.hh"
#include "Types.hh"
+#include "Input.hh"
#include "Graphics/Drawable.hh"