home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk11 / tk5 / wmchar / wmchar.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-02-20  |  16.2 KB  |  684 lines

  1. /***************************************************************************\
  2. * wmchar.c -- Displays WM_CHAR messages
  3. *
  4. * Created by Microsoft Corporation, 1989
  5. \***************************************************************************/
  6.  
  7.  
  8. #define INCL_WIN
  9. #define INCL_GPILCIDS
  10. #include <os2.h>
  11. #include <string.h>
  12. #include <stdio.h>
  13. #include "wmchar.h"
  14.  
  15.  
  16. #define max2(a, b)  ((a) > (b) ? (a) : (b))
  17. #define min2(a, b)  ((a) < (b) ? (a) : (b))
  18.  
  19.  
  20. /* display dependent values */
  21. SHORT gcyChar;
  22. SHORT gcxAveChar;
  23. SHORT gcxMaxChar;
  24. SHORT gcxMargin;
  25.  
  26. /* program globals */
  27. USHORT gcMessages = 0;      /* also the "number" of the most recent message */
  28. CHAR gszNull[] = "  --";    /* denotes an empty field */
  29. BOOL gfKeyUps = FALSE;
  30.  
  31.  
  32. /* char messages are stored in a circular buffer */
  33. typedef struct _CHMSG {     /* cm */
  34.     USHORT usKC;
  35.     UCHAR uchRep;
  36.     UCHAR uchScan;
  37.     USHORT ch;
  38.     USHORT usVK;
  39. } CHMSG;
  40.  
  41. #define CBUFFERELTS 20
  42.  
  43. CHMSG gacm[CBUFFERELTS];
  44. SHORT gicmStart = 0;
  45.  
  46.  
  47. /* display field attributes are stored in an array */
  48. typedef struct _MSGFIELD {  /* mf */
  49.     BOOL fDisplay;          /* TRUE if field is currently being displayed */
  50.     SHORT cxWidth;          /* field width, initially chars, then pixels */
  51.     CHAR *szHeading;        /* field heading */
  52. } MSGFIELD;
  53.  
  54. #define INUMBER         0
  55. #define IVIRTUALKEY     1
  56. #define ICHAR           2
  57. #define ISCANCODE       3
  58. #define IREPEAT         4
  59. #define IFLAGS          5
  60.  
  61. MSGFIELD gamf[CDISPLAYFIELDS] = {
  62.     TRUE,   7, " #",
  63.     TRUE,  15, "VK_ Value",
  64.     TRUE,  14, "Char",
  65.     FALSE, 10, "Scan",
  66.     FALSE, 8,  "Rep",
  67.     TRUE,  0,  "KC_ Flags"      /* variable width, so it's last */
  68. };
  69.  
  70. SHORT gcxMargin = 3;
  71.  
  72.  
  73. /* char flag strings */
  74. CHAR *gachFlags[] = {
  75.     "char",
  76.     "virtualkey",
  77.     "scancode",
  78.     "shift",
  79.     "ctrl",
  80.     "alt",
  81.     "keyup",
  82.     "prevdown",
  83.     "lonekey",
  84.     "deadkey",
  85.     "composite",
  86.     "invalidcomp",
  87.     "toggle",
  88.     "invalidchar",
  89.     "dbcsrsrvd1",
  90.     "dbcsrsrvd2"
  91. };
  92.  
  93. /* virtual key strings */
  94. CHAR *gachVK[] = {
  95.     gszNull,
  96.     "button1",
  97.     "button2",
  98.     "button3",
  99.     "break",
  100.     "backspace",
  101.     "tab",
  102.     "backtab",
  103.     "newline",
  104.     "shift",
  105.     "ctrl",
  106.     "alt",
  107.     "altgraf",
  108.     "pause",
  109.     "capslock",
  110.     "esc",
  111.     "space",
  112.     "pageup",
  113.     "pagedown",
  114.     "end",
  115.     "home",
  116.     "left",
  117.     "up",
  118.     "right",
  119.     "down",
  120.     "printscrn",
  121.     "insert",
  122.     "delete",
  123.     "scrllock",
  124.     "numlock",
  125.     "enter",
  126.     "sysrq",
  127.     "f1",
  128.     "f2",
  129.     "f3",
  130.     "f4",
  131.     "f5",
  132.     "f6",
  133.     "f7",
  134.     "f8",
  135.     "f9",
  136.     "f10",
  137.     "f11",
  138.     "f12",
  139.     "f13",
  140.     "f14",
  141.     "f15",
  142.     "f16",
  143.     "f17",
  144.     "f18",
  145.     "f19",
  146.     "f20",
  147.     "f21",
  148.     "f22",
  149.     "f23",
  150.     "f24"
  151. };
  152.  
  153.  
  154.  
  155. /***************************************************************************\
  156. * DrawText
  157. *
  158. * This function displays a text string.
  159. *
  160. * Parameters:
  161. *   hps:        presentation space
  162. *   cx, cy:     point to begin drawing
  163. *   sz:         string to draw
  164. *   iColor:     text color
  165. *   fExtent:    whether to calc extent or not
  166. *
  167. * Returns:
  168. *   x position of end of painted string if fExtent == TRUE
  169. \***************************************************************************/
  170.  
  171. SHORT DrawText(
  172.     HPS hps,
  173.     SHORT cx,
  174.     SHORT cy,
  175.     CHAR *sz,
  176.     LONG iColor,
  177.     BOOL fExtent)
  178. {
  179.     RECTL rcl;
  180.     SHORT cch;
  181.  
  182.     cch = strlen(sz);
  183.  
  184.     rcl.xLeft = cx;
  185.     rcl.xRight = cx + cch * gcxMaxChar;     /* hack */
  186.     rcl.yBottom = cy;
  187.     rcl.yTop = cy + gcyChar;
  188.  
  189.     WinDrawText(hps, cch, (PCH)sz, (PRECTL)&rcl, iColor, SYSCLR_WINDOW, 0);
  190.  
  191.     if (fExtent) {
  192.         WinDrawText(hps, cch, (PCH)sz, (PRECTL)&rcl, iColor,
  193.                     SYSCLR_WINDOW, DT_QUERYEXTENT);
  194.         return (SHORT)rcl.xRight;
  195.     }
  196.  
  197.     return 0;
  198. }
  199.  
  200.  
  201.  
  202. /***************************************************************************\
  203. * FormatHexChar
  204. *
  205. * This function formats an unsigned hex number into a string.  It is needed
  206. * to get around shortcomings of sprintf().
  207. *
  208. * Parameters:
  209. *   uch:    number to format
  210. *   sz:     string to get number
  211. \***************************************************************************/
  212.  
  213. VOID FormatHexChar(
  214.     USHORT uch,
  215.     CHAR *sz)
  216. {
  217.     sprintf(sz, "0x%2x", uch);
  218.  
  219.     /* patch up hex byte display */
  220.     if (strlen(sz) > 4) {
  221.         /* remove sign extension of byte */
  222.         sz[2] = sz[4];
  223.         sz[3] = sz[5];
  224.         sz[4] = 0;
  225.     } else if (sz[2] == ' ') {
  226.         /* fill in blank with 0 */
  227.         sz[2] = '0';
  228.     }
  229. }
  230.  
  231.  
  232.  
  233. /***************************************************************************\
  234. * DrawMessage
  235. *
  236. * This function draws a single message line.
  237. *
  238. * Parameters:
  239. *   hps:        presentation space
  240. *   iMessage:   message number to display
  241. *   pcm:        pointer to message structure
  242. *   cy:         y position of message
  243. \***************************************************************************/
  244.  
  245. VOID DrawMessage(
  246.     HPS hps,
  247.     SHORT iMessage,
  248.     CHMSG *pcm,
  249.     SHORT cy)
  250. {
  251.     CHAR sz[16];
  252.     USHORT fsFlags;
  253.     SHORT i;
  254.     SHORT cx;
  255.  
  256.     cx = gcxMargin;
  257.  
  258.     if (gamf[INUMBER].fDisplay) {
  259.         /* draw message number */
  260.         sprintf(sz, "%u.", iMessage);
  261.         DrawText(hps, cx, cy, sz, SYSCLR_WINDOWTEXT, FALSE);
  262.         cx += gamf[INUMBER].cxWidth;
  263.     }
  264.  
  265.     if (gamf[IVIRTUALKEY].fDisplay) {
  266.         /* draw virtual key code */
  267.         DrawText(hps, cx, cy, gachVK[pcm->usVK], SYSCLR_WINDOWTEXT,
  268.                  FALSE);
  269.         cx += gamf[IVIRTUALKEY].cxWidth;
  270.     }
  271.  
  272.     if (gamf[ICHAR].fDisplay) {
  273.         /* draw character */
  274.         if ((CHAR)pcm->ch) {
  275.             FormatHexChar(pcm->ch, sz);
  276.             DrawText(hps, cx, cy, sz, SYSCLR_WINDOWTEXT, FALSE);
  277.             sprintf(sz, "'%c'", (CHAR)pcm->ch);
  278.             DrawText(hps, cx + 7 * gcxAveChar, cy, sz, SYSCLR_WINDOWTEXT,
  279.                      FALSE);
  280.         } else {
  281.             DrawText(hps, cx, cy, gszNull, SYSCLR_WINDOWTEXT, FALSE);
  282.         }
  283.         cx += gamf[ICHAR].cxWidth;
  284.     }
  285.  
  286.     if (gamf[ISCANCODE].fDisplay) {
  287.         if (pcm->uchScan) {
  288.             FormatHexChar(pcm->uchScan, sz);
  289.             DrawText(hps, cx, cy, sz, SYSCLR_WINDOWTEXT, FALSE);
  290.         } else {
  291.             DrawText(hps, cx, cy, gszNull, SYSCLR_WINDOWTEXT, FALSE);
  292.         }
  293.         cx += gamf[ISCANCODE].cxWidth;
  294.     }
  295.  
  296.     if (gamf[IREPEAT].fDisplay) {
  297.         sprintf(sz, "%u", pcm->uchRep);
  298.         DrawText(hps, cx, cy, sz, SYSCLR_WINDOWTEXT, FALSE);
  299.         cx += gamf[IREPEAT].cxWidth;
  300.     }
  301.  
  302.     if (gamf[IFLAGS].fDisplay) {
  303.         /* draw KC_ flags */
  304.         fsFlags = pcm->usKC;
  305.         for (i = 0; i < 16; i++) {
  306.             if (fsFlags & 1) {
  307.                 switch (i) {
  308.                 case 0:
  309.                     if (gamf[ICHAR].fDisplay)
  310.                         goto DF_PRINTIT;
  311.                     break;
  312.                 case 1:
  313.                     if (gamf[IVIRTUALKEY].fDisplay)
  314.                         goto DF_PRINTIT;
  315.                     break;
  316.                 case 2:
  317.                     if (gamf[ISCANCODE].fDisplay)
  318.                         goto DF_PRINTIT;
  319.                     break;
  320.                 default:
  321. DF_PRINTIT:
  322.                     cx = DrawText(hps, cx, cy, gachFlags[i], SYSCLR_WINDOWTEXT, TRUE);
  323.                     cx += gcxAveChar;
  324.                 }
  325.             }
  326.             fsFlags >>= 1;
  327.         }
  328.         cx += gamf[IFLAGS].cxWidth;
  329.     }
  330. }
  331.  
  332.  
  333.  
  334. /***************************************************************************\
  335. * PaintClient
  336. *
  337. * This function paints a client window.
  338. *
  339. * Parameters:
  340. *   hwnd:   window handle
  341. \***************************************************************************/
  342.  
  343. VOID PaintClient(
  344.     HWND hwnd)
  345. {
  346.     HPS hps;
  347.     RECTL rcl;
  348.     SHORT iMessage;
  349.     SHORT yBottom;
  350.     SHORT cx;
  351.     SHORT i;
  352.  
  353.     hps = WinBeginPaint(hwnd, (HPS)NULL, (PRECTL)&rcl);
  354.  
  355.     /* clear invalidated region */
  356.     WinFillRect(hps, (PRECTL)&rcl, SYSCLR_WINDOW);
  357.  
  358.     /* get y position to start drawing */
  359.     WinQueryWindowRect(hwnd, (PRECTL)&rcl);
  360.     yBottom = (SHORT)(rcl.yTop - gcyChar - gcyChar / 2);
  361.  
  362.     /* draw headings */
  363.     cx = gcxMargin;
  364.     for (i = 0; i < CDISPLAYFIELDS; i++) {
  365.         if (gamf[i].fDisplay) {
  366.             DrawText(hps, cx, yBottom, gamf[i].szHeading,
  367.                     SYSCLR_WINDOWSTATICTEXT, FALSE);
  368.             cx += gamf[i].cxWidth;
  369.         }
  370.     }
  371.  
  372.     /* draw each entry */
  373.     i = gicmStart;
  374.     iMessage = gcMessages;
  375.     yBottom -= (gcyChar + gcyChar / 2);
  376.     do {
  377.         if (!iMessage || yBottom < -gcyChar)
  378.             break;
  379.  
  380.         DrawMessage(hps, iMessage, &gacm[i], yBottom);
  381.  
  382.         i = (i + 1) % CBUFFERELTS;
  383.         iMessage--;
  384.         yBottom -= gcyChar;
  385.  
  386.     } while (i != gicmStart);
  387.  
  388.     WinEndPaint(hps);
  389. }
  390.  
  391.  
  392.  
  393. /***************************************************************************\
  394. * NewMessage
  395. *
  396. * This function adds a new WM_CHAR message to the list.
  397. *
  398. * Parameters:
  399. *   hwnd:       window handle
  400. *   mp1, mp2:
  401. *   usKC:    key flags
  402. *   usVK:    virtual key code
  403. *   ch:     char;
  404. \***************************************************************************/
  405.  
  406. VOID NewMessage(
  407.     HWND hwnd,
  408.     MPARAM mp1,
  409.     MPARAM mp2)
  410. {
  411.     RECTL rclScroll, rclUpdate;
  412.     HPS hps;
  413.  
  414.     /* overwrite oldest entry */
  415.     if (gicmStart)
  416.         gicmStart--;
  417.     else
  418.         gicmStart = CBUFFERELTS - 1;
  419.  
  420.     gacm[gicmStart].usKC = SHORT1FROMMP(mp1);
  421.     gacm[gicmStart].uchRep = CHAR3FROMMP(mp1);
  422.     gacm[gicmStart].uchScan = CHAR4FROMMP(mp1);
  423.     gacm[gicmStart].ch = SHORT1FROMMP(mp2);
  424.     gacm[gicmStart].usVK = SHORT2FROMMP(mp2);
  425.  
  426.     gcMessages++;
  427.  
  428.     /* scroll and update intelligently */
  429.     WinQueryWindowRect(hwnd, (PRECTL)&rclScroll);
  430.     rclScroll.yTop -= 2 * gcyChar;
  431.     rclScroll.yBottom = max2(0L, rclScroll.yTop - (LONG)(CBUFFERELTS * gcyChar));
  432.  
  433.     WinScrollWindow(hwnd, 0, -gcyChar, (PRECTL)&rclScroll, (PRECTL)&rclScroll,
  434.                     NULL, &rclUpdate, 0);
  435.  
  436.     hps = WinGetPS(hwnd);
  437.     WinFillRect(hps, (PRECTL)&rclUpdate, SYSCLR_WINDOW);
  438.     DrawMessage( hps
  439.            , gcMessages
  440.            , &gacm[gicmStart]
  441.            , (SHORT)rclScroll.yTop - gcyChar );
  442.     WinReleasePS(hps);
  443. }
  444.  
  445.  
  446.  
  447. /***************************************************************************\
  448. * CheckMenuItem
  449. *
  450. * This function sets the check state of a menu item.
  451. *
  452. * Parameters:
  453. *   hwnd:   frame window
  454. *   id:     menu id
  455. *   fCheck: check state
  456. \***************************************************************************/
  457.  
  458. VOID CheckMenuItem(
  459.     HWND hwndFrame,
  460.     SHORT id,
  461.     BOOL fCheck)
  462. {
  463.     HWND hwndMenu;
  464.  
  465.     /* toggle menu checkmark */
  466.     hwndMenu = WinWindowFromID(hwndFrame, FID_MENU);
  467.     WinSendMsg(hwndMenu, MM_SETITEMATTR, MPFROM2SHORT(id, TRUE),
  468.                MPFROM2SHORT(MIA_CHECKED, fCheck ? MIA_CHECKED : 0));
  469. }
  470.  
  471.  
  472.  
  473. /***************************************************************************\
  474. * MenuCommand
  475. *
  476. * This function processes WM_COMMAND messages.
  477. *
  478. * Parameters:
  479. *   hwnd:   client window handle
  480. *   id:     command identifier
  481. \***************************************************************************/
  482.  
  483. VOID MenuCommand(
  484.     HWND hwnd,
  485.     SHORT id)
  486. {
  487.     BOOL *pfDisplay;
  488.     HWND hwndFrame;
  489.  
  490.     if (id == IDM_CLEAR) {
  491.  
  492.         /* clear current messages */
  493.         gcMessages = 0;
  494.         WinInvalidateRect(hwnd, NULL, FALSE);
  495.  
  496.     } else if (id == IDM_KEYUPS) {
  497.  
  498.         /* toggle logging keyups */
  499.         gfKeyUps = !gfKeyUps;
  500.         hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE);
  501.         CheckMenuItem(hwndFrame, IDM_KEYUPS, gfKeyUps);
  502.  
  503.     } else if (id >= IDM_DISPLAYFIRST && id <= IDM_DISPLAYLAST) {
  504.  
  505.         /* toggle display field */
  506.         pfDisplay = &(gamf[id - IDM_DISPLAYFIRST].fDisplay);
  507.         *pfDisplay = !*pfDisplay;
  508.         hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE);
  509.         CheckMenuItem(hwndFrame, id, *pfDisplay);
  510.  
  511.         /* repaint in new format */
  512.         WinInvalidateRect(hwnd, NULL, FALSE);
  513.     }
  514. }
  515.  
  516.  
  517.  
  518. /***************************************************************************\
  519. * MainWndProc
  520. *
  521. * This is the window procedure for the main client window.
  522. \***************************************************************************/
  523.  
  524. MRESULT CALLBACK MainWndProc(
  525.     HWND hwnd,
  526.     USHORT msg,
  527.     MPARAM mp1,
  528.     MPARAM mp2)
  529. {
  530.     switch (msg) {
  531.  
  532.     case WM_PAINT:
  533.         PaintClient(hwnd);
  534.         break;
  535.  
  536.     case WM_COMMAND:
  537.         MenuCommand(hwnd, SHORT1FROMMP(mp1));
  538.         break;
  539.  
  540.     case WM_CHAR:
  541.         if (gfKeyUps || !(KC_KEYUP & SHORT1FROMMP(mp1))) {
  542.  
  543.             /* add new message to list */
  544.             NewMessage(hwnd, mp1, mp2);
  545.         }
  546.         break;
  547.  
  548.     default:
  549.         return WinDefWindowProc(hwnd, msg, mp1, mp2);
  550.     }
  551.  
  552.     return (MRESULT)0;
  553. }
  554.  
  555.  
  556.  
  557. /***************************************************************************\
  558. * CheckMenus
  559. *
  560. * This function sets menu check marks according to their current internal
  561. * state.
  562. *
  563. * Parameters:
  564. *   hwndFrame:  main app window handle
  565. \***************************************************************************/
  566.  
  567. VOID CheckMenus(
  568.     HWND hwndFrame)
  569. {
  570.     SHORT id;
  571.  
  572.     CheckMenuItem(hwndFrame, IDM_KEYUPS, gfKeyUps);
  573.  
  574.     for (id = IDM_DISPLAYFIRST; id <= IDM_DISPLAYLAST; id++) {
  575.         CheckMenuItem(hwndFrame, id, gamf[id - IDM_DISPLAYFIRST].fDisplay);
  576.     }
  577. }
  578.  
  579.  
  580.  
  581. /***************************************************************************\
  582. * RegisterSwitchEntry
  583. *
  584. * This function registers the app with the switch list.
  585. *
  586. * Parameters:
  587. *   hwndFrame:  main app window handle
  588. \***************************************************************************/
  589.  
  590. VOID RegisterSwitchEntry(
  591.     HWND hwndFrame)
  592. {
  593.     PID pid;
  594.     TID tid;
  595.     SWCNTRL swc;
  596.  
  597.     WinQueryWindowProcess(hwndFrame, (PPID)&pid, (PTID)&tid);
  598.     WinQueryWindowText(hwndFrame, MAXNAMEL, (PSZ)swc.szSwtitle);
  599.     swc.hwnd = hwndFrame;
  600.     swc.hwndIcon = (ULONG)NULL;
  601.     swc.hprog = (HPROGRAM)NULL;
  602.     swc.idProcess = pid;
  603.     swc.idSession = NULL;
  604.     swc.uchVisibility = SWL_VISIBLE;
  605.     swc.fbJump = SWL_JUMPABLE;
  606.     WinAddSwitchEntry((PSWCNTRL)&swc);
  607. }
  608.  
  609.  
  610.  
  611. /***************************************************************************\
  612. * GetDisplayValues
  613. *
  614. * This function sets display dependent global variables.
  615. \***************************************************************************/
  616.  
  617. VOID GetDisplayValues(VOID)
  618. {
  619.     HPS hps;
  620.     FONTMETRICS fm;
  621.     SHORT i;
  622.  
  623.     hps = WinGetPS(HWND_DESKTOP);
  624.     GpiQueryFontMetrics(hps, (ULONG)sizeof(FONTMETRICS), (PFONTMETRICS)&fm);
  625.     WinReleasePS(hps);
  626.  
  627.     gcyChar = (SHORT)(fm.lMaxBaselineExt + fm.lExternalLeading);
  628.     gcxAveChar = (SHORT)fm.lAveCharWidth;
  629.     gcxMaxChar = (SHORT)fm.lMaxCharInc;
  630.  
  631.     /* adjust display widths for this font */
  632.     gcxMargin *= gcxAveChar;
  633.     for (i = 0; i < CDISPLAYFIELDS; i++) {
  634.         gamf[i].cxWidth *= gcxAveChar;
  635.     }
  636. }
  637.  
  638.  
  639.  
  640. /***************************************************************************\
  641. * main
  642. *
  643. * This is the main procedure for the app.
  644. \***************************************************************************/
  645.  
  646. VOID cdecl main(VOID)
  647. {
  648.     HAB hab;
  649.     HMQ hmq;
  650.     QMSG qmsg;
  651.     ULONG ulCreate;
  652.     HWND hwndFrame;
  653.     HWND hwndClient;
  654.     static CHAR szApp[] = "Char Messages";
  655.  
  656.     /* init app */
  657.     hab = WinInitialize(NULL);
  658.     hmq = WinCreateMsgQueue(hab, 0);
  659.     GetDisplayValues();
  660.  
  661.     /* create main window */
  662.     WinRegisterClass(hab, szApp, MainWndProc, 0L, 0);
  663.     ulCreate = FCF_TITLEBAR | FCF_SYSMENU | FCF_MINMAX | FCF_SIZEBORDER |
  664.                FCF_MENU | FCF_SHELLPOSITION;
  665.     hwndFrame = WinCreateStdWindow(HWND_DESKTOP, WS_VISIBLE, &ulCreate,
  666.                                     szApp, szApp, 0L, NULL, ID_RESOURCES,
  667.                                     &hwndClient);
  668.  
  669.     /* register with switch list */
  670.     RegisterSwitchEntry(hwndFrame);
  671.  
  672.     /* initialize menu */
  673.     CheckMenus(hwndFrame);
  674.  
  675.     /* message loop */
  676.     while (WinGetMsg(hab, &qmsg, NULL, 0, 0))
  677.         WinDispatchMsg(hab, &qmsg);
  678.  
  679.     /* clean up */
  680.     WinDestroyWindow(hwndFrame);
  681.     WinDestroyMsgQueue(hmq);
  682.     WinTerminate(hab);
  683. }
  684.