void CTextService::_EndCompletionList(TfEditCookie ec, ITfContext *pContext) { if(pContext != NULL && !showcandlist) { _EndCandidateList(); } }
HRESULT CCandidateListUIPresenter::_StartCandidateList(TfClientId tfClientId, _In_ ITfDocumentMgr *pDocumentMgr, _In_ ITfContext *pContextDocument, TfEditCookie ec, _In_ ITfRange *pRangeComposition, UINT wndWidth) { pDocumentMgr;tfClientId; HRESULT hr = E_FAIL; if (FAILED(_StartLayout(pContextDocument, ec, pRangeComposition))) { goto Exit; } BeginUIElement(); hr = MakeCandidateWindow(pContextDocument, wndWidth); if (FAILED(hr)) { goto Exit; } Show(_isShowMode); RECT rcTextExt; if (SUCCEEDED(_GetTextExt(&rcTextExt))) { _LayoutChangeNotification(&rcTextExt); } Exit: if (FAILED(hr)) { _EndCandidateList(); } return hr; }
STDAPI CCandidateList::OnLayoutChange(ITfContext *pContext, TfLayoutCode lcode, ITfContextView *pContextView){ if (pContext != _pContextDocument) return S_OK; switch (lcode){ case TF_LC_CHANGE: if (_pCandidateWindow != NULL) { CGetTextExtentEditSession *pEditSession; if ((pEditSession = new CGetTextExtentEditSession(_pTextService, pContext, pContextView, _pRangeComposition, _pCandidateWindow)) != NULL) { HRESULT hr; // a lock is required // nb: this method is one of the few places where it is legal to use // the TF_ES_SYNC flag pContext->RequestEditSession(_pTextService->_GetClientId(), pEditSession, TF_ES_SYNC | TF_ES_READ, &hr); pEditSession->Release(); } } break; case TF_LC_DESTROY: _EndCandidateList(); break; } return S_OK; }
CCandidateList::~CCandidateList() { _EndCandidateList(); SafeRelease(&_pTextService); DllRelease(); }
STDAPI CCandidateList::OnKeyUp(WPARAM wParam, LPARAM lParam, BOOL *pfEaten){ if (pfEaten == NULL) return E_INVALIDARG; //*pfEaten = TRUE; // consume VK_RETURN here to finish candidate list. switch(wParam){ case VK_SPACE: case VK_RETURN: _EndCandidateList(); break; default: _pCandidateWindow->_OnKeyUp((UINT)wParam); } return S_OK; }
STDAPI CCandidateList::OnLayoutChange(ITfContext *pContext, TfLayoutCode lcode, ITfContextView *pContextView) { HRESULT hr; if(pContext != _pContextDocument) { return S_OK; } switch(lcode) { case TF_LC_CREATE: break; case TF_LC_CHANGE: if(_pCandidateWindow != NULL) { try { CCandidateListGetTextExtEditSession *pEditSession = new CCandidateListGetTextExtEditSession(_pTextService, pContext, pContextView, _pRangeComposition, _pCandidateWindow); pContext->RequestEditSession(_pTextService->_GetClientId(), pEditSession, TF_ES_SYNC | TF_ES_READ, &hr); SafeRelease(&pEditSession); } catch(...) { } } break; case TF_LC_DESTROY: _EndCandidateList(); break; default: break; } return S_OK; }
STDAPI CTextService::Deactivate() { if(_pThreadMgr == nullptr) { return S_OK; } _SaveUserDic(); _EndCandidateList(); _EndInputModeWindow(); _UninitFunctionProvider(); _UninitPreservedKey(0); _UninitPreservedKey(1); _UninitKeyEventSink(); _UninitLanguageBar(); _InitTextEditSink(nullptr); _UninitCompartmentEventSink(); _UninitThreadFocusSink(); _UninitThreadMgrEventSink(); _UninitD2D(); SafeRelease(&_pThreadMgr); _ClientId = TF_CLIENTID_NULL; return S_OK; }
CCandidateList::~CCandidateList() { _EndCandidateList(); DllRelease(); }
HRESULT CCandidateList::_StartCandidateList(TfClientId tfClientId, ITfDocumentMgr *pDocumentMgr, ITfContext *pContextDocument, TfEditCookie ec, ITfRange *pRangeComposition){ TfEditCookie ecTmp; HRESULT hr = E_FAIL; BOOL fClipped; // clear the previous candidate list. // only one candidate window is supported. _EndCandidateList(); // create a new context on the document manager object for // the candidate ui. if (FAILED(pDocumentMgr->CreateContext(tfClientId, 0, NULL, &_pContextCandidateWindow, &ecTmp))) return E_FAIL; // push the new context. if (FAILED(pDocumentMgr->Push(_pContextCandidateWindow))) goto Exit; _pDocumentMgr = pDocumentMgr; _pDocumentMgr->AddRef(); _pContextDocument = pContextDocument; _pContextDocument->AddRef(); _pRangeComposition = pRangeComposition; _pRangeComposition->AddRef(); // advise ITfContextKeyEventSink to the new context. if (FAILED(_AdviseContextKeyEventSink())) goto Exit; // advise ITfTextLayoutSink to the document context. if (FAILED(_AdviseTextLayoutSink())) goto Exit; //ÉêÇ뻺³åÇø int cchMax = 10; wchar_t *pchText = new wchar_t[cchMax]; //»ñµÃÊäÈë×Ö·û ULONG pcch = 0; if(_pRangeComposition->GetText(ec, NULL, pchText, cchMax, &pcch) == S_OK){ pchText[pcch] = 0; } //²éѯºòÑ¡×Ö if(!CandidateTree->ForwardTo(pchText[pcch - 1])){ _pRangeComposition->Collapse(ec, TF_ANCHOR_END); _pTextService->_TerminateComposition(ec, _pContextDocument); }else{ CCandidateTree::Node *node = CandidateTree->GetCurrent(); if(node != NULL){ //ÏÔʾ/ÊäÈëºòÑ¡×Ö if(node->IsEnd()){ _InputDefaultCandidate(ec); // create an instance of CCandidateWindow class. }else if(_pCandidateWindow = new CCandidateWindow()){ RECT rc; ITfContextView *pContextView; // get an active view of the document context. if (FAILED(pContextDocument->GetActiveView(&pContextView))) goto Exit; // get text extent for the range of the composition. if (FAILED(pContextView->GetTextExt(ec, pRangeComposition, &rc, &fClipped))) goto Exit; pContextView->Release(); // create the dummy candidate window if (!_pCandidateWindow->_Create()) goto Exit; _pCandidateWindow->_Move(rc.left, rc.bottom); _pCandidateWindow->_Show(); hr = S_OK; } } } //ÊÍ·Å»º³åÇø delete[] pchText; Exit: if (FAILED(hr)) { _EndCandidateList(); } return hr; }
void CCandidateWindow::_OnKeyDownRegword(UINT uVKey) { WCHAR ch; BYTE sf; _GetChSf(uVKey, ch, sf); //確定していないとき if(!regwordfixed) { _pTextService->showcandlist = FALSE; //候補一覧表示をループさせる _HandleKey((WPARAM)uVKey, SKK_NULL); _Update(); if(_pInputModeWindow != NULL) { _pInputModeWindow->_Redraw(); } return; } if(_pTextService->_IsKeyVoid(ch, (BYTE)uVKey)) { _pTextService->_UpdateLanguageBar(); if(_pInputModeWindow != NULL) { _pInputModeWindow->_Redraw(); } if(sf == SKK_ENTER) { return; } } switch(sf) { case SKK_ENTER: _RestoreStatusReg(); _ClearStatusReg(); regwordfixed = FALSE; regwordul = FALSE; regword = FALSE; //スペースのみのとき空として扱う if(std::regex_match(regwordtext, std::wregex(L"^\\s+$"))) { regwordtext.clear(); } if(regwordtext.empty()) //空のときはキャンセル扱い { regwordtext.clear(); regwordtextpos = 0; if(!_reg) { _InitList(); _uIndex = _PageIndex[_PageIndex.size() - 1]; _Update(); _UpdateUIElement(); if(_pInputModeWindow != NULL) { _pInputModeWindow->_Show(FALSE); } } else { if(_pCandidateWindowParent == NULL) { if(_pTextService->candidates.empty()) { _EndCandidateList(SKK_CANCEL); } else { _EndCandidateList(SKK_PREV_CAND); } } else { _PreEndReq(); if(_pTextService->candidates.empty()) { _HandleKey(0, SKK_CANCEL); } else { _HandleKey(0, SKK_PREV_CAND); } _EndReq(); } } } else { std::wstring conv; std::wstring candidate; std::wstring annotation; std::wsmatch result; std::wstring okurikey; //候補と注釈を、行頭以外の最後のセミコロンで分割 if(std::regex_search(regwordtext, result, std::wregex(L".+;"))) { candidate = result.str().substr(0, result.str().size() - 1); annotation = result.suffix(); } else { candidate = regwordtext; annotation.clear(); } if(_pTextService->okuriidx != 0) { okurikey = _pTextService->kana.substr(_pTextService->okuriidx + 1); if(okurikey.size() >= 2 && IS_SURROGATE_PAIR(okurikey.c_str()[0], okurikey.c_str()[1])) { okurikey = okurikey.substr(0, 2); } else { okurikey = okurikey.substr(0, 1); } } //候補変換 _pTextService->_ConvertWord(REQ_CONVERTCND, _pTextService->searchkeyorg, candidate, okurikey, conv); if(_pTextService->searchkey.empty() || conv.empty()) { //変換見出し語が空文字列または //変換済み候補が空文字列であれば未変換見出し語を見出し語とする _pTextService->searchkey = _pTextService->searchkeyorg; } if(conv.empty()) { conv = candidate; } _pTextService->candidates.push_back(CANDIDATE (CANDIDATEBASE(conv, annotation), (CANDIDATEBASE(candidate, annotation)))); _pTextService->candidx = _pTextService->candidates.size() - 1; _pTextService->candorgcnt = 0; regwordtext.clear(); regwordtextpos = 0; if(_pCandidateWindowParent == NULL) { _EndCandidateList(SKK_ENTER); } else { _PreEndReq(); _HandleKey(0, SKK_ENTER); _EndReq(); } } break; case SKK_CANCEL: _RestoreStatusReg(); _ClearStatusReg(); regwordfixed = FALSE; regwordul = FALSE; regword = FALSE; regwordtext.clear(); regwordtextpos = 0; if(!_reg) { _InitList(); _uIndex = _PageIndex[_PageIndex.size() - 1]; _Update(); _UpdateUIElement(); if(_pInputModeWindow != NULL) { _pInputModeWindow->_Show(FALSE); } } else { if(_pCandidateWindowParent == NULL) { if(_pTextService->candidates.empty()) { _EndCandidateList(SKK_CANCEL); } else { _EndCandidateList(SKK_PREV_CAND); } } else { _PreEndReq(); if(_pTextService->candidates.empty()) { _HandleKey(0, SKK_CANCEL); } else { _HandleKey(0, SKK_PREV_CAND); } _EndReq(); } } break; case SKK_BACK: if(comptext.empty() && regwordtextpos > 0 && regwordtext.size() > 0) { // surrogate pair if(regwordtext.size() >= 2 && regwordtextpos >= 2 && IS_SURROGATE_PAIR(regwordtext[regwordtextpos - 2], regwordtext[regwordtextpos - 1])) { regwordtextpos -= 2; regwordtext.erase(regwordtext.begin() + regwordtextpos); regwordtext.erase(regwordtext.begin() + regwordtextpos); } else { --regwordtextpos; regwordtext.erase(regwordtext.begin() + regwordtextpos); } _Update(); } break; case SKK_DELETE: if(comptext.empty() && regwordtextpos < regwordtext.size()) { // surrogate pair if(regwordtext.size() >= regwordtextpos + 2 && IS_SURROGATE_PAIR(regwordtext[regwordtextpos + 0], regwordtext[regwordtextpos + 1])) { regwordtext.erase(regwordtext.begin() + regwordtextpos); regwordtext.erase(regwordtext.begin() + regwordtextpos); } else { regwordtext.erase(regwordtext.begin() + regwordtextpos); } _Update(); } break; case SKK_LEFT: if(comptext.empty() && regwordtextpos > 0 && regwordtext.size() > 0) { // surrogate pair if(regwordtext.size() >= 2 && regwordtextpos >= 2 && IS_SURROGATE_PAIR(regwordtext[regwordtextpos - 2], regwordtext[regwordtextpos - 1])) { regwordtextpos -= 2; } else { --regwordtextpos; } _Update(); } break; case SKK_UP: if(comptext.empty()) { regwordtextpos = 0; _Update(); } break; case SKK_RIGHT: if(comptext.empty() && regwordtextpos < regwordtext.size()) { // surrogate pair if(regwordtext.size() >= regwordtextpos + 2 && IS_SURROGATE_PAIR(regwordtext[regwordtextpos + 0], regwordtext[regwordtextpos + 1])) { regwordtextpos += 2; } else { ++regwordtextpos; } _Update(); } break; case SKK_DOWN: if(comptext.empty()) { regwordtextpos = regwordtext.size(); _Update(); } break; case SKK_PASTE: if(IsClipboardFormatAvailable(CF_UNICODETEXT)) { if(OpenClipboard(NULL)) { HANDLE hCB = GetClipboardData(CF_UNICODETEXT); if(hCB != NULL) { LPWSTR pwCB = (LPWSTR)GlobalLock(hCB); if(pwCB != NULL) { std::wstring scb = std::regex_replace(std::wstring(pwCB), std::wregex(L"[\\x00-\\x19]"), std::wstring(L"")); regwordtext.insert(regwordtextpos, scb); regwordtextpos += scb.size(); _Update(); _UpdateUIElement(); GlobalUnlock(hCB); } } CloseClipboard(); } } break; default: _HandleKey((WPARAM)uVKey, SKK_NULL); if(_pInputModeWindow != NULL) { _pInputModeWindow->_Redraw(); } break; } }
void CCandidateWindow::_PrevPage() { UINT uOldPage, uNewPage; GetCurrentPage(&uOldPage); if(uOldPage > 0) { uNewPage = uOldPage - 1; } else { if(_pCandidateList != NULL) { if(!regword) { if(_pTextService->cx_untilcandlist == 1) { if(_pCandidateWindowParent == NULL) { _EndCandidateList(SKK_CANCEL); } else { if(_reg) { _RestoreStatusReg(); } _PreEndReq(); _HandleKey(0, SKK_CANCEL); _EndReq(); } } else { if(_pCandidateWindowParent == NULL) { _pTextService->candidx = _pTextService->cx_untilcandlist - 1; _EndCandidateList(SKK_PREV_CAND); } else { if(_reg) { _RestoreStatusReg(); } _PreEndReq(); _pTextService->candidx = _pTextService->cx_untilcandlist - 1; _HandleKey(0, SKK_PREV_CAND); _EndReq(); } } } else { if(_pTextService->cx_untilcandlist == 1) { _HandleKey(0, SKK_CANCEL); } else { _pTextService->candidx = _pTextService->cx_untilcandlist - 1; _HandleKey(0, SKK_PREV_CAND); } _Update(); _UpdateUIElement(); } } return; } _uIndex = _PageIndex[uNewPage]; _dwFlags = TF_CLUIE_SELECTION; if(uNewPage != uOldPage) { _dwFlags |= TF_CLUIE_CURRENTPAGE; } _Update(); _UpdateUIElement(); }
HRESULT CCandidateWindow::_OnKeyDown(UINT uVKey) { UINT i, page, index; WCHAR ch; BYTE sf; if(_pCandidateWindow != NULL && !_preEnd) { return _pCandidateWindow->_OnKeyDown(uVKey); } //辞書登録モード if(regword) { _OnKeyDownRegword(uVKey); return S_OK; } _GetChSf(uVKey, ch, sf); //複数補完/複数動的補完 if(_comp) { switch(sf) { case SKK_NEXT_COMP: if(candidx == (size_t)-1) { candidx = 0; _InvokeSfHandler(SKK_NEXT_COMP); } else { _NextComp(); } break; case SKK_PREV_COMP: if(candidx != (size_t)-1) { _PrevComp(); } break; default: _InvokeKeyHandler(uVKey); break; } return S_OK; } //候補選択 switch(sf) { case SKK_CANCEL: if(_pCandidateList != NULL) { if(!regword) { if(_pCandidateWindowParent == NULL) { _EndCandidateList(SKK_CANCEL); } else { if(_reg) { _RestoreStatusReg(); } _PreEndReq(); _HandleKey(0, SKK_CANCEL); _EndReq(); } } else { _HandleKey(0, SKK_CANCEL); _Update(); } } break; case SKK_BACK: case SKK_PREV_CAND: _PrevPage(); break; case SKK_NEXT_CAND: _NextPage(); break; default: _GetChSf(uVKey, ch, sf, VK_KANA); for(i = 0; i < MAX_SELKEY_C; i++) { if(ch == (L'1' + i) || (ch == _pTextService->selkey[i][0][0] && _pTextService->selkey[i][0][0] != L'\0') || (ch == _pTextService->selkey[i][1][0] && _pTextService->selkey[i][1][0] != L'\0')) { GetCurrentPage(&page); if(i < _CandCount[page]) { index = (UINT)(_pTextService->cx_untilcandlist - 1) + _PageIndex[page] + i; if(index < _pTextService->candidates.size()) { if(!regword) { if(_pCandidateWindowParent == NULL) { _pTextService->candidx = index; _EndCandidateList(SKK_ENTER); } else { if(_reg) { _RestoreStatusReg(); } _PreEndReq(); _pTextService->candidx = index; _HandleKey(0, SKK_ENTER); _EndReq(); } } else { _pTextService->candidx = index; _HandleKey(0, SKK_ENTER); _Update(); } break; } } } } break; } return S_OK; }
CCandidateListUIPresenter::~CCandidateListUIPresenter() { _EndCandidateList(); _pTextService->Release(); }
VOID CCandidateListUIPresenter::_LayoutDestroyNotification() { _EndCandidateList(); }
HRESULT CCandidateList::_StartCandidateList(TfClientId tfClientId, ITfDocumentMgr *pDocumentMgr, ITfContext *pContext, TfEditCookie ec, ITfRange *pRange, BOOL reg, BOOL comp) { HRESULT hr = E_FAIL; TfEditCookie ecTextStore; ITfContextView *pContextView; HWND hwnd = NULL; _EndCandidateList(); if(pDocumentMgr->CreateContext(tfClientId, 0, NULL, &_pContextCandidateWindow, &ecTextStore) != S_OK) { return E_FAIL; } if(pDocumentMgr->Push(_pContextCandidateWindow) != S_OK) { goto exit; } _pDocumentMgr = pDocumentMgr; _pDocumentMgr->AddRef(); _pContextDocument = pContext; _pContextDocument->AddRef(); _pRangeComposition = pRange; _pRangeComposition->AddRef(); _ec = ec; _comp = comp; if(_AdviseContextKeyEventSink() != S_OK) { goto exit; } if(_AdviseTextLayoutSink() != S_OK) { goto exit; } try { _pCandidateWindow = new CCandidateWindow(_pTextService, this); if(pContext->GetActiveView(&pContextView) == S_OK) { if(!_pTextService->_UILessMode && _pCandidateWindow->_CanShowUIElement()) { if(FAILED(pContextView->GetWnd(&hwnd)) || hwnd == NULL) { hwnd = GetFocus(); } } SafeRelease(&pContextView); } if(!_pCandidateWindow->_Create(hwnd, NULL, 0, 0, reg, comp)) { goto exit; } HRESULT hrSession = E_FAIL; try { CCandidateWindowEditSession *pEditSession = new CCandidateWindowEditSession(_pTextService, _pContextDocument, _pRangeComposition, _pCandidateWindow); // Asynchronous pContext->RequestEditSession(ec, pEditSession, TF_ES_ASYNC | TF_ES_READWRITE, &hrSession); SafeRelease(&pEditSession); } catch(...) { } if(hrSession != TF_S_ASYNC) { hr = E_FAIL; goto exit; } hr = S_OK; } catch(...) { } exit: if(hr != S_OK) { _EndCandidateList(); } return hr; }