mirror of https://github.com/snes9xgit/snes9x.git
1035 lines
28 KiB
C++
Executable File
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 pascal OSStatus KeyWindowEventHandler (EventHandlerCallRef, EventRef, void *);
|
|
static pascal OSStatus KeyLegendEventHandler (EventHandlerCallRef, EventRef, void *);
|
|
static pascal 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 pascal 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 pascal 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 pascal 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);
|
|
}
|