File:  [OS/2 SDKs] / pmsdk / samples / wmchar / wmchar.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 12:28:22 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: pmsdk-1989, HEAD
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);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.