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.
Source/ReKeyTrans.c
/******************************************************************************* |
OpenWindow by Cameron |
(OpenWindow? Cameron? What's going on here?) |
OK, intrepid developer-like objects, we admit it! We don't |
know where this sample came from and we don't know anything about |
its original intent. However, since we're super-geniuses, we were |
able to make up a plausible story. |
Say you're a terminal emulator. And you have to run on a Mac Plus. |
With us so far? Now, the Plus doesn't have a control key, but you'd |
really like to pretend it does. So you use the option key. Here's where |
the problem comes in. |
The default behavior of KeyTrans is to support umlauts and other |
fun letter modifiers by making option-U, for example, into a |
"dead" key which results in no keystrokes but modifies subsequent |
keystrokes. So when you type option-U followed by a u, you get: ''. |
And there was much rejoicing, except in Terminal Emulator Land. |
There, the people were downtrodden, as they had no way to tell |
their UNIX command line to clear. |
So, you ask, why don't I just install my own keymap? Well, that'd |
be swell for all us qwerty people, but the people who type on those |
keyboards with all the keys rearranged would really hate it (Hi Quinn!) |
and they'd have to relearn the icky qwerty (try typing that 5 times |
fast) layout again after they'd gone to all the effort of rearranging |
their keycaps on the keyboard so they'd feel funny (they're not all |
the same shape, you know). So... |
This sample shows how to patch KeyTrans in order to completely |
ignore the dead-key processing that goes on and lets you type those |
fancy accented characters. You're back in 7-bit ASCII days now, |
bucko. Enjoy. |
*******************************************************************************/ |
#include <String.h> |
/* Type 1 includes */ |
#include <Types.h> |
#include <QuickDraw.h> |
/* Type 2 includes */ |
#include <Controls.h> |
#include <Events.h> |
#include <Fonts.h> |
#include <Memory.h> |
#include <Menus.h> |
#include <OSUtils.h> |
#include <Resources.h> |
#include <SegLoad.h> |
#include <TextEdit.h> |
#include <ToolUtils.h> |
#include <Traps.h> |
#include <Script.h> |
/* Type 3 includes */ |
#include <Desk.h> |
#include <Files.h> |
#include <OSEvents.h> |
#include <Windows.h> |
/* Type 4 includes */ |
#include <Dialogs.h> |
/* Type BITE ME includes */ |
#include <Traps.h> |
#include <Assembler.h> |
/* Global Variables */ |
Str255 WindTitle; |
WindowPtr MyWindow,aWindPtr; |
short err,keycode,StartV,StartH; |
EventRecord MyEvent; |
Boolean quit,DrawOn; |
Rect WindRect,Rect1,Rect2; |
Point aPoint,lastPoint; |
long KCHRID,newKey,state; |
Handle KCHRHdl; |
/*************************************************************************************/ |
static asm pascal UniversalProcPtr KeyTransPatcher (UniversalProcPtr) |
{ |
// compute patch code size |
LEA endPatch,A1 |
LEA patch,A0 |
MOVE.L A1,D0 |
SUB.L A0,D0 |
MOVE.L D0,-(A7) // save size for later |
_NewPtrSys // alloc block in sys heap for patch |
MOVE.L (A7)+,D0 // restore size for BlockMove |
MOVE.L A0,D1 // set up CCR (I thought 68K was CISC!) |
BEQ.S fail // if'n (_NewPtrSys) didn't work, give up |
MOVE.L A0,A1 // new block is BlockMove dest |
// hijack A0 temporarily, thank you |
LEA oldTrapAddress,A0 // point to PC-relative storage |
MOVE.L 4(A7),(A0) // set PC-relative storage |
LEA patch,A0 // source for BlockMove |
_BlockMove // copy patch to system heap |
BRA.S out // skip exception handling |
fail: |
SUB.L A1,A1 // tell caller we're hosed |
out: |
MOVE.L (A7)+,A0 // get return address |
ADDQ.L #4,A7 // drop arg |
MOVE.L A1,(A7) // set return value |
JMP (A0) // phone home |
patch: |
// set the up/down bit - KeyTrans won't process |
// "dead" up strokes. Currently, this does not |
// affect the event record up/down state. |
BSET #7,9(SP) |
MOVE.L oldTrapAddress,-(A7) |
RTS |
oldTrapAddress: |
DC.L 'hack' |
endPatch: |
} |
/*************************************************************************************/ |
static void InitMac(void) |
{ |
InitGraf(&qd.thePort); |
InitFonts(); |
FlushEvents(everyEvent,0); |
InitWindows(); |
InitCursor(); |
quit = false; |
DrawOn = false; |
StartV = 25; |
StartH = 5; |
} |
/*************************************************************************************/ |
static void DoCR(void) |
{ |
if (lastPoint.v > (*MyWindow).portRect.bottom-15) |
{ |
EraseRect(&(*MyWindow).portRect); |
lastPoint.v = StartV; |
lastPoint.h = StartH; |
} |
else |
{ |
lastPoint.v = lastPoint.v+14; |
lastPoint.h = StartH; |
} |
} |
/*************************************************************************************/ |
static void DoKeyDown(void) |
{ |
if (BitAnd(MyEvent.message,charCodeMask) == 'q' // if the user typed the magic "cmd-q" sequence, |
&& BitAnd(MyEvent.modifiers,0x0100)) |
{ quit = true; } // it's Miller time! |
else { |
MoveTo(lastPoint.h,lastPoint.v); |
newKey = BitAnd(MyEvent.message,keyCodeMask); // Strip out all but the keycode |
newKey = BitShift(newKey,-8); // move the keycode down to the low byte |
keycode = LoWord(newKey); // extract the low word of the event message (ignore modifier bits) |
keycode = keycode & 0xFF7F; // make sure it looks like a key down stroke |
newKey = KeyTranslate(*KCHRHdl, keycode, (UInt32*)&state); // have KeyTrans translate the key code to ASCII |
keycode = LoWord(newKey); // now get the ASCII 2 value (IM5, p195 has it backward!) |
DrawChar(keycode); // just to make sure, let's have a look |
GetPen(&lastPoint); // now make sure we stay inside the content region |
if (lastPoint.h > ((*MyWindow).portRect.right-10)) // if we're getting to close to the edge, |
{ DoCR(); } // go fix it up |
} |
} |
/*************************************************************************************/ |
void main() |
{ |
InitMac(); |
MyWindow = GetNewWindow(2009,nil,(WindowPtr)-1); |
if (MyWindow) |
{ |
SetPort(MyWindow); |
MoveTo(StartH,StartV); |
lastPoint.h = StartH; |
lastPoint.v = StartV; |
KCHRID = GetScriptVariable(smRoman, smScriptKeys); /* returns resource ID of KCHR being used by system */ |
KCHRHdl = GetResource('KCHR',KCHRID); |
if (KCHRHdl) |
{ |
UniversalProcPtr oldKeyTrans = GetToolTrapAddress (_KeyTrans), |
newKeyTrans = KeyTransPatcher (oldKeyTrans); |
if (newKeyTrans) |
{ |
SetToolTrapAddress (newKeyTrans, _KeyTrans); |
MoveHHi(KCHRHdl); |
HLock(KCHRHdl); |
while (quit != true) |
{ |
if (DrawOn) |
{ |
if (StillDown()) |
{ |
GetMouse(&aPoint); |
StdLine(aPoint); |
} |
else { DrawOn = false; } |
} |
else |
{ |
if (WaitNextEvent(everyEvent,&MyEvent,0,nil)) |
{ |
switch (MyEvent.what) |
{ |
case mouseDown: |
{ |
Rect boundsRect = qd.screenBits.bounds; |
switch (FindWindow(MyEvent.where,&aWindPtr)) |
{ |
case inGoAway : |
quit = TrackGoAway (aWindPtr,MyEvent.where); |
break; |
case inDrag : |
InsetRect (&boundsRect,4,4); |
DragWindow (aWindPtr,MyEvent.where,&boundsRect); |
break; |
} |
break; |
} |
case keyDown: |
{ |
DoKeyDown(); |
break; |
} |
case autoKey: |
{ |
DoKeyDown(); |
break; |
} |
} |
} |
} |
} |
SetToolTrapAddress (oldKeyTrans, _KeyTrans); |
DisposePtr ((Ptr) newKeyTrans); |
} |
} |
} |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-30