Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
kcapApp.c
/* |
File: kcapApp.c |
Contains: demonstration keyboard drawing from KCAP resource |
Written by: Greg Robbins |
Copyright: Copyright © 1991-1999 by Apple Computer, Inc., All Rights Reserved. |
You may incorporate this Apple sample source code into your program(s) without |
restriction. This Apple sample source code has been provided "AS IS" and the |
responsibility for its operation is yours. You are not permitted to redistribute |
this Apple sample source code as "Apple sample source code" after having made |
changes. If you're going to re-distribute the source, we require that you make |
it clear in the source that the code was descended from Apple sample source |
code, but that you've made changes. |
Change History (most recent first): |
8/6/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1 |
2/92 uses RGetResource rather than GetResource for KCAP; |
gets KCHR number from script manager |
adds menu of KCAP IDs, displays virtual keycodes |
*/ |
#include <String.h> |
#include <Dialogs.h> |
#include <Desk.h> |
#include <ToolUtils.h> |
#include <LowMem.h> |
#include <TextUtils.h> |
/* Constants */ |
#define appleID 1000 /* resource IDs/menu IDs for Apple, */ |
#define fileID 1001 /* File and */ |
#define editID 1002 /* Edit menus */ |
#define displayID 1003 |
#define appleM 0 /* Index for each menu in myMenus (array of menu handles) */ |
#define fileM 1 |
#define editM 2 |
#define displayM 3 |
#define menuCount 4 /* Total number of menus */ |
#define windowID 1000 /* Resource ID for main window */ |
#define aboutMeDLOG 1000 /* And Resource ID for About box dialog. */ |
#define quitItem 1 /* Quit in the File menu */ |
#define aboutMeCommand 1 /* Menu item in apple menu for About */ |
/* Globals */ |
MenuHandle myMenus[menuCount]; |
Rect dragRect; |
Boolean doneFlag; |
EventRecord myEvent; |
WindowPtr myWindow, whichWindow; |
char theChar; |
Boolean gKeycodesFlag = false; |
short gKcapNum, gCurrDisplayItem; |
void SetUpMenus(); |
void DoCommand(long int mResult); |
void DrawKeyCaps(short modifiers, short kcharNum, short kcapNum, Boolean keycodesFlag); |
void ShowAboutMeDialog(); |
void main(void) |
{ |
Str255 tempStr, tempStr2; |
StringHandle tempStrHandle; |
InitGraf(&qd.thePort); |
InitFonts(); |
InitWindows(); |
InitMenus(); |
TEInit(); |
InitDialogs(nil); |
InitCursor(); |
SetRect(&dragRect, 4, 24, qd.screenBits.bounds.right - 4, qd.screenBits.bounds.bottom - 4); |
doneFlag = false; /* flag to detect when Quit command is chosen */ |
myWindow = GetNewWindow(windowID, nil, (WindowPtr) -1); |
SetPort(myWindow); |
SetUpMenus(); |
/* |
** Main Event Loop |
*/ |
do { |
if (WaitNextEvent(everyEvent, &myEvent, 600, nil)) { |
switch (myEvent.what) { /* case on event type */ |
case mouseDown: |
switch (FindWindow(myEvent.where, &whichWindow)) { |
case inSysWindow: /* desk accessory window: call Desk Manager to handle it */ |
SystemClick(&myEvent, whichWindow); |
break; |
case inMenuBar: /* Menu bar: learn which command, then execute it. */ |
DoCommand(MenuSelect(myEvent.where)); |
break; |
case inDrag: /* title bar: call Window Manager to drag */ |
DragWindow(whichWindow, myEvent.where, &dragRect); |
break; |
case inContent: /* body of application window: */ |
if (whichWindow != FrontWindow()) |
SelectWindow(whichWindow); /* and make it active if not */ |
break; |
} |
break; |
case updateEvt: /* Update the window. */ |
if ((WindowPtr) myEvent.message == myWindow) { |
BeginUpdate((WindowPtr) myEvent.message); |
/* draw keyboard using current keyboard modifiers, |
current KCHR, current keyboard KCAP |
see Tech Note 263 for a better way to get the |
KCHR data under System 7 */ |
DrawKeyCaps(myEvent.modifiers, |
GetScriptVariable(GetScriptManagerVariable(smKeyScript), smScriptKeys), |
gKcapNum, gKeycodesFlag); |
EndUpdate((WindowPtr) myEvent.message); |
/* set window title */ |
NumToString(gKcapNum, tempStr); |
if (gKeycodesFlag) { |
/* set window title to "Virtual Keycodes for KCAP ID _" */ |
tempStrHandle = GetString(128); |
if (tempStrHandle) { |
p2cstr(*tempStrHandle); |
strcpy((char*)tempStr2, (const char*)*tempStrHandle); |
strcat((char*)tempStr2, p2cstr(tempStr)); |
SetWTitle(myWindow, c2pstr((char*)tempStr2)); |
ReleaseResource((Handle)tempStrHandle); |
} |
} |
else { |
tempStrHandle = GetString(129); |
if (tempStrHandle) { |
/* set window title to "Key Labels for KCAP ID _ and KCHR _" */ |
p2cstr(*tempStrHandle); |
strcpy((char*)tempStr2, (const char*)*tempStrHandle); /* string */ |
strcat((char*)tempStr2, p2cstr(tempStr)); /* KCAP # */ |
ReleaseResource((Handle)tempStrHandle); |
tempStrHandle = GetString(130); |
if (tempStrHandle) { |
p2cstr(*tempStrHandle); |
strcat((char*)tempStr2, (const char*)*tempStrHandle); /* string */ |
/* get current KCHR number */ |
NumToString(GetScriptVariable(GetScriptManagerVariable(smKeyScript), smScriptKeys), tempStr); |
strcat((char*)tempStr2, p2cstr(tempStr)); /* KCHR # */ |
SetWTitle(myWindow, c2pstr((char*)tempStr2)); |
ReleaseResource((Handle)tempStrHandle); |
} |
} |
} |
} |
break; |
case keyDown: |
case autoKey: /* key pressed once or held down to repeat */ |
if (myWindow == FrontWindow()) { |
theChar = (myEvent.message & charCodeMask); /* get the char */ |
/* |
** If Command key down, do it as a Menu Command. |
*/ |
if (myEvent.modifiers & cmdKey) |
DoCommand(MenuKey(theChar)); |
else { |
EraseRect(&myWindow->portRect); |
InvalRect(&myWindow->portRect); |
} |
} |
break; |
} |
} |
} while (!doneFlag); |
DisposeWindow (myWindow); |
} |
void SetUpMenus() |
{ |
short i, kcapMaxCount, tempInt; |
Handle kcapHandle; |
Str255 tempStr, kcapStr; |
ResType tempResType; |
myMenus[appleM] = GetMenu(appleID); /* read Apple menu from resource file */ |
AppendResMenu(myMenus[appleM], 'DRVR'); /* add desk accessory names to Apple menu */ |
myMenus[fileM] = GetMenu(fileID); /* read file menu from resource file */ |
myMenus[editM] = GetMenu(editID); /* read edit menu from resource file */ |
DisableItem(myMenus[editM], 0); |
myMenus[displayM] = GetMenu(displayID); /* read display menu from resource file */ |
/* add IDs of KCAP resources to display menu */ |
gKcapNum = LMGetKbdType(); /* KCAP ID of current keyboard */ |
LMSetROMMapInsert (0x0100); /* use ROM resources, SetResLoad(false) */ |
kcapMaxCount = CountResources('KCAP'); |
if (kcapMaxCount > 0) AppendMenu(myMenus[displayM], "\p(-!"); |
/* add KCAP menu items */ |
for (i = 1; i <= kcapMaxCount; i++) { |
LMSetROMMapInsert (0x0100); |
kcapHandle = GetIndResource('KCAP', i); |
if (kcapHandle) { |
GetResInfo(kcapHandle, &tempInt, &tempResType, tempStr); |
NumToString(tempInt, tempStr); |
AppendMenu(myMenus[displayM], |
c2pstr(strcat(strcpy((char*)kcapStr, "KCAP "), p2cstr(tempStr)))); |
ReleaseResource(kcapHandle); |
if (tempInt == gKcapNum) { |
CheckItem(myMenus[displayM], i+2, true); |
gCurrDisplayItem = i+2; |
} |
} |
} |
gKeycodesFlag = false; /* not displaying keycodes on keys initially */ |
CheckItem(myMenus[displayM], 1, !gKeycodesFlag); /* mark that key labels are displayed */ |
for (i = 0; i < menuCount; i++) |
InsertMenu(myMenus[i], 0); /* install menus in menu bar */ |
DrawMenuBar(); /* and draw menu bar */ |
} |
void ShowAboutMeDialog() |
{ |
DialogPtr theDialog; |
short itemHit; |
theDialog = GetNewDialog(aboutMeDLOG, nil, (WindowPtr) -1); |
ModalDialog(nil, &itemHit); |
DisposeDialog(theDialog); |
} |
/* DrawKeyCaps draws the key caps, given a set of |
modifiers (in the high byte of the short) and |
KCHR and KCAP resource IDs, using the current pen in |
the current GrafPort |
if keycodesFlag is true, the virtual keycodes are drawn |
rather than the key labels. |
kcapPtr just bounces along the resource data as we |
parse it |
*/ |
/* see resource type definition on p. 14-101 of IM VI */ |
void DrawKeyCaps(short modifiers, short kchrNum, short kcapNum, Boolean keycodesFlag) |
{ |
typedef struct { |
char modifierMask; |
char keyCode; |
short deltaV; |
short deltaH; |
} KeyEntryRec; |
#define SHAPEMAXPTS 10 /* hopefully, fewer than 10 points per shape */ |
Rect tempRect; |
Point penPoint, currPoint, swapPoint; |
Point shapePoint[SHAPEMAXPTS]; |
Handle kcapResHandle; |
Ptr kcapPtr; |
KeyEntryRec thisKeyEntryRec; |
short mainIndex, shapeIndex, keyIndex, shapeTotal, shapeCount; |
short modifiedKeyCode; |
FontInfo theFontInfo; |
short fontHeight; |
Point charLoc; |
char theChar; |
RgnHandle keyshapeRgnHandle; |
Handle kchrResHandle; |
long state; |
Str255 keycodeStr; |
short saveTextSize; |
GetFontInfo(&theFontInfo); |
fontHeight = theFontInfo.ascent + theFontInfo.descent; |
saveTextSize = myWindow->txSize; |
kchrResHandle = RGetResource('KCHR', kchrNum); |
if (ResError() == noErr && kchrResHandle != nil) { |
state = 0; |
kcapResHandle = RGetResource('KCAP', kcapNum); |
if (ResError() == noErr && kcapResHandle != nil) { |
keyshapeRgnHandle = NewRgn(); |
MoveHHi(kcapResHandle); |
HLock(kcapResHandle); |
kcapPtr = *kcapResHandle; |
/* draw boundary from origin */ |
tempRect = *((Rect *) kcapPtr); |
OffsetRect(&tempRect, - tempRect.left, -tempRect.top); |
EraseRect(&tempRect); |
FrameRect(&tempRect); |
kcapPtr += sizeof(Rect); |
/* draw textedit area */ |
tempRect = *((Rect *) kcapPtr); |
FrameRect(&tempRect); |
kcapPtr += sizeof(Rect); |
/* loop through main array */ |
mainIndex = *((short *) kcapPtr); |
kcapPtr += sizeof(short); |
for ( ; mainIndex>0; mainIndex--) { |
/* loop through shape array - build array of points for this shape */ |
shapeIndex = *((short *) kcapPtr); |
kcapPtr += sizeof(short); |
shapeTotal = (shapeIndex < SHAPEMAXPTS ? shapeIndex + 1 : SHAPEMAXPTS); |
for (shapeCount=0; shapeIndex>-1; shapeIndex--, shapeCount++) { |
shapePoint[shapeCount] = *((Point *) kcapPtr); |
kcapPtr += sizeof(Point); |
} |
/* start drawing keys of this shape from 0,0 */ |
MoveTo(0,0); |
/* loop through key array */ |
keyIndex = *((short *) kcapPtr); |
kcapPtr += sizeof(short); |
for ( ; keyIndex>-1; keyIndex--) { |
/* get modifier mask, keyCode, and offset from previous key */ |
thisKeyEntryRec = *((KeyEntryRec *) kcapPtr); |
kcapPtr += sizeof(KeyEntryRec); |
/* move the pen to the start of the key */ |
Move(thisKeyEntryRec.deltaH, thisKeyEntryRec.deltaV); |
/* draw the key, composed of one or more rects */ |
SetPt(&currPoint, 0, 0); |
OpenRgn(); |
for (shapeCount=0, shapeIndex=shapeTotal; shapeIndex; |
shapeIndex--, shapeCount++) { |
/* set the rect, then reverse coordinates if necessary |
to ensure it is not empty */ |
SetRect(&tempRect, currPoint.h, currPoint.v, |
shapePoint[shapeCount].h, shapePoint[shapeCount].v); |
if (tempRect.top > tempRect.bottom) { |
swapPoint.v = tempRect.top; |
tempRect.top = tempRect.bottom; |
tempRect.bottom = swapPoint.v; |
} |
if (tempRect.left > tempRect.right) { |
swapPoint.h = tempRect.left; |
tempRect.left = tempRect.right; |
tempRect.right = swapPoint.h; |
} |
/* move the rect to the pen location and add it to the region */ |
currPoint = shapePoint[shapeCount]; |
GetPen(&penPoint); |
OffsetRect(&tempRect, penPoint.h, penPoint.v); |
FrameRect(&tempRect); |
} |
/* draw the key frame */ |
CloseRgn(keyshapeRgnHandle); |
FrameRgn(keyshapeRgnHandle); |
SetEmptyRgn(keyshapeRgnHandle); |
/* convert the keyCode to a character code */ |
/* mask out high bit of keyCode and add masked modifiers; |
KeyTranslate stroke bit taken from modifier parameter */ |
if (thisKeyEntryRec.keyCode & 0x80) |
modifiers &= (((short) thisKeyEntryRec.modifierMask) << 8); |
else modifiers |= (((short) thisKeyEntryRec.modifierMask) << 8); |
modifiedKeyCode = |
((thisKeyEntryRec.keyCode & 0x007F) | (modifiers & 0xFF80)); |
theChar = KeyTranslate(*kchrResHandle, modifiedKeyCode, (UInt32*)&state); |
if (!keycodesFlag) { |
/* center and draw the character */ |
charLoc.v = |
((tempRect.top + tempRect.bottom) / 2) - (fontHeight / 2); |
charLoc.v += theFontInfo.ascent; |
charLoc.h = |
((tempRect.left + tempRect.right) / 2) - (CharWidth(theChar) / 2); |
MoveTo(charLoc.h, charLoc.v); |
DrawChar(theChar); |
} else { |
/* draw the virtual keycode instead of the key label */ |
TextSize(9); |
NumToString(modifiedKeyCode & 0x7F, keycodeStr); |
charLoc.v = |
((tempRect.top + tempRect.bottom) / 2) - (fontHeight / 2); |
charLoc.v += theFontInfo.ascent; |
charLoc.h = |
((tempRect.left + tempRect.right) / 2) - (StringWidth(keycodeStr) / 2); |
MoveTo(charLoc.h, charLoc.v); |
DrawString(keycodeStr); |
} |
/* reposition pen for next key */ |
MoveTo(penPoint.h, penPoint.v); |
} |
} |
HUnlock(kcapResHandle); |
DisposeRgn(keyshapeRgnHandle); |
/* release the KCAP and KCHR unless they're System resources */ |
if (HomeResFile(kcapResHandle) > 1) ReleaseResource(kcapResHandle); |
} |
if (HomeResFile(kchrResHandle) > 1) ReleaseResource(kchrResHandle); |
TextSize(saveTextSize); |
} |
} |
void DoCommand(long int mResult) |
{ |
short theItem, /* menu item number from mResult low-order word */ |
theMenu; /* menu number from mResult high-order word */ |
Str255 name; /* desk accessory name */ |
int tempInt; |
ResType tempResType; |
Str255 tempStr; |
Handle kcapHandle; |
theItem = LoWord(mResult); /* call Toolbox Utility routines to */ |
theMenu = HiWord(mResult); /* set menu item number and menu */ |
switch (theMenu) { /* switch on menu ID */ |
case appleID: |
if (theItem == aboutMeCommand) |
ShowAboutMeDialog(); |
else { |
GetMenuItemText(myMenus[appleM], theItem, name); |
tempInt = OpenDeskAcc(name); |
SetPort(myWindow); |
} |
break; |
case fileID: |
if (theItem == quitItem) |
doneFlag = true; |
break; |
case editID: |
if (!SystemEdit(theItem - 1)) { /* Pass the command on to the Desk Manager. */ |
; /* do nothing */ |
}; |
break; |
case displayID: |
if (gCurrDisplayItem != theItem) { |
if (theItem == 1) { |
/* display key labels */ |
gKeycodesFlag = !gKeycodesFlag; |
CheckItem(myMenus[displayM], 1, !gKeycodesFlag); |
} else { |
LMSetROMMapInsert (0x0100); /* use ROM resources, SetResLoad(false) */ |
kcapHandle = GetIndResource('KCAP', theItem - 2); |
if (kcapHandle) { |
/* find the ID of the chosen KCAP */ |
GetResInfo(kcapHandle, &gKcapNum, &tempResType, tempStr); |
ReleaseResource(kcapHandle); |
CheckItem(myMenus[displayM], gCurrDisplayItem, false); |
CheckItem(myMenus[displayM], theItem, true); |
gCurrDisplayItem = theItem; |
} |
} |
EraseRect(&myWindow->portRect); |
InvalRect(&myWindow->portRect); |
} |
break; |
} |
HiliteMenu(0); /* Unhighlight menu title */ |
/* (highlighted by MenuSelect) */ |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-30