fixed: Ensure SDL mouse is cleaned up in the application cleanup, and not when the...
[xbmc:xbmc-antiquated.git] / guilib / common / Mouse.cpp
1 /*
2  *      Copyright (C) 2005-2008 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "include.h"
23 #include "Mouse.h"
24
25 #if defined (HAS_SDL)
26 #include "SDLMouse.h"
27 #else
28 #include "DirectInputMouse.h"
29 #endif
30
31 #include "../Key.h"
32 #include "../GraphicContext.h"
33
34 #define MOUSE_MINIMUM_MOVEMENT 2
35 #define MOUSE_DOUBLE_CLICK_LENGTH 500L
36 #define MOUSE_ACTIVE_LENGTH   5000L
37
38 CMouse g_Mouse; // global
39
40 CMouse::CMouse()
41 {
42   m_mouseDevice = NULL;
43   m_exclusiveWindowID = WINDOW_INVALID;
44   m_exclusiveControlID = WINDOW_INVALID;
45   m_pointerState = MOUSE_STATE_NORMAL;
46   m_mouseEnabled = true;
47   m_speedX = m_speedY = 0;
48   m_maxX = m_maxY = 0;
49   memset(&m_mouseState, 0, sizeof(m_mouseState));
50 }
51
52 CMouse::~CMouse()
53 {
54 }
55
56 void CMouse::Initialize(void *appData)
57 {
58   if (m_mouseDevice)
59     return; // nothing to do
60
61   // create the mouse device
62 #if defined (HAS_SDL)
63   m_mouseDevice = new CSDLMouse();
64 #else
65   m_mouseDevice = new CDirectInputMouse();
66 #endif
67
68   if (m_mouseDevice)
69     m_mouseDevice->Initialize(appData);
70
71   // Set the default resolution (PAL)
72   SetResolution(720, 576, 1, 1);
73 }
74
75 void CMouse::Cleanup()
76 {
77   delete m_mouseDevice;
78   m_mouseDevice = NULL;
79 }
80
81 void CMouse::Update()
82 {
83   // update our state from the mouse device
84   if (m_mouseDevice && m_mouseDevice->Update(m_mouseState))
85   {
86     // check our position is not out of bounds
87     if (m_mouseState.x < 0) m_mouseState.x = 0;
88     if (m_mouseState.y < 0) m_mouseState.y = 0;
89     if (m_mouseState.x > m_maxX) m_mouseState.x = m_maxX;
90     if (m_mouseState.y > m_maxY) m_mouseState.y = m_maxY;
91     if (HasMoved())
92     {
93       m_mouseState.active = true;
94       m_lastActiveTime = timeGetTime();
95     }
96   }
97   else
98   {
99     m_mouseState.dx = 0;
100     m_mouseState.dy = 0;
101     m_mouseState.dz = 0;
102     // check how long we've been inactive
103     if (timeGetTime() - m_lastActiveTime > MOUSE_ACTIVE_LENGTH)
104       m_mouseState.active = false;
105   }
106
107   // Perform the click mapping (for single + double click detection)
108   bool bNothingDown = true;
109   for (int i = 0; i < 5; i++)
110   {
111     bClick[i] = false;
112     bDoubleClick[i] = false;
113     bHold[i] = false;
114     if (m_mouseState.button[i])
115     {
116       if (!m_mouseState.active) // wake up mouse on any click
117       {
118         m_mouseState.active = true;
119         m_lastActiveTime = timeGetTime();
120       }
121       bNothingDown = false;
122       if (m_lastDown[i])
123       { // start of hold
124         bHold[i] = true;
125       }
126       else
127       {
128         if (timeGetTime() - m_lastClickTime[i] < MOUSE_DOUBLE_CLICK_LENGTH)
129         { // Double click
130           bDoubleClick[i] = true;
131         }
132         else
133         { // Mouse down
134         }
135       }
136     }
137     else
138     {
139       if (m_lastDown[i])
140       { // Mouse up
141         bNothingDown = false;
142         bClick[i] = true;
143         m_lastClickTime[i] = timeGetTime();
144       }
145       else
146       { // no change
147       }
148     }
149     m_lastDown[i] = m_mouseState.button[i];
150   }
151   if (bNothingDown)
152   { // reset mouse pointer
153     SetState(MOUSE_STATE_NORMAL);
154   }
155
156   // update our mouse pointer as necessary - we show the default pointer
157   // only if we don't have the mouse on, and the mouse is active
158   if (m_mouseDevice)
159     m_mouseDevice->ShowPointer(m_mouseState.active && !m_mouseEnabled);
160 }
161
162 void CMouse::SetResolution(int maxX, int maxY, float speedX, float speedY)
163 {
164   m_maxX = maxX;
165   m_maxY = maxY;
166
167   // speed is currently unused
168   m_speedX = speedX;
169   m_speedY = speedY;
170
171   // reset the coordinates
172   m_mouseState.x = m_maxX / 2;
173   m_mouseState.y = m_maxY / 2;
174 }
175
176 // IsActive - returns true if we have been active in the last MOUSE_ACTIVE_LENGTH period
177 bool CMouse::IsActive() const
178 {
179   return m_mouseState.active && m_mouseEnabled;
180 }
181
182 // IsEnabled - returns true if mouse is enabled
183 bool CMouse::IsEnabled() const
184 {
185   return m_mouseEnabled;
186 }
187
188 // turns off mouse activation
189 void CMouse::SetInactive()
190 {
191   m_mouseState.active = false;
192 }
193
194 bool CMouse::HasMoved() const
195 {
196   return (m_mouseState.dx * m_mouseState.dx + m_mouseState.dy * m_mouseState.dy >= MOUSE_MINIMUM_MOVEMENT * MOUSE_MINIMUM_MOVEMENT);
197 }
198
199 CPoint CMouse::GetLocation() const
200 {
201   return CPoint((float)m_mouseState.x, (float)m_mouseState.y);
202 }
203
204 void CMouse::SetLocation(const CPoint &point, bool activate)
205 {
206   m_mouseState.x = (int)point.x;
207   m_mouseState.y = (int)point.y;
208   if (activate)
209   {
210     m_lastActiveTime = timeGetTime();
211     m_mouseState.active = true;
212   }
213 }
214
215 CPoint CMouse::GetLastMove() const
216 {
217   return CPoint(m_mouseState.dx, m_mouseState.dy);
218 }
219
220 char CMouse::GetWheel() const
221 {
222   return m_mouseState.dz;
223 }
224
225 void CMouse::UpdateMouseWheel(char dir)
226 {
227   m_mouseState.dz = dir;
228   m_mouseState.active = true;
229   m_lastActiveTime = timeGetTime();
230 }
231
232 void CMouse::SetExclusiveAccess(DWORD dwControlID, DWORD dwWindowID, const CPoint &point)
233 {
234   m_exclusiveControlID = dwControlID;
235   m_exclusiveWindowID = dwWindowID;
236   // convert posX, posY to screen coords...
237   // NOTE: This relies on the window resolution having been set correctly beforehand in CGUIWindow::OnMouseAction()
238   CPoint mouseCoords(GetLocation());
239   g_graphicsContext.InvertFinalCoords(mouseCoords.x, mouseCoords.y);
240   m_exclusiveOffset = point - mouseCoords;
241 }
242
243 void CMouse::EndExclusiveAccess(DWORD dwControlID, DWORD dwWindowID)
244 {
245   if (m_exclusiveControlID == dwControlID && m_exclusiveWindowID == dwWindowID)
246     SetExclusiveAccess(WINDOW_INVALID, WINDOW_INVALID, CPoint(0, 0));
247 }
248
249 void CMouse::Acquire()
250 {
251   if (m_mouseDevice)
252     m_mouseDevice->Acquire();
253 }
254