• R/O
  • HTTP
  • SSH
  • HTTPS

nvdajp: Commit

NVDA with Japanese branch


Commit MetaInfo

Revisiónb7b4dc9c385dc9478316719dd80c2d371ddf4b09 (tree)
Tiempo2013-08-20 14:40:49
AutorTakuya Nishimoto <nishimotz@gmai...>
CommiterTakuya Nishimoto

Log Message

merged tsf_japanese branch

Cambiar Resumen

Diferencia incremental

--- /dev/null
+++ b/nvdaHelper/remote/tsf.BAK
@@ -0,0 +1,780 @@
1+/*
2+This file is a part of the NVDA project.
3+URL: http://www.nvda-project.org/
4+Copyright 2010-2012 World Light Information Limited and Hong Kong Blind Union.
5+ This program is free software: you can redistribute it and/or modify
6+ it under the terms of the GNU General Public License version 2.0, as published by
7+ the Free Software Foundation.
8+ This program is distributed in the hope that it will be useful,
9+ but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11+This license can be found at:
12+http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
13+*/
14+
15+#include <map>
16+#include <windows.h>
17+#include <wchar.h>
18+#include <msctf.h>
19+#include <common/log.h>
20+#include <common/lock.h>
21+#include "nvdaHelperRemote.h"
22+#include "nvdaControllerInternal.h"
23+#include "typedCharacter.h"
24+#include "ime.h"
25+#include "tsf.h"
26+#include "inputLangChange.h"
27+
28+using namespace std;
29+
30+CLSID curTSFClsID={0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
31+bool isUIElementMgrSafe=false;
32+
33+
34+bool fetchRangeExtent(ITfRange* pRange, long* start, ULONG* length) {
35+ HRESULT res=S_OK;
36+ if(!pRange) return false;
37+ ITfRangeACP* pRangeACP=NULL;
38+ res=pRange->QueryInterface(IID_ITfRangeACP,(void**)&pRangeACP);
39+ if(res!=S_OK||!pRangeACP) return false;
40+ res=pRangeACP->GetExtent(start,(long*)length);
41+ pRangeACP->Release();
42+ return true?(res==S_OK):false;
43+}
44+
45+#define NVDAJP 1
46+
47+#ifdef NVDAJP
48+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms629224%28v=vs.85%29.aspx
49+HRESULT getDispAttrFromRange(ITfContext *pContext,
50+ ITfRange *pRange,
51+ TfEditCookie ec,
52+ TF_DISPLAYATTRIBUTE *pDispAttr)
53+{
54+ HRESULT hr;
55+ ITfCategoryMgr *pCategoryMgr;
56+ hr = CoCreateInstance(CLSID_TF_CategoryMgr,
57+ NULL,
58+ CLSCTX_INPROC_SERVER,
59+ IID_ITfCategoryMgr,
60+ (LPVOID*)&pCategoryMgr);
61+ if(FAILED(hr)){
62+ return hr;
63+ }
64+ ITfDisplayAttributeMgr *pDispMgr;
65+ hr = CoCreateInstance(CLSID_TF_DisplayAttributeMgr,
66+ NULL,
67+ CLSCTX_INPROC_SERVER,
68+ IID_ITfDisplayAttributeMgr,
69+ (LPVOID*)&pDispMgr);
70+ if(FAILED(hr)){
71+ pCategoryMgr->Release();
72+ return hr;
73+ }
74+ ITfProperty *pProp;
75+ hr = pContext->GetProperty(GUID_PROP_ATTRIBUTE, &pProp);
76+ if(SUCCEEDED(hr)){
77+ VARIANT var;
78+ VariantInit(&var);
79+ hr = pProp->GetValue(ec, pRange, &var);
80+ if(S_OK == hr){
81+ if(VT_I4 == var.vt){
82+ GUID guid;
83+ hr = pCategoryMgr->GetGUID((TfGuidAtom)var.lVal, &guid);
84+ if(SUCCEEDED(hr)){
85+ ITfDisplayAttributeInfo *pDispInfo;
86+ hr = pDispMgr->GetDisplayAttributeInfo(guid, &pDispInfo, NULL);
87+ if(SUCCEEDED(hr)){
88+ hr = pDispInfo->GetAttributeInfo(pDispAttr);
89+ if(SUCCEEDED(hr)){
90+ OutputDebugString(L"GetAttributeInfo() succeeded");
91+ }
92+ pDispInfo->Release();
93+ }
94+ }
95+ } else {
96+ hr = E_FAIL;
97+ }
98+ VariantClear(&var);
99+ }
100+ pProp->Release();
101+ }
102+ pCategoryMgr->Release();
103+ pDispMgr->Release();
104+ return hr;
105+}
106+#endif // NVDAJP
107+
108+
109+class TsfSink;
110+typedef map<DWORD,TsfSink*> sinkMap_t;
111+
112+static DWORD gTsfIndex = TLS_OUT_OF_INDEXES;
113+static sinkMap_t gTsfSinks;
114+static LockableObject gTsfSinksLock;
115+static PVOID gLastCompStr = NULL;
116+
117+class TsfSink : public ITfThreadMgrEventSink, public ITfActiveLanguageProfileNotifySink, public ITfTextEditSink, public ITfUIElementSink, public ITfInputProcessorProfileActivationSink {
118+public:
119+ TsfSink();
120+ ~TsfSink();
121+
122+ // Initializes object after creation
123+ bool Initialize();
124+
125+ // Cleans up object before destruction
126+ void CleanUp();
127+
128+ // IUnknown methods
129+ STDMETHODIMP QueryInterface(REFIID, LPVOID*);
130+ STDMETHODIMP_(ULONG) AddRef();
131+ STDMETHODIMP_(ULONG) Release();
132+
133+ // ITfThreadMgrEventSink methods
134+ STDMETHODIMP OnInitDocumentMgr(ITfDocumentMgr*);
135+ STDMETHODIMP OnUninitDocumentMgr(ITfDocumentMgr*);
136+ STDMETHODIMP OnSetFocus(ITfDocumentMgr*, ITfDocumentMgr*);
137+ STDMETHODIMP OnPushContext(ITfContext*);
138+ STDMETHODIMP OnPopContext(ITfContext*);
139+
140+ // ITfTextEditSink methods
141+ STDMETHODIMP OnEndEdit(ITfContext*, TfEditCookie, ITfEditRecord*);
142+
143+ STDMETHODIMP ITfActiveLanguageProfileNotifySink::OnActivated(REFCLSID, REFGUID, BOOL);
144+ STDMETHODIMP ITfInputProcessorProfileActivationSink::OnActivated(DWORD dwProfileType, LANGID langId, REFCLSID rclsid, REFGUID catId, REFGUID guidProfile, HKL hkl, DWORD dwFlags);
145+
146+ // ITfUIElementSink methods
147+ STDMETHODIMP BeginUIElement(DWORD, BOOL*);
148+ STDMETHODIMP UpdateUIElement(DWORD);
149+ STDMETHODIMP EndUIElement(DWORD);
150+
151+ //Is TSF actually being used for this thread?
152+ bool hasActiveProfile;
153+
154+private:
155+ LONG mRefCount;
156+ ITfThreadMgr* mpThreadMgr;
157+ ITfSource* mpTextEditSrc;
158+ ITfUIElementMgr* mpUIElementMgr;
159+ DWORD mThreadMgrCookie;
160+ DWORD mLangProfCookie;
161+ DWORD mTextEditCookie;
162+ DWORD mUIElementCookie;
163+ DWORD curReadingInformationUIElementId;
164+ bool inComposition;
165+
166+ void UpdateTextEditSink(ITfDocumentMgr* docMgr);
167+ void RemoveTextEditSink();
168+ WCHAR* HandleCompositionView(ITfContext* pCtx, TfEditCookie cookie);
169+ WCHAR* HandleEditRecord(TfEditCookie cookie, ITfEditRecord* pEditRec);
170+ IEnumITfCompositionView* GetCompViewEnum(ITfContext* pCtx);
171+ ITfRange* CombineCompRange(ITfContext* pCtx, TfEditCookie cookie);
172+};
173+
174+typedef HRESULT (WINAPI* TF_GetThreadMgr_t)(ITfThreadMgr**);
175+typedef HRESULT (WINAPI* TF_CreateThreadMgr_t)(ITfThreadMgr**);
176+
177+ITfThreadMgr*
178+create_thread_manager() {
179+ ITfThreadMgr* mgr = NULL;
180+ HMODULE dll = LoadLibraryA("msctf.dll");
181+ if (!dll) return NULL;
182+ TF_GetThreadMgr_t get_func =
183+ (TF_GetThreadMgr_t)GetProcAddress(dll, "TF_GetThreadMgr");
184+ if (get_func) get_func(&mgr);
185+ /*
186+ if (!mgr) {
187+ TF_CreateThreadMgr_t create_func =
188+ (TF_CreateThreadMgr_t)GetProcAddress(dll, "TF_CreateThreadMgr");
189+ if (create_func) create_func(&mgr);
190+ }
191+ */
192+ FreeLibrary(dll);
193+ return mgr;
194+}
195+
196+typedef HRESULT (WINAPI* TF_CreateInputProcessorProfiles_t)(ITfInputProcessorProfiles**);
197+
198+ITfInputProcessorProfiles*
199+create_input_processor_profiles() {
200+ ITfInputProcessorProfiles* profiles = NULL;
201+ HMODULE dll = LoadLibraryA("msctf.dll");
202+ if (!dll) return NULL;
203+ TF_CreateInputProcessorProfiles_t func =
204+ (TF_CreateInputProcessorProfiles_t)GetProcAddress(dll, "TF_CreateInputProcessorProfiles");
205+ if (func) func(&profiles);
206+ FreeLibrary(dll);
207+ return profiles;
208+}
209+
210+TsfSink::TsfSink() {
211+ mRefCount = 1;
212+ mpThreadMgr = NULL;
213+ mpTextEditSrc = NULL;
214+ mpUIElementMgr=NULL;
215+ mThreadMgrCookie = TF_INVALID_COOKIE;
216+ mLangProfCookie = TF_INVALID_COOKIE;
217+ mTextEditCookie = TF_INVALID_COOKIE;
218+ mUIElementCookie = TF_INVALID_COOKIE;
219+ curReadingInformationUIElementId=-1;
220+ inComposition=false;
221+ int lastCompositionStartOffset=0;
222+ hasActiveProfile=false;
223+}
224+
225+TsfSink::~TsfSink() {
226+}
227+
228+bool TsfSink::Initialize() {
229+ mpThreadMgr = create_thread_manager();
230+ if(!mpThreadMgr) return false;
231+ HRESULT hr = S_OK;
232+ ITfSource* src = NULL;
233+ if (hr == S_OK) {
234+ hr = mpThreadMgr->QueryInterface(IID_ITfSource, (void**)&src);
235+ }
236+ if (src) {
237+ if (hr == S_OK) {
238+ hr = src->AdviseSink(IID_ITfThreadMgrEventSink,
239+ (ITfThreadMgrEventSink*)this, &mThreadMgrCookie);
240+ }
241+ if (hr == S_OK) {
242+ ///For profile activations use ITfInputProcessProfileActivationSink if its available, otherwise ITfActiveLanguageNotifySink (usually on XP).
243+ hr = src->AdviseSink(IID_ITfInputProcessorProfileActivationSink,(ITfInputProcessorProfileActivationSink*)this, &mLangProfCookie);
244+ if(hr!=S_OK||mLangProfCookie==TF_INVALID_COOKIE) {
245+ LOG_DEBUGWARNING(L"Cannot register ITfInputProcessorProfileActivationSink, trying ITfActiveLanguageProfileNotifySink instead");
246+ hr = src->AdviseSink(IID_ITfActiveLanguageProfileNotifySink,(ITfActiveLanguageProfileNotifySink*)this, &mLangProfCookie);
247+ }
248+ }
249+ if(isUIElementMgrSafe) {
250+ if (hr == S_OK) {
251+ hr = mpThreadMgr->QueryInterface(IID_ITfUIElementMgr,(void**)&mpUIElementMgr);
252+ }
253+ if (hr == S_OK) {
254+ hr = src->AdviseSink(IID_ITfUIElementSink,(ITfUIElementSink*)this, &mUIElementCookie);
255+ }
256+ }
257+ src->Release();
258+ src = NULL;
259+ }
260+ ITfDocumentMgr* doc_mgr = NULL;
261+ mpThreadMgr->GetFocus(&doc_mgr);
262+ if (doc_mgr) {
263+ UpdateTextEditSink(doc_mgr);
264+ doc_mgr->Release();
265+ }
266+ //Check to see if there is an active TSF language profile and set hasActiveProfile accordingly.
267+ ITfInputProcessorProfiles* profiles = create_input_processor_profiles();
268+ if(profiles) {
269+ LANGID lang = 0;
270+ profiles->GetCurrentLanguage(&lang);
271+ if(lang) {
272+ IEnumTfLanguageProfiles* pEnumTfLanguageProfiles=NULL;
273+ profiles->EnumLanguageProfiles(lang,&pEnumTfLanguageProfiles);
274+ if(pEnumTfLanguageProfiles) {
275+ TF_LANGUAGEPROFILE profile;
276+ ULONG fetched=0;
277+ while(pEnumTfLanguageProfiles->Next(1,&profile,&fetched)==S_OK&&fetched==1) {
278+ if(profile.fActive&&IsEqualCLSID(profile.catid,GUID_TFCAT_TIP_KEYBOARD)) {
279+ hasActiveProfile=true;
280+ break;
281+ }
282+ }
283+ pEnumTfLanguageProfiles->Release();
284+ }
285+ }
286+ profiles->Release();
287+ }
288+ return true;
289+}
290+
291+void TsfSink::CleanUp() {
292+ RemoveTextEditSink();
293+ if (mpThreadMgr) {
294+ ITfSource* src = NULL;
295+ mpThreadMgr->QueryInterface(IID_ITfSource, (void**)&src);
296+ if (src)
297+ {
298+ if (mUIElementCookie != TF_INVALID_COOKIE) {
299+ src->UnadviseSink(mUIElementCookie);
300+ mUIElementCookie = TF_INVALID_COOKIE;
301+ }
302+ if (mThreadMgrCookie != TF_INVALID_COOKIE) {
303+ src->UnadviseSink(mThreadMgrCookie);
304+ }
305+ if (mLangProfCookie != TF_INVALID_COOKIE) {
306+ src->UnadviseSink(mLangProfCookie);
307+ }
308+ src->Release();
309+ }
310+ if(mpUIElementMgr) {
311+ mpUIElementMgr->Release();
312+ mpUIElementMgr=NULL;
313+ }
314+ mThreadMgrCookie = TF_INVALID_COOKIE;
315+ mLangProfCookie = TF_INVALID_COOKIE;
316+ mpThreadMgr->Release();
317+ mpThreadMgr = NULL;
318+ }
319+ CoUninitialize();
320+}
321+
322+void TsfSink::UpdateTextEditSink(ITfDocumentMgr* docMgr) {
323+ RemoveTextEditSink();
324+ if (!docMgr) return;
325+ ITfContext* ctx = NULL;
326+ HRESULT hr = docMgr->GetBase(&ctx);
327+ if (hr == S_OK) {
328+ hr = ctx->QueryInterface(IID_ITfSource, (void**)&mpTextEditSrc);
329+ ctx->Release();
330+ }
331+ if (hr == S_OK) {
332+ hr = mpTextEditSrc->AdviseSink(IID_ITfTextEditSink,
333+ (ITfTextEditSink*)this, &mTextEditCookie);
334+ }
335+ if (hr != S_OK) {
336+ RemoveTextEditSink();
337+ return;
338+ }
339+}
340+
341+void TsfSink::RemoveTextEditSink() {
342+ if (mTextEditCookie != TF_INVALID_COOKIE) {
343+ mpTextEditSrc->UnadviseSink(mTextEditCookie);
344+ mTextEditCookie = TF_INVALID_COOKIE;
345+ }
346+ if (mpTextEditSrc) {
347+ mpTextEditSrc->Release();
348+ mpTextEditSrc = NULL;
349+ }
350+}
351+
352+STDMETHODIMP TsfSink::QueryInterface(REFIID riid, LPVOID* ppvObj) {
353+ if (!ppvObj) return E_INVALIDARG;
354+ if (IsEqualIID(riid, IID_IUnknown) ||
355+ IsEqualIID(riid, IID_ITfThreadMgrEventSink)) {
356+ *ppvObj = (ITfThreadMgrEventSink*)this;
357+ } else if (IsEqualIID(riid, IID_ITfActiveLanguageProfileNotifySink)) {
358+ *ppvObj = (ITfActiveLanguageProfileNotifySink*)this;
359+ } else if (IsEqualIID(riid, IID_ITfInputProcessorProfileActivationSink)) {
360+ *ppvObj = (ITfInputProcessorProfileActivationSink*)this;
361+ } else if (IsEqualIID(riid, IID_ITfTextEditSink)) {
362+ *ppvObj = (ITfTextEditSink*)this;
363+ } else if (IsEqualIID(riid, IID_ITfUIElementSink)) {
364+ *ppvObj = (ITfUIElementSink*)this;
365+ } else {
366+ *ppvObj = NULL;
367+ return E_NOINTERFACE;
368+ }
369+ AddRef();
370+ return S_OK;
371+}
372+
373+STDMETHODIMP_(ULONG) TsfSink::AddRef() {
374+ return ++mRefCount;
375+}
376+
377+STDMETHODIMP_(ULONG) TsfSink::Release() {
378+ LONG count = --mRefCount;
379+ if (count == 0) delete this;
380+ return count;
381+}
382+
383+STDMETHODIMP TsfSink::OnInitDocumentMgr(ITfDocumentMgr* pDIM) {
384+ return S_OK;
385+}
386+
387+STDMETHODIMP TsfSink::OnUninitDocumentMgr(ITfDocumentMgr* pDIM) {
388+ return S_OK;
389+}
390+
391+STDMETHODIMP TsfSink::OnSetFocus(
392+ ITfDocumentMgr* pDIM, ITfDocumentMgr* pPrevDIM) {
393+ UpdateTextEditSink(pDIM);
394+ return S_OK;
395+}
396+
397+STDMETHODIMP TsfSink::OnPushContext(ITfContext* pCtx) {
398+ return S_OK;
399+}
400+
401+STDMETHODIMP TsfSink::OnPopContext(ITfContext* pCtx) {
402+ return S_OK;
403+}
404+
405+IEnumITfCompositionView* TsfSink::GetCompViewEnum(ITfContext* pCtx) {
406+ // Make sure there is a composition context
407+ ITfContextComposition* ctx_comp = NULL;
408+ pCtx->QueryInterface(IID_ITfContextComposition, (void**)&ctx_comp);
409+ if (!ctx_comp) return NULL;
410+
411+ // Obtain composition view enumerator
412+ IEnumITfCompositionView* enum_view = NULL;
413+ ctx_comp->EnumCompositions(&enum_view);
414+ ctx_comp->Release();
415+ return enum_view;
416+}
417+
418+ITfRange* TsfSink::CombineCompRange(ITfContext* pCtx, TfEditCookie cookie) {
419+ // Make sure there is a composition view enumerator
420+ IEnumITfCompositionView* enum_view = GetCompViewEnum(pCtx);
421+ if (!enum_view) return NULL;
422+
423+ // Combine composition ranges from all views
424+ ITfRange* range = NULL;
425+ ITfCompositionView* view = NULL;
426+ while (enum_view->Next(1, &view, NULL) == S_OK) {
427+ ITfRange *view_range = NULL;
428+ if (view->GetRange(&view_range) == S_OK) {
429+ if (!range) {
430+ view_range->Clone(&range);
431+ } else {
432+ range->ShiftEndToRange(cookie, view_range, TF_ANCHOR_END);
433+ }
434+ view_range->Release();
435+ }
436+ view->Release();
437+ }
438+ enum_view->Release();
439+ return range;
440+}
441+
442+WCHAR* TsfSink::HandleCompositionView(ITfContext* pCtx, TfEditCookie cookie) {
443+ // Make sure there is a composition view enumerator
444+ IEnumITfCompositionView* enum_view = GetCompViewEnum(pCtx);
445+ if (!enum_view) return NULL;
446+
447+ // Concatenate text in all composition views into composition string
448+ WCHAR* comp_str = (WCHAR*)malloc(sizeof(WCHAR));
449+ int comp_len = 0;
450+ ITfCompositionView* view = NULL;
451+ while (enum_view->Next(1, &view, NULL) == S_OK) {
452+ ITfRange *range;
453+ if (view->GetRange(&range) == S_OK) {
454+ BOOL empty;
455+ while ((range->IsEmpty(cookie, &empty) == S_OK) && !empty) {
456+ wchar_t buf[256];
457+ ULONG len = ARRAYSIZE(buf) - 1;
458+ range->GetText(cookie, TF_TF_MOVESTART, buf, len, &len);
459+ comp_str = (WCHAR*)realloc(comp_str,
460+ (comp_len + len + 1) * sizeof(WCHAR));
461+ CopyMemory(comp_str + comp_len, buf, len * sizeof(WCHAR));
462+ comp_len += len;
463+ }
464+ range->Release();
465+ }
466+ view->Release();
467+ }
468+ enum_view->Release();
469+
470+ // Generate notification
471+ comp_str[comp_len] = '\0';
472+ if (comp_len > 0) return comp_str;
473+ free(comp_str);
474+ return NULL;
475+}
476+
477+WCHAR* TsfSink::HandleEditRecord(TfEditCookie cookie, ITfEditRecord* pEditRec) {
478+ // Make sure that are is a valid range enumerator
479+#ifdef NVDAJP
480+ OutputDebugString(L"TsfSink::HandleEditRecord");
481+#endif
482+ IEnumTfRanges* enum_range = NULL;
483+ HRESULT hr = pEditRec->GetTextAndPropertyUpdates(
484+ TF_GTP_INCL_TEXT, NULL, 0, &enum_range);
485+ if (!enum_range) return NULL;
486+
487+ // Concatenate the text from all ranges
488+ WCHAR* edit_str = (WCHAR*)malloc(sizeof(WCHAR));
489+ int edit_len = 0;
490+ ITfRange* range = NULL;
491+ ULONG count = 0;
492+ while ((enum_range->Next(1, &range, &count) == S_OK) && count) {
493+ BOOL empty;
494+ while ((range->IsEmpty(cookie, &empty) == S_OK) && !empty) {
495+ wchar_t buf[256];
496+ ULONG len = ARRAYSIZE(buf) - 1;
497+ range->GetText(cookie, TF_TF_MOVESTART, buf, len, &len);
498+ edit_str = (WCHAR*)realloc(edit_str,
499+ (edit_len + len + 1) * sizeof(WCHAR));
500+ CopyMemory(edit_str + edit_len, buf, len * sizeof(WCHAR));
501+ edit_len += len;
502+ }
503+ range->Release();
504+ }
505+ enum_range->Release();
506+
507+ // Generate notification
508+ edit_str[edit_len] = '\0';
509+ if (edit_len > 0) return edit_str;
510+ free(edit_str);
511+ return NULL;
512+}
513+
514+STDMETHODIMP TsfSink::BeginUIElement(DWORD elementId, BOOL* pShow) {
515+ if(mpUIElementMgr) {
516+ ITfUIElement* pUIElement=NULL;
517+ mpUIElementMgr->GetUIElement(elementId,&pUIElement);
518+ if(pUIElement) {
519+ ITfReadingInformationUIElement* pReadingInformationUIElement=NULL;
520+ pUIElement->QueryInterface(IID_ITfReadingInformationUIElement,(void**)&pReadingInformationUIElement);
521+ pUIElement->Release();
522+ if(pReadingInformationUIElement) {
523+ curReadingInformationUIElementId=elementId;
524+ pReadingInformationUIElement->Release();
525+ }
526+ }
527+ }
528+ *pShow=(curReadingInformationUIElementId!=-1)?false:true;
529+ return S_OK;
530+}
531+
532+STDMETHODIMP TsfSink::UpdateUIElement(DWORD elementId) {
533+ if(elementId==curReadingInformationUIElementId&&mpUIElementMgr) {
534+ ITfUIElement* pUIElement=NULL;
535+ mpUIElementMgr->GetUIElement(elementId,&pUIElement);
536+ if(pUIElement) {
537+ ITfReadingInformationUIElement* pReadingInformationUIElement=NULL;
538+ pUIElement->QueryInterface(IID_ITfReadingInformationUIElement,(void**)&pReadingInformationUIElement);
539+ pUIElement->Release();
540+ if(pReadingInformationUIElement) {
541+ BSTR read_str=NULL;
542+ pReadingInformationUIElement->GetString(&read_str);
543+ if(read_str) {
544+ long len=SysStringLen(read_str);
545+ if(len>0) {
546+ nvdaControllerInternal_inputCompositionUpdate(read_str,len,len,1);
547+ }
548+ SysFreeString(read_str);
549+ }
550+ pReadingInformationUIElement->Release();
551+ }
552+ }
553+ }
554+ return S_OK;
555+}
556+
557+STDMETHODIMP TsfSink::EndUIElement(DWORD elementId) {
558+ if(elementId==curReadingInformationUIElementId) curReadingInformationUIElementId=-1;
559+ return S_OK;
560+}
561+
562+
563+STDMETHODIMP TsfSink::OnEndEdit(
564+ ITfContext* pCtx, TfEditCookie cookie, ITfEditRecord* pEditRec) {
565+ // TSF input processor performing composition
566+ ITfRange* pRange=CombineCompRange(pCtx,cookie);
567+ if(!pRange) {
568+ if(inComposition) {
569+ inComposition=false;
570+ if(!curIMEWindow) {
571+ wchar_t* edit_str=HandleEditRecord(cookie, pEditRec);
572+ nvdaControllerInternal_inputCompositionUpdate((edit_str?edit_str:L""),-1,-1,0);
573+ if(edit_str) free(edit_str);
574+ //Disable further typed character notifications produced by TSF
575+ typedCharacter_window=NULL;
576+ }
577+ }
578+ return S_OK;
579+ }
580+ inComposition=true;
581+ wchar_t buf[256];
582+ ULONG len = ARRAYSIZE(buf) - 1;
583+ pRange->GetText(cookie, 0, buf, len, &len);
584+ buf[min(len,255)]=L'\0';
585+ long compStart=0;
586+ fetchRangeExtent(pRange,&compStart,&len);
587+ long selStart=compStart;
588+ long selEnd=compStart;
589+ TF_SELECTION tfSelection={0};
590+ if(pCtx->GetSelection(cookie,TF_DEFAULT_SELECTION,1,&tfSelection,&len)==S_OK&&tfSelection.range) {
591+ if(fetchRangeExtent(tfSelection.range,&selStart,&len)) {
592+ selEnd=selStart+len;
593+ }
594+ tfSelection.range->Release();
595+ }
596+ selStart=max(0,selStart-compStart);
597+ selEnd=max(0,selEnd-compStart);
598+#ifdef NVDAJP
599+ TF_DISPLAYATTRIBUTE dispAttr;
600+ TF_DA_ATTR_INFO attr = TF_ATTR_OTHER; // -1
601+ HRESULT hr = getDispAttrFromRange(pCtx, pRange, cookie, &dispAttr);
602+ if (hr == S_OK) {
603+ attr = dispAttr.bAttr;
604+ }
605+ wchar_t buf_[200];
606+ wsprintf(buf_, L"TsfSink::OnEndEdit %ld %ld %d %d (%s)", selStart, selEnd, hr, attr, buf);
607+ OutputDebugString(buf_);
608+#endif
609+ nvdaControllerInternal_inputCompositionUpdate(buf,selStart,selEnd,0);
610+ return S_OK;
611+}
612+
613+//ITfActiveLanguageProfileNotifySink::OnActivated
614+//To notify NVDA (in XP) of a TSF profile change
615+STDMETHODIMP TsfSink::OnActivated(REFCLSID rClsID, REFGUID rProfGUID, BOOL activated) {
616+ const CLSID null_clsid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
617+ if (!activated) {
618+ curTSFClsID=null_clsid;
619+ hasActiveProfile=false;
620+ return S_OK;
621+ }
622+ //Re-enable IME conversion mode update reporting as input lang change window message disabled it while completing the switch
623+ curTSFClsID=rClsID;
624+ if (IsEqualCLSID(rClsID, null_clsid)) {
625+ hasActiveProfile = false;
626+ // When switching to non-TSF profile, resend last input language
627+ wchar_t buf[KL_NAMELENGTH];
628+ GetKeyboardLayoutName(buf);
629+ nvdaControllerInternal_inputLangChangeNotify(GetCurrentThreadId(),
630+ (unsigned long)GetKeyboardLayout(0), buf);
631+ handleIMEConversionModeUpdate(GetFocus(),true);
632+ return S_OK;
633+ }
634+ hasActiveProfile = true;
635+ ITfInputProcessorProfiles* profiles = create_input_processor_profiles();
636+ if (!profiles) return S_OK;
637+ HRESULT hr = S_OK;
638+ LANGID lang = 0;
639+ if (hr == S_OK)
640+ hr = profiles->GetCurrentLanguage(&lang);
641+ if (hr == S_OK) {
642+ BSTR desc = NULL;
643+ profiles->GetLanguageProfileDescription(rClsID, lang, rProfGUID, &desc);
644+ if (desc) {
645+ nvdaControllerInternal_inputLangChangeNotify(GetCurrentThreadId(),(unsigned long)GetKeyboardLayout(0), desc);
646+ SysFreeString(desc);
647+ }
648+ }
649+ profiles->Release();
650+ handleIMEConversionModeUpdate(GetFocus(),true);
651+ return S_OK;
652+}
653+
654+//ITfInputProcessorProfileActivationSink::OnActivated
655+//To notify NVDA (Win7 and above) of a TSF profile change
656+STDMETHODIMP TsfSink::OnActivated(DWORD dwProfileType, LANGID langId, REFCLSID rclsid, REFGUID catId, REFGUID guidProfile, HKL hkl, DWORD dwFlags) {
657+ const CLSID null_clsid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
658+ if(dwProfileType==TF_PROFILETYPE_KEYBOARDLAYOUT) {
659+ //This is a normal keyboard layout so forget any last active TSF profile
660+ hasActiveProfile=false;
661+ curTSFClsID=null_clsid;
662+ if(dwFlags&TF_IPSINK_FLAG_ACTIVE) {
663+ //As its activating, report the layout change to NVDA
664+ wchar_t buf[KL_NAMELENGTH];
665+ GetKeyboardLayoutName(buf);
666+ nvdaControllerInternal_inputLangChangeNotify(GetCurrentThreadId(),(unsigned long)GetKeyboardLayout(0), buf);
667+ handleIMEConversionModeUpdate(GetFocus(),true);
668+ }
669+ return S_OK;
670+ }
671+ //From here on this is a text service change
672+ if(!IsEqualCLSID(catId,GUID_TFCAT_TIP_KEYBOARD)) {
673+ //We don't handle anything other than keyboard text services (no speech etc)
674+ return S_OK;
675+ }
676+ if(!(dwFlags&TF_IPSINK_FLAG_ACTIVE)) {
677+ //This keyboard text service is deactivating
678+ curTSFClsID=null_clsid;
679+ hasActiveProfile=false;
680+ return S_OK;
681+ }
682+ curTSFClsID=rclsid;
683+ hasActiveProfile = true;
684+ ITfInputProcessorProfiles* profiles = create_input_processor_profiles();
685+ if (!profiles) return S_OK;
686+ BSTR desc = NULL;
687+ profiles->GetLanguageProfileDescription(rclsid, langId, guidProfile, &desc);
688+ if (desc) {
689+ nvdaControllerInternal_inputLangChangeNotify(GetCurrentThreadId(),(unsigned long)GetKeyboardLayout(0), desc);
690+ SysFreeString(desc);
691+ }
692+ profiles->Release();
693+ handleIMEConversionModeUpdate(GetFocus(),true);
694+ return S_OK;
695+}
696+
697+static void CALLBACK TSF_winEventHook(HWINEVENTHOOK hookID, DWORD eventID, HWND hwnd, long objectID, long childID, DWORD threadID, DWORD time) {
698+ switch (eventID)
699+ {
700+ case EVENT_SYSTEM_FOREGROUND:
701+ case EVENT_OBJECT_FOCUS:
702+ // Create TSF sink when window gains focus
703+ break;
704+ default:
705+ // Ignore all other events
706+ return;
707+ }
708+
709+ // Create TSF sink now
710+ if (TlsGetValue(gTsfIndex)) return;
711+ TsfSink* sink = new TsfSink;
712+ if (!sink) return;
713+ if(!sink->Initialize()) {
714+ sink->Release();
715+ return;
716+ }
717+ gTsfSinksLock.acquire();
718+ gTsfSinks[GetCurrentThreadId()] = sink;
719+ gTsfSinksLock.release();
720+ TlsSetValue(gTsfIndex, sink);
721+}
722+
723+TsfSink* fetchCurrentTsfSink() {
724+ if (gTsfIndex == TLS_OUT_OF_INDEXES) return NULL;
725+ return (TsfSink*)TlsGetValue(gTsfIndex);
726+}
727+
728+void TSF_inProcess_initialize() {
729+#ifdef NVDAJP
730+ OutputDebugString(L"TSF_inProcess_initialize");
731+#endif
732+ //Allow use of UIElementMgr on Vista and higher (crashes things on XP)
733+ if((GetVersion()&0xff)>5) isUIElementMgrSafe=true;
734+ // Initialize TLS and use window hook to create TSF sink in each thread
735+ gTsfIndex = TlsAlloc();
736+ if (gTsfIndex != TLS_OUT_OF_INDEXES)
737+ registerWinEventHook(TSF_winEventHook);
738+}
739+
740+void TSF_inProcess_terminate() {
741+#ifdef NVDAJP
742+ OutputDebugString(L"TSF_inProcess_terminate");
743+#endif
744+ if (gTsfIndex == TLS_OUT_OF_INDEXES) return;
745+
746+ // Remove window hook and clean up TLS
747+ unregisterWinEventHook(TSF_winEventHook);
748+ TlsFree(gTsfIndex);
749+ gTsfIndex = TLS_OUT_OF_INDEXES;
750+
751+ // Destroy all TSF sinks belonging to this process
752+ gTsfSinksLock.acquire();
753+ sinkMap_t::const_iterator end = gTsfSinks.end();
754+ for (sinkMap_t::const_iterator i = gTsfSinks.begin(); i != end; ++i) {
755+ TsfSink* sink = i->second;
756+ sink->CleanUp();
757+ sink->Release();
758+ }
759+ gTsfSinks.clear();
760+ gTsfSinksLock.release();
761+}
762+
763+void TSF_thread_detached() {
764+ TsfSink* sink=fetchCurrentTsfSink();
765+ // Remove TSF sink from the list
766+ gTsfSinksLock.acquire();
767+ gTsfSinks.erase(GetCurrentThreadId());
768+ gTsfSinksLock.release();
769+
770+ // Destroy TSF sink belonging to this thread
771+ TlsSetValue(gTsfIndex, NULL);
772+ sink->CleanUp();
773+ sink->Release();
774+}
775+
776+bool isTSFThread(bool checkActiveProfile) {
777+TsfSink* tsf=fetchCurrentTsfSink();
778+ if(!tsf) return false;
779+ return checkActiveProfile?tsf->hasActiveProfile:true;
780+}
--- a/nvdaHelper/remote/tsf.cpp
+++ b/nvdaHelper/remote/tsf.cpp
@@ -42,6 +42,123 @@ bool fetchRangeExtent(ITfRange* pRange, long* start, ULONG* length) {
4242 return true?(res==S_OK):false;
4343 }
4444
45+#define NVDAJP 1
46+
47+#ifdef NVDAJP
48+// http://msdn.microsoft.com/en-us/library/windows/desktop/ms629224%28v=vs.85%29.aspx
49+HRESULT getDispAttrFromRange(ITfContext *pContext,
50+ ITfRange *pRange,
51+ TfEditCookie ec,
52+ TF_DISPLAYATTRIBUTE *pDispAttr)
53+{
54+ HRESULT hr;
55+ ITfCategoryMgr *pCategoryMgr;
56+ hr = CoCreateInstance(CLSID_TF_CategoryMgr,
57+ NULL,
58+ CLSCTX_INPROC_SERVER,
59+ IID_ITfCategoryMgr,
60+ (LPVOID*)&pCategoryMgr);
61+ if(FAILED(hr)){
62+ return hr;
63+ }
64+ ITfDisplayAttributeMgr *pDispMgr;
65+ hr = CoCreateInstance(CLSID_TF_DisplayAttributeMgr,
66+ NULL,
67+ CLSCTX_INPROC_SERVER,
68+ IID_ITfDisplayAttributeMgr,
69+ (LPVOID*)&pDispMgr);
70+ if(FAILED(hr)){
71+ pCategoryMgr->Release();
72+ return hr;
73+ }
74+ ITfProperty *pProp;
75+ hr = pContext->GetProperty(GUID_PROP_ATTRIBUTE, &pProp);
76+ if(SUCCEEDED(hr)){
77+ VARIANT var;
78+ VariantInit(&var);
79+ hr = pProp->GetValue(ec, pRange, &var);
80+ if(S_OK == hr){
81+ if(VT_I4 == var.vt){
82+ GUID guid;
83+ hr = pCategoryMgr->GetGUID((TfGuidAtom)var.lVal, &guid);
84+ if(SUCCEEDED(hr)){
85+ ITfDisplayAttributeInfo *pDispInfo;
86+ hr = pDispMgr->GetDisplayAttributeInfo(guid, &pDispInfo, NULL);
87+ if(SUCCEEDED(hr)){
88+ hr = pDispInfo->GetAttributeInfo(pDispAttr);
89+ if(SUCCEEDED(hr)){
90+ OutputDebugString(L"GetAttributeInfo() succeeded");
91+ }
92+ pDispInfo->Release();
93+ }
94+ }
95+ } else {
96+ hr = E_FAIL;
97+ }
98+ VariantClear(&var);
99+ }
100+ pProp->Release();
101+ }
102+ pCategoryMgr->Release();
103+ pDispMgr->Release();
104+ return hr;
105+}
106+#endif // NVDAJP
107+
108+#ifdef NVDAJP
109+BOOL _FindComposingRange(TfEditCookie ec, ITfContext *pContext, ITfRange *pSelection, ITfRange **ppRange)
110+{
111+ if (ppRange == NULL)
112+ {
113+ return FALSE;
114+ }
115+
116+ *ppRange = NULL;
117+
118+ // find GUID_PROP_COMPOSING
119+ ITfProperty* pPropComp = NULL;
120+ IEnumTfRanges* enumComp = NULL;
121+
122+ HRESULT hr = pContext->GetProperty(GUID_PROP_COMPOSING, &pPropComp);
123+ if (FAILED(hr) || pPropComp == NULL)
124+ {
125+ return FALSE;
126+ }
127+
128+ hr = pPropComp->EnumRanges(ec, &enumComp, pSelection);
129+ if (FAILED(hr) || enumComp == NULL)
130+ {
131+ pPropComp->Release();
132+ return FALSE;
133+ }
134+
135+ BOOL isCompExist = FALSE;
136+ VARIANT var;
137+ ULONG fetched = 0;
138+
139+ while (enumComp->Next(1, ppRange, &fetched) == S_OK && fetched == 1)
140+ {
141+ hr = pPropComp->GetValue(ec, *ppRange, &var);
142+ if (hr == S_OK)
143+ {
144+ if (var.vt == VT_I4 && var.lVal != 0)
145+ {
146+ isCompExist = TRUE;
147+ break;
148+ }
149+ }
150+ (*ppRange)->Release();
151+ *ppRange = NULL;
152+ }
153+
154+ pPropComp->Release();
155+ enumComp->Release();
156+
157+ return isCompExist;
158+}
159+#endif // NVDAJP
160+
161+
45162 class TsfSink;
46163 typedef map<DWORD,TsfSink*> sinkMap_t;
47164
@@ -412,6 +529,9 @@ WCHAR* TsfSink::HandleCompositionView(ITfContext* pCtx, TfEditCookie cookie) {
412529
413530 WCHAR* TsfSink::HandleEditRecord(TfEditCookie cookie, ITfEditRecord* pEditRec) {
414531 // Make sure that are is a valid range enumerator
532+#ifdef NVDAJP
533+ OutputDebugString(L"TsfSink::HandleEditRecord");
534+#endif
415535 IEnumTfRanges* enum_range = NULL;
416536 HRESULT hr = pEditRec->GetTextAndPropertyUpdates(
417537 TF_GTP_INCL_TEXT, NULL, 0, &enum_range);
@@ -492,6 +612,7 @@ STDMETHODIMP TsfSink::EndUIElement(DWORD elementId) {
492612 return S_OK;
493613 }
494614
615+
495616 STDMETHODIMP TsfSink::OnEndEdit(
496617 ITfContext* pCtx, TfEditCookie cookie, ITfEditRecord* pEditRec) {
497618 // TSF input processor performing composition
@@ -527,6 +648,17 @@ STDMETHODIMP TsfSink::OnEndEdit(
527648 }
528649 selStart=max(0,selStart-compStart);
529650 selEnd=max(0,selEnd-compStart);
651+#ifdef NVDAJP
652+ TF_DISPLAYATTRIBUTE dispAttr;
653+ TF_DA_ATTR_INFO attr = TF_ATTR_OTHER; // -1
654+ HRESULT hr = getDispAttrFromRange(pCtx, pRange, cookie, &dispAttr);
655+ if (hr == S_OK) {
656+ attr = dispAttr.bAttr;
657+ }
658+ wchar_t buf_[200];
659+ wsprintf(buf_, L"TsfSink::OnEndEdit %ld %ld %d %d (%s)", selStart, selEnd, hr, attr, buf);
660+ OutputDebugString(buf_);
661+#endif
530662 nvdaControllerInternal_inputCompositionUpdate(buf,selStart,selEnd,0);
531663 return S_OK;
532664 }
@@ -647,6 +779,9 @@ TsfSink* fetchCurrentTsfSink() {
647779 }
648780
649781 void TSF_inProcess_initialize() {
782+#ifdef NVDAJP
783+ OutputDebugString(L"TSF_inProcess_initialize");
784+#endif
650785 //Allow use of UIElementMgr on Vista and higher (crashes things on XP)
651786 if((GetVersion()&0xff)>5) isUIElementMgrSafe=true;
652787 // Initialize TLS and use window hook to create TSF sink in each thread
@@ -656,6 +791,9 @@ void TSF_inProcess_initialize() {
656791 }
657792
658793 void TSF_inProcess_terminate() {
794+#ifdef NVDAJP
795+ OutputDebugString(L"TSF_inProcess_terminate");
796+#endif
659797 if (gTsfIndex == TLS_OUT_OF_INDEXES) return;
660798
661799 // Remove window hook and clean up TLS
--- a/source/NVDAHelper.py
+++ b/source/NVDAHelper.py
@@ -180,7 +180,12 @@ def handleInputCompositionEnd(result):
180180 if curInputComposition and not result:
181181 result=curInputComposition.compositionString.lstrip(u'\u3000 ')
182182 if result:
183- speech.speakText(result,symbolLevel=characterProcessing.SYMLVL_ALL)
183+ #nvdajp begin
184+ #speech.speakText(result,symbolLevel=characterProcessing.SYMLVL_ALL)
185+ import ui
186+ #. Translators: a message when the IME cancelation status
187+ ui.message(_("Clear"))
188+ #nvdajp end
184189
185190 def handleInputCompositionStart(compositionString,selectionStart,selectionEnd,isReading):
186191 import speech
--- a/source/locale/ja/LC_MESSAGES/nvda.po
+++ b/source/locale/ja/LC_MESSAGES/nvda.po
@@ -185,6 +185,11 @@ msgstr "日本語6点情報処理点字"
185185 msgid "%s:%s"
186186 msgstr "%s時%s分"
187187
188+#. Translators: a message when the IME cancelation status
189+#: NVDAHelper.py:
190+msgid "Clear"
191+msgstr "クリア"
192+
188193 # end of nvdajp
189194
190195 #. Translators: Message to indicate User Account Control (UAC) or other secure
Show on old repository browser