msctf: Implement ITfKeystrokeMgr::UnadviseKeyEventSink.
[wine] / dlls / msctf / threadmgr.c
1 /*
2  *  ITfThreadMgr implementation
3  *
4  *  Copyright 2008 Aric Stewart, CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22
23 #include <stdarg.h>
24
25 #define COBJMACROS
26
27 #include "wine/debug.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winreg.h"
31 #include "winuser.h"
32 #include "shlwapi.h"
33 #include "winerror.h"
34 #include "objbase.h"
35 #include "olectl.h"
36
37 #include "wine/unicode.h"
38 #include "wine/list.h"
39
40 #include "msctf.h"
41 #include "msctf_internal.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(msctf);
44
45 typedef struct tagThreadMgrSink {
46     struct list         entry;
47     union {
48         /* ThreadMgr Sinks */
49         IUnknown            *pIUnknown;
50         /* ITfActiveLanguageProfileNotifySink *pITfActiveLanguageProfileNotifySink; */
51         /* ITfDisplayAttributeNotifySink *pITfDisplayAttributeNotifySink; */
52         /* ITfKeyTraceEventSink *pITfKeyTraceEventSink; */
53         /* ITfPreservedKeyNotifySink *pITfPreservedKeyNotifySink; */
54         /* ITfThreadFocusSink *pITfThreadFocusSink; */
55         ITfThreadMgrEventSink *pITfThreadMgrEventSink;
56     } interfaces;
57 } ThreadMgrSink;
58
59 typedef struct tagPreservedKey
60 {
61     struct list     entry;
62     GUID            guid;
63     TF_PRESERVEDKEY prekey;
64     LPWSTR          description;
65     TfClientId      tid;
66 } PreservedKey;
67
68 typedef struct tagACLMulti {
69     const ITfThreadMgrVtbl *ThreadMgrVtbl;
70     const ITfSourceVtbl *SourceVtbl;
71     const ITfKeystrokeMgrVtbl *KeystrokeMgrVtbl;
72     const ITfMessagePumpVtbl *MessagePumpVtbl;
73     const ITfClientIdVtbl *ClientIdVtbl;
74     LONG refCount;
75
76     const ITfThreadMgrEventSinkVtbl *ThreadMgrEventSinkVtbl; /* internal */
77
78     ITfDocumentMgr *focus;
79     LONG activationCount;
80
81     ITfKeyEventSink *forgroundKeyEventSink;
82
83     struct list CurrentPreservedKeys;
84
85     /* kept as separate lists to reduce unnecessary iterations */
86     struct list     ActiveLanguageProfileNotifySink;
87     struct list     DisplayAttributeNotifySink;
88     struct list     KeyTraceEventSink;
89     struct list     PreservedKeyNotifySink;
90     struct list     ThreadFocusSink;
91     struct list     ThreadMgrEventSink;
92 } ThreadMgr;
93
94 static inline ThreadMgr *impl_from_ITfSourceVtbl(ITfSource *iface)
95 {
96     return (ThreadMgr *)((char *)iface - FIELD_OFFSET(ThreadMgr,SourceVtbl));
97 }
98
99 static inline ThreadMgr *impl_from_ITfKeystrokeMgrVtbl(ITfKeystrokeMgr *iface)
100 {
101     return (ThreadMgr *)((char *)iface - FIELD_OFFSET(ThreadMgr,KeystrokeMgrVtbl));
102 }
103
104 static inline ThreadMgr *impl_from_ITfMessagePumpVtbl(ITfMessagePump *iface)
105 {
106     return (ThreadMgr *)((char *)iface - FIELD_OFFSET(ThreadMgr,MessagePumpVtbl));
107 }
108
109 static inline ThreadMgr *impl_from_ITfClientIdVtbl(ITfClientId *iface)
110 {
111     return (ThreadMgr *)((char *)iface - FIELD_OFFSET(ThreadMgr,ClientIdVtbl));
112 }
113
114 static inline ThreadMgr *impl_from_ITfThreadMgrEventSink(ITfThreadMgrEventSink *iface)
115 {
116     return (ThreadMgr *)((char *)iface - FIELD_OFFSET(ThreadMgr,ThreadMgrEventSinkVtbl));
117 }
118
119 static void free_sink(ThreadMgrSink *sink)
120 {
121         IUnknown_Release(sink->interfaces.pIUnknown);
122         HeapFree(GetProcessHeap(),0,sink);
123 }
124
125 static void ThreadMgr_Destructor(ThreadMgr *This)
126 {
127     struct list *cursor, *cursor2;
128
129     TlsSetValue(tlsIndex,NULL);
130     TRACE("destroying %p\n", This);
131     if (This->focus)
132         ITfDocumentMgr_Release(This->focus);
133
134     /* free sinks */
135     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->ActiveLanguageProfileNotifySink)
136     {
137         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
138         list_remove(cursor);
139         free_sink(sink);
140     }
141     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->DisplayAttributeNotifySink)
142     {
143         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
144         list_remove(cursor);
145         free_sink(sink);
146     }
147     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->KeyTraceEventSink)
148     {
149         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
150         list_remove(cursor);
151         free_sink(sink);
152     }
153     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->PreservedKeyNotifySink)
154     {
155         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
156         list_remove(cursor);
157         free_sink(sink);
158     }
159     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->ThreadFocusSink)
160     {
161         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
162         list_remove(cursor);
163         free_sink(sink);
164     }
165     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->ThreadMgrEventSink)
166     {
167         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
168         list_remove(cursor);
169         free_sink(sink);
170     }
171
172     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->CurrentPreservedKeys)
173     {
174         PreservedKey* key = LIST_ENTRY(cursor,PreservedKey,entry);
175         list_remove(cursor);
176         HeapFree(GetProcessHeap(),0,key->description);
177         HeapFree(GetProcessHeap(),0,key);
178     }
179
180     HeapFree(GetProcessHeap(),0,This);
181 }
182
183 static HRESULT WINAPI ThreadMgr_QueryInterface(ITfThreadMgr *iface, REFIID iid, LPVOID *ppvOut)
184 {
185     ThreadMgr *This = (ThreadMgr *)iface;
186     *ppvOut = NULL;
187
188     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfThreadMgr))
189     {
190         *ppvOut = This;
191     }
192     else if (IsEqualIID(iid, &IID_ITfSource))
193     {
194         *ppvOut = &This->SourceVtbl;
195     }
196     else if (IsEqualIID(iid, &IID_ITfKeystrokeMgr))
197     {
198         *ppvOut = &This->KeystrokeMgrVtbl;
199     }
200     else if (IsEqualIID(iid, &IID_ITfMessagePump))
201     {
202         *ppvOut = &This->MessagePumpVtbl;
203     }
204     else if (IsEqualIID(iid, &IID_ITfClientId))
205     {
206         *ppvOut = &This->ClientIdVtbl;
207     }
208
209     if (*ppvOut)
210     {
211         IUnknown_AddRef(iface);
212         return S_OK;
213     }
214
215     WARN("unsupported interface: %s\n", debugstr_guid(iid));
216     return E_NOINTERFACE;
217 }
218
219 static ULONG WINAPI ThreadMgr_AddRef(ITfThreadMgr *iface)
220 {
221     ThreadMgr *This = (ThreadMgr *)iface;
222     return InterlockedIncrement(&This->refCount);
223 }
224
225 static ULONG WINAPI ThreadMgr_Release(ITfThreadMgr *iface)
226 {
227     ThreadMgr *This = (ThreadMgr *)iface;
228     ULONG ret;
229
230     ret = InterlockedDecrement(&This->refCount);
231     if (ret == 0)
232         ThreadMgr_Destructor(This);
233     return ret;
234 }
235
236 /*****************************************************
237  * ITfThreadMgr functions
238  *****************************************************/
239
240 static HRESULT WINAPI ThreadMgr_fnActivate( ITfThreadMgr* iface, TfClientId *ptid)
241 {
242     ThreadMgr *This = (ThreadMgr *)iface;
243
244     TRACE("(%p) %p\n",This, ptid);
245
246     if (!ptid)
247         return E_INVALIDARG;
248
249     if (!processId)
250     {
251         GUID guid;
252         CoCreateGuid(&guid);
253         ITfClientId_GetClientId((ITfClientId*)&This->ClientIdVtbl,&guid,&processId);
254     }
255
256     activate_textservices(iface);
257     This->activationCount++;
258     *ptid = processId;
259     return S_OK;
260 }
261
262 static HRESULT WINAPI ThreadMgr_fnDeactivate( ITfThreadMgr* iface)
263 {
264     ThreadMgr *This = (ThreadMgr *)iface;
265     TRACE("(%p)\n",This);
266
267     if (This->activationCount == 0)
268         return E_UNEXPECTED;
269
270     This->activationCount --;
271
272     if (This->activationCount == 0)
273     {
274         if (This->focus)
275         {
276             ITfThreadMgrEventSink_OnSetFocus((ITfThreadMgrEventSink*)&This->ThreadMgrEventSinkVtbl, 0, This->focus);
277             ITfDocumentMgr_Release(This->focus);
278             This->focus = 0;
279         }
280     }
281
282     deactivate_textservices();
283
284     return S_OK;
285 }
286
287 static HRESULT WINAPI ThreadMgr_CreateDocumentMgr( ITfThreadMgr* iface, ITfDocumentMgr
288 **ppdim)
289 {
290     ThreadMgr *This = (ThreadMgr *)iface;
291     TRACE("(%p)\n",iface);
292     return DocumentMgr_Constructor((ITfThreadMgrEventSink*)&This->ThreadMgrEventSinkVtbl, ppdim);
293 }
294
295 static HRESULT WINAPI ThreadMgr_EnumDocumentMgrs( ITfThreadMgr* iface, IEnumTfDocumentMgrs
296 **ppEnum)
297 {
298     ThreadMgr *This = (ThreadMgr *)iface;
299     FIXME("STUB:(%p)\n",This);
300     return E_NOTIMPL;
301 }
302
303 static HRESULT WINAPI ThreadMgr_GetFocus( ITfThreadMgr* iface, ITfDocumentMgr
304 **ppdimFocus)
305 {
306     ThreadMgr *This = (ThreadMgr *)iface;
307     TRACE("(%p)\n",This);
308
309     if (!ppdimFocus)
310         return E_INVALIDARG;
311
312     *ppdimFocus = This->focus;
313
314     TRACE("->%p\n",This->focus);
315
316     if (This->focus == NULL)
317         return S_FALSE;
318
319     ITfDocumentMgr_AddRef(This->focus);
320
321     return S_OK;
322 }
323
324 static HRESULT WINAPI ThreadMgr_SetFocus( ITfThreadMgr* iface, ITfDocumentMgr *pdimFocus)
325 {
326     ITfDocumentMgr *check;
327     ThreadMgr *This = (ThreadMgr *)iface;
328
329     TRACE("(%p) %p\n",This,pdimFocus);
330
331     if (!pdimFocus || FAILED(IUnknown_QueryInterface(pdimFocus,&IID_ITfDocumentMgr,(LPVOID*) &check)))
332         return E_INVALIDARG;
333
334     ITfThreadMgrEventSink_OnSetFocus((ITfThreadMgrEventSink*)&This->ThreadMgrEventSinkVtbl, check, This->focus);
335
336     if (This->focus)
337         ITfDocumentMgr_Release(This->focus);
338
339     This->focus = check;
340     return S_OK;
341 }
342
343 static HRESULT WINAPI ThreadMgr_AssociateFocus( ITfThreadMgr* iface, HWND hwnd,
344 ITfDocumentMgr *pdimNew, ITfDocumentMgr **ppdimPrev)
345 {
346     ThreadMgr *This = (ThreadMgr *)iface;
347     FIXME("STUB:(%p)\n",This);
348     return E_NOTIMPL;
349 }
350
351 static HRESULT WINAPI ThreadMgr_IsThreadFocus( ITfThreadMgr* iface, BOOL *pfThreadFocus)
352 {
353     ThreadMgr *This = (ThreadMgr *)iface;
354     FIXME("STUB:(%p)\n",This);
355     return E_NOTIMPL;
356 }
357
358 static HRESULT WINAPI ThreadMgr_GetFunctionProvider( ITfThreadMgr* iface, REFCLSID clsid,
359 ITfFunctionProvider **ppFuncProv)
360 {
361     ThreadMgr *This = (ThreadMgr *)iface;
362     FIXME("STUB:(%p)\n",This);
363     return E_NOTIMPL;
364 }
365
366 static HRESULT WINAPI ThreadMgr_EnumFunctionProviders( ITfThreadMgr* iface,
367 IEnumTfFunctionProviders **ppEnum)
368 {
369     ThreadMgr *This = (ThreadMgr *)iface;
370     FIXME("STUB:(%p)\n",This);
371     return E_NOTIMPL;
372 }
373
374 static HRESULT WINAPI ThreadMgr_GetGlobalCompartment( ITfThreadMgr* iface,
375 ITfCompartmentMgr **ppCompMgr)
376 {
377     ThreadMgr *This = (ThreadMgr *)iface;
378     FIXME("STUB:(%p)\n",This);
379     return E_NOTIMPL;
380 }
381
382 static const ITfThreadMgrVtbl ThreadMgr_ThreadMgrVtbl =
383 {
384     ThreadMgr_QueryInterface,
385     ThreadMgr_AddRef,
386     ThreadMgr_Release,
387
388     ThreadMgr_fnActivate,
389     ThreadMgr_fnDeactivate,
390     ThreadMgr_CreateDocumentMgr,
391     ThreadMgr_EnumDocumentMgrs,
392     ThreadMgr_GetFocus,
393     ThreadMgr_SetFocus,
394     ThreadMgr_AssociateFocus,
395     ThreadMgr_IsThreadFocus,
396     ThreadMgr_GetFunctionProvider,
397     ThreadMgr_EnumFunctionProviders,
398     ThreadMgr_GetGlobalCompartment
399 };
400
401
402 static HRESULT WINAPI Source_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut)
403 {
404     ThreadMgr *This = impl_from_ITfSourceVtbl(iface);
405     return ThreadMgr_QueryInterface((ITfThreadMgr *)This, iid, *ppvOut);
406 }
407
408 static ULONG WINAPI Source_AddRef(ITfSource *iface)
409 {
410     ThreadMgr *This = impl_from_ITfSourceVtbl(iface);
411     return ThreadMgr_AddRef((ITfThreadMgr*)This);
412 }
413
414 static ULONG WINAPI Source_Release(ITfSource *iface)
415 {
416     ThreadMgr *This = impl_from_ITfSourceVtbl(iface);
417     return ThreadMgr_Release((ITfThreadMgr *)This);
418 }
419
420 /*****************************************************
421  * ITfSource functions
422  *****************************************************/
423 static WINAPI HRESULT ThreadMgrSource_AdviseSink(ITfSource *iface,
424         REFIID riid, IUnknown *punk, DWORD *pdwCookie)
425 {
426     ThreadMgrSink *tms;
427     ThreadMgr *This = impl_from_ITfSourceVtbl(iface);
428
429     TRACE("(%p) %s %p %p\n",This,debugstr_guid(riid),punk,pdwCookie);
430
431     if (!riid || !punk || !pdwCookie)
432         return E_INVALIDARG;
433
434     if (IsEqualIID(riid, &IID_ITfThreadMgrEventSink))
435     {
436         tms = HeapAlloc(GetProcessHeap(),0,sizeof(ThreadMgrSink));
437         if (!tms)
438             return E_OUTOFMEMORY;
439         if (!SUCCEEDED(IUnknown_QueryInterface(punk, riid, (LPVOID*)&tms->interfaces.pITfThreadMgrEventSink)))
440         {
441             HeapFree(GetProcessHeap(),0,tms);
442             return CONNECT_E_CANNOTCONNECT;
443         }
444         list_add_head(&This->ThreadMgrEventSink,&tms->entry);
445         *pdwCookie = generate_Cookie(COOKIE_MAGIC_TMSINK, tms);
446     }
447     else
448     {
449         FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid));
450         return E_NOTIMPL;
451     }
452
453     TRACE("cookie %x\n",*pdwCookie);
454
455     return S_OK;
456 }
457
458 static WINAPI HRESULT ThreadMgrSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie)
459 {
460     ThreadMgrSink *sink;
461     ThreadMgr *This = impl_from_ITfSourceVtbl(iface);
462
463     TRACE("(%p) %x\n",This,pdwCookie);
464
465     if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_TMSINK)
466         return E_INVALIDARG;
467
468     sink = (ThreadMgrSink*)remove_Cookie(pdwCookie);
469     if (!sink)
470         return CONNECT_E_NOCONNECTION;
471
472     list_remove(&sink->entry);
473     free_sink(sink);
474
475     return S_OK;
476 }
477
478 static const ITfSourceVtbl ThreadMgr_SourceVtbl =
479 {
480     Source_QueryInterface,
481     Source_AddRef,
482     Source_Release,
483
484     ThreadMgrSource_AdviseSink,
485     ThreadMgrSource_UnadviseSink,
486 };
487
488 /*****************************************************
489  * ITfKeystrokeMgr functions
490  *****************************************************/
491
492 static HRESULT WINAPI KeystrokeMgr_QueryInterface(ITfKeystrokeMgr *iface, REFIID iid, LPVOID *ppvOut)
493 {
494     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
495     return ThreadMgr_QueryInterface((ITfThreadMgr *)This, iid, *ppvOut);
496 }
497
498 static ULONG WINAPI KeystrokeMgr_AddRef(ITfKeystrokeMgr *iface)
499 {
500     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
501     return ThreadMgr_AddRef((ITfThreadMgr*)This);
502 }
503
504 static ULONG WINAPI KeystrokeMgr_Release(ITfKeystrokeMgr *iface)
505 {
506     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
507     return ThreadMgr_Release((ITfThreadMgr *)This);
508 }
509
510 static HRESULT WINAPI KeystrokeMgr_AdviseKeyEventSink(ITfKeystrokeMgr *iface,
511         TfClientId tid, ITfKeyEventSink *pSink, BOOL fForeground)
512 {
513     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
514     CLSID textservice;
515     ITfKeyEventSink *check = NULL;
516
517     TRACE("(%p) %x %p %i\n",This,tid,pSink,fForeground);
518
519     if (!tid || !pSink)
520         return E_INVALIDARG;
521
522     textservice = get_textservice_clsid(tid);
523     if (IsEqualCLSID(&GUID_NULL,&textservice))
524         return E_INVALIDARG;
525
526     get_textservice_sink(tid, &IID_ITfKeyEventSink, (IUnknown**)&check);
527     if (check != NULL)
528         return CONNECT_E_ADVISELIMIT;
529
530     if (FAILED(IUnknown_QueryInterface(pSink,&IID_ITfKeyEventSink,(LPVOID*) &check)))
531         return E_INVALIDARG;
532
533     set_textservice_sink(tid, &IID_ITfKeyEventSink, (IUnknown*)check);
534
535     if (fForeground)
536     {
537         if (This->forgroundKeyEventSink)
538             ITfKeyEventSink_Release(This->forgroundKeyEventSink);
539         ITfKeyEventSink_AddRef(check);
540         This->forgroundKeyEventSink = check;
541     }
542     return S_OK;
543 }
544
545 static HRESULT WINAPI KeystrokeMgr_UnadviseKeyEventSink(ITfKeystrokeMgr *iface,
546         TfClientId tid)
547 {
548     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
549     CLSID textservice;
550     ITfKeyEventSink *check = NULL;
551     TRACE("(%p) %x\n",This,tid);
552
553     if (!tid)
554         return E_INVALIDARG;
555
556     textservice = get_textservice_clsid(tid);
557     if (IsEqualCLSID(&GUID_NULL,&textservice))
558         return E_INVALIDARG;
559
560     get_textservice_sink(tid, &IID_ITfKeyEventSink, (IUnknown**)&check);
561
562     if (!check)
563         return CONNECT_E_NOCONNECTION;
564
565     set_textservice_sink(tid, &IID_ITfKeyEventSink, NULL);
566     ITfKeyEventSink_Release(check);
567
568     if (This->forgroundKeyEventSink == check)
569     {
570         ITfKeyEventSink_Release(This->forgroundKeyEventSink);
571         This->forgroundKeyEventSink = NULL;
572     }
573     return S_OK;
574 }
575
576 static HRESULT WINAPI KeystrokeMgr_GetForeground(ITfKeystrokeMgr *iface,
577         CLSID *pclsid)
578 {
579     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
580     FIXME("STUB:(%p)\n",This);
581     return E_NOTIMPL;
582 }
583
584 static HRESULT WINAPI KeystrokeMgr_TestKeyDown(ITfKeystrokeMgr *iface,
585         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
586 {
587     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
588     FIXME("STUB:(%p)\n",This);
589     return E_NOTIMPL;
590 }
591
592 static HRESULT WINAPI KeystrokeMgr_TestKeyUp(ITfKeystrokeMgr *iface,
593         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
594 {
595     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
596     FIXME("STUB:(%p)\n",This);
597     return E_NOTIMPL;
598 }
599
600 static HRESULT WINAPI KeystrokeMgr_KeyDown(ITfKeystrokeMgr *iface,
601         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
602 {
603     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
604     FIXME("STUB:(%p)\n",This);
605     return E_NOTIMPL;
606 }
607
608 static HRESULT WINAPI KeystrokeMgr_KeyUp(ITfKeystrokeMgr *iface,
609         WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
610 {
611     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
612     FIXME("STUB:(%p)\n",This);
613     return E_NOTIMPL;
614 }
615
616 static HRESULT WINAPI KeystrokeMgr_GetPreservedKey(ITfKeystrokeMgr *iface,
617         ITfContext *pic, const TF_PRESERVEDKEY *pprekey, GUID *pguid)
618 {
619     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
620     FIXME("STUB:(%p)\n",This);
621     return E_NOTIMPL;
622 }
623
624 static HRESULT WINAPI KeystrokeMgr_IsPreservedKey(ITfKeystrokeMgr *iface,
625         REFGUID rguid, const TF_PRESERVEDKEY *pprekey, BOOL *pfRegistered)
626 {
627     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
628     struct list *cursor;
629
630     TRACE("(%p) %s (%x %x) %p\n",This,debugstr_guid(rguid), (pprekey)?pprekey->uVKey:0, (pprekey)?pprekey->uModifiers:0, pfRegistered);
631
632     if (!rguid || !pprekey || !pfRegistered)
633         return E_INVALIDARG;
634
635     LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys)
636     {
637         PreservedKey* key = LIST_ENTRY(cursor,PreservedKey,entry);
638         if (IsEqualGUID(rguid,&key->guid) && pprekey->uVKey == key->prekey.uVKey && pprekey->uModifiers == key->prekey.uModifiers)
639         {
640             *pfRegistered = TRUE;
641             return S_OK;
642         }
643     }
644
645     *pfRegistered = FALSE;
646     return S_FALSE;
647 }
648
649 static HRESULT WINAPI KeystrokeMgr_PreserveKey(ITfKeystrokeMgr *iface,
650         TfClientId tid, REFGUID rguid, const TF_PRESERVEDKEY *prekey,
651         const WCHAR *pchDesc, ULONG cchDesc)
652 {
653     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
654     struct list *cursor;
655     PreservedKey *newkey;
656
657     TRACE("(%p) %x %s (%x,%x) %s\n",This,tid, debugstr_guid(rguid),(prekey)?prekey->uVKey:0,(prekey)?prekey->uModifiers:0,debugstr_wn(pchDesc,cchDesc));
658
659     if (!tid || ! rguid || !prekey || (cchDesc && !pchDesc))
660         return E_INVALIDARG;
661
662     LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys)
663     {
664         PreservedKey* key = LIST_ENTRY(cursor,PreservedKey,entry);
665         if (IsEqualGUID(rguid,&key->guid) && prekey->uVKey == key->prekey.uVKey && prekey->uModifiers == key->prekey.uModifiers)
666             return TF_E_ALREADY_EXISTS;
667     }
668
669     newkey = HeapAlloc(GetProcessHeap(),0,sizeof(PreservedKey));
670     if (!newkey)
671         return E_OUTOFMEMORY;
672
673     newkey->guid  = *rguid;
674     newkey->prekey = *prekey;
675     newkey->tid = tid;
676     if (cchDesc)
677     {
678         newkey->description = HeapAlloc(GetProcessHeap(),0,cchDesc * sizeof(WCHAR));
679         if (!newkey->description)
680         {
681             HeapFree(GetProcessHeap(),0,newkey);
682             return E_OUTOFMEMORY;
683         }
684         memcpy(newkey->description, pchDesc, cchDesc*sizeof(WCHAR));
685     }
686
687     list_add_head(&This->CurrentPreservedKeys,&newkey->entry);
688
689     return S_OK;
690 }
691
692 static HRESULT WINAPI KeystrokeMgr_UnpreserveKey(ITfKeystrokeMgr *iface,
693         REFGUID rguid, const TF_PRESERVEDKEY *pprekey)
694 {
695     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
696     PreservedKey* key = NULL;
697     struct list *cursor;
698     TRACE("(%p) %s (%x %x)\n",This,debugstr_guid(rguid),(pprekey)?pprekey->uVKey:0, (pprekey)?pprekey->uModifiers:0);
699
700     if (!pprekey || !rguid)
701         return E_INVALIDARG;
702
703     LIST_FOR_EACH(cursor, &This->CurrentPreservedKeys)
704     {
705         key = LIST_ENTRY(cursor,PreservedKey,entry);
706         if (IsEqualGUID(rguid,&key->guid) && pprekey->uVKey == key->prekey.uVKey && pprekey->uModifiers == key->prekey.uModifiers)
707             break;
708         key = NULL;
709     }
710
711     if (!key)
712         return CONNECT_E_NOCONNECTION;
713
714     list_remove(&key->entry);
715     HeapFree(GetProcessHeap(),0,key->description);
716     HeapFree(GetProcessHeap(),0,key);
717
718     return S_OK;
719 }
720
721 static HRESULT WINAPI KeystrokeMgr_SetPreservedKeyDescription(ITfKeystrokeMgr *iface,
722         REFGUID rguid, const WCHAR *pchDesc, ULONG cchDesc)
723 {
724     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
725     FIXME("STUB:(%p)\n",This);
726     return E_NOTIMPL;
727 }
728
729 static HRESULT WINAPI KeystrokeMgr_GetPreservedKeyDescription(ITfKeystrokeMgr *iface,
730         REFGUID rguid, BSTR *pbstrDesc)
731 {
732     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
733     FIXME("STUB:(%p)\n",This);
734     return E_NOTIMPL;
735 }
736
737 static HRESULT WINAPI KeystrokeMgr_SimulatePreservedKey(ITfKeystrokeMgr *iface,
738         ITfContext *pic, REFGUID rguid, BOOL *pfEaten)
739 {
740     ThreadMgr *This = impl_from_ITfKeystrokeMgrVtbl(iface);
741     FIXME("STUB:(%p)\n",This);
742     return E_NOTIMPL;
743 }
744
745 static const ITfKeystrokeMgrVtbl ThreadMgr_KeystrokeMgrVtbl =
746 {
747     KeystrokeMgr_QueryInterface,
748     KeystrokeMgr_AddRef,
749     KeystrokeMgr_Release,
750
751     KeystrokeMgr_AdviseKeyEventSink,
752     KeystrokeMgr_UnadviseKeyEventSink,
753     KeystrokeMgr_GetForeground,
754     KeystrokeMgr_TestKeyDown,
755     KeystrokeMgr_TestKeyUp,
756     KeystrokeMgr_KeyDown,
757     KeystrokeMgr_KeyUp,
758     KeystrokeMgr_GetPreservedKey,
759     KeystrokeMgr_IsPreservedKey,
760     KeystrokeMgr_PreserveKey,
761     KeystrokeMgr_UnpreserveKey,
762     KeystrokeMgr_SetPreservedKeyDescription,
763     KeystrokeMgr_GetPreservedKeyDescription,
764     KeystrokeMgr_SimulatePreservedKey
765 };
766
767 /*****************************************************
768  * ITfMessagePump functions
769  *****************************************************/
770
771 static HRESULT WINAPI MessagePump_QueryInterface(ITfMessagePump *iface, REFIID iid, LPVOID *ppvOut)
772 {
773     ThreadMgr *This = impl_from_ITfMessagePumpVtbl(iface);
774     return ThreadMgr_QueryInterface((ITfThreadMgr *)This, iid, *ppvOut);
775 }
776
777 static ULONG WINAPI MessagePump_AddRef(ITfMessagePump *iface)
778 {
779     ThreadMgr *This = impl_from_ITfMessagePumpVtbl(iface);
780     return ThreadMgr_AddRef((ITfThreadMgr*)This);
781 }
782
783 static ULONG WINAPI MessagePump_Release(ITfMessagePump *iface)
784 {
785     ThreadMgr *This = impl_from_ITfMessagePumpVtbl(iface);
786     return ThreadMgr_Release((ITfThreadMgr *)This);
787 }
788
789 static HRESULT WINAPI MessagePump_PeekMessageA(ITfMessagePump *iface,
790         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
791         UINT wRemoveMsg, BOOL *pfResult)
792 {
793     if (!pfResult)
794         return E_INVALIDARG;
795     *pfResult = PeekMessageA(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
796     return S_OK;
797 }
798
799 static HRESULT WINAPI MessagePump_GetMessageA(ITfMessagePump *iface,
800         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
801         BOOL *pfResult)
802 {
803     if (!pfResult)
804         return E_INVALIDARG;
805     *pfResult = GetMessageA(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax);
806     return S_OK;
807 }
808
809 static HRESULT WINAPI MessagePump_PeekMessageW(ITfMessagePump *iface,
810         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
811         UINT wRemoveMsg, BOOL *pfResult)
812 {
813     if (!pfResult)
814         return E_INVALIDARG;
815     *pfResult = PeekMessageW(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
816     return S_OK;
817 }
818
819 static HRESULT WINAPI MessagePump_GetMessageW(ITfMessagePump *iface,
820         LPMSG pMsg, HWND hwnd, UINT wMsgFilterMin, UINT wMsgFilterMax,
821         BOOL *pfResult)
822 {
823     if (!pfResult)
824         return E_INVALIDARG;
825     *pfResult = GetMessageW(pMsg, hwnd, wMsgFilterMin, wMsgFilterMax);
826     return S_OK;
827 }
828
829 static const ITfMessagePumpVtbl ThreadMgr_MessagePumpVtbl =
830 {
831     MessagePump_QueryInterface,
832     MessagePump_AddRef,
833     MessagePump_Release,
834
835     MessagePump_PeekMessageA,
836     MessagePump_GetMessageA,
837     MessagePump_PeekMessageW,
838     MessagePump_GetMessageW
839 };
840
841 /*****************************************************
842  * ITfClientId functions
843  *****************************************************/
844
845 static HRESULT WINAPI ClientId_QueryInterface(ITfClientId *iface, REFIID iid, LPVOID *ppvOut)
846 {
847     ThreadMgr *This = impl_from_ITfClientIdVtbl(iface);
848     return ThreadMgr_QueryInterface((ITfThreadMgr *)This, iid, *ppvOut);
849 }
850
851 static ULONG WINAPI ClientId_AddRef(ITfClientId *iface)
852 {
853     ThreadMgr *This = impl_from_ITfClientIdVtbl(iface);
854     return ThreadMgr_AddRef((ITfThreadMgr*)This);
855 }
856
857 static ULONG WINAPI ClientId_Release(ITfClientId *iface)
858 {
859     ThreadMgr *This = impl_from_ITfClientIdVtbl(iface);
860     return ThreadMgr_Release((ITfThreadMgr *)This);
861 }
862
863 static HRESULT WINAPI ClientId_GetClientId(ITfClientId *iface,
864     REFCLSID rclsid, TfClientId *ptid)
865
866 {
867     HRESULT hr;
868     ITfCategoryMgr *catmgr;
869     ThreadMgr *This = impl_from_ITfClientIdVtbl(iface);
870
871     TRACE("(%p) %s\n",This,debugstr_guid(rclsid));
872
873     CategoryMgr_Constructor(NULL,(IUnknown**)&catmgr);
874     hr = ITfCategoryMgr_RegisterGUID(catmgr,rclsid,ptid);
875     ITfCategoryMgr_Release(catmgr);
876
877     return hr;
878 }
879
880 static const ITfClientIdVtbl ThreadMgr_ClientIdVtbl =
881 {
882     ClientId_QueryInterface,
883     ClientId_AddRef,
884     ClientId_Release,
885
886     ClientId_GetClientId
887 };
888
889 /*****************************************************
890  * ITfThreadMgrEventSink functions  (internal)
891  *****************************************************/
892 static HRESULT WINAPI ThreadMgrEventSink_QueryInterface(ITfThreadMgrEventSink *iface, REFIID iid, LPVOID *ppvOut)
893 {
894     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
895     return ThreadMgr_QueryInterface((ITfThreadMgr *)This, iid, *ppvOut);
896 }
897
898 static ULONG WINAPI ThreadMgrEventSink_AddRef(ITfThreadMgrEventSink *iface)
899 {
900     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
901     return ThreadMgr_AddRef((ITfThreadMgr*)This);
902 }
903
904 static ULONG WINAPI ThreadMgrEventSink_Release(ITfThreadMgrEventSink *iface)
905 {
906     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
907     return ThreadMgr_Release((ITfThreadMgr *)This);
908 }
909
910
911 static WINAPI HRESULT ThreadMgrEventSink_OnInitDocumentMgr(
912         ITfThreadMgrEventSink *iface,ITfDocumentMgr *pdim)
913 {
914     struct list *cursor;
915     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
916
917     TRACE("(%p) %p\n",This,pdim);
918
919     LIST_FOR_EACH(cursor, &This->ThreadMgrEventSink)
920     {
921         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
922         ITfThreadMgrEventSink_OnInitDocumentMgr(sink->interfaces.pITfThreadMgrEventSink,pdim);
923     }
924
925     return S_OK;
926 }
927
928 static WINAPI HRESULT ThreadMgrEventSink_OnUninitDocumentMgr(
929         ITfThreadMgrEventSink *iface, ITfDocumentMgr *pdim)
930 {
931     struct list *cursor;
932     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
933
934     TRACE("(%p) %p\n",This,pdim);
935
936     LIST_FOR_EACH(cursor, &This->ThreadMgrEventSink)
937     {
938         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
939         ITfThreadMgrEventSink_OnUninitDocumentMgr(sink->interfaces.pITfThreadMgrEventSink,pdim);
940     }
941
942     return S_OK;
943 }
944
945 static WINAPI HRESULT ThreadMgrEventSink_OnSetFocus(
946         ITfThreadMgrEventSink *iface, ITfDocumentMgr *pdimFocus,
947         ITfDocumentMgr *pdimPrevFocus)
948 {
949     struct list *cursor;
950     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
951
952     TRACE("(%p) %p %p\n",This,pdimFocus, pdimPrevFocus);
953
954     LIST_FOR_EACH(cursor, &This->ThreadMgrEventSink)
955     {
956         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
957         ITfThreadMgrEventSink_OnSetFocus(sink->interfaces.pITfThreadMgrEventSink, pdimFocus, pdimPrevFocus);
958     }
959
960     return S_OK;
961 }
962
963 static WINAPI HRESULT ThreadMgrEventSink_OnPushContext(
964         ITfThreadMgrEventSink *iface, ITfContext *pic)
965 {
966     struct list *cursor;
967     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
968
969     TRACE("(%p) %p\n",This,pic);
970
971     LIST_FOR_EACH(cursor, &This->ThreadMgrEventSink)
972     {
973         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
974         ITfThreadMgrEventSink_OnPushContext(sink->interfaces.pITfThreadMgrEventSink,pic);
975     }
976
977     return S_OK;
978 }
979
980 static WINAPI HRESULT ThreadMgrEventSink_OnPopContext(
981         ITfThreadMgrEventSink *iface, ITfContext *pic)
982 {
983     struct list *cursor;
984     ThreadMgr *This = impl_from_ITfThreadMgrEventSink(iface);
985
986     TRACE("(%p) %p\n",This,pic);
987
988     LIST_FOR_EACH(cursor, &This->ThreadMgrEventSink)
989     {
990         ThreadMgrSink* sink = LIST_ENTRY(cursor,ThreadMgrSink,entry);
991         ITfThreadMgrEventSink_OnPopContext(sink->interfaces.pITfThreadMgrEventSink,pic);
992     }
993
994     return S_OK;
995 }
996
997 static const ITfThreadMgrEventSinkVtbl ThreadMgr_ThreadMgrEventSinkVtbl =
998 {
999     ThreadMgrEventSink_QueryInterface,
1000     ThreadMgrEventSink_AddRef,
1001     ThreadMgrEventSink_Release,
1002
1003     ThreadMgrEventSink_OnInitDocumentMgr,
1004     ThreadMgrEventSink_OnUninitDocumentMgr,
1005     ThreadMgrEventSink_OnSetFocus,
1006     ThreadMgrEventSink_OnPushContext,
1007     ThreadMgrEventSink_OnPopContext
1008 };
1009
1010 HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut)
1011 {
1012     ThreadMgr *This;
1013     if (pUnkOuter)
1014         return CLASS_E_NOAGGREGATION;
1015
1016     /* Only 1 ThreadMgr is created per thread */
1017     This = TlsGetValue(tlsIndex);
1018     if (This)
1019     {
1020         ThreadMgr_AddRef((ITfThreadMgr*)This);
1021         *ppOut = (IUnknown*)This;
1022         return S_OK;
1023     }
1024
1025     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ThreadMgr));
1026     if (This == NULL)
1027         return E_OUTOFMEMORY;
1028
1029     This->ThreadMgrVtbl= &ThreadMgr_ThreadMgrVtbl;
1030     This->SourceVtbl = &ThreadMgr_SourceVtbl;
1031     This->KeystrokeMgrVtbl= &ThreadMgr_KeystrokeMgrVtbl;
1032     This->MessagePumpVtbl= &ThreadMgr_MessagePumpVtbl;
1033     This->ClientIdVtbl = &ThreadMgr_ClientIdVtbl;
1034     This->ThreadMgrEventSinkVtbl = &ThreadMgr_ThreadMgrEventSinkVtbl;
1035     This->refCount = 1;
1036     TlsSetValue(tlsIndex,This);
1037
1038     list_init(&This->CurrentPreservedKeys);
1039
1040     list_init(&This->ActiveLanguageProfileNotifySink);
1041     list_init(&This->DisplayAttributeNotifySink);
1042     list_init(&This->KeyTraceEventSink);
1043     list_init(&This->PreservedKeyNotifySink);
1044     list_init(&This->ThreadFocusSink);
1045     list_init(&This->ThreadMgrEventSink);
1046
1047     TRACE("returning %p\n", This);
1048     *ppOut = (IUnknown *)This;
1049     return S_OK;
1050 }