1 /**
2 * Copyright (c) 2006-2019 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21 // LOVE
22 #include "Mouse.h"
23 #include "window/sdl/Window.h"
24
25 // SDL
26 #include <SDL_mouse.h>
27
28 namespace love
29 {
30 namespace mouse
31 {
32 namespace sdl
33 {
34
35 // SDL reports mouse coordinates in the window coordinate system in OS X, but
36 // we want them in pixel coordinates (may be different with high-DPI enabled.)
windowToDPICoords(double * x,double * y)37 static void windowToDPICoords(double *x, double *y)
38 {
39 auto window = Module::getInstance<window::Window>(Module::M_WINDOW);
40 if (window)
41 window->windowToDPICoords(x, y);
42 }
43
44 // And vice versa for setting mouse coordinates.
DPIToWindowCoords(double * x,double * y)45 static void DPIToWindowCoords(double *x, double *y)
46 {
47 auto window = Module::getInstance<window::Window>(Module::M_WINDOW);
48 if (window)
49 window->DPIToWindowCoords(x, y);
50 }
51
getName() const52 const char *Mouse::getName() const
53 {
54 return "love.mouse.sdl";
55 }
56
Mouse()57 Mouse::Mouse()
58 : curCursor(nullptr)
59 {
60 // SDL may need the video subsystem in order to clean up the cursor when
61 // quitting. Subsystems are reference-counted.
62 SDL_InitSubSystem(SDL_INIT_VIDEO);
63 }
64
~Mouse()65 Mouse::~Mouse()
66 {
67 if (curCursor.get())
68 setCursor();
69
70 for (auto &c : systemCursors)
71 c.second->release();
72
73 SDL_QuitSubSystem(SDL_INIT_VIDEO);
74 }
75
newCursor(love::image::ImageData * data,int hotx,int hoty)76 love::mouse::Cursor *Mouse::newCursor(love::image::ImageData *data, int hotx, int hoty)
77 {
78 return new Cursor(data, hotx, hoty);
79 }
80
getSystemCursor(Cursor::SystemCursor cursortype)81 love::mouse::Cursor *Mouse::getSystemCursor(Cursor::SystemCursor cursortype)
82 {
83 Cursor *cursor = nullptr;
84 auto it = systemCursors.find(cursortype);
85
86 if (it != systemCursors.end())
87 cursor = it->second;
88 else
89 {
90 cursor = new Cursor(cursortype);
91 systemCursors[cursortype] = cursor;
92 }
93
94 return cursor;
95 }
96
setCursor(love::mouse::Cursor * cursor)97 void Mouse::setCursor(love::mouse::Cursor *cursor)
98 {
99 curCursor.set(cursor);
100 SDL_SetCursor((SDL_Cursor *) cursor->getHandle());
101 }
102
setCursor()103 void Mouse::setCursor()
104 {
105 curCursor.set(nullptr);
106 SDL_SetCursor(SDL_GetDefaultCursor());
107 }
108
getCursor() const109 love::mouse::Cursor *Mouse::getCursor() const
110 {
111 return curCursor.get();
112 }
113
114
isCursorSupported() const115 bool Mouse::isCursorSupported() const
116 {
117 return SDL_GetDefaultCursor() != nullptr;
118 }
119
getX() const120 double Mouse::getX() const
121 {
122 int x;
123 SDL_GetMouseState(&x, nullptr);
124
125 double dx = (double) x;
126 windowToDPICoords(&dx, nullptr);
127
128 return dx;
129 }
130
getY() const131 double Mouse::getY() const
132 {
133 int y;
134 SDL_GetMouseState(nullptr, &y);
135
136 double dy = (double) y;
137 windowToDPICoords(nullptr, &dy);
138
139 return dy;
140 }
141
getPosition(double & x,double & y) const142 void Mouse::getPosition(double &x, double &y) const
143 {
144 int mx, my;
145 SDL_GetMouseState(&mx, &my);
146
147 x = (double) mx;
148 y = (double) my;
149 windowToDPICoords(&x, &y);
150 }
151
setPosition(double x,double y)152 void Mouse::setPosition(double x, double y)
153 {
154 auto window = Module::getInstance<window::Window>(Module::M_WINDOW);
155
156 SDL_Window *handle = nullptr;
157 if (window)
158 handle = (SDL_Window *) window->getHandle();
159
160 DPIToWindowCoords(&x, &y);
161 SDL_WarpMouseInWindow(handle, (int) x, (int) y);
162
163 // SDL_WarpMouse doesn't directly update SDL's internal mouse state in Linux
164 // and Windows, so we call SDL_PumpEvents now to make sure the next
165 // getPosition call always returns the updated state.
166 SDL_PumpEvents();
167 }
168
setX(double x)169 void Mouse::setX(double x)
170 {
171 setPosition(x, getY());
172 }
173
setY(double y)174 void Mouse::setY(double y)
175 {
176 setPosition(getX(), y);
177 }
178
setVisible(bool visible)179 void Mouse::setVisible(bool visible)
180 {
181 SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE);
182 }
183
isDown(const std::vector<int> & buttons) const184 bool Mouse::isDown(const std::vector<int> &buttons) const
185 {
186 Uint32 buttonstate = SDL_GetMouseState(nullptr, nullptr);
187
188 for (int button : buttons)
189 {
190 if (button <= 0)
191 continue;
192
193 // We use button index 2 to represent the right mouse button, but SDL
194 // uses 2 to represent the middle mouse button.
195 switch (button)
196 {
197 case 2:
198 button = SDL_BUTTON_RIGHT;
199 break;
200 case 3:
201 button = SDL_BUTTON_MIDDLE;
202 break;
203 }
204
205 if (buttonstate & SDL_BUTTON(button))
206 return true;
207 }
208
209 return false;
210 }
211
isVisible() const212 bool Mouse::isVisible() const
213 {
214 return SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE;
215 }
216
setGrabbed(bool grab)217 void Mouse::setGrabbed(bool grab)
218 {
219 auto window = Module::getInstance<window::Window>(Module::M_WINDOW);
220 if (window)
221 window->setMouseGrab(grab);
222 }
223
isGrabbed() const224 bool Mouse::isGrabbed() const
225 {
226 auto window = Module::getInstance<window::Window>(Module::M_WINDOW);
227 if (window)
228 return window->isMouseGrabbed();
229 else
230 return false;
231 }
232
setRelativeMode(bool relative)233 bool Mouse::setRelativeMode(bool relative)
234 {
235 return SDL_SetRelativeMouseMode(relative ? SDL_TRUE : SDL_FALSE) == 0;
236 }
237
getRelativeMode() const238 bool Mouse::getRelativeMode() const
239 {
240 return SDL_GetRelativeMouseMode() != SDL_FALSE;
241 }
242
243 } // sdl
244 } // mouse
245 } // love
246