|
|
1.1 root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.