snes9x/macosx/mac-keyboard.cpp
2019-11-22 21:25:46 -08:00

1035 lines
28 KiB
C++
Executable File

/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
This file is licensed under the Snes9x License.
For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/
/***********************************************************************************
SNES9X for Mac OS (c) Copyright John Stiles
Snes9x for Mac OS X
(c) Copyright 2001 - 2011 zones
(c) Copyright 2002 - 2005 107
(c) Copyright 2002 PB1400c
(c) Copyright 2004 Alexander and Sander
(c) Copyright 2004 - 2005 Steven Seeger
(c) Copyright 2005 Ryan Vogt
***********************************************************************************/
#include "port.h"
#include "mac-prefix.h"
#include "mac-dialog.h"
#include "mac-gworld.h"
#include "mac-os.h"
#include "mac-keyboard.h"
#define kmUpArrowKey 0x7E
#define kmDownArrowKey 0x7D
#define kmRightArrowKey 0x7C
#define kmLeftArrowKey 0x7B
#define kmReturnKey 0x24
#define kmTabKey 0x30
#define kmShiftKey 0x38
#define kmControlKey 0x3B
#define kmOptionKey 0x3A
#define kmCommandKey 0x37
#define kmXKey 0x07
#define kmZKey 0x06
#define kmKP2Key 0x54
#define kmKP4Key 0x56
#define kmKP5Key 0x57
#define kmKP6Key 0x58
#define kmKP8Key 0x5B
#define kmKPEnterKey 0x4C
#define kmKPPlusKey 0x45
#define kmKP0Key 0x52
#define kmKPPeriodKey 0x41
#define kmHomeKey 0x73
#define kmPageUpKey 0x74
#define kmEndKey 0x77
#define kmPageDownKey 0x79
#define kmBackslashKey 0x2A
#define km1Key 0x12
#define km0Key 0x1D
#define kmIKey 0x22
#define kmJKey 0x26
#define kmKKey 0x28
#define kmLKey 0x25
#define kmTildeKey 0x32
#define kmRKey 0x0F
#define kmBKey 0x0B
#define kmNKey 0x2D
#define kmMKey 0x2E
#define kmSpaceKey 0x31
#define kmSlashKey 0x2C
#define kmPeriodKey 0x2F
#define kmQKey 0x0C
#define kmWKey 0x0D
#define kmEscKey 0x35
#define kmCommaKey 0x2B
#define kIconSize 16
#define kKeySize 24
#define KS kKeySize
uint8 keyCode[kKeys] =
{
kmUpArrowKey,
kmDownArrowKey,
kmLeftArrowKey,
kmRightArrowKey,
kmShiftKey,
kmOptionKey,
kmControlKey,
kmCommandKey,
kmZKey,
kmXKey,
kmReturnKey,
kmTabKey,
kmKP8Key,
kmKP2Key,
kmKP4Key,
kmKP6Key,
kmPageDownKey,
kmPageUpKey,
kmEndKey,
kmHomeKey,
kmKP0Key,
kmKPPeriodKey,
kmKPEnterKey,
kmKPPlusKey,
kmBackslashKey,
km1Key,
km0Key,
kmTildeKey,
kmRKey,
kmBKey,
kmNKey,
kmMKey,
kmSpaceKey,
kmSlashKey,
kmPeriodKey,
kmQKey,
kmWKey,
kmEscKey,
kmCommaKey
};
typedef struct
{
int keyWidth, keyHeight;
uint8 scancode;
const char *keyLabel;
} KeyboardLayout;
typedef struct
{
HIViewRef view;
} CustomViewData;
static CGImageRef iconTableImage;
static CGImageRef keyLayoutImage;
static CGImageRef iconPlaceImage;
static Ptr iconTableCGWld;
static Ptr keyLayoutWorld;
static Ptr iconPlaceWorld;
static CGRect keyRect[0x80][2];
static uint8 defaultKeys[kKeys];
static HIObjectClassRef theClass;
static HIViewRef customView;
static HIPoint mousePos;
static float ofsx, ofsy;
static int dragKey;
static CGPoint dragKeyOfs;
static CGRect dragKeyRect;
static volatile Boolean keyInDrag;
static const int kKeyLayoutWidth = kKeySize * 23 + 1,
kKeyLayoutHeight = kKeySize * 7 + 1;
static KeyboardLayout keys[] =
{
{ KS, KS, 0x35, "esc" },
{ KS, KS, 0x00, NULL },
{ KS, KS, 0x7a, "F1" },
{ KS, KS, 0x78, "F2" },
{ KS, KS, 0x63, "F3" },
{ KS, KS, 0x76, "F4" },
{ KS / 2, KS, 0x00, NULL },
{ KS, KS, 0x60, "F5" },
{ KS, KS, 0x61, "F6" },
{ KS, KS, 0x62, "F7" },
{ KS, KS, 0x64, "F8" },
{ KS / 2, KS, 0x00, NULL },
{ KS, KS, 0x65, "F9" },
{ KS, KS, 0x6d, "F10" },
{ KS, KS, 0x67, "F11" },
{ KS, KS, 0x6f, "F12" },
{ KS / 2, KS, 0x00, NULL },
{ KS, KS, 0x69, "F13" },
{ KS, KS, 0x6b, "F14" },
{ KS, KS, 0x71, "F15" },
{ 0, 0, 0x00, NULL },
{ 0, 0, 0x00, NULL },
{ KS, KS, 0x32, "`" },
{ KS, KS, 0x12, "1" },
{ KS, KS, 0x13, "2" },
{ KS, KS, 0x14, "3" },
{ KS, KS, 0x15, "4" },
{ KS, KS, 0x17, "5" },
{ KS, KS, 0x16, "6" },
{ KS, KS, 0x1a, "7" },
{ KS, KS, 0x1c, "8" },
{ KS, KS, 0x19, "9" },
{ KS, KS, 0x1d, "0" },
{ KS, KS, 0x1b, "-" },
{ KS, KS, 0x18, "=" },
{ KS * 2, KS, 0x33, "delete" },
{ KS / 2, KS, 0x00, NULL },
{ KS, KS, 0x72, "ins" },
{ KS, KS, 0x73, "hom" },
{ KS, KS, 0x74, "pgu" },
{ KS / 2, KS, 0x00, NULL },
{ KS, KS, 0x47, "clr" },
{ KS, KS, 0x51, "=" },
{ KS, KS, 0x4b, "/" },
{ KS, KS, 0x43, "*" },
{ 0, 0, 0x00, NULL },
{ KS * 3 / 2, KS, 0x30, "tab" },
{ KS, KS, 0x0c, "Q" },
{ KS, KS, 0x0d, "W" },
{ KS, KS, 0x0e, "E" },
{ KS, KS, 0x0f, "R" },
{ KS, KS, 0x11, "T" },
{ KS, KS, 0x10, "Y" },
{ KS, KS, 0x20, "U" },
{ KS, KS, 0x22, "I" },
{ KS, KS, 0x1f, "O" },
{ KS, KS, 0x23, "P" },
{ KS, KS, 0x21, "[" },
{ KS, KS, 0x1e, "]" },
{ KS * 3 / 2, KS, 0x2a, "\\" },
{ KS / 2, KS, 0x00, NULL },
{ KS, KS, 0x75, "del" },
{ KS, KS, 0x77, "end" },
{ KS, KS, 0x79, "pgd" },
{ KS / 2, KS, 0x00, NULL },
{ KS, KS, 0x59, "7" },
{ KS, KS, 0x5b, "8" },
{ KS, KS, 0x5c, "9" },
{ KS, KS, 0x4e, "-" },
{ 0, 0, 0x00, NULL },
{ KS * 2, KS, 0x39, "caps" },
{ KS, KS, 0x00, "A" },
{ KS, KS, 0x01, "S" },
{ KS, KS, 0x02, "D" },
{ KS, KS, 0x03, "F" },
{ KS, KS, 0x05, "G" },
{ KS, KS, 0x04, "H" },
{ KS, KS, 0x26, "J" },
{ KS, KS, 0x28, "K" },
{ KS, KS, 0x25, "L" },
{ KS, KS, 0x29, ";" },
{ KS, KS, 0x27, "\xd3" },
{ KS * 2, KS, 0x24, "return" },
{ KS * 4, KS, 0x00, NULL },
{ KS, KS, 0x56, "4" },
{ KS, KS, 0x57, "5" },
{ KS, KS, 0x58, "6" },
{ KS, KS, 0x45, "+" },
{ 0, 0, 0x00, NULL },
{ KS * 5 / 2, KS, 0x38, "shift" },
{ KS, KS, 0x06, "Z" },
{ KS, KS, 0x07, "X" },
{ KS, KS, 0x08, "C" },
{ KS, KS, 0x09, "V" },
{ KS, KS, 0x0b, "B" },
{ KS, KS, 0x2d, "N" },
{ KS, KS, 0x2e, "M" },
{ KS, KS, 0x2b, "," },
{ KS, KS, 0x2f, "." },
{ KS, KS, 0x2c, "/" },
{ KS * 5 / 2, KS, 0x38, "shift" },
{ KS * 3 / 2, KS, 0x00, NULL },
{ KS, KS, 0x7e, "up" },
{ KS * 3 / 2, KS, 0x00, NULL },
{ KS, KS, 0x53, "1" },
{ KS, KS, 0x54, "2" },
{ KS, KS, 0x55, "3" },
{ KS, KS * 2, 0x4c, "ent" },
{ 0, 0, 0x00, NULL },
{ KS * 3 / 2, KS, 0x3b, "ctrl" },
{ KS * 3 / 2, KS, 0x3a, "opt" },
{ KS * 3 / 2, KS, 0x37, "cmd" },
{ KS * 6, KS, 0x31, " " },
{ KS * 3 / 2, KS, 0x37, "cmd" },
{ KS * 3 / 2, KS, 0x3a, "opt" },
{ KS * 3 / 2, KS, 0x3b, "ctrl" },
{ KS / 2, KS, 0x00, NULL },
{ KS, KS, 0x7b, "lt" },
{ KS, KS, 0x7d, "dn" },
{ KS, KS, 0x7c, "rt" },
{ KS / 2, KS, 0x00, NULL },
{ KS * 2, KS, 0x52, "0" },
{ KS, KS, 0x41, "." },
{ 0, 0, 0x00, NULL }
};
static void CreateIconTableImage (void);
static void ReleaseIconTableImage (void);
static void CreateKeyLayoutImage (void);
static void ReleaseKeyLayoutImage (void);
static void CreateIconPlaceImage (void);
static void UpdateIconPlaceImage (void);
static void ReleaseIconPlaceImage (void);
static void DrawPlacedIcon (CGContextRef, int);
static void DrawDraggedIcon (CGContextRef, int, CGPoint *);
static Boolean KeyCodeInUse (int);
static int FindHitKey (HIPoint, CGRect *, CGPoint *);
static OSStatus KeyWindowEventHandler (EventHandlerCallRef, EventRef, void *);
static OSStatus KeyLegendEventHandler (EventHandlerCallRef, EventRef, void *);
static OSStatus KeyLayoutEventHandler (EventHandlerCallRef, EventRef, void *);
#define kCustomLayoutViewClassID CFSTR("com.snes9x.macos.snes9x.keylayout")
void ConfigureKeyboard (void)
{
OSStatus err;
IBNibRef nibRef;
err = CreateNibReference(kMacS9XCFString, &nibRef);
if (err == noErr)
{
WindowRef tWindowRef;
err = CreateWindowFromNib(nibRef, CFSTR("Keyboard"), &tWindowRef);
if (err == noErr)
{
EventHandlerRef wref, iref1, iref2;
EventHandlerUPP wUPP, iUPP;
EventTypeSpec wEvents[] = { { kEventClassWindow, kEventWindowClose },
{ kEventClassCommand, kEventCommandProcess },
{ kEventClassCommand, kEventCommandUpdateStatus } },
cEvents[] = { { kEventClassHIObject, kEventHIObjectConstruct },
{ kEventClassHIObject, kEventHIObjectDestruct },
{ kEventClassHIObject, kEventHIObjectInitialize },
{ kEventClassControl, kEventControlDraw },
{ kEventClassControl, kEventControlHitTest },
{ kEventClassControl, kEventControlTrack } },
iEvents[] = { { kEventClassControl, kEventControlDraw } };
HIObjectRef hiObject;
HIViewRef contentView, image1, image2;
HIViewID cid;
HIRect frame;
Rect winBounds;
UpdateIconPlaceImage();
keyInDrag = false;
dragKey = -1;
dragKeyOfs = CGPointMake(0.0f, 0.0f);
dragKeyRect = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f);
mousePos = CGPointMake(0.0f, 0.0f);
err = noErr;
if (theClass == NULL)
err = HIObjectRegisterSubclass(kCustomLayoutViewClassID, kHIViewClassID, 0, KeyLayoutEventHandler, GetEventTypeCount(cEvents), cEvents, NULL, &theClass);
if (err == noErr)
{
err = HIObjectCreate(kCustomLayoutViewClassID, NULL, &hiObject);
if (err == noErr)
{
GetWindowBounds(tWindowRef, kWindowContentRgn, &winBounds);
frame.origin.x = 2.0f;
frame.origin.y = 2.0f;
frame.size.width = (float) (winBounds.right - winBounds.left) - 4.0f;
frame.size.height = (float) kKeyLayoutHeight + 36.0f;
ofsx = (float) (((int) frame.size.width - kKeyLayoutWidth ) >> 1) + 1.0f;
ofsy = (float) (((int) frame.size.height - kKeyLayoutHeight) >> 1) + 1.0f;
customView = (HIViewRef) hiObject;
HIViewFindByID(HIViewGetRoot(tWindowRef), kHIViewWindowContentID, &contentView);
HIViewAddSubview(contentView, customView);
HIViewSetFrame(customView, &frame);
HIViewSetVisible(customView, true);
cid.signature = 'Lgnd';
cid.id = 0;
HIViewFindByID(contentView, cid, &image1);
cid.id = 1;
HIViewFindByID(contentView, cid, &image2);
iUPP = NewEventHandlerUPP(KeyLegendEventHandler);
err = InstallControlEventHandler(image1, iUPP, GetEventTypeCount(iEvents), iEvents, (void *) image1, &iref1);
err = InstallControlEventHandler(image2, iUPP, GetEventTypeCount(iEvents), iEvents, (void *) image2, &iref2);
wUPP = NewEventHandlerUPP(KeyWindowEventHandler);
err = InstallWindowEventHandler(tWindowRef, wUPP, GetEventTypeCount(wEvents), wEvents, (void *) tWindowRef, &wref);
MoveWindowPosition(tWindowRef, kWindowKeyConfig, false);
ShowWindow(tWindowRef);
err = RunAppModalLoopForWindow(tWindowRef);
HideWindow(tWindowRef);
SaveWindowPosition(tWindowRef, kWindowKeyConfig);
err = RemoveEventHandler(iref2);
err = RemoveEventHandler(iref1);
DisposeEventHandlerUPP(iUPP);
err = RemoveEventHandler(wref);
DisposeEventHandlerUPP(wUPP);
}
}
CFRelease(tWindowRef);
}
DisposeNibReference(nibRef);
}
}
static void CreateIconTableImage (void)
{
CGContextRef ctx;
CGDataProviderRef prov;
CGColorSpaceRef color;
CGRect rct;
rct = CGRectMake(0.0f, 0.0f, (float) kIconSize, (float) kIconSize);
iconTableCGWld = (Ptr) malloc(kIconSize * kKeys * (kIconSize + 1) * 4);
if (!iconTableCGWld)
QuitWithFatalError(0, "keyboard 08");
ctx = NULL;
color = CGColorSpaceCreateDeviceRGB();
if (color)
{
ctx = CGBitmapContextCreate(iconTableCGWld, kIconSize * kKeys, kIconSize, 8, kIconSize * kKeys * 4, color, kCGImageAlphaNoneSkipFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrderDefault : 0));
CGColorSpaceRelease(color);
}
if (!ctx)
QuitWithFatalError(0, "keyboard 09");
CGContextTranslateCTM(ctx, 0.0f, (float) kIconSize);
CGContextScaleCTM(ctx, 1.0f, -1.0f);
// SNES pads
for (int i = macPadIconIndex; i < macPadIconIndex + 12 * 2; i++)
{
if (systemVersion >= 0x1040)
CGContextDrawImage(ctx, rct, macIconImage[i]);
#ifdef MAC_PANTHER_SUPPORT
else
PlotIconRefInContext(ctx, &rct, kAlignNone, kTransformNone, NULL, kPlotIconRefNormalFlags, macIconRef[i]);
#endif
rct = CGRectOffset(rct, kIconSize, 0);
}
// Function buttons
for (int i = macFunctionIconIndex; i < macFunctionIconIndex + 17; i++)
{
if (systemVersion >= 0x1040)
CGContextDrawImage(ctx, rct, macIconImage[i]);
#ifdef MAC_PANTHER_SUPPORT
else
PlotIconRefInContext(ctx, &rct, kAlignNone, kTransformNone, NULL, kPlotIconRefNormalFlags, macIconRef[i]);
#endif
rct = CGRectOffset(rct, kIconSize, 0);
}
CGContextRelease(ctx);
iconTableImage = NULL;
prov = CGDataProviderCreateWithData(NULL, iconTableCGWld, kIconSize * kKeys * kIconSize * 4, NULL);
if (prov)
{
color = CGColorSpaceCreateDeviceRGB();
if (color)
{
iconTableImage = CGImageCreate(kIconSize * kKeys, kIconSize, 8, 32, kIconSize * kKeys * 4, color, kCGImageAlphaNoneSkipFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrderDefault : 0), prov, NULL, 0, kCGRenderingIntentDefault);
CGColorSpaceRelease(color);
}
CGDataProviderRelease(prov);
}
if (!iconTableImage)
QuitWithFatalError(0, "keyboard 10");
}
static void ReleaseIconTableImage (void)
{
CGImageRelease(iconTableImage);
free(iconTableCGWld);
}
static void CreateKeyLayoutImage (void)
{
CGContextRef ctx;
CGDataProviderRef prov;
CGColorSpaceRef color;
CGAffineTransform flipMatrix;
CGRect rct, r;
int index, scancode;
rct = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f);
for (int i = 0; i < 0x80; i++)
keyRect[i][0] = keyRect[i][1] = rct;
keyLayoutWorld = (Ptr) malloc(kKeyLayoutWidth * (kKeyLayoutHeight + 1) * 4);
if (!keyLayoutWorld)
QuitWithFatalError(0, "keyboard 02");
ctx = NULL;
color = CGColorSpaceCreateDeviceRGB();
if (color)
{
ctx = CGBitmapContextCreate(keyLayoutWorld, kKeyLayoutWidth, kKeyLayoutHeight, 8, kKeyLayoutWidth * 4, color, kCGImageAlphaPremultipliedFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrderDefault : 0));
CGColorSpaceRelease(color);
}
if (!ctx)
QuitWithFatalError(0, "keyboard 04");
CGContextSetLineJoin(ctx, kCGLineJoinMiter);
flipMatrix = CGAffineTransformMake(1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
CGContextSelectFont(ctx, "Helvetica", 10.0f, kCGEncodingMacRoman);
CGContextSetTextDrawingMode(ctx, kCGTextFill);
CGContextSetTextMatrix(ctx, flipMatrix);
rct = CGRectMake(0.0f, 0.0f, (float) kKeyLayoutWidth, (float) kKeyLayoutHeight);
CGContextClearRect(ctx, rct);
index = 0;
rct = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f);
for (int i = 0; i < 7; i++)
{
while (keys[index].keyWidth)
{
rct.size.width = (float) keys[index].keyWidth;
if (keys[index].keyLabel)
{
rct.size.height = (float) keys[index].keyHeight;
scancode = keys[index].scancode;
if (keyRect[scancode][0].size.height < 1.0)
keyRect[scancode][0] = rct;
else
keyRect[scancode][1] = rct;
r = rct;
r.origin.x += 1.0f;
r.origin.y += 1.0f;
r.size.width -= 1.0f;
r.size.height -= 1.0f;
CGContextSetRGBStrokeColor(ctx, 0.1f, 0.1f, 0.1f, 1.0f);
CGContextStrokeRect(ctx, r);
float h, p;
CGRectInset(r, 2.0f, 2.0f);
h = r.size.height;
for (float f = h; f >= 1.0f; f -= 1.0f)
{
p = (155.0f + (h - f)) / 180.0f;
CGContextSetRGBFillColor(ctx, p, p, p, 1.0f);
CGContextFillRect(ctx, r);
r.size.height -= 1.0f;
}
CGContextSetRGBFillColor(ctx, 0.1f, 0.1f, 0.1f, 1.0f);
CGContextShowTextAtPoint(ctx, rct.origin.x + 3.0f, rct.origin.y + rct.size.height - 3.0f, keys[index].keyLabel, strlen(keys[index].keyLabel));
}
rct.origin.x += rct.size.width;
index++;
}
rct.origin.y += kKeySize;
rct.origin.x = rct.size.width = 0;
index++;
}
CGContextRelease(ctx);
keyLayoutImage = NULL;
prov = CGDataProviderCreateWithData(NULL, keyLayoutWorld, kKeyLayoutWidth * kKeyLayoutHeight * 4, NULL);
if (prov)
{
color = CGColorSpaceCreateDeviceRGB();
if (color)
{
keyLayoutImage = CGImageCreate(kKeyLayoutWidth, kKeyLayoutHeight, 8, 32, kKeyLayoutWidth * 4, color, kCGImageAlphaPremultipliedFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrderDefault : 0), prov, NULL, 0, kCGRenderingIntentDefault);
CGColorSpaceRelease(color);
}
CGDataProviderRelease(prov);
}
if (!keyLayoutImage)
QuitWithFatalError(0, "keyboard 05");
}
static void ReleaseKeyLayoutImage (void)
{
CGImageRelease(keyLayoutImage);
free(keyLayoutWorld);
}
static void CreateIconPlaceImage (void)
{
iconPlaceWorld = (Ptr) malloc(kKeyLayoutWidth * (kKeyLayoutHeight + 1) * 4);
if (!iconPlaceWorld)
QuitWithFatalError(0, "keyboard 06");
iconPlaceImage = NULL;
UpdateIconPlaceImage();
}
static void UpdateIconPlaceImage (void)
{
CGContextRef ctx;
CGDataProviderRef prov;
CGColorSpaceRef color;
CGRect rct;
if (iconPlaceImage)
CGImageRelease(iconPlaceImage);
iconPlaceImage = NULL;
color = CGColorSpaceCreateDeviceRGB();
if (color)
{
ctx = CGBitmapContextCreate(iconPlaceWorld, kKeyLayoutWidth, kKeyLayoutHeight, 8, kKeyLayoutWidth * 4, color, kCGImageAlphaPremultipliedFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrderDefault : 0));
if (ctx)
{
rct = CGRectMake(0.0f, 0.0f, (float) kKeyLayoutWidth, (float) kKeyLayoutHeight);
CGContextDrawImage(ctx, rct, keyLayoutImage);
for (int i = 0; i < kKeys; i++)
DrawPlacedIcon(ctx, i);
CGContextRelease(ctx);
}
prov = CGDataProviderCreateWithData(NULL, iconPlaceWorld, kKeyLayoutWidth * kKeyLayoutHeight * 4, NULL);
if (prov)
{
iconPlaceImage = CGImageCreate(kKeyLayoutWidth, kKeyLayoutHeight, 8, 32, kKeyLayoutWidth * 4, color, kCGImageAlphaPremultipliedFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrderDefault : 0), prov, NULL, 0, kCGRenderingIntentDefault);
CGDataProviderRelease(prov);
}
CGColorSpaceRelease(color);
}
if (!iconPlaceImage)
QuitWithFatalError(0, "keyboard 07");
}
static void ReleaseIconPlaceImage (void)
{
CGImageRelease(iconPlaceImage);
free(iconPlaceWorld);
}
void InitKeyboard (void)
{
theClass = NULL;
memcpy(defaultKeys, keyCode, sizeof(keyCode));
CreateIconTableImage();
CreateKeyLayoutImage();
CreateIconPlaceImage();
}
void DeinitKeyboard (void)
{
ReleaseIconPlaceImage();
ReleaseKeyLayoutImage();
ReleaseIconTableImage();
}
static void DrawPlacedIcon (CGContextRef ctx, int which)
{
CGRect keyBounds, srcRect, dstRect;
CGContextSaveGState(ctx);
CGContextSetRGBFillColor(ctx, 0.40f, 0.40f, 0.65f, 0.5f);
for (int each = 0; each <= 1; each++)
{
keyBounds = keyRect[keyCode[which]][each];
if (keyBounds.size.height > 1.0f)
{
keyBounds.origin.x += 1.0f;
keyBounds.origin.y += 1.0f;
keyBounds.size.width -= 1.0f;
keyBounds.size.height -= 1.0f;
CGContextFillRect(ctx, keyBounds);
keyBounds.origin.x -= 1.0f;
keyBounds.origin.y -= 1.0f;
keyBounds.size.width += 1.0f;
keyBounds.size.height += 1.0f;
srcRect.origin.x = (float) (which * kIconSize);
srcRect.origin.y = 0.0f;
srcRect.size.width = (float) kIconSize;
srcRect.size.height = (float) kIconSize;
dstRect.origin.x = keyBounds.origin.x + (keyBounds.size.width - kIconSize) / 2.0f;
dstRect.origin.y = keyBounds.origin.y + (keyBounds.size.height - kIconSize) / 2.0f;
dstRect.size.width = (float) kIconSize;
dstRect.size.height = (float) kIconSize;
DrawSubCGImage(ctx, iconTableImage, srcRect, dstRect);
}
}
CGContextRestoreGState(ctx);
}
static void DrawDraggedIcon (CGContextRef ctx, int which, CGPoint *offset)
{
CGRect srcRect, dstRect;
CGContextSaveGState(ctx);
srcRect.origin.x = (float) (which * kIconSize);
srcRect.origin.y = 0.0f;
srcRect.size.width = (float) kIconSize;
srcRect.size.height = (float) kIconSize;
dstRect.origin.x = mousePos.x + offset->x;
dstRect.origin.y = mousePos.y + offset->y;
dstRect.size.width = (float) kIconSize;
dstRect.size.height = (float) kIconSize;
CGContextSetAlpha(ctx, 0.5f);
DrawSubCGImage(ctx, iconTableImage, srcRect, dstRect);
CGContextRestoreGState(ctx);
}
static Boolean KeyCodeInUse (int code)
{
for (int i = 0; i < kKeys; i++)
if (keyCode[i] == code)
return (true);
return (false);
}
static int FindHitKey (HIPoint where, CGRect *keybounds, CGPoint *offset)
{
int hit;
hit = -1;
*offset = CGPointMake(0.0f, 0.0f);
*keybounds = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f);
for (int which = 0; which < kKeys; which++)
{
for (int each = 0; each <= 1; each++)
{
if (CGRectContainsPoint(keyRect[keyCode[which]][each], where))
{
hit = which;
*keybounds = keyRect[keyCode[which]][each];
offset->x = keybounds->origin.x + (keybounds->size.width - kIconSize) / 2.0f - where.x + 18.0f;
offset->y = keybounds->origin.y + (keybounds->size.height - kIconSize) / 2.0f - where.y + 18.0f;
}
}
}
return (hit);
}
static OSStatus KeyWindowEventHandler (EventHandlerCallRef inHandlerRef, EventRef inEvent, void *inUserData)
{
OSStatus err, result = eventNotHandledErr;
WindowRef tWindowRef = (WindowRef) inUserData;
switch (GetEventClass(inEvent))
{
case kEventClassWindow:
switch (GetEventKind(inEvent))
{
case kEventWindowClose:
QuitAppModalLoopForWindow(tWindowRef);
result = noErr;
}
break;
case kEventClassCommand:
switch (GetEventKind(inEvent))
{
HICommand tHICommand;
case kEventCommandUpdateStatus:
err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &tHICommand);
if (err == noErr && tHICommand.commandID == 'clos')
{
UpdateMenuCommandStatus(true);
result = noErr;
}
break;
case kEventCommandProcess:
err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &tHICommand);
if (err == noErr)
{
if (tHICommand.commandID == 'DFLT')
{
memcpy(keyCode, defaultKeys, sizeof(keyCode));
UpdateIconPlaceImage();
HIViewSetNeedsDisplay(customView, true);
result = noErr;
}
}
}
}
return (result);
}
static OSStatus KeyLegendEventHandler (EventHandlerCallRef inHandlerRef, EventRef inEvent, void *inUserData)
{
OSStatus err, result = eventNotHandledErr;
HIViewRef view = (HIViewRef) inUserData;
switch (GetEventClass(inEvent))
{
case kEventClassControl:
switch (GetEventKind(inEvent))
{
case kEventControlDraw:
CGContextRef ctx;
err = GetEventParameter(inEvent, kEventParamCGContextRef, typeCGContextRef, NULL, sizeof(CGContextRef), NULL, &ctx);
if (err == noErr)
{
HIViewID cid;
HIRect bounds;
GetControlID(view, &cid);
HIViewGetBounds(view, &bounds);
CGContextTranslateCTM(ctx, 0, bounds.size.height);
CGContextScaleCTM(ctx, 1.0f, -1.0f);
CGContextDrawImage(ctx, CGRectMake(0, 0, kIconSize, kIconSize), macIconImage[macLegendIconIndex + cid.id]);
result = noErr;
}
}
}
return (result);
}
static OSStatus KeyLayoutEventHandler (EventHandlerCallRef inHandlerRef, EventRef inEvent, void *inUserData)
{
OSStatus err, result = eventNotHandledErr;
CustomViewData *data = (CustomViewData *) inUserData;
switch (GetEventClass(inEvent))
{
case kEventClassHIObject:
switch (GetEventKind(inEvent))
{
case kEventHIObjectConstruct:
data = (CustomViewData *) calloc(1, sizeof(CustomViewData));
if (data)
{
HIViewRef epView;
err = GetEventParameter(inEvent, kEventParamHIObjectInstance, typeHIObjectRef, NULL, sizeof(epView), NULL, &epView);
if (err == noErr)
{
data->view = epView;
result = SetEventParameter(inEvent, kEventParamHIObjectInstance, typeVoidPtr, sizeof(data), &data);
}
}
break;
case kEventHIObjectDestruct:
if (data)
free(data);
result = noErr;
break;
case kEventHIObjectInitialize:
result = CallNextEventHandler(inHandlerRef, inEvent);
}
break;
case kEventClassControl:
switch (GetEventKind(inEvent))
{
case kEventControlDraw:
CGContextRef ctx;
err = GetEventParameter(inEvent, kEventParamCGContextRef, typeCGContextRef, NULL, sizeof(ctx), NULL, &ctx);
if (err == noErr)
{
HIRect bounds, srcRect, dstRect;
HIViewGetBounds(customView, &bounds);
srcRect = CGRectMake(0, 0, kKeyLayoutWidth, kKeyLayoutHeight);
dstRect.origin.x = (float) (((int) bounds.size.width - kKeyLayoutWidth ) >> 1);
dstRect.origin.y = (float) (((int) bounds.size.height - kKeyLayoutHeight) >> 1);
dstRect.size.width = (float) kKeyLayoutWidth;
dstRect.size.height = (float) kKeyLayoutHeight;
DrawSubCGImage(ctx, iconPlaceImage, srcRect, dstRect);
if (keyInDrag && (dragKey != -1))
DrawDraggedIcon(ctx, dragKey, &dragKeyOfs);
}
result = noErr;
break;
case kEventControlHitTest:
ControlPartCode part;
part = kControlButtonPart;
result = SetEventParameter(inEvent, kEventParamControlPart, typeControlPartCode, sizeof(part), &part);
break;
case kEventControlTrack:
MouseTrackingResult trackResult;
WindowRef window;
HIViewRef contentView;
HIPoint hipt;
dragKey = -1;
dragKeyOfs = CGPointMake(0.0f, 0.0f);
dragKeyRect = CGRectMake(0.0f, 0.0f, 0.0f, 0.0f);
mousePos = CGPointMake(0.0f, 0.0f);
trackResult = kMouseTrackingMouseDown;
window = GetControlOwner(customView);
HIViewFindByID(HIViewGetRoot(window), kHIViewWindowContentID, &contentView);
#ifdef MAC_TIGER_PANTHER_SUPPORT
CGrafPtr oldPort;
Point qdpt;
Boolean portChanged = false;
if (systemVersion < 0x1050)
portChanged = QDSwapPort(GetWindowPort(window), &oldPort);
#endif
err = GetEventParameter(inEvent, kEventParamMouseLocation, typeHIPoint, NULL, sizeof(hipt), NULL, &hipt);
if (err == noErr)
{
hipt.x -= ofsx;
hipt.y -= ofsy;
dragKey = FindHitKey(hipt, &dragKeyRect, &dragKeyOfs);
if (dragKey != -1)
{
keyInDrag = true;
while (trackResult != kMouseTrackingMouseUp)
{
if (CGPointEqualToPoint(mousePos, hipt) == 0)
{
mousePos = hipt;
HIViewSetNeedsDisplay(customView, true);
}
if (systemVersion >= 0x1050)
{
err = HIViewTrackMouseLocation(customView, 0, kEventDurationForever, 0, NULL, &hipt, NULL, NULL, &trackResult);
hipt.x -= ofsx;
hipt.y -= ofsy;
}
#ifdef MAC_TIGER_PANTHER_SUPPORT
else
{
TrackMouseLocation(NULL, &qdpt, &trackResult);
hipt.x = qdpt.h - ofsx;
hipt.y = qdpt.v - ofsy;
HIViewConvertPoint(&hipt, contentView, customView);
}
#endif
}
keyInDrag = false;
for (int code = 0; code < 0x80; code++)
{
for (int each = 0; each <= 1; each++)
{
if (CGRectContainsPoint(keyRect[code][each], mousePos))
{
if (!KeyCodeInUse(code))
{
keyCode[dragKey] = code;
UpdateIconPlaceImage();
}
}
}
}
HIViewSetNeedsDisplay(customView, true);
}
}
#ifdef MAC_TIGER_PANTHER_SUPPORT
if (systemVersion < 0x1050)
{
if (portChanged)
QDSwapPort(oldPort, NULL);
}
#endif
result = noErr;
}
}
return (result);
}