win32u: Use platform-independent layout for ntuser_thread_info.
[wine.git] / dlls / imm32 / imm.c
blob780d544c0e9bf2276fbc2c8940fb78fb8b7bab8e
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 "ntuser.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 /* MSIME messages */
47 static UINT WM_MSIME_SERVICE;
48 static UINT WM_MSIME_RECONVERTOPTIONS;
49 static UINT WM_MSIME_MOUSE;
50 static UINT WM_MSIME_RECONVERTREQUEST;
51 static UINT WM_MSIME_RECONVERT;
52 static UINT WM_MSIME_QUERYPOSITION;
53 static UINT WM_MSIME_DOCUMENTFEED;
55 typedef struct _tagImmHkl{
56 struct list entry;
57 HKL hkl;
58 HMODULE hIME;
59 IMEINFO imeInfo;
60 WCHAR imeClassName[17]; /* 16 character max */
61 ULONG uSelected;
62 HWND UIWnd;
64 /* Function Pointers */
65 BOOL (WINAPI *pImeInquire)(IMEINFO *, WCHAR *, const WCHAR *);
66 BOOL (WINAPI *pImeConfigure)(HKL, HWND, DWORD, void *);
67 BOOL (WINAPI *pImeDestroy)(UINT);
68 LRESULT (WINAPI *pImeEscape)(HIMC, UINT, void *);
69 BOOL (WINAPI *pImeSelect)(HIMC, BOOL);
70 BOOL (WINAPI *pImeSetActiveContext)(HIMC, BOOL);
71 UINT (WINAPI *pImeToAsciiEx)(UINT, UINT, const BYTE *, DWORD *, UINT, HIMC);
72 BOOL (WINAPI *pNotifyIME)(HIMC, DWORD, DWORD, DWORD);
73 BOOL (WINAPI *pImeRegisterWord)(const WCHAR *, DWORD, const WCHAR *);
74 BOOL (WINAPI *pImeUnregisterWord)(const WCHAR *, DWORD, const WCHAR *);
75 UINT (WINAPI *pImeEnumRegisterWord)(REGISTERWORDENUMPROCW, const WCHAR *, DWORD, const WCHAR *, void *);
76 BOOL (WINAPI *pImeSetCompositionString)(HIMC, DWORD, const void *, DWORD, const void *, DWORD);
77 DWORD (WINAPI *pImeConversionList)(HIMC, const WCHAR *, CANDIDATELIST *, DWORD, UINT);
78 BOOL (WINAPI *pImeProcessKey)(HIMC, UINT, LPARAM, const BYTE *);
79 UINT (WINAPI *pImeGetRegisterWordStyle)(UINT, STYLEBUFW *);
80 DWORD (WINAPI *pImeGetImeMenuItems)(HIMC, DWORD, DWORD, IMEMENUITEMINFOW *, IMEMENUITEMINFOW *, DWORD);
81 } ImmHkl;
83 typedef struct tagInputContextData
85 HIMC handle;
86 DWORD dwLock;
87 INPUTCONTEXT IMC;
88 DWORD threadID;
90 ImmHkl *immKbd;
91 UINT lastVK;
92 BOOL threadDefault;
93 } InputContextData;
95 #define WINE_IMC_VALID_MAGIC 0x56434D49
97 typedef struct _tagTRANSMSG {
98 UINT message;
99 WPARAM wParam;
100 LPARAM lParam;
101 } TRANSMSG, *LPTRANSMSG;
103 struct coinit_spy
105 IInitializeSpy IInitializeSpy_iface;
106 LONG ref;
107 ULARGE_INTEGER cookie;
108 enum
110 IMM_APT_INIT = 0x1,
111 IMM_APT_CREATED = 0x2,
112 IMM_APT_CAN_FREE = 0x4,
113 IMM_APT_BROKEN = 0x8
114 } apt_flags;
117 static struct list ImmHklList = LIST_INIT(ImmHklList);
119 static const WCHAR szImeRegFmt[] = L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08lx";
121 static inline BOOL is_himc_ime_unicode(const InputContextData *data)
123 return !!(data->immKbd->imeInfo.fdwProperty & IME_PROP_UNICODE);
126 static inline BOOL is_kbd_ime_unicode(const ImmHkl *hkl)
128 return !!(hkl->imeInfo.fdwProperty & IME_PROP_UNICODE);
131 static BOOL IMM_DestroyContext(HIMC hIMC);
132 static InputContextData* get_imc_data(HIMC hIMC);
134 static inline WCHAR *strdupAtoW( const char *str )
136 WCHAR *ret = NULL;
137 if (str)
139 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
140 if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
141 MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
143 return ret;
146 static inline CHAR *strdupWtoA( const WCHAR *str )
148 CHAR *ret = NULL;
149 if (str)
151 DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
152 if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
153 WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
155 return ret;
158 static DWORD convert_candidatelist_WtoA(
159 LPCANDIDATELIST lpSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen)
161 DWORD ret, i, len;
163 ret = FIELD_OFFSET( CANDIDATELIST, dwOffset[lpSrc->dwCount] );
164 if ( lpDst && dwBufLen > 0 )
166 *lpDst = *lpSrc;
167 lpDst->dwOffset[0] = ret;
170 for ( i = 0; i < lpSrc->dwCount; i++)
172 LPBYTE src = (LPBYTE)lpSrc + lpSrc->dwOffset[i];
174 if ( lpDst && dwBufLen > 0 )
176 LPBYTE dest = (LPBYTE)lpDst + lpDst->dwOffset[i];
178 len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1,
179 (LPSTR)dest, dwBufLen, NULL, NULL);
181 if ( i + 1 < lpSrc->dwCount )
182 lpDst->dwOffset[i+1] = lpDst->dwOffset[i] + len * sizeof(char);
183 dwBufLen -= len * sizeof(char);
185 else
186 len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1, NULL, 0, NULL, NULL);
188 ret += len * sizeof(char);
191 if ( lpDst )
192 lpDst->dwSize = ret;
194 return ret;
197 static DWORD convert_candidatelist_AtoW(
198 LPCANDIDATELIST lpSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen)
200 DWORD ret, i, len;
202 ret = FIELD_OFFSET( CANDIDATELIST, dwOffset[lpSrc->dwCount] );
203 if ( lpDst && dwBufLen > 0 )
205 *lpDst = *lpSrc;
206 lpDst->dwOffset[0] = ret;
209 for ( i = 0; i < lpSrc->dwCount; i++)
211 LPBYTE src = (LPBYTE)lpSrc + lpSrc->dwOffset[i];
213 if ( lpDst && dwBufLen > 0 )
215 LPBYTE dest = (LPBYTE)lpDst + lpDst->dwOffset[i];
217 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1,
218 (LPWSTR)dest, dwBufLen);
220 if ( i + 1 < lpSrc->dwCount )
221 lpDst->dwOffset[i+1] = lpDst->dwOffset[i] + len * sizeof(WCHAR);
222 dwBufLen -= len * sizeof(WCHAR);
224 else
225 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1, NULL, 0);
227 ret += len * sizeof(WCHAR);
230 if ( lpDst )
231 lpDst->dwSize = ret;
233 return ret;
236 static struct coinit_spy *get_thread_coinit_spy(void)
238 return (struct coinit_spy *)(UINT_PTR)NtUserGetThreadInfo()->client_imm;
241 static void imm_couninit_thread(BOOL cleanup)
243 struct coinit_spy *spy;
245 TRACE("implicit COM deinitialization\n");
247 if (!(spy = get_thread_coinit_spy()) || (spy->apt_flags & IMM_APT_BROKEN))
248 return;
250 if (cleanup && spy->cookie.QuadPart)
252 CoRevokeInitializeSpy(spy->cookie);
253 spy->cookie.QuadPart = 0;
256 if (!(spy->apt_flags & IMM_APT_INIT))
257 return;
258 spy->apt_flags &= ~IMM_APT_INIT;
260 if (spy->apt_flags & IMM_APT_CREATED)
262 spy->apt_flags &= ~IMM_APT_CREATED;
263 if (spy->apt_flags & IMM_APT_CAN_FREE)
264 CoUninitialize();
266 if (cleanup)
267 spy->apt_flags = 0;
270 static inline struct coinit_spy *impl_from_IInitializeSpy(IInitializeSpy *iface)
272 return CONTAINING_RECORD(iface, struct coinit_spy, IInitializeSpy_iface);
275 static HRESULT WINAPI InitializeSpy_QueryInterface(IInitializeSpy *iface, REFIID riid, void **obj)
277 if (IsEqualIID(&IID_IInitializeSpy, riid) ||
278 IsEqualIID(&IID_IUnknown, riid))
280 *obj = iface;
281 IInitializeSpy_AddRef(iface);
282 return S_OK;
285 *obj = NULL;
286 return E_NOINTERFACE;
289 static ULONG WINAPI InitializeSpy_AddRef(IInitializeSpy *iface)
291 struct coinit_spy *spy = impl_from_IInitializeSpy(iface);
292 return InterlockedIncrement(&spy->ref);
295 static ULONG WINAPI InitializeSpy_Release(IInitializeSpy *iface)
297 struct coinit_spy *spy = impl_from_IInitializeSpy(iface);
298 LONG ref = InterlockedDecrement(&spy->ref);
299 if (!ref)
301 HeapFree(GetProcessHeap(), 0, spy);
302 NtUserGetThreadInfo()->client_imm = 0;
304 return ref;
307 static HRESULT WINAPI InitializeSpy_PreInitialize(IInitializeSpy *iface,
308 DWORD coinit, DWORD refs)
310 struct coinit_spy *spy = impl_from_IInitializeSpy(iface);
312 if ((spy->apt_flags & IMM_APT_CREATED) &&
313 !(coinit & COINIT_APARTMENTTHREADED) && refs == 1)
315 imm_couninit_thread(TRUE);
316 spy->apt_flags |= IMM_APT_BROKEN;
318 return S_OK;
321 static HRESULT WINAPI InitializeSpy_PostInitialize(IInitializeSpy *iface,
322 HRESULT hr, DWORD coinit, DWORD refs)
324 struct coinit_spy *spy = impl_from_IInitializeSpy(iface);
326 if ((spy->apt_flags & IMM_APT_CREATED) && hr == S_FALSE && refs == 2)
327 hr = S_OK;
328 if (SUCCEEDED(hr))
329 spy->apt_flags |= IMM_APT_CAN_FREE;
330 return hr;
333 static HRESULT WINAPI InitializeSpy_PreUninitialize(IInitializeSpy *iface, DWORD refs)
335 return S_OK;
338 static HRESULT WINAPI InitializeSpy_PostUninitialize(IInitializeSpy *iface, DWORD refs)
340 struct coinit_spy *spy = impl_from_IInitializeSpy(iface);
342 TRACE("%lu %p\n", refs, ImmGetDefaultIMEWnd(0));
344 if (refs == 1 && !ImmGetDefaultIMEWnd(0))
345 imm_couninit_thread(FALSE);
346 else if (!refs)
347 spy->apt_flags &= ~IMM_APT_CAN_FREE;
348 return S_OK;
351 static const IInitializeSpyVtbl InitializeSpyVtbl =
353 InitializeSpy_QueryInterface,
354 InitializeSpy_AddRef,
355 InitializeSpy_Release,
356 InitializeSpy_PreInitialize,
357 InitializeSpy_PostInitialize,
358 InitializeSpy_PreUninitialize,
359 InitializeSpy_PostUninitialize,
362 static void imm_coinit_thread(void)
364 struct coinit_spy *spy;
365 HRESULT hr;
367 TRACE("implicit COM initialization\n");
369 if (!(spy = get_thread_coinit_spy()))
371 if (!(spy = HeapAlloc(GetProcessHeap(), 0, sizeof(*spy)))) return;
372 spy->IInitializeSpy_iface.lpVtbl = &InitializeSpyVtbl;
373 spy->ref = 1;
374 spy->cookie.QuadPart = 0;
375 spy->apt_flags = 0;
376 NtUserGetThreadInfo()->client_imm = (UINT_PTR)spy;
380 if (spy->apt_flags & (IMM_APT_INIT | IMM_APT_BROKEN))
381 return;
382 spy->apt_flags |= IMM_APT_INIT;
384 if(!spy->cookie.QuadPart)
386 hr = CoRegisterInitializeSpy(&spy->IInitializeSpy_iface, &spy->cookie);
387 if (FAILED(hr))
388 return;
391 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
392 if (SUCCEEDED(hr))
393 spy->apt_flags |= IMM_APT_CREATED;
396 static BOOL IMM_IsDefaultContext(HIMC imc)
398 InputContextData *data = get_imc_data(imc);
400 if (!data)
401 return FALSE;
403 return data->threadDefault;
406 static InputContextData *query_imc_data(HIMC handle)
408 InputContextData *ret;
410 if (!handle) return NULL;
411 ret = (void *)NtUserQueryInputContext(handle, NtUserInputContextClientPtr);
412 return ret && ret->handle == handle ? ret : NULL;
415 static BOOL free_input_context_data(HIMC hIMC)
417 InputContextData *data = query_imc_data(hIMC);
419 if (!data)
420 return FALSE;
422 TRACE("Destroying %p\n", hIMC);
424 data->immKbd->uSelected--;
425 data->immKbd->pImeSelect(hIMC, FALSE);
426 SendMessageW(data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)data->immKbd);
428 ImmDestroyIMCC(data->IMC.hCompStr);
429 ImmDestroyIMCC(data->IMC.hCandInfo);
430 ImmDestroyIMCC(data->IMC.hGuideLine);
431 ImmDestroyIMCC(data->IMC.hPrivate);
432 ImmDestroyIMCC(data->IMC.hMsgBuf);
434 HeapFree(GetProcessHeap(), 0, data);
436 return TRUE;
439 static void IMM_FreeThreadData(void)
441 struct coinit_spy *spy;
443 free_input_context_data(UlongToHandle(NtUserGetThreadInfo()->default_imc));
444 if ((spy = get_thread_coinit_spy()))
445 IInitializeSpy_Release(&spy->IInitializeSpy_iface);
448 static HMODULE load_graphics_driver(void)
450 static const WCHAR key_pathW[] = L"System\\CurrentControlSet\\Control\\Video\\{";
451 static const WCHAR displayW[] = L"}\\0000";
453 HMODULE ret = 0;
454 HKEY hkey;
455 DWORD size;
456 WCHAR path[MAX_PATH];
457 WCHAR key[ARRAY_SIZE( key_pathW ) + ARRAY_SIZE( displayW ) + 40];
458 UINT guid_atom = HandleToULong( GetPropW( GetDesktopWindow(), L"__wine_display_device_guid" ));
460 if (!guid_atom) return 0;
461 memcpy( key, key_pathW, sizeof(key_pathW) );
462 if (!GlobalGetAtomNameW( guid_atom, key + lstrlenW(key), 40 )) return 0;
463 lstrcatW( key, displayW );
464 if (RegOpenKeyW( HKEY_LOCAL_MACHINE, key, &hkey )) return 0;
465 size = sizeof(path);
466 if (!RegQueryValueExW( hkey, L"GraphicsDriver", NULL, NULL, (BYTE *)path, &size ))
467 ret = LoadLibraryW( path );
468 RegCloseKey( hkey );
469 TRACE( "%s %p\n", debugstr_w(path), ret );
470 return ret;
473 /* ImmHkl loading and freeing */
474 #define LOAD_FUNCPTR(f) if((ptr->p##f = (LPVOID)GetProcAddress(ptr->hIME, #f)) == NULL){WARN("Can't find function %s in ime\n", #f);}
475 static ImmHkl *IMM_GetImmHkl(HKL hkl)
477 ImmHkl *ptr;
478 WCHAR filename[MAX_PATH];
480 TRACE("Seeking ime for keyboard %p\n",hkl);
482 LIST_FOR_EACH_ENTRY(ptr, &ImmHklList, ImmHkl, entry)
484 if (ptr->hkl == hkl)
485 return ptr;
487 /* not found... create it */
489 ptr = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ImmHkl));
491 ptr->hkl = hkl;
492 if (ImmGetIMEFileNameW(hkl, filename, MAX_PATH)) ptr->hIME = LoadLibraryW(filename);
493 if (!ptr->hIME) ptr->hIME = load_graphics_driver();
494 if (ptr->hIME)
496 LOAD_FUNCPTR(ImeInquire);
497 if (!ptr->pImeInquire || !ptr->pImeInquire(&ptr->imeInfo, ptr->imeClassName, NULL))
499 FreeLibrary(ptr->hIME);
500 ptr->hIME = NULL;
502 else
504 LOAD_FUNCPTR(ImeDestroy);
505 LOAD_FUNCPTR(ImeSelect);
506 if (!ptr->pImeSelect || !ptr->pImeDestroy)
508 FreeLibrary(ptr->hIME);
509 ptr->hIME = NULL;
511 else
513 LOAD_FUNCPTR(ImeConfigure);
514 LOAD_FUNCPTR(ImeEscape);
515 LOAD_FUNCPTR(ImeSetActiveContext);
516 LOAD_FUNCPTR(ImeToAsciiEx);
517 LOAD_FUNCPTR(NotifyIME);
518 LOAD_FUNCPTR(ImeRegisterWord);
519 LOAD_FUNCPTR(ImeUnregisterWord);
520 LOAD_FUNCPTR(ImeEnumRegisterWord);
521 LOAD_FUNCPTR(ImeSetCompositionString);
522 LOAD_FUNCPTR(ImeConversionList);
523 LOAD_FUNCPTR(ImeProcessKey);
524 LOAD_FUNCPTR(ImeGetRegisterWordStyle);
525 LOAD_FUNCPTR(ImeGetImeMenuItems);
526 /* make sure our classname is WCHAR */
527 if (!is_kbd_ime_unicode(ptr))
529 WCHAR bufW[17];
530 MultiByteToWideChar(CP_ACP, 0, (LPSTR)ptr->imeClassName,
531 -1, bufW, 17);
532 lstrcpyW(ptr->imeClassName, bufW);
537 list_add_head(&ImmHklList,&ptr->entry);
539 return ptr;
541 #undef LOAD_FUNCPTR
544 static void IMM_FreeAllImmHkl(void)
546 ImmHkl *ptr,*cursor2;
548 LIST_FOR_EACH_ENTRY_SAFE(ptr, cursor2, &ImmHklList, ImmHkl, entry)
550 list_remove(&ptr->entry);
551 if (ptr->hIME)
553 ptr->pImeDestroy(1);
554 FreeLibrary(ptr->hIME);
556 if (ptr->UIWnd)
557 DestroyWindow(ptr->UIWnd);
558 HeapFree(GetProcessHeap(),0,ptr);
562 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved)
564 TRACE("%p, %lx, %p\n",hInstDLL,fdwReason,lpReserved);
565 switch (fdwReason)
567 case DLL_PROCESS_ATTACH:
568 if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC))
570 return FALSE;
572 break;
573 case DLL_THREAD_ATTACH:
574 break;
575 case DLL_THREAD_DETACH:
576 IMM_FreeThreadData();
577 break;
578 case DLL_PROCESS_DETACH:
579 if (lpReserved) break;
580 IMM_FreeThreadData();
581 IMM_FreeAllImmHkl();
582 break;
584 return TRUE;
587 /* for posting messages as the IME */
588 static void ImmInternalPostIMEMessage(InputContextData *data, UINT msg, WPARAM wParam, LPARAM lParam)
590 HWND target = GetFocus();
591 if (!target)
592 PostMessageW(data->IMC.hWnd,msg,wParam,lParam);
593 else
594 PostMessageW(target, msg, wParam, lParam);
597 /* for sending messages as the IME */
598 static void ImmInternalSendIMEMessage(InputContextData *data, UINT msg, WPARAM wParam, LPARAM lParam)
600 HWND target = GetFocus();
601 if (!target)
602 SendMessageW(data->IMC.hWnd,msg,wParam,lParam);
603 else
604 SendMessageW(target, msg, wParam, lParam);
607 static LRESULT ImmInternalSendIMENotify(InputContextData *data, WPARAM notify, LPARAM lParam)
609 HWND target;
611 target = data->IMC.hWnd;
612 if (!target) target = GetFocus();
614 if (target)
615 return SendMessageW(target, WM_IME_NOTIFY, notify, lParam);
617 return 0;
620 static HIMCC ImmCreateBlankCompStr(void)
622 HIMCC rc;
623 LPCOMPOSITIONSTRING ptr;
624 rc = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
625 ptr = ImmLockIMCC(rc);
626 memset(ptr,0,sizeof(COMPOSITIONSTRING));
627 ptr->dwSize = sizeof(COMPOSITIONSTRING);
628 ImmUnlockIMCC(rc);
629 return rc;
632 static BOOL IMM_IsCrossThreadAccess(HWND hWnd, HIMC hIMC)
634 InputContextData *data;
636 if (hWnd)
638 DWORD thread = GetWindowThreadProcessId(hWnd, NULL);
639 if (thread != GetCurrentThreadId()) return TRUE;
641 data = get_imc_data(hIMC);
642 if (data && data->threadID != GetCurrentThreadId())
643 return TRUE;
645 return FALSE;
648 /***********************************************************************
649 * ImmSetActiveContext (IMM32.@)
651 BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC himc, BOOL activate)
653 InputContextData *data = get_imc_data(himc);
655 TRACE("(%p, %p, %x)\n", hwnd, himc, activate);
657 if (himc && !data && activate)
658 return FALSE;
660 imm_coinit_thread();
662 if (data)
664 data->IMC.hWnd = activate ? hwnd : NULL;
666 if (data->immKbd->hIME && data->immKbd->pImeSetActiveContext)
667 data->immKbd->pImeSetActiveContext(himc, activate);
670 if (IsWindow(hwnd))
672 SendMessageW(hwnd, WM_IME_SETCONTEXT, activate, ISC_SHOWUIALL);
673 /* TODO: send WM_IME_NOTIFY */
675 SetLastError(0);
676 return TRUE;
679 /***********************************************************************
680 * ImmAssociateContext (IMM32.@)
682 HIMC WINAPI ImmAssociateContext(HWND hwnd, HIMC imc)
684 HIMC old;
685 UINT ret;
687 TRACE("(%p, %p):\n", hwnd, imc);
689 old = NtUserGetWindowInputContext(hwnd);
690 ret = NtUserAssociateInputContext(hwnd, imc, 0);
691 if (ret == AICR_FOCUS_CHANGED)
693 ImmSetActiveContext(hwnd, old, FALSE);
694 ImmSetActiveContext(hwnd, imc, TRUE);
696 return ret == AICR_FAILED ? 0 : old;
701 * Helper function for ImmAssociateContextEx
703 static BOOL CALLBACK _ImmAssociateContextExEnumProc(HWND hwnd, LPARAM lParam)
705 HIMC hImc = (HIMC)lParam;
706 ImmAssociateContext(hwnd,hImc);
707 return TRUE;
710 /***********************************************************************
711 * ImmAssociateContextEx (IMM32.@)
713 BOOL WINAPI ImmAssociateContextEx(HWND hwnd, HIMC imc, DWORD flags)
715 HIMC old;
716 UINT ret;
718 TRACE("(%p, %p, 0x%lx):\n", hwnd, imc, flags);
720 if (!hwnd)
721 return FALSE;
723 if (flags == IACE_CHILDREN)
725 EnumChildWindows(hwnd, _ImmAssociateContextExEnumProc, (LPARAM)imc);
726 return TRUE;
729 old = NtUserGetWindowInputContext(hwnd);
730 ret = NtUserAssociateInputContext(hwnd, imc, flags);
731 if (ret == AICR_FOCUS_CHANGED)
733 ImmSetActiveContext(hwnd, old, FALSE);
734 ImmSetActiveContext(hwnd, imc, TRUE);
736 return ret != AICR_FAILED;
739 /***********************************************************************
740 * ImmConfigureIMEA (IMM32.@)
742 BOOL WINAPI ImmConfigureIMEA(
743 HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
745 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
747 TRACE("(%p, %p, %ld, %p):\n", hKL, hWnd, dwMode, lpData);
749 if (dwMode == IME_CONFIG_REGISTERWORD && !lpData)
750 return FALSE;
752 if (immHkl->hIME && immHkl->pImeConfigure)
754 if (dwMode != IME_CONFIG_REGISTERWORD || !is_kbd_ime_unicode(immHkl))
755 return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData);
756 else
758 REGISTERWORDW rww;
759 REGISTERWORDA *rwa = lpData;
760 BOOL rc;
762 rww.lpReading = strdupAtoW(rwa->lpReading);
763 rww.lpWord = strdupAtoW(rwa->lpWord);
764 rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rww);
765 HeapFree(GetProcessHeap(),0,rww.lpReading);
766 HeapFree(GetProcessHeap(),0,rww.lpWord);
767 return rc;
770 else
771 return FALSE;
774 /***********************************************************************
775 * ImmConfigureIMEW (IMM32.@)
777 BOOL WINAPI ImmConfigureIMEW(
778 HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
780 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
782 TRACE("(%p, %p, %ld, %p):\n", hKL, hWnd, dwMode, lpData);
784 if (dwMode == IME_CONFIG_REGISTERWORD && !lpData)
785 return FALSE;
787 if (immHkl->hIME && immHkl->pImeConfigure)
789 if (dwMode != IME_CONFIG_REGISTERWORD || is_kbd_ime_unicode(immHkl))
790 return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData);
791 else
793 REGISTERWORDW *rww = lpData;
794 REGISTERWORDA rwa;
795 BOOL rc;
797 rwa.lpReading = strdupWtoA(rww->lpReading);
798 rwa.lpWord = strdupWtoA(rww->lpWord);
799 rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rwa);
800 HeapFree(GetProcessHeap(),0,rwa.lpReading);
801 HeapFree(GetProcessHeap(),0,rwa.lpWord);
802 return rc;
805 else
806 return FALSE;
809 static InputContextData *create_input_context(HIMC default_imc)
811 InputContextData *new_context;
812 LPGUIDELINE gl;
813 LPCANDIDATEINFO ci;
814 int i;
816 new_context = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(InputContextData));
818 /* Load the IME */
819 new_context->threadDefault = !!default_imc;
820 new_context->immKbd = IMM_GetImmHkl(GetKeyboardLayout(0));
822 if (!new_context->immKbd->hIME)
824 TRACE("IME dll could not be loaded\n");
825 HeapFree(GetProcessHeap(),0,new_context);
826 return 0;
829 /* the HIMCCs are never NULL */
830 new_context->IMC.hCompStr = ImmCreateBlankCompStr();
831 new_context->IMC.hMsgBuf = ImmCreateIMCC(0);
832 new_context->IMC.hCandInfo = ImmCreateIMCC(sizeof(CANDIDATEINFO));
833 ci = ImmLockIMCC(new_context->IMC.hCandInfo);
834 memset(ci,0,sizeof(CANDIDATEINFO));
835 ci->dwSize = sizeof(CANDIDATEINFO);
836 ImmUnlockIMCC(new_context->IMC.hCandInfo);
837 new_context->IMC.hGuideLine = ImmCreateIMCC(sizeof(GUIDELINE));
838 gl = ImmLockIMCC(new_context->IMC.hGuideLine);
839 memset(gl,0,sizeof(GUIDELINE));
840 gl->dwSize = sizeof(GUIDELINE);
841 ImmUnlockIMCC(new_context->IMC.hGuideLine);
843 for (i = 0; i < ARRAY_SIZE(new_context->IMC.cfCandForm); i++)
844 new_context->IMC.cfCandForm[i].dwIndex = ~0u;
846 /* Initialize the IME Private */
847 new_context->IMC.hPrivate = ImmCreateIMCC(new_context->immKbd->imeInfo.dwPrivateDataSize);
849 new_context->IMC.fdwConversion = new_context->immKbd->imeInfo.fdwConversionCaps;
850 new_context->IMC.fdwSentence = new_context->immKbd->imeInfo.fdwSentenceCaps;
852 if (!default_imc)
853 new_context->handle = NtUserCreateInputContext((UINT_PTR)new_context);
854 else if (NtUserUpdateInputContext(default_imc, NtUserInputContextClientPtr, (UINT_PTR)new_context))
855 new_context->handle = default_imc;
856 if (!new_context->handle)
858 free_input_context_data(new_context);
859 return 0;
862 if (!new_context->immKbd->pImeSelect(new_context->handle, TRUE))
864 TRACE("Selection of IME failed\n");
865 IMM_DestroyContext(new_context);
866 return 0;
868 new_context->threadID = GetCurrentThreadId();
869 SendMessageW(GetFocus(), WM_IME_SELECT, TRUE, (LPARAM)new_context->immKbd);
871 new_context->immKbd->uSelected++;
872 TRACE("Created context %p\n", new_context);
873 return new_context;
876 static InputContextData* get_imc_data(HIMC handle)
878 InputContextData *ret;
880 if ((ret = query_imc_data(handle)) || !handle) return ret;
881 return create_input_context(handle);
884 /***********************************************************************
885 * ImmCreateContext (IMM32.@)
887 HIMC WINAPI ImmCreateContext(void)
889 InputContextData *new_context;
891 if (!(new_context = create_input_context(0))) return 0;
892 return new_context->handle;
895 static BOOL IMM_DestroyContext(HIMC hIMC)
897 if (!free_input_context_data(hIMC)) return FALSE;
898 NtUserDestroyInputContext(hIMC);
899 return TRUE;
902 /***********************************************************************
903 * ImmDestroyContext (IMM32.@)
905 BOOL WINAPI ImmDestroyContext(HIMC hIMC)
907 if (!IMM_IsDefaultContext(hIMC) && !IMM_IsCrossThreadAccess(NULL, hIMC))
908 return IMM_DestroyContext(hIMC);
909 else
910 return FALSE;
913 /***********************************************************************
914 * ImmEnumRegisterWordA (IMM32.@)
916 UINT WINAPI ImmEnumRegisterWordA(
917 HKL hKL, REGISTERWORDENUMPROCA lpfnEnumProc,
918 LPCSTR lpszReading, DWORD dwStyle,
919 LPCSTR lpszRegister, LPVOID lpData)
921 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
922 TRACE("(%p, %p, %s, %ld, %s, %p):\n", hKL, lpfnEnumProc,
923 debugstr_a(lpszReading), dwStyle, debugstr_a(lpszRegister), lpData);
924 if (immHkl->hIME && immHkl->pImeEnumRegisterWord)
926 if (!is_kbd_ime_unicode(immHkl))
927 return immHkl->pImeEnumRegisterWord((REGISTERWORDENUMPROCW)lpfnEnumProc,
928 (LPCWSTR)lpszReading, dwStyle, (LPCWSTR)lpszRegister, lpData);
929 else
931 LPWSTR lpszwReading = strdupAtoW(lpszReading);
932 LPWSTR lpszwRegister = strdupAtoW(lpszRegister);
933 BOOL rc;
935 rc = immHkl->pImeEnumRegisterWord((REGISTERWORDENUMPROCW)lpfnEnumProc,
936 lpszwReading, dwStyle, lpszwRegister,
937 lpData);
939 HeapFree(GetProcessHeap(),0,lpszwReading);
940 HeapFree(GetProcessHeap(),0,lpszwRegister);
941 return rc;
944 else
945 return 0;
948 /***********************************************************************
949 * ImmEnumRegisterWordW (IMM32.@)
951 UINT WINAPI ImmEnumRegisterWordW(
952 HKL hKL, REGISTERWORDENUMPROCW lpfnEnumProc,
953 LPCWSTR lpszReading, DWORD dwStyle,
954 LPCWSTR lpszRegister, LPVOID lpData)
956 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
957 TRACE("(%p, %p, %s, %ld, %s, %p):\n", hKL, lpfnEnumProc,
958 debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister), lpData);
959 if (immHkl->hIME && immHkl->pImeEnumRegisterWord)
961 if (is_kbd_ime_unicode(immHkl))
962 return immHkl->pImeEnumRegisterWord(lpfnEnumProc, lpszReading, dwStyle,
963 lpszRegister, lpData);
964 else
966 LPSTR lpszaReading = strdupWtoA(lpszReading);
967 LPSTR lpszaRegister = strdupWtoA(lpszRegister);
968 BOOL rc;
970 rc = immHkl->pImeEnumRegisterWord(lpfnEnumProc, (LPCWSTR)lpszaReading,
971 dwStyle, (LPCWSTR)lpszaRegister, lpData);
973 HeapFree(GetProcessHeap(),0,lpszaReading);
974 HeapFree(GetProcessHeap(),0,lpszaRegister);
975 return rc;
978 else
979 return 0;
982 static inline BOOL EscapeRequiresWA(UINT uEscape)
984 if (uEscape == IME_ESC_GET_EUDC_DICTIONARY ||
985 uEscape == IME_ESC_SET_EUDC_DICTIONARY ||
986 uEscape == IME_ESC_IME_NAME ||
987 uEscape == IME_ESC_GETHELPFILENAME)
988 return TRUE;
989 return FALSE;
992 /***********************************************************************
993 * ImmEscapeA (IMM32.@)
995 LRESULT WINAPI ImmEscapeA(
996 HKL hKL, HIMC hIMC,
997 UINT uEscape, LPVOID lpData)
999 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1000 TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData);
1002 if (immHkl->hIME && immHkl->pImeEscape)
1004 if (!EscapeRequiresWA(uEscape) || !is_kbd_ime_unicode(immHkl))
1005 return immHkl->pImeEscape(hIMC,uEscape,lpData);
1006 else
1008 WCHAR buffer[81]; /* largest required buffer should be 80 */
1009 LRESULT rc;
1010 if (uEscape == IME_ESC_SET_EUDC_DICTIONARY)
1012 MultiByteToWideChar(CP_ACP,0,lpData,-1,buffer,81);
1013 rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
1015 else
1017 rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
1018 WideCharToMultiByte(CP_ACP,0,buffer,-1,lpData,80, NULL, NULL);
1020 return rc;
1023 else
1024 return 0;
1027 /***********************************************************************
1028 * ImmEscapeW (IMM32.@)
1030 LRESULT WINAPI ImmEscapeW(
1031 HKL hKL, HIMC hIMC,
1032 UINT uEscape, LPVOID lpData)
1034 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1035 TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData);
1037 if (immHkl->hIME && immHkl->pImeEscape)
1039 if (!EscapeRequiresWA(uEscape) || is_kbd_ime_unicode(immHkl))
1040 return immHkl->pImeEscape(hIMC,uEscape,lpData);
1041 else
1043 CHAR buffer[81]; /* largest required buffer should be 80 */
1044 LRESULT rc;
1045 if (uEscape == IME_ESC_SET_EUDC_DICTIONARY)
1047 WideCharToMultiByte(CP_ACP,0,lpData,-1,buffer,81, NULL, NULL);
1048 rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
1050 else
1052 rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
1053 MultiByteToWideChar(CP_ACP,0,buffer,-1,lpData,80);
1055 return rc;
1058 else
1059 return 0;
1062 /***********************************************************************
1063 * ImmGetCandidateListA (IMM32.@)
1065 DWORD WINAPI ImmGetCandidateListA(
1066 HIMC hIMC, DWORD dwIndex,
1067 LPCANDIDATELIST lpCandList, DWORD dwBufLen)
1069 InputContextData *data = get_imc_data(hIMC);
1070 LPCANDIDATEINFO candinfo;
1071 LPCANDIDATELIST candlist;
1072 DWORD ret = 0;
1074 TRACE("%p, %ld, %p, %ld\n", hIMC, dwIndex, lpCandList, dwBufLen);
1076 if (!data || !data->IMC.hCandInfo)
1077 return 0;
1079 candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1080 if (dwIndex >= candinfo->dwCount || dwIndex >= ARRAY_SIZE(candinfo->dwOffset))
1081 goto done;
1083 candlist = (LPCANDIDATELIST)((LPBYTE)candinfo + candinfo->dwOffset[dwIndex]);
1084 if ( !candlist->dwSize || !candlist->dwCount )
1085 goto done;
1087 if ( !is_himc_ime_unicode(data) )
1089 ret = candlist->dwSize;
1090 if ( lpCandList && dwBufLen >= ret )
1091 memcpy(lpCandList, candlist, ret);
1093 else
1094 ret = convert_candidatelist_WtoA( candlist, lpCandList, dwBufLen);
1096 done:
1097 ImmUnlockIMCC(data->IMC.hCandInfo);
1098 return ret;
1101 /***********************************************************************
1102 * ImmGetCandidateListCountA (IMM32.@)
1104 DWORD WINAPI ImmGetCandidateListCountA(
1105 HIMC hIMC, LPDWORD lpdwListCount)
1107 InputContextData *data = get_imc_data(hIMC);
1108 LPCANDIDATEINFO candinfo;
1109 DWORD ret, count;
1111 TRACE("%p, %p\n", hIMC, lpdwListCount);
1113 if (!data || !lpdwListCount || !data->IMC.hCandInfo)
1114 return 0;
1116 candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1118 *lpdwListCount = count = candinfo->dwCount;
1120 if ( !is_himc_ime_unicode(data) )
1121 ret = candinfo->dwSize;
1122 else
1124 ret = sizeof(CANDIDATEINFO);
1125 while ( count-- )
1126 ret += ImmGetCandidateListA(hIMC, count, NULL, 0);
1129 ImmUnlockIMCC(data->IMC.hCandInfo);
1130 return ret;
1133 /***********************************************************************
1134 * ImmGetCandidateListCountW (IMM32.@)
1136 DWORD WINAPI ImmGetCandidateListCountW(
1137 HIMC hIMC, LPDWORD lpdwListCount)
1139 InputContextData *data = get_imc_data(hIMC);
1140 LPCANDIDATEINFO candinfo;
1141 DWORD ret, count;
1143 TRACE("%p, %p\n", hIMC, lpdwListCount);
1145 if (!data || !lpdwListCount || !data->IMC.hCandInfo)
1146 return 0;
1148 candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1150 *lpdwListCount = count = candinfo->dwCount;
1152 if ( is_himc_ime_unicode(data) )
1153 ret = candinfo->dwSize;
1154 else
1156 ret = sizeof(CANDIDATEINFO);
1157 while ( count-- )
1158 ret += ImmGetCandidateListW(hIMC, count, NULL, 0);
1161 ImmUnlockIMCC(data->IMC.hCandInfo);
1162 return ret;
1165 /***********************************************************************
1166 * ImmGetCandidateListW (IMM32.@)
1168 DWORD WINAPI ImmGetCandidateListW(
1169 HIMC hIMC, DWORD dwIndex,
1170 LPCANDIDATELIST lpCandList, DWORD dwBufLen)
1172 InputContextData *data = get_imc_data(hIMC);
1173 LPCANDIDATEINFO candinfo;
1174 LPCANDIDATELIST candlist;
1175 DWORD ret = 0;
1177 TRACE("%p, %ld, %p, %ld\n", hIMC, dwIndex, lpCandList, dwBufLen);
1179 if (!data || !data->IMC.hCandInfo)
1180 return 0;
1182 candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1183 if (dwIndex >= candinfo->dwCount || dwIndex >= ARRAY_SIZE(candinfo->dwOffset))
1184 goto done;
1186 candlist = (LPCANDIDATELIST)((LPBYTE)candinfo + candinfo->dwOffset[dwIndex]);
1187 if ( !candlist->dwSize || !candlist->dwCount )
1188 goto done;
1190 if ( is_himc_ime_unicode(data) )
1192 ret = candlist->dwSize;
1193 if ( lpCandList && dwBufLen >= ret )
1194 memcpy(lpCandList, candlist, ret);
1196 else
1197 ret = convert_candidatelist_AtoW( candlist, lpCandList, dwBufLen);
1199 done:
1200 ImmUnlockIMCC(data->IMC.hCandInfo);
1201 return ret;
1204 /***********************************************************************
1205 * ImmGetCandidateWindow (IMM32.@)
1207 BOOL WINAPI ImmGetCandidateWindow(
1208 HIMC hIMC, DWORD dwIndex, LPCANDIDATEFORM lpCandidate)
1210 InputContextData *data = get_imc_data(hIMC);
1212 TRACE("%p, %ld, %p\n", hIMC, dwIndex, lpCandidate);
1214 if (!data || !lpCandidate)
1215 return FALSE;
1217 if (dwIndex >= ARRAY_SIZE(data->IMC.cfCandForm))
1218 return FALSE;
1220 if (data->IMC.cfCandForm[dwIndex].dwIndex != dwIndex)
1221 return FALSE;
1223 *lpCandidate = data->IMC.cfCandForm[dwIndex];
1225 return TRUE;
1228 /***********************************************************************
1229 * ImmGetCompositionFontA (IMM32.@)
1231 BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
1233 LOGFONTW lfW;
1234 BOOL rc;
1236 TRACE("(%p, %p):\n", hIMC, lplf);
1238 rc = ImmGetCompositionFontW(hIMC,&lfW);
1239 if (!rc || !lplf)
1240 return FALSE;
1242 memcpy(lplf,&lfW,sizeof(LOGFONTA));
1243 WideCharToMultiByte(CP_ACP, 0, lfW.lfFaceName, -1, lplf->lfFaceName,
1244 LF_FACESIZE, NULL, NULL);
1245 return TRUE;
1248 /***********************************************************************
1249 * ImmGetCompositionFontW (IMM32.@)
1251 BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
1253 InputContextData *data = get_imc_data(hIMC);
1255 TRACE("(%p, %p):\n", hIMC, lplf);
1257 if (!data || !lplf)
1258 return FALSE;
1260 *lplf = data->IMC.lfFont.W;
1262 return TRUE;
1266 /* Helpers for the GetCompositionString functions */
1268 /* Source encoding is defined by context, source length is always given in respective characters. Destination buffer
1269 length is always in bytes. */
1270 static INT CopyCompStringIMEtoClient(const InputContextData *data, const void *src, INT src_len, void *dst,
1271 INT dst_len, BOOL unicode)
1273 int char_size = unicode ? sizeof(WCHAR) : sizeof(char);
1274 INT ret;
1276 if (is_himc_ime_unicode(data) ^ unicode)
1278 if (unicode)
1279 ret = MultiByteToWideChar(CP_ACP, 0, src, src_len, dst, dst_len / sizeof(WCHAR));
1280 else
1281 ret = WideCharToMultiByte(CP_ACP, 0, src, src_len, dst, dst_len, NULL, NULL);
1282 ret *= char_size;
1284 else
1286 if (dst_len)
1288 ret = min(src_len * char_size, dst_len);
1289 memcpy(dst, src, ret);
1291 else
1292 ret = src_len * char_size;
1295 return ret;
1298 /* Composition string encoding is defined by context, returned attributes correspond to string, converted according to
1299 passed mode. String length is in characters, attributes are in byte arrays. */
1300 static INT CopyCompAttrIMEtoClient(const InputContextData *data, const BYTE *src, INT src_len, const void *comp_string,
1301 INT str_len, BYTE *dst, INT dst_len, BOOL unicode)
1303 union
1305 const void *str;
1306 const WCHAR *strW;
1307 const char *strA;
1308 } string;
1309 INT rc;
1311 string.str = comp_string;
1313 if (is_himc_ime_unicode(data) && !unicode)
1315 rc = WideCharToMultiByte(CP_ACP, 0, string.strW, str_len, NULL, 0, NULL, NULL);
1316 if (dst_len)
1318 int i, j = 0, k = 0;
1320 if (rc < dst_len)
1321 dst_len = rc;
1322 for (i = 0; i < str_len; ++i)
1324 int len;
1326 len = WideCharToMultiByte(CP_ACP, 0, string.strW + i, 1, NULL, 0, NULL, NULL);
1327 for (; len > 0; --len)
1329 dst[j++] = src[k];
1331 if (j >= dst_len)
1332 goto end;
1334 ++k;
1336 end:
1337 rc = j;
1340 else if (!is_himc_ime_unicode(data) && unicode)
1342 rc = MultiByteToWideChar(CP_ACP, 0, string.strA, str_len, NULL, 0);
1343 if (dst_len)
1345 int i, j = 0;
1347 if (rc < dst_len)
1348 dst_len = rc;
1349 for (i = 0; i < str_len; ++i)
1351 if (IsDBCSLeadByte(string.strA[i]))
1352 continue;
1354 dst[j++] = src[i];
1356 if (j >= dst_len)
1357 break;
1359 rc = j;
1362 else
1364 memcpy(dst, src, min(src_len, dst_len));
1365 rc = src_len;
1368 return rc;
1371 static INT CopyCompClauseIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE ssource,
1372 LPBYTE target, INT tlen, BOOL unicode )
1374 INT rc;
1376 if (is_himc_ime_unicode(data) && !unicode)
1378 if (tlen)
1380 int i;
1382 if (slen < tlen)
1383 tlen = slen;
1384 tlen /= sizeof (DWORD);
1385 for (i = 0; i < tlen; ++i)
1387 ((DWORD *)target)[i] = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource,
1388 ((DWORD *)source)[i],
1389 NULL, 0,
1390 NULL, NULL);
1392 rc = sizeof (DWORD) * i;
1394 else
1395 rc = slen;
1397 else if (!is_himc_ime_unicode(data) && unicode)
1399 if (tlen)
1401 int i;
1403 if (slen < tlen)
1404 tlen = slen;
1405 tlen /= sizeof (DWORD);
1406 for (i = 0; i < tlen; ++i)
1408 ((DWORD *)target)[i] = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource,
1409 ((DWORD *)source)[i],
1410 NULL, 0);
1412 rc = sizeof (DWORD) * i;
1414 else
1415 rc = slen;
1417 else
1419 memcpy( target, source, min(slen,tlen));
1420 rc = slen;
1423 return rc;
1426 static INT CopyCompOffsetIMEtoClient(InputContextData *data, DWORD offset, LPBYTE ssource, BOOL unicode)
1428 int rc;
1430 if (is_himc_ime_unicode(data) && !unicode)
1432 rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, offset, NULL, 0, NULL, NULL);
1434 else if (!is_himc_ime_unicode(data) && unicode)
1436 rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, offset, NULL, 0);
1438 else
1439 rc = offset;
1441 return rc;
1444 static LONG ImmGetCompositionStringT( HIMC hIMC, DWORD dwIndex, LPVOID lpBuf,
1445 DWORD dwBufLen, BOOL unicode)
1447 LONG rc = 0;
1448 InputContextData *data = get_imc_data(hIMC);
1449 LPCOMPOSITIONSTRING compstr;
1450 LPBYTE compdata;
1452 TRACE("(%p, 0x%lx, %p, %ld)\n", hIMC, dwIndex, lpBuf, dwBufLen);
1454 if (!data)
1455 return FALSE;
1457 if (!data->IMC.hCompStr)
1458 return FALSE;
1460 compdata = ImmLockIMCC(data->IMC.hCompStr);
1461 compstr = (LPCOMPOSITIONSTRING)compdata;
1463 switch (dwIndex)
1465 case GCS_RESULTSTR:
1466 TRACE("GCS_RESULTSTR\n");
1467 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultStrOffset, compstr->dwResultStrLen, lpBuf, dwBufLen, unicode);
1468 break;
1469 case GCS_COMPSTR:
1470 TRACE("GCS_COMPSTR\n");
1471 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen, lpBuf, dwBufLen, unicode);
1472 break;
1473 case GCS_COMPATTR:
1474 TRACE("GCS_COMPATTR\n");
1475 rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompAttrOffset, compstr->dwCompAttrLen,
1476 compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen,
1477 lpBuf, dwBufLen, unicode);
1478 break;
1479 case GCS_COMPCLAUSE:
1480 TRACE("GCS_COMPCLAUSE\n");
1481 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompClauseOffset,compstr->dwCompClauseLen,
1482 compdata + compstr->dwCompStrOffset,
1483 lpBuf, dwBufLen, unicode);
1484 break;
1485 case GCS_RESULTCLAUSE:
1486 TRACE("GCS_RESULTCLAUSE\n");
1487 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultClauseOffset,compstr->dwResultClauseLen,
1488 compdata + compstr->dwResultStrOffset,
1489 lpBuf, dwBufLen, unicode);
1490 break;
1491 case GCS_RESULTREADSTR:
1492 TRACE("GCS_RESULTREADSTR\n");
1493 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultReadStrOffset, compstr->dwResultReadStrLen, lpBuf, dwBufLen, unicode);
1494 break;
1495 case GCS_RESULTREADCLAUSE:
1496 TRACE("GCS_RESULTREADCLAUSE\n");
1497 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultReadClauseOffset,compstr->dwResultReadClauseLen,
1498 compdata + compstr->dwResultStrOffset,
1499 lpBuf, dwBufLen, unicode);
1500 break;
1501 case GCS_COMPREADSTR:
1502 TRACE("GCS_COMPREADSTR\n");
1503 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen, lpBuf, dwBufLen, unicode);
1504 break;
1505 case GCS_COMPREADATTR:
1506 TRACE("GCS_COMPREADATTR\n");
1507 rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompReadAttrOffset, compstr->dwCompReadAttrLen,
1508 compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen,
1509 lpBuf, dwBufLen, unicode);
1510 break;
1511 case GCS_COMPREADCLAUSE:
1512 TRACE("GCS_COMPREADCLAUSE\n");
1513 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompReadClauseOffset,compstr->dwCompReadClauseLen,
1514 compdata + compstr->dwCompStrOffset,
1515 lpBuf, dwBufLen, unicode);
1516 break;
1517 case GCS_CURSORPOS:
1518 TRACE("GCS_CURSORPOS\n");
1519 rc = CopyCompOffsetIMEtoClient(data, compstr->dwCursorPos, compdata + compstr->dwCompStrOffset, unicode);
1520 break;
1521 case GCS_DELTASTART:
1522 TRACE("GCS_DELTASTART\n");
1523 rc = CopyCompOffsetIMEtoClient(data, compstr->dwDeltaStart, compdata + compstr->dwCompStrOffset, unicode);
1524 break;
1525 default:
1526 FIXME("Unhandled index 0x%lx\n",dwIndex);
1527 break;
1530 ImmUnlockIMCC(data->IMC.hCompStr);
1532 return rc;
1535 /***********************************************************************
1536 * ImmGetCompositionStringA (IMM32.@)
1538 LONG WINAPI ImmGetCompositionStringA(
1539 HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
1541 return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, FALSE);
1545 /***********************************************************************
1546 * ImmGetCompositionStringW (IMM32.@)
1548 LONG WINAPI ImmGetCompositionStringW(
1549 HIMC hIMC, DWORD dwIndex,
1550 LPVOID lpBuf, DWORD dwBufLen)
1552 return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, TRUE);
1555 /***********************************************************************
1556 * ImmGetCompositionWindow (IMM32.@)
1558 BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
1560 InputContextData *data = get_imc_data(hIMC);
1562 TRACE("(%p, %p)\n", hIMC, lpCompForm);
1564 if (!data)
1565 return FALSE;
1567 *lpCompForm = data->IMC.cfCompForm;
1568 return TRUE;
1571 /***********************************************************************
1572 * ImmGetContext (IMM32.@)
1575 HIMC WINAPI ImmGetContext(HWND hWnd)
1577 HIMC rc;
1579 TRACE("%p\n", hWnd);
1581 rc = NtUserGetWindowInputContext(hWnd);
1583 if (rc)
1585 InputContextData *data = get_imc_data(rc);
1586 if (data) data->IMC.hWnd = hWnd;
1587 else rc = 0;
1590 TRACE("returning %p\n", rc);
1592 return rc;
1595 /***********************************************************************
1596 * ImmGetConversionListA (IMM32.@)
1598 DWORD WINAPI ImmGetConversionListA(
1599 HKL hKL, HIMC hIMC,
1600 LPCSTR pSrc, LPCANDIDATELIST lpDst,
1601 DWORD dwBufLen, UINT uFlag)
1603 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1604 TRACE("(%p, %p, %s, %p, %ld, %d):\n", hKL, hIMC, debugstr_a(pSrc), lpDst,
1605 dwBufLen, uFlag);
1606 if (immHkl->hIME && immHkl->pImeConversionList)
1608 if (!is_kbd_ime_unicode(immHkl))
1609 return immHkl->pImeConversionList(hIMC,(LPCWSTR)pSrc,lpDst,dwBufLen,uFlag);
1610 else
1612 LPCANDIDATELIST lpwDst;
1613 DWORD ret = 0, len;
1614 LPWSTR pwSrc = strdupAtoW(pSrc);
1616 len = immHkl->pImeConversionList(hIMC, pwSrc, NULL, 0, uFlag);
1617 lpwDst = HeapAlloc(GetProcessHeap(), 0, len);
1618 if ( lpwDst )
1620 immHkl->pImeConversionList(hIMC, pwSrc, lpwDst, len, uFlag);
1621 ret = convert_candidatelist_WtoA( lpwDst, lpDst, dwBufLen);
1622 HeapFree(GetProcessHeap(), 0, lpwDst);
1624 HeapFree(GetProcessHeap(), 0, pwSrc);
1626 return ret;
1629 else
1630 return 0;
1633 /***********************************************************************
1634 * ImmGetConversionListW (IMM32.@)
1636 DWORD WINAPI ImmGetConversionListW(
1637 HKL hKL, HIMC hIMC,
1638 LPCWSTR pSrc, LPCANDIDATELIST lpDst,
1639 DWORD dwBufLen, UINT uFlag)
1641 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1642 TRACE("(%p, %p, %s, %p, %ld, %d):\n", hKL, hIMC, debugstr_w(pSrc), lpDst,
1643 dwBufLen, uFlag);
1644 if (immHkl->hIME && immHkl->pImeConversionList)
1646 if (is_kbd_ime_unicode(immHkl))
1647 return immHkl->pImeConversionList(hIMC,pSrc,lpDst,dwBufLen,uFlag);
1648 else
1650 LPCANDIDATELIST lpaDst;
1651 DWORD ret = 0, len;
1652 LPSTR paSrc = strdupWtoA(pSrc);
1654 len = immHkl->pImeConversionList(hIMC, (LPCWSTR)paSrc, NULL, 0, uFlag);
1655 lpaDst = HeapAlloc(GetProcessHeap(), 0, len);
1656 if ( lpaDst )
1658 immHkl->pImeConversionList(hIMC, (LPCWSTR)paSrc, lpaDst, len, uFlag);
1659 ret = convert_candidatelist_AtoW( lpaDst, lpDst, dwBufLen);
1660 HeapFree(GetProcessHeap(), 0, lpaDst);
1662 HeapFree(GetProcessHeap(), 0, paSrc);
1664 return ret;
1667 else
1668 return 0;
1671 /***********************************************************************
1672 * ImmGetConversionStatus (IMM32.@)
1674 BOOL WINAPI ImmGetConversionStatus(
1675 HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence)
1677 InputContextData *data = get_imc_data(hIMC);
1679 TRACE("%p %p %p\n", hIMC, lpfdwConversion, lpfdwSentence);
1681 if (!data)
1682 return FALSE;
1684 if (lpfdwConversion)
1685 *lpfdwConversion = data->IMC.fdwConversion;
1686 if (lpfdwSentence)
1687 *lpfdwSentence = data->IMC.fdwSentence;
1689 return TRUE;
1692 /***********************************************************************
1693 * ImmGetDefaultIMEWnd (IMM32.@)
1695 HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
1697 return NtUserGetDefaultImeWindow(hWnd);
1700 /***********************************************************************
1701 * ImmGetDescriptionA (IMM32.@)
1703 UINT WINAPI ImmGetDescriptionA(
1704 HKL hKL, LPSTR lpszDescription, UINT uBufLen)
1706 WCHAR *buf;
1707 DWORD len;
1709 TRACE("%p %p %d\n", hKL, lpszDescription, uBufLen);
1711 /* find out how many characters in the unicode buffer */
1712 len = ImmGetDescriptionW( hKL, NULL, 0 );
1713 if (!len)
1714 return 0;
1716 /* allocate a buffer of that size */
1717 buf = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof (WCHAR) );
1718 if( !buf )
1719 return 0;
1721 /* fetch the unicode buffer */
1722 len = ImmGetDescriptionW( hKL, buf, len + 1 );
1724 /* convert it back to ANSI */
1725 len = WideCharToMultiByte( CP_ACP, 0, buf, len + 1,
1726 lpszDescription, uBufLen, NULL, NULL );
1728 HeapFree( GetProcessHeap(), 0, buf );
1730 if (len == 0)
1731 return 0;
1733 return len - 1;
1736 /***********************************************************************
1737 * ImmGetDescriptionW (IMM32.@)
1739 UINT WINAPI ImmGetDescriptionW(HKL hKL, LPWSTR lpszDescription, UINT uBufLen)
1741 FIXME("(%p, %p, %d): semi stub\n", hKL, lpszDescription, uBufLen);
1743 if (!hKL) return 0;
1744 if (!uBufLen) return lstrlenW(L"Wine XIM" );
1745 lstrcpynW( lpszDescription, L"Wine XIM", uBufLen );
1746 return lstrlenW( lpszDescription );
1749 /***********************************************************************
1750 * ImmGetGuideLineA (IMM32.@)
1752 DWORD WINAPI ImmGetGuideLineA(
1753 HIMC hIMC, DWORD dwIndex, LPSTR lpBuf, DWORD dwBufLen)
1755 FIXME("(%p, %ld, %s, %ld): stub\n",
1756 hIMC, dwIndex, debugstr_a(lpBuf), dwBufLen
1758 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1759 return 0;
1762 /***********************************************************************
1763 * ImmGetGuideLineW (IMM32.@)
1765 DWORD WINAPI ImmGetGuideLineW(HIMC hIMC, DWORD dwIndex, LPWSTR lpBuf, DWORD dwBufLen)
1767 FIXME("(%p, %ld, %s, %ld): stub\n",
1768 hIMC, dwIndex, debugstr_w(lpBuf), dwBufLen
1770 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1771 return 0;
1774 /***********************************************************************
1775 * ImmGetIMEFileNameA (IMM32.@)
1777 UINT WINAPI ImmGetIMEFileNameA( HKL hKL, LPSTR lpszFileName, UINT uBufLen)
1779 LPWSTR bufW = NULL;
1780 UINT wBufLen = uBufLen;
1781 UINT rc;
1783 if (uBufLen && lpszFileName)
1784 bufW = HeapAlloc(GetProcessHeap(),0,uBufLen * sizeof(WCHAR));
1785 else /* We need this to get the number of byte required */
1787 bufW = HeapAlloc(GetProcessHeap(),0,MAX_PATH * sizeof(WCHAR));
1788 wBufLen = MAX_PATH;
1791 rc = ImmGetIMEFileNameW(hKL,bufW,wBufLen);
1793 if (rc > 0)
1795 if (uBufLen && lpszFileName)
1796 rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, lpszFileName,
1797 uBufLen, NULL, NULL);
1798 else /* get the length */
1799 rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL,
1800 NULL);
1803 HeapFree(GetProcessHeap(),0,bufW);
1804 return rc;
1807 /***********************************************************************
1808 * ImmGetIMEFileNameW (IMM32.@)
1810 UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen)
1812 HKEY hkey;
1813 DWORD length;
1814 DWORD rc;
1815 WCHAR regKey[ARRAY_SIZE(szImeRegFmt)+8];
1817 wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hKL );
1818 rc = RegOpenKeyW( HKEY_LOCAL_MACHINE, regKey, &hkey);
1819 if (rc != ERROR_SUCCESS)
1821 SetLastError(rc);
1822 return 0;
1825 length = 0;
1826 rc = RegGetValueW(hkey, NULL, L"Ime File", RRF_RT_REG_SZ, NULL, NULL, &length);
1828 if (rc != ERROR_SUCCESS)
1830 RegCloseKey(hkey);
1831 SetLastError(rc);
1832 return 0;
1834 if (length > uBufLen * sizeof(WCHAR) || !lpszFileName)
1836 RegCloseKey(hkey);
1837 if (lpszFileName)
1839 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1840 return 0;
1842 else
1843 return length / sizeof(WCHAR);
1846 RegGetValueW(hkey, NULL, L"Ime File", RRF_RT_REG_SZ, NULL, lpszFileName, &length);
1848 RegCloseKey(hkey);
1850 return length / sizeof(WCHAR);
1853 /***********************************************************************
1854 * ImmGetOpenStatus (IMM32.@)
1856 BOOL WINAPI ImmGetOpenStatus(HIMC hIMC)
1858 InputContextData *data = get_imc_data(hIMC);
1859 static int i;
1861 if (!data)
1862 return FALSE;
1864 TRACE("(%p): semi-stub\n", hIMC);
1866 if (!i++)
1867 FIXME("(%p): semi-stub\n", hIMC);
1869 return data->IMC.fOpen;
1872 /***********************************************************************
1873 * ImmGetProperty (IMM32.@)
1875 DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex)
1877 DWORD rc = 0;
1878 ImmHkl *kbd;
1880 TRACE("(%p, %ld)\n", hKL, fdwIndex);
1881 kbd = IMM_GetImmHkl(hKL);
1883 if (kbd && kbd->hIME)
1885 switch (fdwIndex)
1887 case IGP_PROPERTY: rc = kbd->imeInfo.fdwProperty; break;
1888 case IGP_CONVERSION: rc = kbd->imeInfo.fdwConversionCaps; break;
1889 case IGP_SENTENCE: rc = kbd->imeInfo.fdwSentenceCaps; break;
1890 case IGP_SETCOMPSTR: rc = kbd->imeInfo.fdwSCSCaps; break;
1891 case IGP_SELECT: rc = kbd->imeInfo.fdwSelectCaps; break;
1892 case IGP_GETIMEVERSION: rc = IMEVER_0400; break;
1893 case IGP_UI: rc = 0; break;
1894 default: rc = 0;
1897 return rc;
1900 /***********************************************************************
1901 * ImmGetRegisterWordStyleA (IMM32.@)
1903 UINT WINAPI ImmGetRegisterWordStyleA(
1904 HKL hKL, UINT nItem, LPSTYLEBUFA lpStyleBuf)
1906 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1907 TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf);
1908 if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle)
1910 if (!is_kbd_ime_unicode(immHkl))
1911 return immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)lpStyleBuf);
1912 else
1914 STYLEBUFW sbw;
1915 UINT rc;
1917 rc = immHkl->pImeGetRegisterWordStyle(nItem,&sbw);
1918 WideCharToMultiByte(CP_ACP, 0, sbw.szDescription, -1,
1919 lpStyleBuf->szDescription, 32, NULL, NULL);
1920 lpStyleBuf->dwStyle = sbw.dwStyle;
1921 return rc;
1924 else
1925 return 0;
1928 /***********************************************************************
1929 * ImmGetRegisterWordStyleW (IMM32.@)
1931 UINT WINAPI ImmGetRegisterWordStyleW(
1932 HKL hKL, UINT nItem, LPSTYLEBUFW lpStyleBuf)
1934 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1935 TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf);
1936 if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle)
1938 if (is_kbd_ime_unicode(immHkl))
1939 return immHkl->pImeGetRegisterWordStyle(nItem,lpStyleBuf);
1940 else
1942 STYLEBUFA sba;
1943 UINT rc;
1945 rc = immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)&sba);
1946 MultiByteToWideChar(CP_ACP, 0, sba.szDescription, -1,
1947 lpStyleBuf->szDescription, 32);
1948 lpStyleBuf->dwStyle = sba.dwStyle;
1949 return rc;
1952 else
1953 return 0;
1956 /***********************************************************************
1957 * ImmGetStatusWindowPos (IMM32.@)
1959 BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
1961 InputContextData *data = get_imc_data(hIMC);
1963 TRACE("(%p, %p)\n", hIMC, lpptPos);
1965 if (!data || !lpptPos)
1966 return FALSE;
1968 *lpptPos = data->IMC.ptStatusWndPos;
1970 return TRUE;
1973 /***********************************************************************
1974 * ImmGetVirtualKey (IMM32.@)
1976 UINT WINAPI ImmGetVirtualKey(HWND hWnd)
1978 OSVERSIONINFOA version;
1979 InputContextData *data = get_imc_data( ImmGetContext( hWnd ));
1980 TRACE("%p\n", hWnd);
1982 if ( data )
1983 return data->lastVK;
1985 version.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1986 GetVersionExA( &version );
1987 switch(version.dwPlatformId)
1989 case VER_PLATFORM_WIN32_WINDOWS:
1990 return VK_PROCESSKEY;
1991 case VER_PLATFORM_WIN32_NT:
1992 return 0;
1993 default:
1994 FIXME("%ld not supported\n",version.dwPlatformId);
1995 return VK_PROCESSKEY;
1999 /***********************************************************************
2000 * ImmInstallIMEA (IMM32.@)
2002 HKL WINAPI ImmInstallIMEA(
2003 LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
2005 LPWSTR lpszwIMEFileName;
2006 LPWSTR lpszwLayoutText;
2007 HKL hkl;
2009 TRACE ("(%s, %s)\n", debugstr_a(lpszIMEFileName),
2010 debugstr_a(lpszLayoutText));
2012 lpszwIMEFileName = strdupAtoW(lpszIMEFileName);
2013 lpszwLayoutText = strdupAtoW(lpszLayoutText);
2015 hkl = ImmInstallIMEW(lpszwIMEFileName, lpszwLayoutText);
2017 HeapFree(GetProcessHeap(),0,lpszwIMEFileName);
2018 HeapFree(GetProcessHeap(),0,lpszwLayoutText);
2019 return hkl;
2022 /***********************************************************************
2023 * ImmInstallIMEW (IMM32.@)
2025 HKL WINAPI ImmInstallIMEW(
2026 LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
2028 INT lcid = GetUserDefaultLCID();
2029 INT count;
2030 HKL hkl;
2031 DWORD rc;
2032 HKEY hkey;
2033 WCHAR regKey[ARRAY_SIZE(szImeRegFmt)+8];
2035 TRACE ("(%s, %s):\n", debugstr_w(lpszIMEFileName),
2036 debugstr_w(lpszLayoutText));
2038 /* Start with 2. e001 will be blank and so default to the wine internal IME */
2039 count = 2;
2041 while (count < 0xfff)
2043 DWORD disposition = 0;
2045 hkl = (HKL)MAKELPARAM( lcid, 0xe000 | count );
2046 wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hkl);
2048 rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, regKey, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &disposition);
2049 if (rc == ERROR_SUCCESS && disposition == REG_CREATED_NEW_KEY)
2050 break;
2051 else if (rc == ERROR_SUCCESS)
2052 RegCloseKey(hkey);
2054 count++;
2057 if (count == 0xfff)
2059 WARN("Unable to find slot to install IME\n");
2060 return 0;
2063 if (rc == ERROR_SUCCESS)
2065 rc = RegSetValueExW(hkey, L"Ime File", 0, REG_SZ, (const BYTE*)lpszIMEFileName,
2066 (lstrlenW(lpszIMEFileName) + 1) * sizeof(WCHAR));
2067 if (rc == ERROR_SUCCESS)
2068 rc = RegSetValueExW(hkey, L"Layout Text", 0, REG_SZ, (const BYTE*)lpszLayoutText,
2069 (lstrlenW(lpszLayoutText) + 1) * sizeof(WCHAR));
2070 RegCloseKey(hkey);
2071 return hkl;
2073 else
2075 WARN("Unable to set IME registry values\n");
2076 return 0;
2080 /***********************************************************************
2081 * ImmIsIME (IMM32.@)
2083 BOOL WINAPI ImmIsIME(HKL hKL)
2085 ImmHkl *ptr;
2086 TRACE("(%p):\n", hKL);
2087 ptr = IMM_GetImmHkl(hKL);
2088 return (ptr && ptr->hIME);
2091 /***********************************************************************
2092 * ImmIsUIMessageA (IMM32.@)
2094 BOOL WINAPI ImmIsUIMessageA(
2095 HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
2097 TRACE("(%p, %x, %Id, %Id)\n", hWndIME, msg, wParam, lParam);
2098 if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
2099 (msg == WM_IME_SETCONTEXT) ||
2100 (msg == WM_IME_NOTIFY) ||
2101 (msg == WM_IME_COMPOSITIONFULL) ||
2102 (msg == WM_IME_SELECT) ||
2103 (msg == 0x287 /* FIXME: WM_IME_SYSTEM */))
2105 if (hWndIME)
2106 SendMessageA(hWndIME, msg, wParam, lParam);
2108 return TRUE;
2110 return FALSE;
2113 /***********************************************************************
2114 * ImmIsUIMessageW (IMM32.@)
2116 BOOL WINAPI ImmIsUIMessageW(
2117 HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
2119 TRACE("(%p, %x, %Id, %Id)\n", hWndIME, msg, wParam, lParam);
2120 if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
2121 (msg == WM_IME_SETCONTEXT) ||
2122 (msg == WM_IME_NOTIFY) ||
2123 (msg == WM_IME_COMPOSITIONFULL) ||
2124 (msg == WM_IME_SELECT) ||
2125 (msg == 0x287 /* FIXME: WM_IME_SYSTEM */))
2127 if (hWndIME)
2128 SendMessageW(hWndIME, msg, wParam, lParam);
2130 return TRUE;
2132 return FALSE;
2135 /***********************************************************************
2136 * ImmNotifyIME (IMM32.@)
2138 BOOL WINAPI ImmNotifyIME(
2139 HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
2141 InputContextData *data = get_imc_data(hIMC);
2143 TRACE("(%p, %ld, %ld, %ld)\n",
2144 hIMC, dwAction, dwIndex, dwValue);
2146 if (hIMC == NULL)
2148 SetLastError(ERROR_SUCCESS);
2149 return FALSE;
2152 if (!data || ! data->immKbd->pNotifyIME)
2154 return FALSE;
2157 return data->immKbd->pNotifyIME(hIMC,dwAction,dwIndex,dwValue);
2160 /***********************************************************************
2161 * ImmRegisterWordA (IMM32.@)
2163 BOOL WINAPI ImmRegisterWordA(
2164 HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszRegister)
2166 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2167 TRACE("(%p, %s, %ld, %s):\n", hKL, debugstr_a(lpszReading), dwStyle,
2168 debugstr_a(lpszRegister));
2169 if (immHkl->hIME && immHkl->pImeRegisterWord)
2171 if (!is_kbd_ime_unicode(immHkl))
2172 return immHkl->pImeRegisterWord((LPCWSTR)lpszReading,dwStyle,
2173 (LPCWSTR)lpszRegister);
2174 else
2176 LPWSTR lpszwReading = strdupAtoW(lpszReading);
2177 LPWSTR lpszwRegister = strdupAtoW(lpszRegister);
2178 BOOL rc;
2180 rc = immHkl->pImeRegisterWord(lpszwReading,dwStyle,lpszwRegister);
2181 HeapFree(GetProcessHeap(),0,lpszwReading);
2182 HeapFree(GetProcessHeap(),0,lpszwRegister);
2183 return rc;
2186 else
2187 return FALSE;
2190 /***********************************************************************
2191 * ImmRegisterWordW (IMM32.@)
2193 BOOL WINAPI ImmRegisterWordW(
2194 HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszRegister)
2196 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2197 TRACE("(%p, %s, %ld, %s):\n", hKL, debugstr_w(lpszReading), dwStyle,
2198 debugstr_w(lpszRegister));
2199 if (immHkl->hIME && immHkl->pImeRegisterWord)
2201 if (is_kbd_ime_unicode(immHkl))
2202 return immHkl->pImeRegisterWord(lpszReading,dwStyle,lpszRegister);
2203 else
2205 LPSTR lpszaReading = strdupWtoA(lpszReading);
2206 LPSTR lpszaRegister = strdupWtoA(lpszRegister);
2207 BOOL rc;
2209 rc = immHkl->pImeRegisterWord((LPCWSTR)lpszaReading,dwStyle,
2210 (LPCWSTR)lpszaRegister);
2211 HeapFree(GetProcessHeap(),0,lpszaReading);
2212 HeapFree(GetProcessHeap(),0,lpszaRegister);
2213 return rc;
2216 else
2217 return FALSE;
2220 /***********************************************************************
2221 * ImmReleaseContext (IMM32.@)
2223 BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC)
2225 static BOOL shown = FALSE;
2227 if (!shown) {
2228 FIXME("(%p, %p): stub\n", hWnd, hIMC);
2229 shown = TRUE;
2231 return TRUE;
2234 /***********************************************************************
2235 * ImmRequestMessageA(IMM32.@)
2237 LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam)
2239 InputContextData *data = get_imc_data(hIMC);
2241 TRACE("%p %Id %Id\n", hIMC, wParam, wParam);
2243 if (data) return SendMessageA(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
2245 SetLastError(ERROR_INVALID_HANDLE);
2246 return 0;
2249 /***********************************************************************
2250 * ImmRequestMessageW(IMM32.@)
2252 LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam)
2254 InputContextData *data = get_imc_data(hIMC);
2256 TRACE("%p %Id %Id\n", hIMC, wParam, wParam);
2258 if (data) return SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
2260 SetLastError(ERROR_INVALID_HANDLE);
2261 return 0;
2264 /***********************************************************************
2265 * ImmSetCandidateWindow (IMM32.@)
2267 BOOL WINAPI ImmSetCandidateWindow(
2268 HIMC hIMC, LPCANDIDATEFORM lpCandidate)
2270 InputContextData *data = get_imc_data(hIMC);
2272 TRACE("(%p, %p)\n", hIMC, lpCandidate);
2274 if (!data || !lpCandidate)
2275 return FALSE;
2277 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2278 return FALSE;
2280 TRACE("\t%lx, %lx, %s, %s\n",
2281 lpCandidate->dwIndex, lpCandidate->dwStyle,
2282 wine_dbgstr_point(&lpCandidate->ptCurrentPos),
2283 wine_dbgstr_rect(&lpCandidate->rcArea));
2285 if (lpCandidate->dwIndex >= ARRAY_SIZE(data->IMC.cfCandForm))
2286 return FALSE;
2288 data->IMC.cfCandForm[lpCandidate->dwIndex] = *lpCandidate;
2289 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCANDIDATEPOS);
2290 ImmInternalSendIMENotify(data, IMN_SETCANDIDATEPOS, 1 << lpCandidate->dwIndex);
2292 return TRUE;
2295 /***********************************************************************
2296 * ImmSetCompositionFontA (IMM32.@)
2298 BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
2300 InputContextData *data = get_imc_data(hIMC);
2301 TRACE("(%p, %p)\n", hIMC, lplf);
2303 if (!data || !lplf)
2305 SetLastError(ERROR_INVALID_HANDLE);
2306 return FALSE;
2309 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2310 return FALSE;
2312 memcpy(&data->IMC.lfFont.W,lplf,sizeof(LOGFONTA));
2313 MultiByteToWideChar(CP_ACP, 0, lplf->lfFaceName, -1, data->IMC.lfFont.W.lfFaceName,
2314 LF_FACESIZE);
2315 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT);
2316 ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
2318 return TRUE;
2321 /***********************************************************************
2322 * ImmSetCompositionFontW (IMM32.@)
2324 BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
2326 InputContextData *data = get_imc_data(hIMC);
2327 TRACE("(%p, %p)\n", hIMC, lplf);
2329 if (!data || !lplf)
2331 SetLastError(ERROR_INVALID_HANDLE);
2332 return FALSE;
2335 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2336 return FALSE;
2338 data->IMC.lfFont.W = *lplf;
2339 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT);
2340 ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
2342 return TRUE;
2345 /***********************************************************************
2346 * ImmSetCompositionStringA (IMM32.@)
2348 BOOL WINAPI ImmSetCompositionStringA(
2349 HIMC hIMC, DWORD dwIndex,
2350 LPCVOID lpComp, DWORD dwCompLen,
2351 LPCVOID lpRead, DWORD dwReadLen)
2353 DWORD comp_len;
2354 DWORD read_len;
2355 WCHAR *CompBuffer = NULL;
2356 WCHAR *ReadBuffer = NULL;
2357 BOOL rc;
2358 InputContextData *data = get_imc_data(hIMC);
2360 TRACE("(%p, %ld, %p, %ld, %p, %ld):\n",
2361 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
2363 if (!data)
2364 return FALSE;
2366 if (!(dwIndex == SCS_SETSTR ||
2367 dwIndex == SCS_CHANGEATTR ||
2368 dwIndex == SCS_CHANGECLAUSE ||
2369 dwIndex == SCS_SETRECONVERTSTRING ||
2370 dwIndex == SCS_QUERYRECONVERTSTRING))
2371 return FALSE;
2373 if (!is_himc_ime_unicode(data))
2374 return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
2375 dwCompLen, lpRead, dwReadLen);
2377 comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0);
2378 if (comp_len)
2380 CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len * sizeof(WCHAR));
2381 MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len);
2384 read_len = MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, NULL, 0);
2385 if (read_len)
2387 ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len * sizeof(WCHAR));
2388 MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len);
2391 rc = ImmSetCompositionStringW(hIMC, dwIndex, CompBuffer, comp_len,
2392 ReadBuffer, read_len);
2394 HeapFree(GetProcessHeap(), 0, CompBuffer);
2395 HeapFree(GetProcessHeap(), 0, ReadBuffer);
2397 return rc;
2400 /***********************************************************************
2401 * ImmSetCompositionStringW (IMM32.@)
2403 BOOL WINAPI ImmSetCompositionStringW(
2404 HIMC hIMC, DWORD dwIndex,
2405 LPCVOID lpComp, DWORD dwCompLen,
2406 LPCVOID lpRead, DWORD dwReadLen)
2408 DWORD comp_len;
2409 DWORD read_len;
2410 CHAR *CompBuffer = NULL;
2411 CHAR *ReadBuffer = NULL;
2412 BOOL rc;
2413 InputContextData *data = get_imc_data(hIMC);
2415 TRACE("(%p, %ld, %p, %ld, %p, %ld):\n",
2416 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
2418 if (!data)
2419 return FALSE;
2421 if (!(dwIndex == SCS_SETSTR ||
2422 dwIndex == SCS_CHANGEATTR ||
2423 dwIndex == SCS_CHANGECLAUSE ||
2424 dwIndex == SCS_SETRECONVERTSTRING ||
2425 dwIndex == SCS_QUERYRECONVERTSTRING))
2426 return FALSE;
2428 if (is_himc_ime_unicode(data))
2429 return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
2430 dwCompLen, lpRead, dwReadLen);
2432 comp_len = WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, NULL, 0, NULL,
2433 NULL);
2434 if (comp_len)
2436 CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len);
2437 WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len,
2438 NULL, NULL);
2441 read_len = WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, NULL, 0, NULL,
2442 NULL);
2443 if (read_len)
2445 ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len);
2446 WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len,
2447 NULL, NULL);
2450 rc = ImmSetCompositionStringA(hIMC, dwIndex, CompBuffer, comp_len,
2451 ReadBuffer, read_len);
2453 HeapFree(GetProcessHeap(), 0, CompBuffer);
2454 HeapFree(GetProcessHeap(), 0, ReadBuffer);
2456 return rc;
2459 /***********************************************************************
2460 * ImmSetCompositionWindow (IMM32.@)
2462 BOOL WINAPI ImmSetCompositionWindow(
2463 HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
2465 BOOL reshow = FALSE;
2466 InputContextData *data = get_imc_data(hIMC);
2468 TRACE("(%p, %p)\n", hIMC, lpCompForm);
2469 if (lpCompForm)
2470 TRACE("\t%lx, %s, %s\n", lpCompForm->dwStyle,
2471 wine_dbgstr_point(&lpCompForm->ptCurrentPos),
2472 wine_dbgstr_rect(&lpCompForm->rcArea));
2474 if (!data)
2476 SetLastError(ERROR_INVALID_HANDLE);
2477 return FALSE;
2480 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2481 return FALSE;
2483 data->IMC.cfCompForm = *lpCompForm;
2485 if (IsWindowVisible(data->immKbd->UIWnd))
2487 reshow = TRUE;
2488 ShowWindow(data->immKbd->UIWnd,SW_HIDE);
2491 /* FIXME: this is a partial stub */
2493 if (reshow)
2494 ShowWindow(data->immKbd->UIWnd,SW_SHOWNOACTIVATE);
2496 ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONWINDOW, 0);
2497 return TRUE;
2500 /***********************************************************************
2501 * ImmSetConversionStatus (IMM32.@)
2503 BOOL WINAPI ImmSetConversionStatus(
2504 HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence)
2506 DWORD oldConversion, oldSentence;
2507 InputContextData *data = get_imc_data(hIMC);
2509 TRACE("%p %ld %ld\n", hIMC, fdwConversion, fdwSentence);
2511 if (!data)
2513 SetLastError(ERROR_INVALID_HANDLE);
2514 return FALSE;
2517 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2518 return FALSE;
2520 if ( fdwConversion != data->IMC.fdwConversion )
2522 oldConversion = data->IMC.fdwConversion;
2523 data->IMC.fdwConversion = fdwConversion;
2524 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldConversion, IMC_SETCONVERSIONMODE);
2525 ImmInternalSendIMENotify(data, IMN_SETCONVERSIONMODE, 0);
2527 if ( fdwSentence != data->IMC.fdwSentence )
2529 oldSentence = data->IMC.fdwSentence;
2530 data->IMC.fdwSentence = fdwSentence;
2531 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldSentence, IMC_SETSENTENCEMODE);
2532 ImmInternalSendIMENotify(data, IMN_SETSENTENCEMODE, 0);
2535 return TRUE;
2538 /***********************************************************************
2539 * ImmSetOpenStatus (IMM32.@)
2541 BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen)
2543 InputContextData *data = get_imc_data(hIMC);
2545 TRACE("%p %d\n", hIMC, fOpen);
2547 if (!data)
2549 SetLastError(ERROR_INVALID_HANDLE);
2550 return FALSE;
2553 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2554 return FALSE;
2556 if (data->immKbd->UIWnd == NULL)
2558 /* create the ime window */
2559 data->immKbd->UIWnd = CreateWindowExW( WS_EX_TOOLWINDOW,
2560 data->immKbd->imeClassName, NULL, WS_POPUP, 0, 0, 1, 1, 0,
2561 0, data->immKbd->hIME, 0);
2562 SetWindowLongPtrW(data->immKbd->UIWnd, IMMGWL_IMC, (LONG_PTR)data);
2564 else if (fOpen)
2565 SetWindowLongPtrW(data->immKbd->UIWnd, IMMGWL_IMC, (LONG_PTR)data);
2567 if (!fOpen != !data->IMC.fOpen)
2569 data->IMC.fOpen = fOpen;
2570 ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETOPENSTATUS);
2571 ImmInternalSendIMENotify(data, IMN_SETOPENSTATUS, 0);
2574 return TRUE;
2577 /***********************************************************************
2578 * ImmSetStatusWindowPos (IMM32.@)
2580 BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
2582 InputContextData *data = get_imc_data(hIMC);
2584 TRACE("(%p, %p)\n", hIMC, lpptPos);
2586 if (!data || !lpptPos)
2588 SetLastError(ERROR_INVALID_HANDLE);
2589 return FALSE;
2592 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2593 return FALSE;
2595 TRACE("\t%s\n", wine_dbgstr_point(lpptPos));
2597 data->IMC.ptStatusWndPos = *lpptPos;
2598 ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETSTATUSWINDOWPOS);
2599 ImmInternalSendIMENotify(data, IMN_SETSTATUSWINDOWPOS, 0);
2601 return TRUE;
2604 /***********************************************************************
2605 * ImmCreateSoftKeyboard(IMM32.@)
2607 HWND WINAPI ImmCreateSoftKeyboard(UINT uType, UINT hOwner, int x, int y)
2609 FIXME("(%d, %d, %d, %d): stub\n", uType, hOwner, x, y);
2610 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2611 return 0;
2614 /***********************************************************************
2615 * ImmDestroySoftKeyboard(IMM32.@)
2617 BOOL WINAPI ImmDestroySoftKeyboard(HWND hSoftWnd)
2619 FIXME("(%p): stub\n", hSoftWnd);
2620 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2621 return FALSE;
2624 /***********************************************************************
2625 * ImmShowSoftKeyboard(IMM32.@)
2627 BOOL WINAPI ImmShowSoftKeyboard(HWND hSoftWnd, int nCmdShow)
2629 FIXME("(%p, %d): stub\n", hSoftWnd, nCmdShow);
2630 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2631 return FALSE;
2634 /***********************************************************************
2635 * ImmSimulateHotKey (IMM32.@)
2637 BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID)
2639 FIXME("(%p, %ld): stub\n", hWnd, dwHotKeyID);
2640 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2641 return FALSE;
2644 /***********************************************************************
2645 * ImmUnregisterWordA (IMM32.@)
2647 BOOL WINAPI ImmUnregisterWordA(
2648 HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszUnregister)
2650 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2651 TRACE("(%p, %s, %ld, %s):\n", hKL, debugstr_a(lpszReading), dwStyle,
2652 debugstr_a(lpszUnregister));
2653 if (immHkl->hIME && immHkl->pImeUnregisterWord)
2655 if (!is_kbd_ime_unicode(immHkl))
2656 return immHkl->pImeUnregisterWord((LPCWSTR)lpszReading,dwStyle,
2657 (LPCWSTR)lpszUnregister);
2658 else
2660 LPWSTR lpszwReading = strdupAtoW(lpszReading);
2661 LPWSTR lpszwUnregister = strdupAtoW(lpszUnregister);
2662 BOOL rc;
2664 rc = immHkl->pImeUnregisterWord(lpszwReading,dwStyle,lpszwUnregister);
2665 HeapFree(GetProcessHeap(),0,lpszwReading);
2666 HeapFree(GetProcessHeap(),0,lpszwUnregister);
2667 return rc;
2670 else
2671 return FALSE;
2674 /***********************************************************************
2675 * ImmUnregisterWordW (IMM32.@)
2677 BOOL WINAPI ImmUnregisterWordW(
2678 HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszUnregister)
2680 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2681 TRACE("(%p, %s, %ld, %s):\n", hKL, debugstr_w(lpszReading), dwStyle,
2682 debugstr_w(lpszUnregister));
2683 if (immHkl->hIME && immHkl->pImeUnregisterWord)
2685 if (is_kbd_ime_unicode(immHkl))
2686 return immHkl->pImeUnregisterWord(lpszReading,dwStyle,lpszUnregister);
2687 else
2689 LPSTR lpszaReading = strdupWtoA(lpszReading);
2690 LPSTR lpszaUnregister = strdupWtoA(lpszUnregister);
2691 BOOL rc;
2693 rc = immHkl->pImeUnregisterWord((LPCWSTR)lpszaReading,dwStyle,
2694 (LPCWSTR)lpszaUnregister);
2695 HeapFree(GetProcessHeap(),0,lpszaReading);
2696 HeapFree(GetProcessHeap(),0,lpszaUnregister);
2697 return rc;
2700 else
2701 return FALSE;
2704 /***********************************************************************
2705 * ImmGetImeMenuItemsA (IMM32.@)
2707 DWORD WINAPI ImmGetImeMenuItemsA( HIMC hIMC, DWORD dwFlags, DWORD dwType,
2708 LPIMEMENUITEMINFOA lpImeParentMenu, LPIMEMENUITEMINFOA lpImeMenu,
2709 DWORD dwSize)
2711 InputContextData *data = get_imc_data(hIMC);
2712 TRACE("(%p, %li, %li, %p, %p, %li):\n", hIMC, dwFlags, dwType,
2713 lpImeParentMenu, lpImeMenu, dwSize);
2715 if (!data)
2717 SetLastError(ERROR_INVALID_HANDLE);
2718 return 0;
2721 if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
2723 if (!is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
2724 return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2725 (IMEMENUITEMINFOW*)lpImeParentMenu,
2726 (IMEMENUITEMINFOW*)lpImeMenu, dwSize);
2727 else
2729 IMEMENUITEMINFOW lpImeParentMenuW;
2730 IMEMENUITEMINFOW *lpImeMenuW, *parent = NULL;
2731 DWORD rc;
2733 if (lpImeParentMenu)
2734 parent = &lpImeParentMenuW;
2735 if (lpImeMenu)
2737 int count = dwSize / sizeof(LPIMEMENUITEMINFOA);
2738 dwSize = count * sizeof(IMEMENUITEMINFOW);
2739 lpImeMenuW = HeapAlloc(GetProcessHeap(), 0, dwSize);
2741 else
2742 lpImeMenuW = NULL;
2744 rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2745 parent, lpImeMenuW, dwSize);
2747 if (lpImeParentMenu)
2749 memcpy(lpImeParentMenu,&lpImeParentMenuW,sizeof(IMEMENUITEMINFOA));
2750 lpImeParentMenu->hbmpItem = lpImeParentMenuW.hbmpItem;
2751 WideCharToMultiByte(CP_ACP, 0, lpImeParentMenuW.szString,
2752 -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE,
2753 NULL, NULL);
2755 if (lpImeMenu && rc)
2757 unsigned int i;
2758 for (i = 0; i < rc; i++)
2760 memcpy(&lpImeMenu[i],&lpImeMenuW[1],sizeof(IMEMENUITEMINFOA));
2761 lpImeMenu[i].hbmpItem = lpImeMenuW[i].hbmpItem;
2762 WideCharToMultiByte(CP_ACP, 0, lpImeMenuW[i].szString,
2763 -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE,
2764 NULL, NULL);
2767 HeapFree(GetProcessHeap(),0,lpImeMenuW);
2768 return rc;
2771 else
2772 return 0;
2775 /***********************************************************************
2776 * ImmGetImeMenuItemsW (IMM32.@)
2778 DWORD WINAPI ImmGetImeMenuItemsW( HIMC hIMC, DWORD dwFlags, DWORD dwType,
2779 LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu,
2780 DWORD dwSize)
2782 InputContextData *data = get_imc_data(hIMC);
2783 TRACE("(%p, %li, %li, %p, %p, %li):\n", hIMC, dwFlags, dwType,
2784 lpImeParentMenu, lpImeMenu, dwSize);
2786 if (!data)
2788 SetLastError(ERROR_INVALID_HANDLE);
2789 return 0;
2792 if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
2794 if (is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
2795 return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2796 lpImeParentMenu, lpImeMenu, dwSize);
2797 else
2799 IMEMENUITEMINFOA lpImeParentMenuA;
2800 IMEMENUITEMINFOA *lpImeMenuA, *parent = NULL;
2801 DWORD rc;
2803 if (lpImeParentMenu)
2804 parent = &lpImeParentMenuA;
2805 if (lpImeMenu)
2807 int count = dwSize / sizeof(LPIMEMENUITEMINFOW);
2808 dwSize = count * sizeof(IMEMENUITEMINFOA);
2809 lpImeMenuA = HeapAlloc(GetProcessHeap(), 0, dwSize);
2811 else
2812 lpImeMenuA = NULL;
2814 rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2815 (IMEMENUITEMINFOW*)parent,
2816 (IMEMENUITEMINFOW*)lpImeMenuA, dwSize);
2818 if (lpImeParentMenu)
2820 memcpy(lpImeParentMenu,&lpImeParentMenuA,sizeof(IMEMENUITEMINFOA));
2821 lpImeParentMenu->hbmpItem = lpImeParentMenuA.hbmpItem;
2822 MultiByteToWideChar(CP_ACP, 0, lpImeParentMenuA.szString,
2823 -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE);
2825 if (lpImeMenu && rc)
2827 unsigned int i;
2828 for (i = 0; i < rc; i++)
2830 memcpy(&lpImeMenu[i],&lpImeMenuA[1],sizeof(IMEMENUITEMINFOA));
2831 lpImeMenu[i].hbmpItem = lpImeMenuA[i].hbmpItem;
2832 MultiByteToWideChar(CP_ACP, 0, lpImeMenuA[i].szString,
2833 -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE);
2836 HeapFree(GetProcessHeap(),0,lpImeMenuA);
2837 return rc;
2840 else
2841 return 0;
2844 /***********************************************************************
2845 * ImmLockIMC(IMM32.@)
2847 LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC)
2849 InputContextData *data = get_imc_data(hIMC);
2851 if (!data)
2852 return NULL;
2853 data->dwLock++;
2854 return &data->IMC;
2857 /***********************************************************************
2858 * ImmUnlockIMC(IMM32.@)
2860 BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
2862 InputContextData *data = get_imc_data(hIMC);
2864 if (!data)
2865 return FALSE;
2866 if (data->dwLock)
2867 data->dwLock--;
2868 return TRUE;
2871 /***********************************************************************
2872 * ImmGetIMCLockCount(IMM32.@)
2874 DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC)
2876 InputContextData *data = get_imc_data(hIMC);
2877 if (!data)
2878 return 0;
2879 return data->dwLock;
2882 /***********************************************************************
2883 * ImmCreateIMCC(IMM32.@)
2885 HIMCC WINAPI ImmCreateIMCC(DWORD size)
2887 return GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE, size);
2890 /***********************************************************************
2891 * ImmDestroyIMCC(IMM32.@)
2893 HIMCC WINAPI ImmDestroyIMCC(HIMCC block)
2895 return GlobalFree(block);
2898 /***********************************************************************
2899 * ImmLockIMCC(IMM32.@)
2901 LPVOID WINAPI ImmLockIMCC(HIMCC imcc)
2903 return GlobalLock(imcc);
2906 /***********************************************************************
2907 * ImmUnlockIMCC(IMM32.@)
2909 BOOL WINAPI ImmUnlockIMCC(HIMCC imcc)
2911 return GlobalUnlock(imcc);
2914 /***********************************************************************
2915 * ImmGetIMCCLockCount(IMM32.@)
2917 DWORD WINAPI ImmGetIMCCLockCount(HIMCC imcc)
2919 return GlobalFlags(imcc) & GMEM_LOCKCOUNT;
2922 /***********************************************************************
2923 * ImmReSizeIMCC(IMM32.@)
2925 HIMCC WINAPI ImmReSizeIMCC(HIMCC imcc, DWORD size)
2927 return GlobalReAlloc(imcc, size, GMEM_ZEROINIT | GMEM_MOVEABLE);
2930 /***********************************************************************
2931 * ImmGetIMCCSize(IMM32.@)
2933 DWORD WINAPI ImmGetIMCCSize(HIMCC imcc)
2935 return GlobalSize(imcc);
2938 /***********************************************************************
2939 * ImmGenerateMessage(IMM32.@)
2941 BOOL WINAPI ImmGenerateMessage(HIMC hIMC)
2943 InputContextData *data = get_imc_data(hIMC);
2945 if (!data)
2947 SetLastError(ERROR_INVALID_HANDLE);
2948 return FALSE;
2951 TRACE("%li messages queued\n",data->IMC.dwNumMsgBuf);
2952 if (data->IMC.dwNumMsgBuf > 0)
2954 LPTRANSMSG lpTransMsg;
2955 HIMCC hMsgBuf;
2956 DWORD i, dwNumMsgBuf;
2958 /* We are going to detach our hMsgBuff so that if processing messages
2959 generates new messages they go into a new buffer */
2960 hMsgBuf = data->IMC.hMsgBuf;
2961 dwNumMsgBuf = data->IMC.dwNumMsgBuf;
2963 data->IMC.hMsgBuf = ImmCreateIMCC(0);
2964 data->IMC.dwNumMsgBuf = 0;
2966 lpTransMsg = ImmLockIMCC(hMsgBuf);
2967 for (i = 0; i < dwNumMsgBuf; i++)
2968 ImmInternalSendIMEMessage(data, lpTransMsg[i].message, lpTransMsg[i].wParam, lpTransMsg[i].lParam);
2970 ImmUnlockIMCC(hMsgBuf);
2971 ImmDestroyIMCC(hMsgBuf);
2974 return TRUE;
2977 /***********************************************************************
2978 * ImmTranslateMessage(IMM32.@)
2979 * ( Undocumented, call internally and from user32.dll )
2981 BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyData)
2983 InputContextData *data;
2984 HIMC imc = ImmGetContext(hwnd);
2985 BYTE state[256];
2986 UINT scancode;
2987 LPVOID list = 0;
2988 UINT msg_count;
2989 UINT uVirtKey;
2990 static const DWORD list_count = 10;
2992 TRACE("%p %x %x %x\n",hwnd, msg, (UINT)wParam, (UINT)lKeyData);
2994 if (!(data = get_imc_data( imc ))) return FALSE;
2996 if (!data->immKbd->hIME || !data->immKbd->pImeToAsciiEx || data->lastVK == VK_PROCESSKEY)
2997 return FALSE;
2999 GetKeyboardState(state);
3000 scancode = lKeyData >> 0x10 & 0xff;
3002 list = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, list_count * sizeof(TRANSMSG) + sizeof(DWORD));
3003 ((DWORD*)list)[0] = list_count;
3005 if (data->immKbd->imeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST)
3007 WCHAR chr;
3009 if (!is_himc_ime_unicode(data))
3010 ToAscii(data->lastVK, scancode, state, &chr, 0);
3011 else
3012 ToUnicodeEx(data->lastVK, scancode, state, &chr, 1, 0, GetKeyboardLayout(0));
3013 uVirtKey = MAKELONG(data->lastVK,chr);
3015 else
3016 uVirtKey = data->lastVK;
3018 msg_count = data->immKbd->pImeToAsciiEx(uVirtKey, scancode, state, list, 0, imc);
3019 TRACE("%i messages generated\n",msg_count);
3020 if (msg_count && msg_count <= list_count)
3022 UINT i;
3023 LPTRANSMSG msgs = (LPTRANSMSG)((LPBYTE)list + sizeof(DWORD));
3025 for (i = 0; i < msg_count; i++)
3026 ImmInternalPostIMEMessage(data, msgs[i].message, msgs[i].wParam, msgs[i].lParam);
3028 else if (msg_count > list_count)
3029 ImmGenerateMessage(imc);
3031 HeapFree(GetProcessHeap(),0,list);
3033 data->lastVK = VK_PROCESSKEY;
3035 return (msg_count > 0);
3038 /***********************************************************************
3039 * ImmProcessKey(IMM32.@)
3040 * ( Undocumented, called from user32.dll )
3042 BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD unknown)
3044 InputContextData *data;
3045 HIMC imc = ImmGetContext(hwnd);
3046 BYTE state[256];
3048 TRACE("%p %p %x %x %lx\n",hwnd, hKL, vKey, (UINT)lKeyData, unknown);
3050 if (!(data = get_imc_data( imc ))) return FALSE;
3052 /* Make sure we are inputting to the correct keyboard */
3053 if (data->immKbd->hkl != hKL)
3055 ImmHkl *new_hkl = IMM_GetImmHkl(hKL);
3056 if (new_hkl)
3058 data->immKbd->pImeSelect(imc, FALSE);
3059 data->immKbd->uSelected--;
3060 data->immKbd = new_hkl;
3061 data->immKbd->pImeSelect(imc, TRUE);
3062 data->immKbd->uSelected++;
3064 else
3065 return FALSE;
3068 if (!data->immKbd->hIME || !data->immKbd->pImeProcessKey)
3069 return FALSE;
3071 GetKeyboardState(state);
3072 if (data->immKbd->pImeProcessKey(imc, vKey, lKeyData, state))
3074 data->lastVK = vKey;
3075 return TRUE;
3078 data->lastVK = VK_PROCESSKEY;
3079 return FALSE;
3082 /***********************************************************************
3083 * ImmDisableTextFrameService(IMM32.@)
3085 BOOL WINAPI ImmDisableTextFrameService(DWORD idThread)
3087 FIXME("Stub\n");
3088 return FALSE;
3091 /***********************************************************************
3092 * ImmEnumInputContext(IMM32.@)
3095 BOOL WINAPI ImmEnumInputContext(DWORD idThread, IMCENUMPROC lpfn, LPARAM lParam)
3097 FIXME("Stub\n");
3098 return FALSE;
3101 /***********************************************************************
3102 * ImmGetHotKey(IMM32.@)
3105 BOOL WINAPI ImmGetHotKey(DWORD hotkey, UINT *modifiers, UINT *key, HKL hkl)
3107 FIXME("%lx, %p, %p, %p: stub\n", hotkey, modifiers, key, hkl);
3108 return FALSE;
3111 /***********************************************************************
3112 * ImmDisableLegacyIME(IMM32.@)
3114 BOOL WINAPI ImmDisableLegacyIME(void)
3116 FIXME("stub\n");
3117 return TRUE;
3120 static HWND get_ui_window(HKL hkl)
3122 ImmHkl *immHkl = IMM_GetImmHkl(hkl);
3123 return immHkl->UIWnd;
3126 static BOOL is_ime_ui_msg(UINT msg)
3128 switch (msg)
3130 case WM_IME_STARTCOMPOSITION:
3131 case WM_IME_ENDCOMPOSITION:
3132 case WM_IME_COMPOSITION:
3133 case WM_IME_SETCONTEXT:
3134 case WM_IME_NOTIFY:
3135 case WM_IME_CONTROL:
3136 case WM_IME_COMPOSITIONFULL:
3137 case WM_IME_SELECT:
3138 case WM_IME_CHAR:
3139 case WM_IME_REQUEST:
3140 case WM_IME_KEYDOWN:
3141 case WM_IME_KEYUP:
3142 return TRUE;
3143 default:
3144 return msg == WM_MSIME_RECONVERTOPTIONS ||
3145 msg == WM_MSIME_SERVICE ||
3146 msg == WM_MSIME_MOUSE ||
3147 msg == WM_MSIME_RECONVERTREQUEST ||
3148 msg == WM_MSIME_RECONVERT ||
3149 msg == WM_MSIME_QUERYPOSITION ||
3150 msg == WM_MSIME_DOCUMENTFEED;
3154 static LRESULT ime_internal_msg( WPARAM wparam, LPARAM lparam)
3156 HWND hwnd = (HWND)lparam;
3157 HIMC himc;
3159 switch (wparam)
3161 case IME_INTERNAL_ACTIVATE:
3162 case IME_INTERNAL_DEACTIVATE:
3163 himc = ImmGetContext(hwnd);
3164 ImmSetActiveContext(hwnd, himc, wparam == IME_INTERNAL_ACTIVATE);
3165 ImmReleaseContext(hwnd, himc);
3166 break;
3167 default:
3168 FIXME("wparam = %Ix\n", wparam);
3169 break;
3172 return 0;
3175 static void init_messages(void)
3177 static BOOL initialized;
3179 if (initialized) return;
3181 WM_MSIME_SERVICE = RegisterWindowMessageW(L"MSIMEService");
3182 WM_MSIME_RECONVERTOPTIONS = RegisterWindowMessageW(L"MSIMEReconvertOptions");
3183 WM_MSIME_MOUSE = RegisterWindowMessageW(L"MSIMEMouseOperation");
3184 WM_MSIME_RECONVERTREQUEST = RegisterWindowMessageW(L"MSIMEReconvertRequest");
3185 WM_MSIME_RECONVERT = RegisterWindowMessageW(L"MSIMEReconvert");
3186 WM_MSIME_QUERYPOSITION = RegisterWindowMessageW(L"MSIMEQueryPosition");
3187 WM_MSIME_DOCUMENTFEED = RegisterWindowMessageW(L"MSIMEDocumentFeed");
3188 initialized = TRUE;
3191 LRESULT WINAPI __wine_ime_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, BOOL ansi)
3193 HWND uiwnd;
3195 switch (msg)
3197 case WM_CREATE:
3198 init_messages();
3199 return TRUE;
3201 case WM_DESTROY:
3203 HWND default_hwnd = ImmGetDefaultIMEWnd(0);
3204 if (!default_hwnd || hwnd == default_hwnd)
3205 imm_couninit_thread(TRUE);
3207 return TRUE;
3209 case WM_IME_INTERNAL:
3210 return ime_internal_msg(wparam, lparam);
3213 if (is_ime_ui_msg(msg))
3215 if ((uiwnd = get_ui_window(NtUserGetKeyboardLayout(0))))
3217 if (ansi)
3218 return SendMessageA(uiwnd, msg, wparam, lparam);
3219 else
3220 return SendMessageW(uiwnd, msg, wparam, lparam);
3222 return FALSE;
3225 if (ansi)
3226 return DefWindowProcA(hwnd, msg, wparam, lparam);
3227 else
3228 return DefWindowProcW(hwnd, msg, wparam, lparam);