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