From 9757593d51ce459ab9768c704246af38c7461e7b Mon Sep 17 00:00:00 2001 From: Markus Fritze Date: Sun, 11 Jun 2017 19:22:10 +0200 Subject: [PATCH] First upload --- C:F Registration.md | 1 + LICENSE | 4 +- "Newton Keyboard Enabler/Icon\r" | 0 Newton Keyboard Enabler/Main.cp | 1 + .../Newton Keyboard Enabler | 0 .../Newton Keyboard Enabler.µ | Bin 0 -> 1440 bytes Newton Keyboard Enabler/Newton Keyboard.rsrc | Bin 0 -> 10432 bytes .../Serial Enabler Read Me | 1 + README.md | 791 +++++++++++++++++- newton-keyboard-enabler-10.sit | Bin 0 -> 5647 bytes preferences.png | Bin 0 -> 11387 bytes 11 files changed, 795 insertions(+), 3 deletions(-) create mode 100644 C:F Registration.md create mode 100644 "Newton Keyboard Enabler/Icon\r" create mode 100644 Newton Keyboard Enabler/Main.cp create mode 100644 Newton Keyboard Enabler/Newton Keyboard Enabler create mode 100644 Newton Keyboard Enabler/Newton Keyboard Enabler.µ create mode 100644 Newton Keyboard Enabler/Newton Keyboard.rsrc create mode 100644 Newton Keyboard Enabler/Serial Enabler Read Me create mode 100644 newton-keyboard-enabler-10.sit create mode 100644 preferences.png diff --git a/C:F Registration.md b/C:F Registration.md new file mode 100644 index 0000000..03ae7e9 --- /dev/null +++ b/C:F Registration.md @@ -0,0 +1 @@ +QuickMessenger Mail RE: [189587b]C/F Registrati Reference #189587 Dear Markus Fritze, Thank you for registering your creator and file type information. We appreciate your continued product development and support of Apple Computer! The Developer Support Center has reviewed your Creator identification request, and has registered the following product information: Company: =D6-Soft Contact: Markus Fritze Address: Birkhahnkamp 38 22846 Norderstedt Germany Application: Newton Keyboard Enabler Phone: +49-40-52682041 EMail Address: mf@maushh2.hh.provi.de Application Signatures: NwtK (Hex)4E77744B File Types: None This letter serves as your confirmation and proof of registration. Please keep it on file. Additionally, you should review the information for accuracy. If you locate discrepancies in our data, please contact Developer Support with your corrections. Thanks for supporting Apple! Regards, Beth Fox Developer Support The content of your link dated: 15 July 1996 follows: ****************************************************************************** ------------------------------------------------------------------------------ WEB CREATOR/FILE TYPE Registration Request =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D %UNIQUE REGISTRATION%: %NAME%: Markus Fritze %COMPANY%: =D6-Soft %ADDRESS%: Birkhahnkamp 38 22846 Norderstedt Germany %TELEPHONE%: +49-40-52682041 %E-MAIL%: mf@maushh2.hh.provi.de %PRODUCT NAME%: Newton Keyboard Enabler %SIGNATURE (HEX)%: 4E77744B %END ****************************************************************************** \ No newline at end of file diff --git a/LICENSE b/LICENSE index 7e8e867..0319863 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017 Markus Fritze +Copyright (c) 1996 Markus Fritze Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +SOFTWARE. diff --git "a/Newton Keyboard Enabler/Icon\r" "b/Newton Keyboard Enabler/Icon\r" new file mode 100644 index 0000000..e69de29 diff --git a/Newton Keyboard Enabler/Main.cp b/Newton Keyboard Enabler/Main.cp new file mode 100644 index 0000000..d6918a8 --- /dev/null +++ b/Newton Keyboard Enabler/Main.cp @@ -0,0 +1 @@ +/*** * Newton Keyboard Enabler * * Erlaubt die Nutzung eines seriellen Newton- * Keyboards an einem Mac. Das Keyboard verhlt * sich in fast allen Fllen genau wie ein * originales ADB-Keyboard (Ausnahme: MacsBug * kann es nicht nutzen) * * Entwickelt mit dem CodeWarrior 9 von * Metrowerks. * * (c)1996 MAXON Computer, Markus Fritze ***/ // c_moeller@macopen.com // true, wenn das Programm beendet werden soll Boolean gDoQuitFlag; /*** * unsere AppleEvent-Routinen * (schlielich sind wir ein ordentliches * MacOS Programm) ***/ static pascal OSErr DoAENoErr( const AppleEvent*, AppleEvent*, long) { return noErr; // AppleEvent ist ok } static pascal OSErr DoAEQuitAppl( const AppleEvent*, AppleEvent*, long) { gDoQuitFlag = true; // Programm beenden return noErr; } // einen (hoffentlich) undefinierten Code // benutzen wir als ID-Code fr die Tastatur #define NEWTON_KEYBOARD_CODE 117L // Zugriffsfunktionen hnlich // fr den Tastaturtreiber static inline SInt16 LMGetKeyLast() { return *(SInt16*)0x0184; }; static inline void LMSetKeyLast(SInt16 value) { *(SInt16*)0x0184 = value; }; static inline SInt16 LMGetHiKeyLast() { return *(SInt16*)0x0216; }; static inline void LMSetHiKeyLast(SInt16 value) { *(SInt16*)0x0216 = value; }; static inline SInt32 LMGetKeyTime() { return *(SInt32*)0x0186; }; static inline void LMSetKeyTime(SInt32 value) { *(SInt32*)0x0186 = value; }; static inline SInt32 LMGetKeyRepTime() { return *(SInt32*)0x018A; }; static inline void LMSetKeyRepTime(SInt32 value) { *(SInt32*)0x018A = value; }; // ohne "inline", wegen eines 68k Compilerbugs // beim CodeWarrior 9 static /*inline*/ KeyMap *LMGetKeyMapPtr() { return (KeyMap*)0x0174; }; // Unsere globalen Variablen fr die Tastatur Handle gKMAP; Handle gKCHR; UInt8 gKeyMap[16]; /*** * Keyboard-Variablen initialisieren ***/ static void InitKeyboard() { Handle thePref = ::Get1Resource('PREF', 128); // eigener Typ: Newton Keyboard gKMAP = ::Get1Resource('KMAP', **thePref); if(!gKMAP) ::ExitToShell(); ::HLockHi(gKMAP); // ein deutsches Keyboard: gKCHR = ::GetResource('KCHR', ((short*)*thePref)[1]); if(!gKCHR) // ein US-Keyboard: gKCHR = ::GetResource('KCHR', 0); if(!gKCHR) ::ExitToShell(); ::HLockHi(gKCHR); // eigene Keymap lschen for(int i=0; i raus if(inKey == 0x00L) return; // Message zusammensetzen UInt32 theMessage = inKey | UInt16(inKeyCode << 8) | (NEWTON_KEYBOARD_CODE << 16); // Taste gedrckt if(!(inKeyCode & 0x80)) { SInt32 theTicks = LMGetTicks(); LMSetKeyTime(theTicks); LMSetKeyRepTime(theTicks); LMSetKeyLast(theMessage); LMSetHiKeyLast(NEWTON_KEYBOARD_CODE); ::PostEvent(keyDown, theMessage); // Taste losgelassen } else { // Key-Up-Flag lschen theMessage &= 0xFFFF7FFF; ::PostEvent(keyUp, theMessage); } } /*** * Tastendruck (bzw. das Loslassen) dem MacOS * melden ***/ static void EnterKeycode(UInt8 inCode) { // aktuelle Taste im System lschen LMSetKeyLast(0); LMSetHiKeyLast(0); // true, wenn Taste losgelassen wurde Boolean theDownFlag = (inCode & 0x80) == 0x80; // MacOS-Keycode erzeugen UInt8 theKeyCode; Ptr theKMAP = *gKMAP; theKeyCode = theKMAP[(inCode & 0x7F) + 4]; // Sondercode erkannt? if(theKeyCode & 0x80) { // erstmal das Kennungs-Bit lschen theKeyCode &= 0x7F; // Anzahl der Sondereintrge SInt16 theCount = *reinterpret_cast (&theKMAP[0x84]); // ab hier geht es mit den Tabellen los UInt8 *theKMapP = reinterpret_cast (&theKMAP[0x86]); while(theCount-- > 0) { // Code gefunden? if(*theKMapP++ != theKeyCode) { // zum nchsten Eintrag theKMapP += theKMapP[1] + 2; continue; } if((*theKMapP & 0x0F) == 0x00) return; break; } } // Capslock Abfrage if(theKeyCode == 0x39) { if(theDownFlag) { // Taste gedrckt? // Caps bereits gesetzt? if(gKeyMap[theKeyCode >> 3] & (1 << (theKeyCode & 7))) { // dann lsen! theDownFlag = false; } } else { // Taste losgelassen? // (das interessiert uns nie!) return; } } // in die KeyMap eintragen (vorerst nur in // die eigene) if(theDownFlag) { gKeyMap[theKeyCode >> 3] |= 1 << (theKeyCode & 7); } else { gKeyMap[theKeyCode >> 3] &= ~(1 << (theKeyCode & 7)); // Flag fr "losgelassen" theKeyCode |= 0x80; } // Tastencodes in globalen Variablen merken LMSetKbdLast(theKeyCode); LMSetKbdType(NEWTON_KEYBOARD_CODE); // globale KeyMap updaten ::BlockMoveData(gKeyMap, LMGetKeyMapPtr(), sizeof(KeyMap)); // aktuelle Modifiers fr KeyTranslate lesen UInt16 theModifiers = *(3 + reinterpret_cast (LMGetKeyMapPtr())); // ROL.W #1, theModifiers = (theModifiers >> 15) | (theModifiers << 1); // ASCII-Codes (denkbar: zwei pro // Tastendruck!) errechnen static UInt32 state = 0; UInt32 lStructure = ::KeyTranslate(*gKCHR, theKeyCode | (theModifiers << 8), &state); // ggf. zwei Tasten posten PostKeyMessage(lStructure >> 16, theKeyCode); PostKeyMessage(lStructure, theKeyCode); } /*** * diese asynchrone Routine pollt das Keyboard * an der Seriellen ***/ #include // UPP fr die Callback-Routine IOCompletionUPP gIOUPP; // Refnums fr Serial ein/aus SInt16 gSDIn, gSDOut; // das empfangene Zeichen UInt8 gInChar; // der Parameterblock (asynchron!) ParamBlockRec gParamBlk; /*** * das nchste Byte von der * Tastatur asynchron lesen ***/ static void GetNextByte() { if(gDoQuitFlag) return; // Callback setzen gParamBlk.ioParam.ioCompletion = gIOUPP; // Port lesen gParamBlk.ioParam.ioRefNum = gSDIn; // Buffer auf unser Byte gParamBlk.ioParam.ioBuffer = (Ptr)&gInChar; // ein Byte lesen gParamBlk.ioParam.ioReqCount = 1L; // ab der aktuellen Position gParamBlk.ioParam.ioPosMode = fsAtMark; // kein Offset... gParamBlk.ioParam.ioPosOffset = 0L; // Anforderung absetzen PBReadAsync(&gParamBlk); } /*** * Diese Routine wird angesprungen, * wenn ein Byte eingetroffen ist. ***/ static void MyCompletion( ParmBlkPtr ioParam : __A0) { #pragma unused(ioParam) // Byte verarbeiten EnterKeycode(gInChar); // nchstes Byte anfordern GetNextByte(); } /*** * main() ***/ void main() { // 16k anstatt 2k an Stack! ::SetApplLimit((Ptr)((UInt32) ::GetApplLimit() - 0x4000)); // Crasht vor MacOS 7.5.4, falls eine zweite // FBA ebenfalls MaxApplZone() aufruft: // ::MaxApplZone(); // weitere Init-Calls sind bei FBAs nicht // erlaubt ::InitGraf(&qd.thePort); // AppleEvents installieren (wenn vorhanden) long response; if(!::Gestalt(gestaltAppleEventsAttr, &response)) { if(response & (1L<<0x10> 0x02, // 'd_id', 0x0CL, // Device-ID? // 'kybd','appl', 0x01L, // Keyboard-Typ // 'nofm', 0L, 0x1003dde7L // ??? if(reinterpret_cast(&theBuf)[3] != 'ybda') goto raus; gIOUPP = NewIOCompletionProc(MyCompletion); GetNextByte(); // erstes Byte erwarten gDoQuitFlag = false; while(!gDoQuitFlag) { EventRecord theEvent; // nur einmal pro Sekunde erwarten wir einen // Null-Event! ::WaitNextEvent( everyEvent, &theEvent, 60, 0L); if(theEvent.what == kHighLevelEvent) ::AEProcessAppleEvent(&theEvent); #if DEBUG // zum Debuggen: '^' + Control + Option // beendet das Programm! KeyMap theMap; ::GetKeys(theMap); if((theMap[0] & 0x40000) && ((theMap[1] & 0xC) == 0xC)) { break; } #endif } // auf ein letztes Byte warten! SysBeep(10); SysBeep(10); SysBeep(10); // auf Abschlu des aktuellen Polls warten while(gParamBlk.ioParam.ioResult > 0) {} // Tastaturstatus zurcksetzen LMSetKeyLast(0); LMSetHiKeyLast(0); for(int i=0; iqF*w@KNUDjPg=|GM^80vf@*w@69v2figQ-uekaG@#(&PTHh;>HM%d^ zm*ELe^bE9#n)L5+|FQJz(tip*yhIo#uDR}A{i@xlyKPTsnJvfB%NBzepjpvJ7%LE~ zR5l!2Dar8Yqr2JPK#vMIZwdsOiaM6XPRkSa`^fI*Rxya$Dnd*}rRNq)wL8@E%dKY9 zWj-G`!;KvFdVRc)I;Hs~T_9drnPIX(?1o`ABgCIz55HMQoyuah(!+13Ag-d)McVe= zhQ3Vi*IdHt2J@H|iR+E;Bv40e3Iqw2;R%dy@`B_jsZ-`%xVRjN5U~61+k4b06tX#i zAgQ8KWy);g7^{caf!n+E96)6#5b#dLp~?a8Lcq}^8gGsW&>1yh zp-wDBpe^lw;`cFmUmjr7k>54nyT#kn7rnxH&yTPdIM#5P-X09XUH%`|rp2D9`wwwy BMnC`n literal 0 HcmV?d00001 diff --git a/Newton Keyboard Enabler/Newton Keyboard.rsrc b/Newton Keyboard Enabler/Newton Keyboard.rsrc new file mode 100644 index 0000000000000000000000000000000000000000..77d32f27a4a710c161a7c55acfaa9bc9f52cdbf0 GIT binary patch literal 10432 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 - neben vielen anderen Programmen von mir. + + +######################################## +############### LISTINGs ############### +######################################## +```c +/*** + * Newton Keyboard Enabler.c + * + * Erlaubt die Nutzung eines seriellen Newton- + * Keyboards an einem Mac. Das Keyboard verhält + * sich in fast allen Fällen genau wie ein + * originales ADB-Keyboard (Ausnahme: MacsBug + * kann es nicht nutzen) + * + * Entwickelt mit dem CodeWarrior 9 von + * Metrowerks. + * + * (c)1996 MAXON Computer, Markus Fritze + ***/ + +// c_moeller@macopen.com + +// true, wenn das Programm beendet werden soll +Boolean gDoQuitFlag; + +/*** + * unsere AppleEvent-Routinen + * (schließlich sind wir ein ordentliches + * MacOS Programm) + ***/ +static pascal OSErr DoAENoErr( + const AppleEvent*, AppleEvent*, long) +{ + return noErr; // AppleEvent ist ok +} + +static pascal OSErr DoAEQuitAppl( + const AppleEvent*, AppleEvent*, long) +{ + gDoQuitFlag = true; // Programm beenden + return noErr; +} + + +// einen (hoffentlich) undefinierten Code +// benutzen wir als ID-Code für die Tastatur +#define NEWTON_KEYBOARD_CODE 117L + + +// Zugriffsfunktionen ähnlich +// für den Tastaturtreiber +static inline SInt16 LMGetKeyLast() + { return *(SInt16*)0x0184; }; +static inline void LMSetKeyLast(SInt16 value) + { *(SInt16*)0x0184 = value; }; +static inline SInt16 LMGetHiKeyLast() + { return *(SInt16*)0x0216; }; +static inline void LMSetHiKeyLast(SInt16 value) + { *(SInt16*)0x0216 = value; }; + +static inline SInt32 LMGetKeyTime() + { return *(SInt32*)0x0186; }; +static inline void LMSetKeyTime(SInt32 value) + { *(SInt32*)0x0186 = value; }; +static inline SInt32 LMGetKeyRepTime() + { return *(SInt32*)0x018A; }; +static inline void LMSetKeyRepTime(SInt32 value) + { *(SInt32*)0x018A = value; }; + +// ohne "inline", wegen eines 68k Compilerbugs +// beim CodeWarrior 9 +static /*inline*/ KeyMap *LMGetKeyMapPtr() + { return (KeyMap*)0x0174; }; + +// Unsere globalen Variablen für die Tastatur +Handle gKMAP; +Handle gKCHR; +UInt8 gKeyMap[16]; + +/*** + * Keyboard-Variablen initialisieren + ***/ +static void InitKeyboard() +{ + Handle thePref = + ::Get1Resource('PREF', 128); + + // eigener Typ: Newton Keyboard + gKMAP = ::Get1Resource('KMAP', **thePref); + if(!gKMAP) ::ExitToShell(); + ::HLockHi(gKMAP); + + // ein deutsches Keyboard: + gKCHR = ::GetResource('KCHR', + ((short*)*thePref)[1]); + if(!gKCHR) + // ein US-Keyboard: + gKCHR = ::GetResource('KCHR', 0); + if(!gKCHR) ::ExitToShell(); + ::HLockHi(gKCHR); + + // eigene Keymap löschen + for(int i=0; i raus + if(inKey == 0x00L) return; + + // Message zusammensetzen + UInt32 theMessage = inKey + | UInt16(inKeyCode << 8) + | (NEWTON_KEYBOARD_CODE << 16); + + // Taste gedrückt + if(!(inKeyCode & 0x80)) { + SInt32 theTicks = LMGetTicks(); + LMSetKeyTime(theTicks); + LMSetKeyRepTime(theTicks); + LMSetKeyLast(theMessage); + LMSetHiKeyLast(NEWTON_KEYBOARD_CODE); + ::PostEvent(keyDown, theMessage); + + // Taste losgelassen + } else { + // Key-Up-Flag löschen + theMessage &= 0xFFFF7FFF; + ::PostEvent(keyUp, theMessage); + } +} + +/*** + * Tastendruck (bzw. das Loslassen) dem MacOS + * melden + ***/ +static void EnterKeycode(UInt8 inCode) +{ + // aktuelle Taste im System löschen + LMSetKeyLast(0); + LMSetHiKeyLast(0); + + // true, wenn Taste losgelassen wurde + Boolean theDownFlag = + (inCode & 0x80) == 0x80; + + // MacOS-Keycode erzeugen + UInt8 theKeyCode; + Ptr theKMAP = *gKMAP; + theKeyCode = theKMAP[(inCode & 0x7F) + 4]; + // Sondercode erkannt? + if(theKeyCode & 0x80) { + + // erstmal das Kennungs-Bit löschen + theKeyCode &= 0x7F; + + // Anzahl der Sondereinträge + SInt16 theCount = + *reinterpret_cast + (&theKMAP[0x84]); + + // ab hier geht es mit den Tabellen los + UInt8 *theKMapP = + reinterpret_cast + (&theKMAP[0x86]); + while(theCount-- > 0) { + // Code gefunden? + if(*theKMapP++ != theKeyCode) { + // zum nächsten Eintrag + theKMapP += theKMapP[1] + 2; + continue; + } + if((*theKMapP & 0x0F) == 0x00) + return; + break; + } + } + + // Capslock Abfrage + if(theKeyCode == 0x39) { + if(theDownFlag) { // Taste gedrückt? + + // Caps bereits gesetzt? + if(gKeyMap[theKeyCode >> 3] + & (1 << (theKeyCode & 7))) { + // dann lösen! + theDownFlag = false; + } + } else { // Taste losgelassen? + // (das interessiert uns nie!) + return; + } + } + + // in die KeyMap eintragen (vorerst nur in + // die eigene) + if(theDownFlag) { + gKeyMap[theKeyCode >> 3] |= + 1 << (theKeyCode & 7); + } else { + gKeyMap[theKeyCode >> 3] &= + ~(1 << (theKeyCode & 7)); + + // Flag für "losgelassen" + theKeyCode |= 0x80; + } + + // Tastencodes in globalen Variablen merken + LMSetKbdLast(theKeyCode); + LMSetKbdType(NEWTON_KEYBOARD_CODE); + + // globale KeyMap updaten + ::BlockMoveData(gKeyMap, LMGetKeyMapPtr(), + sizeof(KeyMap)); + + // aktuelle Modifiers für KeyTranslate lesen + UInt16 theModifiers = *(3 + + reinterpret_cast + (LMGetKeyMapPtr())); + + // ROL.W #1, + theModifiers = (theModifiers >> 15) + | (theModifiers << 1); + + // ASCII-Codes (denkbar: zwei pro + // Tastendruck!) errechnen + static UInt32 state = 0; + UInt32 lStructure = ::KeyTranslate(*gKCHR, + theKeyCode | (theModifiers << 8), + &state); + + // ggf. zwei Tasten posten + PostKeyMessage(lStructure >> 16, theKeyCode); + PostKeyMessage(lStructure, theKeyCode); +} + +/*** + * diese asynchrone Routine pollt das Keyboard + * an der Seriellen + ***/ +#include + +// UPP für die Callback-Routine +IOCompletionUPP gIOUPP; + +// Refnums für Serial ein/aus +SInt16 gSDIn, gSDOut; + +// das empfangene Zeichen +UInt8 gInChar; + +// der Parameterblock (asynchron!) +ParamBlockRec gParamBlk; + +/*** + * das nächste Byte von der + * Tastatur asynchron lesen + ***/ +static void GetNextByte() +{ + if(gDoQuitFlag) return; + // Callback setzen + gParamBlk.ioParam.ioCompletion = gIOUPP; + // Port lesen + gParamBlk.ioParam.ioRefNum = gSDIn; + // Buffer auf unser Byte + gParamBlk.ioParam.ioBuffer = (Ptr)&gInChar; + // ein Byte lesen + gParamBlk.ioParam.ioReqCount = 1L; + // ab der aktuellen Position + gParamBlk.ioParam.ioPosMode = fsAtMark; + // kein Offset... + gParamBlk.ioParam.ioPosOffset = 0L; + // Anforderung absetzen + PBReadAsync(&gParamBlk); +} + +/*** + * Diese Routine wird angesprungen, + * wenn ein Byte eingetroffen ist. + ***/ +static void MyCompletion( + ParmBlkPtr ioParam : __A0) +{ +#pragma unused(ioParam) + + // Byte verarbeiten + EnterKeycode(gInChar); + + // nächstes Byte anfordern + GetNextByte(); +} + +/*** + * main() + ***/ +void main() +{ + // 16k anstatt 2k an Stack! + ::SetApplLimit((Ptr)((UInt32) + ::GetApplLimit() - 0x4000)); + + // Crasht vor MacOS 7.5.4, falls eine zweite + // FBA ebenfalls MaxApplZone() aufruft: + // ::MaxApplZone(); + + // weitere Init-Calls sind bei FBAs nicht + // erlaubt + ::InitGraf(&qd.thePort); + + // AppleEvents installieren (wenn vorhanden) + long response; + if(!::Gestalt(gestaltAppleEventsAttr, + &response)) { + if(response & + (1L<<0x10> 0x02, + // 'd_id', 0x0CL, // Device-ID? + // 'kybd','appl', 0x01L, // Keyboard-Typ + // 'nofm', 0L, 0x1003dde7L // ??? + if(reinterpret_cast(&theBuf)[3] + != 'ybda') + goto raus; + + gIOUPP = NewIOCompletionProc(MyCompletion); + GetNextByte(); // erstes Byte erwarten + + gDoQuitFlag = false; + while(!gDoQuitFlag) { + EventRecord theEvent; + // nur einmal pro Sekunde erwarten wir einen + // Null-Event! + ::WaitNextEvent( + everyEvent, &theEvent, 60, 0L); + if(theEvent.what == kHighLevelEvent) + ::AEProcessAppleEvent(&theEvent); + +#if DEBUG + // zum Debuggen: '^' + Control + Option + // beendet das Programm! + KeyMap theMap; + ::GetKeys(theMap); + if((theMap[0] & 0x40000) && + ((theMap[1] & 0xC) == 0xC)) { + break; + } +#endif + } + // auf ein letztes Byte warten! + SysBeep(10); SysBeep(10); SysBeep(10); + + // auf Abschluß des aktuellen Polls warten + while(gParamBlk.ioParam.ioResult > 0) {} + + // Tastaturstatus zurücksetzen + LMSetKeyLast(0); + LMSetHiKeyLast(0); + for(int i=0; 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 Dhk05< literal 0 HcmV?d00001 diff --git a/preferences.png b/preferences.png new file mode 100644 index 0000000000000000000000000000000000000000..8a783fb5a107f646ac8930e3cc34bf77762c3f5e GIT binary patch literal 11387 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 literal 0 HcmV?d00001