|
|
Microsoft OS/2 SDK PM 02-24-1989
/***************************************************************************\
* wmchar.c -- Displays WM_CHAR messages
*
* Created by Microsoft Corporation, 1989
\***************************************************************************/
#define INCL_WIN
#define INCL_GPILCIDS
#include <os2.h>
#include <string.h>
#include <stdio.h>
#include "wmchar.h"
#define max2(a, b) ((a) > (b) ? (a) : (b))
#define min2(a, b) ((a) < (b) ? (a) : (b))
/* display dependent values */
SHORT gcyChar;
SHORT gcxAveChar;
SHORT gcxMaxChar;
SHORT gcxMargin;
/* program globals */
USHORT gcMessages = 0; /* also the "number" of the most recent message */
CHAR gszNull[] = " --"; /* denotes an empty field */
BOOL gfKeyUps = FALSE;
/* char messages are stored in a circular buffer */
typedef struct _CHMSG { /* cm */
USHORT usKC;
UCHAR uchRep;
UCHAR uchScan;
USHORT ch;
USHORT usVK;
} CHMSG;
#define CBUFFERELTS 20
CHMSG gacm[CBUFFERELTS];
SHORT gicmStart = 0;
/* display field attributes are stored in an array */
typedef struct _MSGFIELD { /* mf */
BOOL fDisplay; /* TRUE if field is currently being displayed */
SHORT cxWidth; /* field width, initially chars, then pixels */
CHAR *szHeading; /* field heading */
} MSGFIELD;
#define INUMBER 0
#define IVIRTUALKEY 1
#define ICHAR 2
#define ISCANCODE 3
#define IREPEAT 4
#define IFLAGS 5
MSGFIELD gamf[CDISPLAYFIELDS] = {
TRUE, 7, " #",
TRUE, 15, "VK_ Value",
TRUE, 14, "Char",
FALSE, 10, "Scan",
FALSE, 8, "Rep",
TRUE, 0, "KC_ Flags" /* variable width, so it's last */
};
SHORT gcxMargin = 3;
/* char flag strings */
CHAR *gachFlags[] = {
"char",
"virtualkey",
"scancode",
"shift",
"ctrl",
"alt",
"keyup",
"prevdown",
"lonekey",
"deadkey",
"composite",
"invalidcomp",
"toggle",
"invalidchar",
"dbcsrsrvd1",
"dbcsrsrvd2"
};
/* virtual key strings */
CHAR *gachVK[] = {
gszNull,
"button1",
"button2",
"button3",
"break",
"backspace",
"tab",
"backtab",
"newline",
"shift",
"ctrl",
"alt",
"altgraf",
"pause",
"capslock",
"esc",
"space",
"pageup",
"pagedown",
"end",
"home",
"left",
"up",
"right",
"down",
"printscrn",
"insert",
"delete",
"scrllock",
"numlock",
"enter",
"sysrq",
"f1",
"f2",
"f3",
"f4",
"f5",
"f6",
"f7",
"f8",
"f9",
"f10",
"f11",
"f12",
"f13",
"f14",
"f15",
"f16",
"f17",
"f18",
"f19",
"f20",
"f21",
"f22",
"f23",
"f24"
};
/***************************************************************************\
* DrawText
*
* This function displays a text string.
*
* Parameters:
* hps: presentation space
* cx, cy: point to begin drawing
* sz: string to draw
* iColor: text color
* fExtent: whether to calc extent or not
*
* Returns:
* x position of end of painted string if fExtent == TRUE
\***************************************************************************/
SHORT DrawText(
HPS hps,
SHORT cx,
SHORT cy,
CHAR *sz,
LONG iColor,
BOOL fExtent)
{
RECTL rcl;
SHORT cch;
cch = strlen(sz);
rcl.xLeft = cx;
rcl.xRight = cx + cch * gcxMaxChar; /* hack */
rcl.yBottom = cy;
rcl.yTop = cy + gcyChar;
WinDrawText(hps, cch, (PCH)sz, (PRECTL)&rcl, iColor, SYSCLR_WINDOW, 0);
if (fExtent) {
WinDrawText(hps, cch, (PCH)sz, (PRECTL)&rcl, iColor,
SYSCLR_WINDOW, DT_QUERYEXTENT);
return (SHORT)rcl.xRight;
}
return 0;
}
/***************************************************************************\
* FormatHexChar
*
* This function formats an unsigned hex number into a string. It is needed
* to get around shortcomings of sprintf().
*
* Parameters:
* uch: number to format
* sz: string to get number
\***************************************************************************/
VOID FormatHexChar(
USHORT uch,
CHAR *sz)
{
sprintf(sz, "0x%2x", uch);
/* patch up hex byte display */
if (strlen(sz) > 4) {
/* remove sign extension of byte */
sz[2] = sz[4];
sz[3] = sz[5];
sz[4] = 0;
} else if (sz[2] == ' ') {
/* fill in blank with 0 */
sz[2] = '0';
}
}
/***************************************************************************\
* DrawMessage
*
* This function draws a single message line.
*
* Parameters:
* hps: presentation space
* iMessage: message number to display
* pcm: pointer to message structure
* cy: y position of message
\***************************************************************************/
VOID DrawMessage(
HPS hps,
SHORT iMessage,
CHMSG *pcm,
SHORT cy)
{
CHAR sz[16];
USHORT fsFlags;
SHORT i;
SHORT cx;
cx = gcxMargin;
if (gamf[INUMBER].fDisplay) {
/* draw message number */
sprintf(sz, "%u.", iMessage);
DrawText(hps, cx, cy, sz, SYSCLR_WINDOWTEXT, FALSE);
cx += gamf[INUMBER].cxWidth;
}
if (gamf[IVIRTUALKEY].fDisplay) {
/* draw virtual key code */
DrawText(hps, cx, cy, gachVK[pcm->usVK], SYSCLR_WINDOWTEXT,
FALSE);
cx += gamf[IVIRTUALKEY].cxWidth;
}
if (gamf[ICHAR].fDisplay) {
/* draw character */
if ((CHAR)pcm->ch) {
FormatHexChar(pcm->ch, sz);
DrawText(hps, cx, cy, sz, SYSCLR_WINDOWTEXT, FALSE);
sprintf(sz, "'%c'", (CHAR)pcm->ch);
DrawText(hps, cx + 7 * gcxAveChar, cy, sz, SYSCLR_WINDOWTEXT,
FALSE);
} else {
DrawText(hps, cx, cy, gszNull, SYSCLR_WINDOWTEXT, FALSE);
}
cx += gamf[ICHAR].cxWidth;
}
if (gamf[ISCANCODE].fDisplay) {
if (pcm->uchScan) {
FormatHexChar(pcm->uchScan, sz);
DrawText(hps, cx, cy, sz, SYSCLR_WINDOWTEXT, FALSE);
} else {
DrawText(hps, cx, cy, gszNull, SYSCLR_WINDOWTEXT, FALSE);
}
cx += gamf[ISCANCODE].cxWidth;
}
if (gamf[IREPEAT].fDisplay) {
sprintf(sz, "%u", pcm->uchRep);
DrawText(hps, cx, cy, sz, SYSCLR_WINDOWTEXT, FALSE);
cx += gamf[IREPEAT].cxWidth;
}
if (gamf[IFLAGS].fDisplay) {
/* draw KC_ flags */
fsFlags = pcm->usKC;
for (i = 0; i < 16; i++) {
if (fsFlags & 1) {
switch (i) {
case 0:
if (gamf[ICHAR].fDisplay)
goto DF_PRINTIT;
break;
case 1:
if (gamf[IVIRTUALKEY].fDisplay)
goto DF_PRINTIT;
break;
case 2:
if (gamf[ISCANCODE].fDisplay)
goto DF_PRINTIT;
break;
default:
DF_PRINTIT:
cx = DrawText(hps, cx, cy, gachFlags[i], SYSCLR_WINDOWTEXT, TRUE);
cx += gcxAveChar;
}
}
fsFlags >>= 1;
}
cx += gamf[IFLAGS].cxWidth;
}
}
/***************************************************************************\
* PaintClient
*
* This function paints a client window.
*
* Parameters:
* hwnd: window handle
\***************************************************************************/
VOID PaintClient(
HWND hwnd)
{
HPS hps;
RECTL rcl;
SHORT iMessage;
SHORT yBottom;
SHORT cx;
SHORT i;
hps = WinBeginPaint(hwnd, (HPS)NULL, (PRECTL)&rcl);
/* clear invalidated region */
WinFillRect(hps, (PRECTL)&rcl, SYSCLR_WINDOW);
/* get y position to start drawing */
WinQueryWindowRect(hwnd, (PRECTL)&rcl);
yBottom = (SHORT)(rcl.yTop - gcyChar - gcyChar / 2);
/* draw headings */
cx = gcxMargin;
for (i = 0; i < CDISPLAYFIELDS; i++) {
if (gamf[i].fDisplay) {
DrawText(hps, cx, yBottom, gamf[i].szHeading,
SYSCLR_WINDOWSTATICTEXT, FALSE);
cx += gamf[i].cxWidth;
}
}
/* draw each entry */
i = gicmStart;
iMessage = gcMessages;
yBottom -= (gcyChar + gcyChar / 2);
do {
if (!iMessage || yBottom < -gcyChar)
break;
DrawMessage(hps, iMessage, &gacm[i], yBottom);
i = (i + 1) % CBUFFERELTS;
iMessage--;
yBottom -= gcyChar;
} while (i != gicmStart);
WinEndPaint(hps);
}
/***************************************************************************\
* NewMessage
*
* This function adds a new WM_CHAR message to the list.
*
* Parameters:
* hwnd: window handle
* mp1, mp2:
* usKC: key flags
* usVK: virtual key code
* ch: char;
\***************************************************************************/
VOID NewMessage(
HWND hwnd,
MPARAM mp1,
MPARAM mp2)
{
RECTL rclScroll, rclUpdate;
HPS hps;
/* overwrite oldest entry */
if (gicmStart)
gicmStart--;
else
gicmStart = CBUFFERELTS - 1;
gacm[gicmStart].usKC = SHORT1FROMMP(mp1);
gacm[gicmStart].uchRep = CHAR3FROMMP(mp1);
gacm[gicmStart].uchScan = CHAR4FROMMP(mp1);
gacm[gicmStart].ch = SHORT1FROMMP(mp2);
gacm[gicmStart].usVK = SHORT2FROMMP(mp2);
gcMessages++;
/* scroll and update intelligently */
WinQueryWindowRect(hwnd, (PRECTL)&rclScroll);
rclScroll.yTop -= 2 * gcyChar;
rclScroll.yBottom = max2(0L, rclScroll.yTop - (LONG)(CBUFFERELTS * gcyChar));
WinScrollWindow(hwnd, 0, -gcyChar, (PRECTL)&rclScroll, (PRECTL)&rclScroll,
NULL, &rclUpdate, 0);
hps = WinGetPS(hwnd);
WinFillRect(hps, (PRECTL)&rclUpdate, SYSCLR_WINDOW);
DrawMessage( hps
, gcMessages
, &gacm[gicmStart]
, (SHORT)rclScroll.yTop - gcyChar );
WinReleasePS(hps);
}
/***************************************************************************\
* CheckMenuItem
*
* This function sets the check state of a menu item.
*
* Parameters:
* hwnd: frame window
* id: menu id
* fCheck: check state
\***************************************************************************/
VOID CheckMenuItem(
HWND hwndFrame,
SHORT id,
BOOL fCheck)
{
HWND hwndMenu;
/* toggle menu checkmark */
hwndMenu = WinWindowFromID(hwndFrame, FID_MENU);
WinSendMsg(hwndMenu, MM_SETITEMATTR, MPFROM2SHORT(id, TRUE),
MPFROM2SHORT(MIA_CHECKED, fCheck ? MIA_CHECKED : 0));
}
/***************************************************************************\
* MenuCommand
*
* This function processes WM_COMMAND messages.
*
* Parameters:
* hwnd: client window handle
* id: command identifier
\***************************************************************************/
VOID MenuCommand(
HWND hwnd,
SHORT id)
{
BOOL *pfDisplay;
HWND hwndFrame;
if (id == IDM_CLEAR) {
/* clear current messages */
gcMessages = 0;
WinInvalidateRect(hwnd, NULL, FALSE);
} else if (id == IDM_KEYUPS) {
/* toggle logging keyups */
gfKeyUps = !gfKeyUps;
hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE);
CheckMenuItem(hwndFrame, IDM_KEYUPS, gfKeyUps);
} else if (id >= IDM_DISPLAYFIRST && id <= IDM_DISPLAYLAST) {
/* toggle display field */
pfDisplay = &(gamf[id - IDM_DISPLAYFIRST].fDisplay);
*pfDisplay = !*pfDisplay;
hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE);
CheckMenuItem(hwndFrame, id, *pfDisplay);
/* repaint in new format */
WinInvalidateRect(hwnd, NULL, FALSE);
}
}
/***************************************************************************\
* MainWndProc
*
* This is the window procedure for the main client window.
\***************************************************************************/
MRESULT CALLBACK MainWndProc(
HWND hwnd,
USHORT msg,
MPARAM mp1,
MPARAM mp2)
{
switch (msg) {
case WM_PAINT:
PaintClient(hwnd);
break;
case WM_COMMAND:
MenuCommand(hwnd, SHORT1FROMMP(mp1));
break;
case WM_CHAR:
if (gfKeyUps || !(KC_KEYUP & SHORT1FROMMP(mp1))) {
/* add new message to list */
NewMessage(hwnd, mp1, mp2);
}
break;
default:
return WinDefWindowProc(hwnd, msg, mp1, mp2);
}
return (MRESULT)0;
}
/***************************************************************************\
* CheckMenus
*
* This function sets menu check marks according to their current internal
* state.
*
* Parameters:
* hwndFrame: main app window handle
\***************************************************************************/
VOID CheckMenus(
HWND hwndFrame)
{
SHORT id;
CheckMenuItem(hwndFrame, IDM_KEYUPS, gfKeyUps);
for (id = IDM_DISPLAYFIRST; id <= IDM_DISPLAYLAST; id++) {
CheckMenuItem(hwndFrame, id, gamf[id - IDM_DISPLAYFIRST].fDisplay);
}
}
/***************************************************************************\
* RegisterSwitchEntry
*
* This function registers the app with the switch list.
*
* Parameters:
* hwndFrame: main app window handle
\***************************************************************************/
VOID RegisterSwitchEntry(
HWND hwndFrame)
{
PID pid;
TID tid;
SWCNTRL swc;
WinQueryWindowProcess(hwndFrame, (PPID)&pid, (PTID)&tid);
WinQueryWindowText(hwndFrame, MAXNAMEL, (PSZ)swc.szSwtitle);
swc.hwnd = hwndFrame;
swc.hwndIcon = (ULONG)NULL;
swc.hprog = (HPROGRAM)NULL;
swc.idProcess = pid;
swc.idSession = NULL;
swc.uchVisibility = SWL_VISIBLE;
swc.fbJump = SWL_JUMPABLE;
WinAddSwitchEntry((PSWCNTRL)&swc);
}
/***************************************************************************\
* GetDisplayValues
*
* This function sets display dependent global variables.
\***************************************************************************/
VOID GetDisplayValues(VOID)
{
HPS hps;
FONTMETRICS fm;
SHORT i;
hps = WinGetPS(HWND_DESKTOP);
GpiQueryFontMetrics(hps, (ULONG)sizeof(FONTMETRICS), (PFONTMETRICS)&fm);
WinReleasePS(hps);
gcyChar = (SHORT)(fm.lMaxBaselineExt + fm.lExternalLeading);
gcxAveChar = (SHORT)fm.lAveCharWidth;
gcxMaxChar = (SHORT)fm.lMaxCharInc;
/* adjust display widths for this font */
gcxMargin *= gcxAveChar;
for (i = 0; i < CDISPLAYFIELDS; i++) {
gamf[i].cxWidth *= gcxAveChar;
}
}
/***************************************************************************\
* main
*
* This is the main procedure for the app.
\***************************************************************************/
VOID cdecl main(VOID)
{
HAB hab;
HMQ hmq;
QMSG qmsg;
ULONG ulCreate;
HWND hwndFrame;
HWND hwndClient;
static CHAR szApp[] = "Char Messages";
/* init app */
hab = WinInitialize(NULL);
hmq = WinCreateMsgQueue(hab, 0);
GetDisplayValues();
/* create main window */
WinRegisterClass(hab, szApp, MainWndProc, 0L, 0);
ulCreate = FCF_TITLEBAR | FCF_SYSMENU | FCF_MINMAX | FCF_SIZEBORDER |
FCF_MENU | FCF_SHELLPOSITION;
hwndFrame = WinCreateStdWindow(HWND_DESKTOP, WS_VISIBLE, &ulCreate,
szApp, szApp, 0L, NULL, ID_RESOURCES,
&hwndClient);
/* register with switch list */
RegisterSwitchEntry(hwndFrame);
/* initialize menu */
CheckMenus(hwndFrame);
/* message loop */
while (WinGetMsg(hab, &qmsg, NULL, 0, 0))
WinDispatchMsg(hab, &qmsg);
/* clean up */
WinDestroyWindow(hwndFrame);
WinDestroyMsgQueue(hmq);
WinTerminate(hab);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.