src/Graphics/Input.cc
branchnew_graphics
changeset 414 cede5463b845
parent 389 e74c1820fbd2
child 416 38cba347a3a9
equal deleted inserted replaced
413:7dddc163489a 414:cede5463b845
       
     1 
       
     2 #include "Input.hh"
       
     3 #include "../Error.hh"
       
     4 #include "../Config.hh"
       
     5 
       
     6 #include <cassert>
       
     7 
       
     8 namespace graphics
       
     9 {
       
    10 
       
    11 InputKeymapEntry<PlayerInputBit> INPUT_PLAYER_KEYMAP[] = {
       
    12     {   INPUT_AIM_UP,       INPUT_FLAG_UNLIMITED,   { -CL_KEY_ENTER,    CL_KEY_UP       } },
       
    13     {   INPUT_AIM_DOWN,     INPUT_FLAG_UNLIMITED,   { -CL_KEY_ENTER,    CL_KEY_DOWN     } },
       
    14     {   INPUT_MOVE_LEFT,    INPUT_FLAG_UNLIMITED,   { -CL_KEY_ENTER,    CL_KEY_LEFT     } },
       
    15     {   INPUT_MOVE_RIGHT,   INPUT_FLAG_UNLIMITED,   { -CL_KEY_ENTER,    CL_KEY_RIGHT    } },
       
    16     {   INPUT_JUMP,         INPUT_FLAG_SLOWREPEAT,  { -CL_KEY_ENTER,    CL_KEY_RSHIFT   } },
       
    17     {   INPUT_DIG,          INPUT_FLAG_NOREPEAT,    { CL_KEY_LEFT,      CL_KEY_RIGHT    } },
       
    18     {   INPUT_SHOOT,        INPUT_FLAG_UNLIMITED,   { CL_KEY_RCONTROL,  0               } },
       
    19     {   INPUT_CHANGE_PREV,  INPUT_FLAG_SLOWREPEAT,  { CL_KEY_ENTER,     CL_KEY_LEFT     } },
       
    20     {   INPUT_CHANGE_NEXT,  INPUT_FLAG_SLOWREPEAT,  { CL_KEY_ENTER,     CL_KEY_RIGHT    } },
       
    21     {   INPUT_ROPE,         INPUT_FLAG_NOREPEAT,    { CL_KEY_ENTER,     CL_KEY_RSHIFT   } },
       
    22     {   INPUT_UNROPE,       INPUT_FLAG_SLOWREPEAT,  { -CL_KEY_ENTER,    CL_KEY_RSHIFT   } },
       
    23     {   INPUT_ROPE_UP,      INPUT_FLAG_UNLIMITED,   { CL_KEY_ENTER,     CL_KEY_UP       } },
       
    24     {   INPUT_ROPE_DOWN,    INPUT_FLAG_UNLIMITED,   { CL_KEY_ENTER,     CL_KEY_DOWN     } },
       
    25     {   INPUT_SUICIDE,      INPUT_FLAG_NOREPEAT,    { CL_KEY_LCONTROL,  CL_KEY_K        } },
       
    26     {   INPUT_NONE,         0,                      { 0,                0               } }
       
    27 };
       
    28 
       
    29 InputKeymapEntry<GuiInputBit> INPUT_GUI_KEYMAP[] = {
       
    30     {   GUI_INPUT_QUIT,                 0,                  { CL_KEY_ESCAPE,    0               } },
       
    31     {   GUI_INPUT_DISPLAY_WEAPON,       0,                  { CL_KEY_ENTER,     0               } },
       
    32     {   GUI_INPUT_DEBUG_PLAYER,         0,                  { CL_KEY_I,         0               } },
       
    33     {   GUI_INPUT_TOGGLE_FULLSCREEN,    INPUT_FLAG_NOREPEAT,{ CL_KEY_LCONTROL,  CL_KEY_F        } },
       
    34     {   GUI_INPUT_NONE,                 0,                  { 0,                0,              } }
       
    35 };
       
    36 
       
    37 /*
       
    38  * InputKeyRepeatEntry
       
    39  */
       
    40 template <typename BitEnumType> 
       
    41 InputKeyRepeatEntry<BitEnumType>::InputKeyRepeatEntry (BitEnumType value, TimeMS expire) : 
       
    42     value(value), expire(expire) 
       
    43 {
       
    44 
       
    45 }
       
    46 
       
    47 template <typename BitEnumType> 
       
    48 bool InputKeyRepeatEntry<BitEnumType>::operator< (const struct InputKeyRepeatEntry &other) {
       
    49     return other.expire > expire;
       
    50 }
       
    51 
       
    52 template <typename BitEnumType> 
       
    53 bool InputKeyRepeatEntry<BitEnumType>::updateExpired (TimeMS dt) {
       
    54     if (expire == 0)
       
    55         return false;
       
    56 
       
    57     expire -= dt;
       
    58 
       
    59     return (expire <= 0);
       
    60 }
       
    61 
       
    62 /*
       
    63  * InputKeyRepeatQueue
       
    64  */
       
    65 template <typename BitEnumType> 
       
    66 InputKeyRepeatQueue<BitEnumType>::InputKeyRepeatQueue (TimeMS expire) :
       
    67     expire(expire)
       
    68 {
       
    69 
       
    70 }
       
    71 
       
    72 template <typename BitEnumType> 
       
    73 void InputKeyRepeatQueue<BitEnumType>::push (BitEnumType bit, bool expire) {
       
    74     list.push_back(InputKeyRepeatEntry<BitEnumType>(bit, expire ? this->expire : 0));
       
    75 }
       
    76 
       
    77 template <typename BitEnumType> 
       
    78 void InputKeyRepeatQueue<BitEnumType>::forget (BitEnumType bit) {
       
    79     // go through the list, looking for it
       
    80     for (list_iterator it = list.begin(); it != list.end(); it++) {
       
    81         if (it->value == bit) {
       
    82             // found, erase it and return
       
    83             list.erase(it);
       
    84             
       
    85             return;
       
    86         }
       
    87     }
       
    88 }
       
    89 
       
    90 template <typename BitEnumType> 
       
    91 bool InputKeyRepeatQueue<BitEnumType>::find (BitEnumType bit) {
       
    92     for (list_iterator it = list.begin(); it != list.end(); it++) {
       
    93         if (it->value == bit)
       
    94             return true;
       
    95     }
       
    96 
       
    97     return false;
       
    98 }
       
    99 
       
   100 template <typename BitEnumType> 
       
   101 void InputKeyRepeatQueue<BitEnumType>::update (TimeMS dt) {
       
   102     list_iterator it = list.begin();
       
   103     
       
   104     // go through each entry, updateExpired and remove if expired
       
   105     while (it != list.end()) {
       
   106         if (it->updateExpired(dt))
       
   107             it = list.erase(it);
       
   108         else
       
   109             it++;
       
   110     }
       
   111 }
       
   112 
       
   113 template <typename BitEnumType> 
       
   114 void InputKeyRepeatQueue<BitEnumType>::clear (void) {
       
   115     // just clear our list of events
       
   116     list.clear();
       
   117 }
       
   118 
       
   119 /*
       
   120  * InputHandler
       
   121  */
       
   122 template <typename BitEnumType, typename BitMaskType> 
       
   123 InputHandler<BitEnumType, BitMaskType>::InputHandler (CL_InputDevice &keyboard, InputKeymapEntry<BitEnumType> *keymap, TimeMS keyrepeat_expire) :
       
   124     keyboard(keyboard), 
       
   125     keymap(keymap), 
       
   126     value(0), 
       
   127     prev_value(0),
       
   128     dt(0),
       
   129     queue(keyrepeat_expire),
       
   130     _enabled(false)
       
   131 {
       
   132 
       
   133 }
       
   134 
       
   135 template <typename BitEnumType, typename BitMaskType> 
       
   136 bool InputHandler<BitEnumType, BitMaskType>::checkKeycode (int keycode) {
       
   137     if (keycode > 0)
       
   138         return keyboard.get_keycode(keycode);
       
   139 
       
   140     else if (keycode < 0)
       
   141         return !keyboard.get_keycode(-keycode);
       
   142 
       
   143     else // == 0
       
   144         return true;
       
   145 }
       
   146  
       
   147 template <typename BitEnumType, typename BitMaskType> 
       
   148 void InputHandler<BitEnumType, BitMaskType>::update (TimeMS dt) {
       
   149     // ignore if not enabled
       
   150     if (!_enabled)
       
   151         return;
       
   152 
       
   153     // all bits that are held down, even those ignored
       
   154     BitMaskType raw_value = 0;
       
   155 
       
   156     // update the key-repeat queue
       
   157     queue.update(dt);
       
   158 
       
   159     // then go through the keymap
       
   160     for (InputKeymapEntry<BitEnumType> *e = keymap; e->input != 0; e++) {
       
   161         // check if we've got the correct keycodes
       
   162         if (checkKeycode(e->keycodes[0]) && checkKeycode(e->keycodes[1])) {
       
   163             // set raw_value
       
   164             raw_value |= e->input;
       
   165 
       
   166             if (e->flags & INPUT_FLAG_SLOWREPEAT) {
       
   167                 // repeat, but slowly
       
   168                 if (!(prev_value & e->input)) {
       
   169                     // we've released the key earlier, move it to the back of the queue
       
   170                     queue.forget(e->input);
       
   171                     queue.push(e->input);
       
   172 
       
   173                 } else if (queue.find(e->input)) {
       
   174                     // it's still in the queue, so ignore, but set it in ignore_value
       
   175                     continue;
       
   176 
       
   177                 } else {
       
   178                     // ok, but add it to the queue
       
   179                     queue.push(e->input);
       
   180                 }
       
   181 
       
   182             } else if (e->flags & INPUT_FLAG_NOREPEAT) {
       
   183                 // do not repeat at all
       
   184                 if (prev_value & e->input) {
       
   185                     // ignore repeats
       
   186                     continue;
       
   187                 }
       
   188             }
       
   189 
       
   190             // set bit in masks
       
   191             this->value |= e->input;
       
   192         }
       
   193     }
       
   194 
       
   195     // update prev_value, also adding ignored values
       
   196     prev_value = raw_value;
       
   197 
       
   198     // then increment our dt
       
   199     this->dt += dt;
       
   200 }
       
   201  
       
   202 template <typename BitEnumType, typename BitMaskType> 
       
   203 void InputHandler<BitEnumType, BitMaskType>::readValue (BitMaskType &mask, TimeMS &dt) {
       
   204     // throw exception if disabled
       
   205     if (!_enabled)
       
   206         throw Error("InputHandler is disabled");
       
   207 
       
   208     // copy to args
       
   209     mask = this->value;
       
   210     dt = this->dt;
       
   211 
       
   212     this->value = 0;
       
   213     this->dt = 0;
       
   214 }
       
   215        
       
   216 /**
       
   217  * Input
       
   218  */
       
   219 Input::Input (CL_InputDevice &keyboard) :
       
   220     keyboard(keyboard),
       
   221     update_timer(INPUT_POLL_INTERVAL),
       
   222     player(keyboard, INPUT_PLAYER_KEYMAP, INPUT_REPEAT_DELAY),
       
   223     gui(keyboard, INPUT_GUI_KEYMAP, INPUT_REPEAT_DELAY)
       
   224 {
       
   225     // connect timer 
       
   226     slots.connect(update_timer.sig_tick(), &player, &InputHandler<PlayerInputBit, PlayerInput>::update);
       
   227     slots.connect(update_timer.sig_tick(), &gui, &InputHandler<GuiInputBit, GuiInput>::update);
       
   228 
       
   229     // enable timer
       
   230     update_timer.start();
       
   231 }
       
   232 
       
   233 void Input::readPlayerInput (PlayerInput &mask, TimeMS &dt) {
       
   234     player.readValue(mask, dt);
       
   235 }
       
   236 
       
   237 GuiInput Input::readGuiInput (void) {
       
   238     GuiInput mask;
       
   239     TimeMS dt;
       
   240 
       
   241     gui.readValue(mask, dt);
       
   242 
       
   243     return mask;
       
   244 }
       
   245 
       
   246 }