MezzanineEngine 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
mouse.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 _inputmouse_cpp
41 #define _inputmouse_cpp
42 
43 #include "Input/mouse.h"
44 #include "Graphics/viewport.h"
45 #include "Graphics/gamewindow.h"
46 #include "exception.h"
47 
48 #include "timer.h"
49 
50 #include <limits>
51 
52 #include "SDL.h"
53 #include "../src/video/SDL_sysvideo.h"
54 
55 namespace Mezzanine
56 {
57  namespace Input
58  {
60  CurrentViewport(NULL),
61  VerticalWheelState(Input::DIRECTIONALMOTION_UNCHANGED),
62  HorizontalWheelState(Input::DIRECTIONALMOTION_UNCHANGED)
63  {
64  this->Buttons.resize( (Input::MOUSEBUTTON_LAST - Input::MOUSEBUTTON_FIRST) + 1, Input::BUTTON_UP );
65 
66  this->MulticlickTimer = new StopWatchTimer();
67  this->MulticlickTimer->SetInitialTimeInMilliseconds(500);
68  this->MulticlickTimer->SetAutoReset(true);
69  this->MulticlickTimer->Reset();
70  }
71 
73  {
74  delete MulticlickTimer;
75  }
76 
77  void Mouse::UpdateImpl(const MetaCodeContainer& DeltaCodes, MetaCodeContainer& GeneratedCodes)
78  {
79  /// @todo Getting the mouse focus doesn't do what I originally thought it would. When a mouse leaves a window, the focus isn't set to NULL
80  /// as expected. If you have only one window, then it just stays pointing to that window. If you have two then it will stay on the first
81  /// window until you mouse over the second, even if there is a space between the windows. This should be updated somehow so that we can set
82  /// "HoveredWindow" to NULL when none of our windows are being hovered.
83  // First do some setup. Get the window and save our position.
84  SDL_Window* Focus = SDL_GetMouseFocus();
85  Vector2 OldPosition = this->Position;
86  // Update our states
87  for( Whole X = 0 ; X < DeltaCodes.size() ; ++X )
88  {
89  const MetaCode& CurrCode = DeltaCodes[X];
90  const Input::InputCode ICode = CurrCode.GetCode();
91  if( ICode >= Input::MOUSEBUTTON_FIRST && ICode <= Input::MOUSEBUTTON_LAST )
92  {
93  // Mark the index for transition on the next update and then place it's state in the button vector
94  TransitioningIndexes.push_back( ICode - Input::MOUSEBUTTON_FIRST );
95  Buttons.at( ICode - Input::MOUSEBUTTON_FIRST ) = static_cast<Input::ButtonState>(CurrCode.GetMetaValue());
96  // Now do our checks for multi-click
97  if( this->IsMultiClickable(ICode) && Input::BUTTON_PRESSING == CurrCode.GetMetaValueAsButtonState() )
98  {
99  /// @todo This code isn't as graceful as I am sure it can be made.
100  // Update our multiclick timer
101  if( this->MulticlickTimer->IsStopped() ) this->MulticlickCode.SetMetaValue(0);
102  else this->MulticlickTimer->Reset();
103 
104  const Input::InputCode MCICode = this->ConvertToMultiClickCode(ICode);
105  if( this->MulticlickCode.GetCode() != MCICode )
106  {
107  this->MulticlickCode.SetMetaValue(1);
108  this->MulticlickCode.SetCode(MCICode);
109  }else{
110  Int32 ClickCount = this->MulticlickCode.GetMetaValue();
111  this->MulticlickCode.SetMetaValue( ++ClickCount );
112  }
113  this->MulticlickTimer->Start();
114  }
115  }
116  else if( Input::MOUSEWHEELVERTICAL == ICode )
117  {
118  this->VerticalWheelState = static_cast<Input::DirectionalMotionState>(CurrCode.GetMetaValue());
119  }
120  else if( Input::MOUSEWHEELHORIZONTAL == ICode )
121  {
122  this->HorizontalWheelState = static_cast<Input::DirectionalMotionState>(CurrCode.GetMetaValue());
123  }
124  // Only if we're on a window
125  if( Focus )
126  {
127  if( Input::MOUSEABSOLUTEVERTICAL == ICode )
128  {
129  this->Position.Y = (Real)(CurrCode.GetMetaValue());
130  }
131  else if( Input::MOUSEABSOLUTEHORIZONTAL == ICode )
132  {
133  this->Position.X = (Real)(CurrCode.GetMetaValue());
134  }
135  /*else if( Input::MOUSEVERTICAL == ICode )
136  {
137  Delta.Y = (Real)(CurrCode.GetMetaValue());
138  }
139  else if( Input::MOUSEHORIZONTAL == ICode )
140  {
141  Delta.X = (Real)(CurrCode.GetMetaValue());
142  }*/
143  }
144  }
145 
146  // Update our current window
147  if( NULL != Focus )
148  {
149  Graphics::GameWindow* Win = static_cast<Graphics::GameWindow*>(Focus->data->data);
150  for( Graphics::GameWindow::ReverseViewportIterator ViewIt = Win->ReverseBeginViewport() ; ViewIt != Win->ReverseEndViewport() ; ++ViewIt )
151  {
152  Graphics::Viewport* VP = (*ViewIt);
153  if( (this->Position.X >= (Real)(VP->GetActualLeft()) && this->Position.X <= (Real)(VP->GetActualLeft() + VP->GetActualWidth())) &&
154  (this->Position.Y >= (Real)(VP->GetActualTop()) && this->Position.Y <= (Real)(VP->GetActualTop() + VP->GetActualHeight()) ) )
155  {
156  this->CurrentViewport = VP;
157  break;
158  }
159  }
160  }else{
161  this->CurrentViewport = NULL;
162  this->Position.SetIdentity();
163  this->Delta.SetIdentity();
164  }
165  this->Delta = this->Position - OldPosition;
166 
167  // Do our Multiclick check
168  if( this->MulticlickCode.GetMetaValue() > 1 )
169  GeneratedCodes.push_back(MulticlickCode);
170 
171  // Do our sequence updates
172  this->Sequences.Update(DeltaCodes,GeneratedCodes);
173  }
174 
175  void Mouse::VerifySequenceImpl(const MetaCodeContainer& Sequence) const
176  {
177  for( ConstMetaCodeIterator MCIt = Sequence.begin() ; MCIt != Sequence.end() ; ++MCIt )
178  {
179  if( !MCIt->IsMouseEvent() )
180  { MEZZ_EXCEPTION(Exception::PARAMETERS_EXCEPTION,"Non-Mouse MetaCode detected when attempting to insert an Input Sequence into Mouse input device.") }
181  }
182  }
183 
184  void Mouse::AddPressedButtons(MetaCodeContainer& GeneratedCodes) const
185  {
186  for( UInt32 Index = 0 ; Index < this->Buttons.size() ; ++Index )
187  {
188  if( this->Buttons.at(Index) == Input::BUTTON_DOWN )
189  GeneratedCodes.push_back( MetaCode(Input::BUTTON_DOWN,static_cast<Input::InputCode>(Input::MOUSEBUTTON_FIRST + Index),GetDeviceIndex()) );
190  }
191  }
192 
194  {
195  return (Input::MOUSEBUTTON_1 <= Code && Input::MOUSEBUTTON_2 >= Code);
196  }
197 
199  {
200  switch(Code)
201  {
202  case Input::MOUSEBUTTON_1: return Input::COMPOUNDINPUT_MOUSELEFTMULTICLICK; break;
203  case Input::MOUSEBUTTON_2: return Input::COMPOUNDINPUT_MOUSERIGHTMULTICLICK; break;
204  default:
205  {
206  MEZZ_EXCEPTION(Exception::PARAMETERS_EXCEPTION,"Attempting to convert unsupported mouse button code into a multiclick code.");
207  }
208  }
209  }
210 
211  ///////////////////////////////////////////////////////////////////////////////
212  // Query Methods
213 
215  { return this->CurrentViewport; }
216 
218  { return ( this->CurrentViewport ? this->CurrentViewport->GetParentWindow() : NULL ); }
219 
221  { return this->Position; }
222 
224  { return this->Position.X; }
225 
227  { return this->Position.Y; }
228 
230  { return ( this->CurrentViewport ? this->Position - Vector2( this->CurrentViewport->GetLeft(),this->CurrentViewport->GetTop() ) : Vector2(0,0) ); }
231 
233  { return this->GetViewportPosition().X; }
234 
236  { return this->GetViewportPosition().Y; }
237 
239  { return this->Delta; }
240 
242  { return this->Delta.X; }
243 
245  { return this->Delta.Y; }
246 
248  { return std::numeric_limits<UInt16>::max(); }
249 
251  { return this->Buttons.at( Button - 1 ); }
252 
254  { return this->Buttons.at( Button - Input::MOUSEBUTTON_FIRST ); }
255 
257  { return this->VerticalWheelState; }
258 
260  { return this->HorizontalWheelState; }
261 
262  ///////////////////////////////////////////////////////////////////////////////
263  // Configuration Methods
264 
265  void Mouse::SetCursorVisibility(bool Visible)
266  { SDL_ShowCursor(Visible); }
267 
269  { return 0 != SDL_ShowCursor(-1); }
270 
271  bool Mouse::SetRelativeMode(bool Enable)
272  { return 0 == SDL_SetRelativeMouseMode( (Enable?SDL_TRUE:SDL_FALSE) ); }
273 
275  { return SDL_GetRelativeMouseMode(); }
276 
278  { MEZZ_EXCEPTION(Exception::NOT_IMPLEMENTED_EXCEPTION,"Mouse cursor setting is currently not implemented."); } /// @todo Implement this.
279 
281  { MEZZ_EXCEPTION(Exception::NOT_IMPLEMENTED_EXCEPTION,"Mouse cursor getting is currently not implemented."); } /// @todo Implement this.
282 
283  ///////////////////////////////////////////////////////////////////////////////
284  // Utility Methods
285 
287  { if(Win) SDL_WarpMouseInWindow(Win->_GetSDLWindowPointer(),(int)Position.X,(int)Position.Y); }
288  }//Input
289 }//Mezzanine
290 
291 #endif