Angel 3.2
A 2D Game Prototyping Engine
InputManager.cpp
1 
2 // Copyright (C) 2008-2013, Shane Liesegang
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of the copyright holder nor the names of any
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 // POSSIBILITY OF SUCH DAMAGE.
29 
30 #include "stdafx.h"
31 #include "../Input/InputManager.h"
32 
33 #include "../Infrastructure/World.h"
34 #include "../Input/Controller.h"
35 #include "../Messaging/Switchboard.h"
36 #include "../Util/StringUtil.h"
37 #include "../Util/FileUtil.h"
38 #include "../Infrastructure/Log.h"
39 
40 void InputBinding::SetKeyDownMessage( const String& keyDownMessage )
41 {
42  _keyDownMessage = keyDownMessage;
43 }
44 
45 void InputBinding::SetKeyUpMessage( const String& keyUpMessage )
46 {
47  _keyUpMessage = keyUpMessage;
48 }
49 
50 
51 void InputBinding::OnKeyDown()
52 {
53  if( _keyDownMessage.length() == 0 )
54  return;
55 
56  theSwitchboard.Broadcast(new Message(_keyDownMessage));
57 }
58 
59 void InputBinding::OnKeyUp()
60 {
61  if( _keyUpMessage.length() == 0 )
62  return;
63 
64  theSwitchboard.Broadcast(new Message(_keyUpMessage));
65 }
66 
67 InputManager* InputManager::s_Input = NULL;
68 
69 InputManager &InputManager::GetInstance()
70 {
71  if( s_Input == NULL )
72  {
73  s_Input = new InputManager();
74  s_Input->Initialize();
75  }
76  return *s_Input;
77 }
78 
79 void InputManager::Destroy()
80 {
81  if( s_Input != NULL )
82  {
83  delete s_Input;
84  s_Input = NULL;
85  }
86 }
87 
88 void TestBinding( const String& input )
89 {
90  sysLog.Log("BUTTON: " + input);
91 }
92 
93 void InputManager::Initialize()
94 {
95 #define USEINPUTKEY(e,hashVal,text) \
96  _keyNameTable[ToUpper(text)] = e;
97 #include "InputKeys.h"
98 #undef USEINPUTKEY
99 
100  //Clear Xbox Button States
101  ClearXboxButtonStates();
102 
103  StringList bindings;
104  GetLinesFromFile("Config/input_bindings.ini", bindings);
105  StringList::iterator it = bindings.begin();
106  while (it != bindings.end())
107  {
108  if (((*it).size() == 0) || ((*it)[0] == ';'))
109  {
110  it++;
111  continue;
112  }
113  StringList splitBinding = SplitString(*it, "=:", false);
114  if (splitBinding.size() >= 2)
115  {
116  splitBinding[0] = TrimString(splitBinding[0]);
117  splitBinding[1] = TrimString(splitBinding[1]);
118  BindKey(splitBinding[0], splitBinding[1]);
119  }
120  it++;
121  }
122 }
123 
124 InputManager::~InputManager()
125 {
126  for( BindingTable::iterator itr = _bindingTable.begin(); itr != _bindingTable.end(); itr++ )
127  {
128  delete (*itr).second;
129  }
130 
131  _bindingTable.clear();
132 }
133 
134 void InputManager::BindKey( const String& keyId, const String& command )
135 {
136  if( command.length() == 0 )
137  return;
138 
139  int hashVal = GetHashFromKeyName( keyId );
140 
141  InputBinding* pBinding = GetBinding(hashVal);
142  if( pBinding == NULL )
143  {
144  pBinding = new InputBinding();
145  _bindingTable[hashVal] = pBinding;
146  }
147 
148  String setCommand = command;
149  if( setCommand[0] == '-' )
150  {
151  setCommand.erase(0,1);
152  pBinding->SetKeyUpMessage( setCommand );
153  }
154  else
155  {
156  if( setCommand[0] == '+' )
157  setCommand.erase(0,1);
158 
159  pBinding->SetKeyDownMessage( setCommand );
160  }
161 
162 }
163 
164 void InputManager::UnbindKey( const String& keyId )
165 {
166  int hashVal = GetHashFromKeyName( keyId );
167 
168  InputBinding* pBinding = GetBinding(hashVal);
169  if( pBinding == NULL )
170  return;
171 
172  delete pBinding;
173  _bindingTable.erase( hashVal );
174 }
175 
176 bool InputManager::OnKeyDown( int keyVal )
177 {
178  InputBinding* pBinding = GetBinding( tolower(keyVal) );
179  if( pBinding == NULL )
180  return false;
181 
182  pBinding->OnKeyDown();
183 
184  return true;
185 }
186 
187 bool InputManager::OnKeyUp( int keyVal )
188 {
189  InputBinding* pBinding = GetBinding( tolower(keyVal) );
190  if( pBinding == NULL )
191  return false;
192 
193  pBinding->OnKeyUp();
194 
195  return true;
196 }
197 
199 {
200  int HashKey;
201  const bool (Controller::*CheckFunc)();
202 };
203 
204 XboxButtonBindRecord sBindRecordsOne[] =
205 {
206  { P1BUTTON_A, &Controller::IsAButtonDown },
207  { P1BUTTON_B, &Controller::IsBButtonDown },
208  { P1BUTTON_X, &Controller::IsXButtonDown },
209  { P1BUTTON_Y, &Controller::IsYButtonDown },
210 
211  { P1BUTTON_START, &Controller::IsStartButtonDown },
212  { P1BUTTON_BACK, &Controller::IsBackButtonDown },
213 
214  { P1BUTTON_LEFTTHUMB, &Controller::IsLeftThumbstickButtonDown },
215  { P1BUTTON_RIGHTTHUMB, &Controller::IsRightThumbstickButtonDown },
216 
217  { P1BUTTON_LEFTTRIGGER, &Controller::IsLeftTriggerPressed },
218  { P1BUTTON_RIGHTTRIGGER, &Controller::IsRightTriggerPressed },
219 
220  { P1BUTTON_LEFTBUMPER, &Controller::IsLeftBumperDown },
221  { P1BUTTON_RIGHTBUMPER, &Controller::IsRightBumperDown },
222 };
223 
224 XboxButtonBindRecord sBindRecordsTwo[] =
225 {
226  { P2BUTTON_A, &Controller::IsAButtonDown },
227  { P2BUTTON_B, &Controller::IsBButtonDown },
228  { P2BUTTON_X, &Controller::IsXButtonDown },
229  { P2BUTTON_Y, &Controller::IsYButtonDown },
230 
231  { P2BUTTON_START, &Controller::IsStartButtonDown },
232  { P2BUTTON_BACK, &Controller::IsBackButtonDown },
233 
234  { P2BUTTON_LEFTTHUMB, &Controller::IsLeftThumbstickButtonDown },
235  { P2BUTTON_RIGHTTHUMB, &Controller::IsRightThumbstickButtonDown },
236 
237  { P2BUTTON_LEFTTRIGGER, &Controller::IsLeftTriggerPressed },
238  { P2BUTTON_RIGHTTRIGGER, &Controller::IsRightTriggerPressed },
239 
240  { P2BUTTON_LEFTBUMPER, &Controller::IsLeftBumperDown },
241  { P2BUTTON_RIGHTBUMPER, &Controller::IsRightBumperDown },
242 };
243 
244 void InputManager::HandleControl( Controller& controller )
245 {
246  //TODO: make this so it's not just cut-and-pasted code iterating over two enums
247 
248  if (controller.GetControllerID() == 0)
249  {
250  int numXboxButtons = sizeof( sBindRecordsOne ) / sizeof(sBindRecordsOne[0] );
251  for( int i = 0; i < numXboxButtons; i++ )
252  {
253  XboxButtonBindRecord& rec = sBindRecordsOne[i];
254 
255  //Is button currently down
256  bool bIsDown = (controller.*rec.CheckFunc)();
257  bool bWasDown = _xBoxButtonStates[controller.GetControllerID()][rec.HashKey];
258 
259  //Update key value
260  _xBoxButtonStates[controller.GetControllerID()][rec.HashKey] = bIsDown;
261 
262  InputBinding* pBinding = GetBinding( rec.HashKey );
263  if( pBinding == NULL )
264  continue;
265 
266  if( !bWasDown && bIsDown )
267  {
268  //BUTTON DOWN
269  pBinding->OnKeyDown();
270  }
271  else if( bWasDown && !bIsDown )
272  {
273  //BUTTON UP
274  pBinding->OnKeyUp();
275  }
276  }
277  }
278  else if (controller.GetControllerID() == 1)
279  {
280  int numXboxButtons = sizeof( sBindRecordsTwo ) / sizeof(sBindRecordsTwo[0] );
281  for( int i = 0; i < numXboxButtons; i++ )
282  {
283  XboxButtonBindRecord& rec = sBindRecordsTwo[i];
284 
285  //Is button currently down
286  bool bIsDown = (controller.*rec.CheckFunc)();
287  bool bWasDown = _xBoxButtonStates[controller.GetControllerID()][rec.HashKey];
288 
289  //Update key value
290  _xBoxButtonStates[controller.GetControllerID()][rec.HashKey] = bIsDown;
291 
292  InputBinding* pBinding = GetBinding( rec.HashKey );
293  if( pBinding == NULL )
294  continue;
295 
296  if( !bWasDown && bIsDown )
297  {
298  //BUTTON DOWN
299  pBinding->OnKeyDown();
300  }
301  else if( bWasDown && !bIsDown )
302  {
303  //BUTTON UP
304  pBinding->OnKeyUp();
305  }
306  }
307  }
308  else
309  {
310  sysLog.Log("Bad controller ID.");
311  return;
312  }
313 
314 }
315 
316 void InputManager::ClearXboxButtonStates()
317 {
318  int numXboxButtons = sizeof( sBindRecordsOne ) / sizeof(sBindRecordsOne[0] );
319  for( int i = 0; i < numXboxButtons; i++ )
320  {
321  XboxButtonBindRecord& rec = sBindRecordsOne[i];
322  _xBoxButtonStates[0][rec.HashKey] = false;
323  }
324 
325  numXboxButtons = sizeof( sBindRecordsTwo ) / sizeof(sBindRecordsTwo[0] );
326  for( int i = 0; i < numXboxButtons; i++ )
327  {
328  XboxButtonBindRecord& rec = sBindRecordsTwo[i];
329  _xBoxButtonStates[1][rec.HashKey] = false;
330  }
331 }
332 
333 bool InputManager::IsKeyDown(int keyVal)
334 {
335  if (glfwGetKey(theWorld.GetMainWindow(), toupper(keyVal)) == GLFW_PRESS)
336  {
337  return true;
338  }
339  else
340  {
341  return false;
342  }
343 }
344 
345 InputBinding* InputManager::GetBinding( int hashVal )
346 {
347  //Find existing binding
348  BindingTable::iterator itr = _bindingTable.find(hashVal);
349  if( itr == _bindingTable.end() )
350  return NULL;
351 
352  return (*itr).second;
353 }
354 
355 int InputManager::GetHashFromKeyName( const String& keyId )
356 {
357  //Find key ID
358  KeyNameTable::iterator itr = _keyNameTable.find(ToUpper(keyId));
359  if( itr == _keyNameTable.end() )
360  return -1;
361 
362  return (*itr).second;
363 
364 }