1 /*
2  *  Copyright (C) 2005-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #pragma once
10 
11 #include "windowing/XBMC_events.h"
12 
13 #define XBMC_BUTTON(X) (1 << ((X)-1))
14 #define XBMC_BUTTON_LEFT 1
15 #define XBMC_BUTTON_MIDDLE 2
16 #define XBMC_BUTTON_RIGHT 3
17 #define XBMC_BUTTON_WHEELUP 4
18 #define XBMC_BUTTON_WHEELDOWN 5
19 #define XBMC_BUTTON_X1 6
20 #define XBMC_BUTTON_X2 7
21 #define XBMC_BUTTON_X3 8
22 #define XBMC_BUTTON_X4 9
23 #define XBMC_BUTTON_LMASK XBMC_BUTTON(XBMC_BUTTON_LEFT)
24 #define XBMC_BUTTON_MMASK XBMC_BUTTON(XBMC_BUTTON_MIDDLE)
25 #define XBMC_BUTTON_RMASK XBMC_BUTTON(XBMC_BUTTON_RIGHT)
26 #define XBMC_BUTTON_X1MASK XBMC_BUTTON(XBMC_BUTTON_X1)
27 #define XBMC_BUTTON_X2MASK XBMC_BUTTON(XBMC_BUTTON_X2)
28 #define XBMC_BUTTON_X3MASK XBMC_BUTTON(XBMC_BUTTON_X3)
29 #define XBMC_BUTTON_X4MASK XBMC_BUTTON(XBMC_BUTTON_X4)
30 
31 #define MOUSE_MINIMUM_MOVEMENT 2
32 #define MOUSE_DOUBLE_CLICK_LENGTH 500L
33 #define MOUSE_ACTIVE_LENGTH 5000L
34 
35 #define MOUSE_MAX_BUTTON 7
36 
37 enum MOUSE_STATE
38 {
39   MOUSE_STATE_NORMAL = 1, /*! < Normal state */
40   MOUSE_STATE_FOCUS, /*! < Control below the mouse is currently in focus */
41   MOUSE_STATE_DRAG, /*! < A drag operation is being performed */
42   MOUSE_STATE_CLICK /*! < A mousebutton is being clicked */
43 };
44 
45 enum MOUSE_BUTTON
46 {
47   MOUSE_LEFT_BUTTON = 0,
48   MOUSE_RIGHT_BUTTON,
49   MOUSE_MIDDLE_BUTTON,
50   MOUSE_EXTRA_BUTTON1,
51   MOUSE_EXTRA_BUTTON2,
52   MOUSE_EXTRA_BUTTON3,
53   MOUSE_EXTRA_BUTTON4
54 };
55 
56 // this holds everything we know about the current state of the mouse
57 struct MouseState
58 {
59   int x; // x location
60   int y; // y location
61   int16_t dx; // change in x
62   int16_t dy; // change in y
63   int8_t dz; // change in z (wheel)
64   bool button[MOUSE_MAX_BUTTON]; // current state of the buttons
65   bool active; // true if the mouse is active
66 };
67 
68 struct MousePosition
69 {
70   int x;
71   int y;
72 };
73 
74 class CAction;
75 
76 class CMouseStat
77 {
78 public:
79   CMouseStat();
80   virtual ~CMouseStat();
81 
82   void Initialize();
83   void HandleEvent(XBMC_Event& newEvent);
84   void SetResolution(int maxX, int maxY, float speedX, float speedY);
85   bool IsActive();
86   bool IsEnabled() const;
87 
88   void SetActive(bool active = true);
SetState(MOUSE_STATE state)89   void SetState(MOUSE_STATE state) { m_pointerState = state; };
90   void SetEnabled(bool enabled = true);
GetState()91   MOUSE_STATE GetState() const { return m_pointerState; };
92   uint32_t GetKey() const;
93 
94   int GetHold(int ButtonID) const;
GetX(void)95   inline int GetX(void) const { return m_mouseState.x; }
GetY(void)96   inline int GetY(void) const { return m_mouseState.y; }
GetDX(void)97   inline int GetDX(void) const { return m_mouseState.dx; }
GetDY(void)98   inline int GetDY(void) const { return m_mouseState.dy; }
GetPosition()99   MousePosition GetPosition() { return MousePosition{m_mouseState.x, m_mouseState.y}; }
100 
101 private:
102   /*! \brief Holds information regarding a particular mouse button state
103 
104    The CButtonState class is used to track where in a button event the mouse currently is.
105    There is effectively 5 BUTTON_STATE's available, and transitioning between those states
106    is handled by the Update() function.
107 
108    The actions we detect are:
109     * short clicks - down/up press of the mouse within short_click_time ms, where the pointer stays
110       within click_confines pixels
111     * long clicks - down/up press of the mouse greater than short_click_time ms, where the pointers
112       stays within click_confines pixels
113     * double clicks - a further down press of the mouse within double_click_time of the up press of
114       a short click, where the pointer stays within click_confines pixels
115     * drag - the mouse is down and has been moved more than click_confines pixels
116 
117    \sa CMouseStat
118   */
119   class CButtonState
120   {
121   public:
122     /*! \brief enum for the actions to perform as a result of an Update function
123      */
124     enum BUTTON_ACTION
125     {
126       MB_NONE = 0, ///< no action should occur
127       MB_SHORT_CLICK, ///< a short click has occurred (a double click may be in process)
128       MB_LONG_CLICK, ///< a long click has occurred
129       MB_DOUBLE_CLICK, ///< a double click has occurred
130       MB_DRAG_START, ///< a drag action has started
131       MB_DRAG, ///< a drag action is in progress
132       MB_DRAG_END
133     }; ///< a drag action has finished
134 
135     CButtonState();
136 
137     /*! \brief Update the button state, with where the mouse is, and whether the button is down or
138      not
139 
140      \param time frame time in ms
141      \param x horizontal coordinate of the mouse
142      \param y vertical coordinate of the mouse
143      \param down true if the button is down
144      \return action that should be performed
145      */
146     BUTTON_ACTION Update(unsigned int time, int x, int y, bool down);
147 
148   private:
149     //! number of pixels that the pointer may move while the button is down to
150     //! trigger a click
151     static const unsigned int click_confines = 5;
152 
153     //! Time for mouse down/up to trigger a short click rather than a long click
154     static const unsigned int short_click_time = 1000;
155 
156     //! Time for mouse down following a short click to trigger a double click
157     static const unsigned int double_click_time = 500;
158 
159     bool InClickRange(int x, int y) const;
160 
161     enum BUTTON_STATE
162     {
163       STATE_RELEASED = 0, ///< mouse button is released, no events pending
164       STATE_IN_CLICK, ///< mouse button is down, a click is pending
165       STATE_IN_DOUBLE_CLICK, ///< mouse button is released, pending double click
166       STATE_IN_DOUBLE_IGNORE, ///< mouse button is down following double click
167       STATE_IN_DRAG
168     }; ///< mouse button is down during a drag
169 
170     BUTTON_STATE m_state;
171     unsigned int m_time;
172     int m_x;
173     int m_y;
174   };
175 
176   /*! \brief detect whether the mouse has moved
177 
178    Uses a trigger threshold of 2 pixels to detect mouse movement
179 
180    \return whether the mouse has moved past the trigger threshold.
181    */
182   bool MovedPastThreshold() const;
183 
184   // state of the mouse
185   MOUSE_STATE m_pointerState;
186   MouseState m_mouseState;
187   bool m_mouseEnabled;
188   CButtonState m_buttonState[MOUSE_MAX_BUTTON];
189 
190   int m_maxX;
191   int m_maxY;
192   float m_speedX;
193   float m_speedY;
194 
195   // active/click timers
196   unsigned int m_lastActiveTime;
197 
198   bool bClick[MOUSE_MAX_BUTTON];
199   bool bDoubleClick[MOUSE_MAX_BUTTON];
200   int bHold[MOUSE_MAX_BUTTON];
201   bool bLongClick[MOUSE_MAX_BUTTON];
202 
203   uint32_t m_Key;
204 };
205