#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;
}