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