MezzanineEngine 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
metacode.cpp
1 // © Copyright 2010 - 2014 BlackTopp Studios Inc.
2 /* This file is part of The Mezzanine Engine.
3 
4  The Mezzanine Engine is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  The Mezzanine Engine is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with The Mezzanine Engine. If not, see <http://www.gnu.org/licenses/>.
16 */
17 /* The original authors have included a copy of the license specified above in the
18  'Docs' folder. See 'gpl.txt'
19 */
20 /* We welcome the use of the Mezzanine engine to anyone, including companies who wish to
21  Build professional software and charge for their product.
22 
23  However there are some practical restrictions, so if your project involves
24  any of the following you should contact us and we will try to work something
25  out:
26  - DRM or Copy Protection of any kind(except Copyrights)
27  - Software Patents You Do Not Wish to Freely License
28  - Any Kind of Linking to Non-GPL licensed Works
29  - Are Currently In Violation of Another Copyright Holder's GPL License
30  - If You want to change our code and not add a few hundred MB of stuff to
31  your distribution
32 
33  These and other limitations could cause serious legal problems if you ignore
34  them, so it is best to simply contact us or the Free Software Foundation, if
35  you have any questions.
36 
37  Joseph Toppi - toppij@gmail.com
38  John Blackwood - makoenergy02@gmail.com
39 */
40 #ifndef _inputmetacode_cpp
41 #define _inputmetacode_cpp
42 
43 #include "entresol.h" //only used for logging
44 
45 ///////////////////////////////////////////////////////////////////////////////
46 // Includes
47 ///////////////////////////////////////
48 
49 #include "exception.h"
50 #include "Input/metacode.h"
51 #include "stringtool.h"
52 
53 #include <assert.h>
54 #include <limits>
55 #include <ostream>
56 #include <cstring>
57 #include <memory>
58 
59 #include "SDL.h"
60 #include "serialization.h"
61 
62 using namespace std;
63 
64 namespace Mezzanine
65 {
66  namespace Input
67  {
68  ///////////////////////////////////////////////////////////////////////////////
69  // Creation and Deletion Methods
70 
71  MetaCode::MetaCode() : MetaValue(0), DeviceIndex( numeric_limits<UInt16>::max() ), Code(Input::KEY_UNKNOWN)
72  {}
73 
74  MetaCode::MetaCode(const MetaCode& Other) : MetaValue(Other.MetaValue), DeviceIndex(Other.DeviceIndex), Code(Other.Code)
75  {}
76 
77  MetaCode::MetaCode(const Int32& Value, const Input::InputCode& NewCode) : DeviceIndex( numeric_limits<UInt16>::max() )
78  {
79  this->Construct(Value, NewCode);
80  }
81 
82  MetaCode::MetaCode(const Int32& Value, const Input::InputCode& NewCode, const UInt16& Index)
83  {
84  this->Construct(Value, NewCode);
85  this->SetDeviceIndex(Index);
86  }
87 
88  MetaCode::MetaCode(const RawEvent& RawEvent_)
89  {
90  this->Construct(RawEvent_);
91  }
92 
93  void MetaCode::Construct(const RawEvent& RawEvent_)
94  {
95  switch(RawEvent_.type)
96  {
97  case SDL_KEYDOWN:
98  this->Construct(Input::BUTTON_PRESSING, GetInputCodeFromSDL_KEY(RawEvent_));
99  break;
100  case SDL_KEYUP:
101  this->Construct(Input::BUTTON_LIFTING, GetInputCodeFromSDL_KEY(RawEvent_));
102  break;
103  case SDL_MOUSEBUTTONDOWN:
104  this->Construct(Input::BUTTON_PRESSING, GetInputCodeFromSDL_MOUSE(RawEvent_));
105  break;
106  case SDL_MOUSEBUTTONUP:
107  this->Construct(Input::BUTTON_LIFTING, GetInputCodeFromSDL_MOUSE(RawEvent_));
108  break;
109  case SDL_JOYBUTTONDOWN:
110  this->Construct(Input::BUTTON_PRESSING, GetInputCodeFromSDL_JOYSTICK(RawEvent_));
111  break;
112  case SDL_JOYBUTTONUP:
113  this->Construct(Input::BUTTON_LIFTING, GetInputCodeFromSDL_JOYSTICK(RawEvent_));
114  break;
115 
116  // Fail when incorrectly constructed
117  case SDL_JOYBALLMOTION: case SDL_JOYHATMOTION:
118  case SDL_JOYAXISMOTION: case SDL_MOUSEMOTION:
119  this->Construct(Input::BUTTON_UP, Input::KEY_FIRST); // ©reate a safe but gibberish default
120  MEZZ_EXCEPTION(Exception::PARAMETERS_EXCEPTION,"RawEvent which creates Multiple Metacodes inserted into Metacode");
121  break;
122 
123  default:
124  this->Construct(Input::BUTTON_UP, Input::KEY_FIRST); // ©reate a safe but gibberish default
125  MEZZ_EXCEPTION(Exception::PARAMETERS_EXCEPTION,"Unknown User Input Inserted into Metacode");
126  break;
127  }
128  }
129 
130  void MetaCode::Construct(const Int32& Value, const Input::InputCode& NewCode)
131  {
132  this->SetMetaValue(Value);
133  this->SetCode(NewCode);
134  }
135 
136  ///////////////////////////////////////////////////////////////////////////////
137  // Dirty Hacks
138 
139  //This function assumes the RawEvent is a valid SDL Keyevent
140  Input::InputCode MetaCode::GetInputCodeFromSDL_KEY(const RawEvent &RawEvent_)
141  {
142  //This Whole thing will only work with SDL Keyboard events. If we switch out event subsystems this is one of those that must change it.
143  Input::InputCode To;
144 
145  assert( sizeof(To)==sizeof(RawEvent_.key.keysym.sym) );
146  memcpy( &To, &(RawEvent_.key.keysym.scancode), sizeof(RawEvent_.key.keysym.scancode));
147 
148  return To;
149  }
150 
151  Input::InputCode MetaCode::GetInputCodeFromSDL_MOUSE(const RawEvent &RawEvent_)
152  {
153  switch (RawEvent_.button.button )
154  {
155  case SDL_BUTTON_LEFT: return Input::MOUSEBUTTON_1;
156  case SDL_BUTTON_RIGHT: return Input::MOUSEBUTTON_2;
157  case SDL_BUTTON_MIDDLE: return Input::MOUSEBUTTON_3;
158  case SDL_BUTTON_X1: return Input::MOUSEBUTTON_4;
159  case SDL_BUTTON_X2: return Input::MOUSEBUTTON_5;
160  }
161  }
162 
163  Input::InputCode MetaCode::GetInputCodeFromSDL_JOYSTICK(const RawEvent &RawEvent_)
164  { return GetControllerButtonCode(RawEvent_.jbutton.button); }
165 
166  ///////////////////////////////////////////////////////////////////////////////
167  // Gets and Sets
168 
169  void MetaCode::SetCode(const Input::InputCode& NewCode)
170  { this->Code = NewCode; }
171 
172  void MetaCode::SetCode(const Int32& NewCode)
173  { this->Code = (Input::InputCode)NewCode; }
174 
176  { return this->Code; }
177 
178  void MetaCode::SetMetaValue(const Int32& Value)
179  { this->MetaValue = Value; }
180 
182  { return this->MetaValue; }
183 
184  void MetaCode::SetDeviceIndex(const UInt16& Index)
185  { this->DeviceIndex = Index; }
186 
188  { return DeviceIndex; }
189 
191  {
192  this->Code = Input::KEY_UNKNOWN;
193  this->MetaValue = 0;
194  this->DeviceIndex = numeric_limits<UInt32>::max();
195  }
196 
197  ///////////////////////////////////////////////////////////////////////////////
198  // Conversion and Casting Functions
200  {
201  if( Input::BUTTON_LIFTING <= this->MetaValue && Input::BUTTON_DOWN >= this->MetaValue)
202  {
203  return (Input::ButtonState) this->MetaValue;
204  }else{
205  MEZZ_EXCEPTION(Exception::PARAMETERS_EXCEPTION,"Invalid ButtonState in MetaValue");
206  }
207  }
208 
210  {
211  if( Input::DIRECTIONALMOTION_DOWNRIGHT <= this->MetaValue && Input::DIRECTIONALMOTION_UPLEFT >= this->MetaValue)
212  {
213  return (Input::DirectionalMotionState) this->MetaValue;
214  }else{
215  MEZZ_EXCEPTION(Exception::PARAMETERS_EXCEPTION,"Invalid DirectionalMotionState in MetaValue");
216  }
217  }
218 
220  {
221  Input::InputCode Answer = (Input::InputCode)(ButtonNumber + (UInt16)Input::MOUSEBUTTON);
222  if ( Input::MOUSEBUTTON_FIRST > Answer && Input::MOUSEBUTTON_LAST < Answer)
223  { MEZZ_EXCEPTION(Exception::PARAMETERS_EXCEPTION,"Unsupported mouse Button."); }
224  return Answer;
225  }
226 
228  {
231  { MEZZ_EXCEPTION(Exception::PARAMETERS_EXCEPTION,"Unsupported Controller Button."); }
232  return Answer;
233  }
234 
236  {
239  { MEZZ_EXCEPTION(Exception::PARAMETERS_EXCEPTION,"Unsupported Controller AXIS."); }
240  return Answer;
241  }
242 
243  ///////////////////////////////////////////////////////////////////////////////
244  // Utility Checks
245 
247  { return (Input::KEY_FIRST <= this->Code && Input::KEY_LAST >= this->Code); }
248 
250  { return (Input::MOUSEBUTTON_FIRST <= this->Code && Input::MOUSEBUTTON_LAST >= this->Code); }
251 
253  { return (Input::CONTROLLERBUTTON_FIRST <= this->Code && Input::CONTROLLERBUTTON_LAST >= this->Code); }
254 
256  { return (this->IsKeyboardButton() || this->IsMouseButton() || this->IsControllerButton()); }
257 
259  { return IsKeyboardButton(); }
260 
262  { return (Input::MOUSE_FIRST <= this->Code && Input::MOUSE_LAST >= this->Code) || IsMouseMultiClickEvent(); }
263 
265  { return (Input::MOUSEMOTION_FIRST <= this->Code && Input::MOUSEMOTION_LAST && this->Code); }
266 
268  { return (Input::COMPOUNDINPUT_MOUSEMULTICLICKFIRST <= this->Code && Input::COMPOUNDINPUT_MOUSEMULTICLICKLAST >= this->Code); }
269 
271  { return (Input::MULTITOUCH_FIRST <= this->Code && Input::MULTITOUCH_LAST >= this->Code); }
272 
274  { return (Input::CONTROLLER_FIRST <= this->Code && Input::CONTROLLER_LAST >= this->Code); }
275 
277  { return (Input::CONTROLLERAXIS_FIRST <= this->Code && Input::CONTROLLERAXIS_LAST >= this->Code); }
278 
280  { return (Input::CONTROLLERHAT_FIRST <= this->Code && Input::CONTROLLERHAT_LAST >= this->Code); }
281 
283  { return (Input::INPUTEVENT_FIRST <= this->Code && Input::INPUTEVENT_LAST >= this->Code); }
284 
285  bool MetaCode::IsAltKey() const
286  { return (Input::KEY_LALT == this->Code || Input::KEY_RALT == this->Code); }
287 
288  bool MetaCode::IsCtrlKey() const
289  { return (Input::KEY_LCTRL == this->Code || Input::KEY_RCTRL == this->Code); }
290 
291  bool MetaCode::IsShiftKey() const
292  { return (Input::KEY_LSHIFT == this->Code || Input::KEY_RSHIFT == this->Code); }
293 
294  bool MetaCode::IsSuperKey() const
295  { return (Input::KEY_LSUPER == this->Code || Input::KEY_RSUPER == this->Code); }
296 
297  bool MetaCode::IsPollable() const
298  { return ( IsDeviceButton() ); }
299 
301  {
302  if(IsKeyboardEvent()) return Input::DEVICE_KEYBOARD;
303  else if(IsMouseEvent()) return Input::DEVICE_MOUSE;
304  else if(IsMultitouchEvent()) return Input::DEVICE_MULTITOUCH;
305  else if(IsControllerEvent()) return Input::DEVICE_CONTROLLER;
306  else return Input::DEVICE_UNKNOWN;
307  }
308 
309  ///////////////////////////////////////////////////////////////////////////////
310  // Operators
311 
313  {
314  this->Code = Other.Code;
315  this->MetaValue = Other.MetaValue;
316  this->DeviceIndex = Other.DeviceIndex;
317  return *this;
318  }
319 
320  bool MetaCode::operator==(const MetaCode& Other) const
321  {
322  return (this->Code == Other.Code &&
323  this->MetaValue == Other.MetaValue &&
324  this->DeviceIndex == Other.DeviceIndex);
325  }
326 
327  bool MetaCode::operator!=(const MetaCode& Other) const
328  {
329  return (this->Code != Other.Code ||
330  this->MetaValue != Other.MetaValue ||
331  this->DeviceIndex != Other.DeviceIndex);
332  }
333 
334  bool MetaCode::operator<(const MetaCode& Other) const
335  {
336  return (this->Code < Other.Code);
337  }
338 
339  bool MetaCode::operator>(const MetaCode& Other) const
340  {
341  return (this->Code > Other.Code);
342  }
343 
344  // Mike's portion of adding serializable to the metacode starts here
345  void MetaCode::ProtoSerialize(XML::Node& CurrentRoot) const
346  {
347  Mezzanine::XML::Node MetaNode = CurrentRoot.AppendChild(SerializableName());
348  MetaNode.SetName(SerializableName());
349 
350  Mezzanine::XML::Attribute VersionAttr = MetaNode.AppendAttribute("Version");
351  Mezzanine::XML::Attribute MetaValue_ = MetaNode.AppendAttribute("MetaValue");
352  Mezzanine::XML::Attribute Code_ = MetaNode.AppendAttribute("Code");
353 
354  if( VersionAttr && MetaValue_ && Code_ )
355  {
356  if( VersionAttr.SetValue("1") && Code_.SetValue(Code) && MetaValue_.SetValue(MetaValue) )
357  {
358  return;
359  }else{
360  SerializeError("Create XML Attribute Values", SerializableName(),true);
361  }
362  }else{
363  SerializeError("Create XML Attributes", SerializableName(),true);
364  }
365  }
366 
368  {
370  {
371  if(OneNode.GetAttribute("Version").AsInt() == 1)
372  {
373  SetCode(OneNode.GetAttribute("Code").AsInt());
374  MetaValue=OneNode.GetAttribute("MetaValue").AsInt();
375  }else{
376  MEZZ_EXCEPTION(Exception::INVALID_VERSION_EXCEPTION,"Incompatible XML Version for " + SerializableName() + ": Not Version 1.");
377  }
378  }else{
379  MEZZ_EXCEPTION(Exception::II_IDENTITY_INVALID_EXCEPTION,"Attempting to deserialize a " + SerializableName() + ", found a " + String(OneNode.Name()) + ".");
380  }
381  }
382 
384  { return String("MetaCode"); }
385  // end of mike's serializable
386  }//Input
387 }//Mezzanine
388 
389 std::ostream& operator << (std::ostream& stream, const Mezzanine::Input::MetaCode& x)
390 {
391  //stream << "<MetaCode Version=\"1\" MetaValue=\"" << x.GetMetaValue() << "\"" << " Code=\"" << x.GetCode() << "\" />";
392  Mezzanine::Serialize(stream,x);
393  return stream;
394 }
395 
396 std::istream& MEZZ_LIB operator >> (std::istream& stream, Mezzanine::Input::MetaCode& x)
397  { return Mezzanine::DeSerialize(stream, x); }
398 
400 {
401  x.ProtoDeSerialize(OneNode);
402  return OneNode;
403 }
404 
405 #endif