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; i - 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; i