// OVIMTibetan.cpp: The Tibetan Input Method // 2004-2006 by Weizhong Yang // // http://openvanilla.org // // OpenVanilla Tibetan Input Method is based on the Sambhota Keyboard, // please check http://iris.lib.virginia.edu/tibet/tools/jskad_docs/Sambhota_keymap_one.rtf for detail. // // This program is Zonble-ware and adopts Zonble's License // -- "How could a person who doesn't even believe in law adopt any license?" // #define OV_DEBUG #include #include #include #include #include #include #include "OVIMTibetan.h" int keyboardlayout = 0; // The Deafault keyboard layout is Sambhota Keymap #1 char *imlocale; short isSymbolKey(int key) // Check if the keycode is mapping to a punctuation or a symbol { int i; for(i=0; i< SYMBOL_NUM; i++) { if(key == SymbolKeys[keyboardlayout][i]) return i; } return -1; } short isConsonantKey(int key) { int i; for(i=0; i< CONSONAT_NUM; i++) { if(key == ConsonantKeys[keyboardlayout][i]) return i; } return -1; } short isVowelKey(int key) { int i; for(i=0; i< VOWEL_NUM; i++) { if(key == VowelKeys[keyboardlayout][i]) return i; } return -1; } short isFinalAddKey(int key) { int i; for(i=0; i< FINALADD_NUM; i++) { if(key == FinalAddKeys[keyboardlayout][i]) return i; } return -1; } short isHtransform(int key) { int i; for(i=0; i< 5; i++) { if(key == htransformKey[i]) return i; } return -1; } class OVIMTibetan; class OVTibetanContext : public OVInputMethodContext { public: OVTibetanContext(OVIMTibetan *p){parent=p;} virtual ~OVTibetanContext(){} virtual void clear() { keyseq.clear(); keyseq.lastisother(); } virtual void end() { keyseq.clear(); keyseq.lastisother(); } virtual int keyEvent(OVKeyCode *key, OVBuffer *buf, OVCandidate *textbar, OVService *srv) { unsigned short i; short j = -1, k = -1; const char *u8; if (key->isOpt() || key->isCommand() || key->isCtrl()){return 0;} if (key->code() == ovkUp || key->code() == ovkDown ||key->code() == ovkLeft ||key->code() == ovkRight ) //Locked when composing { keyseq.lastisother(); if(keyseq.len) { buf->send()->clear(); } return 0; // key processed } if (key->isCapslock()) { //CapLock int code; char b[2]; if (key->isShift()) { code = toupper(key->code()); } else { code = tolower(key->code()); } sprintf(b, "%c", code); buf->append(b)->send()->clear(); return 1; } if (key->code() == ovkReturn || key->code() == 3) { if (!keyseq.len) return 0; // if buffer is empty, don't process buf->send()->clear(); keyseq.clear(); keyseq.lastisother(); return 1; // key processed } if (key->code() == ovkSpace) //Space to keyin Tibetan seperator. { i = 0x0F0B; u8=srv->UTF16ToUTF8(&i, 1); buf->append(u8)->send()->clear(); keyseq.clear(); keyseq.lastisother(); return 1; // key processed } if (key->code() == ovkDelete || key->code() == ovkBackspace) { if(!keyseq.len) return 0; buf->clear()->update(); keyseq.clear(); keyseq.lastisother(); return 1; } { char keycode = key->code(); if(keycode >= '0' && keycode <= '9') // Numbers // The numbric keys are always to input tibetan numbers { i = 0x0F20 + (keycode - '0'); u8=srv->UTF16ToUTF8(&i, 1); buf->append(u8)->send()->clear(); keyseq.clear(); keyseq.lastisother(); return 1; // key processed } if(keycode == SpaceKey[keyboardlayout]) // Keyin a space. { buf->append((char *)" ")->send(); keyseq.clear(); keyseq.lastisother(); return 1; // key processed } if(keycode == ComposeKey[keyboardlayout]) // Compose key { buf->send()->clear(); if(keyseq.buf[0] == ComposeKey[keyboardlayout]) //End Stacking { keyseq.clear(); keyseq.lastisconsonant(); } else { //Begin Composing keyseq.clear(); keyseq.lastisother(); keyseq.add(keycode); if (!strcasecmp(srv->locale(), "zh_TW")) srv->notify("進入組合字狀態…"); else if(!strcasecmp(srv->locale(), "zh_CN")) srv->notify("进入组合字状态…"); else srv->notify("Stacking characters.."); } buf->update(); return 1; // key processed } if((j = isFinalAddKey(keycode)) > -1) // Final M or N { if(keyseq.buf[0]== ComposeKey[keyboardlayout] && keyseq.len == 1) return 1; if(keyseq.last || keyseq.len){ i = FinalAddChars[j]; u8=srv->UTF16ToUTF8(&i, 1); buf->append(u8)->send()->clear(); keyseq.clear(); keyseq.lastisother(); } return 1; } if((j = isSymbolKey(keycode)) > -1) // Symbols { i = SymbolChars[j]; u8=srv->UTF16ToUTF8(&i, 1); buf->append(u8)->send()->clear(); keyseq.clear(); keyseq.lastisother(); return 1; // key processed } if((j = isVowelKey(keycode)) > -1) // Vowels { if(keyseq.last == 1 || (keyseq.buf[0] == ComposeKey[keyboardlayout] && keyseq.len > 3)) { i = VowelChars[j]; u8=srv->UTF16ToUTF8(&i, 1); buf->append(u8)->send()->clear(); keyseq.clear(); keyseq.lastisvowel(); } return 1; // key processed } if(keyboardlayout == 1) //Sambhota Keymap #2 { if(keycode == 'D') keycode = 'm'; if(keycode == 'F') keycode = '\''; } if((j = isConsonantKey(keycode)) > -1) // Consonant { i = ConsonantChars[j]; keyseq.lastisconsonant(); if(keyseq.buf[0] == ComposeKey[keyboardlayout] && keyseq.len < MAX_COMPOSE) // Stacking { if(j == 34 && keyseq.len > 1) //kb transform { if(isConsonantKey(keyseq.buf[keyseq.len -1]) == 0) { buf->clear()->update(); if(keyseq.len < 3) { i = 0x0F69; u8=srv->UTF16ToUTF8(&i, 1); buf->append(u8)->update(); } else { if(((k = isHtransform(isConsonantKey(keyseq.buf[1]))) > -1) && isConsonantKey(keyseq.buf[2]) == htransform) { i = htransfromChars[k]; u8=srv->UTF16ToUTF8(&i, 1); buf->append(u8); } else if (isConsonantKey(keyseq.buf[1]) == 0 && //ka isConsonantKey(keyseq.buf[2]) == 34) //ssa { i = 0x0FB9; u8=srv->UTF16ToUTF8(&i, 1); buf->append(u8); //kssa } else { i = ConsonantChars[isConsonantKey(keyseq.buf[1])]; u8=srv->UTF16ToUTF8(&i, 1); buf->append(u8); if(keyseq.len == 4) { i = ConsonantChars[isConsonantKey(keyseq.buf[2])]; u8=srv->UTF16ToUTF8(&i, 1); buf->append(u8); } } i = 0x0FB9; u8=srv->UTF16ToUTF8(&i, 1); buf->append(u8)->update(); } keyseq.add(keycode); return 1; } } if(j == htransform && keyseq.len > 1) //H transform { if((k = isHtransform(isConsonantKey(keyseq.buf[keyseq.len -1]))) > -1) { buf->clear()->update(); if(keyseq.len < 3) { i = htransfromChars[k]; u8=srv->UTF16ToUTF8(&i, 1); buf->append(u8)->update(); } else { int l = -1; if(((l = isHtransform(isConsonantKey(keyseq.buf[1]))) > -1) && isConsonantKey(keyseq.buf[2]) == htransform) { i = htransfromChars[l]; u8=srv->UTF16ToUTF8(&i, 1); buf->append(u8); } else if (isConsonantKey(keyseq.buf[1]) == 0 && //ka isConsonantKey(keyseq.buf[2]) == 34) //ssa { i = 0x0FB9; u8=srv->UTF16ToUTF8(&i, 1); buf->append(u8); } else { i = ConsonantChars[isConsonantKey(keyseq.buf[1])]; u8=srv->UTF16ToUTF8(&i, 1); buf->append(u8); if(keyseq.len == 4) { i = ConsonantChars[isConsonantKey(keyseq.buf[2])]; u8=srv->UTF16ToUTF8(&i, 1); buf->append(u8); } } i = htransfromChars[k] + 0x50; u8=srv->UTF16ToUTF8(&i, 1); buf->append(u8)->update(); } keyseq.add(keycode); return 1; } } if(keyseq.len > 1) { if(j == 22) { i = 0x0F71; } else { i = i + 0x50; // Sub characters. } } u8=srv->UTF16ToUTF8(&i, 1); buf->append(u8)->update(); keyseq.add(keycode); return 1; } u8=srv->UTF16ToUTF8(&i, 1); buf->append(u8)->send()->clear(); keyseq.clear(); return 1; // key processed } { //Extra if(keycode == 'M' || keycode == '>') { buf->clear()->append((char*)"ཧཱུྃ")->send();keyseq.clear(); } if(keycode == '+' || keycode == '!') { buf->clear()->append((char*)"༄༅")->send();keyseq.clear(); } if(keycode == '=') { buf->clear()->append((char*)"ཨཱཿ")->send();keyseq.clear(); } if(keycode == '<') { buf->clear()->append((char*)"ཨོཾ")->send();keyseq.clear(); } if(keycode == '^') { buf->clear()->append((char*)"༁ྃ")->send();keyseq.clear(); } } return 1; } return 0; // key not processed } protected: OVIMTibetan *parent; KeySeq keyseq; }; class OVIMTibetan : public OVInputMethod { public: OVIMTibetan(){} virtual const char *identifier() { return "OVIMTibetan"; } virtual const char *localizedName(const char *locale) { if (!strcasecmp(locale, "zh_TW")) return "藏文"; else if (!strcasecmp(locale, "zh_CN")) return "藏文"; else return "Tibetan"; } virtual int initialize(OVDictionary* l, OVService*, const char* modulePath) { if (!l->keyExist("keyboardLayout")) l->setInteger("keyboardLayout", 0); keyboardlayout=l->getInteger("keyboardLayout"); if(keyboardlayout >= KEYBOARDS) keyboardlayout = 0; return 1; } virtual int update(OVDictionary*, OVDictionary*) { return 1; } virtual OVInputMethodContext* newContext() { return new OVTibetanContext(this); } }; // use these two wrappers OV_SINGLE_MODULE_WRAPPER(OVIMTibetan);