#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