kernelbase: Reimplement LocaleNameToLCID() using the locale.nls data.
[wine.git] / dlls / imm32 / imm.c
blobbcb02b82c83a8b379f440e3df37ab286465291c1
1 /*
2 * IMM32 library
4 * Copyright 1998 Patrik Stridvall
5 * Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart
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.
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.
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
22 #define COBJMACROS
24 #include <stdarg.h>
25 #include <stdio.h>
27 #include "initguid.h"
28 #include "objbase.h"
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "winerror.h"
34 #include "wine/debug.h"
35 #include "imm.h"
36 #include "ddk/imm.h"
37 #include "winnls.h"
38 #include "winreg.h"
39 #include "wine/list.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(imm);
43 #define IMM_INIT_MAGIC 0x19650412
44 BOOL WINAPI User32InitializeImmEntryTable(DWORD);
46 typedef struct _tagImmHkl{
47 struct list entry;
48 HKL hkl;
49 HMODULE hIME;
50 IMEINFO imeInfo;
51 WCHAR imeClassName[17]; /* 16 character max */
52 ULONG uSelected;
53 HWND UIWnd;
55 /* Function Pointers */
56 BOOL (WINAPI *pImeInquire)(IMEINFO *, WCHAR *, const WCHAR *);
57 BOOL (WINAPI *pImeConfigure)(HKL, HWND, DWORD, void *);
58 BOOL (WINAPI *pImeDestroy)(UINT);
59 LRESULT (WINAPI *pImeEscape)(HIMC, UINT, void *);
60 BOOL (WINAPI *pImeSelect)(HIMC, BOOL);
61 BOOL (WINAPI *pImeSetActiveContext)(HIMC, BOOL);
62 UINT (WINAPI *pImeToAsciiEx)(UINT, UINT, const BYTE *, DWORD *, UINT, HIMC);
63 BOOL (WINAPI *pNotifyIME)(HIMC, DWORD, DWORD, DWORD);
64 BOOL (WINAPI *pImeRegisterWord)(const WCHAR *, DWORD, const WCHAR *);
65 BOOL (WINAPI *pImeUnregisterWord)(const WCHAR *, DWORD, const WCHAR *);
66 UINT (WINAPI *pImeEnumRegisterWord)(REGISTERWORDENUMPROCW, const WCHAR *, DWORD, const WCHAR *, void *);
67 BOOL (WINAPI *pImeSetCompositionString)(HIMC, DWORD, const void *, DWORD, const void *, DWORD);
68 DWORD (WINAPI *pImeConversionList)(HIMC, const WCHAR *, CANDIDATELIST *, DWORD, UINT);
69 BOOL (WINAPI *pImeProcessKey)(HIMC, UINT, LPARAM, const BYTE *);
70 UINT (WINAPI *pImeGetRegisterWordStyle)(UINT, STYLEBUFW *);
71 DWORD (WINAPI *pImeGetImeMenuItems)(HIMC, DWORD, DWORD, IMEMENUITEMINFOW *, IMEMENUITEMINFOW *, DWORD);
72 } ImmHkl;
74 typedef struct tagInputContextData
76 DWORD dwLock;
77 INPUTCONTEXT IMC;
78 DWORD threadID;
80 ImmHkl *immKbd;
81 UINT lastVK;
82 BOOL threadDefault;
83 DWORD magic;
84 } InputContextData;
86 #define WINE_IMC_VALID_MAGIC 0x56434D49
88 typedef struct _tagTRANSMSG {
89 UINT message;
90 WPARAM wParam;
91 LPARAM lParam;
92 } TRANSMSG, *LPTRANSMSG;
94 typedef struct _tagIMMThreadData {
95 struct list entry;
96 DWORD threadID;
97 HIMC defaultContext;
98 HWND hwndDefault;
99 BOOL disableIME;
100 DWORD windowRefs;
101 IInitializeSpy IInitializeSpy_iface;
102 ULARGE_INTEGER spy_cookie;
103 enum
105 IMM_APT_INIT = 0x1,
106 IMM_APT_CREATED = 0x2,
107 IMM_APT_CAN_FREE = 0x4,
108 IMM_APT_BROKEN = 0x8
109 } apt_flags;
110 } IMMThreadData;
112 static struct list ImmHklList = LIST_INIT(ImmHklList);
113 static struct list ImmThreadDataList = LIST_INIT(ImmThreadDataList);
115 static const WCHAR szwWineIMCProperty[] = L"WineImmHIMCProperty";
116 static const WCHAR szImeRegFmt[] = L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08lx";
118 static CRITICAL_SECTION threaddata_cs;
119 static CRITICAL_SECTION_DEBUG critsect_debug =
121 0, 0, &threaddata_cs,
122 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
123 0, 0, { (DWORD_PTR)(__FILE__ ": threaddata_cs") }
125 static CRITICAL_SECTION threaddata_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
126 static BOOL disable_ime;
128 static inline BOOL is_himc_ime_unicode(const InputContextData *data)
130 return !!(data->immKbd->imeInfo.fdwProperty & IME_PROP_UNICODE);
133 static inline BOOL is_kbd_ime_unicode(const ImmHkl *hkl)
135 return !!(hkl->imeInfo.fdwProperty & IME_PROP_UNICODE);
138 static BOOL IMM_DestroyContext(HIMC hIMC);
139 static InputContextData* get_imc_data(HIMC hIMC);
141 static inline WCHAR *strdupAtoW( const char *str )
143 WCHAR *ret = NULL;
144 if (str)
146 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
147 if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
148 MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
150 return ret;
153 static inline CHAR *strdupWtoA( const WCHAR *str )
155 CHAR *ret = NULL;
156 if (str)
158 DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
159 if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
160 WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
162 return ret;
165 static DWORD convert_candidatelist_WtoA(
166 LPCANDIDATELIST lpSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen)
168 DWORD ret, i, len;
170 ret = FIELD_OFFSET( CANDIDATELIST, dwOffset[lpSrc->dwCount] );
171 if ( lpDst && dwBufLen > 0 )
173 *lpDst = *lpSrc;
174 lpDst->dwOffset[0] = ret;
177 for ( i = 0; i < lpSrc->dwCount; i++)
179 LPBYTE src = (LPBYTE)lpSrc + lpSrc->dwOffset[i];
181 if ( lpDst && dwBufLen > 0 )
183 LPBYTE dest = (LPBYTE)lpDst + lpDst->dwOffset[i];
185 len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1,
186 (LPSTR)dest, dwBufLen, NULL, NULL);
188 if ( i + 1 < lpSrc->dwCount )
189 lpDst->dwOffset[i+1] = lpDst->dwOffset[i] + len * sizeof(char);
190 dwBufLen -= len * sizeof(char);
192 else
193 len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1, NULL, 0, NULL, NULL);
195 ret += len * sizeof(char);
198 if ( lpDst )
199 lpDst->dwSize = ret;
201 return ret;
204 static DWORD convert_candidatelist_AtoW(
205 LPCANDIDATELIST lpSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen)
207 DWORD ret, i, len;
209 ret = FIELD_OFFSET( CANDIDATELIST, dwOffset[lpSrc->dwCount] );
210 if ( lpDst && dwBufLen > 0 )
212 *lpDst = *lpSrc;
213 lpDst->dwOffset[0] = ret;
216 for ( i = 0; i < lpSrc->dwCount; i++)
218 LPBYTE src = (LPBYTE)lpSrc + lpSrc->dwOffset[i];
220 if ( lpDst && dwBufLen > 0 )
222 LPBYTE dest = (LPBYTE)lpDst + lpDst->dwOffset[i];
224 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1,
225 (LPWSTR)dest, dwBufLen);
227 if ( i + 1 < lpSrc->dwCount )
228 lpDst->dwOffset[i+1] = lpDst->dwOffset[i] + len * sizeof(WCHAR);
229 dwBufLen -= len * sizeof(WCHAR);
231 else
232 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1, NULL, 0);
234 ret += len * sizeof(WCHAR);
237 if ( lpDst )
238 lpDst->dwSize = ret;
240 return ret;
243 static void imm_coinit_thread(IMMThreadData *thread_data)
245 HRESULT hr;
247 TRACE("implicit COM initialization\n");
249 if (thread_data->threadID != GetCurrentThreadId())
250 return;
252 if (thread_data->apt_flags & (IMM_APT_INIT | IMM_APT_BROKEN))
253 return;
254 thread_data->apt_flags |= IMM_APT_INIT;
256 if(!thread_data->spy_cookie.QuadPart)
258 hr = CoRegisterInitializeSpy(&thread_data->IInitializeSpy_iface,
259 &thread_data->spy_cookie);
260 if (FAILED(hr))
261 return;
264 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
265 if (SUCCEEDED(hr))
266 thread_data->apt_flags |= IMM_APT_CREATED;
269 static void imm_couninit_thread(IMMThreadData *thread_data, BOOL cleanup)
271 TRACE("implicit COM deinitialization\n");
273 if (thread_data->apt_flags & IMM_APT_BROKEN)
274 return;
276 if (cleanup && thread_data->spy_cookie.QuadPart)
278 CoRevokeInitializeSpy(thread_data->spy_cookie);
279 thread_data->spy_cookie.QuadPart = 0;
282 if (!(thread_data->apt_flags & IMM_APT_INIT))
283 return;
284 thread_data->apt_flags &= ~IMM_APT_INIT;
286 if (thread_data->apt_flags & IMM_APT_CREATED)
288 thread_data->apt_flags &= ~IMM_APT_CREATED;
289 if (thread_data->apt_flags & IMM_APT_CAN_FREE)
290 CoUninitialize();
292 if (cleanup)
293 thread_data->apt_flags = 0;
296 static inline IMMThreadData *impl_from_IInitializeSpy(IInitializeSpy *iface)
298 return CONTAINING_RECORD(iface, IMMThreadData, IInitializeSpy_iface);
301 static HRESULT WINAPI InitializeSpy_QueryInterface(IInitializeSpy *iface, REFIID riid, void **obj)
303 if (IsEqualIID(&IID_IInitializeSpy, riid) ||
304 IsEqualIID(&IID_IUnknown, riid))
306 *obj = iface;
307 IInitializeSpy_AddRef(iface);
308 return S_OK;
311 *obj = NULL;
312 return E_NOINTERFACE;
315 static ULONG WINAPI InitializeSpy_AddRef(IInitializeSpy *iface)
317 return 2;
320 static ULONG WINAPI InitializeSpy_Release(IInitializeSpy *iface)
322 return 1;
325 static HRESULT WINAPI InitializeSpy_PreInitialize(IInitializeSpy *iface,
326 DWORD coinit, DWORD refs)
328 IMMThreadData *thread_data = impl_from_IInitializeSpy(iface);
330 if ((thread_data->apt_flags & IMM_APT_CREATED) &&
331 !(coinit & COINIT_APARTMENTTHREADED) && refs == 1)
333 imm_couninit_thread(thread_data, TRUE);
334 thread_data->apt_flags |= IMM_APT_BROKEN;
336 return S_OK;
339 static HRESULT WINAPI InitializeSpy_PostInitialize(IInitializeSpy *iface,
340 HRESULT hr, DWORD coinit, DWORD refs)
342 IMMThreadData *thread_data = impl_from_IInitializeSpy(iface);
344 if ((thread_data->apt_flags & IMM_APT_CREATED) && hr == S_FALSE && refs == 2)
345 hr = S_OK;
346 if (SUCCEEDED(hr))
347 thread_data->apt_flags |= IMM_APT_CAN_FREE;
348 return hr;
351 static HRESULT WINAPI InitializeSpy_PreUninitialize(IInitializeSpy *iface, DWORD refs)
353 return S_OK;
356 static HRESULT WINAPI InitializeSpy_PostUninitialize(IInitializeSpy *iface, DWORD refs)
358 IMMThreadData *thread_data = impl_from_IInitializeSpy(iface);
360 if (refs == 1 && !thread_data->windowRefs)
361 imm_couninit_thread(thread_data, FALSE);
362 else if (!refs)
363 thread_data->apt_flags &= ~IMM_APT_CAN_FREE;
364 return S_OK;
367 static const IInitializeSpyVtbl InitializeSpyVtbl =
369 InitializeSpy_QueryInterface,
370 InitializeSpy_AddRef,
371 InitializeSpy_Release,
372 InitializeSpy_PreInitialize,
373 InitializeSpy_PostInitialize,
374 InitializeSpy_PreUninitialize,
375 InitializeSpy_PostUninitialize,
378 static IMMThreadData *IMM_GetThreadData(HWND hwnd, DWORD thread)
380 IMMThreadData *data;
381 DWORD process;
383 if (hwnd)
385 if (!(thread = GetWindowThreadProcessId(hwnd, &process))) return NULL;
386 if (process != GetCurrentProcessId()) return NULL;
388 else if (thread)
390 HANDLE h = OpenThread(THREAD_QUERY_INFORMATION, FALSE, thread);
391 if (!h) return NULL;
392 process = GetProcessIdOfThread(h);
393 CloseHandle(h);
394 if (process != GetCurrentProcessId()) return NULL;
396 else
397 thread = GetCurrentThreadId();
399 EnterCriticalSection(&threaddata_cs);
400 LIST_FOR_EACH_ENTRY(data, &ImmThreadDataList, IMMThreadData, entry)
401 if (data->threadID == thread) return data;
403 data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data));
404 data->IInitializeSpy_iface.lpVtbl = &InitializeSpyVtbl;
405 data->threadID = thread;
406 list_add_head(&ImmThreadDataList,&data->entry);
407 TRACE("Thread Data Created (%lx)\n",thread);
408 return data;
411 static BOOL IMM_IsDefaultContext(HIMC imc)
413 InputContextData *data = get_imc_data(imc);
415 if (!data)
416 return FALSE;
418 return data->threadDefault;
421 static void IMM_FreeThreadData(void)
423 IMMThreadData *data;
425 EnterCriticalSection(&threaddata_cs);
426 LIST_FOR_EACH_ENTRY(data, &ImmThreadDataList, IMMThreadData, entry)
428 if (data->threadID == GetCurrentThreadId())
430 list_remove(&data->entry);
431 LeaveCriticalSection(&threaddata_cs);
432 IMM_DestroyContext(data->defaultContext);
433 imm_couninit_thread(data, TRUE);
434 HeapFree(GetProcessHeap(),0,data);
435 TRACE("Thread Data Destroyed\n");
436 return;
439 LeaveCriticalSection(&threaddata_cs);
442 static HMODULE load_graphics_driver(void)
444 static const WCHAR key_pathW[] = L"System\\CurrentControlSet\\Control\\Video\\{";
445 static const WCHAR displayW[] = L"}\\0000";
447 HMODULE ret = 0;
448 HKEY hkey;
449 DWORD size;
450 WCHAR path[MAX_PATH];
451 WCHAR key[ARRAY_SIZE( key_pathW ) + ARRAY_SIZE( displayW ) + 40];
452 UINT guid_atom = HandleToULong( GetPropW( GetDesktopWindow(), L"__wine_display_device_guid" ));
454 if (!guid_atom) return 0;
455 memcpy( key, key_pathW, sizeof(key_pathW) );
456 if (!GlobalGetAtomNameW( guid_atom, key + lstrlenW(key), 40 )) return 0;
457 lstrcatW( key, displayW );
458 if (RegOpenKeyW( HKEY_LOCAL_MACHINE, key, &hkey )) return 0;
459 size = sizeof(path);
460 if (!RegQueryValueExW( hkey, L"GraphicsDriver", NULL, NULL, (BYTE *)path, &size ))
461 ret = LoadLibraryW( path );
462 RegCloseKey( hkey );
463 TRACE( "%s %p\n", debugstr_w(path), ret );
464 return ret;
467 /* ImmHkl loading and freeing */
468 #define LOAD_FUNCPTR(f) if((ptr->p##f = (LPVOID)GetProcAddress(ptr->hIME, #f)) == NULL){WARN("Can't find function %s in ime\n", #f);}
469 static ImmHkl *IMM_GetImmHkl(HKL hkl)
471 ImmHkl *ptr;
472 WCHAR filename[MAX_PATH];
474 TRACE("Seeking ime for keyboard %p\n",hkl);
476 LIST_FOR_EACH_ENTRY(ptr, &ImmHklList, ImmHkl, entry)
478 if (ptr->hkl == hkl)
479 return ptr;
481 /* not found... create it */
483 ptr = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ImmHkl));
485 ptr->hkl = hkl;
486 if (ImmGetIMEFileNameW(hkl, filename, MAX_PATH)) ptr->hIME = LoadLibraryW(filename);
487 if (!ptr->hIME) ptr->hIME = load_graphics_driver();
488 if (ptr->hIME)
490 LOAD_FUNCPTR(ImeInquire);
491 if (!ptr->pImeInquire || !ptr->pImeInquire(&ptr->imeInfo, ptr->imeClassName, NULL))
493 FreeLibrary(ptr->hIME);
494 ptr->hIME = NULL;
496 else
498 LOAD_FUNCPTR(ImeDestroy);
499 LOAD_FUNCPTR(ImeSelect);
500 if (!ptr->pImeSelect || !ptr->pImeDestroy)
502 FreeLibrary(ptr->hIME);
503 ptr->hIME = NULL;
505 else
507 LOAD_FUNCPTR(ImeConfigure);
508 LOAD_FUNCPTR(ImeEscape);
509 LOAD_FUNCPTR(ImeSetActiveContext);
510 LOAD_FUNCPTR(ImeToAsciiEx);
511 LOAD_FUNCPTR(NotifyIME);
512 LOAD_FUNCPTR(ImeRegisterWord);
513 LOAD_FUNCPTR(ImeUnregisterWord);
514 LOAD_FUNCPTR(ImeEnumRegisterWord);
515 LOAD_FUNCPTR(ImeSetCompositionString);
516 LOAD_FUNCPTR(ImeConversionList);
517 LOAD_FUNCPTR(ImeProcessKey);
518 LOAD_FUNCPTR(ImeGetRegisterWordStyle);
519 LOAD_FUNCPTR(ImeGetImeMenuItems);
520 /* make sure our classname is WCHAR */
521 if (!is_kbd_ime_unicode(ptr))
523 WCHAR bufW[17];
524 MultiByteToWideChar(CP_ACP, 0, (LPSTR)ptr->imeClassName,
525 -1, bufW, 17);
526 lstrcpyW(ptr->imeClassName, bufW);
531 list_add_head(&ImmHklList,&ptr->entry);
533 return ptr;
535 #undef LOAD_FUNCPTR
537 HWND WINAPI __wine_get_ui_window(HKL hkl)
539 ImmHkl *immHkl = IMM_GetImmHkl(hkl);
540 return immHkl->UIWnd;
543 static void IMM_FreeAllImmHkl(void)
545 ImmHkl *ptr,*cursor2;
547 LIST_FOR_EACH_ENTRY_SAFE(ptr, cursor2, &ImmHklList, ImmHkl, entry)
549 list_remove(&ptr->entry);
550 if (ptr->hIME)
552 ptr->pImeDestroy(1);
553 FreeLibrary(ptr->hIME);
555 if (ptr->UIWnd)
556 DestroyWindow(ptr->UIWnd);
557 HeapFree(GetProcessHeap(),0,ptr);
561 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved)
563 TRACE("%p, %lx, %p\n",hInstDLL,fdwReason,lpReserved);
564 switch (fdwReason)
566 case DLL_PROCESS_ATTACH:
567 if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC))
569 return FALSE;
571 break;
572 case DLL_THREAD_ATTACH:
573 break;
574 case DLL_THREAD_DETACH:
575 IMM_FreeThreadData();
576 break;
577 case DLL_PROCESS_DETACH:
578 if (lpReserved) break;
579 IMM_FreeThreadData();
580 IMM_FreeAllImmHkl();
581 break;
583 return TRUE;
586 /* for posting messages as the IME */
587 static void ImmInternalPostIMEMessage(InputContextData *data, UINT msg, WPARAM wParam, LPARAM lParam)
589 HWND target = GetFocus();
590 if (!target)
591 PostMessageW(data->IMC.hWnd,msg,wParam,lParam);
592 else
593 PostMessageW(target, msg, wParam, lParam);
596 /* for sending messages as the IME */
597 static void ImmInternalSendIMEMessage(InputContextData *data, UINT msg, WPARAM wParam, LPARAM lParam)
599 HWND target = GetFocus();
600 if (!target)
601 SendMessageW(data->IMC.hWnd,msg,wParam,lParam);
602 else
603 SendMessageW(target, msg, wParam, lParam);
606 static LRESULT ImmInternalSendIMENotify(InputContextData *data, WPARAM notify, LPARAM lParam)
608 HWND target;
610 target = data->IMC.hWnd;
611 if (!target) target = GetFocus();
613 if (target)
614 return SendMessageW(target, WM_IME_NOTIFY, notify, lParam);
616 return 0;
619 static HIMCC ImmCreateBlankCompStr(void)
621 HIMCC rc;
622 LPCOMPOSITIONSTRING ptr;
623 rc = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
624 ptr = ImmLockIMCC(rc);
625 memset(ptr,0,sizeof(COMPOSITIONSTRING));
626 ptr->dwSize = sizeof(COMPOSITIONSTRING);
627 ImmUnlockIMCC(rc);
628 return rc;
631 static InputContextData* get_imc_data(HIMC hIMC)
633 InputContextData *data = hIMC;
635 if (hIMC == NULL)
636 return NULL;
638 if(IsBadReadPtr(data, sizeof(InputContextData)) || data->magic != WINE_IMC_VALID_MAGIC)
640 SetLastError(ERROR_INVALID_HANDLE);
641 return NULL;
643 return data;
646 static HIMC get_default_context( HWND hwnd )
648 HIMC ret;
649 IMMThreadData* thread_data = IMM_GetThreadData( hwnd, 0 );
651 if (!thread_data) return 0;
653 if (thread_data->defaultContext)
655 ret = thread_data->defaultContext;
656 LeaveCriticalSection(&threaddata_cs);
657 return ret;
660 /* can't create a default context in another thread */
661 if (thread_data->threadID != GetCurrentThreadId())
663 LeaveCriticalSection(&threaddata_cs);
664 return 0;
667 LeaveCriticalSection(&threaddata_cs);
669 ret = ImmCreateContext();
670 if (!ret) return 0;
671 ((InputContextData*)ret)->threadDefault = TRUE;
673 /* thread_data is in the current thread so we can assume it's still valid */
674 EnterCriticalSection(&threaddata_cs);
676 if (thread_data->defaultContext) /* someone beat us */
678 IMM_DestroyContext( ret );
679 ret = thread_data->defaultContext;
681 else thread_data->defaultContext = ret;
683 LeaveCriticalSection(&threaddata_cs);
684 return ret;
687 static BOOL IMM_IsCrossThreadAccess(HWND hWnd, HIMC hIMC)
689 InputContextData *data;
691 if (hWnd)
693 DWORD thread = GetWindowThreadProcessId(hWnd, NULL);
694 if (thread != GetCurrentThreadId()) return TRUE;
696 data = get_imc_data(hIMC);
697 if (data && data->threadID != GetCurrentThreadId())
698 return TRUE;
700 return FALSE;
703 /***********************************************************************
704 * ImmSetActiveContext (IMM32.@)
706 BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC himc, BOOL activate)
708 InputContextData *data = get_imc_data(himc);
709 IMMThreadData *thread_data;
711 TRACE("(%p, %p, %x)\n", hwnd, himc, activate);
713 if (himc && !data && activate)
714 return FALSE;
716 thread_data = IMM_GetThreadData(hwnd, 0);
717 if (thread_data)
719 imm_coinit_thread(thread_data);
720 LeaveCriticalSection(&threaddata_cs);
723 if (data)
725 data->IMC.hWnd = activate ? hwnd : NULL;
727 if (data->immKbd->hIME && data->immKbd->pImeSetActiveContext)
728 data->immKbd->pImeSetActiveContext(himc, activate);
731 if (IsWindow(hwnd))
733 SendMessageW(hwnd, WM_IME_SETCONTEXT, activate, ISC_SHOWUIALL);
734 /* TODO: send WM_IME_NOTIFY */
736 return TRUE;
739 /***********************************************************************
740 * ImmAssociateContext (IMM32.@)
742 HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
744 InputContextData *data = get_imc_data(hIMC);
745 HIMC defaultContext;
746 HIMC old;
748 TRACE("(%p, %p):\n", hWnd, hIMC);
750 if (!IsWindow(hWnd) || (hIMC && !data))
751 return NULL;
753 if (hIMC && IMM_IsCrossThreadAccess(hWnd, hIMC))
754 return NULL;
756 old = GetPropW(hWnd, szwWineIMCProperty);
757 defaultContext = get_default_context( hWnd );
758 if (!old)
759 old = defaultContext;
760 else if (old == (HIMC)-1)
761 old = NULL;
763 /* If already associated just return */
764 if (old == hIMC)
765 return hIMC;
767 if (!hIMC) /* Meaning disable imm for that window*/
768 SetPropW(hWnd, szwWineIMCProperty, (HANDLE)-1);
769 else if (hIMC == defaultContext)
770 RemovePropW(hWnd, szwWineIMCProperty);
771 else
772 SetPropW(hWnd, szwWineIMCProperty, hIMC);
774 if (GetFocus() == hWnd)
776 ImmSetActiveContext(hWnd, old, FALSE);
777 ImmSetActiveContext(hWnd, hIMC, TRUE);
779 return old;
784 * Helper function for ImmAssociateContextEx
786 static BOOL CALLBACK _ImmAssociateContextExEnumProc(HWND hwnd, LPARAM lParam)
788 HIMC hImc = (HIMC)lParam;
789 ImmAssociateContext(hwnd,hImc);
790 return TRUE;
793 /***********************************************************************
794 * ImmAssociateContextEx (IMM32.@)
796 BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags)
798 TRACE("(%p, %p, 0x%lx):\n", hWnd, hIMC, dwFlags);
800 if (!hWnd)
801 return FALSE;
803 switch (dwFlags)
805 case 0:
806 ImmAssociateContext(hWnd,hIMC);
807 return TRUE;
808 case IACE_DEFAULT:
810 HIMC defaultContext = get_default_context( hWnd );
811 if (!defaultContext) return FALSE;
812 ImmAssociateContext(hWnd,defaultContext);
813 return TRUE;
815 case IACE_IGNORENOCONTEXT:
816 if (GetPropW(hWnd,szwWineIMCProperty))
817 ImmAssociateContext(hWnd,hIMC);
818 return TRUE;
819 case IACE_CHILDREN:
820 EnumChildWindows(hWnd,_ImmAssociateContextExEnumProc,(LPARAM)hIMC);
821 return TRUE;
822 default:
823 FIXME("Unknown dwFlags 0x%lx\n",dwFlags);
824 return FALSE;
828 /***********************************************************************
829 * ImmConfigureIMEA (IMM32.@)
831 BOOL WINAPI ImmConfigureIMEA(
832 HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
834 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
836 TRACE("(%p, %p, %ld, %p):\n", hKL, hWnd, dwMode, lpData);
838 if (dwMode == IME_CONFIG_REGISTERWORD && !lpData)
839 return FALSE;
841 if (immHkl->hIME && immHkl->pImeConfigure)
843 if (dwMode != IME_CONFIG_REGISTERWORD || !is_kbd_ime_unicode(immHkl))
844 return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData);
845 else
847 REGISTERWORDW rww;
848 REGISTERWORDA *rwa = lpData;
849 BOOL rc;
851 rww.lpReading = strdupAtoW(rwa->lpReading);
852 rww.lpWord = strdupAtoW(rwa->lpWord);
853 rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rww);
854 HeapFree(GetProcessHeap(),0,rww.lpReading);
855 HeapFree(GetProcessHeap(),0,rww.lpWord);
856 return rc;
859 else
860 return FALSE;
863 /***********************************************************************
864 * ImmConfigureIMEW (IMM32.@)
866 BOOL WINAPI ImmConfigureIMEW(
867 HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
869 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
871 TRACE("(%p, %p, %ld, %p):\n", hKL, hWnd, dwMode, lpData);
873 if (dwMode == IME_CONFIG_REGISTERWORD && !lpData)
874 return FALSE;
876 if (immHkl->hIME && immHkl->pImeConfigure)
878 if (dwMode != IME_CONFIG_REGISTERWORD || is_kbd_ime_unicode(immHkl))
879 return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData);
880 else
882 REGISTERWORDW *rww = lpData;
883 REGISTERWORDA rwa;
884 BOOL rc;
886 rwa.lpReading = strdupWtoA(rww->lpReading);
887 rwa.lpWord = strdupWtoA(rww->lpWord);
888 rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rwa);
889 HeapFree(GetProcessHeap(),0,rwa.lpReading);
890 HeapFree(GetProcessHeap(),0,rwa.lpWord);
891 return rc;
894 else
895 return FALSE;
898 /***********************************************************************
899 * ImmCreateContext (IMM32.@)
901 HIMC WINAPI ImmCreateContext(void)
903 InputContextData *new_context;
904 LPGUIDELINE gl;
905 LPCANDIDATEINFO ci;
906 int i;
908 new_context = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(InputContextData));
910 /* Load the IME */
911 new_context->immKbd = IMM_GetImmHkl(GetKeyboardLayout(0));
913 if (!new_context->immKbd->hIME)
915 TRACE("IME dll could not be loaded\n");
916 HeapFree(GetProcessHeap(),0,new_context);
917 return 0;
920 /* the HIMCCs are never NULL */
921 new_context->IMC.hCompStr = ImmCreateBlankCompStr();
922 new_context->IMC.hMsgBuf = ImmCreateIMCC(0);
923 new_context->IMC.hCandInfo = ImmCreateIMCC(sizeof(CANDIDATEINFO));
924 ci = ImmLockIMCC(new_context->IMC.hCandInfo);
925 memset(ci,0,sizeof(CANDIDATEINFO));
926 ci->dwSize = sizeof(CANDIDATEINFO);
927 ImmUnlockIMCC(new_context->IMC.hCandInfo);
928 new_context->IMC.hGuideLine = ImmCreateIMCC(sizeof(GUIDELINE));
929 gl = ImmLockIMCC(new_context->IMC.hGuideLine);
930 memset(gl,0,sizeof(GUIDELINE));
931 gl->dwSize = sizeof(GUIDELINE);
932 ImmUnlockIMCC(new_context->IMC.hGuideLine);
934 for (i = 0; i < ARRAY_SIZE(new_context->IMC.cfCandForm); i++)
935 new_context->IMC.cfCandForm[i].dwIndex = ~0u;
937 /* Initialize the IME Private */
938 new_context->IMC.hPrivate = ImmCreateIMCC(new_context->immKbd->imeInfo.dwPrivateDataSize);
940 new_context->IMC.fdwConversion = new_context->immKbd->imeInfo.fdwConversionCaps;
941 new_context->IMC.fdwSentence = new_context->immKbd->imeInfo.fdwSentenceCaps;
943 if (!new_context->immKbd->pImeSelect(new_context, TRUE))
945 TRACE("Selection of IME failed\n");
946 IMM_DestroyContext(new_context);
947 return 0;
949 new_context->threadID = GetCurrentThreadId();
950 SendMessageW(GetFocus(), WM_IME_SELECT, TRUE, (LPARAM)new_context->immKbd);
952 new_context->immKbd->uSelected++;
953 TRACE("Created context %p\n",new_context);
955 new_context->magic = WINE_IMC_VALID_MAGIC;
956 return new_context;
959 static BOOL IMM_DestroyContext(HIMC hIMC)
961 InputContextData *data = get_imc_data(hIMC);
963 TRACE("Destroying %p\n",hIMC);
965 if (!data)
966 return FALSE;
968 data->immKbd->uSelected --;
969 data->immKbd->pImeSelect(hIMC, FALSE);
970 SendMessageW(data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)data->immKbd);
972 ImmDestroyIMCC(data->IMC.hCompStr);
973 ImmDestroyIMCC(data->IMC.hCandInfo);
974 ImmDestroyIMCC(data->IMC.hGuideLine);
975 ImmDestroyIMCC(data->IMC.hPrivate);
976 ImmDestroyIMCC(data->IMC.hMsgBuf);
978 data->magic = 0;
979 HeapFree(GetProcessHeap(),0,data);
981 return TRUE;
984 /***********************************************************************
985 * ImmDestroyContext (IMM32.@)
987 BOOL WINAPI ImmDestroyContext(HIMC hIMC)
989 if (!IMM_IsDefaultContext(hIMC) && !IMM_IsCrossThreadAccess(NULL, hIMC))
990 return IMM_DestroyContext(hIMC);
991 else
992 return FALSE;
995 static HWND imm_detach_default_window(IMMThreadData *thread_data)
997 HWND to_destroy;
999 imm_couninit_thread(thread_data, TRUE);
1000 to_destroy = thread_data->hwndDefault;
1001 thread_data->hwndDefault = NULL;
1002 thread_data->windowRefs = 0;
1003 return to_destroy;
1006 /***********************************************************************
1007 * ImmDisableIME (IMM32.@)
1009 BOOL WINAPI ImmDisableIME(DWORD idThread)
1011 IMMThreadData *thread_data;
1012 HWND to_destroy;
1014 if (idThread == (DWORD)-1)
1016 disable_ime = TRUE;
1018 while (1)
1020 to_destroy = 0;
1021 EnterCriticalSection(&threaddata_cs);
1022 LIST_FOR_EACH_ENTRY(thread_data, &ImmThreadDataList, IMMThreadData, entry)
1024 if (thread_data->hwndDefault)
1026 to_destroy = imm_detach_default_window(thread_data);
1027 break;
1030 LeaveCriticalSection(&threaddata_cs);
1032 if (!to_destroy)
1033 break;
1034 DestroyWindow(to_destroy);
1037 else
1039 thread_data = IMM_GetThreadData(NULL, idThread);
1040 if (!thread_data) return FALSE;
1041 thread_data->disableIME = TRUE;
1042 to_destroy = imm_detach_default_window(thread_data);
1043 LeaveCriticalSection(&threaddata_cs);
1045 if (to_destroy)
1046 DestroyWindow(to_destroy);
1048 return TRUE;
1051 /***********************************************************************
1052 * ImmEnumRegisterWordA (IMM32.@)
1054 UINT WINAPI ImmEnumRegisterWordA(
1055 HKL hKL, REGISTERWORDENUMPROCA lpfnEnumProc,
1056 LPCSTR lpszReading, DWORD dwStyle,
1057 LPCSTR lpszRegister, LPVOID lpData)
1059 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1060 TRACE("(%p, %p, %s, %ld, %s, %p):\n", hKL, lpfnEnumProc,
1061 debugstr_a(lpszReading), dwStyle, debugstr_a(lpszRegister), lpData);
1062 if (immHkl->hIME && immHkl->pImeEnumRegisterWord)
1064 if (!is_kbd_ime_unicode(immHkl))
1065 return immHkl->pImeEnumRegisterWord((REGISTERWORDENUMPROCW)lpfnEnumProc,
1066 (LPCWSTR)lpszReading, dwStyle, (LPCWSTR)lpszRegister, lpData);
1067 else
1069 LPWSTR lpszwReading = strdupAtoW(lpszReading);
1070 LPWSTR lpszwRegister = strdupAtoW(lpszRegister);
1071 BOOL rc;
1073 rc = immHkl->pImeEnumRegisterWord((REGISTERWORDENUMPROCW)lpfnEnumProc,
1074 lpszwReading, dwStyle, lpszwRegister,
1075 lpData);
1077 HeapFree(GetProcessHeap(),0,lpszwReading);
1078 HeapFree(GetProcessHeap(),0,lpszwRegister);
1079 return rc;
1082 else
1083 return 0;
1086 /***********************************************************************
1087 * ImmEnumRegisterWordW (IMM32.@)
1089 UINT WINAPI ImmEnumRegisterWordW(
1090 HKL hKL, REGISTERWORDENUMPROCW lpfnEnumProc,
1091 LPCWSTR lpszReading, DWORD dwStyle,
1092 LPCWSTR lpszRegister, LPVOID lpData)
1094 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1095 TRACE("(%p, %p, %s, %ld, %s, %p):\n", hKL, lpfnEnumProc,
1096 debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister), lpData);
1097 if (immHkl->hIME && immHkl->pImeEnumRegisterWord)
1099 if (is_kbd_ime_unicode(immHkl))
1100 return immHkl->pImeEnumRegisterWord(lpfnEnumProc, lpszReading, dwStyle,
1101 lpszRegister, lpData);
1102 else
1104 LPSTR lpszaReading = strdupWtoA(lpszReading);
1105 LPSTR lpszaRegister = strdupWtoA(lpszRegister);
1106 BOOL rc;
1108 rc = immHkl->pImeEnumRegisterWord(lpfnEnumProc, (LPCWSTR)lpszaReading,
1109 dwStyle, (LPCWSTR)lpszaRegister, lpData);
1111 HeapFree(GetProcessHeap(),0,lpszaReading);
1112 HeapFree(GetProcessHeap(),0,lpszaRegister);
1113 return rc;
1116 else
1117 return 0;
1120 static inline BOOL EscapeRequiresWA(UINT uEscape)
1122 if (uEscape == IME_ESC_GET_EUDC_DICTIONARY ||
1123 uEscape == IME_ESC_SET_EUDC_DICTIONARY ||
1124 uEscape == IME_ESC_IME_NAME ||
1125 uEscape == IME_ESC_GETHELPFILENAME)
1126 return TRUE;
1127 return FALSE;
1130 /***********************************************************************
1131 * ImmEscapeA (IMM32.@)
1133 LRESULT WINAPI ImmEscapeA(
1134 HKL hKL, HIMC hIMC,
1135 UINT uEscape, LPVOID lpData)
1137 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1138 TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData);
1140 if (immHkl->hIME && immHkl->pImeEscape)
1142 if (!EscapeRequiresWA(uEscape) || !is_kbd_ime_unicode(immHkl))
1143 return immHkl->pImeEscape(hIMC,uEscape,lpData);
1144 else
1146 WCHAR buffer[81]; /* largest required buffer should be 80 */
1147 LRESULT rc;
1148 if (uEscape == IME_ESC_SET_EUDC_DICTIONARY)
1150 MultiByteToWideChar(CP_ACP,0,lpData,-1,buffer,81);
1151 rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
1153 else
1155 rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
1156 WideCharToMultiByte(CP_ACP,0,buffer,-1,lpData,80, NULL, NULL);
1158 return rc;
1161 else
1162 return 0;
1165 /***********************************************************************
1166 * ImmEscapeW (IMM32.@)
1168 LRESULT WINAPI ImmEscapeW(
1169 HKL hKL, HIMC hIMC,
1170 UINT uEscape, LPVOID lpData)
1172 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1173 TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData);
1175 if (immHkl->hIME && immHkl->pImeEscape)
1177 if (!EscapeRequiresWA(uEscape) || is_kbd_ime_unicode(immHkl))
1178 return immHkl->pImeEscape(hIMC,uEscape,lpData);
1179 else
1181 CHAR buffer[81]; /* largest required buffer should be 80 */
1182 LRESULT rc;
1183 if (uEscape == IME_ESC_SET_EUDC_DICTIONARY)
1185 WideCharToMultiByte(CP_ACP,0,lpData,-1,buffer,81, NULL, NULL);
1186 rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
1188 else
1190 rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
1191 MultiByteToWideChar(CP_ACP,0,buffer,-1,lpData,80);
1193 return rc;
1196 else
1197 return 0;
1200 /***********************************************************************
1201 * ImmGetCandidateListA (IMM32.@)
1203 DWORD WINAPI ImmGetCandidateListA(
1204 HIMC hIMC, DWORD dwIndex,
1205 LPCANDIDATELIST lpCandList, DWORD dwBufLen)
1207 InputContextData *data = get_imc_data(hIMC);
1208 LPCANDIDATEINFO candinfo;
1209 LPCANDIDATELIST candlist;
1210 DWORD ret = 0;
1212 TRACE("%p, %ld, %p, %ld\n", hIMC, dwIndex, lpCandList, dwBufLen);
1214 if (!data || !data->IMC.hCandInfo)
1215 return 0;
1217 candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1218 if (dwIndex >= candinfo->dwCount || dwIndex >= ARRAY_SIZE(candinfo->dwOffset))
1219 goto done;
1221 candlist = (LPCANDIDATELIST)((LPBYTE)candinfo + candinfo->dwOffset[dwIndex]);
1222 if ( !candlist->dwSize || !candlist->dwCount )
1223 goto done;
1225 if ( !is_himc_ime_unicode(data) )
1227 ret = candlist->dwSize;
1228 if ( lpCandList && dwBufLen >= ret )
1229 memcpy(lpCandList, candlist, ret);
1231 else
1232 ret = convert_candidatelist_WtoA( candlist, lpCandList, dwBufLen);
1234 done:
1235 ImmUnlockIMCC(data->IMC.hCandInfo);
1236 return ret;
1239 /***********************************************************************
1240 * ImmGetCandidateListCountA (IMM32.@)
1242 DWORD WINAPI ImmGetCandidateListCountA(
1243 HIMC hIMC, LPDWORD lpdwListCount)
1245 InputContextData *data = get_imc_data(hIMC);
1246 LPCANDIDATEINFO candinfo;
1247 DWORD ret, count;
1249 TRACE("%p, %p\n", hIMC, lpdwListCount);
1251 if (!data || !lpdwListCount || !data->IMC.hCandInfo)
1252 return 0;
1254 candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1256 *lpdwListCount = count = candinfo->dwCount;
1258 if ( !is_himc_ime_unicode(data) )
1259 ret = candinfo->dwSize;
1260 else
1262 ret = sizeof(CANDIDATEINFO);
1263 while ( count-- )
1264 ret += ImmGetCandidateListA(hIMC, count, NULL, 0);
1267 ImmUnlockIMCC(data->IMC.hCandInfo);
1268 return ret;
1271 /***********************************************************************
1272 * ImmGetCandidateListCountW (IMM32.@)
1274 DWORD WINAPI ImmGetCandidateListCountW(
1275 HIMC hIMC, LPDWORD lpdwListCount)
1277 InputContextData *data = get_imc_data(hIMC);
1278 LPCANDIDATEINFO candinfo;
1279 DWORD ret, count;
1281 TRACE("%p, %p\n", hIMC, lpdwListCount);
1283 if (!data || !lpdwListCount || !data->IMC.hCandInfo)
1284 return 0;
1286 candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1288 *lpdwListCount = count = candinfo->dwCount;
1290 if ( is_himc_ime_unicode(data) )
1291 ret = candinfo->dwSize;
1292 else
1294 ret = sizeof(CANDIDATEINFO);
1295 while ( count-- )
1296 ret += ImmGetCandidateListW(hIMC, count, NULL, 0);
1299 ImmUnlockIMCC(data->IMC.hCandInfo);
1300 return ret;
1303 /***********************************************************************
1304 * ImmGetCandidateListW (IMM32.@)
1306 DWORD WINAPI ImmGetCandidateListW(
1307 HIMC hIMC, DWORD dwIndex,
1308 LPCANDIDATELIST lpCandList, DWORD dwBufLen)
1310 InputContextData *data = get_imc_data(hIMC);
1311 LPCANDIDATEINFO candinfo;
1312 LPCANDIDATELIST candlist;
1313 DWORD ret = 0;
1315 TRACE("%p, %ld, %p, %ld\n", hIMC, dwIndex, lpCandList, dwBufLen);
1317 if (!data || !data->IMC.hCandInfo)
1318 return 0;
1320 candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1321 if (dwIndex >= candinfo->dwCount || dwIndex >= ARRAY_SIZE(candinfo->dwOffset))
1322 goto done;
1324 candlist = (LPCANDIDATELIST)((LPBYTE)candinfo + candinfo->dwOffset[dwIndex]);
1325 if ( !candlist->dwSize || !candlist->dwCount )
1326 goto done;
1328 if ( is_himc_ime_unicode(data) )
1330 ret = candlist->dwSize;
1331 if ( lpCandList && dwBufLen >= ret )
1332 memcpy(lpCandList, candlist, ret);
1334 else
1335 ret = convert_candidatelist_AtoW( candlist, lpCandList, dwBufLen);
1337 done:
1338 ImmUnlockIMCC(data->IMC.hCandInfo);
1339 return ret;
1342 /***********************************************************************
1343 * ImmGetCandidateWindow (IMM32.@)
1345 BOOL WINAPI ImmGetCandidateWindow(
1346 HIMC hIMC, DWORD dwIndex, LPCANDIDATEFORM lpCandidate)
1348 InputContextData *data = get_imc_data(hIMC);
1350 TRACE("%p, %ld, %p\n", hIMC, dwIndex, lpCandidate);
1352 if (!data || !lpCandidate)
1353 return FALSE;
1355 if (dwIndex >= ARRAY_SIZE(data->IMC.cfCandForm))
1356 return FALSE;
1358 if (data->IMC.cfCandForm[dwIndex].dwIndex != dwIndex)
1359 return FALSE;
1361 *lpCandidate = data->IMC.cfCandForm[dwIndex];
1363 return TRUE;
1366 /***********************************************************************
1367 * ImmGetCompositionFontA (IMM32.@)
1369 BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
1371 LOGFONTW lfW;
1372 BOOL rc;
1374 TRACE("(%p, %p):\n", hIMC, lplf);
1376 rc = ImmGetCompositionFontW(hIMC,&lfW);
1377 if (!rc || !lplf)
1378 return FALSE;
1380 memcpy(lplf,&lfW,sizeof(LOGFONTA));
1381 WideCharToMultiByte(CP_ACP, 0, lfW.lfFaceName, -1, lplf->lfFaceName,
1382 LF_FACESIZE, NULL, NULL);
1383 return TRUE;
1386 /***********************************************************************
1387 * ImmGetCompositionFontW (IMM32.@)
1389 BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
1391 InputContextData *data = get_imc_data(hIMC);
1393 TRACE("(%p, %p):\n", hIMC, lplf);
1395 if (!data || !lplf)
1396 return FALSE;
1398 *lplf = data->IMC.lfFont.W;
1400 return TRUE;
1404 /* Helpers for the GetCompositionString functions */
1406 /* Source encoding is defined by context, source length is always given in respective characters. Destination buffer
1407 length is always in bytes. */
1408 static INT CopyCompStringIMEtoClient(const InputContextData *data, const void *src, INT src_len, void *dst,
1409 INT dst_len, BOOL unicode)
1411 int char_size = unicode ? sizeof(WCHAR) : sizeof(char);
1412 INT ret;
1414 if (is_himc_ime_unicode(data) ^ unicode)
1416 if (unicode)
1417 ret = MultiByteToWideChar(CP_ACP, 0, src, src_len, dst, dst_len / sizeof(WCHAR));
1418 else
1419 ret = WideCharToMultiByte(CP_ACP, 0, src, src_len, dst, dst_len, NULL, NULL);
1420 ret *= char_size;
1422 else
1424 if (dst_len)
1426 ret = min(src_len * char_size, dst_len);
1427 memcpy(dst, src, ret);
1429 else
1430 ret = src_len * char_size;
1433 return ret;
1436 /* Composition string encoding is defined by context, returned attributes correspond to string, converted according to
1437 passed mode. String length is in characters, attributes are in byte arrays. */
1438 static INT CopyCompAttrIMEtoClient(const InputContextData *data, const BYTE *src, INT src_len, const void *comp_string,
1439 INT str_len, BYTE *dst, INT dst_len, BOOL unicode)
1441 union
1443 const void *str;
1444 const WCHAR *strW;
1445 const char *strA;
1446 } string;
1447 INT rc;
1449 string.str = comp_string;
1451 if (is_himc_ime_unicode(data) && !unicode)
1453 rc = WideCharToMultiByte(CP_ACP, 0, string.strW, str_len, NULL, 0, NULL, NULL);
1454 if (dst_len)
1456 int i, j = 0, k = 0;
1458 if (rc < dst_len)
1459 dst_len = rc;
1460 for (i = 0; i < str_len; ++i)
1462 int len;
1464 len = WideCharToMultiByte(CP_ACP, 0, string.strW + i, 1, NULL, 0, NULL, NULL);
1465 for (; len > 0; --len)
1467 dst[j++] = src[k];
1469 if (j >= dst_len)
1470 goto end;
1472 ++k;
1474 end:
1475 rc = j;
1478 else if (!is_himc_ime_unicode(data) && unicode)
1480 rc = MultiByteToWideChar(CP_ACP, 0, string.strA, str_len, NULL, 0);
1481 if (dst_len)
1483 int i, j = 0;
1485 if (rc < dst_len)
1486 dst_len = rc;
1487 for (i = 0; i < str_len; ++i)
1489 if (IsDBCSLeadByte(string.strA[i]))
1490 continue;
1492 dst[j++] = src[i];
1494 if (j >= dst_len)
1495 break;
1497 rc = j;
1500 else
1502 memcpy(dst, src, min(src_len, dst_len));
1503 rc = src_len;
1506 return rc;
1509 static INT CopyCompClauseIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE ssource,
1510 LPBYTE target, INT tlen, BOOL unicode )
1512 INT rc;
1514 if (is_himc_ime_unicode(data) && !unicode)
1516 if (tlen)
1518 int i;
1520 if (slen < tlen)
1521 tlen = slen;
1522 tlen /= sizeof (DWORD);
1523 for (i = 0; i < tlen; ++i)
1525 ((DWORD *)target)[i] = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource,
1526 ((DWORD *)source)[i],
1527 NULL, 0,
1528 NULL, NULL);
1530 rc = sizeof (DWORD) * i;
1532 else
1533 rc = slen;
1535 else if (!is_himc_ime_unicode(data) && unicode)
1537 if (tlen)
1539 int i;
1541 if (slen < tlen)
1542 tlen = slen;
1543 tlen /= sizeof (DWORD);
1544 for (i = 0; i < tlen; ++i)
1546 ((DWORD *)target)[i] = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource,
1547 ((DWORD *)source)[i],
1548 NULL, 0);
1550 rc = sizeof (DWORD) * i;
1552 else
1553 rc = slen;
1555 else
1557 memcpy( target, source, min(slen,tlen));
1558 rc = slen;
1561 return rc;
1564 static INT CopyCompOffsetIMEtoClient(InputContextData *data, DWORD offset, LPBYTE ssource, BOOL unicode)
1566 int rc;
1568 if (is_himc_ime_unicode(data) && !unicode)
1570 rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, offset, NULL, 0, NULL, NULL);
1572 else if (!is_himc_ime_unicode(data) && unicode)
1574 rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, offset, NULL, 0);
1576 else
1577 rc = offset;
1579 return rc;
1582 static LONG ImmGetCompositionStringT( HIMC hIMC, DWORD dwIndex, LPVOID lpBuf,
1583 DWORD dwBufLen, BOOL unicode)
1585 LONG rc = 0;
1586 InputContextData *data = get_imc_data(hIMC);
1587 LPCOMPOSITIONSTRING compstr;
1588 LPBYTE compdata;
1590 TRACE("(%p, 0x%lx, %p, %ld)\n", hIMC, dwIndex, lpBuf, dwBufLen);
1592 if (!data)
1593 return FALSE;
1595 if (!data->IMC.hCompStr)
1596 return FALSE;
1598 compdata = ImmLockIMCC(data->IMC.hCompStr);
1599 compstr = (LPCOMPOSITIONSTRING)compdata;
1601 switch (dwIndex)
1603 case GCS_RESULTSTR:
1604 TRACE("GCS_RESULTSTR\n");
1605 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultStrOffset, compstr->dwResultStrLen, lpBuf, dwBufLen, unicode);
1606 break;
1607 case GCS_COMPSTR:
1608 TRACE("GCS_COMPSTR\n");
1609 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen, lpBuf, dwBufLen, unicode);
1610 break;
1611 case GCS_COMPATTR:
1612 TRACE("GCS_COMPATTR\n");
1613 rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompAttrOffset, compstr->dwCompAttrLen,
1614 compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen,
1615 lpBuf, dwBufLen, unicode);
1616 break;
1617 case GCS_COMPCLAUSE:
1618 TRACE("GCS_COMPCLAUSE\n");
1619 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompClauseOffset,compstr->dwCompClauseLen,
1620 compdata + compstr->dwCompStrOffset,
1621 lpBuf, dwBufLen, unicode);
1622 break;
1623 case GCS_RESULTCLAUSE:
1624 TRACE("GCS_RESULTCLAUSE\n");
1625 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultClauseOffset,compstr->dwResultClauseLen,
1626 compdata + compstr->dwResultStrOffset,
1627 lpBuf, dwBufLen, unicode);
1628 break;
1629 case GCS_RESULTREADSTR:
1630 TRACE("GCS_RESULTREADSTR\n");
1631 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultReadStrOffset, compstr->dwResultReadStrLen, lpBuf, dwBufLen, unicode);
1632 break;
1633 case GCS_RESULTREADCLAUSE:
1634 TRACE("GCS_RESULTREADCLAUSE\n");
1635 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultReadClauseOffset,compstr->dwResultReadClauseLen,
1636 compdata + compstr->dwResultStrOffset,
1637 lpBuf, dwBufLen, unicode);
1638 break;
1639 case GCS_COMPREADSTR:
1640 TRACE("GCS_COMPREADSTR\n");
1641 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen, lpBuf, dwBufLen, unicode);
1642 break;
1643 case GCS_COMPREADATTR:
1644 TRACE("GCS_COMPREADATTR\n");
1645 rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompReadAttrOffset, compstr->dwCompReadAttrLen,
1646 compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen,
1647 lpBuf, dwBufLen, unicode);
1648 break;
1649 case GCS_COMPREADCLAUSE:
1650 TRACE("GCS_COMPREADCLAUSE\n");
1651 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompReadClauseOffset,compstr->dwCompReadClauseLen,
1652 compdata + compstr->dwCompStrOffset,
1653 lpBuf, dwBufLen, unicode);
1654 break;
1655 case GCS_CURSORPOS:
1656 TRACE("GCS_CURSORPOS\n");
1657 rc = CopyCompOffsetIMEtoClient(data, compstr->dwCursorPos, compdata + compstr->dwCompStrOffset, unicode);
1658 break;
1659 case GCS_DELTASTART:
1660 TRACE("GCS_DELTASTART\n");
1661 rc = CopyCompOffsetIMEtoClient(data, compstr->dwDeltaStart, compdata + compstr->dwCompStrOffset, unicode);
1662 break;
1663 default:
1664 FIXME("Unhandled index 0x%lx\n",dwIndex);
1665 break;
1668 ImmUnlockIMCC(data->IMC.hCompStr);
1670 return rc;
1673 /***********************************************************************
1674 * ImmGetCompositionStringA (IMM32.@)
1676 LONG WINAPI ImmGetCompositionStringA(
1677 HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
1679 return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, FALSE);
1683 /***********************************************************************
1684 * ImmGetCompositionStringW (IMM32.@)
1686 LONG WINAPI ImmGetCompositionStringW(
1687 HIMC hIMC, DWORD dwIndex,
1688 LPVOID lpBuf, DWORD dwBufLen)
1690 return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, TRUE);
1693 /***********************************************************************
1694 * ImmGetCompositionWindow (IMM32.@)
1696 BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
1698 InputContextData *data = get_imc_data(hIMC);
1700 TRACE("(%p, %p)\n", hIMC, lpCompForm);
1702 if (!data)
1703 return FALSE;
1705 *lpCompForm = data->IMC.cfCompForm;
1706 return TRUE;
1709 /***********************************************************************
1710 * ImmGetContext (IMM32.@)
1713 HIMC WINAPI ImmGetContext(HWND hWnd)
1715 HIMC rc;
1717 TRACE("%p\n", hWnd);
1719 if (!IsWindow(hWnd))
1721 SetLastError(ERROR_INVALID_WINDOW_HANDLE);
1722 return NULL;
1725 rc = GetPropW(hWnd,szwWineIMCProperty);
1726 if (rc == (HIMC)-1)
1727 rc = NULL;
1728 else if (rc == NULL)
1729 rc = get_default_context( hWnd );
1731 if (rc)
1733 InputContextData *data = rc;
1734 data->IMC.hWnd = hWnd;
1737 TRACE("returning %p\n", rc);
1739 return rc;
1742 /***********************************************************************
1743 * ImmGetConversionListA (IMM32.@)
1745 DWORD WINAPI ImmGetConversionListA(
1746 HKL hKL, HIMC hIMC,
1747 LPCSTR pSrc, LPCANDIDATELIST lpDst,
1748 DWORD dwBufLen, UINT uFlag)
1750 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1751 TRACE("(%p, %p, %s, %p, %ld, %d):\n", hKL, hIMC, debugstr_a(pSrc), lpDst,
1752 dwBufLen, uFlag);
1753 if (immHkl->hIME && immHkl->pImeConversionList)
1755 if (!is_kbd_ime_unicode(immHkl))
1756 return immHkl->pImeConversionList(hIMC,(LPCWSTR)pSrc,lpDst,dwBufLen,uFlag);
1757 else
1759 LPCANDIDATELIST lpwDst;
1760 DWORD ret = 0, len;
1761 LPWSTR pwSrc = strdupAtoW(pSrc);
1763 len = immHkl->pImeConversionList(hIMC, pwSrc, NULL, 0, uFlag);
1764 lpwDst = HeapAlloc(GetProcessHeap(), 0, len);
1765 if ( lpwDst )
1767 immHkl->pImeConversionList(hIMC, pwSrc, lpwDst, len, uFlag);
1768 ret = convert_candidatelist_WtoA( lpwDst, lpDst, dwBufLen);
1769 HeapFree(GetProcessHeap(), 0, lpwDst);
1771 HeapFree(GetProcessHeap(), 0, pwSrc);
1773 return ret;
1776 else
1777 return 0;
1780 /***********************************************************************
1781 * ImmGetConversionListW (IMM32.@)
1783 DWORD WINAPI ImmGetConversionListW(
1784 HKL hKL, HIMC hIMC,
1785 LPCWSTR pSrc, LPCANDIDATELIST lpDst,
1786 DWORD dwBufLen, UINT uFlag)
1788 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1789 TRACE("(%p, %p, %s, %p, %ld, %d):\n", hKL, hIMC, debugstr_w(pSrc), lpDst,
1790 dwBufLen, uFlag);
1791 if (immHkl->hIME && immHkl->pImeConversionList)
1793 if (is_kbd_ime_unicode(immHkl))
1794 return immHkl->pImeConversionList(hIMC,pSrc,lpDst,dwBufLen,uFlag);
1795 else
1797 LPCANDIDATELIST lpaDst;
1798 DWORD ret = 0, len;
1799 LPSTR paSrc = strdupWtoA(pSrc);
1801 len = immHkl->pImeConversionList(hIMC, (LPCWSTR)paSrc, NULL, 0, uFlag);
1802 lpaDst = HeapAlloc(GetProcessHeap(), 0, len);
1803 if ( lpaDst )
1805 immHkl->pImeConversionList(hIMC, (LPCWSTR)paSrc, lpaDst, len, uFlag);
1806 ret = convert_candidatelist_AtoW( lpaDst, lpDst, dwBufLen);
1807 HeapFree(GetProcessHeap(), 0, lpaDst);
1809 HeapFree(GetProcessHeap(), 0, paSrc);
1811 return ret;
1814 else
1815 return 0;
1818 /***********************************************************************
1819 * ImmGetConversionStatus (IMM32.@)
1821 BOOL WINAPI ImmGetConversionStatus(
1822 HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence)
1824 InputContextData *data = get_imc_data(hIMC);
1826 TRACE("%p %p %p\n", hIMC, lpfdwConversion, lpfdwSentence);
1828 if (!data)
1829 return FALSE;
1831 if (lpfdwConversion)
1832 *lpfdwConversion = data->IMC.fdwConversion;
1833 if (lpfdwSentence)
1834 *lpfdwSentence = data->IMC.fdwSentence;
1836 return TRUE;
1839 static BOOL needs_ime_window(HWND hwnd)
1841 WCHAR classW[8];
1843 if (GetClassNameW(hwnd, classW, ARRAY_SIZE(classW)) && !lstrcmpW(classW, L"IME"))
1844 return FALSE;
1845 if (GetClassLongPtrW(hwnd, GCL_STYLE) & CS_IME) return FALSE;
1847 return TRUE;
1850 /***********************************************************************
1851 * __wine_register_window (IMM32.@)
1853 BOOL WINAPI __wine_register_window(HWND hwnd)
1855 HWND new = NULL;
1856 IMMThreadData *thread_data;
1857 TRACE("(%p)\n", hwnd);
1859 if (!needs_ime_window(hwnd))
1860 return FALSE;
1862 thread_data = IMM_GetThreadData(hwnd, 0);
1863 if (!thread_data)
1864 return FALSE;
1866 if (thread_data->disableIME || disable_ime)
1868 TRACE("IME for this thread is disabled\n");
1869 LeaveCriticalSection(&threaddata_cs);
1870 return FALSE;
1872 thread_data->windowRefs++;
1873 TRACE("windowRefs=%lu, hwndDefault=%p\n",
1874 thread_data->windowRefs, thread_data->hwndDefault);
1876 /* Create default IME window */
1877 if (thread_data->windowRefs == 1)
1879 /* Do not create the window inside of a critical section */
1880 LeaveCriticalSection(&threaddata_cs);
1881 new = CreateWindowExW( 0, L"IME", L"Default IME",
1882 WS_POPUP | WS_DISABLED | WS_CLIPSIBLINGS,
1883 0, 0, 1, 1, 0, 0, 0, 0);
1884 /* thread_data is in the current thread so we can assume it's still valid */
1885 EnterCriticalSection(&threaddata_cs);
1886 /* See if anyone beat us */
1887 if (thread_data->hwndDefault == NULL)
1889 thread_data->hwndDefault = new;
1890 new = NULL;
1891 TRACE("Default is %p\n", thread_data->hwndDefault);
1895 LeaveCriticalSection(&threaddata_cs);
1897 /* Clean up an unused new window outside of the critical section */
1898 if (new != NULL)
1899 DestroyWindow(new);
1900 return TRUE;
1903 /***********************************************************************
1904 * __wine_unregister_window (IMM32.@)
1906 void WINAPI __wine_unregister_window(HWND hwnd)
1908 HWND to_destroy = 0;
1909 IMMThreadData *thread_data;
1910 TRACE("(%p)\n", hwnd);
1912 thread_data = IMM_GetThreadData(hwnd, 0);
1913 if (!thread_data) return;
1915 thread_data->windowRefs--;
1916 TRACE("windowRefs=%lu, hwndDefault=%p\n",
1917 thread_data->windowRefs, thread_data->hwndDefault);
1919 /* Destroy default IME window */
1920 if (thread_data->windowRefs == 0)
1921 to_destroy = imm_detach_default_window(thread_data);
1922 LeaveCriticalSection(&threaddata_cs);
1924 if (to_destroy) DestroyWindow( to_destroy );
1927 /***********************************************************************
1928 * ImmGetDefaultIMEWnd (IMM32.@)
1930 HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
1932 HWND ret;
1933 IMMThreadData* thread_data = IMM_GetThreadData(hWnd, 0);
1934 if (!thread_data)
1935 return NULL;
1936 ret = thread_data->hwndDefault;
1937 LeaveCriticalSection(&threaddata_cs);
1938 TRACE("Default is %p\n",ret);
1939 return ret;
1942 /***********************************************************************
1943 * ImmGetDescriptionA (IMM32.@)
1945 UINT WINAPI ImmGetDescriptionA(
1946 HKL hKL, LPSTR lpszDescription, UINT uBufLen)
1948 WCHAR *buf;
1949 DWORD len;
1951 TRACE("%p %p %d\n", hKL, lpszDescription, uBufLen);
1953 /* find out how many characters in the unicode buffer */
1954 len = ImmGetDescriptionW( hKL, NULL, 0 );
1955 if (!len)
1956 return 0;
1958 /* allocate a buffer of that size */
1959 buf = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof (WCHAR) );
1960 if( !buf )
1961 return 0;
1963 /* fetch the unicode buffer */
1964 len = ImmGetDescriptionW( hKL, buf, len + 1 );
1966 /* convert it back to ANSI */
1967 len = WideCharToMultiByte( CP_ACP, 0, buf, len + 1,
1968 lpszDescription, uBufLen, NULL, NULL );
1970 HeapFree( GetProcessHeap(), 0, buf );
1972 if (len == 0)
1973 return 0;
1975 return len - 1;
1978 /***********************************************************************
1979 * ImmGetDescriptionW (IMM32.@)
1981 UINT WINAPI ImmGetDescriptionW(HKL hKL, LPWSTR lpszDescription, UINT uBufLen)
1983 FIXME("(%p, %p, %d): semi stub\n", hKL, lpszDescription, uBufLen);
1985 if (!hKL) return 0;
1986 if (!uBufLen) return lstrlenW(L"Wine XIM" );
1987 lstrcpynW( lpszDescription, L"Wine XIM", uBufLen );
1988 return lstrlenW( lpszDescription );
1991 /***********************************************************************
1992 * ImmGetGuideLineA (IMM32.@)
1994 DWORD WINAPI ImmGetGuideLineA(
1995 HIMC hIMC, DWORD dwIndex, LPSTR lpBuf, DWORD dwBufLen)
1997 FIXME("(%p, %ld, %s, %ld): stub\n",
1998 hIMC, dwIndex, debugstr_a(lpBuf), dwBufLen
2000 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2001 return 0;
2004 /***********************************************************************
2005 * ImmGetGuideLineW (IMM32.@)
2007 DWORD WINAPI ImmGetGuideLineW(HIMC hIMC, DWORD dwIndex, LPWSTR lpBuf, DWORD dwBufLen)
2009 FIXME("(%p, %ld, %s, %ld): stub\n",
2010 hIMC, dwIndex, debugstr_w(lpBuf), dwBufLen
2012 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2013 return 0;
2016 /***********************************************************************
2017 * ImmGetIMEFileNameA (IMM32.@)
2019 UINT WINAPI ImmGetIMEFileNameA( HKL hKL, LPSTR lpszFileName, UINT uBufLen)
2021 LPWSTR bufW = NULL;
2022 UINT wBufLen = uBufLen;
2023 UINT rc;
2025 if (uBufLen && lpszFileName)
2026 bufW = HeapAlloc(GetProcessHeap(),0,uBufLen * sizeof(WCHAR));
2027 else /* We need this to get the number of byte required */
2029 bufW = HeapAlloc(GetProcessHeap(),0,MAX_PATH * sizeof(WCHAR));
2030 wBufLen = MAX_PATH;
2033 rc = ImmGetIMEFileNameW(hKL,bufW,wBufLen);
2035 if (rc > 0)
2037 if (uBufLen && lpszFileName)
2038 rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, lpszFileName,
2039 uBufLen, NULL, NULL);
2040 else /* get the length */
2041 rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL,
2042 NULL);
2045 HeapFree(GetProcessHeap(),0,bufW);
2046 return rc;
2049 /***********************************************************************
2050 * ImmGetIMEFileNameW (IMM32.@)
2052 UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen)
2054 HKEY hkey;
2055 DWORD length;
2056 DWORD rc;
2057 WCHAR regKey[ARRAY_SIZE(szImeRegFmt)+8];
2059 wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hKL );
2060 rc = RegOpenKeyW( HKEY_LOCAL_MACHINE, regKey, &hkey);
2061 if (rc != ERROR_SUCCESS)
2063 SetLastError(rc);
2064 return 0;
2067 length = 0;
2068 rc = RegGetValueW(hkey, NULL, L"Ime File", RRF_RT_REG_SZ, NULL, NULL, &length);
2070 if (rc != ERROR_SUCCESS)
2072 RegCloseKey(hkey);
2073 SetLastError(rc);
2074 return 0;
2076 if (length > uBufLen * sizeof(WCHAR) || !lpszFileName)
2078 RegCloseKey(hkey);
2079 if (lpszFileName)
2081 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2082 return 0;
2084 else
2085 return length / sizeof(WCHAR);
2088 RegGetValueW(hkey, NULL, L"Ime File", RRF_RT_REG_SZ, NULL, lpszFileName, &length);
2090 RegCloseKey(hkey);
2092 return length / sizeof(WCHAR);
2095 /***********************************************************************
2096 * ImmGetOpenStatus (IMM32.@)
2098 BOOL WINAPI ImmGetOpenStatus(HIMC hIMC)
2100 InputContextData *data = get_imc_data(hIMC);
2101 static int i;
2103 if (!data)
2104 return FALSE;
2106 TRACE("(%p): semi-stub\n", hIMC);
2108 if (!i++)
2109 FIXME("(%p): semi-stub\n", hIMC);
2111 return data->IMC.fOpen;
2114 /***********************************************************************
2115 * ImmGetProperty (IMM32.@)
2117 DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex)
2119 DWORD rc = 0;
2120 ImmHkl *kbd;
2122 TRACE("(%p, %ld)\n", hKL, fdwIndex);
2123 kbd = IMM_GetImmHkl(hKL);
2125 if (kbd && kbd->hIME)
2127 switch (fdwIndex)
2129 case IGP_PROPERTY: rc = kbd->imeInfo.fdwProperty; break;
2130 case IGP_CONVERSION: rc = kbd->imeInfo.fdwConversionCaps; break;
2131 case IGP_SENTENCE: rc = kbd->imeInfo.fdwSentenceCaps; break;
2132 case IGP_SETCOMPSTR: rc = kbd->imeInfo.fdwSCSCaps; break;
2133 case IGP_SELECT: rc = kbd->imeInfo.fdwSelectCaps; break;
2134 case IGP_GETIMEVERSION: rc = IMEVER_0400; break;
2135 case IGP_UI: rc = 0; break;
2136 default: rc = 0;
2139 return rc;
2142 /***********************************************************************
2143 * ImmGetRegisterWordStyleA (IMM32.@)
2145 UINT WINAPI ImmGetRegisterWordStyleA(
2146 HKL hKL, UINT nItem, LPSTYLEBUFA lpStyleBuf)
2148 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2149 TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf);
2150 if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle)
2152 if (!is_kbd_ime_unicode(immHkl))
2153 return immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)lpStyleBuf);
2154 else
2156 STYLEBUFW sbw;
2157 UINT rc;
2159 rc = immHkl->pImeGetRegisterWordStyle(nItem,&sbw);
2160 WideCharToMultiByte(CP_ACP, 0, sbw.szDescription, -1,
2161 lpStyleBuf->szDescription, 32, NULL, NULL);
2162 lpStyleBuf->dwStyle = sbw.dwStyle;
2163 return rc;
2166 else
2167 return 0;
2170 /***********************************************************************
2171 * ImmGetRegisterWordStyleW (IMM32.@)
2173 UINT WINAPI ImmGetRegisterWordStyleW(
2174 HKL hKL, UINT nItem, LPSTYLEBUFW lpStyleBuf)
2176 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2177 TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf);
2178 if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle)
2180 if (is_kbd_ime_unicode(immHkl))
2181 return immHkl->pImeGetRegisterWordStyle(nItem,lpStyleBuf);
2182 else
2184 STYLEBUFA sba;
2185 UINT rc;
2187 rc = immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)&sba);
2188 MultiByteToWideChar(CP_ACP, 0, sba.szDescription, -1,
2189 lpStyleBuf->szDescription, 32);
2190 lpStyleBuf->dwStyle = sba.dwStyle;
2191 return rc;
2194 else
2195 return 0;
2198 /***********************************************************************
2199 * ImmGetStatusWindowPos (IMM32.@)
2201 BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
2203 InputContextData *data = get_imc_data(hIMC);
2205 TRACE("(%p, %p)\n", hIMC, lpptPos);
2207 if (!data || !lpptPos)
2208 return FALSE;
2210 *lpptPos = data->IMC.ptStatusWndPos;
2212 return TRUE;
2215 /***********************************************************************
2216 * ImmGetVirtualKey (IMM32.@)
2218 UINT WINAPI ImmGetVirtualKey(HWND hWnd)
2220 OSVERSIONINFOA version;
2221 InputContextData *data = ImmGetContext( hWnd );
2222 TRACE("%p\n", hWnd);
2224 if ( data )
2225 return data->lastVK;
2227 version.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
2228 GetVersionExA( &version );
2229 switch(version.dwPlatformId)
2231 case VER_PLATFORM_WIN32_WINDOWS:
2232 return VK_PROCESSKEY;
2233 case VER_PLATFORM_WIN32_NT:
2234 return 0;
2235 default:
2236 FIXME("%ld not supported\n",version.dwPlatformId);
2237 return VK_PROCESSKEY;
2241 /***********************************************************************
2242 * ImmInstallIMEA (IMM32.@)
2244 HKL WINAPI ImmInstallIMEA(
2245 LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
2247 LPWSTR lpszwIMEFileName;
2248 LPWSTR lpszwLayoutText;
2249 HKL hkl;
2251 TRACE ("(%s, %s)\n", debugstr_a(lpszIMEFileName),
2252 debugstr_a(lpszLayoutText));
2254 lpszwIMEFileName = strdupAtoW(lpszIMEFileName);
2255 lpszwLayoutText = strdupAtoW(lpszLayoutText);
2257 hkl = ImmInstallIMEW(lpszwIMEFileName, lpszwLayoutText);
2259 HeapFree(GetProcessHeap(),0,lpszwIMEFileName);
2260 HeapFree(GetProcessHeap(),0,lpszwLayoutText);
2261 return hkl;
2264 /***********************************************************************
2265 * ImmInstallIMEW (IMM32.@)
2267 HKL WINAPI ImmInstallIMEW(
2268 LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
2270 INT lcid = GetUserDefaultLCID();
2271 INT count;
2272 HKL hkl;
2273 DWORD rc;
2274 HKEY hkey;
2275 WCHAR regKey[ARRAY_SIZE(szImeRegFmt)+8];
2277 TRACE ("(%s, %s):\n", debugstr_w(lpszIMEFileName),
2278 debugstr_w(lpszLayoutText));
2280 /* Start with 2. e001 will be blank and so default to the wine internal IME */
2281 count = 2;
2283 while (count < 0xfff)
2285 DWORD disposition = 0;
2287 hkl = (HKL)MAKELPARAM( lcid, 0xe000 | count );
2288 wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hkl);
2290 rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, regKey, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &disposition);
2291 if (rc == ERROR_SUCCESS && disposition == REG_CREATED_NEW_KEY)
2292 break;
2293 else if (rc == ERROR_SUCCESS)
2294 RegCloseKey(hkey);
2296 count++;
2299 if (count == 0xfff)
2301 WARN("Unable to find slot to install IME\n");
2302 return 0;
2305 if (rc == ERROR_SUCCESS)
2307 rc = RegSetValueExW(hkey, L"Ime File", 0, REG_SZ, (const BYTE*)lpszIMEFileName,
2308 (lstrlenW(lpszIMEFileName) + 1) * sizeof(WCHAR));
2309 if (rc == ERROR_SUCCESS)
2310 rc = RegSetValueExW(hkey, L"Layout Text", 0, REG_SZ, (const BYTE*)lpszLayoutText,
2311 (lstrlenW(lpszLayoutText) + 1) * sizeof(WCHAR));
2312 RegCloseKey(hkey);
2313 return hkl;
2315 else
2317 WARN("Unable to set IME registry values\n");
2318 return 0;
2322 /***********************************************************************
2323 * ImmIsIME (IMM32.@)
2325 BOOL WINAPI ImmIsIME(HKL hKL)
2327 ImmHkl *ptr;
2328 TRACE("(%p):\n", hKL);
2329 ptr = IMM_GetImmHkl(hKL);
2330 return (ptr && ptr->hIME);
2333 /***********************************************************************
2334 * ImmIsUIMessageA (IMM32.@)
2336 BOOL WINAPI ImmIsUIMessageA(
2337 HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
2339 TRACE("(%p, %x, %Id, %Id)\n", hWndIME, msg, wParam, lParam);
2340 if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
2341 (msg == WM_IME_SETCONTEXT) ||
2342 (msg == WM_IME_NOTIFY) ||
2343 (msg == WM_IME_COMPOSITIONFULL) ||
2344 (msg == WM_IME_SELECT) ||
2345 (msg == 0x287 /* FIXME: WM_IME_SYSTEM */))
2347 if (hWndIME)
2348 SendMessageA(hWndIME, msg, wParam, lParam);
2350 return TRUE;
2352 return FALSE;
2355 /***********************************************************************
2356 * ImmIsUIMessageW (IMM32.@)
2358 BOOL WINAPI ImmIsUIMessageW(
2359 HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
2361 TRACE("(%p, %x, %Id, %Id)\n", hWndIME, msg, wParam, lParam);
2362 if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
2363 (msg == WM_IME_SETCONTEXT) ||
2364 (msg == WM_IME_NOTIFY) ||
2365 (msg == WM_IME_COMPOSITIONFULL) ||
2366 (msg == WM_IME_SELECT) ||
2367 (msg == 0x287 /* FIXME: WM_IME_SYSTEM */))
2369 if (hWndIME)
2370 SendMessageW(hWndIME, msg, wParam, lParam);
2372 return TRUE;
2374 return FALSE;
2377 /***********************************************************************
2378 * ImmNotifyIME (IMM32.@)
2380 BOOL WINAPI ImmNotifyIME(
2381 HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
2383 InputContextData *data = get_imc_data(hIMC);
2385 TRACE("(%p, %ld, %ld, %ld)\n",
2386 hIMC, dwAction, dwIndex, dwValue);
2388 if (hIMC == NULL)
2390 SetLastError(ERROR_SUCCESS);
2391 return FALSE;
2394 if (!data || ! data->immKbd->pNotifyIME)
2396 return FALSE;
2399 return data->immKbd->pNotifyIME(hIMC,dwAction,dwIndex,dwValue);
2402 /***********************************************************************
2403 * ImmRegisterWordA (IMM32.@)
2405 BOOL WINAPI ImmRegisterWordA(
2406 HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszRegister)
2408 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2409 TRACE("(%p, %s, %ld, %s):\n", hKL, debugstr_a(lpszReading), dwStyle,
2410 debugstr_a(lpszRegister));
2411 if (immHkl->hIME && immHkl->pImeRegisterWord)
2413 if (!is_kbd_ime_unicode(immHkl))
2414 return immHkl->pImeRegisterWord((LPCWSTR)lpszReading,dwStyle,
2415 (LPCWSTR)lpszRegister);
2416 else
2418 LPWSTR lpszwReading = strdupAtoW(lpszReading);
2419 LPWSTR lpszwRegister = strdupAtoW(lpszRegister);
2420 BOOL rc;
2422 rc = immHkl->pImeRegisterWord(lpszwReading,dwStyle,lpszwRegister);
2423 HeapFree(GetProcessHeap(),0,lpszwReading);
2424 HeapFree(GetProcessHeap(),0,lpszwRegister);
2425 return rc;
2428 else
2429 return FALSE;
2432 /***********************************************************************
2433 * ImmRegisterWordW (IMM32.@)
2435 BOOL WINAPI ImmRegisterWordW(
2436 HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszRegister)
2438 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2439 TRACE("(%p, %s, %ld, %s):\n", hKL, debugstr_w(lpszReading), dwStyle,
2440 debugstr_w(lpszRegister));
2441 if (immHkl->hIME && immHkl->pImeRegisterWord)
2443 if (is_kbd_ime_unicode(immHkl))
2444 return immHkl->pImeRegisterWord(lpszReading,dwStyle,lpszRegister);
2445 else
2447 LPSTR lpszaReading = strdupWtoA(lpszReading);
2448 LPSTR lpszaRegister = strdupWtoA(lpszRegister);
2449 BOOL rc;
2451 rc = immHkl->pImeRegisterWord((LPCWSTR)lpszaReading,dwStyle,
2452 (LPCWSTR)lpszaRegister);
2453 HeapFree(GetProcessHeap(),0,lpszaReading);
2454 HeapFree(GetProcessHeap(),0,lpszaRegister);
2455 return rc;
2458 else
2459 return FALSE;
2462 /***********************************************************************
2463 * ImmReleaseContext (IMM32.@)
2465 BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC)
2467 static BOOL shown = FALSE;
2469 if (!shown) {
2470 FIXME("(%p, %p): stub\n", hWnd, hIMC);
2471 shown = TRUE;
2473 return TRUE;
2476 /***********************************************************************
2477 * ImmRequestMessageA(IMM32.@)
2479 LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam)
2481 InputContextData *data = get_imc_data(hIMC);
2483 TRACE("%p %Id %Id\n", hIMC, wParam, wParam);
2485 if (data) return SendMessageA(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
2487 SetLastError(ERROR_INVALID_HANDLE);
2488 return 0;
2491 /***********************************************************************
2492 * ImmRequestMessageW(IMM32.@)
2494 LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam)
2496 InputContextData *data = get_imc_data(hIMC);
2498 TRACE("%p %Id %Id\n", hIMC, wParam, wParam);
2500 if (data) return SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
2502 SetLastError(ERROR_INVALID_HANDLE);
2503 return 0;
2506 /***********************************************************************
2507 * ImmSetCandidateWindow (IMM32.@)
2509 BOOL WINAPI ImmSetCandidateWindow(
2510 HIMC hIMC, LPCANDIDATEFORM lpCandidate)
2512 InputContextData *data = get_imc_data(hIMC);
2514 TRACE("(%p, %p)\n", hIMC, lpCandidate);
2516 if (!data || !lpCandidate)
2517 return FALSE;
2519 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2520 return FALSE;
2522 TRACE("\t%lx, %lx, %s, %s\n",
2523 lpCandidate->dwIndex, lpCandidate->dwStyle,
2524 wine_dbgstr_point(&lpCandidate->ptCurrentPos),
2525 wine_dbgstr_rect(&lpCandidate->rcArea));
2527 if (lpCandidate->dwIndex >= ARRAY_SIZE(data->IMC.cfCandForm))
2528 return FALSE;
2530 data->IMC.cfCandForm[lpCandidate->dwIndex] = *lpCandidate;
2531 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCANDIDATEPOS);
2532 ImmInternalSendIMENotify(data, IMN_SETCANDIDATEPOS, 1 << lpCandidate->dwIndex);
2534 return TRUE;
2537 /***********************************************************************
2538 * ImmSetCompositionFontA (IMM32.@)
2540 BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
2542 InputContextData *data = get_imc_data(hIMC);
2543 TRACE("(%p, %p)\n", hIMC, lplf);
2545 if (!data || !lplf)
2547 SetLastError(ERROR_INVALID_HANDLE);
2548 return FALSE;
2551 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2552 return FALSE;
2554 memcpy(&data->IMC.lfFont.W,lplf,sizeof(LOGFONTA));
2555 MultiByteToWideChar(CP_ACP, 0, lplf->lfFaceName, -1, data->IMC.lfFont.W.lfFaceName,
2556 LF_FACESIZE);
2557 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT);
2558 ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
2560 return TRUE;
2563 /***********************************************************************
2564 * ImmSetCompositionFontW (IMM32.@)
2566 BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
2568 InputContextData *data = get_imc_data(hIMC);
2569 TRACE("(%p, %p)\n", hIMC, lplf);
2571 if (!data || !lplf)
2573 SetLastError(ERROR_INVALID_HANDLE);
2574 return FALSE;
2577 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2578 return FALSE;
2580 data->IMC.lfFont.W = *lplf;
2581 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT);
2582 ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
2584 return TRUE;
2587 /***********************************************************************
2588 * ImmSetCompositionStringA (IMM32.@)
2590 BOOL WINAPI ImmSetCompositionStringA(
2591 HIMC hIMC, DWORD dwIndex,
2592 LPCVOID lpComp, DWORD dwCompLen,
2593 LPCVOID lpRead, DWORD dwReadLen)
2595 DWORD comp_len;
2596 DWORD read_len;
2597 WCHAR *CompBuffer = NULL;
2598 WCHAR *ReadBuffer = NULL;
2599 BOOL rc;
2600 InputContextData *data = get_imc_data(hIMC);
2602 TRACE("(%p, %ld, %p, %ld, %p, %ld):\n",
2603 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
2605 if (!data)
2606 return FALSE;
2608 if (!(dwIndex == SCS_SETSTR ||
2609 dwIndex == SCS_CHANGEATTR ||
2610 dwIndex == SCS_CHANGECLAUSE ||
2611 dwIndex == SCS_SETRECONVERTSTRING ||
2612 dwIndex == SCS_QUERYRECONVERTSTRING))
2613 return FALSE;
2615 if (!is_himc_ime_unicode(data))
2616 return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
2617 dwCompLen, lpRead, dwReadLen);
2619 comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0);
2620 if (comp_len)
2622 CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len * sizeof(WCHAR));
2623 MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len);
2626 read_len = MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, NULL, 0);
2627 if (read_len)
2629 ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len * sizeof(WCHAR));
2630 MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len);
2633 rc = ImmSetCompositionStringW(hIMC, dwIndex, CompBuffer, comp_len,
2634 ReadBuffer, read_len);
2636 HeapFree(GetProcessHeap(), 0, CompBuffer);
2637 HeapFree(GetProcessHeap(), 0, ReadBuffer);
2639 return rc;
2642 /***********************************************************************
2643 * ImmSetCompositionStringW (IMM32.@)
2645 BOOL WINAPI ImmSetCompositionStringW(
2646 HIMC hIMC, DWORD dwIndex,
2647 LPCVOID lpComp, DWORD dwCompLen,
2648 LPCVOID lpRead, DWORD dwReadLen)
2650 DWORD comp_len;
2651 DWORD read_len;
2652 CHAR *CompBuffer = NULL;
2653 CHAR *ReadBuffer = NULL;
2654 BOOL rc;
2655 InputContextData *data = get_imc_data(hIMC);
2657 TRACE("(%p, %ld, %p, %ld, %p, %ld):\n",
2658 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
2660 if (!data)
2661 return FALSE;
2663 if (!(dwIndex == SCS_SETSTR ||
2664 dwIndex == SCS_CHANGEATTR ||
2665 dwIndex == SCS_CHANGECLAUSE ||
2666 dwIndex == SCS_SETRECONVERTSTRING ||
2667 dwIndex == SCS_QUERYRECONVERTSTRING))
2668 return FALSE;
2670 if (is_himc_ime_unicode(data))
2671 return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
2672 dwCompLen, lpRead, dwReadLen);
2674 comp_len = WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, NULL, 0, NULL,
2675 NULL);
2676 if (comp_len)
2678 CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len);
2679 WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len,
2680 NULL, NULL);
2683 read_len = WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, NULL, 0, NULL,
2684 NULL);
2685 if (read_len)
2687 ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len);
2688 WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len,
2689 NULL, NULL);
2692 rc = ImmSetCompositionStringA(hIMC, dwIndex, CompBuffer, comp_len,
2693 ReadBuffer, read_len);
2695 HeapFree(GetProcessHeap(), 0, CompBuffer);
2696 HeapFree(GetProcessHeap(), 0, ReadBuffer);
2698 return rc;
2701 /***********************************************************************
2702 * ImmSetCompositionWindow (IMM32.@)
2704 BOOL WINAPI ImmSetCompositionWindow(
2705 HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
2707 BOOL reshow = FALSE;
2708 InputContextData *data = get_imc_data(hIMC);
2710 TRACE("(%p, %p)\n", hIMC, lpCompForm);
2711 if (lpCompForm)
2712 TRACE("\t%lx, %s, %s\n", lpCompForm->dwStyle,
2713 wine_dbgstr_point(&lpCompForm->ptCurrentPos),
2714 wine_dbgstr_rect(&lpCompForm->rcArea));
2716 if (!data)
2718 SetLastError(ERROR_INVALID_HANDLE);
2719 return FALSE;
2722 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2723 return FALSE;
2725 data->IMC.cfCompForm = *lpCompForm;
2727 if (IsWindowVisible(data->immKbd->UIWnd))
2729 reshow = TRUE;
2730 ShowWindow(data->immKbd->UIWnd,SW_HIDE);
2733 /* FIXME: this is a partial stub */
2735 if (reshow)
2736 ShowWindow(data->immKbd->UIWnd,SW_SHOWNOACTIVATE);
2738 ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONWINDOW, 0);
2739 return TRUE;
2742 /***********************************************************************
2743 * ImmSetConversionStatus (IMM32.@)
2745 BOOL WINAPI ImmSetConversionStatus(
2746 HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence)
2748 DWORD oldConversion, oldSentence;
2749 InputContextData *data = get_imc_data(hIMC);
2751 TRACE("%p %ld %ld\n", hIMC, fdwConversion, fdwSentence);
2753 if (!data)
2755 SetLastError(ERROR_INVALID_HANDLE);
2756 return FALSE;
2759 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2760 return FALSE;
2762 if ( fdwConversion != data->IMC.fdwConversion )
2764 oldConversion = data->IMC.fdwConversion;
2765 data->IMC.fdwConversion = fdwConversion;
2766 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldConversion, IMC_SETCONVERSIONMODE);
2767 ImmInternalSendIMENotify(data, IMN_SETCONVERSIONMODE, 0);
2769 if ( fdwSentence != data->IMC.fdwSentence )
2771 oldSentence = data->IMC.fdwSentence;
2772 data->IMC.fdwSentence = fdwSentence;
2773 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldSentence, IMC_SETSENTENCEMODE);
2774 ImmInternalSendIMENotify(data, IMN_SETSENTENCEMODE, 0);
2777 return TRUE;
2780 /***********************************************************************
2781 * ImmSetOpenStatus (IMM32.@)
2783 BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen)
2785 InputContextData *data = get_imc_data(hIMC);
2787 TRACE("%p %d\n", hIMC, fOpen);
2789 if (!data)
2791 SetLastError(ERROR_INVALID_HANDLE);
2792 return FALSE;
2795 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2796 return FALSE;
2798 if (data->immKbd->UIWnd == NULL)
2800 /* create the ime window */
2801 data->immKbd->UIWnd = CreateWindowExW( WS_EX_TOOLWINDOW,
2802 data->immKbd->imeClassName, NULL, WS_POPUP, 0, 0, 1, 1, 0,
2803 0, data->immKbd->hIME, 0);
2804 SetWindowLongPtrW(data->immKbd->UIWnd, IMMGWL_IMC, (LONG_PTR)data);
2806 else if (fOpen)
2807 SetWindowLongPtrW(data->immKbd->UIWnd, IMMGWL_IMC, (LONG_PTR)data);
2809 if (!fOpen != !data->IMC.fOpen)
2811 data->IMC.fOpen = fOpen;
2812 ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETOPENSTATUS);
2813 ImmInternalSendIMENotify(data, IMN_SETOPENSTATUS, 0);
2816 return TRUE;
2819 /***********************************************************************
2820 * ImmSetStatusWindowPos (IMM32.@)
2822 BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
2824 InputContextData *data = get_imc_data(hIMC);
2826 TRACE("(%p, %p)\n", hIMC, lpptPos);
2828 if (!data || !lpptPos)
2830 SetLastError(ERROR_INVALID_HANDLE);
2831 return FALSE;
2834 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2835 return FALSE;
2837 TRACE("\t%s\n", wine_dbgstr_point(lpptPos));
2839 data->IMC.ptStatusWndPos = *lpptPos;
2840 ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETSTATUSWINDOWPOS);
2841 ImmInternalSendIMENotify(data, IMN_SETSTATUSWINDOWPOS, 0);
2843 return TRUE;
2846 /***********************************************************************
2847 * ImmCreateSoftKeyboard(IMM32.@)
2849 HWND WINAPI ImmCreateSoftKeyboard(UINT uType, UINT hOwner, int x, int y)
2851 FIXME("(%d, %d, %d, %d): stub\n", uType, hOwner, x, y);
2852 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2853 return 0;
2856 /***********************************************************************
2857 * ImmDestroySoftKeyboard(IMM32.@)
2859 BOOL WINAPI ImmDestroySoftKeyboard(HWND hSoftWnd)
2861 FIXME("(%p): stub\n", hSoftWnd);
2862 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2863 return FALSE;
2866 /***********************************************************************
2867 * ImmShowSoftKeyboard(IMM32.@)
2869 BOOL WINAPI ImmShowSoftKeyboard(HWND hSoftWnd, int nCmdShow)
2871 FIXME("(%p, %d): stub\n", hSoftWnd, nCmdShow);
2872 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2873 return FALSE;
2876 /***********************************************************************
2877 * ImmSimulateHotKey (IMM32.@)
2879 BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID)
2881 FIXME("(%p, %ld): stub\n", hWnd, dwHotKeyID);
2882 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2883 return FALSE;
2886 /***********************************************************************
2887 * ImmUnregisterWordA (IMM32.@)
2889 BOOL WINAPI ImmUnregisterWordA(
2890 HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszUnregister)
2892 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2893 TRACE("(%p, %s, %ld, %s):\n", hKL, debugstr_a(lpszReading), dwStyle,
2894 debugstr_a(lpszUnregister));
2895 if (immHkl->hIME && immHkl->pImeUnregisterWord)
2897 if (!is_kbd_ime_unicode(immHkl))
2898 return immHkl->pImeUnregisterWord((LPCWSTR)lpszReading,dwStyle,
2899 (LPCWSTR)lpszUnregister);
2900 else
2902 LPWSTR lpszwReading = strdupAtoW(lpszReading);
2903 LPWSTR lpszwUnregister = strdupAtoW(lpszUnregister);
2904 BOOL rc;
2906 rc = immHkl->pImeUnregisterWord(lpszwReading,dwStyle,lpszwUnregister);
2907 HeapFree(GetProcessHeap(),0,lpszwReading);
2908 HeapFree(GetProcessHeap(),0,lpszwUnregister);
2909 return rc;
2912 else
2913 return FALSE;
2916 /***********************************************************************
2917 * ImmUnregisterWordW (IMM32.@)
2919 BOOL WINAPI ImmUnregisterWordW(
2920 HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszUnregister)
2922 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2923 TRACE("(%p, %s, %ld, %s):\n", hKL, debugstr_w(lpszReading), dwStyle,
2924 debugstr_w(lpszUnregister));
2925 if (immHkl->hIME && immHkl->pImeUnregisterWord)
2927 if (is_kbd_ime_unicode(immHkl))
2928 return immHkl->pImeUnregisterWord(lpszReading,dwStyle,lpszUnregister);
2929 else
2931 LPSTR lpszaReading = strdupWtoA(lpszReading);
2932 LPSTR lpszaUnregister = strdupWtoA(lpszUnregister);
2933 BOOL rc;
2935 rc = immHkl->pImeUnregisterWord((LPCWSTR)lpszaReading,dwStyle,
2936 (LPCWSTR)lpszaUnregister);
2937 HeapFree(GetProcessHeap(),0,lpszaReading);
2938 HeapFree(GetProcessHeap(),0,lpszaUnregister);
2939 return rc;
2942 else
2943 return FALSE;
2946 /***********************************************************************
2947 * ImmGetImeMenuItemsA (IMM32.@)
2949 DWORD WINAPI ImmGetImeMenuItemsA( HIMC hIMC, DWORD dwFlags, DWORD dwType,
2950 LPIMEMENUITEMINFOA lpImeParentMenu, LPIMEMENUITEMINFOA lpImeMenu,
2951 DWORD dwSize)
2953 InputContextData *data = get_imc_data(hIMC);
2954 TRACE("(%p, %li, %li, %p, %p, %li):\n", hIMC, dwFlags, dwType,
2955 lpImeParentMenu, lpImeMenu, dwSize);
2957 if (!data)
2959 SetLastError(ERROR_INVALID_HANDLE);
2960 return 0;
2963 if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
2965 if (!is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
2966 return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2967 (IMEMENUITEMINFOW*)lpImeParentMenu,
2968 (IMEMENUITEMINFOW*)lpImeMenu, dwSize);
2969 else
2971 IMEMENUITEMINFOW lpImeParentMenuW;
2972 IMEMENUITEMINFOW *lpImeMenuW, *parent = NULL;
2973 DWORD rc;
2975 if (lpImeParentMenu)
2976 parent = &lpImeParentMenuW;
2977 if (lpImeMenu)
2979 int count = dwSize / sizeof(LPIMEMENUITEMINFOA);
2980 dwSize = count * sizeof(IMEMENUITEMINFOW);
2981 lpImeMenuW = HeapAlloc(GetProcessHeap(), 0, dwSize);
2983 else
2984 lpImeMenuW = NULL;
2986 rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2987 parent, lpImeMenuW, dwSize);
2989 if (lpImeParentMenu)
2991 memcpy(lpImeParentMenu,&lpImeParentMenuW,sizeof(IMEMENUITEMINFOA));
2992 lpImeParentMenu->hbmpItem = lpImeParentMenuW.hbmpItem;
2993 WideCharToMultiByte(CP_ACP, 0, lpImeParentMenuW.szString,
2994 -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE,
2995 NULL, NULL);
2997 if (lpImeMenu && rc)
2999 unsigned int i;
3000 for (i = 0; i < rc; i++)
3002 memcpy(&lpImeMenu[i],&lpImeMenuW[1],sizeof(IMEMENUITEMINFOA));
3003 lpImeMenu[i].hbmpItem = lpImeMenuW[i].hbmpItem;
3004 WideCharToMultiByte(CP_ACP, 0, lpImeMenuW[i].szString,
3005 -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE,
3006 NULL, NULL);
3009 HeapFree(GetProcessHeap(),0,lpImeMenuW);
3010 return rc;
3013 else
3014 return 0;
3017 /***********************************************************************
3018 * ImmGetImeMenuItemsW (IMM32.@)
3020 DWORD WINAPI ImmGetImeMenuItemsW( HIMC hIMC, DWORD dwFlags, DWORD dwType,
3021 LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu,
3022 DWORD dwSize)
3024 InputContextData *data = get_imc_data(hIMC);
3025 TRACE("(%p, %li, %li, %p, %p, %li):\n", hIMC, dwFlags, dwType,
3026 lpImeParentMenu, lpImeMenu, dwSize);
3028 if (!data)
3030 SetLastError(ERROR_INVALID_HANDLE);
3031 return 0;
3034 if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
3036 if (is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
3037 return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
3038 lpImeParentMenu, lpImeMenu, dwSize);
3039 else
3041 IMEMENUITEMINFOA lpImeParentMenuA;
3042 IMEMENUITEMINFOA *lpImeMenuA, *parent = NULL;
3043 DWORD rc;
3045 if (lpImeParentMenu)
3046 parent = &lpImeParentMenuA;
3047 if (lpImeMenu)
3049 int count = dwSize / sizeof(LPIMEMENUITEMINFOW);
3050 dwSize = count * sizeof(IMEMENUITEMINFOA);
3051 lpImeMenuA = HeapAlloc(GetProcessHeap(), 0, dwSize);
3053 else
3054 lpImeMenuA = NULL;
3056 rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
3057 (IMEMENUITEMINFOW*)parent,
3058 (IMEMENUITEMINFOW*)lpImeMenuA, dwSize);
3060 if (lpImeParentMenu)
3062 memcpy(lpImeParentMenu,&lpImeParentMenuA,sizeof(IMEMENUITEMINFOA));
3063 lpImeParentMenu->hbmpItem = lpImeParentMenuA.hbmpItem;
3064 MultiByteToWideChar(CP_ACP, 0, lpImeParentMenuA.szString,
3065 -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE);
3067 if (lpImeMenu && rc)
3069 unsigned int i;
3070 for (i = 0; i < rc; i++)
3072 memcpy(&lpImeMenu[i],&lpImeMenuA[1],sizeof(IMEMENUITEMINFOA));
3073 lpImeMenu[i].hbmpItem = lpImeMenuA[i].hbmpItem;
3074 MultiByteToWideChar(CP_ACP, 0, lpImeMenuA[i].szString,
3075 -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE);
3078 HeapFree(GetProcessHeap(),0,lpImeMenuA);
3079 return rc;
3082 else
3083 return 0;
3086 /***********************************************************************
3087 * ImmLockIMC(IMM32.@)
3089 LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC)
3091 InputContextData *data = get_imc_data(hIMC);
3093 if (!data)
3094 return NULL;
3095 data->dwLock++;
3096 return &data->IMC;
3099 /***********************************************************************
3100 * ImmUnlockIMC(IMM32.@)
3102 BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
3104 InputContextData *data = get_imc_data(hIMC);
3106 if (!data)
3107 return FALSE;
3108 if (data->dwLock)
3109 data->dwLock--;
3110 return TRUE;
3113 /***********************************************************************
3114 * ImmGetIMCLockCount(IMM32.@)
3116 DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC)
3118 InputContextData *data = get_imc_data(hIMC);
3119 if (!data)
3120 return 0;
3121 return data->dwLock;
3124 /***********************************************************************
3125 * ImmCreateIMCC(IMM32.@)
3127 HIMCC WINAPI ImmCreateIMCC(DWORD size)
3129 return GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE, size);
3132 /***********************************************************************
3133 * ImmDestroyIMCC(IMM32.@)
3135 HIMCC WINAPI ImmDestroyIMCC(HIMCC block)
3137 return GlobalFree(block);
3140 /***********************************************************************
3141 * ImmLockIMCC(IMM32.@)
3143 LPVOID WINAPI ImmLockIMCC(HIMCC imcc)
3145 return GlobalLock(imcc);
3148 /***********************************************************************
3149 * ImmUnlockIMCC(IMM32.@)
3151 BOOL WINAPI ImmUnlockIMCC(HIMCC imcc)
3153 return GlobalUnlock(imcc);
3156 /***********************************************************************
3157 * ImmGetIMCCLockCount(IMM32.@)
3159 DWORD WINAPI ImmGetIMCCLockCount(HIMCC imcc)
3161 return GlobalFlags(imcc) & GMEM_LOCKCOUNT;
3164 /***********************************************************************
3165 * ImmReSizeIMCC(IMM32.@)
3167 HIMCC WINAPI ImmReSizeIMCC(HIMCC imcc, DWORD size)
3169 return GlobalReAlloc(imcc, size, GMEM_ZEROINIT | GMEM_MOVEABLE);
3172 /***********************************************************************
3173 * ImmGetIMCCSize(IMM32.@)
3175 DWORD WINAPI ImmGetIMCCSize(HIMCC imcc)
3177 return GlobalSize(imcc);
3180 /***********************************************************************
3181 * ImmGenerateMessage(IMM32.@)
3183 BOOL WINAPI ImmGenerateMessage(HIMC hIMC)
3185 InputContextData *data = get_imc_data(hIMC);
3187 if (!data)
3189 SetLastError(ERROR_INVALID_HANDLE);
3190 return FALSE;
3193 TRACE("%li messages queued\n",data->IMC.dwNumMsgBuf);
3194 if (data->IMC.dwNumMsgBuf > 0)
3196 LPTRANSMSG lpTransMsg;
3197 HIMCC hMsgBuf;
3198 DWORD i, dwNumMsgBuf;
3200 /* We are going to detach our hMsgBuff so that if processing messages
3201 generates new messages they go into a new buffer */
3202 hMsgBuf = data->IMC.hMsgBuf;
3203 dwNumMsgBuf = data->IMC.dwNumMsgBuf;
3205 data->IMC.hMsgBuf = ImmCreateIMCC(0);
3206 data->IMC.dwNumMsgBuf = 0;
3208 lpTransMsg = ImmLockIMCC(hMsgBuf);
3209 for (i = 0; i < dwNumMsgBuf; i++)
3210 ImmInternalSendIMEMessage(data, lpTransMsg[i].message, lpTransMsg[i].wParam, lpTransMsg[i].lParam);
3212 ImmUnlockIMCC(hMsgBuf);
3213 ImmDestroyIMCC(hMsgBuf);
3216 return TRUE;
3219 /***********************************************************************
3220 * ImmTranslateMessage(IMM32.@)
3221 * ( Undocumented, call internally and from user32.dll )
3223 BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyData)
3225 InputContextData *data;
3226 HIMC imc = ImmGetContext(hwnd);
3227 BYTE state[256];
3228 UINT scancode;
3229 LPVOID list = 0;
3230 UINT msg_count;
3231 UINT uVirtKey;
3232 static const DWORD list_count = 10;
3234 TRACE("%p %x %x %x\n",hwnd, msg, (UINT)wParam, (UINT)lKeyData);
3236 if (imc)
3237 data = imc;
3238 else
3239 return FALSE;
3241 if (!data->immKbd->hIME || !data->immKbd->pImeToAsciiEx || data->lastVK == VK_PROCESSKEY)
3242 return FALSE;
3244 GetKeyboardState(state);
3245 scancode = lKeyData >> 0x10 & 0xff;
3247 list = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, list_count * sizeof(TRANSMSG) + sizeof(DWORD));
3248 ((DWORD*)list)[0] = list_count;
3250 if (data->immKbd->imeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST)
3252 WCHAR chr;
3254 if (!is_himc_ime_unicode(data))
3255 ToAscii(data->lastVK, scancode, state, &chr, 0);
3256 else
3257 ToUnicodeEx(data->lastVK, scancode, state, &chr, 1, 0, GetKeyboardLayout(0));
3258 uVirtKey = MAKELONG(data->lastVK,chr);
3260 else
3261 uVirtKey = data->lastVK;
3263 msg_count = data->immKbd->pImeToAsciiEx(uVirtKey, scancode, state, list, 0, imc);
3264 TRACE("%i messages generated\n",msg_count);
3265 if (msg_count && msg_count <= list_count)
3267 UINT i;
3268 LPTRANSMSG msgs = (LPTRANSMSG)((LPBYTE)list + sizeof(DWORD));
3270 for (i = 0; i < msg_count; i++)
3271 ImmInternalPostIMEMessage(data, msgs[i].message, msgs[i].wParam, msgs[i].lParam);
3273 else if (msg_count > list_count)
3274 ImmGenerateMessage(imc);
3276 HeapFree(GetProcessHeap(),0,list);
3278 data->lastVK = VK_PROCESSKEY;
3280 return (msg_count > 0);
3283 /***********************************************************************
3284 * ImmProcessKey(IMM32.@)
3285 * ( Undocumented, called from user32.dll )
3287 BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD unknown)
3289 InputContextData *data;
3290 HIMC imc = ImmGetContext(hwnd);
3291 BYTE state[256];
3293 TRACE("%p %p %x %x %lx\n",hwnd, hKL, vKey, (UINT)lKeyData, unknown);
3295 if (imc)
3296 data = imc;
3297 else
3298 return FALSE;
3300 /* Make sure we are inputting to the correct keyboard */
3301 if (data->immKbd->hkl != hKL)
3303 ImmHkl *new_hkl = IMM_GetImmHkl(hKL);
3304 if (new_hkl)
3306 data->immKbd->pImeSelect(imc, FALSE);
3307 data->immKbd->uSelected--;
3308 data->immKbd = new_hkl;
3309 data->immKbd->pImeSelect(imc, TRUE);
3310 data->immKbd->uSelected++;
3312 else
3313 return FALSE;
3316 if (!data->immKbd->hIME || !data->immKbd->pImeProcessKey)
3317 return FALSE;
3319 GetKeyboardState(state);
3320 if (data->immKbd->pImeProcessKey(imc, vKey, lKeyData, state))
3322 data->lastVK = vKey;
3323 return TRUE;
3326 data->lastVK = VK_PROCESSKEY;
3327 return FALSE;
3330 /***********************************************************************
3331 * ImmDisableTextFrameService(IMM32.@)
3333 BOOL WINAPI ImmDisableTextFrameService(DWORD idThread)
3335 FIXME("Stub\n");
3336 return FALSE;
3339 /***********************************************************************
3340 * ImmEnumInputContext(IMM32.@)
3343 BOOL WINAPI ImmEnumInputContext(DWORD idThread, IMCENUMPROC lpfn, LPARAM lParam)
3345 FIXME("Stub\n");
3346 return FALSE;
3349 /***********************************************************************
3350 * ImmGetHotKey(IMM32.@)
3353 BOOL WINAPI ImmGetHotKey(DWORD hotkey, UINT *modifiers, UINT *key, HKL hkl)
3355 FIXME("%lx, %p, %p, %p: stub\n", hotkey, modifiers, key, hkl);
3356 return FALSE;
3359 /***********************************************************************
3360 * ImmDisableLegacyIME(IMM32.@)
3362 BOOL WINAPI ImmDisableLegacyIME(void)
3364 FIXME("stub\n");
3365 return TRUE;