home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1991 / 06 / dflat3 / message.c < prev    next >
Text File  |  1991-05-19  |  15KB  |  489 lines

  1. /* --------- message.c ---------- */
  2.  
  3. #include <stdio.h>
  4. #include <dos.h>
  5. #include <conio.h>
  6. #include <string.h>
  7. #include <time.h>
  8. #include "dflat.h"
  9.  
  10. static int px = -1, py = -1;
  11. static int pmx = -1, pmy = -1;
  12. static int mx, my;
  13.  
  14. static int CriticalError;
  15.  
  16. /* ---------- event queue ---------- */
  17. static struct events    {
  18.     MESSAGE event;
  19.     int mx;
  20.     int my;
  21. } EventQueue[MAXMESSAGES];
  22.  
  23. /* ---------- message queue --------- */
  24. static struct msgs {
  25.     WINDOW wnd;
  26.     MESSAGE msg;
  27.     PARAM p1;
  28.     PARAM p2;
  29. } MsgQueue[MAXMESSAGES];
  30.  
  31. static int EventQueueOnCtr;
  32. static int EventQueueOffCtr;
  33. static int EventQueueCtr;
  34.  
  35. static int MsgQueueOnCtr;
  36. static int MsgQueueOffCtr;
  37. static int MsgQueueCtr;
  38.  
  39. static int lagdelay = FIRSTDELAY;
  40.  
  41. #ifdef POWERC
  42. static void interrupt (far *oldtimer)(void) = NULL;
  43. #else
  44. static void (interrupt far *oldtimer)(void) = NULL;
  45. #endif
  46.  
  47. WINDOW CaptureMouse = NULLWND;
  48. WINDOW CaptureKeyboard = NULLWND;
  49. static int NoChildCaptureMouse = FALSE;
  50. static int NoChildCaptureKeyboard = FALSE;
  51.  
  52. static int doubletimer = -1;
  53. static int delaytimer  = -1;
  54. #ifdef INCLUDE_CLOCK
  55. static int clocktimer  = -1;
  56. #endif
  57.  
  58. WINDOW Cwnd = NULLWND;
  59.  
  60. /* ------- timer interrupt service routine ------- */
  61. static void interrupt far newtimer(void)
  62. {
  63.     if (timer_running(doubletimer))
  64.         countdown(doubletimer);
  65.     if (timer_running(delaytimer))
  66.         countdown(delaytimer);
  67. #ifdef INCLUDE_CLOCK
  68.     if (timer_running(clocktimer))
  69.         countdown(clocktimer);
  70. #endif
  71.     oldtimer();
  72. }
  73.  
  74. static char ermsg[] = "Error accessing drive x";
  75.  
  76. /* -------- test for critical errors --------- */
  77. int TestCriticalError(void)
  78. {
  79.     int rtn = 0;
  80.     if (CriticalError)    {
  81.         rtn = 1;
  82.         CriticalError = FALSE;
  83.         if (TestErrorMessage(ermsg) == FALSE)
  84.             rtn = 2;
  85.     }
  86.     return rtn;
  87. }
  88.  
  89. /* ------ critical error interrupt service routine ------ */
  90. static void interrupt far newcrit(IREGS ir)
  91. {
  92.     if (!(ir.ax & 0x8000))     {
  93.         ermsg[sizeof(ermsg) - 2] = (ir.ax & 0xff) + 'A';
  94.         CriticalError = TRUE;
  95.     }
  96.     ir.ax = 0;
  97. }
  98.  
  99. /* ------------ initialize the message system --------- */
  100. void init_messages(void)
  101. {
  102.     resetmouse();
  103.     show_mousecursor();
  104.     px = py = -1;
  105.     pmx = pmy = -1;
  106.     mx = my = 0;
  107.     CaptureMouse = CaptureKeyboard = NULLWND;
  108.     NoChildCaptureMouse = FALSE;
  109.     NoChildCaptureKeyboard = FALSE;
  110.     MsgQueueOnCtr = MsgQueueOffCtr = MsgQueueCtr = 0;
  111.     EventQueueOnCtr = EventQueueOffCtr = EventQueueCtr = 0;
  112.     if (oldtimer == NULL)    {
  113.         oldtimer = getvect(TIMER);
  114.         setvect(TIMER, newtimer);
  115.     }
  116.     setvect(CRIT, newcrit);    
  117.     PostMessage(NULLWND,START,0,0);
  118.     lagdelay = FIRSTDELAY;
  119. }
  120.  
  121. /* ----- post an event and parameters to event queue ---- */
  122. static void PostEvent(MESSAGE event, int p1, int p2)
  123. {
  124.     if (EventQueueCtr != MAXMESSAGES)    {
  125.         EventQueue[EventQueueOnCtr].event = event;
  126.         EventQueue[EventQueueOnCtr].mx = p1;
  127.         EventQueue[EventQueueOnCtr].my = p2;
  128.         if (++EventQueueOnCtr == MAXMESSAGES)
  129.             EventQueueOnCtr = 0;
  130.         EventQueueCtr++;
  131.     }
  132. }
  133.  
  134. /* ------ collect mouse, clock, and keyboard events ----- */
  135. static void near collect_events(void)
  136. {
  137.     static int ShiftKeys = 0;
  138.     int sk;
  139. #ifdef INCLUDE_CLOCK
  140.     struct tm *now;
  141.     static int flipflop = FALSE;
  142.     static char timestr[8];
  143.     int hr;
  144.  
  145.     /* -------- test for a clock event (one/second) ------- */
  146.     if (timed_out(clocktimer))    {
  147.         /* ----- get the current time ----- */
  148.         time_t t = time(NULL);
  149.         now = localtime(&t);
  150.         hr = now->tm_hour > 12 ?
  151.              now->tm_hour - 12 :
  152.              now->tm_hour;
  153.         if (hr == 0)
  154.             hr = 12;
  155.         sprintf(timestr, "%2d:%02d", hr, now->tm_min);
  156.         strcpy(timestr+5, now->tm_hour > 11 ? "pm" : "am");
  157.         /* ------- blink the : at one-second intervals ----- */
  158.         if (flipflop)
  159.             *(timestr+2) = ' ';
  160.         flipflop ^= TRUE;
  161.         /* -------- reset the timer -------- */
  162.         set_timer(clocktimer, 1);
  163.         /* -------- post the clock event -------- */
  164.         PostEvent(CLOCKTICK, FP_SEG(timestr), FP_OFF(timestr));
  165.     }
  166. #endif
  167.  
  168.     /* --------- keyboard events ---------- */
  169.     if ((sk = getshift()) != ShiftKeys)    {
  170.         ShiftKeys = sk;
  171.         /* ---- the shift status changed ---- */
  172.         PostEvent(SHIFT_CHANGED, sk, 0);
  173.     }
  174.  
  175.     /* ---- build keyboard events for key combinations that
  176.         BIOS doesn't report --------- */
  177.     if (sk & ALTKEY)
  178.         if (inp(0x60) == 14)    {
  179.             while (!(inp(0x60) & 0x80))
  180.                 ;
  181.             PostEvent(KEYBOARD, ALT_BS, sk);
  182.         }
  183.     if (sk & CTRLKEY)
  184.         if (inp(0x60) == 82)    {
  185.             while (!(inp(0x60) & 0x80))
  186.                 ;
  187.             PostEvent(KEYBOARD, CTRL_INS, sk);
  188.         }
  189.  
  190.     /* ----------- test for keystroke ------- */
  191.     if (keyhit())    {
  192.         static int cvt[] = {SHIFT_INS,END,DN,PGDN,BS,'5',
  193.                         FWD,HOME,UP,PGUP};
  194.         int c = getkey();
  195.  
  196.         /* -------- convert numeric pad keys ------- */
  197.         if (sk & (LEFTSHIFT | RIGHTSHIFT))    {
  198.             if (c >= '0' && c <= '9')
  199.                 c = cvt[c-'0'];
  200.             else if (c == '.' || c == DEL)
  201.                 c = SHIFT_DEL;
  202.             else if (c == INS)
  203.                 c = SHIFT_INS;
  204.         }
  205.         if (c != '\r' && (c < ' ' || c > 127))
  206.             /* -------- clear the BIOS readahead buffer -------- */
  207.             *(int far *)(MK_FP(0x40,0x1a)) =
  208.                 *(int far *)(MK_FP(0x40,0x1c));
  209.         /* ---- if help key call generic help function ---- */
  210.         if (c == F1)
  211.             HelpFunction();
  212.         else
  213.             /* ------ post the keyboard event ------ */
  214.             PostEvent(KEYBOARD, c, sk);
  215.     }
  216.  
  217.     /* ------------ test for mouse events --------- */
  218.     if (button_releases())    {
  219.         /* ------- the button was released -------- */
  220.         doubletimer = DOUBLETICKS;
  221.         PostEvent(BUTTON_RELEASED, mx, my);
  222.         disable_timer(delaytimer);
  223.     }
  224.     get_mouseposition(&mx, &my);
  225.     if (mx != px || my != py)  {
  226.         px = mx;
  227.         py = my;
  228.         PostEvent(MOUSE_MOVED, mx, my);
  229.     }
  230.     if (rightbutton())
  231.         PostEvent(RIGHT_BUTTON, mx, my);
  232.     if (leftbutton())    {
  233.         if (mx == pmx && my == pmy)    {
  234.             /* ---- same position as last left button ---- */
  235.             if (timer_running(doubletimer))    {
  236.                 /* -- second click before double timeout -- */
  237.                 disable_timer(doubletimer);
  238.                 PostEvent(DOUBLE_CLICK, mx, my);
  239.             }
  240.             else if (!timer_running(delaytimer))    {
  241.                 /* ---- button held down a while ---- */
  242.                 delaytimer = lagdelay;
  243.                 lagdelay = DELAYTICKS;
  244.                 /* ---- post a typematic-like button ---- */
  245.                 PostEvent(LEFT_BUTTON, mx, my);
  246.             }
  247.         }
  248.         else    {
  249.             /* --------- new button press ------- */
  250.             disable_timer(doubletimer);
  251.             delaytimer = FIRSTDELAY;
  252.             lagdelay = DELAYTICKS;
  253.             PostEvent(LEFT_BUTTON, mx, my);
  254.             pmx = mx;
  255.             pmy = my;
  256.         }
  257.     }
  258.     else
  259.         lagdelay = FIRSTDELAY;
  260. }
  261.  
  262. /* ----- post a message and parameters to msg queue ---- */
  263. void PostMessage(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2)
  264. {
  265.     if (MsgQueueCtr != MAXMESSAGES)    {
  266.         MsgQueue[MsgQueueOnCtr].wnd = wnd;
  267.         MsgQueue[MsgQueueOnCtr].msg = msg;
  268.         MsgQueue[MsgQueueOnCtr].p1 = p1;
  269.         MsgQueue[MsgQueueOnCtr].p2 = p2;
  270.         if (++MsgQueueOnCtr == MAXMESSAGES)
  271.             MsgQueueOnCtr = 0;
  272.         MsgQueueCtr++;
  273.     }
  274. }
  275.  
  276. /* --------- send a message to a window ----------- */
  277. int SendMessage(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2)
  278. {
  279.     int rtn = TRUE, x, y;
  280.  
  281. #ifdef INCLUDE_LOGGING
  282.     LogMessages(wnd, msg, p1, p2);
  283. #endif
  284.     if (wnd != NULLWND)
  285.         switch (msg)    {
  286.             case PAINT:
  287.             case BORDER:
  288.             case RIGHT_BUTTON:
  289.             case LEFT_BUTTON:
  290.             case DOUBLE_CLICK:
  291.             case BUTTON_RELEASED:
  292.             case KEYBOARD:
  293.             case SHIFT_CHANGED:
  294.                 /* ------- don't send these messages unless the
  295.                     window is visible -------- */
  296.                 if (!isVisible(wnd))
  297.                     break;
  298.             default:
  299.                 rtn = (*wnd->wndproc)(wnd, msg, p1, p2);
  300.                 break;
  301.         }
  302.     /* ----- window processor returned or the message was sent
  303.         to no window at all (NULLWND) ----- */
  304.     if (rtn != FALSE)    {
  305.         /* --------- process messages that a window sends to the
  306.             system itself ---------- */
  307.         switch (msg)    {
  308.             case STOP:
  309.                 hide_mousecursor();
  310.                 if (oldtimer != NULL)    {
  311.                     setvect(TIMER, oldtimer);
  312.                     oldtimer = NULL;
  313.                 }
  314.                 break;
  315. #ifdef INCLUDE_CLOCK
  316.             /* ------- clock messages --------- */
  317.             case CAPTURE_CLOCK:
  318.                 Cwnd = wnd;
  319.                 set_timer(clocktimer, 0);
  320.                 break;
  321.             case RELEASE_CLOCK:
  322.                 Cwnd = NULLWND;
  323.                 disable_timer(clocktimer);
  324.                 break;
  325. #endif
  326.             /* -------- keyboard messages ------- */
  327.             case KEYBOARD_CURSOR:
  328.                 if (wnd == NULLWND)
  329.                     cursor((int)p1, (int)p2);
  330.                 else
  331.                     cursor(GetClientLeft(wnd)+(int)p1,
  332.                                 GetClientTop(wnd)+(int)p2);
  333.                 break;
  334.             case CAPTURE_KEYBOARD:
  335.                 if (p2)
  336.                     ((WINDOW)p2)->PrevKeyboard=CaptureKeyboard;
  337.                 else
  338.                     wnd->PrevKeyboard = CaptureKeyboard;
  339.                 CaptureKeyboard = wnd;
  340.                 NoChildCaptureKeyboard = (int)p1;
  341.                 break;
  342.             case RELEASE_KEYBOARD:
  343.                 CaptureKeyboard = wnd->PrevKeyboard;
  344.                 NoChildCaptureKeyboard = FALSE;
  345.                 break;
  346.             case CURRENT_KEYBOARD_CURSOR:
  347.                 curr_cursor(&x, &y);
  348.                 *(int*)p1 = x;
  349.                 *(int*)p2 = y;
  350.                 break;
  351.             case SAVE_CURSOR:
  352.                 savecursor();
  353.                 break;
  354.             case RESTORE_CURSOR:
  355.                 restorecursor();
  356.                 break;
  357.             case HIDE_CURSOR:
  358.                 normalcursor();
  359.                 hidecursor();
  360.                 break;
  361.             case SHOW_CURSOR:
  362.                 if (p1)
  363.                     set_cursor_type(0x0106);
  364.                 else
  365.                     set_cursor_type(0x0607);
  366.                 unhidecursor();
  367.                 break;
  368.             /* -------- mouse messages -------- */
  369.             case MOUSE_INSTALLED:
  370.                 rtn = mouse_installed();
  371.                 break;
  372.             case SHOW_MOUSE:
  373.                 show_mousecursor();
  374.                 break;
  375.             case HIDE_MOUSE:
  376.                 hide_mousecursor();
  377.                 break;
  378.             case MOUSE_CURSOR:
  379.                 set_mouseposition((int)p1, (int)p2);
  380.                 break;
  381.             case CURRENT_MOUSE_CURSOR:
  382.                 get_mouseposition((int*)p1,(int*)p2);
  383.                 break;
  384.             case WAITMOUSE:
  385.                 waitformouse();
  386.                 break;
  387.             case TESTMOUSE:
  388.                 rtn = mousebuttons();
  389.                 break;
  390.             case CAPTURE_MOUSE:
  391.                 if (p2)
  392.                     ((WINDOW)p2)->PrevMouse = CaptureMouse;
  393.                 else
  394.                     wnd->PrevMouse = CaptureMouse;
  395.                 CaptureMouse = wnd;
  396.                 NoChildCaptureMouse = (int)p1;
  397.                 break;
  398.             case RELEASE_MOUSE:
  399.                 CaptureMouse = wnd->PrevMouse;
  400.                 NoChildCaptureMouse = FALSE;
  401.                 break;
  402.             default:
  403.                 break;
  404.         }
  405.     }
  406.     return rtn;
  407. }
  408.  
  409. /* ---- dispatch messages to the message proc function ---- */
  410. int dispatch_message(void)
  411. {
  412.     WINDOW Mwnd, Kwnd;
  413.     /* -------- collect mouse and keyboard events ------- */
  414.     collect_events();
  415.     /* --------- dequeue and process events -------- */
  416.     while (EventQueueCtr > 0)  {
  417.         struct events ev;
  418.             
  419.         ev = EventQueue[EventQueueOffCtr];
  420.         if (++EventQueueOffCtr == MAXMESSAGES)
  421.             EventQueueOffCtr = 0;
  422.         --EventQueueCtr;
  423.  
  424.         /* ------ get the window in which a
  425.                         mouse event occurred ------ */
  426.         Mwnd = inWindow(ev.mx, ev.my);
  427.  
  428.         /* ---- process mouse captures ----- */
  429.         if (CaptureMouse != NULLWND)
  430.             if (Mwnd == NULLWND ||
  431.                     NoChildCaptureMouse ||
  432.                         GetParent(Mwnd) != CaptureMouse)
  433.                 Mwnd = CaptureMouse;
  434.  
  435.         /* ------ get the window in which a
  436.                         keyboard event occurred ------ */
  437.         Kwnd = inFocus;
  438.  
  439.         /* ---- process keyboard captures ----- */
  440.         if (CaptureKeyboard != NULLWND)
  441.             if (Kwnd == NULLWND ||
  442.                     NoChildCaptureKeyboard ||
  443.                         GetParent(Kwnd) != CaptureKeyboard)
  444.                 Kwnd = CaptureKeyboard;
  445.  
  446.         /* -------- send mouse and keyboard messages to the
  447.             window that should get them -------- */
  448.         switch (ev.event)    {
  449.             case SHIFT_CHANGED:
  450.             case KEYBOARD:
  451.                 SendMessage(Kwnd, ev.event, ev.mx, ev.my);
  452.                 break;
  453.             case LEFT_BUTTON:
  454.                 if (!CaptureMouse ||
  455.                         (!NoChildCaptureMouse &&
  456.                             GetParent(Mwnd) == CaptureMouse))
  457.                     if (Mwnd != inFocus)
  458.                         SendMessage(Mwnd, SETFOCUS, TRUE, 0);
  459.             case BUTTON_RELEASED:
  460.             case DOUBLE_CLICK:
  461.             case RIGHT_BUTTON:
  462.             case MOUSE_MOVED:
  463.                 SendMessage(Mwnd, ev.event, ev.mx, ev.my);
  464.                 break;
  465. #ifdef INCLUDE_CLOCK
  466.             case CLOCKTICK:
  467.                 SendMessage(Cwnd, ev.event,
  468.                     LPARAM(MK_FP(ev.mx, ev.my)), 0);
  469. #endif
  470.             default:
  471.                 break;
  472.         }
  473.     }
  474.     /* ------ dequeue and process messages ----- */
  475.     while (MsgQueueCtr > 0)  {
  476.         struct msgs mq;
  477.  
  478.         mq = MsgQueue[MsgQueueOffCtr];
  479.         if (++MsgQueueOffCtr == MAXMESSAGES)
  480.             MsgQueueOffCtr = 0;
  481.         --MsgQueueCtr;
  482.         SendMessage(mq.wnd, mq.msg, mq.p1, mq.p2);
  483.         if (mq.msg == STOP || mq.msg == ENDDIALOG)
  484.                return FALSE;
  485.     }
  486.     return TRUE;
  487. }
  488.  
  489.