1 /**
2 ** w32inp.c ---- DOS (TCC/BCC/DJGPP: "conio.h") style keyboard utilities
3 **
4 ** Author: Gernot Graeff
5 ** E-mail: gernot.graeff@t-online.de
6 ** Date: 02-11-99
7 **
8 ** This file is part of the GRX graphics library.
9 **
10 ** The GRX graphics library is free software; you can redistribute it
11 ** and/or modify it under some conditions; see the "copying.grx" file
12 ** for details.
13 **
14 ** This library is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 **
18 ** Contributions by M.Alvarez (malfer@teleline.es) 18/11/2001
19 ** - Better keys handling using translation tables (w32input.h).
20 **
21 ** Contributions by M.Alvarez (malfer@teleline.es) 02/02/2002
22 ** - The w32 imput queue implemented as a circular queue.
23 ** - All the input related code moved here from vd_win32.c
24 **
25 ** Contribution by M. Lombardi 05/08/2007
26 ** Do not treat WM_PAINT messages here. They are delt with in vd_win32.c.
27 ** This produced saturation of GRX event queue and gobbling of
28 ** keyboard/mouse events there (compare behavior of test/mousetst)
29 **
30 ** Contribution by Richard Sanders (richard@dogcreek.ca) 02/04/2009
31 ** Synchronisation of windows and grx mouse cursors
32 **/
33
34 #include "libwin32.h"
35 #include "libgrx.h"
36 #include "grxkeys.h"
37 #include "input.h"
38 #include "arith.h"
39 #include "memcopy.h"
40 #include "w32input.h"
41
42 int _nkeysw32pool = 0;
43 int _keysw32pool[_MAXKEYSW32POOL];
44
45 static int kbd_enabled = TRUE;
46 static int kbd_lastmod = 0;
47 static int kbd_hitcount = 0;
48 static int mou_enabled = TRUE;
49 static int mou_buttons = 0;
50 static long evt_lasttime;
51
_GrIsKbdEnabled(void)52 int _GrIsKbdEnabled(void)
53 {
54 return kbd_enabled;
55 }
56
_GrKeyPressed(void)57 int _GrKeyPressed(void)
58 {
59 _GrUpdateInputs();
60 if (kbd_enabled)
61 return (kbd_hitcount > 0);
62 else
63 return (_nkeysw32pool > 0);
64 }
65
_GrKeyStat(void)66 int _GrKeyStat(void)
67 {
68 return kbd_lastmod;
69 }
70
uninit(void)71 static void uninit(void)
72 {
73 if (MOUINFO->msstatus > 1) {
74 MOUINFO->msstatus = 1;
75 }
76 }
77
GrMouseDetect(void)78 int GrMouseDetect(void)
79 {
80 return GetSystemMetrics(SM_MOUSEPRESENT);
81 }
82
init_w32queue(int queue_size)83 static void init_w32queue(int queue_size)
84 {
85 EnterCriticalSection(&_csEventQueue);
86 if (_W32EventQueueSize != queue_size) {
87 if (_W32EventQueue != NULL)
88 free(_W32EventQueue);
89 _W32EventQueue = (W32Event *)malloc(sizeof(W32Event) * queue_size);
90 _W32EventQueueSize = _W32EventQueue ? queue_size : 0;
91 }
92 _W32EventQueueRead = 0;
93 _W32EventQueueWrite = 0;
94 _W32EventQueueLength = 0;
95 LeaveCriticalSection(&_csEventQueue);
96 }
97
GrMouseInitN(int queue_size)98 void GrMouseInitN(int queue_size)
99 {
100 uninit();
101 queue_size = umax(4, umin(256, queue_size));
102 init_queue(queue_size);
103 init_w32queue(queue_size);
104 kbd_hitcount = 0;
105 if (GrMouseDetect()) {
106 GrMouseSetSpeed(1, 1);
107 GrMouseSetAccel(100, 1);
108 GrMouseSetLimits(0, 0, SCRN->gc_xmax, SCRN->gc_ymax);
109 GrMouseWarp((SCRN->gc_xmax >> 1), (SCRN->gc_ymax >> 1));
110 _GrInitMouseCursor();
111 MOUINFO->msstatus = 2;
112 mou_buttons = 0;
113 }
114 GrMouseEventEnable(TRUE, TRUE);
115 real_time(evt_lasttime);
116 MOUINFO->uninit = uninit;
117 }
118
GrMouseSetSpeed(int spmult,int spdiv)119 void GrMouseSetSpeed(int spmult, int spdiv)
120 {
121 MOUINFO->spmult = umin(16, umax(1, spmult));
122 MOUINFO->spdiv = umin(16, umax(1, spdiv));
123 }
124
GrMouseSetAccel(int thresh,int accel)125 void GrMouseSetAccel(int thresh, int accel)
126 {
127 MOUINFO->thresh = umin(64, umax(1, thresh));
128 MOUINFO->accel = umin(16, umax(1, accel));
129 }
130
GrMouseSetLimits(int x1,int y1,int x2,int y2)131 void GrMouseSetLimits(int x1, int y1, int x2, int y2)
132 {
133 isort(x1, x2);
134 isort(y1, y2);
135 MOUINFO->xmin = imax(0, imin(x1, SCRN->gc_xmax));
136 MOUINFO->ymin = imax(0, imin(y1, SCRN->gc_ymax));
137 MOUINFO->xmax = imax(0, imin(x2, SCRN->gc_xmax));
138 MOUINFO->ymax = imax(0, imin(y2, SCRN->gc_ymax));
139 }
140
GrMouseWarp(int x,int y)141 void GrMouseWarp(int x, int y)
142 {
143 POINT point;
144
145 MOUINFO->xpos = imax(MOUINFO->xmin, imin(MOUINFO->xmax, x));
146 MOUINFO->ypos = imax(MOUINFO->ymin, imin(MOUINFO->ymax, y));
147 GrMouseUpdateCursor();
148 point.x = MOUINFO->xpos;
149 point.y = MOUINFO->ypos;
150 ClientToScreen(hGRXWnd, &point);
151 SetCursorPos(point.x, point.y);
152 }
153
GrMouseEventEnable(int enable_kb,int enable_ms)154 void GrMouseEventEnable(int enable_kb, int enable_ms)
155 {
156 kbd_enabled = enable_kb;
157 mou_enabled = enable_ms;
158 }
159
GrMouseGetEventT(int flags,GrMouseEvent * ev,long tout)160 void GrMouseGetEventT(int flags, GrMouseEvent * ev, long tout)
161 {
162 int msdraw;
163
164 if (MOUINFO->msstatus == 0) GrMouseInit();
165
166 msdraw = !MOUINFO->displayed && !(flags & GR_M_NOPAINT);
167 if (msdraw) GrMouseDisplayCursor();
168
169 if (tout <= 0L) tout = 1L;
170
171 for (;;) {
172 _GrUpdateInputs();
173 GrMouseUpdateCursor();
174 while (MOUINFO->qlength > 0) {
175 dequeue_event((*ev));
176 if (ev->flags & GR_M_KEYPRESS) kbd_hitcount--;
177 if (ev->flags & flags) {
178 if (msdraw) GrMouseEraseCursor();
179 return;
180 }
181 }
182 if ((flags & GR_M_POLL) ||
183 (tout == 0L) || (MOUINFO->moved && (flags & GR_M_MOTION))) {
184 fill_mouse_ev((*ev),
185 mou_buttons, mou_buttons,
186 GR_M_LEFT, GR_M_MIDDLE, GR_M_RIGHT, GR_M_P4, GR_M_P5, kbd_lastmod);
187 if (ev->flags) /* something happend */
188 real_dtime(ev->dtime, evt_lasttime);
189 else
190 ev->dtime = -1; /* special time if nothing happend */
191 MOUINFO->moved = FALSE;
192 if (msdraw) {
193 GrMouseEraseCursor();
194 }
195 return;
196 }
197 if (tout > 0L) {
198 Sleep(10);
199 if ((tout -= 10) < 0L) tout = 0L;
200 }
201 }
202 }
203
StdKeyTranslate(int winkey,int fkbState)204 static GrKeyType StdKeyTranslate(int winkey, int fkbState)
205 {
206 keytrans *k;
207 int i;
208
209 if (fkbState & GR_KB_ALT)
210 k = altstdkeys;
211 else if (fkbState & GR_KB_CTRL)
212 k = controlstdkeys;
213 else if (fkbState & GR_KB_SHIFT)
214 k = shiftstdkeys;
215 else
216 k = stdkeys;
217
218 for (i = 0; i < NSTDKEYS; i++) {
219 if (winkey == k[i].winkey)
220 return k[i].grkey;
221 }
222
223 return 0;
224 }
225
DequeueW32Event(GrMouseEvent * ev)226 static int DequeueW32Event(GrMouseEvent * ev)
227 {
228 W32Event evaux;
229 int key;
230 int buttons;
231
232 if (_W32EventQueueLength < 1){
233 Sleep(1); /* yield */
234 return 0;
235 }
236
237 EnterCriticalSection(&_csEventQueue);
238 // if (!TryEnterCriticalSection(&_csEventQueue))
239 // return 0;
240
241 evaux = _W32EventQueue[_W32EventQueueRead];
242 if (++_W32EventQueueRead == _W32EventQueueSize)
243 _W32EventQueueRead = 0;
244 _W32EventQueueLength--;
245 LeaveCriticalSection(&_csEventQueue);
246
247 switch (evaux.uMsg) {
248
249 case WM_CHAR:
250 fill_keybd_ev((*ev), evaux.wParam, evaux.kbstat);
251 kbd_lastmod = evaux.kbstat;
252 return 1;
253
254 case WM_SYSCHAR:
255 key = 0;
256 if (evaux.wParam >= 'a' && evaux.wParam <= 'z')
257 key = altletters[evaux.wParam - 'a'];
258 if (evaux.wParam >= 'A' && evaux.wParam <= 'Z')
259 key = altletters[evaux.wParam - 'A'];
260 if (evaux.wParam >= '0' && evaux.wParam <= '9')
261 key = altnumbers[evaux.wParam - '0'];
262 if (key == 0)
263 return -1;
264 fill_keybd_ev((*ev), key, evaux.kbstat);
265 kbd_lastmod = evaux.kbstat;
266 return 1;
267
268 case WM_KEYDOWN:
269 case WM_SYSKEYDOWN:
270 key = StdKeyTranslate(evaux.wParam, evaux.kbstat);
271 if (key == 0)
272 return -1;
273 fill_keybd_ev((*ev), key, evaux.kbstat);
274 kbd_lastmod = evaux.kbstat;
275 return 1;
276
277 case WM_COMMAND:
278 fill_cmd_ev((*ev), evaux.wParam, evaux.kbstat);
279 return 1;
280
281 case WM_LBUTTONDOWN:
282 buttons = GR_M_LEFT | mou_buttons;
283 MOUINFO->xpos = LOWORD(evaux.lParam);
284 MOUINFO->ypos = HIWORD(evaux.lParam);
285 fill_mouse_ev((*ev), mou_buttons, buttons, GR_M_LEFT,
286 GR_M_MIDDLE, GR_M_RIGHT, GR_M_P4, GR_M_P5, evaux.kbstat);
287 mou_buttons = buttons;
288 MOUINFO->moved = FALSE;
289 kbd_lastmod = evaux.kbstat;
290 return 1;
291
292 case WM_MBUTTONDOWN:
293 buttons = GR_M_MIDDLE | mou_buttons;
294 MOUINFO->xpos = LOWORD(evaux.lParam);
295 MOUINFO->ypos = HIWORD(evaux.lParam);
296 fill_mouse_ev((*ev), mou_buttons, buttons, GR_M_LEFT,
297 GR_M_MIDDLE, GR_M_RIGHT, GR_M_P4, GR_M_P5, evaux.kbstat);
298 mou_buttons = buttons;
299 MOUINFO->moved = FALSE;
300 kbd_lastmod = evaux.kbstat;
301 return 1;
302
303 case WM_RBUTTONDOWN:
304 buttons = GR_M_RIGHT | mou_buttons;
305 MOUINFO->xpos = LOWORD(evaux.lParam);
306 MOUINFO->ypos = HIWORD(evaux.lParam);
307 fill_mouse_ev((*ev), mou_buttons, buttons, GR_M_LEFT,
308 GR_M_MIDDLE, GR_M_RIGHT, GR_M_P4, GR_M_P5, evaux.kbstat);
309 mou_buttons = buttons;
310 MOUINFO->moved = FALSE;
311 kbd_lastmod = evaux.kbstat;
312 return 1;
313
314 case WM_LBUTTONUP:
315 buttons = ~GR_M_LEFT & mou_buttons;
316 MOUINFO->xpos = LOWORD(evaux.lParam);
317 MOUINFO->ypos = HIWORD(evaux.lParam);
318 fill_mouse_ev((*ev), mou_buttons, buttons, GR_M_LEFT,
319 GR_M_MIDDLE, GR_M_RIGHT, GR_M_P4, GR_M_P5, evaux.kbstat);
320 mou_buttons = buttons;
321 MOUINFO->moved = FALSE;
322 kbd_lastmod = evaux.kbstat;
323 return 1;
324
325 case WM_MBUTTONUP:
326 buttons = ~GR_M_MIDDLE & mou_buttons;
327 MOUINFO->xpos = LOWORD(evaux.lParam);
328 MOUINFO->ypos = HIWORD(evaux.lParam);
329 fill_mouse_ev((*ev), mou_buttons, buttons, GR_M_LEFT,
330 GR_M_MIDDLE, GR_M_RIGHT, GR_M_P4, GR_M_P5, evaux.kbstat);
331 mou_buttons = buttons;
332 MOUINFO->moved = FALSE;
333 kbd_lastmod = evaux.kbstat;
334 return 1;
335
336 case WM_RBUTTONUP:
337 buttons = ~GR_M_RIGHT & mou_buttons;
338 MOUINFO->xpos = LOWORD(evaux.lParam);
339 MOUINFO->ypos = HIWORD(evaux.lParam);
340 fill_mouse_ev((*ev), mou_buttons, buttons, GR_M_LEFT,
341 GR_M_MIDDLE, GR_M_RIGHT, GR_M_P4, GR_M_P5, evaux.kbstat);
342 mou_buttons = buttons;
343 MOUINFO->moved = FALSE;
344 kbd_lastmod = evaux.kbstat;
345 return 1;
346
347 case WM_MOUSEWHEEL:
348 buttons = mou_buttons ^ (((short)HIWORD(evaux.wParam) > 0) ?
349 GR_M_P4 : GR_M_P5);
350 MOUINFO->xpos = LOWORD(evaux.lParam);
351 MOUINFO->ypos = HIWORD(evaux.lParam);
352 fill_mouse_ev((*ev), mou_buttons, buttons, GR_M_LEFT,
353 GR_M_MIDDLE, GR_M_RIGHT, GR_M_P4, GR_M_P5, evaux.kbstat);
354 mou_buttons = buttons;
355 MOUINFO->moved = FALSE;
356 kbd_lastmod = evaux.kbstat;
357 return 1;
358
359 case WM_MOUSEMOVE:
360 MOUINFO->xpos = LOWORD(evaux.lParam);
361 MOUINFO->ypos = HIWORD(evaux.lParam);
362 MOUINFO->moved = TRUE;
363 ev->kbstat = evaux.kbstat;
364 kbd_lastmod = evaux.kbstat;
365 return -1;
366
367 default:
368 return -1;
369
370 }
371 }
372
_GrUpdateInputs(void)373 void _GrUpdateInputs(void)
374 {
375 GrMouseEvent ev;
376 int r;
377
378 while ((r = DequeueW32Event(&ev)) != 0) {
379 if (r > 0) {
380 if (ev.flags & GR_M_KEYPRESS && !kbd_enabled){
381 if (_nkeysw32pool < _MAXKEYSW32POOL)
382 _keysw32pool[_nkeysw32pool++] = ev.key;
383 }
384 else{
385 real_dtime(ev.dtime, evt_lasttime);
386 enqueue_event(ev);
387 if (ev.flags & GR_M_KEYPRESS) kbd_hitcount++;
388 }
389 }
390 }
391 }
392