1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * Windows mouse driver.
12 *
13 * By Milan Mimica.
14 *
15 * See readme.txt for copyright information.
16 */
17
18 #if 0
19 /* Raw input */
20 #define _WIN32_WINNT 0x0501
21 #ifndef WINVER
22 #define WINVER 0x0600
23 #endif
24 #endif
25 #include <windows.h>
26
27 /*
28 * Even the most recent MinGW at the moment of writing this is missing
29 * this symbol.
30 */
31 #ifndef SM_MOUSEHORIZONTALWHEELPRESENT
32 #define SM_MOUSEHORIZONTALWHEELPRESENT 91
33 #endif
34
35 #include "allegro5/allegro.h"
36 #include "allegro5/internal/aintern.h"
37 #include "allegro5/internal/aintern_driver.h"
38 #include "allegro5/internal/aintern_mouse.h"
39 #include "allegro5/platform/aintwin.h"
40 #include "allegro5/internal/aintern_display.h"
41
42 static ALLEGRO_MOUSE_STATE mouse_state;
43 static ALLEGRO_MOUSE the_mouse;
44 static bool installed = false;
45
46 // The raw versions of z/w in the mouse_state. They are related to them by a scaling constant.
47 static int raw_mouse_z = 0;
48 static int raw_mouse_w = 0;
49
50
init_mouse(void)51 static bool init_mouse(void)
52 {
53 ALLEGRO_DISPLAY *display;
54
55 if (installed)
56 return false;
57
58 /* If the display was created before the mouse is installed and the mouse
59 * cursor is initially within the window, then the display field has correct
60 * and useful info so don't clobber it.
61 */
62 display = mouse_state.display;
63 memset(&mouse_state, 0, sizeof(mouse_state));
64 mouse_state.display = display;
65
66 _al_event_source_init(&the_mouse.es);
67
68 #if 0
69 if (al_get_new_display_flags() & ALLEGRO_FULLSCREEN) {
70 RAWINPUTDEVICE rid[1];
71 rid[0].usUsagePage = 0x01;
72 rid[0].usUsage = 0x02;
73 rid[0].dwFlags = RIDEV_NOLEGACY;
74 rid[0].hwndTarget = 0;
75 if (RegisterRawInputDevices(rid, 1, sizeof(rid[0])) == FALSE) {
76 return false;
77 }
78 }
79 #endif
80
81 installed = true;
82
83 return true;
84 }
85
86
exit_mouse(void)87 static void exit_mouse(void)
88 {
89 if (!installed)
90 return;
91
92 memset(&mouse_state, 0, sizeof(mouse_state));
93 _al_event_source_free(&the_mouse.es);
94 installed = false;
95 }
96
97
generate_mouse_event(unsigned int type,int x,int y,int z,int w,float pressure,int dx,int dy,int dz,int dw,unsigned int button,ALLEGRO_DISPLAY * source)98 static void generate_mouse_event(unsigned int type,
99 int x, int y, int z, int w, float pressure,
100 int dx, int dy, int dz, int dw,
101 unsigned int button,
102 ALLEGRO_DISPLAY *source)
103 {
104 ALLEGRO_EVENT event;
105
106 if (!_al_event_source_needs_to_generate_event(&the_mouse.es))
107 return;
108
109 _al_event_source_lock(&the_mouse.es);
110 event.mouse.type = type;
111 event.mouse.timestamp = al_get_time();
112 event.mouse.display = source;
113 event.mouse.x = x;
114 event.mouse.y = y;
115 event.mouse.z = z;
116 event.mouse.w = w;
117 event.mouse.dx = dx;
118 event.mouse.dy = dy;
119 event.mouse.dz = dz;
120 event.mouse.dw = dw;
121 event.mouse.button = button;
122 event.mouse.pressure = pressure;
123 _al_event_source_emit_event(&the_mouse.es, &event);
124 _al_event_source_unlock(&the_mouse.es);
125 }
126
127
get_mouse(void)128 static ALLEGRO_MOUSE* get_mouse(void)
129 {
130 return &the_mouse;
131 }
132
133
get_num_buttons(void)134 static unsigned int get_num_buttons(void)
135 {
136 return GetSystemMetrics(SM_CMOUSEBUTTONS);
137 }
138
139
get_num_axes(void)140 static unsigned int get_num_axes(void)
141 {
142 bool x = GetSystemMetrics(SM_MOUSEHORIZONTALWHEELPRESENT);
143 bool z = GetSystemMetrics(SM_MOUSEWHEELPRESENT);
144 if (x && z)
145 return 4;
146 if (x || z)
147 return 3;
148 return 2;
149 }
150
151
set_mouse_xy(ALLEGRO_DISPLAY * disp,int x,int y)152 static bool set_mouse_xy(ALLEGRO_DISPLAY *disp, int x, int y)
153 {
154 int dx, dy;
155 POINT pt;
156 ALLEGRO_DISPLAY_WIN *win_disp = (void*)disp;
157
158 if (!installed)
159 return false;
160
161 dx = x - mouse_state.x;
162 dy = y - mouse_state.y;
163
164 if (dx || dy) {
165 mouse_state.x = x;
166 mouse_state.y = y;
167
168 generate_mouse_event(
169 ALLEGRO_EVENT_MOUSE_WARPED,
170 mouse_state.x, mouse_state.y, mouse_state.z, mouse_state.w, mouse_state.pressure,
171 dx, dy, 0, 0,
172 0, (void*)win_disp);
173 }
174
175 pt.x = x;
176 pt.y = y;
177
178 ClientToScreen(win_disp->window, &pt);
179
180 SetCursorPos(pt.x, pt.y);
181
182 return true;
183 }
184
185
set_mouse_axis(int which,int val)186 static bool set_mouse_axis(int which, int val)
187 {
188 /* Vertical mouse wheel. */
189 if (which == 2) {
190 int dz = (val - mouse_state.z);
191
192 raw_mouse_z = WHEEL_DELTA * val / al_get_mouse_wheel_precision();
193
194 if (dz != 0) {
195 mouse_state.z = val;
196
197 generate_mouse_event(
198 ALLEGRO_EVENT_MOUSE_AXES,
199 mouse_state.x, mouse_state.y, mouse_state.z, mouse_state.w, mouse_state.pressure,
200 0, 0, dz, 0,
201 0, mouse_state.display);
202 }
203
204 return true;
205 }
206
207 /* Horizontal mouse wheel. */
208 if (which == 3) {
209 int dw = (val - mouse_state.w);
210
211 raw_mouse_w = WHEEL_DELTA * val / al_get_mouse_wheel_precision();
212
213 if (dw != 0) {
214 mouse_state.w = val;
215
216 generate_mouse_event(
217 ALLEGRO_EVENT_MOUSE_AXES,
218 mouse_state.x, mouse_state.y, mouse_state.z, mouse_state.w, mouse_state.pressure,
219 0, 0, 0, dw,
220 0, mouse_state.display);
221 }
222
223 return true;
224 }
225
226 return false;
227 }
228
229
get_mouse_state(ALLEGRO_MOUSE_STATE * ret_state)230 static void get_mouse_state(ALLEGRO_MOUSE_STATE *ret_state)
231 {
232 _al_event_source_lock(&the_mouse.es);
233 *ret_state = mouse_state;
234 _al_event_source_unlock(&the_mouse.es);
235 }
236
237
238 /* the driver vtable */
239 #define MOUSE_WINAPI AL_ID('W','A','P','I')
240
241 static ALLEGRO_MOUSE_DRIVER mousedrv_winapi =
242 {
243 MOUSE_WINAPI,
244 "",
245 "",
246 "WinAPI mouse",
247 init_mouse,
248 exit_mouse,
249 get_mouse,
250 get_num_buttons,
251 get_num_axes,
252 set_mouse_xy,
253 set_mouse_axis,
254 get_mouse_state
255 };
256
257
258 _AL_DRIVER_INFO _al_mouse_driver_list[] =
259 {
260 {MOUSE_WINAPI, &mousedrv_winapi, true},
261 {0, NULL, 0}
262 };
263
264
_al_win_mouse_handle_leave(ALLEGRO_DISPLAY_WIN * win_disp)265 void _al_win_mouse_handle_leave(ALLEGRO_DISPLAY_WIN *win_disp)
266 {
267 /* The state should be updated even if the mouse is not installed so that
268 * it will be correct if the mouse is installed later.
269 */
270 if (mouse_state.display == (void*)win_disp)
271 mouse_state.display = NULL;
272
273 if (!installed)
274 return;
275
276 generate_mouse_event(ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY,
277 mouse_state.x, mouse_state.y, mouse_state.z, mouse_state.w, mouse_state.pressure,
278 0, 0, 0, 0,
279 0, (void*)win_disp);
280 }
281
282
_al_win_mouse_handle_enter(ALLEGRO_DISPLAY_WIN * win_disp)283 void _al_win_mouse_handle_enter(ALLEGRO_DISPLAY_WIN *win_disp)
284 {
285 /* The state should be updated even if the mouse is not installed so that
286 * it will be correct if the mouse is installed later.
287 */
288 mouse_state.display = (void*)win_disp;
289
290 if (!installed)
291 return;
292
293 generate_mouse_event(ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY,
294 mouse_state.x, mouse_state.y, mouse_state.z, mouse_state.w, mouse_state.pressure,
295 0, 0, 0, 0,
296 0, (void*)win_disp);
297 }
298
299
_al_win_mouse_handle_move(int x,int y,bool abs,ALLEGRO_DISPLAY_WIN * win_disp)300 void _al_win_mouse_handle_move(int x, int y, bool abs, ALLEGRO_DISPLAY_WIN *win_disp)
301 {
302 int dx, dy;
303 int oldx, oldy;
304
305 oldx = mouse_state.x;
306 oldy = mouse_state.y;
307
308 if (!installed)
309 return;
310
311 if (!abs) {
312 mouse_state.x += x;
313 mouse_state.y += y;
314 dx = x;
315 dy = y;
316 }
317 else {
318 dx = x - mouse_state.x;
319 dy = y - mouse_state.y;
320 mouse_state.x = x;
321 mouse_state.y = y;
322 }
323
324 if (oldx != mouse_state.x || oldy != mouse_state.y) {
325 generate_mouse_event(ALLEGRO_EVENT_MOUSE_AXES,
326 mouse_state.x, mouse_state.y, mouse_state.z, mouse_state.w, mouse_state.pressure,
327 dx, dy, 0, 0,
328 0, (void*)win_disp);
329 }
330 }
331
332
_al_win_mouse_handle_wheel(int raw_dz,bool abs,ALLEGRO_DISPLAY_WIN * win_disp)333 void _al_win_mouse_handle_wheel(int raw_dz, bool abs, ALLEGRO_DISPLAY_WIN *win_disp)
334 {
335 int d;
336 int new_z;
337
338 if (!installed)
339 return;
340
341 if (!abs) {
342 raw_mouse_z += raw_dz;
343 }
344 else {
345 raw_mouse_z = raw_dz;
346 }
347
348 new_z = al_get_mouse_wheel_precision() * raw_mouse_z / WHEEL_DELTA;
349 d = new_z - mouse_state.z;
350 mouse_state.z = new_z;
351
352 generate_mouse_event(ALLEGRO_EVENT_MOUSE_AXES,
353 mouse_state.x, mouse_state.y, mouse_state.z, mouse_state.w, mouse_state.pressure,
354 0, 0, d, 0,
355 0, (void*)win_disp);
356 }
357
358
_al_win_mouse_handle_hwheel(int raw_dw,bool abs,ALLEGRO_DISPLAY_WIN * win_disp)359 void _al_win_mouse_handle_hwheel(int raw_dw, bool abs, ALLEGRO_DISPLAY_WIN *win_disp)
360 {
361 int d;
362 int new_w;
363
364 if (!installed)
365 return;
366
367 if (!abs) {
368 raw_mouse_w += raw_dw;
369 }
370 else {
371 raw_mouse_w = raw_dw;
372 }
373
374 new_w = al_get_mouse_wheel_precision() * raw_mouse_w / WHEEL_DELTA;
375 d = new_w - mouse_state.w;
376 mouse_state.w = new_w;
377
378 generate_mouse_event(ALLEGRO_EVENT_MOUSE_AXES,
379 mouse_state.x, mouse_state.y, mouse_state.z, mouse_state.w, mouse_state.pressure,
380 0, 0, 0, d,
381 0, (void*)win_disp);
382 }
383
384
385
_al_win_mouse_handle_button(int button,bool down,int x,int y,bool abs,ALLEGRO_DISPLAY_WIN * win_disp)386 void _al_win_mouse_handle_button(int button, bool down, int x, int y, bool abs,
387 ALLEGRO_DISPLAY_WIN *win_disp)
388 {
389 int type = down ? ALLEGRO_EVENT_MOUSE_BUTTON_DOWN
390 : ALLEGRO_EVENT_MOUSE_BUTTON_UP;
391
392 if (!installed)
393 return;
394
395 if (!abs) {
396 mouse_state.x += x;
397 mouse_state.y += y;
398 }
399 else {
400 mouse_state.x = x;
401 mouse_state.y = y;
402 }
403
404 if (down)
405 mouse_state.buttons |= (1 << (button-1));
406 else
407 mouse_state.buttons &= ~(1 << (button-1));
408
409 mouse_state.pressure = mouse_state.buttons ? 1.0 : 0.0; /* TODO */
410
411 generate_mouse_event(type,
412 mouse_state.x, mouse_state.y, mouse_state.z, mouse_state.w, mouse_state.pressure,
413 0, 0, 0, 0,
414 button, (void*)win_disp);
415 }
416
417 /* vim: set sts=3 sw=3 et: */
418