HRESULT CTextService::_HandleCharacterKey(TfEditCookie ec, ITfContext *pContext, WPARAM wParam) { if (!_IsComposing()) _StartComposition(pContext); // // create an instance of the candidate list class. // if (_pCandidateList == NULL) _pCandidateList = new CCandidateList(this); // // The document manager object is not cached. Get it from pContext. // ITfDocumentMgr *pDocumentMgr; if (pContext->GetDocumentMgr(&pDocumentMgr) == S_OK) { // // get the composition range. // ITfRange *pRange; if (_pComposition->GetRange(&pRange) == S_OK) { _pCandidateList->_StartCandidateList(_tfClientId, pDocumentMgr, pContext, ec, pRange); pRange->Release(); } pDocumentMgr->Release(); } if (_IsComposing()) _TerminateComposition(ec, pContext); return S_OK; }
HRESULT CTextService::_ShowCandidateList(TfEditCookie ec, ITfContext *pContext, BOOL reg, BOOL comp) { HRESULT hr = E_FAIL; try { if(_pCandidateList == NULL) { _pCandidateList = new CCandidateList(this); } ITfDocumentMgr *pDocumentMgr; if(pContext->GetDocumentMgr(&pDocumentMgr) == S_OK) { ITfRange *pRange; if(_IsComposing() && _pComposition->GetRange(&pRange) == S_OK) { hr = _pCandidateList->_StartCandidateList(_ClientId, pDocumentMgr, pContext, ec, pRange, reg, comp); SafeRelease(&pRange); } SafeRelease(&pDocumentMgr); } if(hr != S_OK) { _ResetStatus(); _CancelComposition(ec, pContext); } } catch(...) { } return hr; }
BOOL CTextService::_GetVertical(TfEditCookie ec, ITfContext *pContext) { BOOL ret = FALSE; if(pContext != NULL) { ITfRange *pRange; if(_IsComposing() && _pComposition->GetRange(&pRange) == S_OK) { ITfReadOnlyProperty *pReadOnlyProperty; if(pContext->GetAppProperty(TSATTRID_Text_VerticalWriting, &pReadOnlyProperty) == S_OK) { VARIANT var; if(pReadOnlyProperty->GetValue(ec, pRange, &var) == S_OK) { if(var.vt == VT_BOOL) { ret = var.boolVal; } } SafeRelease(&pReadOnlyProperty); } SafeRelease(&pRange); } } return ret; }
STDAPI CTextService::OnTestKeyDown(ITfContext *pic, WPARAM wParam, LPARAM lParam, BOOL *pfEaten) { if(pfEaten == NULL) { return E_INVALIDARG; } int eaten = _IsKeyEaten(pic, wParam, lParam, TRUE, TRUE); if(eaten == -1) { *pfEaten = TRUE; return S_OK; } *pfEaten = (eaten == TRUE); _EndInputModeWindow(); if(!_IsKeyboardDisabled() && _IsKeyboardOpen() && !_IsComposing()) { WCHAR ch = _GetCh((BYTE)wParam); if(_IsKeyVoid(ch, (BYTE)wParam)) { _GetActiveFlags(); _UpdateLanguageBar(); } } return S_OK; }
HRESULT COVTSF::_HandleCompositionBackspace(TfEditCookie ec, _In_ ITfContext *pContext) { ITfRange* pRangeComposition = nullptr; TF_SELECTION tfSelection; ULONG fetched = 0; BOOL isCovered = TRUE; // Start the new (std::nothrow) compositon if there is no composition. if (!_IsComposing()) { return S_OK; } // first, test where a keystroke would go in the document if we did an insert if (FAILED(pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &fetched)) || fetched != 1) { return S_FALSE; } // is the insertion point covered by a composition? if (SUCCEEDED(_pComposition->GetRange(&pRangeComposition))) { isCovered = _IsRangeCovered(ec, tfSelection.range, pRangeComposition); pRangeComposition->Release(); if (!isCovered) { goto Exit; } } // // Add virtual key to composition processor engine // CCompositionProcessorEngine* pCompositionProcessorEngine = nullptr; pCompositionProcessorEngine = _pCompositionProcessorEngine; DWORD_PTR vKeyLen = pCompositionProcessorEngine->GetVirtualKeyLength(); if (vKeyLen) { pCompositionProcessorEngine->RemoveVirtualKey(vKeyLen - 1); if (pCompositionProcessorEngine->GetVirtualKeyLength()) { _HandleCompositionInputWorker(pCompositionProcessorEngine, ec, pContext); } else { _HandleCancel(ec, pContext); } } Exit: tfSelection.range->Release(); return S_OK; }
STDAPI CTextService::OnEndEdit(ITfContext *pContext, TfEditCookie ecReadOnly, ITfEditRecord *pEditRecord) { BOOL fSelectionChanged; IEnumTfRanges *pEnumTextChanges; ITfRange *pRange; // // did the selection change? // The selection change includes the movement of caret as well. // The caret position is represent as the empty selection range when // there is no selection. // if (pEditRecord->GetSelectionStatus(&fSelectionChanged) == S_OK && fSelectionChanged) { // If the selection is moved to out side of the current composition, // we terminate the composition. This TextService supports only one // composition in one context object. if (_IsComposing()) { TF_SELECTION tfSelection; ULONG cFetched; if (pContext->GetSelection(ecReadOnly, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) == S_OK && cFetched == 1) { ITfRange *pRangeComposition; // is the insertion point covered by a composition? if (_pComposition->GetRange(&pRangeComposition) == S_OK) { if (!IsRangeCovered(ecReadOnly, tfSelection.range, pRangeComposition)) { _EndComposition(pContext); } pRangeComposition->Release(); } } } } // text modification? if (pEditRecord->GetTextAndPropertyUpdates(TF_GTP_INCL_TEXT, NULL, 0, &pEnumTextChanges) == S_OK) { if (pEnumTextChanges->Next(1, &pRange, NULL) == S_OK) { // // pRange is the updated range. // pRange->Release(); } pEnumTextChanges->Release(); } return S_OK; }
HRESULT CTextService::_HandleCharacterKey(TfEditCookie ec, ITfContext *pContext, WPARAM wParam) { ITfRange *pRangeComposition; TF_SELECTION tfSelection; ULONG cFetched; WCHAR ch; BOOL fCovered; // Start the new compositon if there is no composition. OutputDebugString("test compositing"); if (!_IsComposing()) _StartComposition(pContext); OutputDebugString("after test compositing"); // // Assign VK_ value to the char. So the inserted the character is always // uppercase. // ch = (WCHAR)wParam; // first, test where a keystroke would go in the document if an insert is done if (pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) != S_OK || cFetched != 1) return S_FALSE; // is the insertion point covered by a composition? if (_pComposition->GetRange(&pRangeComposition) == S_OK) { fCovered = IsRangeCovered(ec, tfSelection.range, pRangeComposition); pRangeComposition->Release(); if (!fCovered) { goto Exit; } } // insert the text // use SetText here instead of InsertTextAtSelection because a composition was already started //Don't allow to the app to adjust the insertion point inside the composition if (tfSelection.range->SetText(ec, 0, &ch, 1) != S_OK) goto Exit; // update the selection, make it an insertion point just past // the inserted text. tfSelection.range->Collapse(ec, TF_ANCHOR_END); pContext->SetSelection(ec, 1, &tfSelection); // // set the display attribute to the composition range. // _SetCompositionDisplayAttributes(ec, pContext, _gaDisplayAttributeInput); Exit: tfSelection.range->Release(); return S_OK; }
HRESULT COVTSF::_HandleCompositionFinalize(TfEditCookie ec, _In_ ITfContext *pContext, BOOL isCandidateList) { HRESULT hr = S_OK; if (isCandidateList && _pCandidateListUIPresenter) { // Finalize selected candidate string from CCandidateListUIPresenter DWORD_PTR candidateLen = 0; const WCHAR *pCandidateString = nullptr; candidateLen = _pCandidateListUIPresenter->_GetSelectedCandidateString(&pCandidateString); CStringRange candidateString; candidateString.Set(pCandidateString, candidateLen); if (candidateLen) { // Finalize character hr = _AddCharAndFinalize(ec, pContext, &candidateString); if (FAILED(hr)) { return hr; } } } else { // Finalize current text store strings if (_IsComposing()) { ULONG fetched = 0; TF_SELECTION tfSelection; if (FAILED(pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &fetched)) || fetched != 1) { return S_FALSE; } ITfRange* pRangeComposition = nullptr; if (SUCCEEDED(_pComposition->GetRange(&pRangeComposition))) { if (_IsRangeCovered(ec, tfSelection.range, pRangeComposition)) { _EndComposition(pContext); } pRangeComposition->Release(); } tfSelection.range->Release(); } } _HandleCancel(ec, pContext); return S_OK; }
BOOL CTextService::_IsKeyEaten(ITfContext *pContext, WPARAM wParam) { // if the keyboard is disabled, keys are not consumed. if (_IsKeyboardDisabled()) return FALSE; // if the keyboard is closed, keys are not consumed. if (!_IsKeyboardOpen()) return FALSE; // // The text service key handler does not do anything while the candidate // window is shown. // The candidate list handles the keys through ITfContextKeyEventSink. // if (_pCandidateList && _pCandidateList->_IsContextCandidateWindow(pContext)) { return FALSE; } // eat only keys that CKeyHandlerEditSession can hadles. switch (wParam) { case VK_LEFT: case VK_RIGHT: case VK_RETURN: case VK_SPACE: case VK_BACK: if (_IsComposing()) return TRUE; return FALSE; case 0xC0: case 0xBD: case 0xBB: case 0xDB: case 0xDD: case 0xDC: case 0xBA: case 0xDE: case 0xBC: case 0xBE: case 0xBF: return TRUE; } if (GetKeyState(VK_MENU) & 0x8000) return FALSE; else if (GetKeyState(VK_CONTROL) & 0x8000) return FALSE; else if (wParam >= VK_NUMPAD0 && wParam <= VK_NUMPAD9) return FALSE; else if ( (wParam >= '0' && wParam <= '9') || (wParam >= 'A' && wParam <= 'Z') ) return TRUE; return FALSE; }
void CDIME::OnKeyboardClosed() { debugPrint(L"CDIME::OnKeyboardClosed()\n"); // switching to English (native) mode delete the phrase candidate window before exting. _isChinese = FALSE; if(_IsComposing()) { _EndComposition(_pContext); } _DeleteCandidateList(TRUE,_pContext); }
void CDIME::OnSwitchedToHalfShape() { debugPrint(L"CDIME::OnSwitchedToHalfShape()\n"); _isFullShape = FALSE; if(_IsComposing()) { _EndComposition(_pContext); } _DeleteCandidateList(TRUE,_pContext); if (CConfig::GetDoubleSingleByteMode() != DOUBLE_SINGLE_BYTE_SHIFT_SPACE) CConfig::SetDoubleSingleByteMode(DOUBLE_SINGLE_BYTE_ALWAYS_SINGLE); }
/* Update Composition */ void WeaselTSF::_UpdateComposition(ITfContext *pContext) { // get commit string from server std::wstring commit; weasel::Status status; weasel::Config config; auto context = std::make_shared<weasel::Context>(); weasel::ResponseParser parser(&commit, context.get(), &status, &config); bool ok = m_client.GetResponseData(std::ref(parser)); if (ok) { bool composing = _IsComposing(); if (!commit.empty()) { // 修复顶字上屏的吞字问题: // 顶字上屏(如五笔 4 码上屏时),当候选词数 > 1 时, // 第 5 码输入时会将首选项顶屏。 // 此时由于第五码的输入,composition 应是开启的,同时也要在输入处插入顶字。 // 这里先关闭上一个字的 composition,然后为后续输入开启一个新 composition。 // 有点 dirty 但是 it works ... if (composing) { _EndComposition(pContext); composing = false; } _InsertText(pContext, commit); } if (status.composing && !composing) { if (!_fCUASWorkaroundTested) { /* Test if we need to apply the workaround */ _UpdateCompositionWindow(pContext); } else if (!_fCUASWorkaroundEnabled || config.inline_preedit) { /* Workaround not applied, update candidate window position at this point. */ _UpdateCompositionWindow(pContext); } _StartComposition(pContext, _fCUASWorkaroundEnabled && !config.inline_preedit); } else if (!status.composing && composing) { _EndComposition(pContext); composing = false; } if (composing && config.inline_preedit) _ShowInlinePreedit(pContext, context); } }
HRESULT CDIME::_ProbeCompositionRangeNotification(_In_ TfEditCookie ec, _In_ ITfContext *pContext) { debugPrint(L"CDIME::_ProbeCompositionRangeNotification(), \n"); HRESULT hr = S_OK; if(!_IsComposing()) _StartComposition(pContext); hr = E_FAIL; ULONG fetched = 0; TF_SELECTION tfSelection; if ( pContext == nullptr || (hr = pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &fetched)) != S_OK || fetched != 1 ||tfSelection.range==nullptr) { _TerminateComposition(ec,pContext); return hr; } tfSelection.range->Release(); ITfRange *pRange; ITfContextView* pContextView; ITfDocumentMgr* pDocumgr; if (_pComposition&&SUCCEEDED(_pComposition->GetRange(&pRange)) && pRange) { if(pContext && SUCCEEDED(pContext->GetActiveView(&pContextView)) && pContextView) { if(pContext && SUCCEEDED( pContext->GetDocumentMgr(&pDocumgr)) && pDocumgr && _pThreadMgr &&_pUIPresenter) { ITfDocumentMgr* pFocusDocuMgr; _pThreadMgr->GetFocus(&pFocusDocuMgr); if(pFocusDocuMgr == pDocumgr) { _pUIPresenter->_StartLayout(pContext, ec, pRange); _pUIPresenter->_MoveUIWindowsToTextExt(); } else _pUIPresenter->ClearNotify(); pDocumgr->Release(); } pContextView->Release(); } pRange->Release(); } _TerminateComposition(ec,pContext); return hr; }
STDAPI CSampleIME::OnEndEdit(__RPC__in_opt ITfContext *pContext, TfEditCookie ecReadOnly, __RPC__in_opt ITfEditRecord *pEditRecord) { BOOL isSelectionChanged; // // did the selection change? // The selection change includes the movement of caret as well. // The caret position is represent as the empty selection range when // there is no selection. // if (pEditRecord == nullptr) { return E_INVALIDARG; } if (SUCCEEDED(pEditRecord->GetSelectionStatus(&isSelectionChanged)) && isSelectionChanged) { // If the selection is moved to out side of the current composition, // we terminate the composition. This TextService supports only one // composition in one context object. if (_IsComposing()) { TF_SELECTION tfSelection; ULONG fetched = 0; if (pContext == nullptr) { return E_INVALIDARG; } if (FAILED(pContext->GetSelection(ecReadOnly, TF_DEFAULT_SELECTION, 1, &tfSelection, &fetched)) || fetched != 1) { return S_FALSE; } ITfRange* pRangeComposition = nullptr; if (SUCCEEDED(_pComposition->GetRange(&pRangeComposition))) { if (!_IsRangeCovered(ecReadOnly, tfSelection.range, pRangeComposition)) { _EndComposition(pContext); } pRangeComposition->Release(); } tfSelection.range->Release(); } } return S_OK; }
void CTextService::_ClearCompositionDisplayAttributes(TfEditCookie ec, ITfContext *pContext) { ITfRange *pRange; if(_IsComposing() && _pComposition->GetRange(&pRange) == S_OK) { ITfProperty *pProperty; if(pContext->GetProperty(GUID_PROP_ATTRIBUTE, &pProperty) == S_OK) { pProperty->Clear(ec, pRange); SafeRelease(&pProperty); } SafeRelease(&pRange); } }
HRESULT COVTSF::_HandleCompositionInput(TfEditCookie ec, _In_ ITfContext *pContext, WCHAR wch) { ITfRange* pRangeComposition = nullptr; TF_SELECTION tfSelection; ULONG fetched = 0; BOOL isCovered = TRUE; CCompositionProcessorEngine* pCompositionProcessorEngine = nullptr; pCompositionProcessorEngine = _pCompositionProcessorEngine; if ((_pCandidateListUIPresenter != nullptr) && (_candidateMode != CANDIDATE_INCREMENTAL)) { _HandleCompositionFinalize(ec, pContext, FALSE); } // Start the new (std::nothrow) compositon if there is no composition. if (!_IsComposing()) { _StartComposition(pContext); } // first, test where a keystroke would go in the document if we did an insert if (pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &fetched) != S_OK || fetched != 1) { return S_FALSE; } // is the insertion point covered by a composition? if (SUCCEEDED(_pComposition->GetRange(&pRangeComposition))) { isCovered = _IsRangeCovered(ec, tfSelection.range, pRangeComposition); pRangeComposition->Release(); if (!isCovered) { goto Exit; } } // Add virtual key to composition processor engine pCompositionProcessorEngine->AddVirtualKey(wch); _HandleCompositionInputWorker(pCompositionProcessorEngine, ec, pContext); Exit: tfSelection.range->Release(); return S_OK; }
void CTextService::_ClearCompositionDisplayAttributes(TfEditCookie ec, ITfContext *pContext) { if(_IsComposing()) { ITfRange *pRange = nullptr; if(SUCCEEDED(_pComposition->GetRange(&pRange)) && (pRange != nullptr)) { ITfProperty *pProperty = nullptr; if(SUCCEEDED(pContext->GetProperty(GUID_PROP_ATTRIBUTE, &pProperty)) && (pProperty != nullptr)) { pProperty->Clear(ec, pRange); SafeRelease(&pProperty); } SafeRelease(&pRange); } } }
STDAPI CTextService::OnEndEdit(ITfContext *pic, TfEditCookie ecReadOnly, ITfEditRecord *pEditRecord) { if(_IsComposing() && pic != nullptr) { ITfRange *pRange = nullptr; if(SUCCEEDED(_pComposition->GetRange(&pRange)) && (pRange != nullptr)) { // clear when auto completion BOOL fEmpty = FALSE; if(SUCCEEDED(pRange->IsEmpty(ecReadOnly, &fEmpty)) && fEmpty) { if(!roman.empty() || !kana.empty()) { _ResetStatus(); _EndComposition(pic); } } // reposition candidate window if(_pCandidateList != nullptr) { ITfContextView *pContextView = nullptr; if(SUCCEEDED(pic->GetActiveView(&pContextView)) && (pContextView != nullptr)) { RECT rc = {}; BOOL fClipped; if(SUCCEEDED(pContextView->GetTextExt(ecReadOnly, pRange, &rc, &fClipped))) { _pCandidateList->_Move(&rc, ecReadOnly, pic); } SafeRelease(&pContextView); } } SafeRelease(&pRange); } } return S_OK; }
void CTextService::_UpdateLanguageBar(BOOL showinputmode) { if(_pLangBarItem != nullptr) { _pLangBarItem->_Update(); } if(_pLangBarItemI != nullptr) { _pLangBarItemI->_Update(); } if(showinputmode && _ShowInputMode && !_IsComposing()) { _StartInputModeWindow(); } else { _EndInputModeWindow(); } }
BOOL CTextService::_IsKeyEaten(ITfContext *pContext, WPARAM wParam) { // if the keyboard is disabled, we don't eat keys. if (_IsKeyboardDisabled()) return FALSE; // if the keyboard is closed, we don't eat keys. if (!_IsKeyboardOpen()) return FALSE; // // The text service key handler does not do anything while the candidate // window is shown. // The candidate list handles the keys through ITfContextKeyEventSink. // if (_pCandidateList && _pCandidateList->_IsContextCandidateWindow(pContext)) { return FALSE; } // eat only keys that CKeyHandlerEditSession can hadles. switch (wParam) { case VK_LEFT: case VK_RIGHT: case VK_RETURN: case VK_SPACE: if (_IsComposing()) return TRUE; return FALSE; } if (wParam >= 'A' && wParam <= 'Z') return TRUE; return FALSE; }
HRESULT CTextService::_HandleCharShift(TfEditCookie ec, ITfContext *pContext) { if(showentry || (!inputkey && !kana.empty() && roman.empty())) { _EndCompletionList(ec, pContext); //leave composition cursoridx = kana.size(); _Update(ec, pContext, TRUE); if(pContext != NULL) { ITfRange *pRange; if(_IsComposing() && _pComposition->GetRange(&pRange) == S_OK) { pRange->Collapse(ec, TF_ANCHOR_END); _pComposition->ShiftStart(ec, pRange); SafeRelease(&pRange); } } _ResetStatus(); } return S_OK; }
int CTextService::_IsKeyEaten(ITfContext *pContext, WPARAM wParam, LPARAM lParam, bool isKeyDown, bool isTest) { if(_IsKeyboardDisabled()) { return FALSE; } if(!_IsKeyboardOpen()) { return FALSE; } //カーソル直前文字列削除をBSを送って消す場合のDeleter用処理。 //(TSFによるカーソル直前文字列削除ができなかった場合用。) //mozcのwin32/tip/tip_keyevent_handler.ccから。 bool is_key_down = isKeyDown; if(isTest) { const mozc::win32::LParamKeyInfo key_info(lParam); is_key_down = key_info.IsKeyDownInImeProcessKey(); } const mozc::win32::VKBackBasedDeleter::ClientAction vk_back_action = deleter.OnKeyEvent(wParam, is_key_down, isTest); switch(vk_back_action) { case mozc::win32::VKBackBasedDeleter::DO_DEFAULT_ACTION: // do nothing. break; case mozc::win32::VKBackBasedDeleter::CALL_END_DELETION_THEN_DO_DEFAULT_ACTION: deleter.EndDeletion(); break; case mozc::win32::VKBackBasedDeleter::SEND_KEY_TO_APPLICATION: if(is_key_down && isTest && !postbuf.empty()) { postbuf.pop_back(); } return FALSE; // Do not consume this key. case mozc::win32::VKBackBasedDeleter::CONSUME_KEY_BUT_NEVER_SEND_TO_SERVER: return -1; // Consume this key but do not send this key to server. case mozc::win32::VKBackBasedDeleter::CALL_END_DELETION_BUT_NEVER_SEND_TO_SERVER: if(!isTest) { deleter.EndDeletion(); return -1; } else { return FALSE; } case mozc::win32::VKBackBasedDeleter::APPLY_PENDING_STATUS: if(!isTest) { _InvokeKeyHandler(pContext, wParam, lParam, SKK_AFTER_DELETER); return -1; } else { return FALSE; } default: break; } if(_pCandidateList && _pCandidateList->_IsContextCandidateWindow(pContext)) { return FALSE; } if(_IsComposing() || !cx_showromancomp && !roman.empty()) { if(inputmode != im_ascii) { return TRUE; } } SHORT vk_ctrl = GetKeyState(VK_CONTROL) & 0x8000; SHORT vk_kana = GetKeyState(VK_KANA) & 0x0001; WCHAR ch = _GetCh((BYTE)wParam); BYTE sf = _GetSf((BYTE)wParam, ch); //確定状態で処理する機能 switch(inputmode) { case im_jlatin: case im_ascii: switch(sf) { case SKK_JMODE: case SKK_OTHERIME: return TRUE; break; default: break; } break; case im_hiragana: case im_katakana: switch(sf) { case SKK_CONV_POINT: case SKK_KANA: case SKK_CONV_CHAR: case SKK_JLATIN: case SKK_ASCII: case SKK_ABBREV: case SKK_OTHERIME: return TRUE; break; case SKK_VIESC: inputmode = im_ascii; _UpdateLanguageBar(); postbuf.clear(); return FALSE; break; default: break; } break; case im_katakana_ank: switch(sf) { case SKK_KANA: case SKK_CONV_CHAR: case SKK_JLATIN: case SKK_ASCII: case SKK_OTHERIME: return TRUE; break; case SKK_VIESC: inputmode = im_ascii; _UpdateLanguageBar(); postbuf.clear(); return FALSE; default: break; } break; default: break; } //無効 if(_IsKeyVoid(ch, (BYTE)wParam)) { return TRUE; } //処理しないCtrlキー if(vk_ctrl != 0) { postbuf.clear(); return FALSE; } //ASCIIモード、かなキーロックOFF if(inputmode == im_ascii && vk_kana == 0) { return FALSE; } if(ch >= L'\x20') { return TRUE; } if(!postbuf.empty()) { if((wParam == VK_BACK || wParam == VK_LEFT) && is_key_down && isTest) { postbuf.pop_back(); } else { switch(wParam) { //case VK_LEFT: case VK_RIGHT: case VK_UP: case VK_DOWN: case VK_HOME: case VK_END: case VK_PRIOR: case VK_NEXT: if(is_key_down && isTest) { postbuf.clear(); } break; default: break; } } } return FALSE; }
HRESULT CTextService::_HandleKey(TfEditCookie ec, ITfContext *pContext, WPARAM wParam) { /* * FIXME: the following keys are not handled: * shift left VK_LSHIFT * shift right VK_RSHIFT * caps lock VK_CAPITAL * page up VK_PRIOR * page down VK_NEXT * ctrl num * shift space * numlock num VK_NUMLOCK */ if (('A' <= wParam && wParam <= 'Z')) { chewing_handle_Default(mChewingContext, wParam - 'A' + 'a'); } else if ('0' <= wParam && wParam <= '9') { chewing_handle_Default(mChewingContext, wParam); } else { switch(wParam) { case VK_OEM_COMMA: chewing_handle_Default(mChewingContext, ','); break; case VK_OEM_MINUS: chewing_handle_Default(mChewingContext, '-'); break; case VK_OEM_PERIOD: chewing_handle_Default(mChewingContext, '.'); break; case VK_OEM_1: chewing_handle_Default(mChewingContext, ';'); break; case VK_OEM_2: chewing_handle_Default(mChewingContext, '/'); break; case VK_OEM_3: chewing_handle_Default(mChewingContext, '`'); break; case VK_SPACE: chewing_handle_Space(mChewingContext); break; case VK_ESCAPE: chewing_handle_Esc(mChewingContext); break; case VK_RETURN: chewing_handle_Enter(mChewingContext); break; case VK_DELETE: chewing_handle_Del(mChewingContext); break; case VK_BACK: chewing_handle_Backspace(mChewingContext); break; case VK_UP: chewing_handle_Up(mChewingContext); break; case VK_DOWN: chewing_handle_Down(mChewingContext); case VK_LEFT: chewing_handle_Left(mChewingContext); break; case VK_RIGHT: chewing_handle_Right(mChewingContext); break; case VK_HOME: chewing_handle_Home(mChewingContext); break; case VK_END: chewing_handle_End(mChewingContext); break; default: return S_OK; } } // Remove old candidate list. We will create a new one if necessary. _pCandidateList->_EndCandidateList(); ChewingCandidates candidate(mChewingContext); if (!candidate.IsEmpty()) { _SetCompositionDisplayAttributes(ec, pContext, _gaDisplayAttributeConverted); // // The document manager object is not cached. Get it from pContext. // ITfDocumentMgr *pDocumentMgr; if (pContext->GetDocumentMgr(&pDocumentMgr) == S_OK) { // // get the composition range. // ITfRange *pRange; if (_pComposition->GetRange(&pRange) == S_OK) { _pCandidateList->_StartCandidateList(_tfClientId, pDocumentMgr, pContext, ec, pRange, candidate); pRange->Release(); } pDocumentMgr->Release(); } return S_OK; } ChewingString commit(mChewingContext, CHEWING_STRING_COMMIT); if (!commit.IsEmpty()) { // FIXME: Need a better way to submit a string if (!_IsComposing()) _StartComposition(pContext); ULONG cFetched; BOOL fCovered; TF_SELECTION tfSelection; // FIXME: Why we need this here? // first, test where a keystroke would go in the document if an insert is done if (pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) != S_OK || cFetched != 1) return S_FALSE; // FIXME: Why we need this here? // is the insertion point covered by a composition? ITfRange *pRangeComposition; if (_pComposition->GetRange(&pRangeComposition) == S_OK) { fCovered = IsRangeCovered(ec, tfSelection.range, pRangeComposition); pRangeComposition->Release(); if (!fCovered) { goto End3; } } if (tfSelection.range->SetText(ec, 0, commit.GetString(), commit.GetLength()) != S_OK) goto End3; _TerminateComposition(ec, pContext); End3: // FIXME: RAII? tfSelection.range->Release(); } /* * Composition is mapped to preedit buffer + zuin buffer */ ChewingString preedit_zuin(mChewingContext, CHEWING_STRING_PREEDIT_ZUIN); if (preedit_zuin.IsEmpty()) { // Remove composition if (_IsComposing()) { ULONG cFetched; BOOL fCovered; TF_SELECTION tfSelection; // FIXME: Why we need this here? // first, test where a keystroke would go in the document if an insert is done if (pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) != S_OK || cFetched != 1) return S_FALSE; // FIXME: Why we need this here? // is the insertion point covered by a composition? ITfRange *pRangeComposition; if (_pComposition->GetRange(&pRangeComposition) == S_OK) { fCovered = IsRangeCovered(ec, tfSelection.range, pRangeComposition); pRangeComposition->Release(); if (!fCovered) { goto End; } } // Empties the composition tfSelection.range->SetText(ec, 0, L"", 0); _TerminateComposition(ec, pContext); End: // FIXME: RAII? tfSelection.range->Release(); } } else { if (!_IsComposing()) _StartComposition(pContext); ULONG cFetched; BOOL fCovered; TF_SELECTION tfSelection; // FIXME: Why we need this here? // first, test where a keystroke would go in the document if an insert is done if (pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) != S_OK || cFetched != 1) return S_FALSE; // FIXME: Why we need this here? // is the insertion point covered by a composition? ITfRange *pRangeComposition; if (_pComposition->GetRange(&pRangeComposition) == S_OK) { fCovered = IsRangeCovered(ec, tfSelection.range, pRangeComposition); pRangeComposition->Release(); if (!fCovered) { goto End2; } } if (tfSelection.range->SetText(ec, 0, preedit_zuin.GetString(), preedit_zuin.GetLength()) != S_OK) goto End2; _SetCompositionDisplayAttributes(ec, pContext, _gaDisplayAttributeInput); End2: // FIXME: RAII? tfSelection.range->Release(); } return S_OK; }
BOOL CTextService::_IsKeyEaten(ITfContext *pContext, WPARAM wParam) { if(_IsKeyboardDisabled()) { return FALSE; } if(!_IsKeyboardOpen()) { return FALSE; } if(_pCandidateList && _pCandidateList->_IsContextCandidateWindow(pContext)) { return FALSE; } if(_IsComposing()) { if(inputmode != im_ascii && !_pInputModeWindow) { return TRUE; } } SHORT vk_ctrl = GetKeyState(VK_CONTROL) & 0x8000; SHORT vk_kana = GetKeyState(VK_KANA) & 0x0001; WCHAR ch = _GetCh((BYTE)wParam); BYTE sf = _GetSf((BYTE)wParam, ch); //確定状態で処理する機能 switch(inputmode) { case im_jlatin: case im_ascii: switch(sf) { case SKK_JMODE: return TRUE; break; default: break; } break; case im_hiragana: case im_katakana: switch(sf) { case SKK_CONV_POINT: case SKK_KANA: case SKK_CONV_CHAR: case SKK_JLATIN: case SKK_ASCII: case SKK_ABBREV: return TRUE; break; default: break; } break; case im_katakana_ank: switch(sf) { case SKK_KANA: case SKK_CONV_CHAR: case SKK_JLATIN: case SKK_ASCII: return TRUE; break; default: break; } break; default: break; } //無効 if(_IsKeyVoid(ch, (BYTE)wParam)) { return TRUE; } //処理しないCtrlキー if(vk_ctrl) { return FALSE; } //ASCIIモード、かなキーロック if(inputmode == im_ascii && !vk_kana) { return FALSE; } if(ch >= L'\x20') { return TRUE; } return FALSE; }
HRESULT CTextService::_SetText(TfEditCookie ec, ITfContext *pContext, const std::wstring &text, LONG cchCursor, LONG cchOkuri, BOOL fixed) { TF_SELECTION tfSelection; ULONG cFetched = 0; LONG cch, cchRes; if(pContext == NULL && _pCandidateList != NULL) //辞書登録用 { _pCandidateList->_SetText(text, fixed, FALSE, FALSE); return S_OK; } if(!_IsComposing()) { if(!_StartComposition(pContext)) { return S_FALSE; } } if(pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) != S_OK) { return S_FALSE; } if(cFetched != 1) { SafeRelease(&tfSelection.range); return S_FALSE; } ITfRange *pRange; if(_IsComposing() && _pComposition->GetRange(&pRange) == S_OK) { if(_IsRangeCovered(ec, tfSelection.range, pRange)) { pRange->SetText(ec, 0, text.c_str(), (LONG)text.size()); // shift from end to start. // shift over mathematical operators (U+2200-U+22FF) is rejected by OneNote. if(cchCursor == 0) { cchRes = (LONG)cursoridx - (LONG)kana.size(); if((complement && okuriidx != 0) || (!cx_showmodemark && okuriidx != 0 && cursoridx <= okuriidx && cursoridx < kana.size())) { cchRes += 1; } } else { cchRes = cchCursor - (LONG)text.size(); if(cchRes > 0) { cchRes = 0; } else if(cchRes < -(LONG)text.size()) { cchRes = -(LONG)text.size(); } } tfSelection.range->ShiftEndToRange(ec, pRange, TF_ANCHOR_END); tfSelection.range->ShiftStartToRange(ec, pRange, TF_ANCHOR_END); tfSelection.range->ShiftStart(ec, cchRes, &cch, NULL); //decide cursor position tfSelection.range->Collapse(ec, TF_ANCHOR_START); pContext->SetSelection(ec, 1, &tfSelection); //composition attribute if(!fixed) { ITfRange *pRangeClone; if(pRange->Clone(&pRangeClone) == S_OK) { pRangeClone->ShiftEndToRange(ec, pRange, TF_ANCHOR_END); pRangeClone->ShiftStartToRange(ec, pRange, TF_ANCHOR_START); if(cchCursor == 0 || !showentry) { if(inputkey) { _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeInputMark); if(cx_showmodemark) { pRangeClone->ShiftStart(ec, 1, &cch, NULL); } } if(!display_attribute_series[1] || !inputkey) { _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeInputText); } if(cchOkuri != 0) { pRangeClone->ShiftStartToRange(ec, pRange, TF_ANCHOR_START); pRangeClone->ShiftStart(ec, cchOkuri, &cch, NULL); if(!display_attribute_series[2]) { _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeInputOkuri); } if(hintmode && text.find_first_of(CHAR_SKK_HINT) != std::wstring::npos) { LONG hintpos = (LONG)text.find_first_of(CHAR_SKK_HINT); if(cchOkuri < hintpos) { pRangeClone->ShiftStartToRange(ec, pRange, TF_ANCHOR_START); pRangeClone->ShiftStart(ec, hintpos, &cch, NULL); _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeInputText); } } } } else { _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeConvMark); if(cx_showmodemark) { pRangeClone->ShiftStart(ec, 1, &cch, NULL); } if(!display_attribute_series[4]) { _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeConvText); } if(cchOkuri != 0) { pRangeClone->ShiftStartToRange(ec, pRange, TF_ANCHOR_START); pRangeClone->ShiftStart(ec, cchOkuri, &cch, NULL); if(!display_attribute_series[5]) { _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeConvOkuri); } } pRangeClone->ShiftEndToRange(ec, pRange, TF_ANCHOR_END); pRangeClone->ShiftStartToRange(ec, tfSelection.range, TF_ANCHOR_END); if(!display_attribute_series[6]) { _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeConvAnnot); } } SafeRelease(&pRangeClone); } } // for Excel's PHONETIC function if(fixed && !text.empty()) { ITfProperty *pProperty; if(pContext->GetProperty(GUID_PROP_READING, &pProperty) == S_OK) { VARIANT var; var.vt = VT_BSTR; std::wstring phone(kana); if(okuriidx == 0) { switch(inputmode) { case im_hiragana: case im_katakana: case im_katakana_ank: //接辞 if(!abbrevmode && kana.size() >= 2) { if(kana.front() == L'>') { phone = kana.substr(1); } else if(kana.back() == L'>') { phone = kana.substr(0, kana.size() - 1); } } break; default: break; } } else { if(kana.size() > (okuriidx + 1)) { phone = kana.substr(0, okuriidx) + kana.substr(okuriidx + 1); } else if(kana.size() >= okuriidx) { phone = kana.substr(0, okuriidx); } } if(!phone.empty()) { var.bstrVal = SysAllocString(phone.c_str()); pProperty->SetValue(ec, pRange, &var); SysFreeString(var.bstrVal); } SafeRelease(&pProperty); } } } SafeRelease(&pRange); } SafeRelease(&tfSelection.range); return S_OK; }
HRESULT CDIME::_HandleCandidateWorker(TfEditCookie ec, _In_ ITfContext *pContext) { debugPrint(L"CDIME::_HandleCandidateWorker() \n"); HRESULT hr = S_OK; CStringRange commitString, convertedString; CDIMEArray<CCandidateListItem> candidatePhraseList; CStringRange lastChar; CStringRange notify; if (nullptr == _pUIPresenter) { goto Exit; //should not happen } const WCHAR* pCandidateString = nullptr; DWORD_PTR candidateLen = 0; BOOL arrayUsingSPCode =FALSE; if (!_IsComposing()) _StartComposition(pContext); if (Global::imeMode == IME_MODE_ARRAY)// check if the _strokebuffer is array special code { candidateLen = _pCompositionProcessorEngine->CollectWordFromArraySpeicalCode(&pCandidateString); if(candidateLen) arrayUsingSPCode = TRUE; } candidateLen = 0; candidateLen = _pUIPresenter->_GetSelectedCandidateString(&pCandidateString); if (candidateLen == 0) { if(_candidateMode == CANDIDATE_WITH_NEXT_COMPOSITION || _candidateMode == CANDIDATE_PHRASE) { _HandleCancel(ec, pContext); goto Exit; } else { hr = S_FALSE; _HandleCancel(ec, pContext); DoBeep(BEEP_COMPOSITION_ERROR); //beep for no valid mapping found goto Exit; } } if (_pCompositionProcessorEngine->IsArrayShortCode() && candidateLen == 1 && *pCandidateString == 0x2394) // empty position in arry short code table. { hr = S_FALSE; if (Global::imeMode == IME_MODE_PHONETIC) DoBeep(BEEP_WARNING); else { if (CConfig::GetClearOnBeep()) _HandleCancel(ec, pContext); DoBeep(BEEP_COMPOSITION_ERROR); //beep for no valid mapping found } goto Exit; } StringCchCopy(_commitString, 1, L"\0"); StringCchCatN(_commitString, MAX_COMMIT_LENGTH, pCandidateString, candidateLen); commitString.Set(_commitString, candidateLen); //_commitString = commitString; PWCHAR pwch = new (std::nothrow) WCHAR[2]; // pCandidateString will be destroyed after _detelteCanddiateList was called. if(candidateLen > 1) { StringCchCopyN(pwch, 2, pCandidateString + candidateLen -1, 1); }else // cnadidateLen ==1 { StringCchCopyN(pwch, 2, pCandidateString, 1); } lastChar.Set(pwch, 1 ); //-----------------do reverse conversion notify. We should not show notify in UI-less mode, thus cancel reverse conversion notify in UILess Mode if (!_IsUILessMode()) { if (_pITfReverseConversion[Global::imeMode]) { _AsyncReverseConversion(pContext); //asynchronized the reverse conversion with editsession for better perfomance } //-----------------or complete real key code when input with wildcard else if (_isCandidateWithWildcard) { const WCHAR* pCandidateKeyCode = nullptr; DWORD_PTR keyCodeLen = _pUIPresenter->_GetSelectedCandidateKeyCode(&pCandidateKeyCode); StringCchCopy(_commitKeyCode, 1, L"\0"); StringCchCatN(_commitKeyCode, MAX_KEY_LENGTH, pCandidateKeyCode, keyCodeLen); CStringRange commitKeyCode, convertedKeyCode; _pCompositionProcessorEngine->GetReadingString(&convertedKeyCode, NULL, &commitKeyCode.Set(_commitKeyCode, wcslen(_commitKeyCode))); _pUIPresenter->ShowNotifyText(&convertedKeyCode); } } //-----------------do array spcial code notify. We should not show notify in UI-less mode, thus cancel forceSP mode in UILess Mode--- BOOL ArraySPFound = FALSE; if(Global::imeMode == IME_MODE_ARRAY && !_IsUILessMode() && !arrayUsingSPCode && (CConfig::GetArrayForceSP() || CConfig::GetArrayNotifySP())) { CStringRange specialCode; CStringRange notifyText; ArraySPFound = _pCompositionProcessorEngine->GetArraySpeicalCodeFromConvertedText(&commitString, &specialCode); if(specialCode.Get()) _pUIPresenter->ShowNotifyText(&specialCode); } convertedString = commitString; //----------------- do TC to SC covert if required---------------------------------------------------------------------------------- if(CConfig::GetDoHanConvert()) { _pCompositionProcessorEngine->GetSCFromTC(&commitString, &convertedString); } //----------------- commit the selected string ------------------------------------------------------------------------------------ if(Global::imeMode == IME_MODE_ARRAY && !_IsUILessMode() && !arrayUsingSPCode && CConfig::GetArrayForceSP() && ArraySPFound ) { _HandleCancel(ec, pContext); DoBeep(BEEP_WARNING); return hr; } else { hr = _AddComposingAndChar(ec, pContext, &convertedString); if (FAILED(hr)) return hr; // Do not send _endcandidatelist (or handleComplete) here to avoid cand dissapear in win8 metro _HandleComplete(ec,pContext); } //-----------------do accociated phrase (make phrase)-------------------------------------------------------------------------------- if (CConfig::GetMakePhrase()) { _pCompositionProcessorEngine->GetCandidateStringInConverted(lastChar, &candidatePhraseList); // We have a candidate list if candidatePhraseList.Cnt is not 0 // If we are showing reverse conversion, use UIPresenter if (candidatePhraseList.Count()) { CStringRange emptyComposition; if (!_IsComposing()) _StartComposition(pContext); //StartCandidateList require a valid selection from a valid pComposition to determine the location to show the candidate window _AddComposingAndChar(ec, pContext, &emptyComposition.Set(L" ",1)); _pUIPresenter->_ClearCandidateList(); _pUIPresenter->_SetCandidateTextColor(CConfig::GetPhraseColor(), CConfig::GetItemBGColor()); // Text color is green _pUIPresenter->_SetCandidateSelectedTextColor(CConfig::GetSelectedColor(), CConfig::GetSelectedBGColor()); _pUIPresenter->_SetCandidateNumberColor(CConfig::GetNumberColor(), CConfig::GetItemBGColor()); _pUIPresenter->_SetCandidateFillColor(CConfig::GetItemBGColor());//(HBRUSH)(COLOR_WINDOW+1)); // Background color is window _pUIPresenter->_SetCandidateText(&candidatePhraseList, _pCompositionProcessorEngine->GetCandidateListIndexRange(), TRUE, _pCompositionProcessorEngine->GetCandidateWindowWidth()); _pUIPresenter->_SetCandidateSelection(-1, FALSE); // set selected index to -1 if showing phrase candidates _candidateMode = CANDIDATE_PHRASE; _isCandidateWithWildcard = FALSE; } else { //cancel the composition if the phrase lookup return 0 results _HandleCancel(ec,pContext); } } else _DeleteCandidateList(TRUE, pContext); // endCanddiateUI if not doing associated phrase. Exit: return hr; }
BOOL CTextService::_IsKeyEaten(ITfContext *pContext, WPARAM wParam) { if(_IsKeyboardDisabled()) { return FALSE; } if(!_IsKeyboardOpen()) { return FALSE; } if(_pCandidateList && _pCandidateList->_IsContextCandidateWindow(pContext)) { return FALSE; } if(_IsComposing()) { return TRUE; } SHORT vk_ctrl = GetKeyState(VK_CONTROL) & 0x8000; SHORT vk_kana = GetKeyState(VK_KANA) & 0x0001; WCHAR ch = _GetCh((BYTE)wParam); BYTE sf = _GetSf((BYTE)wParam, ch); //確定状態で処理する機能 switch(inputmode) { case im_hiragana: switch(sf) { case SKK_CONV_POINT: return TRUE; break; default: break; } break; default: break; } //無効 if(_IsKeyVoid(ch, (BYTE)wParam)) { return TRUE; } //処理しないCtrlキー if(vk_ctrl != 0) { return FALSE; } if(ch >= L'\x20') { return TRUE; } return FALSE; }