home *** CD-ROM | disk | FTP | other *** search
/ Computer Select (Limited Edition) / Computer Select.iso / dobbs / v17n02 / dflt10.exe / MESSAGE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-21  |  16.4 KB  |  547 lines

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