Merge pull request #4594 from FernetMenta/paplayer
[xbmc.git] / xbmc / input / MouseStat.cpp
blobfb27d92687312827080f29143a511c091553e6ab
1 /*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
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.
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.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "MouseStat.h"
22 #include "guilib/Key.h"
23 #include "settings/lib/Setting.h"
24 #include "utils/TimeUtils.h"
25 #include "windowing/WindowingFactory.h"
27 CMouseStat::CMouseStat()
29 m_pointerState = MOUSE_STATE_NORMAL;
30 SetEnabled();
31 m_speedX = m_speedY = 0;
32 m_maxX = m_maxY = 0;
33 memset(&m_mouseState, 0, sizeof(m_mouseState));
34 m_Action = ACTION_NOOP;
37 CMouseStat::~CMouseStat()
41 void CMouseStat::OnSettingChanged(const CSetting *setting)
43 if (setting == NULL)
44 return;
46 const std::string &settingId = setting->GetId();
47 if (settingId == "input.enablemouse")
48 SetEnabled(((CSettingBool*)setting)->GetValue());
51 void CMouseStat::Initialize()
53 // Set the default resolution (PAL)
54 SetResolution(720, 576, 1, 1);
57 void CMouseStat::HandleEvent(XBMC_Event& newEvent)
59 // Save the mouse position and the size of the last move
60 int dx, dy;
61 if (newEvent.type == XBMC_MOUSEMOTION)
63 dx = newEvent.motion.x - m_mouseState.x;
64 dy = newEvent.motion.y - m_mouseState.y;
66 else if (newEvent.type == XBMC_MOUSEBUTTONDOWN || newEvent.type == XBMC_MOUSEBUTTONUP)
68 dx = newEvent.button.x - m_mouseState.x;
69 dy = newEvent.button.y - m_mouseState.y;
71 else
73 return;
75 m_mouseState.dx = dx;
76 m_mouseState.dy = dy;
77 m_mouseState.x = std::max(0, std::min(m_maxX, m_mouseState.x + dx));
78 m_mouseState.y = std::max(0, std::min(m_maxY, m_mouseState.y + dy));
80 // Fill in the public members
81 if (newEvent.button.type == XBMC_MOUSEBUTTONDOWN)
83 if (newEvent.button.button == XBMC_BUTTON_LEFT) m_mouseState.button[MOUSE_LEFT_BUTTON] = true;
84 if (newEvent.button.button == XBMC_BUTTON_RIGHT) m_mouseState.button[MOUSE_RIGHT_BUTTON] = true;
85 if (newEvent.button.button == XBMC_BUTTON_MIDDLE) m_mouseState.button[MOUSE_MIDDLE_BUTTON] = true;
86 if (newEvent.button.button == XBMC_BUTTON_X1) m_mouseState.button[MOUSE_EXTRA_BUTTON1] = true;
87 if (newEvent.button.button == XBMC_BUTTON_X2) m_mouseState.button[MOUSE_EXTRA_BUTTON2] = true;
88 if (newEvent.button.button == XBMC_BUTTON_WHEELUP) m_mouseState.dz = 1;
89 if (newEvent.button.button == XBMC_BUTTON_WHEELDOWN) m_mouseState.dz = -1;
91 else if (newEvent.button.type == XBMC_MOUSEBUTTONUP)
93 if (newEvent.button.button == XBMC_BUTTON_LEFT) m_mouseState.button[MOUSE_LEFT_BUTTON] = false;
94 if (newEvent.button.button == XBMC_BUTTON_RIGHT) m_mouseState.button[MOUSE_RIGHT_BUTTON] = false;
95 if (newEvent.button.button == XBMC_BUTTON_MIDDLE) m_mouseState.button[MOUSE_MIDDLE_BUTTON] = false;
96 if (newEvent.button.button == XBMC_BUTTON_X1) m_mouseState.button[MOUSE_EXTRA_BUTTON1] = false;
97 if (newEvent.button.button == XBMC_BUTTON_X2) m_mouseState.button[MOUSE_EXTRA_BUTTON2] = false;
98 if (newEvent.button.button == XBMC_BUTTON_WHEELUP) m_mouseState.dz = 0;
99 if (newEvent.button.button == XBMC_BUTTON_WHEELDOWN) m_mouseState.dz = 0;
102 // Now check the current message and the previous state to find out if
103 // this is a click, doubleclick, drag etc
104 uint32_t now = CTimeUtils::GetFrameTime();
105 bool bNothingDown = true;
107 for (int i = 0; i < 5; i++)
109 bClick[i] = false;
110 bDoubleClick[i] = false;
111 bHold[i] = 0;
113 // CButtonState::Update does the hard work of checking the button state
114 // and spotting drags, doubleclicks etc
115 CButtonState::BUTTON_ACTION action = m_buttonState[i].Update(now, m_mouseState.x, m_mouseState.y, m_mouseState.button[i]);
116 switch (action)
118 case CButtonState::MB_SHORT_CLICK:
119 case CButtonState::MB_LONG_CLICK:
120 bClick[i] = true;
121 bNothingDown = false;
122 break;
123 case CButtonState::MB_DOUBLE_CLICK:
124 bDoubleClick[i] = true;
125 bNothingDown = false;
126 break;
127 case CButtonState::MB_DRAG_START:
128 case CButtonState::MB_DRAG:
129 case CButtonState::MB_DRAG_END:
130 bHold[i] = action - CButtonState::MB_DRAG_START + 1;
131 bNothingDown = false;
132 break;
133 default:
134 break;
138 // Now work out what action ID to send to XBMC.
139 // The bClick array is set true if CButtonState::Update spots a click
140 // i.e. a button down followed by a button up.
141 if (bClick[MOUSE_LEFT_BUTTON])
142 m_Action = ACTION_MOUSE_LEFT_CLICK;
143 else if (bClick[MOUSE_RIGHT_BUTTON])
144 m_Action = ACTION_MOUSE_RIGHT_CLICK;
145 else if (bClick[MOUSE_MIDDLE_BUTTON])
146 m_Action = ACTION_MOUSE_MIDDLE_CLICK;
148 // The bDoubleClick array is set true if CButtonState::Update spots a
149 // button down within double_click_time (500ms) of the last click
150 else if (bDoubleClick[MOUSE_LEFT_BUTTON])
151 m_Action = ACTION_MOUSE_DOUBLE_CLICK;
153 // The bHold array is set true if CButtonState::Update spots a mouse drag
154 else if (bHold[MOUSE_LEFT_BUTTON])
155 m_Action = ACTION_MOUSE_DRAG;
157 // dz is +1 on wheel up and -1 on wheel down
158 else if (m_mouseState.dz > 0)
159 m_Action = ACTION_MOUSE_WHEEL_UP;
160 else if (m_mouseState.dz < 0)
161 m_Action = ACTION_MOUSE_WHEEL_DOWN;
163 // Finally check for a mouse move (that isn't a drag)
164 else if (newEvent.type == XBMC_MOUSEMOTION)
165 m_Action = ACTION_MOUSE_MOVE;
167 // ignore any other mouse messages
168 else
169 m_Action = ACTION_NOOP;
171 // activate the mouse pointer if we have an action or the mouse has moved far enough
172 if ((MovedPastThreshold() && m_Action == ACTION_MOUSE_MOVE) ||
173 (m_Action != ACTION_NOOP && m_Action != ACTION_MOUSE_MOVE))
174 SetActive();
176 // reset the mouse state if nothing is held down
177 if (bNothingDown)
178 SetState(MOUSE_STATE_NORMAL);
181 void CMouseStat::SetResolution(int maxX, int maxY, float speedX, float speedY)
183 m_maxX = maxX;
184 m_maxY = maxY;
186 // speed is currently unused
187 m_speedX = speedX;
188 m_speedY = speedY;
191 void CMouseStat::SetActive(bool active /*=true*/)
193 m_lastActiveTime = CTimeUtils::GetFrameTime();
194 m_mouseState.active = active;
195 // we show the OS mouse if:
196 // 1. The mouse is active (it has been moved) AND
197 // 2. The XBMC mouse is disabled in settings AND
198 // 3. XBMC is not in fullscreen.
199 g_Windowing.ShowOSMouse(m_mouseState.active && !IsEnabled() && !g_Windowing.IsFullScreen());
202 // IsActive - returns true if we have been active in the last MOUSE_ACTIVE_LENGTH period
203 bool CMouseStat::IsActive()
205 if (m_mouseState.active && (CTimeUtils::GetFrameTime() - m_lastActiveTime > MOUSE_ACTIVE_LENGTH))
206 SetActive(false);
207 return (m_mouseState.active && IsEnabled());
210 void CMouseStat::SetEnabled(bool enabled)
212 m_mouseEnabled = enabled;
213 SetActive(enabled);
216 // IsEnabled - returns true if mouse is enabled
217 bool CMouseStat::IsEnabled() const
219 return m_mouseEnabled;
222 bool CMouseStat::MovedPastThreshold() const
224 return (m_mouseState.dx * m_mouseState.dx + m_mouseState.dy * m_mouseState.dy >= MOUSE_MINIMUM_MOVEMENT * MOUSE_MINIMUM_MOVEMENT);
227 uint32_t CMouseStat::GetAction() const
229 return m_Action;
232 int CMouseStat::GetHold(int ButtonID) const
234 switch (ButtonID)
235 { case MOUSE_LEFT_BUTTON:
236 return bHold[MOUSE_LEFT_BUTTON];
238 return false;
241 CMouseStat::CButtonState::CButtonState()
243 m_state = STATE_RELEASED;
244 m_time = 0;
245 m_x = 0;
246 m_y = 0;
249 bool CMouseStat::CButtonState::InClickRange(int x, int y) const
251 int dx = x - m_x;
252 int dy = y - m_y;
253 return (unsigned int)(dx*dx + dy*dy) <= click_confines*click_confines;
256 CMouseStat::CButtonState::BUTTON_ACTION CMouseStat::CButtonState::Update(unsigned int time, int x, int y, bool down)
258 if (m_state == STATE_IN_DRAG)
260 if (down)
261 return MB_DRAG;
262 m_state = STATE_RELEASED;
263 return MB_DRAG_END;
265 else if (m_state == STATE_RELEASED)
267 if (down)
269 m_state = STATE_IN_CLICK;
270 m_time = time;
271 m_x = x;
272 m_y = y;
275 else if (m_state == STATE_IN_CLICK)
277 if (down)
279 if (!InClickRange(x,y))
280 { // beginning a drag
281 m_state = STATE_IN_DRAG;
282 return MB_DRAG_START;
285 else
286 { // button up
287 if (time - m_time < short_click_time)
288 { // single click
289 m_state = STATE_IN_DOUBLE_CLICK;
290 m_time = time; // double click time and positioning is measured from the
291 m_x = x; // end of a single click
292 m_y = y;
293 return MB_SHORT_CLICK;
295 else
296 { // long click
297 m_state = STATE_RELEASED;
298 return MB_LONG_CLICK;
302 else if (m_state == STATE_IN_DOUBLE_CLICK)
304 if (time - m_time > double_click_time || !InClickRange(x,y))
305 { // too long, or moved to much - reset to released state and re-update, as we may be starting a new click
306 m_state = STATE_RELEASED;
307 return Update(time, x, y, down);
309 if (down)
311 m_state = STATE_IN_DOUBLE_IGNORE;
312 return MB_DOUBLE_CLICK;
315 else if (m_state == STATE_IN_DOUBLE_IGNORE)
317 if (!down)
318 m_state = STATE_RELEASED;
321 return MB_NONE;