Added D-Flat/32 library
[reactos.git] / rosapps / dflat32 / message.c
1 /* --------- message.c ---------- */
2
3 #include "dflat.h"
4
5 static int handshaking = 0;
6
7 BOOL AllocTesting = FALSE;
8 jmp_buf AllocError;
9 BOOL AltDown = FALSE;
10
11 /* ---------- event queue ---------- */
12 static struct events
13 {
14 DFMESSAGE event;
15 int mx;
16 int my;
17 } EventQueue[MAXMESSAGES];
18
19 /* ---------- message queue --------- */
20 static struct msgs
21 {
22 DFWINDOW wnd;
23 DFMESSAGE msg;
24 PARAM p1;
25 PARAM p2;
26 } MsgQueue[MAXMESSAGES];
27
28 static int EventQueueOnCtr;
29 static int EventQueueOffCtr;
30 static int EventQueueCtr;
31
32 static int MsgQueueOnCtr;
33 static int MsgQueueOffCtr;
34 static int MsgQueueCtr;
35
36
37 DFWINDOW CaptureMouse;
38 DFWINDOW CaptureKeyboard;
39 static BOOL NoChildCaptureMouse;
40 static BOOL NoChildCaptureKeyboard;
41
42 static int doubletimer = -1;
43 static int delaytimer = -1;
44 static int clocktimer = -1;
45
46 static DFWINDOW Cwnd;
47
48 static char ermsg[] = "Error accessing drive x";
49
50
51 static void StopMsg(void)
52 {
53 ClearClipboard();
54 ClearDialogBoxes();
55 restorecursor();
56 unhidecursor();
57 }
58
59 /* ------------ initialize the message system --------- */
60 BOOL init_messages (VOID)
61 {
62 AllocTesting = TRUE;
63 if (setjmp(AllocError) != 0)
64 {
65 StopMsg();
66 return FALSE;
67 }
68
69 /* enable mouse events */
70 SetConsoleMode (GetStdHandle (STD_INPUT_HANDLE),
71 ENABLE_MOUSE_INPUT);
72
73 savecursor();
74 hidecursor();
75
76 CaptureMouse = NULL;
77 CaptureKeyboard = NULL;
78 NoChildCaptureMouse = FALSE;
79 NoChildCaptureKeyboard = FALSE;
80 MsgQueueOnCtr = 0;
81 MsgQueueOffCtr = 0;
82 MsgQueueCtr = 0;
83 EventQueueOnCtr = 0;
84 EventQueueOffCtr = 0;
85 EventQueueCtr = 0;
86 DfPostMessage (NULL, DFM_START, 0, 0);
87
88 return TRUE;
89 }
90
91 /* ----- post an event and parameters to event queue ---- */
92 static void PostEvent(DFMESSAGE event, int p1, int p2)
93 {
94 if (EventQueueCtr != MAXMESSAGES) {
95 EventQueue[EventQueueOnCtr].event = event;
96 EventQueue[EventQueueOnCtr].mx = p1;
97 EventQueue[EventQueueOnCtr].my = p2;
98 if (++EventQueueOnCtr == MAXMESSAGES)
99 EventQueueOnCtr = 0;
100 EventQueueCtr++;
101 }
102 }
103
104 /* ------ collect mouse, clock, and keyboard events ----- */
105 static void collect_events(void)
106 {
107 static int OldShiftKeys = 0;
108 int sk = 0;
109
110 #ifdef TIMER_AVAILABLE
111 static BOOL flipflop = FALSE;
112 static char timestr[9];
113 struct tm *now;
114 int hr;
115 #endif
116
117 HANDLE hInput = GetStdHandle (STD_INPUT_HANDLE);
118 INPUT_RECORD ir;
119 DWORD dwRead;
120 int c;
121
122 #ifdef TIMER_AVAILABLE
123 /* -------- test for a clock event (one/second) ------- */
124 if (timed_out(clocktimer))
125 {
126 /* ----- get the current time ----- */
127 time_t t = time(NULL);
128 now = localtime(&t);
129 hr = now->tm_hour > 12 ?
130 now->tm_hour - 12 :
131 now->tm_hour;
132 if (hr == 0)
133 hr = 12;
134 sprintf(timestr, "%2d:%02d", hr, now->tm_min);
135 strcpy(timestr+5, now->tm_hour > 11 ? "pm " : "am ");
136 /* ------- blink the : at one-second intervals ----- */
137 if (flipflop)
138 *(timestr+2) = ' ';
139 flipflop ^= TRUE;
140 /* -------- reset the timer -------- */
141 set_timer(clocktimer, 1);
142 /* -------- post the clock event -------- */
143 PostEvent(CLOCKTICK, (PARAM)timestr, 0);
144 }
145 #endif
146
147 // WaitForSingleObject (hInput, INFINITE);
148 ReadConsoleInput (hInput, &ir, 1, &dwRead);
149
150 if ((ir.EventType == KEY_EVENT) &&
151 (ir.Event.KeyEvent.bKeyDown == TRUE))
152 {
153 /* handle key down events */
154
155 /* handle shift state changes */
156 if (ir.Event.KeyEvent.dwControlKeyState &
157 (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
158 {
159 sk |= ALTKEY;
160 }
161 if (ir.Event.KeyEvent.dwControlKeyState &
162 (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
163 {
164 sk |= CTRLKEY;
165 }
166
167 #if 0
168 if (sk != OldShiftKeys)
169 {
170 OldShiftKeys = sk;
171 /* the shift status changed */
172 PostEvent(SHIFT_CHANGED, sk, 0);
173 if (sk & ALTKEY)
174 AltDown = TRUE;
175 else
176 AltDown = FALSE;
177 }
178 #endif
179
180 if (ir.Event.KeyEvent.uChar.AsciiChar == 0)
181 {
182 switch (ir.Event.KeyEvent.wVirtualKeyCode)
183 {
184 case VK_F1:
185 c = F1;
186 break;
187
188 case VK_F4:
189 if (sk & ALTKEY)
190 c = ALT_F4;
191 else if (sk & CTRLKEY)
192 c = CTRL_F4;
193 else
194 c = F4;
195
196 case VK_F10:
197 c = F10;
198 break;
199
200 case VK_UP:
201 c = UP;
202 break;
203
204 case VK_DOWN:
205 c = DN;
206 break;
207
208 case VK_LEFT:
209 c = BS;
210 break;
211
212 case VK_RIGHT:
213 c = FWD;
214 break;
215
216 case VK_HOME:
217 c = HOME;
218 break;
219
220 case VK_END:
221 c = END;
222 break;
223
224 case VK_PRIOR:
225 c = PGUP;
226 break;
227
228 case VK_NEXT:
229 c = PGDN;
230 break;
231
232 default:
233 return;
234 }
235 }
236 else
237 c = ir.Event.KeyEvent.uChar.AsciiChar;
238
239 PostEvent (KEYBOARD, c, sk);
240 }
241 else if (ir.EventType == MOUSE_EVENT)
242 {
243 /* handle mouse events */
244 if (ir.Event.MouseEvent.dwEventFlags == MOUSE_MOVED)
245 {
246 PostEvent (MOUSE_MOVED,
247 ir.Event.MouseEvent.dwMousePosition.X,
248 ir.Event.MouseEvent.dwMousePosition.Y);
249 }
250 else if (ir.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK)
251 {
252 if (ir.Event.MouseEvent.dwButtonState ==
253 FROM_LEFT_1ST_BUTTON_PRESSED)
254 {
255 PostEvent (DOUBLE_CLICK,
256 ir.Event.MouseEvent.dwMousePosition.X,
257 ir.Event.MouseEvent.dwMousePosition.Y);
258 }
259 }
260 else if (ir.Event.MouseEvent.dwEventFlags == 0)
261 {
262 /* single click */
263 if (ir.Event.MouseEvent.dwButtonState ==
264 FROM_LEFT_1ST_BUTTON_PRESSED)
265 {
266 PostEvent (LEFT_BUTTON,
267 ir.Event.MouseEvent.dwMousePosition.X,
268 ir.Event.MouseEvent.dwMousePosition.Y);
269 }
270 else if (ir.Event.MouseEvent.dwButtonState ==
271 RIGHTMOST_BUTTON_PRESSED)
272 {
273 PostEvent (RIGHT_BUTTON,
274 ir.Event.MouseEvent.dwMousePosition.X,
275 ir.Event.MouseEvent.dwMousePosition.Y);
276 }
277 else if (ir.Event.MouseEvent.dwButtonState == 0)
278 {
279 PostEvent (DFM_BUTTON_RELEASED,
280 ir.Event.MouseEvent.dwMousePosition.X,
281 ir.Event.MouseEvent.dwMousePosition.Y);
282 }
283 }
284 }
285
286
287 #if 0
288 /* --------- keyboard events ---------- */
289 if ((sk = getshift()) != ShiftKeys)
290 {
291 ShiftKeys = sk;
292 /* ---- the shift status changed ---- */
293 PostEvent(SHIFT_CHANGED, sk, 0);
294 if (sk & ALTKEY)
295 AltDown = TRUE;
296 }
297
298 /* ---- build keyboard events for key combinations that
299 BIOS doesn't report --------- */
300 if (sk & ALTKEY) {
301 if (keyportvalue == 14) {
302 AltDown = FALSE;
303 PostEvent(KEYBOARD, ALT_BS, sk);
304 }
305 if (keyportvalue == 83) {
306 AltDown = FALSE;
307 PostEvent(KEYBOARD, ALT_DEL, sk);
308 }
309 }
310
311 if (sk & CTRLKEY)
312 {
313 AltDown = FALSE;
314 if (keyportvalue == 82) {
315 PostEvent(KEYBOARD, CTRL_INS, sk);
316 }
317 }
318 /* ----------- test for keystroke ------- */
319 if (keyhit()) {
320 static int cvt[] = {SHIFT_INS,END,DN,PGDN,BS,'5',
321 FWD,HOME,UP,PGUP};
322 INPUT_RECORD ir;
323 int c;
324
325 GetKey(&ir);
326 c = ir.Event.KeyEvent.uChar.AsciiChar;
327
328 AltDown = FALSE;
329 /* -------- convert numeric pad keys ------- */
330 if (sk & (LEFTSHIFT | RIGHTSHIFT))
331 {
332 if (c >= '0' && c <= '9')
333 c = cvt[c-'0'];
334 else if (c == '.' || c == DEL)
335 c = SHIFT_DEL;
336 else if (c == INS)
337 c = SHIFT_INS;
338 }
339 /* ------ post the keyboard event ------ */
340 PostEvent(KEYBOARD, c, sk);
341 }
342 #endif
343 }
344
345 /* ----- post a message and parameters to msg queue ---- */
346 void DfPostMessage(DFWINDOW wnd, DFMESSAGE msg, PARAM p1, PARAM p2)
347 {
348 if (msg == ENDDIALOG)
349 {
350 msg++;
351 --msg;
352 }
353
354 if (MsgQueueCtr != MAXMESSAGES)
355 {
356 MsgQueue[MsgQueueOnCtr].wnd = wnd;
357 MsgQueue[MsgQueueOnCtr].msg = msg;
358 MsgQueue[MsgQueueOnCtr].p1 = p1;
359 MsgQueue[MsgQueueOnCtr].p2 = p2;
360 if (++MsgQueueOnCtr == MAXMESSAGES)
361 MsgQueueOnCtr = 0;
362 MsgQueueCtr++;
363 }
364 }
365
366 /* --------- send a message to a window ----------- */
367 int DfSendMessage(DFWINDOW wnd, DFMESSAGE msg, PARAM p1, PARAM p2)
368 {
369 int rtn = TRUE, x, y;
370
371 #ifdef INCLUDE_LOGGING
372 LogMessages(wnd, msg, p1, p2);
373 #endif
374 if (wnd != NULL)
375 switch (msg) {
376 case PAINT:
377 case BORDER:
378 /* ------- don't send these messages unless the
379 window is visible -------- */
380 if (isVisible(wnd))
381 rtn = (*wnd->wndproc)(wnd, msg, p1, p2);
382 break;
383 case RIGHT_BUTTON:
384 case LEFT_BUTTON:
385 case DOUBLE_CLICK:
386 case DFM_BUTTON_RELEASED:
387 /* --- don't send these messages unless the
388 window is visible or has captured the mouse -- */
389 if (isVisible(wnd) || wnd == CaptureMouse)
390 rtn = (*wnd->wndproc)(wnd, msg, p1, p2);
391 break;
392 case KEYBOARD:
393 case SHIFT_CHANGED:
394 /* ------- don't send these messages unless the
395 window is visible or has captured the keyboard -- */
396 if (!(isVisible(wnd) || wnd == CaptureKeyboard))
397 break;
398 default:
399 rtn = (*wnd->wndproc)(wnd, msg, p1, p2);
400 break;
401 }
402 /* ----- window processor returned true or the message was sent
403 to no window at all (NULL) ----- */
404 if (rtn != FALSE) {
405 /* --------- process messages that a window sends to the
406 system itself ---------- */
407 switch (msg) {
408 case DFM_STOP:
409 StopMsg();
410 break;
411 /* ------- clock messages --------- */
412 case CAPTURE_CLOCK:
413 Cwnd = wnd;
414 set_timer(clocktimer, 0);
415 break;
416 case RELEASE_CLOCK:
417 Cwnd = NULL;
418 disable_timer(clocktimer);
419 break;
420 /* -------- keyboard messages ------- */
421 case KEYBOARD_CURSOR:
422 if (wnd == NULL)
423 cursor((int)p1, (int)p2);
424 else if (wnd == inFocus)
425 cursor(GetClientLeft(wnd)+(int)p1,
426 GetClientTop(wnd)+(int)p2);
427 break;
428 case CAPTURE_KEYBOARD:
429 if (p2)
430 ((DFWINDOW)p2)->PrevKeyboard=CaptureKeyboard;
431 else
432 wnd->PrevKeyboard = CaptureKeyboard;
433 CaptureKeyboard = wnd;
434 NoChildCaptureKeyboard = (int)p1;
435 break;
436 case RELEASE_KEYBOARD:
437 if (wnd != NULL)
438 {
439 if (CaptureKeyboard == wnd || (int)p1)
440 CaptureKeyboard = wnd->PrevKeyboard;
441 else
442 {
443 DFWINDOW twnd = CaptureKeyboard;
444 while (twnd != NULL)
445 {
446 if (twnd->PrevKeyboard == wnd)
447 {
448 twnd->PrevKeyboard = wnd->PrevKeyboard;
449 break;
450 }
451 twnd = twnd->PrevKeyboard;
452 }
453 if (twnd == NULL)
454 CaptureKeyboard = NULL;
455 }
456 wnd->PrevKeyboard = NULL;
457 }
458 else
459 CaptureKeyboard = NULL;
460 NoChildCaptureKeyboard = FALSE;
461 break;
462 case CURRENT_KEYBOARD_CURSOR:
463 curr_cursor(&x, &y);
464 *(int*)p1 = x;
465 *(int*)p2 = y;
466 break;
467 case SAVE_CURSOR:
468 savecursor();
469 break;
470 case RESTORE_CURSOR:
471 restorecursor();
472 break;
473 case HIDE_CURSOR:
474 normalcursor();
475 hidecursor();
476 break;
477 case SHOW_CURSOR:
478 if (p1)
479 set_cursor_type(0x0106);
480 else
481 set_cursor_type(0x0607);
482 unhidecursor();
483 break;
484
485 case CAPTURE_MOUSE:
486 if (p2)
487 ((DFWINDOW)p2)->PrevMouse = CaptureMouse;
488 else
489 wnd->PrevMouse = CaptureMouse;
490 CaptureMouse = wnd;
491 NoChildCaptureMouse = (int)p1;
492 break;
493
494 case RELEASE_MOUSE:
495 if (wnd != NULL)
496 {
497 if (CaptureMouse == wnd || (int)p1)
498 CaptureMouse = wnd->PrevMouse;
499 else
500 {
501 DFWINDOW twnd = CaptureMouse;
502 while (twnd != NULL)
503 {
504 if (twnd->PrevMouse == wnd)
505 {
506 twnd->PrevMouse = wnd->PrevMouse;
507 break;
508 }
509 twnd = twnd->PrevMouse;
510 }
511 if (twnd == NULL)
512 CaptureMouse = NULL;
513 }
514 wnd->PrevMouse = NULL;
515 }
516 else
517 CaptureMouse = NULL;
518 NoChildCaptureMouse = FALSE;
519 break;
520
521 default:
522 break;
523 }
524 }
525 return rtn;
526 }
527
528 static DFRECT VisibleRect(DFWINDOW wnd)
529 {
530 DFRECT rc = WindowRect(wnd);
531 if (!TestAttribute(wnd, NOCLIP))
532 {
533 DFWINDOW pwnd = GetParent(wnd);
534 DFRECT prc;
535 prc = ClientRect(pwnd);
536 while (pwnd != NULL)
537 {
538 if (TestAttribute(pwnd, NOCLIP))
539 break;
540 rc = subRectangle(rc, prc);
541 if (!ValidRect(rc))
542 break;
543 if ((pwnd = GetParent(pwnd)) != NULL)
544 prc = ClientRect(pwnd);
545 }
546 }
547 return rc;
548 }
549
550 /* ----- find window that mouse coordinates are in --- */
551 static DFWINDOW inWindow(DFWINDOW wnd, int x, int y)
552 {
553 DFWINDOW Hit = NULL;
554 while (wnd != NULL) {
555 if (isVisible(wnd)) {
556 DFWINDOW wnd1;
557 DFRECT rc = VisibleRect(wnd);
558 if (InsideRect(x, y, rc))
559 Hit = wnd;
560 if ((wnd1 = inWindow(LastWindow(wnd), x, y)) != NULL)
561 Hit = wnd1;
562 if (Hit != NULL)
563 break;
564 }
565 wnd = PrevWindow(wnd);
566 }
567 return Hit;
568 }
569
570 static DFWINDOW MouseWindow(int x, int y)
571 {
572 /* get the window in which a mouse event occurred */
573 DFWINDOW Mwnd = inWindow(ApplicationWindow, x, y);
574
575 /* ---- process mouse captures ----- */
576 if (CaptureMouse != NULL)
577 {
578 if (NoChildCaptureMouse ||
579 Mwnd == NULL ||
580 !isAncestor(Mwnd, CaptureMouse))
581 Mwnd = CaptureMouse;
582 }
583 return Mwnd;
584 }
585
586
587 void handshake(void)
588 {
589 handshaking++;
590 DfDispatchMessage ();
591 --handshaking;
592 }
593
594
595 /* ---- dispatch messages to the message proc function ---- */
596 BOOL DfDispatchMessage (void)
597 {
598 DFWINDOW Mwnd, Kwnd;
599
600 /* -------- collect mouse and keyboard events ------- */
601 collect_events();
602
603 /* --------- dequeue and process events -------- */
604 while (EventQueueCtr > 0)
605 {
606 struct events ev;
607
608 ev = EventQueue[EventQueueOffCtr];
609 if (++EventQueueOffCtr == MAXMESSAGES)
610 EventQueueOffCtr = 0;
611 --EventQueueCtr;
612
613 /* get the window in which a keyboard event occurred */
614 Kwnd = inFocus;
615
616 /* process keyboard captures */
617 if (CaptureKeyboard != NULL)
618 {
619 if (Kwnd == NULL ||
620 NoChildCaptureKeyboard ||
621 !isAncestor(Kwnd, CaptureKeyboard))
622 Kwnd = CaptureKeyboard;
623 }
624
625 /* send mouse and keyboard messages to the
626 window that should get them */
627 switch (ev.event)
628 {
629 case SHIFT_CHANGED:
630 case KEYBOARD:
631 if (!handshaking)
632 DfSendMessage(Kwnd, ev.event, ev.mx, ev.my);
633 break;
634
635 case LEFT_BUTTON:
636 if (!handshaking)
637 {
638 Mwnd = MouseWindow(ev.mx, ev.my);
639 if (!CaptureMouse ||
640 (!NoChildCaptureMouse &&
641 isAncestor(Mwnd, CaptureMouse)))
642 {
643 if (Mwnd != inFocus)
644 DfSendMessage(Mwnd, SETFOCUS, TRUE, 0);
645 DfSendMessage(Mwnd, LEFT_BUTTON, ev.mx, ev.my);
646 }
647 }
648 break;
649
650 case DFM_BUTTON_RELEASED:
651 case DOUBLE_CLICK:
652 case RIGHT_BUTTON:
653 if (handshaking)
654 break;
655
656 case MOUSE_MOVED:
657 Mwnd = MouseWindow(ev.mx, ev.my);
658 DfSendMessage(Mwnd, ev.event, ev.mx, ev.my);
659 break;
660
661 case CLOCKTICK:
662 DfSendMessage(Cwnd, ev.event, ev.mx, ev.my);
663 break;
664
665 default:
666 break;
667 }
668 }
669
670 /* ------ dequeue and process messages ----- */
671 while (MsgQueueCtr > 0)
672 {
673 struct msgs mq;
674
675 mq = MsgQueue[MsgQueueOffCtr];
676
677 if (++MsgQueueOffCtr == MAXMESSAGES)
678 MsgQueueOffCtr = 0;
679 --MsgQueueCtr;
680
681 DfSendMessage (mq.wnd, mq.msg, mq.p1, mq.p2);
682 if (mq.msg == ENDDIALOG)
683 return FALSE;
684
685 if (mq.msg == DFM_STOP)
686 return FALSE;
687 }
688
689 return TRUE;
690 }
691
692 /* EOF */