//#define OV_DEBUG #include "ImmController.h" ImmController* ImmController::m_self = NULL; ImmController::ImmController() { m_shiftPressedTime = 0; m_isCompStarted = false; } ImmController::~ImmController(void) { m_self = NULL; } ImmController* ImmController::open() { if(m_self == NULL) m_self = new ImmController(); return m_self; } void ImmController::close(void) { if(m_self) delete m_self; } int ImmController::onKeyShiftOnly(HIMC hIMC, LPARAM lKeyData) { int shiftState; if(!getKeyInfo(lKeyData).isKeyUp) // Shift pressed { murmur("shift-only: down"); m_shiftPressedTime = GetTickCount(); shiftState = 1; } else if(GetTickCount() - m_shiftPressedTime < 200) // Shift Up { murmur("shift-only: up"); //Toggle Chinese/English mode. //lParam == 2 MyGenerateMessage(hIMC, WM_IME_NOTIFY, IMN_PRIVATE, 2); shiftState = 2; m_shiftPressedTime = 0; } else //Shift Up too late { murmur("shift-only: other"); shiftState = 0; m_shiftPressedTime = 0; } return shiftState; } int ImmController::onKeyShift(HIMC hIMC, UINT uVKey, LPARAM lKeyData) { int processState; if(LOWORD(uVKey) == VK_SPACE) //shift + space { murmur("S: vkey=%u", LOWORD(uVKey)); murmur("S_Space: Full-Half char"); m_shiftPressedTime = 0; processState = 1; } else if(LOWORD(uVKey) == VK_SHIFT) // only shift { switch(onKeyShiftOnly(hIMC, lKeyData)) { case 1: murmur("S: EN-ZH: waiting for key-up"); processState = 1; break; case 2: murmur("S: EN-ZH: proceeded"); //processState = 1; processState = 2; break; case 0: default: murmur("S: passed"); m_shiftPressedTime = 0; processState = 0; break; } } else //shift + ? { murmur("S_%u: assume normal", LOWORD(uVKey)); m_shiftPressedTime = 0; processState = 2; } return processState; } int ImmController::onKeyCtrl(HIMC hIMC, UINT uVKey) { int processState; switch(LOWORD(uVKey)) { case VK_CONTROL: murmur("C: passed"); processState = 0; break; case VK_MENU: murmur("C_A: passed"); processState = 0; break; case VK_OEM_5: //Change the module by Ctrl+"\": //lParam == 8 murmur("C_\\: change module"); MyGenerateMessage(hIMC, WM_IME_NOTIFY, IMN_PRIVATE, 8); processState = 1; break; case VK_OEM_PLUS: //Change the BoPoMoFo keyboard layout by Ctrl+"=": //lParam == 5 murmur("C_=: change Hsu's layout"); MyGenerateMessage(hIMC, WM_IME_NOTIFY, IMN_PRIVATE, 5); processState = 1; break; case VK_SPACE: murmur("C_Space: switch IME"); processState = 1; break; case VK_SHIFT: murmur("C_S: rotate IME"); processState = 1; break; default: murmur("C_%u: assume normal", LOWORD(uVKey)); processState = 2; } return processState; } int ImmController::onKeyCtrlAlt(HIMC hIMC, UINT uVKey) { int processState; switch(LOWORD(uVKey)) { case VK_MENU: case VK_CONTROL: murmur("C_A: passed"); processState = 0; break; case VK_G: //Toggle Traditional / Simplified Chinese. //lParam == 4 murmur("C_A_g: TW-CN"); MyGenerateMessage(hIMC, WM_IME_NOTIFY, IMN_PRIVATE, 4); processState = 1; break; case VK_K: //Toggle Large Candidate window. //lParam == 6 murmur("C_A_k: Expand Cand"); MyGenerateMessage(hIMC, WM_IME_NOTIFY, IMN_PRIVATE, 6); processState = 1; break; case VK_L: // Test Notify window. murmur("C_A_l: Notify"); MyGenerateMessage(hIMC, WM_IME_NOTIFY, IMN_PRIVATE, 7); processState = 1; break; default: murmur("C_A_%u: assume normal", LOWORD(uVKey)); processState = 2; break; } return processState; } int ImmController::onControlEvent (HIMC hIMC, UINT uVKey, LPARAM lKeyData, CONST LPBYTE lpbKeyState) { int processState; if(getKeyInfo(lKeyData).isKeyUp) { if(LOWORD(uVKey) == VK_SHIFT) { processState = onKeyShift(hIMC, uVKey, lKeyData); } else { murmur("other key up"); m_shiftPressedTime = 0; processState = 0; } } else if(isCtrlPressed(lpbKeyState)) { if(isAltPressed(lpbKeyState)) { murmur("ctrl-alt state"); processState = onKeyCtrlAlt(hIMC, uVKey); } else { murmur("ctrl state"); processState = onKeyCtrl(hIMC, uVKey); } } else if(isShiftPressed(lpbKeyState)) { murmur("shift state"); processState = onKeyShift(hIMC, uVKey, lKeyData); DWORD conv, sentence; ImmGetConversionStatus(hIMC, &conv, &sentence); //Alphanumeric mode if(!(conv & IME_CMODE_NATIVE)) processState = 0; //else processState = onKeyShift(hIMC, uVKey, lKeyData); } else { murmur("other state: assume normal"); m_shiftPressedTime = 0; DWORD conv, sentence; ImmGetConversionStatus(hIMC, &conv, &sentence); //Alphanumeric mode if(!(conv & IME_CMODE_NATIVE)) processState = 0; else processState = 2; } return processState; } BOOL ImmController::onTypingEvent (HIMC hIMC, UINT uVKey, LPARAM lKeyData, CONST LPBYTE lpbKeyState) { BOOL isProcessed = FALSE; //if(getKeyInfo(lKeyData).isKeyUp) return isProcessed; /* DWORD conv, sentence; ImmGetConversionStatus(hIMC, &conv, &sentence); //Alphanumeric mode if(!(conv & IME_CMODE_NATIVE)) return isProcessed; */ ImmModel* model = ImmModel::open(hIMC); if(!m_isCompStarted && wcslen(GETLPCOMPSTR(model->getCompStr())) == 0) { murmur("STARTCOMPOSITION"); m_isCompStarted = true;//要先做! MyGenerateMessage(hIMC, WM_IME_STARTCOMPOSITION, 0, 0); } ImmModel::close(); int k = LOWORD(uVKey); if( k >= 65 && k <= 90) k = k + 32; switch(LOWORD(uVKey)) { case VK_PRIOR: // pageup k = 11; break; case VK_NEXT: // pagedown k = 12; break; case VK_END: k = 4; break; case VK_HOME: k = 1; break; case VK_LEFT: k = 28; break; case VK_UP: k = 30; break; case VK_RIGHT: k = 29; break; case VK_DOWN: k = 31; break; case VK_DELETE: k = 127; break; default: //DebugLog("uVKey: %x, %c\n", LOWORD(uVKey), LOWORD(uVKey)); break; } WORD out[2]; int spec = ToAscii(uVKey, MapVirtualKey(uVKey, 0), lpbKeyState, (LPWORD)&out, 0); if(spec == 1) k = (char)out[0]; murmur("KEY: %c", out[0]); AVKeyCode keycode(k); if(LOWORD(lpbKeyState[VK_CAPITAL])) keycode.setCapslock(1); if(isShiftPressed(lpbKeyState) || LOWORD(uVKey) == VK_SHIFT) keycode.setShift(1); if(isCtrlPressed(lpbKeyState)) keycode.setCtrl(1); if(isAltPressed(lpbKeyState)) keycode.setAlt(1); if((lpbKeyState[VK_NUMLOCK]) && (uVKey >= VK_NUMPAD0) && (uVKey <= VK_DIVIDE)) keycode.setNum(1); AVLoader* loader = AVLoader::open(); if(loader->keyEvent(UICurrentInputMethod(), keycode)) //如果目前模組處理此key { isProcessed = TRUE; // // Moves this block back to DisplayServer. /* if(LOWORD(uVKey) != VK_RETURN) { murmur("COMPOSITION GCS_COMPSTR"); MyGenerateMessage(hIMC, WM_IME_COMPOSITION, 0, GCS_COMPSTR); } else { murmur("COMPOSITION GCS_RESULTSTR"); MyGenerateMessage(hIMC, WM_IME_COMPOSITION, 0, GCS_RESULTSTR); m_isCompStarted = false; //要先做! murmur("ENDCOMPOSITION"); MyGenerateMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0); //InitCompStr(m_model->getCompStr()); } */ // } else { model = ImmModel::open(hIMC); //James comment: 解決未組成字之前選字 comp window 會消失的問題(?待商榷) if(m_isCompStarted && wcslen(GETLPCOMPSTR(model->getCompStr())) == 0) { murmur("ENDCOMPOSITION"); m_isCompStarted = false; //要先做! MyGenerateMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0); } ImmModel::close(); } return isProcessed; }