[IMM32] Sync with Wine Staging 4.18. CORE-16441
[reactos.git] / dll / win32 / imm32 / imm.c
1 /*
2 * IMM32 library
3 *
4 * Copyright 1998 Patrik Stridvall
5 * Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include <stdarg.h>
23 #include <stdio.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winerror.h"
30 #include "wine/debug.h"
31 #include "imm.h"
32 #include "ddk/imm.h"
33 #include "winnls.h"
34 #include "winreg.h"
35 #include "wine/list.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(imm);
38
39 #define IMM_INIT_MAGIC 0x19650412
40 BOOL WINAPI User32InitializeImmEntryTable(DWORD);
41
42 typedef struct _tagImmHkl{
43 struct list entry;
44 HKL hkl;
45 HMODULE hIME;
46 IMEINFO imeInfo;
47 WCHAR imeClassName[17]; /* 16 character max */
48 ULONG uSelected;
49 HWND UIWnd;
50
51 /* Function Pointers */
52 BOOL (WINAPI *pImeInquire)(IMEINFO *, WCHAR *, const WCHAR *);
53 BOOL (WINAPI *pImeConfigure)(HKL, HWND, DWORD, void *);
54 BOOL (WINAPI *pImeDestroy)(UINT);
55 LRESULT (WINAPI *pImeEscape)(HIMC, UINT, void *);
56 BOOL (WINAPI *pImeSelect)(HIMC, BOOL);
57 BOOL (WINAPI *pImeSetActiveContext)(HIMC, BOOL);
58 UINT (WINAPI *pImeToAsciiEx)(UINT, UINT, const BYTE *, DWORD *, UINT, HIMC);
59 BOOL (WINAPI *pNotifyIME)(HIMC, DWORD, DWORD, DWORD);
60 BOOL (WINAPI *pImeRegisterWord)(const WCHAR *, DWORD, const WCHAR *);
61 BOOL (WINAPI *pImeUnregisterWord)(const WCHAR *, DWORD, const WCHAR *);
62 UINT (WINAPI *pImeEnumRegisterWord)(REGISTERWORDENUMPROCW, const WCHAR *, DWORD, const WCHAR *, void *);
63 BOOL (WINAPI *pImeSetCompositionString)(HIMC, DWORD, const void *, DWORD, const void *, DWORD);
64 DWORD (WINAPI *pImeConversionList)(HIMC, const WCHAR *, CANDIDATELIST *, DWORD, UINT);
65 BOOL (WINAPI *pImeProcessKey)(HIMC, UINT, LPARAM, const BYTE *);
66 UINT (WINAPI *pImeGetRegisterWordStyle)(UINT, STYLEBUFW *);
67 DWORD (WINAPI *pImeGetImeMenuItems)(HIMC, DWORD, DWORD, IMEMENUITEMINFOW *, IMEMENUITEMINFOW *, DWORD);
68 } ImmHkl;
69
70 typedef struct tagInputContextData
71 {
72 DWORD dwLock;
73 INPUTCONTEXT IMC;
74 DWORD threadID;
75
76 ImmHkl *immKbd;
77 UINT lastVK;
78 BOOL threadDefault;
79 DWORD magic;
80 } InputContextData;
81
82 #define WINE_IMC_VALID_MAGIC 0x56434D49
83
84 typedef struct _tagTRANSMSG {
85 UINT message;
86 WPARAM wParam;
87 LPARAM lParam;
88 } TRANSMSG, *LPTRANSMSG;
89
90 typedef struct _tagIMMThreadData {
91 struct list entry;
92 DWORD threadID;
93 HIMC defaultContext;
94 HWND hwndDefault;
95 BOOL disableIME;
96 DWORD windowRefs;
97 } IMMThreadData;
98
99 static struct list ImmHklList = LIST_INIT(ImmHklList);
100 static struct list ImmThreadDataList = LIST_INIT(ImmThreadDataList);
101
102 static const WCHAR szwWineIMCProperty[] = {'W','i','n','e','I','m','m','H','I','M','C','P','r','o','p','e','r','t','y',0};
103
104 static const WCHAR szImeFileW[] = {'I','m','e',' ','F','i','l','e',0};
105 static const WCHAR szLayoutTextW[] = {'L','a','y','o','u','t',' ','T','e','x','t',0};
106 static const WCHAR szImeRegFmt[] = {'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s','\\','%','0','8','l','x',0};
107
108 static const WCHAR szwIME[] = {'I','M','E',0};
109 static const WCHAR szwDefaultIME[] = {'D','e','f','a','u','l','t',' ','I','M','E',0};
110
111 static CRITICAL_SECTION threaddata_cs;
112 static CRITICAL_SECTION_DEBUG critsect_debug =
113 {
114 0, 0, &threaddata_cs,
115 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
116 0, 0, { (DWORD_PTR)(__FILE__ ": threaddata_cs") }
117 };
118 static CRITICAL_SECTION threaddata_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
119 static BOOL disable_ime;
120
121 static inline BOOL is_himc_ime_unicode(const InputContextData *data)
122 {
123 return !!(data->immKbd->imeInfo.fdwProperty & IME_PROP_UNICODE);
124 }
125
126 static inline BOOL is_kbd_ime_unicode(const ImmHkl *hkl)
127 {
128 return !!(hkl->imeInfo.fdwProperty & IME_PROP_UNICODE);
129 }
130
131 static BOOL IMM_DestroyContext(HIMC hIMC);
132 static InputContextData* get_imc_data(HIMC hIMC);
133
134 static inline WCHAR *strdupAtoW( const char *str )
135 {
136 WCHAR *ret = NULL;
137 if (str)
138 {
139 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
140 if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
141 MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
142 }
143 return ret;
144 }
145
146 static inline CHAR *strdupWtoA( const WCHAR *str )
147 {
148 CHAR *ret = NULL;
149 if (str)
150 {
151 DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
152 if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
153 WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
154 }
155 return ret;
156 }
157
158 static DWORD convert_candidatelist_WtoA(
159 LPCANDIDATELIST lpSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen)
160 {
161 DWORD ret, i, len;
162
163 ret = FIELD_OFFSET( CANDIDATELIST, dwOffset[lpSrc->dwCount] );
164 if ( lpDst && dwBufLen > 0 )
165 {
166 *lpDst = *lpSrc;
167 lpDst->dwOffset[0] = ret;
168 }
169
170 for ( i = 0; i < lpSrc->dwCount; i++)
171 {
172 LPBYTE src = (LPBYTE)lpSrc + lpSrc->dwOffset[i];
173
174 if ( lpDst && dwBufLen > 0 )
175 {
176 LPBYTE dest = (LPBYTE)lpDst + lpDst->dwOffset[i];
177
178 len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1,
179 (LPSTR)dest, dwBufLen, NULL, NULL);
180
181 if ( i + 1 < lpSrc->dwCount )
182 lpDst->dwOffset[i+1] = lpDst->dwOffset[i] + len * sizeof(char);
183 dwBufLen -= len * sizeof(char);
184 }
185 else
186 len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1, NULL, 0, NULL, NULL);
187
188 ret += len * sizeof(char);
189 }
190
191 if ( lpDst )
192 lpDst->dwSize = ret;
193
194 return ret;
195 }
196
197 static DWORD convert_candidatelist_AtoW(
198 LPCANDIDATELIST lpSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen)
199 {
200 DWORD ret, i, len;
201
202 ret = FIELD_OFFSET( CANDIDATELIST, dwOffset[lpSrc->dwCount] );
203 if ( lpDst && dwBufLen > 0 )
204 {
205 *lpDst = *lpSrc;
206 lpDst->dwOffset[0] = ret;
207 }
208
209 for ( i = 0; i < lpSrc->dwCount; i++)
210 {
211 LPBYTE src = (LPBYTE)lpSrc + lpSrc->dwOffset[i];
212
213 if ( lpDst && dwBufLen > 0 )
214 {
215 LPBYTE dest = (LPBYTE)lpDst + lpDst->dwOffset[i];
216
217 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1,
218 (LPWSTR)dest, dwBufLen);
219
220 if ( i + 1 < lpSrc->dwCount )
221 lpDst->dwOffset[i+1] = lpDst->dwOffset[i] + len * sizeof(WCHAR);
222 dwBufLen -= len * sizeof(WCHAR);
223 }
224 else
225 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1, NULL, 0);
226
227 ret += len * sizeof(WCHAR);
228 }
229
230 if ( lpDst )
231 lpDst->dwSize = ret;
232
233 return ret;
234 }
235
236 static IMMThreadData *IMM_GetThreadData(HWND hwnd, DWORD thread)
237 {
238 IMMThreadData *data;
239 DWORD process;
240
241 if (hwnd)
242 {
243 if (!(thread = GetWindowThreadProcessId(hwnd, &process))) return NULL;
244 if (process != GetCurrentProcessId()) return NULL;
245 }
246 else if (thread)
247 {
248 HANDLE h = OpenThread(THREAD_QUERY_INFORMATION, FALSE, thread);
249 if (!h) return NULL;
250 process = GetProcessIdOfThread(h);
251 CloseHandle(h);
252 if (process != GetCurrentProcessId()) return NULL;
253 }
254 else
255 thread = GetCurrentThreadId();
256
257 EnterCriticalSection(&threaddata_cs);
258 LIST_FOR_EACH_ENTRY(data, &ImmThreadDataList, IMMThreadData, entry)
259 if (data->threadID == thread) return data;
260
261 data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data));
262 data->threadID = thread;
263 list_add_head(&ImmThreadDataList,&data->entry);
264 TRACE("Thread Data Created (%x)\n",thread);
265 return data;
266 }
267
268 static BOOL IMM_IsDefaultContext(HIMC imc)
269 {
270 InputContextData *data = get_imc_data(imc);
271
272 if (!data)
273 return FALSE;
274
275 return data->threadDefault;
276 }
277
278 static void IMM_FreeThreadData(void)
279 {
280 IMMThreadData *data;
281
282 EnterCriticalSection(&threaddata_cs);
283 LIST_FOR_EACH_ENTRY(data, &ImmThreadDataList, IMMThreadData, entry)
284 {
285 if (data->threadID == GetCurrentThreadId())
286 {
287 list_remove(&data->entry);
288 LeaveCriticalSection(&threaddata_cs);
289 IMM_DestroyContext(data->defaultContext);
290 HeapFree(GetProcessHeap(),0,data);
291 TRACE("Thread Data Destroyed\n");
292 return;
293 }
294 }
295 LeaveCriticalSection(&threaddata_cs);
296 }
297
298 static HMODULE load_graphics_driver(void)
299 {
300 static const WCHAR display_device_guid_propW[] = {
301 '_','_','w','i','n','e','_','d','i','s','p','l','a','y','_',
302 'd','e','v','i','c','e','_','g','u','i','d',0 };
303 static const WCHAR key_pathW[] = {
304 'S','y','s','t','e','m','\\',
305 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
306 'C','o','n','t','r','o','l','\\',
307 'V','i','d','e','o','\\','{',0};
308 static const WCHAR displayW[] = {'}','\\','0','0','0','0',0};
309 static const WCHAR driverW[] = {'G','r','a','p','h','i','c','s','D','r','i','v','e','r',0};
310
311 HMODULE ret = 0;
312 HKEY hkey;
313 DWORD size;
314 WCHAR path[MAX_PATH];
315 WCHAR key[ARRAY_SIZE( key_pathW ) + ARRAY_SIZE( displayW ) + 40];
316 UINT guid_atom = HandleToULong( GetPropW( GetDesktopWindow(), display_device_guid_propW ));
317
318 if (!guid_atom) return 0;
319 memcpy( key, key_pathW, sizeof(key_pathW) );
320 if (!GlobalGetAtomNameW( guid_atom, key + lstrlenW(key), 40 )) return 0;
321 lstrcatW( key, displayW );
322 if (RegOpenKeyW( HKEY_LOCAL_MACHINE, key, &hkey )) return 0;
323 size = sizeof(path);
324 if (!RegQueryValueExW( hkey, driverW, NULL, NULL, (BYTE *)path, &size )) ret = LoadLibraryW( path );
325 RegCloseKey( hkey );
326 TRACE( "%s %p\n", debugstr_w(path), ret );
327 return ret;
328 }
329
330 /* ImmHkl loading and freeing */
331 #define LOAD_FUNCPTR(f) if((ptr->p##f = (LPVOID)GetProcAddress(ptr->hIME, #f)) == NULL){WARN("Can't find function %s in ime\n", #f);}
332 static ImmHkl *IMM_GetImmHkl(HKL hkl)
333 {
334 ImmHkl *ptr;
335 WCHAR filename[MAX_PATH];
336
337 TRACE("Seeking ime for keyboard %p\n",hkl);
338
339 LIST_FOR_EACH_ENTRY(ptr, &ImmHklList, ImmHkl, entry)
340 {
341 if (ptr->hkl == hkl)
342 return ptr;
343 }
344 /* not found... create it */
345
346 ptr = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ImmHkl));
347
348 ptr->hkl = hkl;
349 if (ImmGetIMEFileNameW(hkl, filename, MAX_PATH)) ptr->hIME = LoadLibraryW(filename);
350 if (!ptr->hIME) ptr->hIME = load_graphics_driver();
351 if (ptr->hIME)
352 {
353 LOAD_FUNCPTR(ImeInquire);
354 if (!ptr->pImeInquire || !ptr->pImeInquire(&ptr->imeInfo, ptr->imeClassName, NULL))
355 {
356 FreeLibrary(ptr->hIME);
357 ptr->hIME = NULL;
358 }
359 else
360 {
361 LOAD_FUNCPTR(ImeDestroy);
362 LOAD_FUNCPTR(ImeSelect);
363 if (!ptr->pImeSelect || !ptr->pImeDestroy)
364 {
365 FreeLibrary(ptr->hIME);
366 ptr->hIME = NULL;
367 }
368 else
369 {
370 LOAD_FUNCPTR(ImeConfigure);
371 LOAD_FUNCPTR(ImeEscape);
372 LOAD_FUNCPTR(ImeSetActiveContext);
373 LOAD_FUNCPTR(ImeToAsciiEx);
374 LOAD_FUNCPTR(NotifyIME);
375 LOAD_FUNCPTR(ImeRegisterWord);
376 LOAD_FUNCPTR(ImeUnregisterWord);
377 LOAD_FUNCPTR(ImeEnumRegisterWord);
378 LOAD_FUNCPTR(ImeSetCompositionString);
379 LOAD_FUNCPTR(ImeConversionList);
380 LOAD_FUNCPTR(ImeProcessKey);
381 LOAD_FUNCPTR(ImeGetRegisterWordStyle);
382 LOAD_FUNCPTR(ImeGetImeMenuItems);
383 /* make sure our classname is WCHAR */
384 if (!is_kbd_ime_unicode(ptr))
385 {
386 WCHAR bufW[17];
387 MultiByteToWideChar(CP_ACP, 0, (LPSTR)ptr->imeClassName,
388 -1, bufW, 17);
389 lstrcpyW(ptr->imeClassName, bufW);
390 }
391 }
392 }
393 }
394 list_add_head(&ImmHklList,&ptr->entry);
395
396 return ptr;
397 }
398 #undef LOAD_FUNCPTR
399
400 HWND WINAPI __wine_get_ui_window(HKL hkl)
401 {
402 ImmHkl *immHkl = IMM_GetImmHkl(hkl);
403 return immHkl->UIWnd;
404 }
405
406 static void IMM_FreeAllImmHkl(void)
407 {
408 ImmHkl *ptr,*cursor2;
409
410 LIST_FOR_EACH_ENTRY_SAFE(ptr, cursor2, &ImmHklList, ImmHkl, entry)
411 {
412 list_remove(&ptr->entry);
413 if (ptr->hIME)
414 {
415 ptr->pImeDestroy(1);
416 FreeLibrary(ptr->hIME);
417 }
418 if (ptr->UIWnd)
419 DestroyWindow(ptr->UIWnd);
420 HeapFree(GetProcessHeap(),0,ptr);
421 }
422 }
423
424 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved)
425 {
426 TRACE("%p, %x, %p\n",hInstDLL,fdwReason,lpReserved);
427 switch (fdwReason)
428 {
429 case DLL_PROCESS_ATTACH:
430 if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC))
431 {
432 return FALSE;
433 }
434 break;
435 case DLL_THREAD_ATTACH:
436 break;
437 case DLL_THREAD_DETACH:
438 IMM_FreeThreadData();
439 break;
440 case DLL_PROCESS_DETACH:
441 if (lpReserved) break;
442 IMM_FreeThreadData();
443 IMM_FreeAllImmHkl();
444 break;
445 }
446 return TRUE;
447 }
448
449 /* for posting messages as the IME */
450 static void ImmInternalPostIMEMessage(InputContextData *data, UINT msg, WPARAM wParam, LPARAM lParam)
451 {
452 HWND target = GetFocus();
453 if (!target)
454 PostMessageW(data->IMC.hWnd,msg,wParam,lParam);
455 else
456 PostMessageW(target, msg, wParam, lParam);
457 }
458
459 /* for sending messages as the IME */
460 static void ImmInternalSendIMEMessage(InputContextData *data, UINT msg, WPARAM wParam, LPARAM lParam)
461 {
462 HWND target = GetFocus();
463 if (!target)
464 SendMessageW(data->IMC.hWnd,msg,wParam,lParam);
465 else
466 SendMessageW(target, msg, wParam, lParam);
467 }
468
469 static LRESULT ImmInternalSendIMENotify(InputContextData *data, WPARAM notify, LPARAM lParam)
470 {
471 HWND target;
472
473 target = data->IMC.hWnd;
474 if (!target) target = GetFocus();
475
476 if (target)
477 return SendMessageW(target, WM_IME_NOTIFY, notify, lParam);
478
479 return 0;
480 }
481
482 static HIMCC ImmCreateBlankCompStr(void)
483 {
484 HIMCC rc;
485 LPCOMPOSITIONSTRING ptr;
486 rc = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
487 ptr = ImmLockIMCC(rc);
488 memset(ptr,0,sizeof(COMPOSITIONSTRING));
489 ptr->dwSize = sizeof(COMPOSITIONSTRING);
490 ImmUnlockIMCC(rc);
491 return rc;
492 }
493
494 static InputContextData* get_imc_data(HIMC hIMC)
495 {
496 InputContextData *data = hIMC;
497
498 if (hIMC == NULL)
499 return NULL;
500
501 if(IsBadReadPtr(data, sizeof(InputContextData)) || data->magic != WINE_IMC_VALID_MAGIC)
502 {
503 SetLastError(ERROR_INVALID_HANDLE);
504 return NULL;
505 }
506 return data;
507 }
508
509 static HIMC get_default_context( HWND hwnd )
510 {
511 HIMC ret;
512 IMMThreadData* thread_data = IMM_GetThreadData( hwnd, 0 );
513
514 if (!thread_data) return 0;
515
516 if (thread_data->defaultContext)
517 {
518 ret = thread_data->defaultContext;
519 LeaveCriticalSection(&threaddata_cs);
520 return ret;
521 }
522
523 /* can't create a default context in another thread */
524 if (thread_data->threadID != GetCurrentThreadId())
525 {
526 LeaveCriticalSection(&threaddata_cs);
527 return 0;
528 }
529
530 LeaveCriticalSection(&threaddata_cs);
531
532 ret = ImmCreateContext();
533 if (!ret) return 0;
534 ((InputContextData*)ret)->threadDefault = TRUE;
535
536 /* thread_data is in the current thread so we can assume it's still valid */
537 EnterCriticalSection(&threaddata_cs);
538
539 if (thread_data->defaultContext) /* someone beat us */
540 {
541 IMM_DestroyContext( ret );
542 ret = thread_data->defaultContext;
543 }
544 else thread_data->defaultContext = ret;
545
546 LeaveCriticalSection(&threaddata_cs);
547 return ret;
548 }
549
550 static BOOL IMM_IsCrossThreadAccess(HWND hWnd, HIMC hIMC)
551 {
552 InputContextData *data;
553
554 if (hWnd)
555 {
556 DWORD thread = GetWindowThreadProcessId(hWnd, NULL);
557 if (thread != GetCurrentThreadId()) return TRUE;
558 }
559 data = get_imc_data(hIMC);
560 if (data && data->threadID != GetCurrentThreadId())
561 return TRUE;
562
563 return FALSE;
564 }
565
566 /***********************************************************************
567 * ImmAssociateContext (IMM32.@)
568 */
569 HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
570 {
571 HIMC old = NULL;
572 InputContextData *data = get_imc_data(hIMC);
573
574 TRACE("(%p, %p):\n", hWnd, hIMC);
575
576 if(hIMC && !data)
577 return NULL;
578
579 /*
580 * If already associated just return
581 */
582 if (hIMC && data->IMC.hWnd == hWnd)
583 return hIMC;
584
585 if (hIMC && IMM_IsCrossThreadAccess(hWnd, hIMC))
586 return NULL;
587
588 if (hWnd)
589 {
590 HIMC defaultContext = get_default_context( hWnd );
591 old = RemovePropW(hWnd,szwWineIMCProperty);
592
593 if (old == NULL)
594 old = defaultContext;
595 else if (old == (HIMC)-1)
596 old = NULL;
597
598 if (hIMC != defaultContext)
599 {
600 if (hIMC == NULL) /* Meaning disable imm for that window*/
601 SetPropW(hWnd,szwWineIMCProperty,(HANDLE)-1);
602 else
603 SetPropW(hWnd,szwWineIMCProperty,hIMC);
604 }
605
606 if (old)
607 {
608 InputContextData *old_data = old;
609 if (old_data->IMC.hWnd == hWnd)
610 old_data->IMC.hWnd = NULL;
611 }
612 }
613
614 if (!hIMC)
615 return old;
616
617 if(GetActiveWindow() == data->IMC.hWnd)
618 {
619 SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, FALSE, ISC_SHOWUIALL);
620 data->IMC.hWnd = hWnd;
621 SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, TRUE, ISC_SHOWUIALL);
622 }
623
624 return old;
625 }
626
627
628 /*
629 * Helper function for ImmAssociateContextEx
630 */
631 static BOOL CALLBACK _ImmAssociateContextExEnumProc(HWND hwnd, LPARAM lParam)
632 {
633 HIMC hImc = (HIMC)lParam;
634 ImmAssociateContext(hwnd,hImc);
635 return TRUE;
636 }
637
638 /***********************************************************************
639 * ImmAssociateContextEx (IMM32.@)
640 */
641 BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags)
642 {
643 TRACE("(%p, %p, 0x%x):\n", hWnd, hIMC, dwFlags);
644
645 if (!hWnd)
646 return FALSE;
647
648 switch (dwFlags)
649 {
650 case 0:
651 ImmAssociateContext(hWnd,hIMC);
652 return TRUE;
653 case IACE_DEFAULT:
654 {
655 HIMC defaultContext = get_default_context( hWnd );
656 if (!defaultContext) return FALSE;
657 ImmAssociateContext(hWnd,defaultContext);
658 return TRUE;
659 }
660 case IACE_IGNORENOCONTEXT:
661 if (GetPropW(hWnd,szwWineIMCProperty))
662 ImmAssociateContext(hWnd,hIMC);
663 return TRUE;
664 case IACE_CHILDREN:
665 EnumChildWindows(hWnd,_ImmAssociateContextExEnumProc,(LPARAM)hIMC);
666 return TRUE;
667 default:
668 FIXME("Unknown dwFlags 0x%x\n",dwFlags);
669 return FALSE;
670 }
671 }
672
673 /***********************************************************************
674 * ImmConfigureIMEA (IMM32.@)
675 */
676 BOOL WINAPI ImmConfigureIMEA(
677 HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
678 {
679 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
680
681 TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData);
682
683 if (dwMode == IME_CONFIG_REGISTERWORD && !lpData)
684 return FALSE;
685
686 if (immHkl->hIME && immHkl->pImeConfigure)
687 {
688 if (dwMode != IME_CONFIG_REGISTERWORD || !is_kbd_ime_unicode(immHkl))
689 return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData);
690 else
691 {
692 REGISTERWORDW rww;
693 REGISTERWORDA *rwa = lpData;
694 BOOL rc;
695
696 rww.lpReading = strdupAtoW(rwa->lpReading);
697 rww.lpWord = strdupAtoW(rwa->lpWord);
698 rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rww);
699 HeapFree(GetProcessHeap(),0,rww.lpReading);
700 HeapFree(GetProcessHeap(),0,rww.lpWord);
701 return rc;
702 }
703 }
704 else
705 return FALSE;
706 }
707
708 /***********************************************************************
709 * ImmConfigureIMEW (IMM32.@)
710 */
711 BOOL WINAPI ImmConfigureIMEW(
712 HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
713 {
714 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
715
716 TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData);
717
718 if (dwMode == IME_CONFIG_REGISTERWORD && !lpData)
719 return FALSE;
720
721 if (immHkl->hIME && immHkl->pImeConfigure)
722 {
723 if (dwMode != IME_CONFIG_REGISTERWORD || is_kbd_ime_unicode(immHkl))
724 return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData);
725 else
726 {
727 REGISTERWORDW *rww = lpData;
728 REGISTERWORDA rwa;
729 BOOL rc;
730
731 rwa.lpReading = strdupWtoA(rww->lpReading);
732 rwa.lpWord = strdupWtoA(rww->lpWord);
733 rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rwa);
734 HeapFree(GetProcessHeap(),0,rwa.lpReading);
735 HeapFree(GetProcessHeap(),0,rwa.lpWord);
736 return rc;
737 }
738 }
739 else
740 return FALSE;
741 }
742
743 /***********************************************************************
744 * ImmCreateContext (IMM32.@)
745 */
746 HIMC WINAPI ImmCreateContext(void)
747 {
748 InputContextData *new_context;
749 LPGUIDELINE gl;
750 LPCANDIDATEINFO ci;
751 int i;
752
753 new_context = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(InputContextData));
754
755 /* Load the IME */
756 new_context->immKbd = IMM_GetImmHkl(GetKeyboardLayout(0));
757
758 if (!new_context->immKbd->hIME)
759 {
760 TRACE("IME dll could not be loaded\n");
761 HeapFree(GetProcessHeap(),0,new_context);
762 return 0;
763 }
764
765 /* the HIMCCs are never NULL */
766 new_context->IMC.hCompStr = ImmCreateBlankCompStr();
767 new_context->IMC.hMsgBuf = ImmCreateIMCC(0);
768 new_context->IMC.hCandInfo = ImmCreateIMCC(sizeof(CANDIDATEINFO));
769 ci = ImmLockIMCC(new_context->IMC.hCandInfo);
770 memset(ci,0,sizeof(CANDIDATEINFO));
771 ci->dwSize = sizeof(CANDIDATEINFO);
772 ImmUnlockIMCC(new_context->IMC.hCandInfo);
773 new_context->IMC.hGuideLine = ImmCreateIMCC(sizeof(GUIDELINE));
774 gl = ImmLockIMCC(new_context->IMC.hGuideLine);
775 memset(gl,0,sizeof(GUIDELINE));
776 gl->dwSize = sizeof(GUIDELINE);
777 ImmUnlockIMCC(new_context->IMC.hGuideLine);
778
779 for (i = 0; i < ARRAY_SIZE(new_context->IMC.cfCandForm); i++)
780 new_context->IMC.cfCandForm[i].dwIndex = ~0u;
781
782 /* Initialize the IME Private */
783 new_context->IMC.hPrivate = ImmCreateIMCC(new_context->immKbd->imeInfo.dwPrivateDataSize);
784
785 new_context->IMC.fdwConversion = new_context->immKbd->imeInfo.fdwConversionCaps;
786 new_context->IMC.fdwSentence = new_context->immKbd->imeInfo.fdwSentenceCaps;
787
788 if (!new_context->immKbd->pImeSelect(new_context, TRUE))
789 {
790 TRACE("Selection of IME failed\n");
791 IMM_DestroyContext(new_context);
792 return 0;
793 }
794 new_context->threadID = GetCurrentThreadId();
795 SendMessageW(GetFocus(), WM_IME_SELECT, TRUE, (LPARAM)new_context->immKbd);
796
797 new_context->immKbd->uSelected++;
798 TRACE("Created context %p\n",new_context);
799
800 new_context->magic = WINE_IMC_VALID_MAGIC;
801 return new_context;
802 }
803
804 static BOOL IMM_DestroyContext(HIMC hIMC)
805 {
806 InputContextData *data = get_imc_data(hIMC);
807
808 TRACE("Destroying %p\n",hIMC);
809
810 if (!data)
811 return FALSE;
812
813 data->immKbd->uSelected --;
814 data->immKbd->pImeSelect(hIMC, FALSE);
815 SendMessageW(data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)data->immKbd);
816
817 ImmDestroyIMCC(data->IMC.hCompStr);
818 ImmDestroyIMCC(data->IMC.hCandInfo);
819 ImmDestroyIMCC(data->IMC.hGuideLine);
820 ImmDestroyIMCC(data->IMC.hPrivate);
821 ImmDestroyIMCC(data->IMC.hMsgBuf);
822
823 data->magic = 0;
824 HeapFree(GetProcessHeap(),0,data);
825
826 return TRUE;
827 }
828
829 /***********************************************************************
830 * ImmDestroyContext (IMM32.@)
831 */
832 BOOL WINAPI ImmDestroyContext(HIMC hIMC)
833 {
834 if (!IMM_IsDefaultContext(hIMC) && !IMM_IsCrossThreadAccess(NULL, hIMC))
835 return IMM_DestroyContext(hIMC);
836 else
837 return FALSE;
838 }
839
840 /***********************************************************************
841 * ImmDisableIME (IMM32.@)
842 */
843 BOOL WINAPI ImmDisableIME(DWORD idThread)
844 {
845 if (idThread == (DWORD)-1)
846 disable_ime = TRUE;
847 else {
848 IMMThreadData *thread_data = IMM_GetThreadData(NULL, idThread);
849 if (!thread_data) return FALSE;
850 thread_data->disableIME = TRUE;
851 LeaveCriticalSection(&threaddata_cs);
852 }
853 return TRUE;
854 }
855
856 /***********************************************************************
857 * ImmEnumRegisterWordA (IMM32.@)
858 */
859 UINT WINAPI ImmEnumRegisterWordA(
860 HKL hKL, REGISTERWORDENUMPROCA lpfnEnumProc,
861 LPCSTR lpszReading, DWORD dwStyle,
862 LPCSTR lpszRegister, LPVOID lpData)
863 {
864 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
865 TRACE("(%p, %p, %s, %d, %s, %p):\n", hKL, lpfnEnumProc,
866 debugstr_a(lpszReading), dwStyle, debugstr_a(lpszRegister), lpData);
867 if (immHkl->hIME && immHkl->pImeEnumRegisterWord)
868 {
869 if (!is_kbd_ime_unicode(immHkl))
870 return immHkl->pImeEnumRegisterWord((REGISTERWORDENUMPROCW)lpfnEnumProc,
871 (LPCWSTR)lpszReading, dwStyle, (LPCWSTR)lpszRegister, lpData);
872 else
873 {
874 LPWSTR lpszwReading = strdupAtoW(lpszReading);
875 LPWSTR lpszwRegister = strdupAtoW(lpszRegister);
876 BOOL rc;
877
878 rc = immHkl->pImeEnumRegisterWord((REGISTERWORDENUMPROCW)lpfnEnumProc,
879 lpszwReading, dwStyle, lpszwRegister,
880 lpData);
881
882 HeapFree(GetProcessHeap(),0,lpszwReading);
883 HeapFree(GetProcessHeap(),0,lpszwRegister);
884 return rc;
885 }
886 }
887 else
888 return 0;
889 }
890
891 /***********************************************************************
892 * ImmEnumRegisterWordW (IMM32.@)
893 */
894 UINT WINAPI ImmEnumRegisterWordW(
895 HKL hKL, REGISTERWORDENUMPROCW lpfnEnumProc,
896 LPCWSTR lpszReading, DWORD dwStyle,
897 LPCWSTR lpszRegister, LPVOID lpData)
898 {
899 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
900 TRACE("(%p, %p, %s, %d, %s, %p):\n", hKL, lpfnEnumProc,
901 debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister), lpData);
902 if (immHkl->hIME && immHkl->pImeEnumRegisterWord)
903 {
904 if (is_kbd_ime_unicode(immHkl))
905 return immHkl->pImeEnumRegisterWord(lpfnEnumProc, lpszReading, dwStyle,
906 lpszRegister, lpData);
907 else
908 {
909 LPSTR lpszaReading = strdupWtoA(lpszReading);
910 LPSTR lpszaRegister = strdupWtoA(lpszRegister);
911 BOOL rc;
912
913 rc = immHkl->pImeEnumRegisterWord(lpfnEnumProc, (LPCWSTR)lpszaReading,
914 dwStyle, (LPCWSTR)lpszaRegister, lpData);
915
916 HeapFree(GetProcessHeap(),0,lpszaReading);
917 HeapFree(GetProcessHeap(),0,lpszaRegister);
918 return rc;
919 }
920 }
921 else
922 return 0;
923 }
924
925 static inline BOOL EscapeRequiresWA(UINT uEscape)
926 {
927 if (uEscape == IME_ESC_GET_EUDC_DICTIONARY ||
928 uEscape == IME_ESC_SET_EUDC_DICTIONARY ||
929 uEscape == IME_ESC_IME_NAME ||
930 uEscape == IME_ESC_GETHELPFILENAME)
931 return TRUE;
932 return FALSE;
933 }
934
935 /***********************************************************************
936 * ImmEscapeA (IMM32.@)
937 */
938 LRESULT WINAPI ImmEscapeA(
939 HKL hKL, HIMC hIMC,
940 UINT uEscape, LPVOID lpData)
941 {
942 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
943 TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData);
944
945 if (immHkl->hIME && immHkl->pImeEscape)
946 {
947 if (!EscapeRequiresWA(uEscape) || !is_kbd_ime_unicode(immHkl))
948 return immHkl->pImeEscape(hIMC,uEscape,lpData);
949 else
950 {
951 WCHAR buffer[81]; /* largest required buffer should be 80 */
952 LRESULT rc;
953 if (uEscape == IME_ESC_SET_EUDC_DICTIONARY)
954 {
955 MultiByteToWideChar(CP_ACP,0,lpData,-1,buffer,81);
956 rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
957 }
958 else
959 {
960 rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
961 WideCharToMultiByte(CP_ACP,0,buffer,-1,lpData,80, NULL, NULL);
962 }
963 return rc;
964 }
965 }
966 else
967 return 0;
968 }
969
970 /***********************************************************************
971 * ImmEscapeW (IMM32.@)
972 */
973 LRESULT WINAPI ImmEscapeW(
974 HKL hKL, HIMC hIMC,
975 UINT uEscape, LPVOID lpData)
976 {
977 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
978 TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData);
979
980 if (immHkl->hIME && immHkl->pImeEscape)
981 {
982 if (!EscapeRequiresWA(uEscape) || is_kbd_ime_unicode(immHkl))
983 return immHkl->pImeEscape(hIMC,uEscape,lpData);
984 else
985 {
986 CHAR buffer[81]; /* largest required buffer should be 80 */
987 LRESULT rc;
988 if (uEscape == IME_ESC_SET_EUDC_DICTIONARY)
989 {
990 WideCharToMultiByte(CP_ACP,0,lpData,-1,buffer,81, NULL, NULL);
991 rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
992 }
993 else
994 {
995 rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
996 MultiByteToWideChar(CP_ACP,0,buffer,-1,lpData,80);
997 }
998 return rc;
999 }
1000 }
1001 else
1002 return 0;
1003 }
1004
1005 /***********************************************************************
1006 * ImmGetCandidateListA (IMM32.@)
1007 */
1008 DWORD WINAPI ImmGetCandidateListA(
1009 HIMC hIMC, DWORD dwIndex,
1010 LPCANDIDATELIST lpCandList, DWORD dwBufLen)
1011 {
1012 InputContextData *data = get_imc_data(hIMC);
1013 LPCANDIDATEINFO candinfo;
1014 LPCANDIDATELIST candlist;
1015 DWORD ret = 0;
1016
1017 TRACE("%p, %d, %p, %d\n", hIMC, dwIndex, lpCandList, dwBufLen);
1018
1019 if (!data || !data->IMC.hCandInfo)
1020 return 0;
1021
1022 candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1023 if (dwIndex >= candinfo->dwCount || dwIndex >= ARRAY_SIZE(candinfo->dwOffset))
1024 goto done;
1025
1026 candlist = (LPCANDIDATELIST)((LPBYTE)candinfo + candinfo->dwOffset[dwIndex]);
1027 if ( !candlist->dwSize || !candlist->dwCount )
1028 goto done;
1029
1030 if ( !is_himc_ime_unicode(data) )
1031 {
1032 ret = candlist->dwSize;
1033 if ( lpCandList && dwBufLen >= ret )
1034 memcpy(lpCandList, candlist, ret);
1035 }
1036 else
1037 ret = convert_candidatelist_WtoA( candlist, lpCandList, dwBufLen);
1038
1039 done:
1040 ImmUnlockIMCC(data->IMC.hCandInfo);
1041 return ret;
1042 }
1043
1044 /***********************************************************************
1045 * ImmGetCandidateListCountA (IMM32.@)
1046 */
1047 DWORD WINAPI ImmGetCandidateListCountA(
1048 HIMC hIMC, LPDWORD lpdwListCount)
1049 {
1050 InputContextData *data = get_imc_data(hIMC);
1051 LPCANDIDATEINFO candinfo;
1052 DWORD ret, count;
1053
1054 TRACE("%p, %p\n", hIMC, lpdwListCount);
1055
1056 if (!data || !lpdwListCount || !data->IMC.hCandInfo)
1057 return 0;
1058
1059 candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1060
1061 *lpdwListCount = count = candinfo->dwCount;
1062
1063 if ( !is_himc_ime_unicode(data) )
1064 ret = candinfo->dwSize;
1065 else
1066 {
1067 ret = sizeof(CANDIDATEINFO);
1068 while ( count-- )
1069 ret += ImmGetCandidateListA(hIMC, count, NULL, 0);
1070 }
1071
1072 ImmUnlockIMCC(data->IMC.hCandInfo);
1073 return ret;
1074 }
1075
1076 /***********************************************************************
1077 * ImmGetCandidateListCountW (IMM32.@)
1078 */
1079 DWORD WINAPI ImmGetCandidateListCountW(
1080 HIMC hIMC, LPDWORD lpdwListCount)
1081 {
1082 InputContextData *data = get_imc_data(hIMC);
1083 LPCANDIDATEINFO candinfo;
1084 DWORD ret, count;
1085
1086 TRACE("%p, %p\n", hIMC, lpdwListCount);
1087
1088 if (!data || !lpdwListCount || !data->IMC.hCandInfo)
1089 return 0;
1090
1091 candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1092
1093 *lpdwListCount = count = candinfo->dwCount;
1094
1095 if ( is_himc_ime_unicode(data) )
1096 ret = candinfo->dwSize;
1097 else
1098 {
1099 ret = sizeof(CANDIDATEINFO);
1100 while ( count-- )
1101 ret += ImmGetCandidateListW(hIMC, count, NULL, 0);
1102 }
1103
1104 ImmUnlockIMCC(data->IMC.hCandInfo);
1105 return ret;
1106 }
1107
1108 /***********************************************************************
1109 * ImmGetCandidateListW (IMM32.@)
1110 */
1111 DWORD WINAPI ImmGetCandidateListW(
1112 HIMC hIMC, DWORD dwIndex,
1113 LPCANDIDATELIST lpCandList, DWORD dwBufLen)
1114 {
1115 InputContextData *data = get_imc_data(hIMC);
1116 LPCANDIDATEINFO candinfo;
1117 LPCANDIDATELIST candlist;
1118 DWORD ret = 0;
1119
1120 TRACE("%p, %d, %p, %d\n", hIMC, dwIndex, lpCandList, dwBufLen);
1121
1122 if (!data || !data->IMC.hCandInfo)
1123 return 0;
1124
1125 candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1126 if (dwIndex >= candinfo->dwCount || dwIndex >= ARRAY_SIZE(candinfo->dwOffset))
1127 goto done;
1128
1129 candlist = (LPCANDIDATELIST)((LPBYTE)candinfo + candinfo->dwOffset[dwIndex]);
1130 if ( !candlist->dwSize || !candlist->dwCount )
1131 goto done;
1132
1133 if ( is_himc_ime_unicode(data) )
1134 {
1135 ret = candlist->dwSize;
1136 if ( lpCandList && dwBufLen >= ret )
1137 memcpy(lpCandList, candlist, ret);
1138 }
1139 else
1140 ret = convert_candidatelist_AtoW( candlist, lpCandList, dwBufLen);
1141
1142 done:
1143 ImmUnlockIMCC(data->IMC.hCandInfo);
1144 return ret;
1145 }
1146
1147 /***********************************************************************
1148 * ImmGetCandidateWindow (IMM32.@)
1149 */
1150 BOOL WINAPI ImmGetCandidateWindow(
1151 HIMC hIMC, DWORD dwIndex, LPCANDIDATEFORM lpCandidate)
1152 {
1153 InputContextData *data = get_imc_data(hIMC);
1154
1155 TRACE("%p, %d, %p\n", hIMC, dwIndex, lpCandidate);
1156
1157 if (!data || !lpCandidate)
1158 return FALSE;
1159
1160 if (dwIndex >= ARRAY_SIZE(data->IMC.cfCandForm))
1161 return FALSE;
1162
1163 if (data->IMC.cfCandForm[dwIndex].dwIndex != dwIndex)
1164 return FALSE;
1165
1166 *lpCandidate = data->IMC.cfCandForm[dwIndex];
1167
1168 return TRUE;
1169 }
1170
1171 /***********************************************************************
1172 * ImmGetCompositionFontA (IMM32.@)
1173 */
1174 BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
1175 {
1176 LOGFONTW lfW;
1177 BOOL rc;
1178
1179 TRACE("(%p, %p):\n", hIMC, lplf);
1180
1181 rc = ImmGetCompositionFontW(hIMC,&lfW);
1182 if (!rc || !lplf)
1183 return FALSE;
1184
1185 memcpy(lplf,&lfW,sizeof(LOGFONTA));
1186 WideCharToMultiByte(CP_ACP, 0, lfW.lfFaceName, -1, lplf->lfFaceName,
1187 LF_FACESIZE, NULL, NULL);
1188 return TRUE;
1189 }
1190
1191 /***********************************************************************
1192 * ImmGetCompositionFontW (IMM32.@)
1193 */
1194 BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
1195 {
1196 InputContextData *data = get_imc_data(hIMC);
1197
1198 TRACE("(%p, %p):\n", hIMC, lplf);
1199
1200 if (!data || !lplf)
1201 return FALSE;
1202
1203 *lplf = data->IMC.lfFont.W;
1204
1205 return TRUE;
1206 }
1207
1208
1209 /* Helpers for the GetCompositionString functions */
1210
1211 /* Source encoding is defined by context, source length is always given in respective characters. Destination buffer
1212 length is always in bytes. */
1213 static INT CopyCompStringIMEtoClient(const InputContextData *data, const void *src, INT src_len, void *dst,
1214 INT dst_len, BOOL unicode)
1215 {
1216 int char_size = unicode ? sizeof(WCHAR) : sizeof(char);
1217 INT ret;
1218
1219 if (is_himc_ime_unicode(data) ^ unicode)
1220 {
1221 if (unicode)
1222 ret = MultiByteToWideChar(CP_ACP, 0, src, src_len, dst, dst_len / sizeof(WCHAR));
1223 else
1224 ret = WideCharToMultiByte(CP_ACP, 0, src, src_len, dst, dst_len, NULL, NULL);
1225 ret *= char_size;
1226 }
1227 else
1228 {
1229 if (dst_len)
1230 {
1231 ret = min(src_len * char_size, dst_len);
1232 memcpy(dst, src, ret);
1233 }
1234 else
1235 ret = src_len * char_size;
1236 }
1237
1238 return ret;
1239 }
1240
1241 /* Composition string encoding is defined by context, returned attributes correspond to string, converted according to
1242 passed mode. String length is in characters, attributes are in byte arrays. */
1243 static INT CopyCompAttrIMEtoClient(const InputContextData *data, const BYTE *src, INT src_len, const void *comp_string,
1244 INT str_len, BYTE *dst, INT dst_len, BOOL unicode)
1245 {
1246 union
1247 {
1248 const void *str;
1249 const WCHAR *strW;
1250 const char *strA;
1251 } string;
1252 INT rc;
1253
1254 string.str = comp_string;
1255
1256 if (is_himc_ime_unicode(data) && !unicode)
1257 {
1258 rc = WideCharToMultiByte(CP_ACP, 0, string.strW, str_len, NULL, 0, NULL, NULL);
1259 if (dst_len)
1260 {
1261 int i, j = 0, k = 0;
1262
1263 if (rc < dst_len)
1264 dst_len = rc;
1265 for (i = 0; i < str_len; ++i)
1266 {
1267 int len;
1268
1269 len = WideCharToMultiByte(CP_ACP, 0, string.strW + i, 1, NULL, 0, NULL, NULL);
1270 for (; len > 0; --len)
1271 {
1272 dst[j++] = src[k];
1273
1274 if (j >= dst_len)
1275 goto end;
1276 }
1277 ++k;
1278 }
1279 end:
1280 rc = j;
1281 }
1282 }
1283 else if (!is_himc_ime_unicode(data) && unicode)
1284 {
1285 rc = MultiByteToWideChar(CP_ACP, 0, string.strA, str_len, NULL, 0);
1286 if (dst_len)
1287 {
1288 int i, j = 0;
1289
1290 if (rc < dst_len)
1291 dst_len = rc;
1292 for (i = 0; i < str_len; ++i)
1293 {
1294 if (IsDBCSLeadByte(string.strA[i]))
1295 continue;
1296
1297 dst[j++] = src[i];
1298
1299 if (j >= dst_len)
1300 break;
1301 }
1302 rc = j;
1303 }
1304 }
1305 else
1306 {
1307 memcpy(dst, src, min(src_len, dst_len));
1308 rc = src_len;
1309 }
1310
1311 return rc;
1312 }
1313
1314 static INT CopyCompClauseIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE ssource,
1315 LPBYTE target, INT tlen, BOOL unicode )
1316 {
1317 INT rc;
1318
1319 if (is_himc_ime_unicode(data) && !unicode)
1320 {
1321 if (tlen)
1322 {
1323 int i;
1324
1325 if (slen < tlen)
1326 tlen = slen;
1327 tlen /= sizeof (DWORD);
1328 for (i = 0; i < tlen; ++i)
1329 {
1330 ((DWORD *)target)[i] = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource,
1331 ((DWORD *)source)[i],
1332 NULL, 0,
1333 NULL, NULL);
1334 }
1335 rc = sizeof (DWORD) * i;
1336 }
1337 else
1338 rc = slen;
1339 }
1340 else if (!is_himc_ime_unicode(data) && unicode)
1341 {
1342 if (tlen)
1343 {
1344 int i;
1345
1346 if (slen < tlen)
1347 tlen = slen;
1348 tlen /= sizeof (DWORD);
1349 for (i = 0; i < tlen; ++i)
1350 {
1351 ((DWORD *)target)[i] = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource,
1352 ((DWORD *)source)[i],
1353 NULL, 0);
1354 }
1355 rc = sizeof (DWORD) * i;
1356 }
1357 else
1358 rc = slen;
1359 }
1360 else
1361 {
1362 memcpy( target, source, min(slen,tlen));
1363 rc = slen;
1364 }
1365
1366 return rc;
1367 }
1368
1369 static INT CopyCompOffsetIMEtoClient(InputContextData *data, DWORD offset, LPBYTE ssource, BOOL unicode)
1370 {
1371 int rc;
1372
1373 if (is_himc_ime_unicode(data) && !unicode)
1374 {
1375 rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, offset, NULL, 0, NULL, NULL);
1376 }
1377 else if (!is_himc_ime_unicode(data) && unicode)
1378 {
1379 rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, offset, NULL, 0);
1380 }
1381 else
1382 rc = offset;
1383
1384 return rc;
1385 }
1386
1387 static LONG ImmGetCompositionStringT( HIMC hIMC, DWORD dwIndex, LPVOID lpBuf,
1388 DWORD dwBufLen, BOOL unicode)
1389 {
1390 LONG rc = 0;
1391 InputContextData *data = get_imc_data(hIMC);
1392 LPCOMPOSITIONSTRING compstr;
1393 LPBYTE compdata;
1394
1395 TRACE("(%p, 0x%x, %p, %d)\n", hIMC, dwIndex, lpBuf, dwBufLen);
1396
1397 if (!data)
1398 return FALSE;
1399
1400 if (!data->IMC.hCompStr)
1401 return FALSE;
1402
1403 compdata = ImmLockIMCC(data->IMC.hCompStr);
1404 compstr = (LPCOMPOSITIONSTRING)compdata;
1405
1406 switch (dwIndex)
1407 {
1408 case GCS_RESULTSTR:
1409 TRACE("GCS_RESULTSTR\n");
1410 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultStrOffset, compstr->dwResultStrLen, lpBuf, dwBufLen, unicode);
1411 break;
1412 case GCS_COMPSTR:
1413 TRACE("GCS_COMPSTR\n");
1414 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen, lpBuf, dwBufLen, unicode);
1415 break;
1416 case GCS_COMPATTR:
1417 TRACE("GCS_COMPATTR\n");
1418 rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompAttrOffset, compstr->dwCompAttrLen,
1419 compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen,
1420 lpBuf, dwBufLen, unicode);
1421 break;
1422 case GCS_COMPCLAUSE:
1423 TRACE("GCS_COMPCLAUSE\n");
1424 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompClauseOffset,compstr->dwCompClauseLen,
1425 compdata + compstr->dwCompStrOffset,
1426 lpBuf, dwBufLen, unicode);
1427 break;
1428 case GCS_RESULTCLAUSE:
1429 TRACE("GCS_RESULTCLAUSE\n");
1430 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultClauseOffset,compstr->dwResultClauseLen,
1431 compdata + compstr->dwResultStrOffset,
1432 lpBuf, dwBufLen, unicode);
1433 break;
1434 case GCS_RESULTREADSTR:
1435 TRACE("GCS_RESULTREADSTR\n");
1436 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultReadStrOffset, compstr->dwResultReadStrLen, lpBuf, dwBufLen, unicode);
1437 break;
1438 case GCS_RESULTREADCLAUSE:
1439 TRACE("GCS_RESULTREADCLAUSE\n");
1440 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultReadClauseOffset,compstr->dwResultReadClauseLen,
1441 compdata + compstr->dwResultStrOffset,
1442 lpBuf, dwBufLen, unicode);
1443 break;
1444 case GCS_COMPREADSTR:
1445 TRACE("GCS_COMPREADSTR\n");
1446 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen, lpBuf, dwBufLen, unicode);
1447 break;
1448 case GCS_COMPREADATTR:
1449 TRACE("GCS_COMPREADATTR\n");
1450 rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompReadAttrOffset, compstr->dwCompReadAttrLen,
1451 compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen,
1452 lpBuf, dwBufLen, unicode);
1453 break;
1454 case GCS_COMPREADCLAUSE:
1455 TRACE("GCS_COMPREADCLAUSE\n");
1456 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompReadClauseOffset,compstr->dwCompReadClauseLen,
1457 compdata + compstr->dwCompStrOffset,
1458 lpBuf, dwBufLen, unicode);
1459 break;
1460 case GCS_CURSORPOS:
1461 TRACE("GCS_CURSORPOS\n");
1462 rc = CopyCompOffsetIMEtoClient(data, compstr->dwCursorPos, compdata + compstr->dwCompStrOffset, unicode);
1463 break;
1464 case GCS_DELTASTART:
1465 TRACE("GCS_DELTASTART\n");
1466 rc = CopyCompOffsetIMEtoClient(data, compstr->dwDeltaStart, compdata + compstr->dwCompStrOffset, unicode);
1467 break;
1468 default:
1469 FIXME("Unhandled index 0x%x\n",dwIndex);
1470 break;
1471 }
1472
1473 ImmUnlockIMCC(data->IMC.hCompStr);
1474
1475 return rc;
1476 }
1477
1478 /***********************************************************************
1479 * ImmGetCompositionStringA (IMM32.@)
1480 */
1481 LONG WINAPI ImmGetCompositionStringA(
1482 HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
1483 {
1484 return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, FALSE);
1485 }
1486
1487
1488 /***********************************************************************
1489 * ImmGetCompositionStringW (IMM32.@)
1490 */
1491 LONG WINAPI ImmGetCompositionStringW(
1492 HIMC hIMC, DWORD dwIndex,
1493 LPVOID lpBuf, DWORD dwBufLen)
1494 {
1495 return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, TRUE);
1496 }
1497
1498 /***********************************************************************
1499 * ImmGetCompositionWindow (IMM32.@)
1500 */
1501 BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
1502 {
1503 InputContextData *data = get_imc_data(hIMC);
1504
1505 TRACE("(%p, %p)\n", hIMC, lpCompForm);
1506
1507 if (!data)
1508 return FALSE;
1509
1510 *lpCompForm = data->IMC.cfCompForm;
1511 return TRUE;
1512 }
1513
1514 /***********************************************************************
1515 * ImmGetContext (IMM32.@)
1516 *
1517 */
1518 HIMC WINAPI ImmGetContext(HWND hWnd)
1519 {
1520 HIMC rc;
1521
1522 TRACE("%p\n", hWnd);
1523
1524 if (!IsWindow(hWnd))
1525 {
1526 SetLastError(ERROR_INVALID_WINDOW_HANDLE);
1527 return NULL;
1528 }
1529
1530 rc = GetPropW(hWnd,szwWineIMCProperty);
1531 if (rc == (HIMC)-1)
1532 rc = NULL;
1533 else if (rc == NULL)
1534 rc = get_default_context( hWnd );
1535
1536 if (rc)
1537 {
1538 InputContextData *data = rc;
1539 data->IMC.hWnd = hWnd;
1540 }
1541
1542 TRACE("returning %p\n", rc);
1543
1544 return rc;
1545 }
1546
1547 /***********************************************************************
1548 * ImmGetConversionListA (IMM32.@)
1549 */
1550 DWORD WINAPI ImmGetConversionListA(
1551 HKL hKL, HIMC hIMC,
1552 LPCSTR pSrc, LPCANDIDATELIST lpDst,
1553 DWORD dwBufLen, UINT uFlag)
1554 {
1555 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1556 TRACE("(%p, %p, %s, %p, %d, %d):\n", hKL, hIMC, debugstr_a(pSrc), lpDst,
1557 dwBufLen, uFlag);
1558 if (immHkl->hIME && immHkl->pImeConversionList)
1559 {
1560 if (!is_kbd_ime_unicode(immHkl))
1561 return immHkl->pImeConversionList(hIMC,(LPCWSTR)pSrc,lpDst,dwBufLen,uFlag);
1562 else
1563 {
1564 LPCANDIDATELIST lpwDst;
1565 DWORD ret = 0, len;
1566 LPWSTR pwSrc = strdupAtoW(pSrc);
1567
1568 len = immHkl->pImeConversionList(hIMC, pwSrc, NULL, 0, uFlag);
1569 lpwDst = HeapAlloc(GetProcessHeap(), 0, len);
1570 if ( lpwDst )
1571 {
1572 immHkl->pImeConversionList(hIMC, pwSrc, lpwDst, len, uFlag);
1573 ret = convert_candidatelist_WtoA( lpwDst, lpDst, dwBufLen);
1574 HeapFree(GetProcessHeap(), 0, lpwDst);
1575 }
1576 HeapFree(GetProcessHeap(), 0, pwSrc);
1577
1578 return ret;
1579 }
1580 }
1581 else
1582 return 0;
1583 }
1584
1585 /***********************************************************************
1586 * ImmGetConversionListW (IMM32.@)
1587 */
1588 DWORD WINAPI ImmGetConversionListW(
1589 HKL hKL, HIMC hIMC,
1590 LPCWSTR pSrc, LPCANDIDATELIST lpDst,
1591 DWORD dwBufLen, UINT uFlag)
1592 {
1593 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1594 TRACE("(%p, %p, %s, %p, %d, %d):\n", hKL, hIMC, debugstr_w(pSrc), lpDst,
1595 dwBufLen, uFlag);
1596 if (immHkl->hIME && immHkl->pImeConversionList)
1597 {
1598 if (is_kbd_ime_unicode(immHkl))
1599 return immHkl->pImeConversionList(hIMC,pSrc,lpDst,dwBufLen,uFlag);
1600 else
1601 {
1602 LPCANDIDATELIST lpaDst;
1603 DWORD ret = 0, len;
1604 LPSTR paSrc = strdupWtoA(pSrc);
1605
1606 len = immHkl->pImeConversionList(hIMC, (LPCWSTR)paSrc, NULL, 0, uFlag);
1607 lpaDst = HeapAlloc(GetProcessHeap(), 0, len);
1608 if ( lpaDst )
1609 {
1610 immHkl->pImeConversionList(hIMC, (LPCWSTR)paSrc, lpaDst, len, uFlag);
1611 ret = convert_candidatelist_AtoW( lpaDst, lpDst, dwBufLen);
1612 HeapFree(GetProcessHeap(), 0, lpaDst);
1613 }
1614 HeapFree(GetProcessHeap(), 0, paSrc);
1615
1616 return ret;
1617 }
1618 }
1619 else
1620 return 0;
1621 }
1622
1623 /***********************************************************************
1624 * ImmGetConversionStatus (IMM32.@)
1625 */
1626 BOOL WINAPI ImmGetConversionStatus(
1627 HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence)
1628 {
1629 InputContextData *data = get_imc_data(hIMC);
1630
1631 TRACE("%p %p %p\n", hIMC, lpfdwConversion, lpfdwSentence);
1632
1633 if (!data)
1634 return FALSE;
1635
1636 if (lpfdwConversion)
1637 *lpfdwConversion = data->IMC.fdwConversion;
1638 if (lpfdwSentence)
1639 *lpfdwSentence = data->IMC.fdwSentence;
1640
1641 return TRUE;
1642 }
1643
1644 static BOOL needs_ime_window(HWND hwnd)
1645 {
1646 WCHAR classW[8];
1647
1648 if (GetClassNameW(hwnd, classW, ARRAY_SIZE(classW)) && !lstrcmpW(classW, szwIME))
1649 return FALSE;
1650 if (GetClassLongPtrW(hwnd, GCL_STYLE) & CS_IME) return FALSE;
1651
1652 return TRUE;
1653 }
1654
1655 /***********************************************************************
1656 * __wine_register_window (IMM32.@)
1657 */
1658 BOOL WINAPI __wine_register_window(HWND hwnd)
1659 {
1660 HWND new = NULL;
1661 IMMThreadData *thread_data;
1662 TRACE("(%p)\n", hwnd);
1663
1664 if (!needs_ime_window(hwnd))
1665 return FALSE;
1666
1667 thread_data = IMM_GetThreadData(hwnd, 0);
1668 if (!thread_data)
1669 return FALSE;
1670
1671 if (thread_data->disableIME || disable_ime)
1672 {
1673 TRACE("IME for this thread is disabled\n");
1674 LeaveCriticalSection(&threaddata_cs);
1675 return FALSE;
1676 }
1677 thread_data->windowRefs++;
1678 TRACE("windowRefs=%u, hwndDefault=%p\n",
1679 thread_data->windowRefs, thread_data->hwndDefault);
1680
1681 /* Create default IME window */
1682 if (thread_data->windowRefs == 1)
1683 {
1684 /* Do not create the window inside of a critical section */
1685 LeaveCriticalSection(&threaddata_cs);
1686 new = CreateWindowExW( 0, szwIME, szwDefaultIME,
1687 WS_POPUP | WS_DISABLED | WS_CLIPSIBLINGS,
1688 0, 0, 1, 1, 0, 0, 0, 0);
1689 /* thread_data is in the current thread so we can assume it's still valid */
1690 EnterCriticalSection(&threaddata_cs);
1691 /* See if anyone beat us */
1692 if (thread_data->hwndDefault == NULL)
1693 {
1694 thread_data->hwndDefault = new;
1695 new = NULL;
1696 TRACE("Default is %p\n", thread_data->hwndDefault);
1697 }
1698 }
1699
1700 LeaveCriticalSection(&threaddata_cs);
1701
1702 /* Clean up an unused new window outside of the critical section */
1703 if (new != NULL)
1704 DestroyWindow(new);
1705 return TRUE;
1706 }
1707
1708 /***********************************************************************
1709 * __wine_unregister_window (IMM32.@)
1710 */
1711 void WINAPI __wine_unregister_window(HWND hwnd)
1712 {
1713 HWND to_destroy = 0;
1714 IMMThreadData *thread_data;
1715 TRACE("(%p)\n", hwnd);
1716
1717 thread_data = IMM_GetThreadData(hwnd, 0);
1718 if (!thread_data) return;
1719
1720 thread_data->windowRefs--;
1721 TRACE("windowRefs=%u, hwndDefault=%p\n",
1722 thread_data->windowRefs, thread_data->hwndDefault);
1723
1724 /* Destroy default IME window */
1725 if (thread_data->windowRefs == 0 && thread_data->hwndDefault)
1726 {
1727 to_destroy = thread_data->hwndDefault;
1728 thread_data->hwndDefault = NULL;
1729 }
1730 LeaveCriticalSection(&threaddata_cs);
1731
1732 if (to_destroy) DestroyWindow( to_destroy );
1733 }
1734
1735 /***********************************************************************
1736 * ImmGetDefaultIMEWnd (IMM32.@)
1737 */
1738 HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
1739 {
1740 HWND ret;
1741 IMMThreadData* thread_data = IMM_GetThreadData(hWnd, 0);
1742 if (!thread_data)
1743 return NULL;
1744 ret = thread_data->hwndDefault;
1745 LeaveCriticalSection(&threaddata_cs);
1746 TRACE("Default is %p\n",ret);
1747 return ret;
1748 }
1749
1750 /***********************************************************************
1751 * ImmGetDescriptionA (IMM32.@)
1752 */
1753 UINT WINAPI ImmGetDescriptionA(
1754 HKL hKL, LPSTR lpszDescription, UINT uBufLen)
1755 {
1756 WCHAR *buf;
1757 DWORD len;
1758
1759 TRACE("%p %p %d\n", hKL, lpszDescription, uBufLen);
1760
1761 /* find out how many characters in the unicode buffer */
1762 len = ImmGetDescriptionW( hKL, NULL, 0 );
1763 if (!len)
1764 return 0;
1765
1766 /* allocate a buffer of that size */
1767 buf = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof (WCHAR) );
1768 if( !buf )
1769 return 0;
1770
1771 /* fetch the unicode buffer */
1772 len = ImmGetDescriptionW( hKL, buf, len + 1 );
1773
1774 /* convert it back to ASCII */
1775 len = WideCharToMultiByte( CP_ACP, 0, buf, len + 1,
1776 lpszDescription, uBufLen, NULL, NULL );
1777
1778 HeapFree( GetProcessHeap(), 0, buf );
1779
1780 if (len == 0)
1781 return 0;
1782
1783 return len - 1;
1784 }
1785
1786 /***********************************************************************
1787 * ImmGetDescriptionW (IMM32.@)
1788 */
1789 UINT WINAPI ImmGetDescriptionW(HKL hKL, LPWSTR lpszDescription, UINT uBufLen)
1790 {
1791 static const WCHAR name[] = { 'W','i','n','e',' ','X','I','M',0 };
1792
1793 FIXME("(%p, %p, %d): semi stub\n", hKL, lpszDescription, uBufLen);
1794
1795 if (!hKL) return 0;
1796 if (!uBufLen) return lstrlenW( name );
1797 lstrcpynW( lpszDescription, name, uBufLen );
1798 return lstrlenW( lpszDescription );
1799 }
1800
1801 /***********************************************************************
1802 * ImmGetGuideLineA (IMM32.@)
1803 */
1804 DWORD WINAPI ImmGetGuideLineA(
1805 HIMC hIMC, DWORD dwIndex, LPSTR lpBuf, DWORD dwBufLen)
1806 {
1807 FIXME("(%p, %d, %s, %d): stub\n",
1808 hIMC, dwIndex, debugstr_a(lpBuf), dwBufLen
1809 );
1810 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1811 return 0;
1812 }
1813
1814 /***********************************************************************
1815 * ImmGetGuideLineW (IMM32.@)
1816 */
1817 DWORD WINAPI ImmGetGuideLineW(HIMC hIMC, DWORD dwIndex, LPWSTR lpBuf, DWORD dwBufLen)
1818 {
1819 FIXME("(%p, %d, %s, %d): stub\n",
1820 hIMC, dwIndex, debugstr_w(lpBuf), dwBufLen
1821 );
1822 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1823 return 0;
1824 }
1825
1826 /***********************************************************************
1827 * ImmGetIMEFileNameA (IMM32.@)
1828 */
1829 UINT WINAPI ImmGetIMEFileNameA( HKL hKL, LPSTR lpszFileName, UINT uBufLen)
1830 {
1831 LPWSTR bufW = NULL;
1832 UINT wBufLen = uBufLen;
1833 UINT rc;
1834
1835 if (uBufLen && lpszFileName)
1836 bufW = HeapAlloc(GetProcessHeap(),0,uBufLen * sizeof(WCHAR));
1837 else /* We need this to get the number of byte required */
1838 {
1839 bufW = HeapAlloc(GetProcessHeap(),0,MAX_PATH * sizeof(WCHAR));
1840 wBufLen = MAX_PATH;
1841 }
1842
1843 rc = ImmGetIMEFileNameW(hKL,bufW,wBufLen);
1844
1845 if (rc > 0)
1846 {
1847 if (uBufLen && lpszFileName)
1848 rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, lpszFileName,
1849 uBufLen, NULL, NULL);
1850 else /* get the length */
1851 rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL,
1852 NULL);
1853 }
1854
1855 HeapFree(GetProcessHeap(),0,bufW);
1856 return rc;
1857 }
1858
1859 /***********************************************************************
1860 * ImmGetIMEFileNameW (IMM32.@)
1861 */
1862 UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen)
1863 {
1864 HKEY hkey;
1865 DWORD length;
1866 DWORD rc;
1867 WCHAR regKey[ARRAY_SIZE(szImeRegFmt)+8];
1868
1869 wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hKL );
1870 rc = RegOpenKeyW( HKEY_LOCAL_MACHINE, regKey, &hkey);
1871 if (rc != ERROR_SUCCESS)
1872 {
1873 SetLastError(rc);
1874 return 0;
1875 }
1876
1877 length = 0;
1878 rc = RegGetValueW(hkey, NULL, szImeFileW, RRF_RT_REG_SZ, NULL, NULL, &length);
1879
1880 if (rc != ERROR_SUCCESS)
1881 {
1882 RegCloseKey(hkey);
1883 SetLastError(rc);
1884 return 0;
1885 }
1886 if (length > uBufLen * sizeof(WCHAR) || !lpszFileName)
1887 {
1888 RegCloseKey(hkey);
1889 if (lpszFileName)
1890 {
1891 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1892 return 0;
1893 }
1894 else
1895 return length / sizeof(WCHAR);
1896 }
1897
1898 RegGetValueW(hkey, NULL, szImeFileW, RRF_RT_REG_SZ, NULL, lpszFileName, &length);
1899
1900 RegCloseKey(hkey);
1901
1902 return length / sizeof(WCHAR);
1903 }
1904
1905 /***********************************************************************
1906 * ImmGetOpenStatus (IMM32.@)
1907 */
1908 BOOL WINAPI ImmGetOpenStatus(HIMC hIMC)
1909 {
1910 InputContextData *data = get_imc_data(hIMC);
1911 static int i;
1912
1913 if (!data)
1914 return FALSE;
1915
1916 TRACE("(%p): semi-stub\n", hIMC);
1917
1918 if (!i++)
1919 FIXME("(%p): semi-stub\n", hIMC);
1920
1921 return data->IMC.fOpen;
1922 }
1923
1924 /***********************************************************************
1925 * ImmGetProperty (IMM32.@)
1926 */
1927 DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex)
1928 {
1929 DWORD rc = 0;
1930 ImmHkl *kbd;
1931
1932 TRACE("(%p, %d)\n", hKL, fdwIndex);
1933 kbd = IMM_GetImmHkl(hKL);
1934
1935 if (kbd && kbd->hIME)
1936 {
1937 switch (fdwIndex)
1938 {
1939 case IGP_PROPERTY: rc = kbd->imeInfo.fdwProperty; break;
1940 case IGP_CONVERSION: rc = kbd->imeInfo.fdwConversionCaps; break;
1941 case IGP_SENTENCE: rc = kbd->imeInfo.fdwSentenceCaps; break;
1942 case IGP_SETCOMPSTR: rc = kbd->imeInfo.fdwSCSCaps; break;
1943 case IGP_SELECT: rc = kbd->imeInfo.fdwSelectCaps; break;
1944 case IGP_GETIMEVERSION: rc = IMEVER_0400; break;
1945 case IGP_UI: rc = 0; break;
1946 default: rc = 0;
1947 }
1948 }
1949 return rc;
1950 }
1951
1952 /***********************************************************************
1953 * ImmGetRegisterWordStyleA (IMM32.@)
1954 */
1955 UINT WINAPI ImmGetRegisterWordStyleA(
1956 HKL hKL, UINT nItem, LPSTYLEBUFA lpStyleBuf)
1957 {
1958 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1959 TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf);
1960 if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle)
1961 {
1962 if (!is_kbd_ime_unicode(immHkl))
1963 return immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)lpStyleBuf);
1964 else
1965 {
1966 STYLEBUFW sbw;
1967 UINT rc;
1968
1969 rc = immHkl->pImeGetRegisterWordStyle(nItem,&sbw);
1970 WideCharToMultiByte(CP_ACP, 0, sbw.szDescription, -1,
1971 lpStyleBuf->szDescription, 32, NULL, NULL);
1972 lpStyleBuf->dwStyle = sbw.dwStyle;
1973 return rc;
1974 }
1975 }
1976 else
1977 return 0;
1978 }
1979
1980 /***********************************************************************
1981 * ImmGetRegisterWordStyleW (IMM32.@)
1982 */
1983 UINT WINAPI ImmGetRegisterWordStyleW(
1984 HKL hKL, UINT nItem, LPSTYLEBUFW lpStyleBuf)
1985 {
1986 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1987 TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf);
1988 if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle)
1989 {
1990 if (is_kbd_ime_unicode(immHkl))
1991 return immHkl->pImeGetRegisterWordStyle(nItem,lpStyleBuf);
1992 else
1993 {
1994 STYLEBUFA sba;
1995 UINT rc;
1996
1997 rc = immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)&sba);
1998 MultiByteToWideChar(CP_ACP, 0, sba.szDescription, -1,
1999 lpStyleBuf->szDescription, 32);
2000 lpStyleBuf->dwStyle = sba.dwStyle;
2001 return rc;
2002 }
2003 }
2004 else
2005 return 0;
2006 }
2007
2008 /***********************************************************************
2009 * ImmGetStatusWindowPos (IMM32.@)
2010 */
2011 BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
2012 {
2013 InputContextData *data = get_imc_data(hIMC);
2014
2015 TRACE("(%p, %p)\n", hIMC, lpptPos);
2016
2017 if (!data || !lpptPos)
2018 return FALSE;
2019
2020 *lpptPos = data->IMC.ptStatusWndPos;
2021
2022 return TRUE;
2023 }
2024
2025 /***********************************************************************
2026 * ImmGetVirtualKey (IMM32.@)
2027 */
2028 UINT WINAPI ImmGetVirtualKey(HWND hWnd)
2029 {
2030 OSVERSIONINFOA version;
2031 InputContextData *data = ImmGetContext( hWnd );
2032 TRACE("%p\n", hWnd);
2033
2034 if ( data )
2035 return data->lastVK;
2036
2037 version.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
2038 GetVersionExA( &version );
2039 switch(version.dwPlatformId)
2040 {
2041 case VER_PLATFORM_WIN32_WINDOWS:
2042 return VK_PROCESSKEY;
2043 case VER_PLATFORM_WIN32_NT:
2044 return 0;
2045 default:
2046 FIXME("%d not supported\n",version.dwPlatformId);
2047 return VK_PROCESSKEY;
2048 }
2049 }
2050
2051 /***********************************************************************
2052 * ImmInstallIMEA (IMM32.@)
2053 */
2054 HKL WINAPI ImmInstallIMEA(
2055 LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
2056 {
2057 LPWSTR lpszwIMEFileName;
2058 LPWSTR lpszwLayoutText;
2059 HKL hkl;
2060
2061 TRACE ("(%s, %s)\n", debugstr_a(lpszIMEFileName),
2062 debugstr_a(lpszLayoutText));
2063
2064 lpszwIMEFileName = strdupAtoW(lpszIMEFileName);
2065 lpszwLayoutText = strdupAtoW(lpszLayoutText);
2066
2067 hkl = ImmInstallIMEW(lpszwIMEFileName, lpszwLayoutText);
2068
2069 HeapFree(GetProcessHeap(),0,lpszwIMEFileName);
2070 HeapFree(GetProcessHeap(),0,lpszwLayoutText);
2071 return hkl;
2072 }
2073
2074 /***********************************************************************
2075 * ImmInstallIMEW (IMM32.@)
2076 */
2077 HKL WINAPI ImmInstallIMEW(
2078 LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
2079 {
2080 INT lcid = GetUserDefaultLCID();
2081 INT count;
2082 HKL hkl;
2083 DWORD rc;
2084 HKEY hkey;
2085 WCHAR regKey[ARRAY_SIZE(szImeRegFmt)+8];
2086
2087 TRACE ("(%s, %s):\n", debugstr_w(lpszIMEFileName),
2088 debugstr_w(lpszLayoutText));
2089
2090 /* Start with 2. e001 will be blank and so default to the wine internal IME */
2091 count = 2;
2092
2093 while (count < 0xfff)
2094 {
2095 DWORD disposition = 0;
2096
2097 hkl = (HKL)MAKELPARAM( lcid, 0xe000 | count );
2098 wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hkl);
2099
2100 rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, regKey, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &disposition);
2101 if (rc == ERROR_SUCCESS && disposition == REG_CREATED_NEW_KEY)
2102 break;
2103 else if (rc == ERROR_SUCCESS)
2104 RegCloseKey(hkey);
2105
2106 count++;
2107 }
2108
2109 if (count == 0xfff)
2110 {
2111 WARN("Unable to find slot to install IME\n");
2112 return 0;
2113 }
2114
2115 if (rc == ERROR_SUCCESS)
2116 {
2117 rc = RegSetValueExW(hkey, szImeFileW, 0, REG_SZ, (const BYTE*)lpszIMEFileName,
2118 (lstrlenW(lpszIMEFileName) + 1) * sizeof(WCHAR));
2119 if (rc == ERROR_SUCCESS)
2120 rc = RegSetValueExW(hkey, szLayoutTextW, 0, REG_SZ, (const BYTE*)lpszLayoutText,
2121 (lstrlenW(lpszLayoutText) + 1) * sizeof(WCHAR));
2122 RegCloseKey(hkey);
2123 return hkl;
2124 }
2125 else
2126 {
2127 WARN("Unable to set IME registry values\n");
2128 return 0;
2129 }
2130 }
2131
2132 /***********************************************************************
2133 * ImmIsIME (IMM32.@)
2134 */
2135 BOOL WINAPI ImmIsIME(HKL hKL)
2136 {
2137 ImmHkl *ptr;
2138 TRACE("(%p):\n", hKL);
2139 ptr = IMM_GetImmHkl(hKL);
2140 return (ptr && ptr->hIME);
2141 }
2142
2143 /***********************************************************************
2144 * ImmIsUIMessageA (IMM32.@)
2145 */
2146 BOOL WINAPI ImmIsUIMessageA(
2147 HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
2148 {
2149 TRACE("(%p, %x, %ld, %ld)\n", hWndIME, msg, wParam, lParam);
2150 if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
2151 (msg == WM_IME_SETCONTEXT) ||
2152 (msg == WM_IME_NOTIFY) ||
2153 (msg == WM_IME_COMPOSITIONFULL) ||
2154 (msg == WM_IME_SELECT) ||
2155 (msg == 0x287 /* FIXME: WM_IME_SYSTEM */))
2156 {
2157 if (hWndIME)
2158 SendMessageA(hWndIME, msg, wParam, lParam);
2159
2160 return TRUE;
2161 }
2162 return FALSE;
2163 }
2164
2165 /***********************************************************************
2166 * ImmIsUIMessageW (IMM32.@)
2167 */
2168 BOOL WINAPI ImmIsUIMessageW(
2169 HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
2170 {
2171 TRACE("(%p, %x, %ld, %ld)\n", hWndIME, msg, wParam, lParam);
2172 if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
2173 (msg == WM_IME_SETCONTEXT) ||
2174 (msg == WM_IME_NOTIFY) ||
2175 (msg == WM_IME_COMPOSITIONFULL) ||
2176 (msg == WM_IME_SELECT) ||
2177 (msg == 0x287 /* FIXME: WM_IME_SYSTEM */))
2178 {
2179 if (hWndIME)
2180 SendMessageW(hWndIME, msg, wParam, lParam);
2181
2182 return TRUE;
2183 }
2184 return FALSE;
2185 }
2186
2187 /***********************************************************************
2188 * ImmNotifyIME (IMM32.@)
2189 */
2190 BOOL WINAPI ImmNotifyIME(
2191 HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
2192 {
2193 InputContextData *data = get_imc_data(hIMC);
2194
2195 TRACE("(%p, %d, %d, %d)\n",
2196 hIMC, dwAction, dwIndex, dwValue);
2197
2198 if (hIMC == NULL)
2199 {
2200 SetLastError(ERROR_SUCCESS);
2201 return FALSE;
2202 }
2203
2204 if (!data || ! data->immKbd->pNotifyIME)
2205 {
2206 return FALSE;
2207 }
2208
2209 return data->immKbd->pNotifyIME(hIMC,dwAction,dwIndex,dwValue);
2210 }
2211
2212 /***********************************************************************
2213 * ImmRegisterWordA (IMM32.@)
2214 */
2215 BOOL WINAPI ImmRegisterWordA(
2216 HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszRegister)
2217 {
2218 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2219 TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_a(lpszReading), dwStyle,
2220 debugstr_a(lpszRegister));
2221 if (immHkl->hIME && immHkl->pImeRegisterWord)
2222 {
2223 if (!is_kbd_ime_unicode(immHkl))
2224 return immHkl->pImeRegisterWord((LPCWSTR)lpszReading,dwStyle,
2225 (LPCWSTR)lpszRegister);
2226 else
2227 {
2228 LPWSTR lpszwReading = strdupAtoW(lpszReading);
2229 LPWSTR lpszwRegister = strdupAtoW(lpszRegister);
2230 BOOL rc;
2231
2232 rc = immHkl->pImeRegisterWord(lpszwReading,dwStyle,lpszwRegister);
2233 HeapFree(GetProcessHeap(),0,lpszwReading);
2234 HeapFree(GetProcessHeap(),0,lpszwRegister);
2235 return rc;
2236 }
2237 }
2238 else
2239 return FALSE;
2240 }
2241
2242 /***********************************************************************
2243 * ImmRegisterWordW (IMM32.@)
2244 */
2245 BOOL WINAPI ImmRegisterWordW(
2246 HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszRegister)
2247 {
2248 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2249 TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_w(lpszReading), dwStyle,
2250 debugstr_w(lpszRegister));
2251 if (immHkl->hIME && immHkl->pImeRegisterWord)
2252 {
2253 if (is_kbd_ime_unicode(immHkl))
2254 return immHkl->pImeRegisterWord(lpszReading,dwStyle,lpszRegister);
2255 else
2256 {
2257 LPSTR lpszaReading = strdupWtoA(lpszReading);
2258 LPSTR lpszaRegister = strdupWtoA(lpszRegister);
2259 BOOL rc;
2260
2261 rc = immHkl->pImeRegisterWord((LPCWSTR)lpszaReading,dwStyle,
2262 (LPCWSTR)lpszaRegister);
2263 HeapFree(GetProcessHeap(),0,lpszaReading);
2264 HeapFree(GetProcessHeap(),0,lpszaRegister);
2265 return rc;
2266 }
2267 }
2268 else
2269 return FALSE;
2270 }
2271
2272 /***********************************************************************
2273 * ImmReleaseContext (IMM32.@)
2274 */
2275 BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC)
2276 {
2277 static BOOL shown = FALSE;
2278
2279 if (!shown) {
2280 FIXME("(%p, %p): stub\n", hWnd, hIMC);
2281 shown = TRUE;
2282 }
2283 return TRUE;
2284 }
2285
2286 /***********************************************************************
2287 * ImmRequestMessageA(IMM32.@)
2288 */
2289 LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam)
2290 {
2291 InputContextData *data = get_imc_data(hIMC);
2292
2293 TRACE("%p %ld %ld\n", hIMC, wParam, wParam);
2294
2295 if (data) return SendMessageA(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
2296
2297 SetLastError(ERROR_INVALID_HANDLE);
2298 return 0;
2299 }
2300
2301 /***********************************************************************
2302 * ImmRequestMessageW(IMM32.@)
2303 */
2304 LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam)
2305 {
2306 InputContextData *data = get_imc_data(hIMC);
2307
2308 TRACE("%p %ld %ld\n", hIMC, wParam, wParam);
2309
2310 if (data) return SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
2311
2312 SetLastError(ERROR_INVALID_HANDLE);
2313 return 0;
2314 }
2315
2316 /***********************************************************************
2317 * ImmSetCandidateWindow (IMM32.@)
2318 */
2319 BOOL WINAPI ImmSetCandidateWindow(
2320 HIMC hIMC, LPCANDIDATEFORM lpCandidate)
2321 {
2322 InputContextData *data = get_imc_data(hIMC);
2323
2324 TRACE("(%p, %p)\n", hIMC, lpCandidate);
2325
2326 if (!data || !lpCandidate)
2327 return FALSE;
2328
2329 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2330 return FALSE;
2331
2332 TRACE("\t%x, %x, %s, %s\n",
2333 lpCandidate->dwIndex, lpCandidate->dwStyle,
2334 wine_dbgstr_point(&lpCandidate->ptCurrentPos),
2335 wine_dbgstr_rect(&lpCandidate->rcArea));
2336
2337 if (lpCandidate->dwIndex >= ARRAY_SIZE(data->IMC.cfCandForm))
2338 return FALSE;
2339
2340 data->IMC.cfCandForm[lpCandidate->dwIndex] = *lpCandidate;
2341 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCANDIDATEPOS);
2342 ImmInternalSendIMENotify(data, IMN_SETCANDIDATEPOS, 1 << lpCandidate->dwIndex);
2343
2344 return TRUE;
2345 }
2346
2347 /***********************************************************************
2348 * ImmSetCompositionFontA (IMM32.@)
2349 */
2350 BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
2351 {
2352 InputContextData *data = get_imc_data(hIMC);
2353 TRACE("(%p, %p)\n", hIMC, lplf);
2354
2355 if (!data || !lplf)
2356 {
2357 SetLastError(ERROR_INVALID_HANDLE);
2358 return FALSE;
2359 }
2360
2361 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2362 return FALSE;
2363
2364 memcpy(&data->IMC.lfFont.W,lplf,sizeof(LOGFONTA));
2365 MultiByteToWideChar(CP_ACP, 0, lplf->lfFaceName, -1, data->IMC.lfFont.W.lfFaceName,
2366 LF_FACESIZE);
2367 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT);
2368 ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
2369
2370 return TRUE;
2371 }
2372
2373 /***********************************************************************
2374 * ImmSetCompositionFontW (IMM32.@)
2375 */
2376 BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
2377 {
2378 InputContextData *data = get_imc_data(hIMC);
2379 TRACE("(%p, %p)\n", hIMC, lplf);
2380
2381 if (!data || !lplf)
2382 {
2383 SetLastError(ERROR_INVALID_HANDLE);
2384 return FALSE;
2385 }
2386
2387 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2388 return FALSE;
2389
2390 data->IMC.lfFont.W = *lplf;
2391 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT);
2392 ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
2393
2394 return TRUE;
2395 }
2396
2397 /***********************************************************************
2398 * ImmSetCompositionStringA (IMM32.@)
2399 */
2400 BOOL WINAPI ImmSetCompositionStringA(
2401 HIMC hIMC, DWORD dwIndex,
2402 LPCVOID lpComp, DWORD dwCompLen,
2403 LPCVOID lpRead, DWORD dwReadLen)
2404 {
2405 DWORD comp_len;
2406 DWORD read_len;
2407 WCHAR *CompBuffer = NULL;
2408 WCHAR *ReadBuffer = NULL;
2409 BOOL rc;
2410 InputContextData *data = get_imc_data(hIMC);
2411
2412 TRACE("(%p, %d, %p, %d, %p, %d):\n",
2413 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
2414
2415 if (!data)
2416 return FALSE;
2417
2418 if (!(dwIndex == SCS_SETSTR ||
2419 dwIndex == SCS_CHANGEATTR ||
2420 dwIndex == SCS_CHANGECLAUSE ||
2421 dwIndex == SCS_SETRECONVERTSTRING ||
2422 dwIndex == SCS_QUERYRECONVERTSTRING))
2423 return FALSE;
2424
2425 if (!is_himc_ime_unicode(data))
2426 return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
2427 dwCompLen, lpRead, dwReadLen);
2428
2429 comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0);
2430 if (comp_len)
2431 {
2432 CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len * sizeof(WCHAR));
2433 MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len);
2434 }
2435
2436 read_len = MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, NULL, 0);
2437 if (read_len)
2438 {
2439 ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len * sizeof(WCHAR));
2440 MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len);
2441 }
2442
2443 rc = ImmSetCompositionStringW(hIMC, dwIndex, CompBuffer, comp_len,
2444 ReadBuffer, read_len);
2445
2446 HeapFree(GetProcessHeap(), 0, CompBuffer);
2447 HeapFree(GetProcessHeap(), 0, ReadBuffer);
2448
2449 return rc;
2450 }
2451
2452 /***********************************************************************
2453 * ImmSetCompositionStringW (IMM32.@)
2454 */
2455 BOOL WINAPI ImmSetCompositionStringW(
2456 HIMC hIMC, DWORD dwIndex,
2457 LPCVOID lpComp, DWORD dwCompLen,
2458 LPCVOID lpRead, DWORD dwReadLen)
2459 {
2460 DWORD comp_len;
2461 DWORD read_len;
2462 CHAR *CompBuffer = NULL;
2463 CHAR *ReadBuffer = NULL;
2464 BOOL rc;
2465 InputContextData *data = get_imc_data(hIMC);
2466
2467 TRACE("(%p, %d, %p, %d, %p, %d):\n",
2468 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
2469
2470 if (!data)
2471 return FALSE;
2472
2473 if (!(dwIndex == SCS_SETSTR ||
2474 dwIndex == SCS_CHANGEATTR ||
2475 dwIndex == SCS_CHANGECLAUSE ||
2476 dwIndex == SCS_SETRECONVERTSTRING ||
2477 dwIndex == SCS_QUERYRECONVERTSTRING))
2478 return FALSE;
2479
2480 if (is_himc_ime_unicode(data))
2481 return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
2482 dwCompLen, lpRead, dwReadLen);
2483
2484 comp_len = WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, NULL, 0, NULL,
2485 NULL);
2486 if (comp_len)
2487 {
2488 CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len);
2489 WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len,
2490 NULL, NULL);
2491 }
2492
2493 read_len = WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, NULL, 0, NULL,
2494 NULL);
2495 if (read_len)
2496 {
2497 ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len);
2498 WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len,
2499 NULL, NULL);
2500 }
2501
2502 rc = ImmSetCompositionStringA(hIMC, dwIndex, CompBuffer, comp_len,
2503 ReadBuffer, read_len);
2504
2505 HeapFree(GetProcessHeap(), 0, CompBuffer);
2506 HeapFree(GetProcessHeap(), 0, ReadBuffer);
2507
2508 return rc;
2509 }
2510
2511 /***********************************************************************
2512 * ImmSetCompositionWindow (IMM32.@)
2513 */
2514 BOOL WINAPI ImmSetCompositionWindow(
2515 HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
2516 {
2517 BOOL reshow = FALSE;
2518 InputContextData *data = get_imc_data(hIMC);
2519
2520 TRACE("(%p, %p)\n", hIMC, lpCompForm);
2521 if (lpCompForm)
2522 TRACE("\t%x, %s, %s\n", lpCompForm->dwStyle,
2523 wine_dbgstr_point(&lpCompForm->ptCurrentPos),
2524 wine_dbgstr_rect(&lpCompForm->rcArea));
2525
2526 if (!data)
2527 {
2528 SetLastError(ERROR_INVALID_HANDLE);
2529 return FALSE;
2530 }
2531
2532 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2533 return FALSE;
2534
2535 data->IMC.cfCompForm = *lpCompForm;
2536
2537 if (IsWindowVisible(data->immKbd->UIWnd))
2538 {
2539 reshow = TRUE;
2540 ShowWindow(data->immKbd->UIWnd,SW_HIDE);
2541 }
2542
2543 /* FIXME: this is a partial stub */
2544
2545 if (reshow)
2546 ShowWindow(data->immKbd->UIWnd,SW_SHOWNOACTIVATE);
2547
2548 ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONWINDOW, 0);
2549 return TRUE;
2550 }
2551
2552 /***********************************************************************
2553 * ImmSetConversionStatus (IMM32.@)
2554 */
2555 BOOL WINAPI ImmSetConversionStatus(
2556 HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence)
2557 {
2558 DWORD oldConversion, oldSentence;
2559 InputContextData *data = get_imc_data(hIMC);
2560
2561 TRACE("%p %d %d\n", hIMC, fdwConversion, fdwSentence);
2562
2563 if (!data)
2564 {
2565 SetLastError(ERROR_INVALID_HANDLE);
2566 return FALSE;
2567 }
2568
2569 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2570 return FALSE;
2571
2572 if ( fdwConversion != data->IMC.fdwConversion )
2573 {
2574 oldConversion = data->IMC.fdwConversion;
2575 data->IMC.fdwConversion = fdwConversion;
2576 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldConversion, IMC_SETCONVERSIONMODE);
2577 ImmInternalSendIMENotify(data, IMN_SETCONVERSIONMODE, 0);
2578 }
2579 if ( fdwSentence != data->IMC.fdwSentence )
2580 {
2581 oldSentence = data->IMC.fdwSentence;
2582 data->IMC.fdwSentence = fdwSentence;
2583 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldSentence, IMC_SETSENTENCEMODE);
2584 ImmInternalSendIMENotify(data, IMN_SETSENTENCEMODE, 0);
2585 }
2586
2587 return TRUE;
2588 }
2589
2590 /***********************************************************************
2591 * ImmSetOpenStatus (IMM32.@)
2592 */
2593 BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen)
2594 {
2595 InputContextData *data = get_imc_data(hIMC);
2596
2597 TRACE("%p %d\n", hIMC, fOpen);
2598
2599 if (!data)
2600 {
2601 SetLastError(ERROR_INVALID_HANDLE);
2602 return FALSE;
2603 }
2604
2605 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2606 return FALSE;
2607
2608 if (data->immKbd->UIWnd == NULL)
2609 {
2610 /* create the ime window */
2611 data->immKbd->UIWnd = CreateWindowExW( WS_EX_TOOLWINDOW,
2612 data->immKbd->imeClassName, NULL, WS_POPUP, 0, 0, 1, 1, 0,
2613 0, data->immKbd->hIME, 0);
2614 SetWindowLongPtrW(data->immKbd->UIWnd, IMMGWL_IMC, (LONG_PTR)data);
2615 }
2616 else if (fOpen)
2617 SetWindowLongPtrW(data->immKbd->UIWnd, IMMGWL_IMC, (LONG_PTR)data);
2618
2619 if (!fOpen != !data->IMC.fOpen)
2620 {
2621 data->IMC.fOpen = fOpen;
2622 ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETOPENSTATUS);
2623 ImmInternalSendIMENotify(data, IMN_SETOPENSTATUS, 0);
2624 }
2625
2626 return TRUE;
2627 }
2628
2629 /***********************************************************************
2630 * ImmSetStatusWindowPos (IMM32.@)
2631 */
2632 BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
2633 {
2634 InputContextData *data = get_imc_data(hIMC);
2635
2636 TRACE("(%p, %p)\n", hIMC, lpptPos);
2637
2638 if (!data || !lpptPos)
2639 {
2640 SetLastError(ERROR_INVALID_HANDLE);
2641 return FALSE;
2642 }
2643
2644 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2645 return FALSE;
2646
2647 TRACE("\t%s\n", wine_dbgstr_point(lpptPos));
2648
2649 data->IMC.ptStatusWndPos = *lpptPos;
2650 ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETSTATUSWINDOWPOS);
2651 ImmInternalSendIMENotify(data, IMN_SETSTATUSWINDOWPOS, 0);
2652
2653 return TRUE;
2654 }
2655
2656 /***********************************************************************
2657 * ImmCreateSoftKeyboard(IMM32.@)
2658 */
2659 HWND WINAPI ImmCreateSoftKeyboard(UINT uType, UINT hOwner, int x, int y)
2660 {
2661 FIXME("(%d, %d, %d, %d): stub\n", uType, hOwner, x, y);
2662 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2663 return 0;
2664 }
2665
2666 /***********************************************************************
2667 * ImmDestroySoftKeyboard(IMM32.@)
2668 */
2669 BOOL WINAPI ImmDestroySoftKeyboard(HWND hSoftWnd)
2670 {
2671 FIXME("(%p): stub\n", hSoftWnd);
2672 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2673 return FALSE;
2674 }
2675
2676 /***********************************************************************
2677 * ImmShowSoftKeyboard(IMM32.@)
2678 */
2679 BOOL WINAPI ImmShowSoftKeyboard(HWND hSoftWnd, int nCmdShow)
2680 {
2681 FIXME("(%p, %d): stub\n", hSoftWnd, nCmdShow);
2682 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2683 return FALSE;
2684 }
2685
2686 /***********************************************************************
2687 * ImmSimulateHotKey (IMM32.@)
2688 */
2689 BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID)
2690 {
2691 FIXME("(%p, %d): stub\n", hWnd, dwHotKeyID);
2692 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2693 return FALSE;
2694 }
2695
2696 /***********************************************************************
2697 * ImmUnregisterWordA (IMM32.@)
2698 */
2699 BOOL WINAPI ImmUnregisterWordA(
2700 HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszUnregister)
2701 {
2702 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2703 TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_a(lpszReading), dwStyle,
2704 debugstr_a(lpszUnregister));
2705 if (immHkl->hIME && immHkl->pImeUnregisterWord)
2706 {
2707 if (!is_kbd_ime_unicode(immHkl))
2708 return immHkl->pImeUnregisterWord((LPCWSTR)lpszReading,dwStyle,
2709 (LPCWSTR)lpszUnregister);
2710 else
2711 {
2712 LPWSTR lpszwReading = strdupAtoW(lpszReading);
2713 LPWSTR lpszwUnregister = strdupAtoW(lpszUnregister);
2714 BOOL rc;
2715
2716 rc = immHkl->pImeUnregisterWord(lpszwReading,dwStyle,lpszwUnregister);
2717 HeapFree(GetProcessHeap(),0,lpszwReading);
2718 HeapFree(GetProcessHeap(),0,lpszwUnregister);
2719 return rc;
2720 }
2721 }
2722 else
2723 return FALSE;
2724 }
2725
2726 /***********************************************************************
2727 * ImmUnregisterWordW (IMM32.@)
2728 */
2729 BOOL WINAPI ImmUnregisterWordW(
2730 HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszUnregister)
2731 {
2732 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2733 TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_w(lpszReading), dwStyle,
2734 debugstr_w(lpszUnregister));
2735 if (immHkl->hIME && immHkl->pImeUnregisterWord)
2736 {
2737 if (is_kbd_ime_unicode(immHkl))
2738 return immHkl->pImeUnregisterWord(lpszReading,dwStyle,lpszUnregister);
2739 else
2740 {
2741 LPSTR lpszaReading = strdupWtoA(lpszReading);
2742 LPSTR lpszaUnregister = strdupWtoA(lpszUnregister);
2743 BOOL rc;
2744
2745 rc = immHkl->pImeUnregisterWord((LPCWSTR)lpszaReading,dwStyle,
2746 (LPCWSTR)lpszaUnregister);
2747 HeapFree(GetProcessHeap(),0,lpszaReading);
2748 HeapFree(GetProcessHeap(),0,lpszaUnregister);
2749 return rc;
2750 }
2751 }
2752 else
2753 return FALSE;
2754 }
2755
2756 /***********************************************************************
2757 * ImmGetImeMenuItemsA (IMM32.@)
2758 */
2759 DWORD WINAPI ImmGetImeMenuItemsA( HIMC hIMC, DWORD dwFlags, DWORD dwType,
2760 LPIMEMENUITEMINFOA lpImeParentMenu, LPIMEMENUITEMINFOA lpImeMenu,
2761 DWORD dwSize)
2762 {
2763 InputContextData *data = get_imc_data(hIMC);
2764 TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
2765 lpImeParentMenu, lpImeMenu, dwSize);
2766
2767 if (!data)
2768 {
2769 SetLastError(ERROR_INVALID_HANDLE);
2770 return 0;
2771 }
2772
2773 if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
2774 {
2775 if (!is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
2776 return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2777 (IMEMENUITEMINFOW*)lpImeParentMenu,
2778 (IMEMENUITEMINFOW*)lpImeMenu, dwSize);
2779 else
2780 {
2781 IMEMENUITEMINFOW lpImeParentMenuW;
2782 IMEMENUITEMINFOW *lpImeMenuW, *parent = NULL;
2783 DWORD rc;
2784
2785 if (lpImeParentMenu)
2786 parent = &lpImeParentMenuW;
2787 if (lpImeMenu)
2788 {
2789 int count = dwSize / sizeof(LPIMEMENUITEMINFOA);
2790 dwSize = count * sizeof(IMEMENUITEMINFOW);
2791 lpImeMenuW = HeapAlloc(GetProcessHeap(), 0, dwSize);
2792 }
2793 else
2794 lpImeMenuW = NULL;
2795
2796 rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2797 parent, lpImeMenuW, dwSize);
2798
2799 if (lpImeParentMenu)
2800 {
2801 memcpy(lpImeParentMenu,&lpImeParentMenuW,sizeof(IMEMENUITEMINFOA));
2802 lpImeParentMenu->hbmpItem = lpImeParentMenuW.hbmpItem;
2803 WideCharToMultiByte(CP_ACP, 0, lpImeParentMenuW.szString,
2804 -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE,
2805 NULL, NULL);
2806 }
2807 if (lpImeMenu && rc)
2808 {
2809 unsigned int i;
2810 for (i = 0; i < rc; i++)
2811 {
2812 memcpy(&lpImeMenu[i],&lpImeMenuW[1],sizeof(IMEMENUITEMINFOA));
2813 lpImeMenu[i].hbmpItem = lpImeMenuW[i].hbmpItem;
2814 WideCharToMultiByte(CP_ACP, 0, lpImeMenuW[i].szString,
2815 -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE,
2816 NULL, NULL);
2817 }
2818 }
2819 HeapFree(GetProcessHeap(),0,lpImeMenuW);
2820 return rc;
2821 }
2822 }
2823 else
2824 return 0;
2825 }
2826
2827 /***********************************************************************
2828 * ImmGetImeMenuItemsW (IMM32.@)
2829 */
2830 DWORD WINAPI ImmGetImeMenuItemsW( HIMC hIMC, DWORD dwFlags, DWORD dwType,
2831 LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu,
2832 DWORD dwSize)
2833 {
2834 InputContextData *data = get_imc_data(hIMC);
2835 TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
2836 lpImeParentMenu, lpImeMenu, dwSize);
2837
2838 if (!data)
2839 {
2840 SetLastError(ERROR_INVALID_HANDLE);
2841 return 0;
2842 }
2843
2844 if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
2845 {
2846 if (is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
2847 return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2848 lpImeParentMenu, lpImeMenu, dwSize);
2849 else
2850 {
2851 IMEMENUITEMINFOA lpImeParentMenuA;
2852 IMEMENUITEMINFOA *lpImeMenuA, *parent = NULL;
2853 DWORD rc;
2854
2855 if (lpImeParentMenu)
2856 parent = &lpImeParentMenuA;
2857 if (lpImeMenu)
2858 {
2859 int count = dwSize / sizeof(LPIMEMENUITEMINFOW);
2860 dwSize = count * sizeof(IMEMENUITEMINFOA);
2861 lpImeMenuA = HeapAlloc(GetProcessHeap(), 0, dwSize);
2862 }
2863 else
2864 lpImeMenuA = NULL;
2865
2866 rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2867 (IMEMENUITEMINFOW*)parent,
2868 (IMEMENUITEMINFOW*)lpImeMenuA, dwSize);
2869
2870 if (lpImeParentMenu)
2871 {
2872 memcpy(lpImeParentMenu,&lpImeParentMenuA,sizeof(IMEMENUITEMINFOA));
2873 lpImeParentMenu->hbmpItem = lpImeParentMenuA.hbmpItem;
2874 MultiByteToWideChar(CP_ACP, 0, lpImeParentMenuA.szString,
2875 -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE);
2876 }
2877 if (lpImeMenu && rc)
2878 {
2879 unsigned int i;
2880 for (i = 0; i < rc; i++)
2881 {
2882 memcpy(&lpImeMenu[i],&lpImeMenuA[1],sizeof(IMEMENUITEMINFOA));
2883 lpImeMenu[i].hbmpItem = lpImeMenuA[i].hbmpItem;
2884 MultiByteToWideChar(CP_ACP, 0, lpImeMenuA[i].szString,
2885 -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE);
2886 }
2887 }
2888 HeapFree(GetProcessHeap(),0,lpImeMenuA);
2889 return rc;
2890 }
2891 }
2892 else
2893 return 0;
2894 }
2895
2896 /***********************************************************************
2897 * ImmLockIMC(IMM32.@)
2898 */
2899 LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC)
2900 {
2901 InputContextData *data = get_imc_data(hIMC);
2902
2903 if (!data)
2904 return NULL;
2905 data->dwLock++;
2906 return &data->IMC;
2907 }
2908
2909 /***********************************************************************
2910 * ImmUnlockIMC(IMM32.@)
2911 */
2912 BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
2913 {
2914 InputContextData *data = get_imc_data(hIMC);
2915
2916 if (!data)
2917 return FALSE;
2918 if (data->dwLock)
2919 data->dwLock--;
2920 return TRUE;
2921 }
2922
2923 /***********************************************************************
2924 * ImmGetIMCLockCount(IMM32.@)
2925 */
2926 DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC)
2927 {
2928 InputContextData *data = get_imc_data(hIMC);
2929 if (!data)
2930 return 0;
2931 return data->dwLock;
2932 }
2933
2934 /***********************************************************************
2935 * ImmCreateIMCC(IMM32.@)
2936 */
2937 HIMCC WINAPI ImmCreateIMCC(DWORD size)
2938 {
2939 return GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE, size);
2940 }
2941
2942 /***********************************************************************
2943 * ImmDestroyIMCC(IMM32.@)
2944 */
2945 HIMCC WINAPI ImmDestroyIMCC(HIMCC block)
2946 {
2947 return GlobalFree(block);
2948 }
2949
2950 /***********************************************************************
2951 * ImmLockIMCC(IMM32.@)
2952 */
2953 LPVOID WINAPI ImmLockIMCC(HIMCC imcc)
2954 {
2955 return GlobalLock(imcc);
2956 }
2957
2958 /***********************************************************************
2959 * ImmUnlockIMCC(IMM32.@)
2960 */
2961 BOOL WINAPI ImmUnlockIMCC(HIMCC imcc)
2962 {
2963 return GlobalUnlock(imcc);
2964 }
2965
2966 /***********************************************************************
2967 * ImmGetIMCCLockCount(IMM32.@)
2968 */
2969 DWORD WINAPI ImmGetIMCCLockCount(HIMCC imcc)
2970 {
2971 return GlobalFlags(imcc) & GMEM_LOCKCOUNT;
2972 }
2973
2974 /***********************************************************************
2975 * ImmReSizeIMCC(IMM32.@)
2976 */
2977 HIMCC WINAPI ImmReSizeIMCC(HIMCC imcc, DWORD size)
2978 {
2979 return GlobalReAlloc(imcc, size, GMEM_ZEROINIT | GMEM_MOVEABLE);
2980 }
2981
2982 /***********************************************************************
2983 * ImmGetIMCCSize(IMM32.@)
2984 */
2985 DWORD WINAPI ImmGetIMCCSize(HIMCC imcc)
2986 {
2987 return GlobalSize(imcc);
2988 }
2989
2990 /***********************************************************************
2991 * ImmGenerateMessage(IMM32.@)
2992 */
2993 BOOL WINAPI ImmGenerateMessage(HIMC hIMC)
2994 {
2995 InputContextData *data = get_imc_data(hIMC);
2996
2997 if (!data)
2998 {
2999 SetLastError(ERROR_INVALID_HANDLE);
3000 return FALSE;
3001 }
3002
3003 TRACE("%i messages queued\n",data->IMC.dwNumMsgBuf);
3004 if (data->IMC.dwNumMsgBuf > 0)
3005 {
3006 LPTRANSMSG lpTransMsg;
3007 HIMCC hMsgBuf;
3008 DWORD i, dwNumMsgBuf;
3009
3010 /* We are going to detach our hMsgBuff so that if processing messages
3011 generates new messages they go into a new buffer */
3012 hMsgBuf = data->IMC.hMsgBuf;
3013 dwNumMsgBuf = data->IMC.dwNumMsgBuf;
3014
3015 data->IMC.hMsgBuf = ImmCreateIMCC(0);
3016 data->IMC.dwNumMsgBuf = 0;
3017
3018 lpTransMsg = ImmLockIMCC(hMsgBuf);
3019 for (i = 0; i < dwNumMsgBuf; i++)
3020 ImmInternalSendIMEMessage(data, lpTransMsg[i].message, lpTransMsg[i].wParam, lpTransMsg[i].lParam);
3021
3022 ImmUnlockIMCC(hMsgBuf);
3023 ImmDestroyIMCC(hMsgBuf);
3024 }
3025
3026 return TRUE;
3027 }
3028
3029 /***********************************************************************
3030 * ImmTranslateMessage(IMM32.@)
3031 * ( Undocumented, call internally and from user32.dll )
3032 */
3033 BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyData)
3034 {
3035 InputContextData *data;
3036 HIMC imc = ImmGetContext(hwnd);
3037 BYTE state[256];
3038 UINT scancode;
3039 LPVOID list = 0;
3040 UINT msg_count;
3041 UINT uVirtKey;
3042 static const DWORD list_count = 10;
3043
3044 TRACE("%p %x %x %x\n",hwnd, msg, (UINT)wParam, (UINT)lKeyData);
3045
3046 if (imc)
3047 data = imc;
3048 else
3049 return FALSE;
3050
3051 if (!data->immKbd->hIME || !data->immKbd->pImeToAsciiEx)
3052 return FALSE;
3053
3054 GetKeyboardState(state);
3055 scancode = lKeyData >> 0x10 & 0xff;
3056
3057 list = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, list_count * sizeof(TRANSMSG) + sizeof(DWORD));
3058 ((DWORD*)list)[0] = list_count;
3059
3060 if (data->immKbd->imeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST)
3061 {
3062 WCHAR chr;
3063
3064 if (!is_himc_ime_unicode(data))
3065 ToAscii(data->lastVK, scancode, state, &chr, 0);
3066 else
3067 ToUnicodeEx(data->lastVK, scancode, state, &chr, 1, 0, GetKeyboardLayout(0));
3068 uVirtKey = MAKELONG(data->lastVK,chr);
3069 }
3070 else
3071 uVirtKey = data->lastVK;
3072
3073 msg_count = data->immKbd->pImeToAsciiEx(uVirtKey, scancode, state, list, 0, imc);
3074 TRACE("%i messages generated\n",msg_count);
3075 if (msg_count && msg_count <= list_count)
3076 {
3077 UINT i;
3078 LPTRANSMSG msgs = (LPTRANSMSG)((LPBYTE)list + sizeof(DWORD));
3079
3080 for (i = 0; i < msg_count; i++)
3081 ImmInternalPostIMEMessage(data, msgs[i].message, msgs[i].wParam, msgs[i].lParam);
3082 }
3083 else if (msg_count > list_count)
3084 ImmGenerateMessage(imc);
3085
3086 HeapFree(GetProcessHeap(),0,list);
3087
3088 data->lastVK = VK_PROCESSKEY;
3089
3090 return (msg_count > 0);
3091 }
3092
3093 /***********************************************************************
3094 * ImmProcessKey(IMM32.@)
3095 * ( Undocumented, called from user32.dll )
3096 */
3097 BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD unknown)
3098 {
3099 InputContextData *data;
3100 HIMC imc = ImmGetContext(hwnd);
3101 BYTE state[256];
3102
3103 TRACE("%p %p %x %x %x\n",hwnd, hKL, vKey, (UINT)lKeyData, unknown);
3104
3105 if (imc)
3106 data = imc;
3107 else
3108 return FALSE;
3109
3110 /* Make sure we are inputting to the correct keyboard */
3111 if (data->immKbd->hkl != hKL)
3112 {
3113 ImmHkl *new_hkl = IMM_GetImmHkl(hKL);
3114 if (new_hkl)
3115 {
3116 data->immKbd->pImeSelect(imc, FALSE);
3117 data->immKbd->uSelected--;
3118 data->immKbd = new_hkl;
3119 data->immKbd->pImeSelect(imc, TRUE);
3120 data->immKbd->uSelected++;
3121 }
3122 else
3123 return FALSE;
3124 }
3125
3126 if (!data->immKbd->hIME || !data->immKbd->pImeProcessKey)
3127 return FALSE;
3128
3129 GetKeyboardState(state);
3130 if (data->immKbd->pImeProcessKey(imc, vKey, lKeyData, state))
3131 {
3132 data->lastVK = vKey;
3133 return TRUE;
3134 }
3135
3136 data->lastVK = VK_PROCESSKEY;
3137 return FALSE;
3138 }
3139
3140 /***********************************************************************
3141 * ImmDisableTextFrameService(IMM32.@)
3142 */
3143 BOOL WINAPI ImmDisableTextFrameService(DWORD idThread)
3144 {
3145 FIXME("Stub\n");
3146 return FALSE;
3147 }
3148
3149 /***********************************************************************
3150 * ImmEnumInputContext(IMM32.@)
3151 */
3152
3153 BOOL WINAPI ImmEnumInputContext(DWORD idThread, IMCENUMPROC lpfn, LPARAM lParam)
3154 {
3155 FIXME("Stub\n");
3156 return FALSE;
3157 }
3158
3159 /***********************************************************************
3160 * ImmGetHotKey(IMM32.@)
3161 */
3162
3163 BOOL WINAPI ImmGetHotKey(DWORD hotkey, UINT *modifiers, UINT *key, HKL hkl)
3164 {
3165 FIXME("%x, %p, %p, %p: stub\n", hotkey, modifiers, key, hkl);
3166 return FALSE;
3167 }
3168
3169 /***********************************************************************
3170 * ImmDisableLegacyIME(IMM32.@)
3171 */
3172 BOOL WINAPI ImmDisableLegacyIME(void)
3173 {
3174 FIXME("stub\n");
3175 return TRUE;
3176 }