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