diff --git a/dlls/msctf/msctf_internal.h b/dlls/msctf/msctf_internal.h index 71ed10bb8dd..584bb1044ed 100644 --- a/dlls/msctf/msctf_internal.h +++ b/dlls/msctf/msctf_internal.h @@ -33,6 +33,7 @@ #define COOKIE_MAGIC_THREADFOCUSSINK 0x0080 #define COOKIE_MAGIC_KEYTRACESINK 0x0090 #define COOKIE_MAGIC_UIELEMENTSINK 0x00a0 +#define COOKIE_MAGIC_INPUTPROCESSORPROFILEACTIVATIONSINK 0x00b0 extern DWORD tlsIndex DECLSPEC_HIDDEN; extern TfClientId processId DECLSPEC_HIDDEN; diff --git a/dlls/msctf/tests/inputprocessor.c b/dlls/msctf/tests/inputprocessor.c index d440b536764..d73a3f94510 100644 --- a/dlls/msctf/tests/inputprocessor.c +++ b/dlls/msctf/tests/inputprocessor.c @@ -64,7 +64,8 @@ static DWORD tmSinkCookie; static DWORD tmSinkRefCount; static DWORD dmSinkCookie; static DWORD documentStatus; -static DWORD key_trace_sink_cookie, ui_element_sink_cookie; +static DWORD key_trace_sink_cookie, ui_element_sink_cookie, profile_activation_sink_cookie; +static DWORD fake_service_onactivated_flags = 0; static ITfDocumentMgr *test_CurrentFocus = NULL; static ITfDocumentMgr *test_PrevFocus = NULL; static ITfDocumentMgr *test_LastCurrentFocus = FOCUS_SAVE; @@ -85,6 +86,7 @@ static INT test_ACP_InsertTextAtSelection = SINK_UNEXPECTED; static INT test_ACP_SetSelection = SINK_UNEXPECTED; static INT test_OnEndEdit = SINK_UNEXPECTED; +DEFINE_GUID(CLSID_FakeService, 0xEDE1A7AD,0x66DE,0x47E0,0xB6,0x20,0x3E,0x92,0xF8,0x24,0x6B,0xF3); static inline int expected_count(int *sink) { @@ -725,6 +727,61 @@ static const ITfUIElementSinkVtbl TfUIElementSinkVtbl = { static ITfUIElementSink TfUIElementSink = { &TfUIElementSinkVtbl }; +static HRESULT WINAPI ProfileActivationSink_QueryInterface(ITfInputProcessorProfileActivationSink *iface, + REFIID riid, void **ppvObject) +{ + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_ITfInputProcessorProfileActivationSink, riid)){ + *ppvObject = iface; + return S_OK; + } + + *ppvObject = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI ProfileActivationSink_AddRef(ITfInputProcessorProfileActivationSink *iface) +{ + return 2; +} + +static ULONG WINAPI ProfileActivationSink_Release(ITfInputProcessorProfileActivationSink *iface) +{ + return 1; +} + +static HRESULT WINAPI ProfileActivationSink_OnActivated(ITfInputProcessorProfileActivationSink *iface, + DWORD dwProfileType, LANGID langid, REFCLSID clsid, REFGUID catid, + REFGUID guidProfile, HKL hkl, DWORD dwFlags) +{ + trace("Got OnActivated: {dwProfileType %08x, langid %08x, clsid %s, catid %s, guidProfile %s, %p, dwFlags %08x}\n", + dwProfileType, langid, wine_dbgstr_guid(clsid), + wine_dbgstr_guid(catid), wine_dbgstr_guid(guidProfile), hkl, dwFlags); + + ok(dwProfileType == TF_PROFILETYPE_INPUTPROCESSOR || dwProfileType == TF_PROFILETYPE_KEYBOARDLAYOUT, + "unexpected dwProfileType: 0x%x\n", dwProfileType); + + if(dwProfileType == TF_PROFILETYPE_INPUTPROCESSOR && IsEqualGUID(&CLSID_FakeService, clsid)){ + if(dwFlags & TF_IPSINK_FLAG_ACTIVE){ + ok(test_ShouldActivate, "OnActivated: Activation came unexpectedly\n"); + } + + fake_service_onactivated_flags = dwFlags; + } + + return S_OK; +} + +static const ITfInputProcessorProfileActivationSinkVtbl TfInputProcessorProfileActivationSinkVtbl = { + ProfileActivationSink_QueryInterface, + ProfileActivationSink_AddRef, + ProfileActivationSink_Release, + ProfileActivationSink_OnActivated +}; + +static ITfInputProcessorProfileActivationSink TfInputProcessorProfileActivationSink = { + &TfInputProcessorProfileActivationSinkVtbl +}; + static HRESULT WINAPI TfTransitoryExtensionSink_QueryInterface(ITfTransitoryExtensionSink *iface, REFIID riid, void **ppv) { if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_ITfTransitoryExtensionSink, riid)) { @@ -974,7 +1031,6 @@ static HRESULT UnregisterTextService(void) * The tests */ -DEFINE_GUID(CLSID_FakeService, 0xEDE1A7AD,0x66DE,0x47E0,0xB6,0x20,0x3E,0x92,0xF8,0x24,0x6B,0xF3); DEFINE_GUID(CLSID_TF_InputProcessorProfiles, 0x33c53a50,0xf456,0x4884,0xb0,0x49,0x85,0xfd,0x64,0x3e,0xcf,0xed); DEFINE_GUID(CLSID_TF_CategoryMgr, 0xA4B544A1,0x438D,0x4B41,0x93,0x25,0x86,0x95,0x23,0xE2,0xD6,0xC7); DEFINE_GUID(GUID_TFCAT_TIP_KEYBOARD, 0x34745c63,0xb2f0,0x4784,0x8b,0x67,0x5e,0x12,0xc8,0x70,0x1a,0x31); @@ -1198,6 +1254,10 @@ static void test_ThreadMgrAdviseSinks(void) &ui_element_sink_cookie); ok(hr == S_OK, "Failed to Advise ITfUIElementSink\n"); + hr = ITfSource_AdviseSink(source, &IID_ITfInputProcessorProfileActivationSink, (IUnknown*)&TfInputProcessorProfileActivationSink, + &profile_activation_sink_cookie); + ok(hr == S_OK, "Failed to Advise ITfInputProcessorProfileActivationSink\n"); + ITfSource_Release(source); } @@ -1221,6 +1281,9 @@ static void test_ThreadMgrUnadviseSinks(void) hr = ITfSource_UnadviseSink(source, ui_element_sink_cookie); ok(hr == S_OK, "Failed to unadvise ITfUIElementSink\n"); + hr = ITfSource_UnadviseSink(source, profile_activation_sink_cookie); + ok(hr == S_OK, "Failed to unadvise ITfInputProcessorProfileActivationSink\n"); + ITfSource_Release(source); } @@ -1618,6 +1681,8 @@ static void test_startSession(void) ok(SUCCEEDED(hr),"Failed to Activate\n"); ok(cid != tid,"TextService id mistakenly matches Client id\n"); + todo_wine ok(fake_service_onactivated_flags & TF_IPSINK_FLAG_ACTIVE, "Expected OnActivated callback\n"); + test_ShouldActivate = FALSE; hr = ITfThreadMgr_Activate(g_tm,&cid2); ok(SUCCEEDED(hr),"Failed to Activate\n"); diff --git a/dlls/msctf/threadmgr.c b/dlls/msctf/threadmgr.c index 7afef3cdd53..2c208fbc04f 100644 --- a/dlls/msctf/threadmgr.c +++ b/dlls/msctf/threadmgr.c @@ -97,6 +97,7 @@ typedef struct tagACLMulti { struct list ThreadFocusSink; struct list ThreadMgrEventSink; struct list UIElementSink; + struct list InputProcessorProfileActivationSink; } ThreadMgr; typedef struct tagEnumTfDocumentMgr { @@ -174,6 +175,7 @@ static void ThreadMgr_Destructor(ThreadMgr *This) free_sinks(&This->ThreadFocusSink); free_sinks(&This->ThreadMgrEventSink); free_sinks(&This->UIElementSink); + free_sinks(&This->InputProcessorProfileActivationSink); LIST_FOR_EACH_SAFE(cursor, cursor2, &This->CurrentPreservedKeys) { @@ -633,6 +635,13 @@ static HRESULT WINAPI ThreadMgrSource_AdviseSink(ITfSource *iface, COOKIE_MAGIC_UIELEMENTSINK, punk, pdwCookie); } + if (IsEqualIID(riid, &IID_ITfInputProcessorProfileActivationSink)) + { + WARN("semi-stub for ITfInputProcessorProfileActivationSink: sink won't be used.\n"); + return advise_sink(&This->InputProcessorProfileActivationSink, &IID_ITfInputProcessorProfileActivationSink, + COOKIE_MAGIC_INPUTPROCESSORPROFILEACTIVATIONSINK, punk, pdwCookie); + } + FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid)); return E_NOTIMPL; } @@ -646,7 +655,8 @@ static HRESULT WINAPI ThreadMgrSource_UnadviseSink(ITfSource *iface, DWORD pdwCo magic = get_Cookie_magic(pdwCookie); if (magic != COOKIE_MAGIC_TMSINK && magic != COOKIE_MAGIC_THREADFOCUSSINK - && magic != COOKIE_MAGIC_KEYTRACESINK && magic != COOKIE_MAGIC_UIELEMENTSINK) + && magic != COOKIE_MAGIC_KEYTRACESINK && magic != COOKIE_MAGIC_UIELEMENTSINK + && magic != COOKIE_MAGIC_INPUTPROCESSORPROFILEACTIVATIONSINK) return E_INVALIDARG; return unadvise_sink(pdwCookie); @@ -1364,6 +1374,7 @@ HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut) list_init(&This->ThreadFocusSink); list_init(&This->ThreadMgrEventSink); list_init(&This->UIElementSink); + list_init(&This->InputProcessorProfileActivationSink); TRACE("returning %p\n", This); *ppOut = (IUnknown *)&This->ITfThreadMgrEx_iface;