// TSBunble.mm: A dynamically-loadable text service bundle // // This implementation loads CocoaVanilla (OVLoader.bundle) // // Copyright (c) 2004-2006 The OpenVanilla Project (http://openvanilla.org) // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // 3. Neither the name of OpenVanilla nor the names of its contributors // may be used to endorse or promote products derived from this software // without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. #include #include #include "TSBundle.h" #include "IMInterface.h" // #define DEBUG // If we follow the ATSC protocol well, we can be 100% sure that // (1) our component will only be initialized once // (2) when initialization fails, no other functions will ever be called // (3) if TSBContextOpen fails, no other functions will ever be called #ifdef DEBUG #define MURMUR(x) fprintf(stderr, x); fprintf(stderr, "\n"); #else #define MURMUR(x) #endif // global data (active context and menu reference) static TSBDataPtr tsbActiveContext=NULL; @interface TSThreadFoo : NSObject - (void)run; @end; @implementation TSThreadFoo - (void)run { // NSLog(@"OpenVanilla gets Cocoa into multithreaded mode"); [NSThread exit]; // NSLog(@"thread ended"); } @end; extern "C" ComponentResult TSBInitialize(MenuRef mnu) { MURMUR("TSBInitialize"); if (!NSApplicationLoad()) { MURMUR("TSBInitialize: NSApplicationLoad() failed"); return -1; } // this is sine-qua-non for every Cocoa bundle... as we will // (and cannot) release this pool, we won't have assign anything to it [[NSAutoreleasePool alloc] init]; id ttf=[[[TSThreadFoo alloc] init] autorelease]; [NSThread detachNewThreadSelector:@selector(run) toTarget:ttf withObject:nil]; // initilize the real IM code return IMInitialize(mnu) ? noErr : -1; } extern "C" ComponentResult TSBContextOpen(ComponentInstance inst, TSBDataPtr* savePtr) { MURMUR("TSBContextOpen"); IMContext *cntx=new IMContext(inst); if (!(*savePtr=cntx) || !cntx->buf) return -1; if (!IMContextOpen(cntx)) return -1; return noErr; } // as we have been said, the functions below will never be called if // there's anything wrong in the init/context opening process, // so we won't do any check extern "C" ComponentResult TSBContextClose(TSBDataPtr ptr) { MURMUR("TSBContextClose"); IMContextClose((IMContext*)ptr); return noErr; } extern "C" ComponentResult TSBContextActivate(TSBDataPtr ptr) { MURMUR("TSBContextActivate"); tsbActiveContext=ptr; IMContextActivate((IMContext*)ptr); return noErr; } extern "C" ComponentResult TSBContextDeactivate(TSBDataPtr ptr) { MURMUR("TSBContextDeactivate"); IMContextDeactivate((IMContext*)ptr); tsbActiveContext=NULL; return noErr; } extern "C" ComponentResult TSBContextFix(TSBDataPtr ptr) { MURMUR("TSBContextFix"); IMContext *c=(IMContext*)ptr; if (!c->sessionlock) IMContextFix(c); return noErr; } extern "C" ComponentResult TSBContextEvent(TSBDataPtr ptr, EventRef evnt) { MURMUR("TSBContextEvent"); // we only take kEventRawKeyDown and kEventRawKeyRepat if (GetEventClass(evnt)!=kEventClassKeyboard) return FALSE; UInt32 eventkind=GetEventKind(evnt); if (eventkind!=kEventRawKeyDown && eventkind!=kEventRawKeyRepeat) return FALSE; // extract charcode (ASCII) and modifiers char charcode=0; UInt32 modifiers=0; UInt32 kcode=0; GetEventParameter(evnt, kEventParamKeyCode, typeUInt32, nil, sizeof(kcode), nil, &kcode); GetEventParameter(evnt, kEventParamKeyMacCharCodes, typeChar, nil, sizeof(charcode), nil, &charcode); GetEventParameter(evnt, kEventParamKeyModifiers, typeUInt32, nil, sizeof(modifiers), nil, &modifiers); UInt32 numkeys[16]={ // keycode (not charcode) for numkeys // 0,1,2,3,4,5 // 6,7,8,9,.,+,-,*,/,= 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5b, 0x5c, 0x41, 0x45, 0x4e, 0x43, 0x4b, 0x51 }; // there is some mysterious OS X numlock key issue, we need // this workaround to tackle it modifiers &= 0xfffeffff; // first, we remove the numlock mask for (int i=0; i<16; i++) { if (kcode==numkeys[i]) { modifiers |= 0x10000; // only if it's numback we put mask back break; } } // fprintf(stderr, "charcode=%x, modifiers=%x, keycode=%x\n", charcode, modifiers, kcode); IMContext *c=(IMContext*)ptr; c->sessionlock=1; int r=IMContextEvent((IMContext*)ptr, charcode, modifiers); c->sessionlock=0; return r; // old code snippet from VanillaInput /* Boolean handled; UInt32 eventClass; UInt32 eventKind; handled = FALSE; eventClass = GetEventClass(inEventRef); eventKind = GetEventKind(inEventRef); if(eventClass==kEventClassKeyboard && (eventKind == kEventRawKeyDown || eventKind == kEventRawKeyRepeat )) { UInt32 keyCode; unsigned char charCode; UInt32 modifiers; GetEventParameter( inEventRef, kEventParamKeyCode, typeUInt32, nil, sizeof (keyCode), nil, &keyCode ); GetEventParameter( inEventRef, kEventParamKeyMacCharCodes, typeChar, nil, sizeof( charCode ), nil, &charCode ); GetEventParameter( inEventRef, kEventParamKeyModifiers, typeUInt32, nil, sizeof( modifiers ), nil, &modifiers ); fprintf(stderr, "charcode=%d, modifiers=%d, keyCode=%x\n", charCode, modifiers, keyCode); IMContext *c=(IMContext*)ptr; c->sessionlock=1; handled=IMContextEvent((IMContext*)ptr, charCode, modifiers); c->sessionlock=0; } return handled; */ } extern "C" ComponentResult TSBMenuHandler(UInt32 cmd) { MURMUR("TSBMenuHandler") if (!tsbActiveContext) return eventNotHandledErr; IMMenuHandler((IMContext*)tsbActiveContext, cmd); return noErr; }