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
24 #include "imm_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(imm
);
28 #define IMM_INIT_MAGIC 0x19650412
29 BOOL WINAPI
User32InitializeImmEntryTable(DWORD
);
34 UINT WM_MSIME_SERVICE
;
35 UINT WM_MSIME_RECONVERTOPTIONS
;
37 UINT WM_MSIME_RECONVERTREQUEST
;
38 UINT WM_MSIME_RECONVERT
;
39 UINT WM_MSIME_QUERYPOSITION
;
40 UINT WM_MSIME_DOCUMENTFEED
;
51 LONG refcount
; /* guarded by ime_cs */
59 struct list input_contexts
;
61 BOOL (WINAPI
*pImeInquire
)(IMEINFO
*, void *, DWORD
);
62 BOOL (WINAPI
*pImeConfigure
)(HKL
, HWND
, DWORD
, void *);
63 BOOL (WINAPI
*pImeDestroy
)(UINT
);
64 LRESULT (WINAPI
*pImeEscape
)(HIMC
, UINT
, void *);
65 BOOL (WINAPI
*pImeSelect
)(HIMC
, BOOL
);
66 BOOL (WINAPI
*pImeSetActiveContext
)(HIMC
, BOOL
);
67 UINT (WINAPI
*pImeToAsciiEx
)(UINT
, UINT
, const BYTE
*, TRANSMSGLIST
*, UINT
, HIMC
);
68 BOOL (WINAPI
*pNotifyIME
)(HIMC
, DWORD
, DWORD
, DWORD
);
69 BOOL (WINAPI
*pImeRegisterWord
)(const void/*TCHAR*/*, DWORD
, const void/*TCHAR*/*);
70 BOOL (WINAPI
*pImeUnregisterWord
)(const void/*TCHAR*/*, DWORD
, const void/*TCHAR*/*);
71 UINT (WINAPI
*pImeEnumRegisterWord
)(void */
*REGISTERWORDENUMPROCW*/
, const void/*TCHAR*/*, DWORD
, const void/*TCHAR*/*, void *);
72 BOOL (WINAPI
*pImeSetCompositionString
)(HIMC
, DWORD
, const void/*TCHAR*/*, DWORD
, const void/*TCHAR*/*, DWORD
);
73 DWORD (WINAPI
*pImeConversionList
)(HIMC
, const void/*TCHAR*/*, CANDIDATELIST
*, DWORD
, UINT
);
74 UINT (WINAPI
*pImeGetRegisterWordStyle
)(UINT
, void/*STYLEBUFW*/*);
75 BOOL (WINAPI
*pImeProcessKey
)(HIMC
, UINT
, LPARAM
, const BYTE
*);
76 DWORD (WINAPI
*pImeGetImeMenuItems
)(HIMC
, DWORD
, DWORD
, void/*IMEMENUITEMINFOW*/*, void/*IMEMENUITEMINFOW*/*, DWORD
);
79 static HRESULT (WINAPI
*pCoRevokeInitializeSpy
)(ULARGE_INTEGER cookie
);
80 static void (WINAPI
*pCoUninitialize
)(void);
91 HWND ui_hwnd
; /* IME UI window, on the default input context */
94 #define WINE_IMC_VALID_MAGIC 0x56434D49
98 IInitializeSpy IInitializeSpy_iface
;
100 ULARGE_INTEGER cookie
;
104 IMM_APT_CREATED
= 0x2,
105 IMM_APT_CAN_FREE
= 0x4,
110 static CRITICAL_SECTION ime_cs
;
111 static CRITICAL_SECTION_DEBUG ime_cs_debug
=
114 { &ime_cs_debug
.ProcessLocksList
, &ime_cs_debug
.ProcessLocksList
},
115 0, 0, { (DWORD_PTR
)(__FILE__
": ime_cs") }
117 static CRITICAL_SECTION ime_cs
= { &ime_cs_debug
, -1, 0, 0, 0, 0 };
118 static struct list ime_list
= LIST_INIT( ime_list
);
120 static const WCHAR layouts_formatW
[] = L
"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08lx";
122 static const char *debugstr_composition( const COMPOSITIONFORM
*composition
)
124 if (!composition
) return "(null)";
125 return wine_dbg_sprintf( "style %#lx, pos %s, area %s", composition
->dwStyle
,
126 wine_dbgstr_point( &composition
->ptCurrentPos
),
127 wine_dbgstr_rect( &composition
->rcArea
) );
130 static const char *debugstr_candidate( const CANDIDATEFORM
*candidate
)
132 if (!candidate
) return "(null)";
133 return wine_dbg_sprintf( "idx %#lx, style %#lx, pos %s, area %s", candidate
->dwIndex
,
134 candidate
->dwStyle
, wine_dbgstr_point( &candidate
->ptCurrentPos
),
135 wine_dbgstr_rect( &candidate
->rcArea
) );
138 static BOOL
ime_is_unicode( const struct ime
*ime
)
140 return !!(ime
->info
.fdwProperty
& IME_PROP_UNICODE
);
143 static BOOL
input_context_is_unicode( INPUTCONTEXT
*ctx
)
145 struct imc
*imc
= CONTAINING_RECORD( ctx
, struct imc
, IMC
);
146 return !imc
->ime
|| ime_is_unicode( imc
->ime
);
149 static BOOL
IMM_DestroyContext(HIMC hIMC
);
150 static struct imc
*get_imc_data( HIMC hIMC
);
152 static inline WCHAR
*strdupAtoW( const char *str
)
157 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
158 if ((ret
= malloc( len
* sizeof(WCHAR
) ))) MultiByteToWideChar( CP_ACP
, 0, str
, -1, ret
, len
);
163 static inline CHAR
*strdupWtoA( const WCHAR
*str
)
168 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
169 if ((ret
= malloc( len
))) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
174 static DWORD
convert_candidatelist_WtoA(
175 LPCANDIDATELIST lpSrc
, LPCANDIDATELIST lpDst
, DWORD dwBufLen
)
179 ret
= FIELD_OFFSET( CANDIDATELIST
, dwOffset
[lpSrc
->dwCount
] );
180 if ( lpDst
&& dwBufLen
> 0 )
183 lpDst
->dwOffset
[0] = ret
;
186 for ( i
= 0; i
< lpSrc
->dwCount
; i
++)
188 LPBYTE src
= (LPBYTE
)lpSrc
+ lpSrc
->dwOffset
[i
];
190 if ( lpDst
&& dwBufLen
> 0 )
192 LPBYTE dest
= (LPBYTE
)lpDst
+ lpDst
->dwOffset
[i
];
194 len
= WideCharToMultiByte(CP_ACP
, 0, (LPCWSTR
)src
, -1,
195 (LPSTR
)dest
, dwBufLen
, NULL
, NULL
);
197 if ( i
+ 1 < lpSrc
->dwCount
)
198 lpDst
->dwOffset
[i
+1] = lpDst
->dwOffset
[i
] + len
* sizeof(char);
199 dwBufLen
-= len
* sizeof(char);
202 len
= WideCharToMultiByte(CP_ACP
, 0, (LPCWSTR
)src
, -1, NULL
, 0, NULL
, NULL
);
204 ret
+= len
* sizeof(char);
213 static DWORD
convert_candidatelist_AtoW(
214 LPCANDIDATELIST lpSrc
, LPCANDIDATELIST lpDst
, DWORD dwBufLen
)
218 ret
= FIELD_OFFSET( CANDIDATELIST
, dwOffset
[lpSrc
->dwCount
] );
219 if ( lpDst
&& dwBufLen
> 0 )
222 lpDst
->dwOffset
[0] = ret
;
225 for ( i
= 0; i
< lpSrc
->dwCount
; i
++)
227 LPBYTE src
= (LPBYTE
)lpSrc
+ lpSrc
->dwOffset
[i
];
229 if ( lpDst
&& dwBufLen
> 0 )
231 LPBYTE dest
= (LPBYTE
)lpDst
+ lpDst
->dwOffset
[i
];
233 len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)src
, -1,
234 (LPWSTR
)dest
, dwBufLen
);
236 if ( i
+ 1 < lpSrc
->dwCount
)
237 lpDst
->dwOffset
[i
+1] = lpDst
->dwOffset
[i
] + len
* sizeof(WCHAR
);
238 dwBufLen
-= len
* sizeof(WCHAR
);
241 len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)src
, -1, NULL
, 0);
243 ret
+= len
* sizeof(WCHAR
);
252 static struct coinit_spy
*get_thread_coinit_spy(void)
254 return (struct coinit_spy
*)(UINT_PTR
)NtUserGetThreadInfo()->client_imm
;
257 static void imm_couninit_thread(BOOL cleanup
)
259 struct coinit_spy
*spy
;
261 TRACE("implicit COM deinitialization\n");
263 if (!(spy
= get_thread_coinit_spy()) || (spy
->apt_flags
& IMM_APT_BROKEN
))
266 if (cleanup
&& spy
->cookie
.QuadPart
)
268 pCoRevokeInitializeSpy(spy
->cookie
);
269 spy
->cookie
.QuadPart
= 0;
272 if (!(spy
->apt_flags
& IMM_APT_INIT
))
274 spy
->apt_flags
&= ~IMM_APT_INIT
;
276 if (spy
->apt_flags
& IMM_APT_CREATED
)
278 spy
->apt_flags
&= ~IMM_APT_CREATED
;
279 if (spy
->apt_flags
& IMM_APT_CAN_FREE
)
286 static inline struct coinit_spy
*impl_from_IInitializeSpy(IInitializeSpy
*iface
)
288 return CONTAINING_RECORD(iface
, struct coinit_spy
, IInitializeSpy_iface
);
291 static HRESULT WINAPI
InitializeSpy_QueryInterface(IInitializeSpy
*iface
, REFIID riid
, void **obj
)
293 if (IsEqualIID(&IID_IInitializeSpy
, riid
) ||
294 IsEqualIID(&IID_IUnknown
, riid
))
297 IInitializeSpy_AddRef(iface
);
302 return E_NOINTERFACE
;
305 static ULONG WINAPI
InitializeSpy_AddRef(IInitializeSpy
*iface
)
307 struct coinit_spy
*spy
= impl_from_IInitializeSpy(iface
);
308 return InterlockedIncrement(&spy
->ref
);
311 static ULONG WINAPI
InitializeSpy_Release(IInitializeSpy
*iface
)
313 struct coinit_spy
*spy
= impl_from_IInitializeSpy(iface
);
314 LONG ref
= InterlockedDecrement(&spy
->ref
);
318 NtUserGetThreadInfo()->client_imm
= 0;
323 static HRESULT WINAPI
InitializeSpy_PreInitialize(IInitializeSpy
*iface
,
324 DWORD coinit
, DWORD refs
)
326 struct coinit_spy
*spy
= impl_from_IInitializeSpy(iface
);
328 if ((spy
->apt_flags
& IMM_APT_CREATED
) &&
329 !(coinit
& COINIT_APARTMENTTHREADED
) && refs
== 1)
331 imm_couninit_thread(TRUE
);
332 spy
->apt_flags
|= IMM_APT_BROKEN
;
337 static HRESULT WINAPI
InitializeSpy_PostInitialize(IInitializeSpy
*iface
,
338 HRESULT hr
, DWORD coinit
, DWORD refs
)
340 struct coinit_spy
*spy
= impl_from_IInitializeSpy(iface
);
342 if ((spy
->apt_flags
& IMM_APT_CREATED
) && hr
== S_FALSE
&& refs
== 2)
345 spy
->apt_flags
|= IMM_APT_CAN_FREE
;
349 static HRESULT WINAPI
InitializeSpy_PreUninitialize(IInitializeSpy
*iface
, DWORD refs
)
354 static HRESULT WINAPI
InitializeSpy_PostUninitialize(IInitializeSpy
*iface
, DWORD refs
)
356 struct coinit_spy
*spy
= impl_from_IInitializeSpy(iface
);
358 TRACE("%lu %p\n", refs
, ImmGetDefaultIMEWnd(0));
360 if (refs
== 1 && !ImmGetDefaultIMEWnd(0))
361 imm_couninit_thread(FALSE
);
363 spy
->apt_flags
&= ~IMM_APT_CAN_FREE
;
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 BOOL WINAPI
init_ole32_funcs( INIT_ONCE
*once
, void *param
, void **context
)
380 HMODULE module_ole32
= GetModuleHandleA("ole32");
381 pCoRevokeInitializeSpy
= (void*)GetProcAddress(module_ole32
, "CoRevokeInitializeSpy");
382 pCoUninitialize
= (void*)GetProcAddress(module_ole32
, "CoUninitialize");
386 static void imm_coinit_thread(void)
388 struct coinit_spy
*spy
;
390 static INIT_ONCE init_ole32_once
= INIT_ONCE_STATIC_INIT
;
392 TRACE("implicit COM initialization\n");
394 if (!(spy
= get_thread_coinit_spy()))
396 if (!(spy
= malloc( sizeof(*spy
) ))) return;
397 spy
->IInitializeSpy_iface
.lpVtbl
= &InitializeSpyVtbl
;
399 spy
->cookie
.QuadPart
= 0;
401 NtUserGetThreadInfo()->client_imm
= (UINT_PTR
)spy
;
405 if (spy
->apt_flags
& (IMM_APT_INIT
| IMM_APT_BROKEN
))
407 spy
->apt_flags
|= IMM_APT_INIT
;
409 if(!spy
->cookie
.QuadPart
)
411 hr
= CoRegisterInitializeSpy(&spy
->IInitializeSpy_iface
, &spy
->cookie
);
416 hr
= CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
);
418 spy
->apt_flags
|= IMM_APT_CREATED
;
420 InitOnceExecuteOnce(&init_ole32_once
, init_ole32_funcs
, NULL
, NULL
);
423 static struct imc
*query_imc_data( HIMC handle
)
427 if (!handle
) return NULL
;
428 ret
= (void *)NtUserQueryInputContext(handle
, NtUserInputContextClientPtr
);
429 return ret
&& ret
->handle
== handle
? ret
: NULL
;
432 static HMODULE
load_graphics_driver(void)
434 static const WCHAR key_pathW
[] = L
"System\\CurrentControlSet\\Control\\Video\\{";
435 static const WCHAR displayW
[] = L
"}\\0000";
440 WCHAR path
[MAX_PATH
];
441 WCHAR key
[ARRAY_SIZE( key_pathW
) + ARRAY_SIZE( displayW
) + 40];
442 UINT guid_atom
= HandleToULong( GetPropW( GetDesktopWindow(), L
"__wine_display_device_guid" ));
444 if (!guid_atom
) return 0;
445 memcpy( key
, key_pathW
, sizeof(key_pathW
) );
446 if (!GlobalGetAtomNameW( guid_atom
, key
+ lstrlenW(key
), 40 )) return 0;
447 lstrcatW( key
, displayW
);
448 if (RegOpenKeyW( HKEY_LOCAL_MACHINE
, key
, &hkey
)) return 0;
450 if (!RegQueryValueExW( hkey
, L
"GraphicsDriver", NULL
, NULL
, (BYTE
*)path
, &size
))
451 ret
= LoadLibraryW( path
);
453 TRACE( "%s %p\n", debugstr_w(path
), ret
);
457 /* lookup an IME from a HKL, must hold ime_cs */
458 static struct ime
*find_ime_from_hkl( HKL hkl
)
460 struct ime
*ime
= NULL
;
461 LIST_FOR_EACH_ENTRY( ime
, &ime_list
, struct ime
, entry
)
462 if (ime
->hkl
== hkl
) return ime
;
466 BOOL WINAPI
ImmFreeLayout( HKL hkl
)
468 struct imc_entry
*imc_entry
, *imc_next
;
471 TRACE( "hkl %p\n", hkl
);
473 EnterCriticalSection( &ime_cs
);
474 if ((ime
= find_ime_from_hkl( hkl
)))
476 list_remove( &ime
->entry
);
477 if (!ime
->pImeDestroy( 0 )) WARN( "ImeDestroy failed\n" );
478 LIST_FOR_EACH_ENTRY_SAFE( imc_entry
, imc_next
, &ime
->input_contexts
, struct imc_entry
, entry
)
480 ImmDestroyIMCC( imc_entry
->context
.hPrivate
);
484 LeaveCriticalSection( &ime_cs
);
485 if (!ime
) return TRUE
;
487 FreeLibrary( ime
->module
);
492 BOOL WINAPI
ImmLoadIME( HKL hkl
)
494 WCHAR buffer
[MAX_PATH
] = {0};
495 BOOL use_default_ime
;
498 TRACE( "hkl %p\n", hkl
);
500 EnterCriticalSection( &ime_cs
);
501 if ((ime
= find_ime_from_hkl( hkl
)) || !(ime
= calloc( 1, sizeof(*ime
) )))
503 LeaveCriticalSection( &ime_cs
);
507 if (!ImmGetIMEFileNameW( hkl
, buffer
, MAX_PATH
)) use_default_ime
= TRUE
;
508 else if (!(ime
->module
= LoadLibraryW( buffer
))) use_default_ime
= TRUE
;
509 else use_default_ime
= FALSE
;
513 if (*buffer
) WARN( "Failed to load %s, falling back to default.\n", debugstr_w(buffer
) );
514 if (!(ime
->module
= load_graphics_driver())) ime
->module
= LoadLibraryW( L
"imm32" );
517 #define LOAD_FUNCPTR( f ) \
518 if (!(ime->p##f = (void *)GetProcAddress( ime->module, #f )) && \
519 !(ime->p##f = use_default_ime ? (void *)f : NULL)) \
521 LeaveCriticalSection( &ime_cs ); \
522 WARN( "Can't find function %s in HKL %p IME\n", #f, hkl ); \
525 LOAD_FUNCPTR( ImeInquire
);
526 LOAD_FUNCPTR( ImeDestroy
);
527 LOAD_FUNCPTR( ImeSelect
);
528 LOAD_FUNCPTR( ImeConfigure
);
529 LOAD_FUNCPTR( ImeEscape
);
530 LOAD_FUNCPTR( ImeSetActiveContext
);
531 LOAD_FUNCPTR( ImeToAsciiEx
);
532 LOAD_FUNCPTR( NotifyIME
);
533 LOAD_FUNCPTR( ImeRegisterWord
);
534 LOAD_FUNCPTR( ImeUnregisterWord
);
535 LOAD_FUNCPTR( ImeEnumRegisterWord
);
536 LOAD_FUNCPTR( ImeSetCompositionString
);
537 LOAD_FUNCPTR( ImeConversionList
);
538 LOAD_FUNCPTR( ImeProcessKey
);
539 LOAD_FUNCPTR( ImeGetRegisterWordStyle
);
540 LOAD_FUNCPTR( ImeGetImeMenuItems
);
544 if (!ime
->pImeInquire( &ime
->info
, buffer
, 0 ))
546 LeaveCriticalSection( &ime_cs
);
550 if (ime_is_unicode( ime
)) lstrcpynW( ime
->ui_class
, buffer
, ARRAY_SIZE(ime
->ui_class
) );
551 else MultiByteToWideChar( CP_ACP
, 0, (char *)buffer
, -1, ime
->ui_class
, ARRAY_SIZE(ime
->ui_class
) );
552 list_init( &ime
->input_contexts
);
554 list_add_tail( &ime_list
, &ime
->entry
);
555 LeaveCriticalSection( &ime_cs
);
557 TRACE( "Created IME %p for HKL %p\n", ime
, hkl
);
561 if (ime
->module
) FreeLibrary( ime
->module
);
566 static struct ime
*ime_acquire( HKL hkl
)
570 EnterCriticalSection( &ime_cs
);
572 if (!ImmLoadIME( hkl
)) ime
= NULL
;
573 else ime
= find_ime_from_hkl( hkl
);
577 ULONG ref
= ++ime
->refcount
;
578 TRACE( "ime %p increasing refcount to %lu.\n", ime
, ref
);
581 LeaveCriticalSection( &ime_cs
);
586 static void ime_release( struct ime
*ime
)
590 EnterCriticalSection( &ime_cs
);
592 ref
= --ime
->refcount
;
593 TRACE( "ime %p decreasing refcount to %lu.\n", ime
, ref
);
595 if (!ref
&& (ime
->info
.fdwProperty
& IME_PROP_END_UNLOAD
))
596 ImmFreeLayout( ime
->hkl
);
598 LeaveCriticalSection( &ime_cs
);
601 static void ime_save_input_context( struct ime
*ime
, HIMC himc
, INPUTCONTEXT
*ctx
)
603 static INPUTCONTEXT default_input_context
=
605 .cfCandForm
= {{.dwIndex
= -1}, {.dwIndex
= -1}, {.dwIndex
= -1}, {.dwIndex
= -1}}
607 const INPUTCONTEXT old
= *ctx
;
608 struct imc_entry
*entry
;
610 *ctx
= default_input_context
;
611 ctx
->hWnd
= old
.hWnd
;
612 ctx
->hMsgBuf
= old
.hMsgBuf
;
613 ctx
->hCompStr
= old
.hCompStr
;
614 ctx
->hCandInfo
= old
.hCandInfo
;
615 ctx
->hGuideLine
= old
.hGuideLine
;
616 if (!(ctx
->hPrivate
= ImmCreateIMCC( ime
->info
.dwPrivateDataSize
)))
617 WARN( "Failed to allocate IME private data\n" );
619 if (!(entry
= malloc( sizeof(*entry
) ))) return;
621 entry
->context
= *ctx
;
623 EnterCriticalSection( &ime_cs
);
625 /* reference the IME the first time the input context cache is used
626 * in the same way Windows does it, so it doesn't get destroyed and
627 * INPUTCONTEXT cache lost when keyboard layout is changed
629 if (list_empty( &ime
->input_contexts
)) ime
->refcount
++;
631 list_add_tail( &ime
->input_contexts
, &entry
->entry
);
632 LeaveCriticalSection( &ime_cs
);
635 static INPUTCONTEXT
*ime_find_input_context( struct ime
*ime
, HIMC himc
)
637 struct imc_entry
*entry
;
639 EnterCriticalSection( &ime_cs
);
640 LIST_FOR_EACH_ENTRY( entry
, &ime
->input_contexts
, struct imc_entry
, entry
)
641 if (entry
->himc
== himc
) break;
642 LeaveCriticalSection( &ime_cs
);
644 if (&entry
->entry
== &ime
->input_contexts
) return NULL
;
645 return &entry
->context
;
648 static void imc_release_ime( struct imc
*imc
, struct ime
*ime
)
652 if (imc
->ui_hwnd
) DestroyWindow( imc
->ui_hwnd
);
654 ime
->pImeSelect( imc
->handle
, FALSE
);
656 if ((ctx
= ime_find_input_context( ime
, imc
->handle
))) *ctx
= imc
->IMC
;
660 static struct ime
*imc_select_ime( struct imc
*imc
)
662 HKL hkl
= GetKeyboardLayout( 0 );
665 if ((ime
= imc
->ime
))
667 if (ime
->hkl
== hkl
) return ime
;
669 imc_release_ime( imc
, ime
);
672 if (!(imc
->ime
= ime_acquire( hkl
)))
673 WARN( "Failed to acquire IME for HKL %p\n", hkl
);
678 if ((ctx
= ime_find_input_context( imc
->ime
, imc
->handle
))) imc
->IMC
= *ctx
;
679 else ime_save_input_context( imc
->ime
, imc
->handle
, &imc
->IMC
);
681 imc
->ime
->pImeSelect( imc
->handle
, TRUE
);
687 static BOOL CALLBACK
enum_activate_layout( HIMC himc
, LPARAM lparam
)
689 if (ImmLockIMC( himc
)) ImmUnlockIMC( himc
);
693 BOOL WINAPI
ImmActivateLayout( HKL hkl
)
695 TRACE( "hkl %p\n", hkl
);
697 if (hkl
== GetKeyboardLayout( 0 )) return TRUE
;
698 if (!ActivateKeyboardLayout( hkl
, 0 )) return FALSE
;
700 ImmEnumInputContext( 0, enum_activate_layout
, 0 );
705 static BOOL
free_input_context_data( HIMC hIMC
)
707 struct imc
*data
= query_imc_data( hIMC
);
710 if (!data
) return FALSE
;
712 TRACE( "Destroying %p\n", hIMC
);
714 if ((ime
= imc_select_ime( data
))) imc_release_ime( data
, ime
);
716 ImmDestroyIMCC( data
->IMC
.hCompStr
);
717 ImmDestroyIMCC( data
->IMC
.hCandInfo
);
718 ImmDestroyIMCC( data
->IMC
.hGuideLine
);
719 ImmDestroyIMCC( data
->IMC
.hMsgBuf
);
726 static void input_context_init( INPUTCONTEXT
*ctx
)
728 COMPOSITIONSTRING
*str
;
733 if (!(ctx
->hMsgBuf
= ImmCreateIMCC( 0 )))
734 WARN( "Failed to allocate %p message buffer\n", ctx
);
736 if (!(ctx
->hCompStr
= ImmCreateIMCC( sizeof(COMPOSITIONSTRING
) )))
737 WARN( "Failed to allocate %p COMPOSITIONSTRING\n", ctx
);
738 else if (!(str
= ImmLockIMCC( ctx
->hCompStr
)))
739 WARN( "Failed to lock IMCC for COMPOSITIONSTRING\n" );
742 str
->dwSize
= sizeof(COMPOSITIONSTRING
);
743 ImmUnlockIMCC( ctx
->hCompStr
);
746 if (!(ctx
->hCandInfo
= ImmCreateIMCC( sizeof(CANDIDATEINFO
) )))
747 WARN( "Failed to allocate %p CANDIDATEINFO\n", ctx
);
748 else if (!(info
= ImmLockIMCC( ctx
->hCandInfo
)))
749 WARN( "Failed to lock IMCC for CANDIDATEINFO\n" );
752 info
->dwSize
= sizeof(CANDIDATEINFO
);
753 ImmUnlockIMCC( ctx
->hCandInfo
);
756 if (!(ctx
->hGuideLine
= ImmCreateIMCC( sizeof(GUIDELINE
) )))
757 WARN( "Failed to allocate %p GUIDELINE\n", ctx
);
758 else if (!(line
= ImmLockIMCC( ctx
->hGuideLine
)))
759 WARN( "Failed to lock IMCC for GUIDELINE\n" );
762 line
->dwSize
= sizeof(GUIDELINE
);
763 ImmUnlockIMCC( ctx
->hGuideLine
);
766 for (i
= 0; i
< ARRAY_SIZE(ctx
->cfCandForm
); i
++)
767 ctx
->cfCandForm
[i
].dwIndex
= ~0u;
770 static void IMM_FreeThreadData(void)
772 struct coinit_spy
*spy
;
774 free_input_context_data( UlongToHandle( NtUserGetThreadInfo()->default_imc
) );
775 if ((spy
= get_thread_coinit_spy())) IInitializeSpy_Release( &spy
->IInitializeSpy_iface
);
778 static void IMM_FreeAllImmHkl(void)
780 struct ime
*ime
, *ime_next
;
782 LIST_FOR_EACH_ENTRY_SAFE( ime
, ime_next
, &ime_list
, struct ime
, entry
)
784 struct imc_entry
*imc_entry
, *imc_next
;
785 list_remove( &ime
->entry
);
787 ime
->pImeDestroy( 1 );
788 FreeLibrary( ime
->module
);
789 LIST_FOR_EACH_ENTRY_SAFE( imc_entry
, imc_next
, &ime
->input_contexts
, struct imc_entry
, entry
)
791 ImmDestroyIMCC( imc_entry
->context
.hPrivate
);
799 BOOL WINAPI
DllMain( HINSTANCE instance
, DWORD reason
, void *reserved
)
801 TRACE( "instance %p, reason %lx, reserved %p\n", instance
, reason
, reserved
);
805 case DLL_PROCESS_ATTACH
:
806 if (!User32InitializeImmEntryTable( IMM_INIT_MAGIC
)) return FALSE
;
807 imm32_module
= instance
;
809 case DLL_THREAD_ATTACH
:
811 case DLL_THREAD_DETACH
:
812 IMM_FreeThreadData();
814 case DLL_PROCESS_DETACH
:
816 IMM_FreeThreadData();
824 /***********************************************************************
825 * ImmSetActiveContext (IMM32.@)
827 BOOL WINAPI
ImmSetActiveContext(HWND hwnd
, HIMC himc
, BOOL activate
)
829 struct imc
*data
= get_imc_data( himc
);
832 TRACE("(%p, %p, %x)\n", hwnd
, himc
, activate
);
834 if (himc
&& !data
&& activate
)
841 if (activate
) data
->IMC
.hWnd
= hwnd
;
842 if ((ime
= imc_select_ime( data
))) ime
->pImeSetActiveContext( himc
, activate
);
847 SendMessageW(hwnd
, WM_IME_SETCONTEXT
, activate
, ISC_SHOWUIALL
);
848 /* TODO: send WM_IME_NOTIFY */
854 /***********************************************************************
855 * ImmConfigureIMEA (IMM32.@)
857 BOOL WINAPI
ImmConfigureIMEA( HKL hkl
, HWND hwnd
, DWORD mode
, void *data
)
862 TRACE( "hkl %p, hwnd %p, mode %lu, data %p.\n", hkl
, hwnd
, mode
, data
);
864 if (mode
== IME_CONFIG_REGISTERWORD
&& !data
) return FALSE
;
865 if (!(ime
= ime_acquire( hkl
))) return FALSE
;
867 if (mode
!= IME_CONFIG_REGISTERWORD
|| !ime_is_unicode( ime
))
868 ret
= ime
->pImeConfigure( hkl
, hwnd
, mode
, data
);
871 REGISTERWORDA
*wordA
= data
;
873 wordW
.lpWord
= strdupAtoW( wordA
->lpWord
);
874 wordW
.lpReading
= strdupAtoW( wordA
->lpReading
);
875 ret
= ime
->pImeConfigure( hkl
, hwnd
, mode
, &wordW
);
876 free( wordW
.lpReading
);
877 free( wordW
.lpWord
);
884 /***********************************************************************
885 * ImmConfigureIMEW (IMM32.@)
887 BOOL WINAPI
ImmConfigureIMEW( HKL hkl
, HWND hwnd
, DWORD mode
, void *data
)
892 TRACE( "hkl %p, hwnd %p, mode %lu, data %p.\n", hkl
, hwnd
, mode
, data
);
894 if (mode
== IME_CONFIG_REGISTERWORD
&& !data
) return FALSE
;
895 if (!(ime
= ime_acquire( hkl
))) return FALSE
;
897 if (mode
!= IME_CONFIG_REGISTERWORD
|| ime_is_unicode( ime
))
898 ret
= ime
->pImeConfigure( hkl
, hwnd
, mode
, data
);
901 REGISTERWORDW
*wordW
= data
;
903 wordA
.lpWord
= strdupWtoA( wordW
->lpWord
);
904 wordA
.lpReading
= strdupWtoA( wordW
->lpReading
);
905 ret
= ime
->pImeConfigure( hkl
, hwnd
, mode
, &wordA
);
906 free( wordA
.lpReading
);
907 free( wordA
.lpWord
);
914 static struct imc
*create_input_context( HIMC default_imc
)
916 struct imc
*new_context
;
918 if (!(new_context
= calloc( 1, sizeof(*new_context
) ))) return NULL
;
919 input_context_init( &new_context
->IMC
);
922 new_context
->handle
= NtUserCreateInputContext((UINT_PTR
)new_context
);
923 else if (NtUserUpdateInputContext(default_imc
, NtUserInputContextClientPtr
, (UINT_PTR
)new_context
))
924 new_context
->handle
= default_imc
;
925 if (!new_context
->handle
)
927 free_input_context_data(new_context
);
931 TRACE("Created context %p\n", new_context
);
935 static struct imc
*get_imc_data( HIMC handle
)
939 if ((ret
= query_imc_data(handle
)) || !handle
) return ret
;
940 return create_input_context(handle
);
943 static struct imc
*default_input_context(void)
945 UINT
*himc
= &NtUserGetThreadInfo()->default_imc
;
946 if (!*himc
) *himc
= (UINT_PTR
)NtUserCreateInputContext( 0 );
947 return get_imc_data( (HIMC
)(UINT_PTR
)*himc
);
950 static HWND
get_ime_ui_window(void)
952 struct imc
*imc
= default_input_context();
955 if (!(ime
= imc_select_ime( imc
))) return 0;
959 imc
->ui_hwnd
= CreateWindowExW( WS_EX_TOOLWINDOW
, ime
->ui_class
, NULL
, WS_POPUP
, 0, 0, 1, 1,
960 ImmGetDefaultIMEWnd( 0 ), 0, ime
->module
, 0 );
961 SetWindowLongPtrW( imc
->ui_hwnd
, IMMGWL_IMC
, (LONG_PTR
)NtUserGetWindowInputContext( GetFocus() ) );
966 static void set_ime_ui_window_himc( HIMC himc
)
969 if (!(hwnd
= get_ime_ui_window())) return;
970 SetWindowLongPtrW( hwnd
, IMMGWL_IMC
, (LONG_PTR
)himc
);
973 /***********************************************************************
974 * ImmCreateContext (IMM32.@)
976 HIMC WINAPI
ImmCreateContext(void)
978 struct imc
*new_context
;
980 if (!(new_context
= create_input_context(0))) return 0;
981 return new_context
->handle
;
984 static BOOL
IMM_DestroyContext(HIMC hIMC
)
986 if (!free_input_context_data(hIMC
)) return FALSE
;
987 NtUserDestroyInputContext(hIMC
);
991 /***********************************************************************
992 * ImmDestroyContext (IMM32.@)
994 BOOL WINAPI
ImmDestroyContext(HIMC hIMC
)
996 if ((UINT_PTR
)hIMC
== NtUserGetThreadInfo()->default_imc
) return FALSE
;
997 if (NtUserQueryInputContext( hIMC
, NtUserInputContextThreadId
) != GetCurrentThreadId()) return FALSE
;
998 return IMM_DestroyContext(hIMC
);
1001 /***********************************************************************
1002 * ImmAssociateContext (IMM32.@)
1004 HIMC WINAPI
ImmAssociateContext( HWND hwnd
, HIMC new_himc
)
1009 TRACE( "hwnd %p, new_himc %p\n", hwnd
, new_himc
);
1011 old_himc
= NtUserGetWindowInputContext( hwnd
);
1012 ret
= NtUserAssociateInputContext( hwnd
, new_himc
, 0 );
1013 if (ret
== AICR_FOCUS_CHANGED
)
1015 ImmSetActiveContext( hwnd
, old_himc
, FALSE
);
1016 ImmSetActiveContext( hwnd
, new_himc
, TRUE
);
1017 if (hwnd
== GetFocus()) set_ime_ui_window_himc( new_himc
);
1020 return ret
== AICR_FAILED
? 0 : old_himc
;
1023 static BOOL CALLBACK
enum_associate_context( HWND hwnd
, LPARAM lparam
)
1025 ImmAssociateContext( hwnd
, (HIMC
)lparam
);
1029 /***********************************************************************
1030 * ImmAssociateContextEx (IMM32.@)
1032 BOOL WINAPI
ImmAssociateContextEx( HWND hwnd
, HIMC new_himc
, DWORD flags
)
1037 TRACE( "hwnd %p, new_himc %p, flags %#lx\n", hwnd
, new_himc
, flags
);
1039 if (!hwnd
) return FALSE
;
1041 if (flags
== IACE_CHILDREN
)
1043 EnumChildWindows( hwnd
, enum_associate_context
, (LPARAM
)new_himc
);
1047 old_himc
= NtUserGetWindowInputContext( hwnd
);
1048 ret
= NtUserAssociateInputContext( hwnd
, new_himc
, flags
);
1049 if (ret
== AICR_FOCUS_CHANGED
)
1051 ImmSetActiveContext( hwnd
, old_himc
, FALSE
);
1052 ImmSetActiveContext( hwnd
, new_himc
, TRUE
);
1053 if (hwnd
== GetFocus()) set_ime_ui_window_himc( new_himc
);
1056 return ret
!= AICR_FAILED
;
1059 struct enum_register_word_params_WtoA
1061 REGISTERWORDENUMPROCA proc
;
1065 static int CALLBACK
enum_register_word_WtoA( const WCHAR
*readingW
, DWORD style
,
1066 const WCHAR
*stringW
, void *user
)
1068 char *readingA
= strdupWtoA( readingW
), *stringA
= strdupWtoA( stringW
);
1069 struct enum_register_word_params_WtoA
*params
= user
;
1070 int ret
= params
->proc( readingA
, style
, stringA
, params
->user
);
1076 /***********************************************************************
1077 * ImmEnumRegisterWordA (IMM32.@)
1079 UINT WINAPI
ImmEnumRegisterWordA( HKL hkl
, REGISTERWORDENUMPROCA procA
, const char *readingA
,
1080 DWORD style
, const char *stringA
, void *user
)
1085 TRACE( "hkl %p, procA %p, readingA %s, style %lu, stringA %s, user %p.\n", hkl
, procA
,
1086 debugstr_a(readingA
), style
, debugstr_a(stringA
), user
);
1088 if (!(ime
= ime_acquire( hkl
))) return 0;
1090 if (!ime_is_unicode( ime
))
1091 ret
= ime
->pImeEnumRegisterWord( procA
, readingA
, style
, stringA
, user
);
1094 struct enum_register_word_params_WtoA params
= {.proc
= procA
, .user
= user
};
1095 WCHAR
*readingW
= strdupAtoW( readingA
), *stringW
= strdupAtoW( stringA
);
1096 ret
= ime
->pImeEnumRegisterWord( enum_register_word_WtoA
, readingW
, style
, stringW
, ¶ms
);
1105 struct enum_register_word_params_AtoW
1107 REGISTERWORDENUMPROCW proc
;
1111 static int CALLBACK
enum_register_word_AtoW( const char *readingA
, DWORD style
,
1112 const char *stringA
, void *user
)
1114 WCHAR
*readingW
= strdupAtoW( readingA
), *stringW
= strdupAtoW( stringA
);
1115 struct enum_register_word_params_AtoW
*params
= user
;
1116 int ret
= params
->proc( readingW
, style
, stringW
, params
->user
);
1122 /***********************************************************************
1123 * ImmEnumRegisterWordW (IMM32.@)
1125 UINT WINAPI
ImmEnumRegisterWordW( HKL hkl
, REGISTERWORDENUMPROCW procW
, const WCHAR
*readingW
,
1126 DWORD style
, const WCHAR
*stringW
, void *user
)
1131 TRACE( "hkl %p, procW %p, readingW %s, style %lu, stringW %s, user %p.\n", hkl
, procW
,
1132 debugstr_w(readingW
), style
, debugstr_w(stringW
), user
);
1134 if (!(ime
= ime_acquire( hkl
))) return 0;
1136 if (ime_is_unicode( ime
))
1137 ret
= ime
->pImeEnumRegisterWord( procW
, readingW
, style
, stringW
, user
);
1140 struct enum_register_word_params_AtoW params
= {.proc
= procW
, .user
= user
};
1141 char *readingA
= strdupWtoA( readingW
), *stringA
= strdupWtoA( stringW
);
1142 ret
= ime
->pImeEnumRegisterWord( enum_register_word_AtoW
, readingA
, style
, stringA
, ¶ms
);
1151 static inline BOOL
EscapeRequiresWA(UINT uEscape
)
1153 if (uEscape
== IME_ESC_GET_EUDC_DICTIONARY
||
1154 uEscape
== IME_ESC_SET_EUDC_DICTIONARY
||
1155 uEscape
== IME_ESC_IME_NAME
||
1156 uEscape
== IME_ESC_GETHELPFILENAME
)
1161 /***********************************************************************
1162 * ImmEscapeA (IMM32.@)
1164 LRESULT WINAPI
ImmEscapeA( HKL hkl
, HIMC himc
, UINT code
, void *data
)
1169 TRACE( "hkl %p, himc %p, code %u, data %p.\n", hkl
, himc
, code
, data
);
1171 if (!(ime
= ime_acquire( hkl
))) return 0;
1173 if (!EscapeRequiresWA( code
) || !ime_is_unicode( ime
) || !data
)
1174 ret
= ime
->pImeEscape( himc
, code
, data
);
1177 WCHAR buffer
[81]; /* largest required buffer should be 80 */
1178 if (code
== IME_ESC_SET_EUDC_DICTIONARY
)
1180 MultiByteToWideChar( CP_ACP
, 0, data
, -1, buffer
, 81 );
1181 ret
= ime
->pImeEscape( himc
, code
, buffer
);
1185 ret
= ime
->pImeEscape( himc
, code
, buffer
);
1186 WideCharToMultiByte( CP_ACP
, 0, buffer
, -1, data
, 80, NULL
, NULL
);
1194 /***********************************************************************
1195 * ImmEscapeW (IMM32.@)
1197 LRESULT WINAPI
ImmEscapeW( HKL hkl
, HIMC himc
, UINT code
, void *data
)
1202 TRACE( "hkl %p, himc %p, code %u, data %p.\n", hkl
, himc
, code
, data
);
1204 if (!(ime
= ime_acquire( hkl
))) return 0;
1206 if (!EscapeRequiresWA( code
) || ime_is_unicode( ime
) || !data
)
1207 ret
= ime
->pImeEscape( himc
, code
, data
);
1210 char buffer
[81]; /* largest required buffer should be 80 */
1211 if (code
== IME_ESC_SET_EUDC_DICTIONARY
)
1213 WideCharToMultiByte( CP_ACP
, 0, data
, -1, buffer
, 81, NULL
, NULL
);
1214 ret
= ime
->pImeEscape( himc
, code
, buffer
);
1218 ret
= ime
->pImeEscape( himc
, code
, buffer
);
1219 MultiByteToWideChar( CP_ACP
, 0, buffer
, -1, data
, 80 );
1227 /***********************************************************************
1228 * ImmGetCandidateListA (IMM32.@)
1230 DWORD WINAPI
ImmGetCandidateListA(
1231 HIMC hIMC
, DWORD dwIndex
,
1232 LPCANDIDATELIST lpCandList
, DWORD dwBufLen
)
1234 struct imc
*data
= get_imc_data( hIMC
);
1235 LPCANDIDATEINFO candinfo
;
1236 LPCANDIDATELIST candlist
;
1240 TRACE("%p, %ld, %p, %ld\n", hIMC
, dwIndex
, lpCandList
, dwBufLen
);
1242 if (!data
|| !data
->IMC
.hCandInfo
)
1245 candinfo
= ImmLockIMCC(data
->IMC
.hCandInfo
);
1246 if (dwIndex
>= candinfo
->dwCount
|| dwIndex
>= ARRAY_SIZE(candinfo
->dwOffset
))
1249 candlist
= (LPCANDIDATELIST
)((LPBYTE
)candinfo
+ candinfo
->dwOffset
[dwIndex
]);
1250 if ( !candlist
->dwSize
|| !candlist
->dwCount
)
1253 if (!(ime
= imc_select_ime( data
)))
1255 else if (!ime_is_unicode( ime
))
1257 ret
= candlist
->dwSize
;
1258 if ( lpCandList
&& dwBufLen
>= ret
)
1259 memcpy(lpCandList
, candlist
, ret
);
1262 ret
= convert_candidatelist_WtoA( candlist
, lpCandList
, dwBufLen
);
1265 ImmUnlockIMCC(data
->IMC
.hCandInfo
);
1269 /***********************************************************************
1270 * ImmGetCandidateListCountA (IMM32.@)
1272 DWORD WINAPI
ImmGetCandidateListCountA(
1273 HIMC hIMC
, LPDWORD lpdwListCount
)
1275 struct imc
*data
= get_imc_data( hIMC
);
1276 LPCANDIDATEINFO candinfo
;
1280 TRACE("%p, %p\n", hIMC
, lpdwListCount
);
1282 if (!data
|| !lpdwListCount
|| !data
->IMC
.hCandInfo
)
1285 candinfo
= ImmLockIMCC(data
->IMC
.hCandInfo
);
1287 *lpdwListCount
= count
= candinfo
->dwCount
;
1289 if (!(ime
= imc_select_ime( data
)))
1291 else if (!ime_is_unicode( ime
))
1292 ret
= candinfo
->dwSize
;
1295 ret
= sizeof(CANDIDATEINFO
);
1297 ret
+= ImmGetCandidateListA(hIMC
, count
, NULL
, 0);
1300 ImmUnlockIMCC(data
->IMC
.hCandInfo
);
1304 /***********************************************************************
1305 * ImmGetCandidateListCountW (IMM32.@)
1307 DWORD WINAPI
ImmGetCandidateListCountW(
1308 HIMC hIMC
, LPDWORD lpdwListCount
)
1310 struct imc
*data
= get_imc_data( hIMC
);
1311 LPCANDIDATEINFO candinfo
;
1315 TRACE("%p, %p\n", hIMC
, lpdwListCount
);
1317 if (!data
|| !lpdwListCount
|| !data
->IMC
.hCandInfo
)
1320 candinfo
= ImmLockIMCC(data
->IMC
.hCandInfo
);
1322 *lpdwListCount
= count
= candinfo
->dwCount
;
1324 if (!(ime
= imc_select_ime( data
)))
1326 else if (ime_is_unicode( ime
))
1327 ret
= candinfo
->dwSize
;
1330 ret
= sizeof(CANDIDATEINFO
);
1332 ret
+= ImmGetCandidateListW(hIMC
, count
, NULL
, 0);
1335 ImmUnlockIMCC(data
->IMC
.hCandInfo
);
1339 /***********************************************************************
1340 * ImmGetCandidateListW (IMM32.@)
1342 DWORD WINAPI
ImmGetCandidateListW(
1343 HIMC hIMC
, DWORD dwIndex
,
1344 LPCANDIDATELIST lpCandList
, DWORD dwBufLen
)
1346 struct imc
*data
= get_imc_data( hIMC
);
1347 LPCANDIDATEINFO candinfo
;
1348 LPCANDIDATELIST candlist
;
1352 TRACE("%p, %ld, %p, %ld\n", hIMC
, dwIndex
, lpCandList
, dwBufLen
);
1354 if (!data
|| !data
->IMC
.hCandInfo
)
1357 candinfo
= ImmLockIMCC(data
->IMC
.hCandInfo
);
1358 if (dwIndex
>= candinfo
->dwCount
|| dwIndex
>= ARRAY_SIZE(candinfo
->dwOffset
))
1361 candlist
= (LPCANDIDATELIST
)((LPBYTE
)candinfo
+ candinfo
->dwOffset
[dwIndex
]);
1362 if ( !candlist
->dwSize
|| !candlist
->dwCount
)
1365 if (!(ime
= imc_select_ime( data
)))
1367 else if (ime_is_unicode( ime
))
1369 ret
= candlist
->dwSize
;
1370 if ( lpCandList
&& dwBufLen
>= ret
)
1371 memcpy(lpCandList
, candlist
, ret
);
1374 ret
= convert_candidatelist_AtoW( candlist
, lpCandList
, dwBufLen
);
1377 ImmUnlockIMCC(data
->IMC
.hCandInfo
);
1381 /***********************************************************************
1382 * ImmGetCandidateWindow (IMM32.@)
1384 BOOL WINAPI
ImmGetCandidateWindow( HIMC himc
, DWORD index
, CANDIDATEFORM
*candidate
)
1389 TRACE( "himc %p, index %lu, candidate %p\n", himc
, index
, candidate
);
1391 if (!candidate
) return FALSE
;
1393 if (!(ctx
= ImmLockIMC( himc
))) return FALSE
;
1394 if (ctx
->cfCandForm
[index
].dwIndex
== -1) ret
= FALSE
;
1395 else *candidate
= ctx
->cfCandForm
[index
];
1396 ImmUnlockIMC( himc
);
1401 /***********************************************************************
1402 * ImmGetCompositionFontA (IMM32.@)
1404 BOOL WINAPI
ImmGetCompositionFontA( HIMC himc
, LOGFONTA
*fontA
)
1410 TRACE( "himc %p, fontA %p\n", himc
, fontA
);
1412 if (!fontA
) return FALSE
;
1414 if (!(ctx
= ImmLockIMC( himc
))) return FALSE
;
1415 if (!(ctx
->fdwInit
& INIT_LOGFONT
)) ret
= FALSE
;
1416 else if (!input_context_is_unicode( ctx
)) *fontA
= ctx
->lfFont
.A
;
1417 else if ((ret
= ImmGetCompositionFontW( himc
, &fontW
)))
1419 memcpy( fontA
, &fontW
, offsetof(LOGFONTA
, lfFaceName
) );
1420 WideCharToMultiByte( CP_ACP
, 0, fontW
.lfFaceName
, -1, fontA
->lfFaceName
, LF_FACESIZE
, NULL
, NULL
);
1422 ImmUnlockIMC( himc
);
1427 /***********************************************************************
1428 * ImmGetCompositionFontW (IMM32.@)
1430 BOOL WINAPI
ImmGetCompositionFontW( HIMC himc
, LOGFONTW
*fontW
)
1436 TRACE( "himc %p, fontW %p\n", himc
, fontW
);
1438 if (!fontW
) return FALSE
;
1440 if (!(ctx
= ImmLockIMC( himc
))) return FALSE
;
1441 if (!(ctx
->fdwInit
& INIT_LOGFONT
)) ret
= FALSE
;
1442 else if (input_context_is_unicode( ctx
)) *fontW
= ctx
->lfFont
.W
;
1443 else if ((ret
= ImmGetCompositionFontA( himc
, &fontA
)))
1445 memcpy( fontW
, &fontA
, offsetof(LOGFONTW
, lfFaceName
) );
1446 MultiByteToWideChar( CP_ACP
, 0, fontA
.lfFaceName
, -1, fontW
->lfFaceName
, LF_FACESIZE
);
1448 ImmUnlockIMC( himc
);
1454 /* Helpers for the GetCompositionString functions */
1456 /* Source encoding is defined by context, source length is always given in respective characters. Destination buffer
1457 length is always in bytes. */
1458 static INT
CopyCompStringIMEtoClient( BOOL src_unicode
, const void *src
, INT src_len
,
1459 void *dst
, INT dst_len
, BOOL dst_unicode
)
1461 int char_size
= dst_unicode
? sizeof(WCHAR
) : sizeof(char);
1464 if (src_unicode
^ dst_unicode
)
1467 ret
= MultiByteToWideChar(CP_ACP
, 0, src
, src_len
, dst
, dst_len
/ sizeof(WCHAR
));
1469 ret
= WideCharToMultiByte(CP_ACP
, 0, src
, src_len
, dst
, dst_len
, NULL
, NULL
);
1476 ret
= min(src_len
* char_size
, dst_len
);
1477 memcpy(dst
, src
, ret
);
1480 ret
= src_len
* char_size
;
1486 /* Composition string encoding is defined by context, returned attributes correspond to string, converted according to
1487 passed mode. String length is in characters, attributes are in byte arrays. */
1488 static INT
CopyCompAttrIMEtoClient( BOOL src_unicode
, const BYTE
*src
, INT src_len
, const void *comp_string
, INT str_len
,
1489 BYTE
*dst
, INT dst_len
, BOOL unicode
)
1499 string
.str
= comp_string
;
1501 if (src_unicode
&& !unicode
)
1503 rc
= WideCharToMultiByte(CP_ACP
, 0, string
.strW
, str_len
, NULL
, 0, NULL
, NULL
);
1506 int i
, j
= 0, k
= 0;
1510 for (i
= 0; i
< str_len
; ++i
)
1514 len
= WideCharToMultiByte(CP_ACP
, 0, string
.strW
+ i
, 1, NULL
, 0, NULL
, NULL
);
1515 for (; len
> 0; --len
)
1528 else if (!src_unicode
&& unicode
)
1530 rc
= MultiByteToWideChar(CP_ACP
, 0, string
.strA
, str_len
, NULL
, 0);
1537 for (i
= 0; i
< str_len
; ++i
)
1539 if (IsDBCSLeadByte(string
.strA
[i
]))
1552 memcpy(dst
, src
, min(src_len
, dst_len
));
1559 static INT
CopyCompClauseIMEtoClient( BOOL src_unicode
, LPBYTE source
, INT slen
, LPBYTE ssource
,
1560 LPBYTE target
, INT tlen
, BOOL unicode
)
1564 if (src_unicode
&& !unicode
)
1572 tlen
/= sizeof (DWORD
);
1573 for (i
= 0; i
< tlen
; ++i
)
1575 ((DWORD
*)target
)[i
] = WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)ssource
,
1576 ((DWORD
*)source
)[i
],
1580 rc
= sizeof (DWORD
) * i
;
1585 else if (!src_unicode
&& unicode
)
1593 tlen
/= sizeof (DWORD
);
1594 for (i
= 0; i
< tlen
; ++i
)
1596 ((DWORD
*)target
)[i
] = MultiByteToWideChar(CP_ACP
, 0, (LPSTR
)ssource
,
1597 ((DWORD
*)source
)[i
],
1600 rc
= sizeof (DWORD
) * i
;
1607 memcpy( target
, source
, min(slen
,tlen
));
1614 static INT
CopyCompOffsetIMEtoClient( BOOL src_unicode
, DWORD offset
, LPBYTE ssource
, BOOL unicode
)
1618 if (src_unicode
&& !unicode
)
1620 rc
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)ssource
, offset
, NULL
, 0, NULL
, NULL
);
1622 else if (!src_unicode
&& unicode
)
1624 rc
= MultiByteToWideChar(CP_ACP
, 0, (LPSTR
)ssource
, offset
, NULL
, 0);
1632 static LONG
ImmGetCompositionStringT( HIMC hIMC
, DWORD dwIndex
, LPVOID lpBuf
,
1633 DWORD dwBufLen
, BOOL unicode
)
1636 struct imc
*data
= get_imc_data( hIMC
);
1637 LPCOMPOSITIONSTRING compstr
;
1642 TRACE("(%p, 0x%lx, %p, %ld)\n", hIMC
, dwIndex
, lpBuf
, dwBufLen
);
1647 if (!data
->IMC
.hCompStr
)
1650 if (!(ime
= imc_select_ime( data
)))
1652 src_unicode
= ime_is_unicode( ime
);
1654 compdata
= ImmLockIMCC(data
->IMC
.hCompStr
);
1655 compstr
= (LPCOMPOSITIONSTRING
)compdata
;
1660 TRACE("GCS_RESULTSTR\n");
1661 rc
= CopyCompStringIMEtoClient(src_unicode
, compdata
+ compstr
->dwResultStrOffset
, compstr
->dwResultStrLen
, lpBuf
, dwBufLen
, unicode
);
1664 TRACE("GCS_COMPSTR\n");
1665 rc
= CopyCompStringIMEtoClient(src_unicode
, compdata
+ compstr
->dwCompStrOffset
, compstr
->dwCompStrLen
, lpBuf
, dwBufLen
, unicode
);
1668 TRACE("GCS_COMPATTR\n");
1669 rc
= CopyCompAttrIMEtoClient(src_unicode
, compdata
+ compstr
->dwCompAttrOffset
, compstr
->dwCompAttrLen
,
1670 compdata
+ compstr
->dwCompStrOffset
, compstr
->dwCompStrLen
,
1671 lpBuf
, dwBufLen
, unicode
);
1673 case GCS_COMPCLAUSE
:
1674 TRACE("GCS_COMPCLAUSE\n");
1675 rc
= CopyCompClauseIMEtoClient(src_unicode
, compdata
+ compstr
->dwCompClauseOffset
,compstr
->dwCompClauseLen
,
1676 compdata
+ compstr
->dwCompStrOffset
,
1677 lpBuf
, dwBufLen
, unicode
);
1679 case GCS_RESULTCLAUSE
:
1680 TRACE("GCS_RESULTCLAUSE\n");
1681 rc
= CopyCompClauseIMEtoClient(src_unicode
, compdata
+ compstr
->dwResultClauseOffset
,compstr
->dwResultClauseLen
,
1682 compdata
+ compstr
->dwResultStrOffset
,
1683 lpBuf
, dwBufLen
, unicode
);
1685 case GCS_RESULTREADSTR
:
1686 TRACE("GCS_RESULTREADSTR\n");
1687 rc
= CopyCompStringIMEtoClient(src_unicode
, compdata
+ compstr
->dwResultReadStrOffset
, compstr
->dwResultReadStrLen
, lpBuf
, dwBufLen
, unicode
);
1689 case GCS_RESULTREADCLAUSE
:
1690 TRACE("GCS_RESULTREADCLAUSE\n");
1691 rc
= CopyCompClauseIMEtoClient(src_unicode
, compdata
+ compstr
->dwResultReadClauseOffset
,compstr
->dwResultReadClauseLen
,
1692 compdata
+ compstr
->dwResultStrOffset
,
1693 lpBuf
, dwBufLen
, unicode
);
1695 case GCS_COMPREADSTR
:
1696 TRACE("GCS_COMPREADSTR\n");
1697 rc
= CopyCompStringIMEtoClient(src_unicode
, compdata
+ compstr
->dwCompReadStrOffset
, compstr
->dwCompReadStrLen
, lpBuf
, dwBufLen
, unicode
);
1699 case GCS_COMPREADATTR
:
1700 TRACE("GCS_COMPREADATTR\n");
1701 rc
= CopyCompAttrIMEtoClient(src_unicode
, compdata
+ compstr
->dwCompReadAttrOffset
, compstr
->dwCompReadAttrLen
,
1702 compdata
+ compstr
->dwCompReadStrOffset
, compstr
->dwCompReadStrLen
,
1703 lpBuf
, dwBufLen
, unicode
);
1705 case GCS_COMPREADCLAUSE
:
1706 TRACE("GCS_COMPREADCLAUSE\n");
1707 rc
= CopyCompClauseIMEtoClient(src_unicode
, compdata
+ compstr
->dwCompReadClauseOffset
,compstr
->dwCompReadClauseLen
,
1708 compdata
+ compstr
->dwCompStrOffset
,
1709 lpBuf
, dwBufLen
, unicode
);
1712 TRACE("GCS_CURSORPOS\n");
1713 rc
= CopyCompOffsetIMEtoClient(src_unicode
, compstr
->dwCursorPos
, compdata
+ compstr
->dwCompStrOffset
, unicode
);
1715 case GCS_DELTASTART
:
1716 TRACE("GCS_DELTASTART\n");
1717 rc
= CopyCompOffsetIMEtoClient(src_unicode
, compstr
->dwDeltaStart
, compdata
+ compstr
->dwCompStrOffset
, unicode
);
1720 FIXME("Unhandled index 0x%lx\n",dwIndex
);
1724 ImmUnlockIMCC(data
->IMC
.hCompStr
);
1729 /***********************************************************************
1730 * ImmGetCompositionStringA (IMM32.@)
1732 LONG WINAPI
ImmGetCompositionStringA(
1733 HIMC hIMC
, DWORD dwIndex
, LPVOID lpBuf
, DWORD dwBufLen
)
1735 return ImmGetCompositionStringT(hIMC
, dwIndex
, lpBuf
, dwBufLen
, FALSE
);
1739 /***********************************************************************
1740 * ImmGetCompositionStringW (IMM32.@)
1742 LONG WINAPI
ImmGetCompositionStringW(
1743 HIMC hIMC
, DWORD dwIndex
,
1744 LPVOID lpBuf
, DWORD dwBufLen
)
1746 return ImmGetCompositionStringT(hIMC
, dwIndex
, lpBuf
, dwBufLen
, TRUE
);
1749 /***********************************************************************
1750 * ImmGetCompositionWindow (IMM32.@)
1752 BOOL WINAPI
ImmGetCompositionWindow( HIMC himc
, COMPOSITIONFORM
*composition
)
1757 TRACE( "himc %p, composition %p\n", himc
, composition
);
1759 if (!(ctx
= ImmLockIMC( himc
))) return FALSE
;
1760 if ((ret
= !!(ctx
->fdwInit
& INIT_COMPFORM
))) *composition
= ctx
->cfCompForm
;
1761 ImmUnlockIMC( himc
);
1766 /***********************************************************************
1767 * ImmGetContext (IMM32.@)
1770 HIMC WINAPI
ImmGetContext( HWND hwnd
)
1772 TRACE( "hwnd %p\n", hwnd
);
1773 return NtUserGetWindowInputContext( hwnd
);
1776 /***********************************************************************
1777 * ImmGetConversionListA (IMM32.@)
1779 DWORD WINAPI
ImmGetConversionListA( HKL hkl
, HIMC himc
, const char *srcA
, CANDIDATELIST
*listA
,
1780 DWORD lengthA
, UINT flags
)
1785 TRACE( "hkl %p, himc %p, srcA %s, listA %p, lengthA %lu, flags %#x.\n", hkl
, himc
,
1786 debugstr_a(srcA
), listA
, lengthA
, flags
);
1788 if (!(ime
= ime_acquire( hkl
))) return 0;
1790 if (!ime_is_unicode( ime
))
1791 ret
= ime
->pImeConversionList( himc
, srcA
, listA
, lengthA
, flags
);
1794 CANDIDATELIST
*listW
;
1795 WCHAR
*srcW
= strdupAtoW( srcA
);
1796 DWORD lengthW
= ime
->pImeConversionList( himc
, srcW
, NULL
, 0, flags
);
1798 if (!(listW
= malloc( lengthW
))) ret
= 0;
1801 ime
->pImeConversionList( himc
, srcW
, listW
, lengthW
, flags
);
1802 ret
= convert_candidatelist_WtoA( listW
, listA
, lengthA
);
1812 /***********************************************************************
1813 * ImmGetConversionListW (IMM32.@)
1815 DWORD WINAPI
ImmGetConversionListW( HKL hkl
, HIMC himc
, const WCHAR
*srcW
, CANDIDATELIST
*listW
,
1816 DWORD lengthW
, UINT flags
)
1821 TRACE( "hkl %p, himc %p, srcW %s, listW %p, lengthW %lu, flags %#x.\n", hkl
, himc
,
1822 debugstr_w(srcW
), listW
, lengthW
, flags
);
1824 if (!(ime
= ime_acquire( hkl
))) return 0;
1826 if (ime_is_unicode( ime
))
1827 ret
= ime
->pImeConversionList( himc
, srcW
, listW
, lengthW
, flags
);
1830 CANDIDATELIST
*listA
;
1831 char *srcA
= strdupWtoA( srcW
);
1832 DWORD lengthA
= ime
->pImeConversionList( himc
, srcA
, NULL
, 0, flags
);
1834 if (!(listA
= malloc( lengthA
))) ret
= 0;
1837 ime
->pImeConversionList( himc
, srcA
, listA
, lengthA
, flags
);
1838 ret
= convert_candidatelist_AtoW( listA
, listW
, lengthW
);
1848 /***********************************************************************
1849 * ImmGetConversionStatus (IMM32.@)
1851 BOOL WINAPI
ImmGetConversionStatus( HIMC himc
, DWORD
*conversion
, DWORD
*sentence
)
1855 TRACE( "himc %p, conversion %p, sentence %p\n", himc
, conversion
, sentence
);
1857 if (!(ctx
= ImmLockIMC( himc
))) return FALSE
;
1858 if (conversion
) *conversion
= ctx
->fdwConversion
;
1859 if (sentence
) *sentence
= ctx
->fdwSentence
;
1860 ImmUnlockIMC( himc
);
1865 /***********************************************************************
1866 * ImmGetDefaultIMEWnd (IMM32.@)
1868 HWND WINAPI
ImmGetDefaultIMEWnd(HWND hWnd
)
1870 return NtUserGetDefaultImeWindow(hWnd
);
1873 /***********************************************************************
1874 * ImmGetDescriptionA (IMM32.@)
1876 UINT WINAPI
ImmGetDescriptionA( HKL hkl
, LPSTR bufferA
, UINT lengthA
)
1881 TRACE( "hkl %p, bufferA %p, lengthA %d\n", hkl
, bufferA
, lengthA
);
1883 if (!(lengthW
= ImmGetDescriptionW( hkl
, NULL
, 0 ))) return 0;
1884 if (!(bufferW
= malloc( (lengthW
+ 1) * sizeof(WCHAR
) ))) return 0;
1885 lengthW
= ImmGetDescriptionW( hkl
, bufferW
, lengthW
+ 1 );
1886 lengthA
= WideCharToMultiByte( CP_ACP
, 0, bufferW
, lengthW
, bufferA
,
1887 bufferA
? lengthA
: 0, NULL
, NULL
);
1888 if (bufferA
) bufferA
[lengthA
] = 0;
1894 /***********************************************************************
1895 * ImmGetDescriptionW (IMM32.@)
1897 UINT WINAPI
ImmGetDescriptionW( HKL hkl
, WCHAR
*buffer
, UINT length
)
1899 WCHAR path
[MAX_PATH
];
1903 TRACE( "hkl %p, buffer %p, length %u\n", hkl
, buffer
, length
);
1905 swprintf( path
, ARRAY_SIZE(path
), layouts_formatW
, (ULONG
)(ULONG_PTR
)hkl
);
1906 if (RegOpenKeyW( HKEY_LOCAL_MACHINE
, path
, &hkey
)) return 0;
1908 size
= ARRAY_SIZE(path
) * sizeof(WCHAR
);
1909 if (RegGetValueW( hkey
, NULL
, L
"Layout Text", RRF_RT_REG_SZ
, NULL
, path
, &size
)) *path
= 0;
1910 RegCloseKey( hkey
);
1912 size
= wcslen( path
);
1913 if (!buffer
) return size
;
1915 lstrcpynW( buffer
, path
, length
);
1916 return wcslen( buffer
);
1919 /***********************************************************************
1920 * ImmGetGuideLineA (IMM32.@)
1922 DWORD WINAPI
ImmGetGuideLineA(
1923 HIMC hIMC
, DWORD dwIndex
, LPSTR lpBuf
, DWORD dwBufLen
)
1925 FIXME("(%p, %ld, %s, %ld): stub\n",
1926 hIMC
, dwIndex
, debugstr_a(lpBuf
), dwBufLen
1928 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1932 /***********************************************************************
1933 * ImmGetGuideLineW (IMM32.@)
1935 DWORD WINAPI
ImmGetGuideLineW(HIMC hIMC
, DWORD dwIndex
, LPWSTR lpBuf
, DWORD dwBufLen
)
1937 FIXME("(%p, %ld, %s, %ld): stub\n",
1938 hIMC
, dwIndex
, debugstr_w(lpBuf
), dwBufLen
1940 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1944 /***********************************************************************
1945 * ImmGetIMEFileNameA (IMM32.@)
1947 UINT WINAPI
ImmGetIMEFileNameA( HKL hkl
, char *bufferA
, UINT lengthA
)
1952 TRACE( "hkl %p, bufferA %p, lengthA %d\n", hkl
, bufferA
, lengthA
);
1954 if (!(lengthW
= ImmGetIMEFileNameW( hkl
, NULL
, 0 ))) return 0;
1955 if (!(bufferW
= malloc( (lengthW
+ 1) * sizeof(WCHAR
) ))) return 0;
1956 lengthW
= ImmGetIMEFileNameW( hkl
, bufferW
, lengthW
+ 1 );
1957 lengthA
= WideCharToMultiByte( CP_ACP
, 0, bufferW
, lengthW
, bufferA
,
1958 bufferA
? lengthA
: 0, NULL
, NULL
);
1959 if (bufferA
) bufferA
[lengthA
] = 0;
1965 /***********************************************************************
1966 * ImmGetIMEFileNameW (IMM32.@)
1968 UINT WINAPI
ImmGetIMEFileNameW( HKL hkl
, WCHAR
*buffer
, UINT length
)
1970 WCHAR path
[MAX_PATH
];
1974 TRACE( "hkl %p, buffer %p, length %u\n", hkl
, buffer
, length
);
1976 swprintf( path
, ARRAY_SIZE(path
), layouts_formatW
, (ULONG
)(ULONG_PTR
)hkl
);
1977 if (RegOpenKeyW( HKEY_LOCAL_MACHINE
, path
, &hkey
)) return 0;
1979 size
= ARRAY_SIZE(path
) * sizeof(WCHAR
);
1980 if (RegGetValueW( hkey
, NULL
, L
"Ime File", RRF_RT_REG_SZ
, NULL
, path
, &size
)) *path
= 0;
1981 RegCloseKey( hkey
);
1983 size
= wcslen( path
);
1984 if (!buffer
) return size
;
1986 lstrcpynW( buffer
, path
, length
);
1987 return wcslen( buffer
);
1990 /***********************************************************************
1991 * ImmGetOpenStatus (IMM32.@)
1993 BOOL WINAPI
ImmGetOpenStatus( HIMC himc
)
1998 TRACE( "himc %p\n", himc
);
2000 if (!(ctx
= ImmLockIMC( himc
))) return FALSE
;
2001 status
= ctx
->fOpen
;
2002 ImmUnlockIMC( himc
);
2007 /***********************************************************************
2008 * ImmGetProperty (IMM32.@)
2010 DWORD WINAPI
ImmGetProperty( HKL hkl
, DWORD index
)
2015 TRACE( "hkl %p, index %lu.\n", hkl
, index
);
2017 if (!(ime
= ime_acquire( hkl
))) return 0;
2021 case IGP_PROPERTY
: ret
= ime
->info
.fdwProperty
; break;
2022 case IGP_CONVERSION
: ret
= ime
->info
.fdwConversionCaps
; break;
2023 case IGP_SENTENCE
: ret
= ime
->info
.fdwSentenceCaps
; break;
2024 case IGP_SETCOMPSTR
: ret
= ime
->info
.fdwSCSCaps
; break;
2025 case IGP_SELECT
: ret
= ime
->info
.fdwSelectCaps
; break;
2026 case IGP_GETIMEVERSION
: ret
= IMEVER_0400
; break;
2027 case IGP_UI
: ret
= 0; break;
2028 default: ret
= 0; break;
2035 /***********************************************************************
2036 * ImmGetRegisterWordStyleA (IMM32.@)
2038 UINT WINAPI
ImmGetRegisterWordStyleA( HKL hkl
, UINT count
, STYLEBUFA
*styleA
)
2043 TRACE( "hkl %p, count %u, styleA %p.\n", hkl
, count
, styleA
);
2045 if (!(ime
= ime_acquire( hkl
))) return 0;
2047 if (!ime_is_unicode( ime
))
2048 ret
= ime
->pImeGetRegisterWordStyle( count
, styleA
);
2052 ret
= ime
->pImeGetRegisterWordStyle( count
, &styleW
);
2053 WideCharToMultiByte( CP_ACP
, 0, styleW
.szDescription
, -1, styleA
->szDescription
, 32, NULL
, NULL
);
2054 styleA
->dwStyle
= styleW
.dwStyle
;
2061 /***********************************************************************
2062 * ImmGetRegisterWordStyleW (IMM32.@)
2064 UINT WINAPI
ImmGetRegisterWordStyleW( HKL hkl
, UINT count
, STYLEBUFW
*styleW
)
2069 TRACE( "hkl %p, count %u, styleW %p.\n", hkl
, count
, styleW
);
2071 if (!(ime
= ime_acquire( hkl
))) return 0;
2073 if (ime_is_unicode( ime
))
2074 ret
= ime
->pImeGetRegisterWordStyle( count
, styleW
);
2078 ret
= ime
->pImeGetRegisterWordStyle( count
, &styleA
);
2079 MultiByteToWideChar( CP_ACP
, 0, styleA
.szDescription
, -1, styleW
->szDescription
, 32 );
2080 styleW
->dwStyle
= styleA
.dwStyle
;
2087 /***********************************************************************
2088 * ImmGetStatusWindowPos (IMM32.@)
2090 BOOL WINAPI
ImmGetStatusWindowPos( HIMC himc
, POINT
*pos
)
2095 TRACE( "himc %p, pos %p\n", himc
, pos
);
2097 if (!(ctx
= ImmLockIMC( himc
))) return FALSE
;
2098 if ((ret
= !!(ctx
->fdwInit
& INIT_STATUSWNDPOS
))) *pos
= ctx
->ptStatusWndPos
;
2099 ImmUnlockIMC( himc
);
2104 /***********************************************************************
2105 * ImmGetVirtualKey (IMM32.@)
2107 UINT WINAPI
ImmGetVirtualKey( HWND hwnd
)
2109 HIMC himc
= ImmGetContext( hwnd
);
2112 TRACE( "%p\n", hwnd
);
2114 if ((imc
= get_imc_data( himc
))) return imc
->vkey
;
2115 return VK_PROCESSKEY
;
2118 /***********************************************************************
2119 * ImmInstallIMEA (IMM32.@)
2121 HKL WINAPI
ImmInstallIMEA( const char *filenameA
, const char *descriptionA
)
2123 WCHAR
*filenameW
= strdupAtoW( filenameA
), *descriptionW
= strdupAtoW( descriptionA
);
2126 TRACE( "filenameA %s, descriptionA %s\n", debugstr_a(filenameA
), debugstr_a(descriptionA
) );
2128 hkl
= ImmInstallIMEW( filenameW
, descriptionW
);
2129 free( descriptionW
);
2135 static LCID
get_ime_file_lang( const WCHAR
*filename
)
2142 if (!(len
= GetFileVersionInfoSizeW( filename
, NULL
))) return 0;
2143 if (!(info
= malloc( len
))) goto done
;
2144 if (!GetFileVersionInfoW( filename
, 0, len
, info
)) goto done
;
2145 if (!VerQueryValueW( info
, L
"\\VarFileInfo\\Translation", (void **)&languages
, &len
) || !len
) goto done
;
2146 lcid
= languages
[0];
2153 /***********************************************************************
2154 * ImmInstallIMEW (IMM32.@)
2156 HKL WINAPI
ImmInstallIMEW( const WCHAR
*filename
, const WCHAR
*description
)
2158 WCHAR path
[ARRAY_SIZE(layouts_formatW
)+8], buffer
[MAX_PATH
];
2166 TRACE( "filename %s, description %s\n", debugstr_w(filename
), debugstr_w(description
) );
2168 if (!filename
|| !description
|| !(lcid
= get_ime_file_lang( filename
)))
2170 SetLastError( ERROR_INVALID_PARAMETER
);
2174 while (count
< 0xfff)
2176 DWORD disposition
= 0;
2178 hkl
= (HKL
)(UINT_PTR
)MAKELONG( lcid
, 0xe000 | count
);
2179 swprintf( path
, ARRAY_SIZE(path
), layouts_formatW
, (ULONG
)(ULONG_PTR
)hkl
);
2180 if (!RegCreateKeyExW( HKEY_LOCAL_MACHINE
, path
, 0, NULL
, 0,
2181 KEY_WRITE
, NULL
, &hkey
, &disposition
))
2183 if (disposition
== REG_CREATED_NEW_KEY
) break;
2184 RegCloseKey( hkey
);
2192 WARN("Unable to find slot to install IME\n");
2196 if ((tmp
= wcsrchr( filename
, '\\' ))) tmp
++;
2197 else tmp
= filename
;
2199 length
= LCMapStringW( LOCALE_USER_DEFAULT
, LCMAP_UPPERCASE
, tmp
, -1, buffer
, ARRAY_SIZE(buffer
) );
2201 if (RegSetValueExW( hkey
, L
"Ime File", 0, REG_SZ
, (const BYTE
*)buffer
, length
* sizeof(WCHAR
) ) ||
2202 RegSetValueExW( hkey
, L
"Layout Text", 0, REG_SZ
, (const BYTE
*)description
,
2203 (wcslen(description
) + 1) * sizeof(WCHAR
) ))
2205 WARN( "Unable to write registry to install IME\n");
2208 RegCloseKey( hkey
);
2210 if (!hkl
) RegDeleteKeyW( HKEY_LOCAL_MACHINE
, path
);
2214 /***********************************************************************
2215 * ImmIsIME (IMM32.@)
2217 BOOL WINAPI
ImmIsIME( HKL hkl
)
2219 TRACE( "hkl %p\n", hkl
);
2220 if (!hkl
) return FALSE
;
2224 /***********************************************************************
2225 * ImmIsUIMessageA (IMM32.@)
2227 BOOL WINAPI
ImmIsUIMessageA(
2228 HWND hWndIME
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
2230 TRACE("(%p, %x, %Id, %Id)\n", hWndIME
, msg
, wParam
, lParam
);
2231 if ((msg
>= WM_IME_STARTCOMPOSITION
&& msg
<= WM_IME_KEYLAST
) ||
2232 (msg
== WM_IME_SETCONTEXT
) ||
2233 (msg
== WM_IME_NOTIFY
) ||
2234 (msg
== WM_IME_COMPOSITIONFULL
) ||
2235 (msg
== WM_IME_SELECT
) ||
2236 (msg
== 0x287 /* FIXME: WM_IME_SYSTEM */))
2239 SendMessageA(hWndIME
, msg
, wParam
, lParam
);
2246 /***********************************************************************
2247 * ImmIsUIMessageW (IMM32.@)
2249 BOOL WINAPI
ImmIsUIMessageW(
2250 HWND hWndIME
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
2252 TRACE("(%p, %x, %Id, %Id)\n", hWndIME
, msg
, wParam
, lParam
);
2253 if ((msg
>= WM_IME_STARTCOMPOSITION
&& msg
<= WM_IME_KEYLAST
) ||
2254 (msg
== WM_IME_SETCONTEXT
) ||
2255 (msg
== WM_IME_NOTIFY
) ||
2256 (msg
== WM_IME_COMPOSITIONFULL
) ||
2257 (msg
== WM_IME_SELECT
) ||
2258 (msg
== 0x287 /* FIXME: WM_IME_SYSTEM */))
2261 SendMessageW(hWndIME
, msg
, wParam
, lParam
);
2268 /***********************************************************************
2269 * ImmNotifyIME (IMM32.@)
2271 BOOL WINAPI
ImmNotifyIME(
2272 HIMC hIMC
, DWORD dwAction
, DWORD dwIndex
, DWORD dwValue
)
2274 struct imc
*data
= get_imc_data( hIMC
);
2277 TRACE("(%p, %ld, %ld, %ld)\n",
2278 hIMC
, dwAction
, dwIndex
, dwValue
);
2282 SetLastError(ERROR_SUCCESS
);
2291 if (!(ime
= imc_select_ime( data
))) return FALSE
;
2292 return ime
->pNotifyIME( hIMC
, dwAction
, dwIndex
, dwValue
);
2295 /***********************************************************************
2296 * ImmRegisterWordA (IMM32.@)
2298 BOOL WINAPI
ImmRegisterWordA( HKL hkl
, const char *readingA
, DWORD style
, const char *stringA
)
2303 TRACE( "hkl %p, readingA %s, style %lu, stringA %s.\n", hkl
, debugstr_a(readingA
), style
, debugstr_a(stringA
) );
2305 if (!(ime
= ime_acquire( hkl
))) return FALSE
;
2307 if (!ime_is_unicode( ime
))
2308 ret
= ime
->pImeRegisterWord( readingA
, style
, stringA
);
2311 WCHAR
*readingW
= strdupAtoW( readingA
), *stringW
= strdupAtoW( stringA
);
2312 ret
= ime
->pImeRegisterWord( readingW
, style
, stringW
);
2321 /***********************************************************************
2322 * ImmRegisterWordW (IMM32.@)
2324 BOOL WINAPI
ImmRegisterWordW( HKL hkl
, const WCHAR
*readingW
, DWORD style
, const WCHAR
*stringW
)
2329 TRACE( "hkl %p, readingW %s, style %lu, stringW %s.\n", hkl
, debugstr_w(readingW
), style
, debugstr_w(stringW
) );
2331 if (!(ime
= ime_acquire( hkl
))) return FALSE
;
2333 if (ime_is_unicode( ime
))
2334 ret
= ime
->pImeRegisterWord( readingW
, style
, stringW
);
2337 char *readingA
= strdupWtoA( readingW
), *stringA
= strdupWtoA( stringW
);
2338 ret
= ime
->pImeRegisterWord( readingA
, style
, stringA
);
2347 /***********************************************************************
2348 * ImmReleaseContext (IMM32.@)
2350 BOOL WINAPI
ImmReleaseContext(HWND hWnd
, HIMC hIMC
)
2352 static BOOL shown
= FALSE
;
2355 FIXME("(%p, %p): stub\n", hWnd
, hIMC
);
2361 /***********************************************************************
2362 * ImmRequestMessageA(IMM32.@)
2364 LRESULT WINAPI
ImmRequestMessageA( HIMC himc
, WPARAM wparam
, LPARAM lparam
)
2369 TRACE( "himc %p, wparam %#Ix, lparam %#Ix\n", himc
, wparam
, lparam
);
2371 if (NtUserQueryInputContext( himc
, NtUserInputContextThreadId
) != GetCurrentThreadId()) return FALSE
;
2375 case IMR_CANDIDATEWINDOW
:
2376 case IMR_COMPOSITIONFONT
:
2377 case IMR_COMPOSITIONWINDOW
:
2378 case IMR_CONFIRMRECONVERTSTRING
:
2379 case IMR_DOCUMENTFEED
:
2380 case IMR_QUERYCHARPOSITION
:
2381 case IMR_RECONVERTSTRING
:
2387 if (!(ctx
= ImmLockIMC( himc
))) return FALSE
;
2388 res
= SendMessageA( ctx
->hWnd
, WM_IME_REQUEST
, wparam
, lparam
);
2389 ImmUnlockIMC( himc
);
2394 /***********************************************************************
2395 * ImmRequestMessageW(IMM32.@)
2397 LRESULT WINAPI
ImmRequestMessageW( HIMC himc
, WPARAM wparam
, LPARAM lparam
)
2402 TRACE( "himc %p, wparam %#Ix, lparam %#Ix\n", himc
, wparam
, lparam
);
2404 if (NtUserQueryInputContext( himc
, NtUserInputContextThreadId
) != GetCurrentThreadId()) return FALSE
;
2408 case IMR_CANDIDATEWINDOW
:
2409 case IMR_COMPOSITIONFONT
:
2410 case IMR_COMPOSITIONWINDOW
:
2411 case IMR_CONFIRMRECONVERTSTRING
:
2412 case IMR_DOCUMENTFEED
:
2413 case IMR_QUERYCHARPOSITION
:
2414 case IMR_RECONVERTSTRING
:
2420 if (!(ctx
= ImmLockIMC( himc
))) return FALSE
;
2421 res
= SendMessageW( ctx
->hWnd
, WM_IME_REQUEST
, wparam
, lparam
);
2422 ImmUnlockIMC( himc
);
2427 /***********************************************************************
2428 * ImmSetCandidateWindow (IMM32.@)
2430 BOOL WINAPI
ImmSetCandidateWindow( HIMC himc
, CANDIDATEFORM
*candidate
)
2434 TRACE( "hwnd %p, candidate %s\n", himc
, debugstr_candidate( candidate
) );
2436 if (!candidate
) return FALSE
;
2437 if (candidate
->dwIndex
>= ARRAY_SIZE(ctx
->cfCandForm
)) return FALSE
;
2439 if (NtUserQueryInputContext( himc
, NtUserInputContextThreadId
) != GetCurrentThreadId()) return FALSE
;
2440 if (!(ctx
= ImmLockIMC( himc
))) return FALSE
;
2442 ctx
->cfCandForm
[candidate
->dwIndex
] = *candidate
;
2444 ImmNotifyIME( himc
, NI_CONTEXTUPDATED
, 0, IMC_SETCANDIDATEPOS
);
2445 SendMessageW( ctx
->hWnd
, WM_IME_NOTIFY
, IMN_SETCANDIDATEPOS
, 1 << candidate
->dwIndex
);
2447 ImmUnlockIMC( himc
);
2452 /***********************************************************************
2453 * ImmSetCompositionFontA (IMM32.@)
2455 BOOL WINAPI
ImmSetCompositionFontA( HIMC himc
, LOGFONTA
*fontA
)
2460 TRACE( "hwnd %p, fontA %p\n", himc
, fontA
);
2462 if (!fontA
) return FALSE
;
2464 if (NtUserQueryInputContext( himc
, NtUserInputContextThreadId
) != GetCurrentThreadId()) return FALSE
;
2465 if (!(ctx
= ImmLockIMC( himc
))) return FALSE
;
2467 if (input_context_is_unicode( ctx
))
2470 memcpy( &fontW
, fontA
, offsetof(LOGFONTW
, lfFaceName
) );
2471 MultiByteToWideChar( CP_ACP
, 0, fontA
->lfFaceName
, -1, fontW
.lfFaceName
, LF_FACESIZE
);
2472 ret
= ImmSetCompositionFontW( himc
, &fontW
);
2476 ctx
->lfFont
.A
= *fontA
;
2477 ctx
->fdwInit
|= INIT_LOGFONT
;
2479 ImmNotifyIME( himc
, NI_CONTEXTUPDATED
, 0, IMC_SETCOMPOSITIONFONT
);
2480 SendMessageW( ctx
->hWnd
, WM_IME_NOTIFY
, IMN_SETCOMPOSITIONFONT
, 0 );
2483 ImmUnlockIMC( himc
);
2488 /***********************************************************************
2489 * ImmSetCompositionFontW (IMM32.@)
2491 BOOL WINAPI
ImmSetCompositionFontW( HIMC himc
, LOGFONTW
*fontW
)
2496 TRACE( "hwnd %p, fontW %p\n", himc
, fontW
);
2498 if (!fontW
) return FALSE
;
2500 if (NtUserQueryInputContext( himc
, NtUserInputContextThreadId
) != GetCurrentThreadId()) return FALSE
;
2501 if (!(ctx
= ImmLockIMC( himc
))) return FALSE
;
2503 if (!input_context_is_unicode( ctx
))
2506 memcpy( &fontA
, fontW
, offsetof(LOGFONTA
, lfFaceName
) );
2507 WideCharToMultiByte( CP_ACP
, 0, fontW
->lfFaceName
, -1, fontA
.lfFaceName
, LF_FACESIZE
, NULL
, NULL
);
2508 ret
= ImmSetCompositionFontA( himc
, &fontA
);
2512 ctx
->lfFont
.W
= *fontW
;
2513 ctx
->fdwInit
|= INIT_LOGFONT
;
2515 ImmNotifyIME( himc
, NI_CONTEXTUPDATED
, 0, IMC_SETCOMPOSITIONFONT
);
2516 SendMessageW( ctx
->hWnd
, WM_IME_NOTIFY
, IMN_SETCOMPOSITIONFONT
, 0 );
2519 ImmUnlockIMC( himc
);
2524 /***********************************************************************
2525 * ImmSetCompositionStringA (IMM32.@)
2527 BOOL WINAPI
ImmSetCompositionStringA(
2528 HIMC hIMC
, DWORD dwIndex
,
2529 LPCVOID lpComp
, DWORD dwCompLen
,
2530 LPCVOID lpRead
, DWORD dwReadLen
)
2534 WCHAR
*CompBuffer
= NULL
;
2535 WCHAR
*ReadBuffer
= NULL
;
2537 struct imc
*data
= get_imc_data( hIMC
);
2540 TRACE("(%p, %ld, %p, %ld, %p, %ld):\n",
2541 hIMC
, dwIndex
, lpComp
, dwCompLen
, lpRead
, dwReadLen
);
2546 if (NtUserQueryInputContext( hIMC
, NtUserInputContextThreadId
) != GetCurrentThreadId()) return FALSE
;
2548 if (!(dwIndex
== SCS_SETSTR
||
2549 dwIndex
== SCS_CHANGEATTR
||
2550 dwIndex
== SCS_CHANGECLAUSE
||
2551 dwIndex
== SCS_SETRECONVERTSTRING
||
2552 dwIndex
== SCS_QUERYRECONVERTSTRING
))
2555 if (!(ime
= imc_select_ime( data
))) return FALSE
;
2556 if (!ime_is_unicode( ime
)) return ime
->pImeSetCompositionString( hIMC
, dwIndex
, lpComp
, dwCompLen
, lpRead
, dwReadLen
);
2558 comp_len
= MultiByteToWideChar(CP_ACP
, 0, lpComp
, dwCompLen
, NULL
, 0);
2561 CompBuffer
= malloc( comp_len
* sizeof(WCHAR
) );
2562 MultiByteToWideChar(CP_ACP
, 0, lpComp
, dwCompLen
, CompBuffer
, comp_len
);
2565 read_len
= MultiByteToWideChar(CP_ACP
, 0, lpRead
, dwReadLen
, NULL
, 0);
2568 ReadBuffer
= malloc( read_len
* sizeof(WCHAR
) );
2569 MultiByteToWideChar(CP_ACP
, 0, lpRead
, dwReadLen
, ReadBuffer
, read_len
);
2572 rc
= ImmSetCompositionStringW(hIMC
, dwIndex
, CompBuffer
, comp_len
,
2573 ReadBuffer
, read_len
);
2581 /***********************************************************************
2582 * ImmSetCompositionStringW (IMM32.@)
2584 BOOL WINAPI
ImmSetCompositionStringW(
2585 HIMC hIMC
, DWORD dwIndex
,
2586 LPCVOID lpComp
, DWORD dwCompLen
,
2587 LPCVOID lpRead
, DWORD dwReadLen
)
2591 CHAR
*CompBuffer
= NULL
;
2592 CHAR
*ReadBuffer
= NULL
;
2594 struct imc
*data
= get_imc_data( hIMC
);
2597 TRACE("(%p, %ld, %p, %ld, %p, %ld):\n",
2598 hIMC
, dwIndex
, lpComp
, dwCompLen
, lpRead
, dwReadLen
);
2603 if (NtUserQueryInputContext( hIMC
, NtUserInputContextThreadId
) != GetCurrentThreadId()) return FALSE
;
2605 if (!(dwIndex
== SCS_SETSTR
||
2606 dwIndex
== SCS_CHANGEATTR
||
2607 dwIndex
== SCS_CHANGECLAUSE
||
2608 dwIndex
== SCS_SETRECONVERTSTRING
||
2609 dwIndex
== SCS_QUERYRECONVERTSTRING
))
2612 if (!(ime
= imc_select_ime( data
))) return FALSE
;
2613 if (ime_is_unicode( ime
)) return ime
->pImeSetCompositionString( hIMC
, dwIndex
, lpComp
, dwCompLen
, lpRead
, dwReadLen
);
2615 comp_len
= WideCharToMultiByte(CP_ACP
, 0, lpComp
, dwCompLen
, NULL
, 0, NULL
,
2619 CompBuffer
= malloc( comp_len
);
2620 WideCharToMultiByte(CP_ACP
, 0, lpComp
, dwCompLen
, CompBuffer
, comp_len
,
2624 read_len
= WideCharToMultiByte(CP_ACP
, 0, lpRead
, dwReadLen
, NULL
, 0, NULL
,
2628 ReadBuffer
= malloc( read_len
);
2629 WideCharToMultiByte(CP_ACP
, 0, lpRead
, dwReadLen
, ReadBuffer
, read_len
,
2633 rc
= ImmSetCompositionStringA(hIMC
, dwIndex
, CompBuffer
, comp_len
,
2634 ReadBuffer
, read_len
);
2642 /***********************************************************************
2643 * ImmSetCompositionWindow (IMM32.@)
2645 BOOL WINAPI
ImmSetCompositionWindow( HIMC himc
, COMPOSITIONFORM
*composition
)
2649 TRACE( "himc %p, composition %s\n", himc
, debugstr_composition( composition
) );
2651 if (NtUserQueryInputContext( himc
, NtUserInputContextThreadId
) != GetCurrentThreadId()) return FALSE
;
2652 if (!(ctx
= ImmLockIMC( himc
))) return FALSE
;
2654 ctx
->cfCompForm
= *composition
;
2655 ctx
->fdwInit
|= INIT_COMPFORM
;
2657 ImmNotifyIME( himc
, NI_CONTEXTUPDATED
, 0, IMC_SETCOMPOSITIONWINDOW
);
2658 SendMessageW( ctx
->hWnd
, WM_IME_NOTIFY
, IMN_SETCOMPOSITIONWINDOW
, 0 );
2660 ImmUnlockIMC( himc
);
2665 /***********************************************************************
2666 * ImmSetConversionStatus (IMM32.@)
2668 BOOL WINAPI
ImmSetConversionStatus( HIMC himc
, DWORD conversion
, DWORD sentence
)
2670 DWORD old_conversion
, old_sentence
;
2673 TRACE( "himc %p, conversion %#lx, sentence %#lx\n", himc
, conversion
, sentence
);
2675 if (NtUserQueryInputContext( himc
, NtUserInputContextThreadId
) != GetCurrentThreadId()) return FALSE
;
2676 if (!(ctx
= ImmLockIMC( himc
))) return FALSE
;
2678 if (conversion
!= ctx
->fdwConversion
)
2680 old_conversion
= ctx
->fdwConversion
;
2681 ctx
->fdwConversion
= conversion
;
2682 ImmNotifyIME( himc
, NI_CONTEXTUPDATED
, old_conversion
, IMC_SETCONVERSIONMODE
);
2683 SendMessageW( ctx
->hWnd
, WM_IME_NOTIFY
, IMN_SETCONVERSIONMODE
, 0 );
2686 if (sentence
!= ctx
->fdwSentence
)
2688 old_sentence
= ctx
->fdwSentence
;
2689 ctx
->fdwSentence
= sentence
;
2690 ImmNotifyIME( himc
, NI_CONTEXTUPDATED
, old_sentence
, IMC_SETSENTENCEMODE
);
2691 SendMessageW( ctx
->hWnd
, WM_IME_NOTIFY
, IMN_SETSENTENCEMODE
, 0 );
2694 ImmUnlockIMC( himc
);
2699 /***********************************************************************
2700 * ImmSetOpenStatus (IMM32.@)
2702 BOOL WINAPI
ImmSetOpenStatus( HIMC himc
, BOOL status
)
2706 TRACE( "himc %p, status %u\n", himc
, status
);
2708 if (NtUserQueryInputContext( himc
, NtUserInputContextThreadId
) != GetCurrentThreadId()) return FALSE
;
2709 if (!(ctx
= ImmLockIMC( himc
))) return FALSE
;
2711 if (status
!= ctx
->fOpen
)
2713 ctx
->fOpen
= status
;
2714 ImmNotifyIME( himc
, NI_CONTEXTUPDATED
, 0, IMC_SETOPENSTATUS
);
2715 SendMessageW( ctx
->hWnd
, WM_IME_NOTIFY
, IMN_SETOPENSTATUS
, 0 );
2718 ImmUnlockIMC( himc
);
2723 /***********************************************************************
2724 * ImmSetStatusWindowPos (IMM32.@)
2726 BOOL WINAPI
ImmSetStatusWindowPos( HIMC himc
, POINT
*pos
)
2730 TRACE( "himc %p, pos %s\n", himc
, wine_dbgstr_point( pos
) );
2734 SetLastError( ERROR_INVALID_HANDLE
);
2738 if (NtUserQueryInputContext( himc
, NtUserInputContextThreadId
) != GetCurrentThreadId()) return FALSE
;
2739 if (!(ctx
= ImmLockIMC( himc
))) return FALSE
;
2741 ctx
->ptStatusWndPos
= *pos
;
2742 ctx
->fdwInit
|= INIT_STATUSWNDPOS
;
2744 ImmNotifyIME( himc
, NI_CONTEXTUPDATED
, 0, IMC_SETSTATUSWINDOWPOS
);
2745 SendMessageW( ctx
->hWnd
, WM_IME_NOTIFY
, IMN_SETSTATUSWINDOWPOS
, 0 );
2747 ImmUnlockIMC( himc
);
2752 /***********************************************************************
2753 * ImmCreateSoftKeyboard(IMM32.@)
2755 HWND WINAPI
ImmCreateSoftKeyboard(UINT uType
, UINT hOwner
, int x
, int y
)
2757 FIXME("(%d, %d, %d, %d): stub\n", uType
, hOwner
, x
, y
);
2758 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2762 /***********************************************************************
2763 * ImmDestroySoftKeyboard(IMM32.@)
2765 BOOL WINAPI
ImmDestroySoftKeyboard(HWND hSoftWnd
)
2767 FIXME("(%p): stub\n", hSoftWnd
);
2768 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2772 /***********************************************************************
2773 * ImmShowSoftKeyboard(IMM32.@)
2775 BOOL WINAPI
ImmShowSoftKeyboard(HWND hSoftWnd
, int nCmdShow
)
2777 FIXME("(%p, %d): stub\n", hSoftWnd
, nCmdShow
);
2778 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2782 /***********************************************************************
2783 * ImmSimulateHotKey (IMM32.@)
2785 BOOL WINAPI
ImmSimulateHotKey(HWND hWnd
, DWORD dwHotKeyID
)
2787 FIXME("(%p, %ld): stub\n", hWnd
, dwHotKeyID
);
2788 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2792 /***********************************************************************
2793 * ImmUnregisterWordA (IMM32.@)
2795 BOOL WINAPI
ImmUnregisterWordA( HKL hkl
, const char *readingA
, DWORD style
, const char *stringA
)
2800 TRACE( "hkl %p, readingA %s, style %lu, stringA %s.\n", hkl
, debugstr_a(readingA
), style
, debugstr_a(stringA
) );
2802 if (!(ime
= ime_acquire( hkl
))) return FALSE
;
2804 if (!ime_is_unicode( ime
))
2805 ret
= ime
->pImeUnregisterWord( readingA
, style
, stringA
);
2808 WCHAR
*readingW
= strdupAtoW( readingA
), *stringW
= strdupAtoW( stringA
);
2809 ret
= ime
->pImeUnregisterWord( readingW
, style
, stringW
);
2818 /***********************************************************************
2819 * ImmUnregisterWordW (IMM32.@)
2821 BOOL WINAPI
ImmUnregisterWordW( HKL hkl
, const WCHAR
*readingW
, DWORD style
, const WCHAR
*stringW
)
2826 TRACE( "hkl %p, readingW %s, style %lu, stringW %s.\n", hkl
, debugstr_w(readingW
), style
, debugstr_w(stringW
) );
2828 if (!(ime
= ime_acquire( hkl
))) return FALSE
;
2830 if (ime_is_unicode( ime
))
2831 ret
= ime
->pImeUnregisterWord( readingW
, style
, stringW
);
2834 char *readingA
= strdupWtoA( readingW
), *stringA
= strdupWtoA( stringW
);
2835 ret
= ime
->pImeUnregisterWord( readingA
, style
, stringA
);
2844 /***********************************************************************
2845 * ImmGetImeMenuItemsA (IMM32.@)
2847 DWORD WINAPI
ImmGetImeMenuItemsA( HIMC himc
, DWORD flags
, DWORD type
, IMEMENUITEMINFOA
*parentA
,
2848 IMEMENUITEMINFOA
*menuA
, DWORD size
)
2850 struct imc
*data
= get_imc_data( himc
);
2854 TRACE( "himc %p, flags %#lx, type %lu, parentA %p, menuA %p, size %lu.\n",
2855 himc
, flags
, type
, parentA
, menuA
, size
);
2859 SetLastError( ERROR_INVALID_HANDLE
);
2863 if (!(ime
= imc_select_ime( data
))) return 0;
2864 if (!ime_is_unicode( ime
) || (!parentA
&& !menuA
))
2865 ret
= ime
->pImeGetImeMenuItems( himc
, flags
, type
, parentA
, menuA
, size
);
2868 IMEMENUITEMINFOW tmpW
, *menuW
, *parentW
= parentA
? &tmpW
: NULL
;
2870 if (!menuA
) menuW
= NULL
;
2873 int count
= size
/ sizeof(LPIMEMENUITEMINFOA
);
2874 size
= count
* sizeof(IMEMENUITEMINFOW
);
2875 menuW
= malloc( size
);
2878 ret
= ime
->pImeGetImeMenuItems( himc
, flags
, type
, parentW
, menuW
, size
);
2882 memcpy( parentA
, parentW
, sizeof(IMEMENUITEMINFOA
) );
2883 parentA
->hbmpItem
= parentW
->hbmpItem
;
2884 WideCharToMultiByte( CP_ACP
, 0, parentW
->szString
, -1, parentA
->szString
,
2885 IMEMENUITEM_STRING_SIZE
, NULL
, NULL
);
2890 for (i
= 0; i
< ret
; i
++)
2892 memcpy( &menuA
[i
], &menuW
[1], sizeof(IMEMENUITEMINFOA
) );
2893 menuA
[i
].hbmpItem
= menuW
[i
].hbmpItem
;
2894 WideCharToMultiByte( CP_ACP
, 0, menuW
[i
].szString
, -1, menuA
[i
].szString
,
2895 IMEMENUITEM_STRING_SIZE
, NULL
, NULL
);
2904 /***********************************************************************
2905 * ImmGetImeMenuItemsW (IMM32.@)
2907 DWORD WINAPI
ImmGetImeMenuItemsW( HIMC himc
, DWORD flags
, DWORD type
, IMEMENUITEMINFOW
*parentW
,
2908 IMEMENUITEMINFOW
*menuW
, DWORD size
)
2910 struct imc
*data
= get_imc_data( himc
);
2914 TRACE( "himc %p, flags %#lx, type %lu, parentW %p, menuW %p, size %lu.\n",
2915 himc
, flags
, type
, parentW
, menuW
, size
);
2919 SetLastError( ERROR_INVALID_HANDLE
);
2923 if (!(ime
= imc_select_ime( data
))) return 0;
2924 if (ime_is_unicode( ime
) || (!parentW
&& !menuW
))
2925 ret
= ime
->pImeGetImeMenuItems( himc
, flags
, type
, parentW
, menuW
, size
);
2928 IMEMENUITEMINFOA tmpA
, *menuA
, *parentA
= parentW
? &tmpA
: NULL
;
2930 if (!menuW
) menuA
= NULL
;
2933 int count
= size
/ sizeof(LPIMEMENUITEMINFOW
);
2934 size
= count
* sizeof(IMEMENUITEMINFOA
);
2935 menuA
= malloc( size
);
2938 ret
= ime
->pImeGetImeMenuItems( himc
, flags
, type
, parentA
, menuA
, size
);
2942 memcpy( parentW
, parentA
, sizeof(IMEMENUITEMINFOA
) );
2943 parentW
->hbmpItem
= parentA
->hbmpItem
;
2944 MultiByteToWideChar( CP_ACP
, 0, parentA
->szString
, -1, parentW
->szString
, IMEMENUITEM_STRING_SIZE
);
2949 for (i
= 0; i
< ret
; i
++)
2951 memcpy( &menuW
[i
], &menuA
[1], sizeof(IMEMENUITEMINFOA
) );
2952 menuW
[i
].hbmpItem
= menuA
[i
].hbmpItem
;
2953 MultiByteToWideChar( CP_ACP
, 0, menuA
[i
].szString
, -1, menuW
[i
].szString
, IMEMENUITEM_STRING_SIZE
);
2962 /***********************************************************************
2963 * ImmLockIMC(IMM32.@)
2965 INPUTCONTEXT
*WINAPI
ImmLockIMC( HIMC himc
)
2967 struct imc
*imc
= get_imc_data( himc
);
2969 TRACE( "himc %p\n", himc
);
2971 if (!imc
) return NULL
;
2974 imc_select_ime( imc
);
2978 /***********************************************************************
2979 * ImmUnlockIMC(IMM32.@)
2981 BOOL WINAPI
ImmUnlockIMC(HIMC hIMC
)
2983 struct imc
*data
= get_imc_data( hIMC
);
2992 /***********************************************************************
2993 * ImmGetIMCLockCount(IMM32.@)
2995 DWORD WINAPI
ImmGetIMCLockCount(HIMC hIMC
)
2997 struct imc
*data
= get_imc_data( hIMC
);
3000 return data
->dwLock
;
3003 /***********************************************************************
3004 * ImmCreateIMCC(IMM32.@)
3006 HIMCC WINAPI
ImmCreateIMCC(DWORD size
)
3008 return GlobalAlloc(GMEM_ZEROINIT
| GMEM_MOVEABLE
, size
);
3011 /***********************************************************************
3012 * ImmDestroyIMCC(IMM32.@)
3014 HIMCC WINAPI
ImmDestroyIMCC(HIMCC block
)
3016 return GlobalFree(block
);
3019 /***********************************************************************
3020 * ImmLockIMCC(IMM32.@)
3022 LPVOID WINAPI
ImmLockIMCC(HIMCC imcc
)
3024 return GlobalLock(imcc
);
3027 /***********************************************************************
3028 * ImmUnlockIMCC(IMM32.@)
3030 BOOL WINAPI
ImmUnlockIMCC(HIMCC imcc
)
3032 return GlobalUnlock(imcc
);
3035 /***********************************************************************
3036 * ImmGetIMCCLockCount(IMM32.@)
3038 DWORD WINAPI
ImmGetIMCCLockCount(HIMCC imcc
)
3040 return GlobalFlags(imcc
) & GMEM_LOCKCOUNT
;
3043 /***********************************************************************
3044 * ImmReSizeIMCC(IMM32.@)
3046 HIMCC WINAPI
ImmReSizeIMCC(HIMCC imcc
, DWORD size
)
3048 return GlobalReAlloc(imcc
, size
, GMEM_ZEROINIT
| GMEM_MOVEABLE
);
3051 /***********************************************************************
3052 * ImmGetIMCCSize(IMM32.@)
3054 DWORD WINAPI
ImmGetIMCCSize(HIMCC imcc
)
3056 return GlobalSize(imcc
);
3059 /***********************************************************************
3060 * ImmGenerateMessage(IMM32.@)
3062 BOOL WINAPI
ImmGenerateMessage( HIMC himc
)
3066 TRACE( "himc %p\n", himc
);
3068 if (NtUserQueryInputContext( himc
, NtUserInputContextThreadId
) != GetCurrentThreadId()) return FALSE
;
3069 if (!(ctx
= ImmLockIMC( himc
))) return FALSE
;
3071 while (ctx
->dwNumMsgBuf
--)
3073 TRANSMSG
*msgs
, msg
;
3074 if (!(msgs
= ImmLockIMCC( ctx
->hMsgBuf
))) return FALSE
;
3076 memmove( msgs
, msgs
+ 1, ctx
->dwNumMsgBuf
* sizeof(*msgs
) );
3077 ImmUnlockIMCC( ctx
->hMsgBuf
);
3078 SendMessageW( ctx
->hWnd
, msg
.message
, msg
.wParam
, msg
.lParam
);
3085 /***********************************************************************
3086 * ImmTranslateMessage(IMM32.@)
3087 * ( Undocumented, call internally and from user32.dll )
3089 BOOL WINAPI
ImmTranslateMessage( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
3096 TRANSMSG TransMsg
[10];
3099 } buffer
= {.uMsgCount
= ARRAY_SIZE(buffer
.TransMsg
)};
3100 TRANSMSG
*msgs
= buffer
.TransMsg
;
3101 UINT scan
, vkey
, count
, i
;
3107 TRACE( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd
, msg
, wparam
, lparam
);
3109 if (msg
< WM_KEYDOWN
|| msg
> WM_KEYUP
) return FALSE
;
3110 if (!(data
= get_imc_data( ImmGetContext( hwnd
) ))) return FALSE
;
3111 if (!(ime
= imc_select_ime( data
))) return FALSE
;
3113 if ((vkey
= data
->vkey
) == VK_PROCESSKEY
) return FALSE
;
3114 data
->vkey
= VK_PROCESSKEY
;
3115 GetKeyboardState( state
);
3116 scan
= lparam
>> 0x10;
3118 if (ime
->info
.fdwProperty
& IME_PROP_KBD_CHAR_FIRST
)
3120 if (!ime_is_unicode( ime
)) ToAscii( vkey
, scan
, state
, &chr
, 0 );
3121 else ToUnicodeEx( vkey
, scan
, state
, &chr
, 1, 0, GetKeyboardLayout( 0 ) );
3122 vkey
= MAKELONG( vkey
, chr
);
3125 count
= ime
->pImeToAsciiEx( vkey
, scan
, state
, &buffer
.list
, 0, data
->handle
);
3126 if (count
>= ARRAY_SIZE(buffer
.TransMsg
)) return 0;
3128 for (i
= 0; i
< count
; i
++) PostMessageW( hwnd
, msgs
[i
].message
, msgs
[i
].wParam
, msgs
[i
].lParam
);
3129 TRACE( "%u messages generated\n", count
);
3134 /***********************************************************************
3135 * ImmProcessKey(IMM32.@)
3136 * ( Undocumented, called from user32.dll )
3138 BOOL WINAPI
ImmProcessKey( HWND hwnd
, HKL hkl
, UINT vkey
, LPARAM lparam
, DWORD unknown
)
3145 TRACE( "hwnd %p, hkl %p, vkey %#x, lparam %#Ix, unknown %#lx\n", hwnd
, hkl
, vkey
, lparam
, unknown
);
3147 if (hkl
!= GetKeyboardLayout( 0 )) return FALSE
;
3148 if (!(imc
= get_imc_data( ImmGetContext( hwnd
) ))) return FALSE
;
3149 if (!(ime
= imc_select_ime( imc
))) return FALSE
;
3151 GetKeyboardState( state
);
3153 ret
= ime
->pImeProcessKey( imc
->handle
, vkey
, lparam
, state
);
3154 imc
->vkey
= ret
? vkey
: VK_PROCESSKEY
;
3159 /***********************************************************************
3160 * ImmDisableTextFrameService(IMM32.@)
3162 BOOL WINAPI
ImmDisableTextFrameService(DWORD idThread
)
3168 /***********************************************************************
3169 * ImmEnumInputContext(IMM32.@)
3172 BOOL WINAPI
ImmEnumInputContext( DWORD thread
, IMCENUMPROC callback
, LPARAM lparam
)
3178 TRACE( "thread %lu, callback %p, lparam %#Ix\n", thread
, callback
, lparam
);
3180 if ((status
= NtUserBuildHimcList( thread
, ARRAY_SIZE(buffer
), buffer
, &size
)))
3182 RtlSetLastWin32Error( RtlNtStatusToDosError( status
) );
3183 WARN( "NtUserBuildHimcList returned %#lx\n", status
);
3187 if (size
== ARRAY_SIZE(buffer
)) FIXME( "NtUserBuildHimcList returned %u handles\n", size
);
3188 for (i
= 0; i
< size
; i
++) if (!callback( buffer
[i
], lparam
)) return FALSE
;
3193 /***********************************************************************
3194 * ImmGetHotKey(IMM32.@)
3197 BOOL WINAPI
ImmGetHotKey(DWORD hotkey
, UINT
*modifiers
, UINT
*key
, HKL
*hkl
)
3199 FIXME("%lx, %p, %p, %p: stub\n", hotkey
, modifiers
, key
, hkl
);
3203 /***********************************************************************
3204 * ImmDisableLegacyIME(IMM32.@)
3206 BOOL WINAPI
ImmDisableLegacyIME(void)
3212 static BOOL
is_ime_ui_msg(UINT msg
)
3216 case WM_IME_STARTCOMPOSITION
:
3217 case WM_IME_ENDCOMPOSITION
:
3218 case WM_IME_COMPOSITION
:
3219 case WM_IME_SETCONTEXT
:
3221 case WM_IME_CONTROL
:
3222 case WM_IME_COMPOSITIONFULL
:
3225 case WM_IME_REQUEST
:
3226 case WM_IME_KEYDOWN
:
3230 return msg
== WM_MSIME_RECONVERTOPTIONS
||
3231 msg
== WM_MSIME_SERVICE
||
3232 msg
== WM_MSIME_MOUSE
||
3233 msg
== WM_MSIME_RECONVERTREQUEST
||
3234 msg
== WM_MSIME_RECONVERT
||
3235 msg
== WM_MSIME_QUERYPOSITION
||
3236 msg
== WM_MSIME_DOCUMENTFEED
;
3240 static LRESULT
ime_internal_msg( WPARAM wparam
, LPARAM lparam
)
3247 case IME_INTERNAL_ACTIVATE
:
3248 hwnd
= (HWND
)lparam
;
3249 himc
= NtUserGetWindowInputContext( hwnd
);
3250 ImmSetActiveContext( hwnd
, himc
, TRUE
);
3251 set_ime_ui_window_himc( himc
);
3253 case IME_INTERNAL_DEACTIVATE
:
3254 hwnd
= (HWND
)lparam
;
3255 himc
= NtUserGetWindowInputContext( hwnd
);
3256 ImmSetActiveContext( hwnd
, himc
, FALSE
);
3258 case IME_INTERNAL_HKL_ACTIVATE
:
3259 ImmEnumInputContext( 0, enum_activate_layout
, 0 );
3260 if (!(hwnd
= get_ime_ui_window())) break;
3261 SendMessageW( hwnd
, WM_IME_SELECT
, TRUE
, lparam
);
3263 case IME_INTERNAL_HKL_DEACTIVATE
:
3264 if (!(hwnd
= get_ime_ui_window())) break;
3265 SendMessageW( hwnd
, WM_IME_SELECT
, FALSE
, lparam
);
3268 FIXME("wparam = %Ix\n", wparam
);
3275 static void init_messages(void)
3277 static BOOL initialized
;
3279 if (initialized
) return;
3281 WM_MSIME_SERVICE
= RegisterWindowMessageW(L
"MSIMEService");
3282 WM_MSIME_RECONVERTOPTIONS
= RegisterWindowMessageW(L
"MSIMEReconvertOptions");
3283 WM_MSIME_MOUSE
= RegisterWindowMessageW(L
"MSIMEMouseOperation");
3284 WM_MSIME_RECONVERTREQUEST
= RegisterWindowMessageW(L
"MSIMEReconvertRequest");
3285 WM_MSIME_RECONVERT
= RegisterWindowMessageW(L
"MSIMEReconvert");
3286 WM_MSIME_QUERYPOSITION
= RegisterWindowMessageW(L
"MSIMEQueryPosition");
3287 WM_MSIME_DOCUMENTFEED
= RegisterWindowMessageW(L
"MSIMEDocumentFeed");
3291 LRESULT WINAPI
__wine_ime_wnd_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
, BOOL ansi
)
3295 TRACE( "hwnd %p, msg %s, wparam %#Ix, lparam %#Ix, ansi %u\n",
3296 hwnd
, debugstr_wm_ime(msg
), wparam
, lparam
, ansi
);
3306 HWND default_hwnd
= ImmGetDefaultIMEWnd(0);
3307 if (!default_hwnd
|| hwnd
== default_hwnd
)
3308 imm_couninit_thread(TRUE
);
3312 case WM_IME_INTERNAL
:
3313 return ime_internal_msg(wparam
, lparam
);
3316 if (is_ime_ui_msg(msg
))
3318 if ((ui_hwnd
= get_ime_ui_window()))
3321 return SendMessageA(ui_hwnd
, msg
, wparam
, lparam
);
3323 return SendMessageW(ui_hwnd
, msg
, wparam
, lparam
);
3329 return DefWindowProcA(hwnd
, msg
, wparam
, lparam
);
3331 return DefWindowProcW(hwnd
, msg
, wparam
, lparam
);