2 * PROJECT: ReactOS IMM32
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: Implementing Far-Eastern languages input
5 * COPYRIGHT: Copyright 1998 Patrik Stridvall
6 * Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart
7 * Copyright 2017 James Tabor <james.tabor@reactos.org>
8 * Copyright 2018 Amine Khaldi <amine.khaldi@reactos.org>
9 * Copyright 2020 Oleg Dubinskiy <oleg.dubinskij2013@yandex.ua>
10 * Copyright 2020-2021 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
15 WINE_DEFAULT_DEBUG_CHANNEL(imm
);
17 HMODULE g_hImm32Inst
= NULL
;
18 PSERVERINFO g_psi
= NULL
;
19 SHAREDINFO g_SharedInfo
= { NULL
};
20 BYTE g_bClientRegd
= FALSE
;
22 static BOOL APIENTRY
Imm32InitInstance(HMODULE hMod
)
32 status
= RtlInitializeCriticalSection(&g_csImeDpi
);
40 /***********************************************************************
41 * ImmRegisterClient(IMM32.@)
42 * ( Undocumented, called from user32.dll )
44 BOOL WINAPI
ImmRegisterClient(PSHAREDINFO ptr
, HINSTANCE hMod
)
47 g_psi
= g_SharedInfo
.psi
;
48 return Imm32InitInstance(hMod
);
51 /***********************************************************************
52 * ImmLoadLayout (IMM32.@)
54 HKL WINAPI
ImmLoadLayout(HKL hKL
, PIMEINFOEX pImeInfoEx
)
57 UNICODE_STRING UnicodeString
;
58 HKEY hLayoutKey
= NULL
, hLayoutsKey
= NULL
;
61 WCHAR szLayout
[MAX_PATH
];
63 TRACE("(%p, %p)\n", hKL
, pImeInfoEx
);
65 if (IS_IME_HKL(hKL
) ||
66 !g_psi
|| !(g_psi
->dwSRVIFlags
& SRVINFO_CICERO_ENABLED
) ||
67 ((PW32CLIENTINFO
)NtCurrentTeb()->Win32ClientInfo
)->W32ClientInfo
[0] & 2)
69 UnicodeString
.Buffer
= szLayout
;
70 UnicodeString
.MaximumLength
= sizeof(szLayout
);
71 Status
= RtlIntegerToUnicodeString((DWORD_PTR
)hKL
, 16, &UnicodeString
);
72 if (!NT_SUCCESS(Status
))
75 error
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, REGKEY_KEYBOARD_LAYOUTS
, &hLayoutsKey
);
79 error
= RegOpenKeyW(hLayoutsKey
, szLayout
, &hLayoutKey
);
83 error
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, REGKEY_IMM
, &hLayoutKey
);
88 ERR("RegOpenKeyW error: 0x%08lX\n", error
);
93 cbData
= sizeof(pImeInfoEx
->wszImeFile
);
94 error
= RegQueryValueExW(hLayoutKey
, L
"Ime File", 0, 0,
95 (LPBYTE
)pImeInfoEx
->wszImeFile
, &cbData
);
100 RegCloseKey(hLayoutKey
);
102 RegCloseKey(hLayoutsKey
);
106 typedef struct _tagImmHkl
112 WCHAR imeClassName
[17]; /* 16 character max */
116 /* Function Pointers */
117 BOOL (WINAPI
*pImeInquire
)(IMEINFO
*, WCHAR
*, const WCHAR
*);
118 BOOL (WINAPI
*pImeConfigure
)(HKL
, HWND
, DWORD
, void *);
119 BOOL (WINAPI
*pImeDestroy
)(UINT
);
120 LRESULT (WINAPI
*pImeEscape
)(HIMC
, UINT
, void *);
121 BOOL (WINAPI
*pImeSelect
)(HIMC
, BOOL
);
122 BOOL (WINAPI
*pImeSetActiveContext
)(HIMC
, BOOL
);
123 UINT (WINAPI
*pImeToAsciiEx
)(UINT
, UINT
, const BYTE
*, DWORD
*, UINT
, HIMC
);
124 BOOL (WINAPI
*pNotifyIME
)(HIMC
, DWORD
, DWORD
, DWORD
);
125 BOOL (WINAPI
*pImeRegisterWord
)(const WCHAR
*, DWORD
, const WCHAR
*);
126 BOOL (WINAPI
*pImeUnregisterWord
)(const WCHAR
*, DWORD
, const WCHAR
*);
127 UINT (WINAPI
*pImeEnumRegisterWord
)(REGISTERWORDENUMPROCW
, const WCHAR
*, DWORD
, const WCHAR
*, void *);
128 BOOL (WINAPI
*pImeSetCompositionString
)(HIMC
, DWORD
, const void *, DWORD
, const void *, DWORD
);
129 DWORD (WINAPI
*pImeConversionList
)(HIMC
, const WCHAR
*, CANDIDATELIST
*, DWORD
, UINT
);
130 BOOL (WINAPI
*pImeProcessKey
)(HIMC
, UINT
, LPARAM
, const BYTE
*);
131 UINT (WINAPI
*pImeGetRegisterWordStyle
)(UINT
, STYLEBUFW
*);
132 DWORD (WINAPI
*pImeGetImeMenuItems
)(HIMC
, DWORD
, DWORD
, IMEMENUITEMINFOW
*, IMEMENUITEMINFOW
*, DWORD
);
135 typedef struct tagInputContextData
147 #define WINE_IMC_VALID_MAGIC 0x56434D49
149 static const WCHAR szwWineIMCProperty
[] = {'W','i','n','e','I','m','m','H','I','M','C','P','r','o','p','e','r','t','y',0};
150 static const WCHAR szImeFileW
[] = {'I','m','e',' ','F','i','l','e',0};
151 static const WCHAR szLayoutTextW
[] = {'L','a','y','o','u','t',' ','T','e','x','t',0};
152 static const WCHAR szImeRegFmt
[] = {'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s','\\','%','0','8','l','x',0};
154 static inline BOOL
is_himc_ime_unicode(const InputContextData
*data
)
156 return !!(data
->immKbd
->imeInfo
.fdwProperty
& IME_PROP_UNICODE
);
159 static InputContextData
* get_imc_data(HIMC hIMC
)
161 InputContextData
*data
= (InputContextData
*)hIMC
;
166 if(IsBadReadPtr(data
, sizeof(InputContextData
)) || data
->magic
!= WINE_IMC_VALID_MAGIC
)
168 SetLastError(ERROR_INVALID_HANDLE
);
174 static HIMC
get_default_context( HWND hwnd
)
176 FIXME("Don't use this function\n");
180 static BOOL
IMM_IsCrossThreadAccess(HWND hWnd
, HIMC hIMC
)
182 InputContextData
*data
;
186 DWORD thread
= GetWindowThreadProcessId(hWnd
, NULL
);
187 if (thread
!= GetCurrentThreadId()) return TRUE
;
189 data
= get_imc_data(hIMC
);
190 if (data
&& data
->threadID
!= GetCurrentThreadId())
196 /***********************************************************************
197 * ImmAssociateContext (IMM32.@)
199 HIMC WINAPI
ImmAssociateContext(HWND hWnd
, HIMC hIMC
)
202 InputContextData
*data
= get_imc_data(hIMC
);
204 TRACE("(%p, %p):\n", hWnd
, hIMC
);
210 * If already associated just return
212 if (hIMC
&& data
->IMC
.hWnd
== hWnd
)
215 if (hIMC
&& IMM_IsCrossThreadAccess(hWnd
, hIMC
))
220 HIMC defaultContext
= get_default_context( hWnd
);
221 old
= RemovePropW(hWnd
,szwWineIMCProperty
);
224 old
= defaultContext
;
225 else if (old
== (HIMC
)-1)
228 if (hIMC
!= defaultContext
)
230 if (hIMC
== NULL
) /* Meaning disable imm for that window*/
231 SetPropW(hWnd
,szwWineIMCProperty
,(HANDLE
)-1);
233 SetPropW(hWnd
,szwWineIMCProperty
,hIMC
);
238 InputContextData
*old_data
= (InputContextData
*)old
;
239 if (old_data
->IMC
.hWnd
== hWnd
)
240 old_data
->IMC
.hWnd
= NULL
;
247 if(GetActiveWindow() == data
->IMC
.hWnd
)
249 SendMessageW(data
->IMC
.hWnd
, WM_IME_SETCONTEXT
, FALSE
, ISC_SHOWUIALL
);
250 data
->IMC
.hWnd
= hWnd
;
251 SendMessageW(data
->IMC
.hWnd
, WM_IME_SETCONTEXT
, TRUE
, ISC_SHOWUIALL
);
258 * Helper function for ImmAssociateContextEx
260 static BOOL CALLBACK
_ImmAssociateContextExEnumProc(HWND hwnd
, LPARAM lParam
)
262 HIMC hImc
= (HIMC
)lParam
;
263 ImmAssociateContext(hwnd
,hImc
);
267 /***********************************************************************
268 * ImmAssociateContextEx (IMM32.@)
270 BOOL WINAPI
ImmAssociateContextEx(HWND hWnd
, HIMC hIMC
, DWORD dwFlags
)
272 TRACE("(%p, %p, 0x%x):\n", hWnd
, hIMC
, dwFlags
);
280 ImmAssociateContext(hWnd
,hIMC
);
284 HIMC defaultContext
= get_default_context( hWnd
);
285 if (!defaultContext
) return FALSE
;
286 ImmAssociateContext(hWnd
,defaultContext
);
289 case IACE_IGNORENOCONTEXT
:
290 if (GetPropW(hWnd
,szwWineIMCProperty
))
291 ImmAssociateContext(hWnd
,hIMC
);
294 EnumChildWindows(hWnd
,_ImmAssociateContextExEnumProc
,(LPARAM
)hIMC
);
297 FIXME("Unknown dwFlags 0x%x\n",dwFlags
);
302 /***********************************************************************
303 * ImmCreateContext (IMM32.@)
305 HIMC WINAPI
ImmCreateContext(void)
307 PCLIENTIMC pClientImc
;
312 if (g_psi
== NULL
|| !(g_psi
->dwSRVIFlags
& SRVINFO_IMM32
))
315 pClientImc
= Imm32HeapAlloc(HEAP_ZERO_MEMORY
, sizeof(CLIENTIMC
));
316 if (pClientImc
== NULL
)
319 hIMC
= NtUserCreateInputContext(pClientImc
);
322 HeapFree(g_hImm32Heap
, 0, pClientImc
);
326 RtlInitializeCriticalSection(&pClientImc
->cs
);
328 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
329 pClientImc
->unknown
= NtUserGetThreadState(13);
334 static VOID APIENTRY
Imm32CleanupContextExtra(LPINPUTCONTEXT pIC
)
336 FIXME("We have to do something do here");
339 static PCLIENTIMC APIENTRY
Imm32FindClientImc(HIMC hIMC
)
345 BOOL APIENTRY
Imm32CleanupContext(HIMC hIMC
, HKL hKL
, BOOL bKeep
)
349 PCLIENTIMC pClientImc
;
351 if (g_psi
== NULL
|| !(g_psi
->dwSRVIFlags
& SRVINFO_IMM32
) || hIMC
== NULL
)
354 FIXME("We have do something to do here\n");
355 pClientImc
= Imm32FindClientImc(hIMC
);
359 if (pClientImc
->hImc
== NULL
)
361 pClientImc
->dwFlags
|= CLIENTIMC_UNKNOWN1
;
362 ImmUnlockClientImc(pClientImc
);
364 return NtUserDestroyInputContext(hIMC
);
368 pIC
= ImmLockIMC(hIMC
);
371 ImmUnlockClientImc(pClientImc
);
375 FIXME("We have do something to do here\n");
377 if (pClientImc
->hKL
== hKL
)
379 pImeDpi
= ImmLockImeDpi(hKL
);
384 pImeDpi
->ImeSelect(hIMC
, FALSE
);
386 else if (g_psi
&& (g_psi
->dwSRVIFlags
& SRVINFO_CICERO_ENABLED
))
388 FIXME("We have do something to do here\n");
390 ImmUnlockImeDpi(pImeDpi
);
392 pClientImc
->hKL
= NULL
;
395 ImmDestroyIMCC(pIC
->hPrivate
);
396 ImmDestroyIMCC(pIC
->hMsgBuf
);
397 ImmDestroyIMCC(pIC
->hGuideLine
);
398 ImmDestroyIMCC(pIC
->hCandInfo
);
399 ImmDestroyIMCC(pIC
->hCompStr
);
401 Imm32CleanupContextExtra(pIC
);
405 pClientImc
->dwFlags
|= CLIENTIMC_UNKNOWN1
;
406 ImmUnlockClientImc(pClientImc
);
409 return NtUserDestroyInputContext(hIMC
);
414 /***********************************************************************
415 * ImmDestroyContext (IMM32.@)
417 BOOL WINAPI
ImmDestroyContext(HIMC hIMC
)
421 TRACE("(%p)\n", hIMC
);
423 if (g_psi
== NULL
|| !(g_psi
->dwSRVIFlags
& SRVINFO_IMM32
))
426 if (Imm32IsCrossThreadAccess(hIMC
))
429 hKL
= GetKeyboardLayout(0);
430 return Imm32CleanupContext(hIMC
, hKL
, FALSE
);
433 static PCLIENTIMC APIENTRY
Imm32GetClientImcCache(void)
435 // FIXME: Do something properly here
439 /***********************************************************************
440 * ImmLockClientImc (IMM32.@)
442 PCLIENTIMC WINAPI
ImmLockClientImc(HIMC hImc
)
444 PCLIENTIMC pClientImc
;
446 TRACE("(%p)\n", hImc
);
451 pClientImc
= Imm32GetClientImcCache();
454 pClientImc
= Imm32HeapAlloc(HEAP_ZERO_MEMORY
, sizeof(CLIENTIMC
));
458 RtlInitializeCriticalSection(&pClientImc
->cs
);
460 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
461 pClientImc
->unknown
= NtUserGetThreadState(13);
463 if (!NtUserUpdateInputContext(hImc
, 0, pClientImc
))
465 HeapFree(g_hImm32Heap
, 0, pClientImc
);
469 pClientImc
->dwFlags
|= CLIENTIMC_UNKNOWN2
;
473 if (pClientImc
->dwFlags
& CLIENTIMC_UNKNOWN1
)
477 InterlockedIncrement(&pClientImc
->cLockObj
);
481 /***********************************************************************
482 * ImmUnlockClientImc (IMM32.@)
484 VOID WINAPI
ImmUnlockClientImc(PCLIENTIMC pClientImc
)
489 TRACE("(%p)\n", pClientImc
);
491 cLocks
= InterlockedDecrement(&pClientImc
->cLockObj
);
492 if (cLocks
!= 0 || !(pClientImc
->dwFlags
& CLIENTIMC_UNKNOWN1
))
495 hImc
= pClientImc
->hImc
;
499 RtlDeleteCriticalSection(&pClientImc
->cs
);
500 HeapFree(g_hImm32Heap
, 0, pClientImc
);
503 static HIMC APIENTRY
Imm32GetContextEx(HWND hWnd
, DWORD dwContextFlags
)
506 PCLIENTIMC pClientImc
;
509 if (!g_psi
|| !(g_psi
->dwSRVIFlags
& SRVINFO_IMM32
))
514 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
515 hIMC
= (HIMC
)NtUserGetThreadState(4);
519 pWnd
= ValidateHwndNoErr(hWnd
);
520 if (!pWnd
|| Imm32IsCrossProcessAccess(hWnd
))
524 if (!hIMC
&& (dwContextFlags
& 1))
525 hIMC
= (HIMC
)NtUserQueryWindow(hWnd
, QUERY_WINDOW_DEFAULT_ICONTEXT
);
528 pClientImc
= ImmLockClientImc(hIMC
);
529 if (pClientImc
== NULL
)
531 if ((dwContextFlags
& 2) && (pClientImc
->dwFlags
& CLIENTIMC_UNKNOWN3
))
533 ImmUnlockClientImc(pClientImc
);
538 /* Helpers for the GetCompositionString functions */
540 /* Source encoding is defined by context, source length is always given in respective characters. Destination buffer
541 length is always in bytes. */
543 CopyCompStringIMEtoClient(const InputContextData
*data
, const void *src
, INT src_len
, void *dst
,
544 INT dst_len
, BOOL unicode
)
546 int char_size
= unicode
? sizeof(WCHAR
) : sizeof(char);
549 if (is_himc_ime_unicode(data
) ^ unicode
)
552 ret
= MultiByteToWideChar(CP_ACP
, 0, src
, src_len
, dst
, dst_len
/ sizeof(WCHAR
));
554 ret
= WideCharToMultiByte(CP_ACP
, 0, src
, src_len
, dst
, dst_len
, NULL
, NULL
);
561 ret
= min(src_len
* char_size
, dst_len
);
562 memcpy(dst
, src
, ret
);
565 ret
= src_len
* char_size
;
571 /* Composition string encoding is defined by context, returned attributes correspond to string, converted according to
572 passed mode. String length is in characters, attributes are in byte arrays. */
574 CopyCompAttrIMEtoClient(const InputContextData
*data
, const BYTE
*src
, INT src_len
, const void *comp_string
,
575 INT str_len
, BYTE
*dst
, INT dst_len
, BOOL unicode
)
585 string
.str
= comp_string
;
587 if (is_himc_ime_unicode(data
) && !unicode
)
589 rc
= WideCharToMultiByte(CP_ACP
, 0, string
.strW
, str_len
, NULL
, 0, NULL
, NULL
);
596 for (i
= 0; i
< str_len
; ++i
)
600 len
= WideCharToMultiByte(CP_ACP
, 0, string
.strW
+ i
, 1, NULL
, 0, NULL
, NULL
);
601 for (; len
> 0; --len
)
614 else if (!is_himc_ime_unicode(data
) && unicode
)
616 rc
= MultiByteToWideChar(CP_ACP
, 0, string
.strA
, str_len
, NULL
, 0);
623 for (i
= 0; i
< str_len
; ++i
)
625 if (IsDBCSLeadByte(string
.strA
[i
]))
638 memcpy(dst
, src
, min(src_len
, dst_len
));
646 CopyCompClauseIMEtoClient(InputContextData
*data
, LPBYTE source
, INT slen
, LPBYTE ssource
,
647 LPBYTE target
, INT tlen
, BOOL unicode
)
651 if (is_himc_ime_unicode(data
) && !unicode
)
659 tlen
/= sizeof (DWORD
);
660 for (i
= 0; i
< tlen
; ++i
)
662 ((DWORD
*)target
)[i
] = WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)ssource
,
663 ((DWORD
*)source
)[i
],
667 rc
= sizeof (DWORD
) * i
;
672 else if (!is_himc_ime_unicode(data
) && unicode
)
680 tlen
/= sizeof (DWORD
);
681 for (i
= 0; i
< tlen
; ++i
)
683 ((DWORD
*)target
)[i
] = MultiByteToWideChar(CP_ACP
, 0, (LPSTR
)ssource
,
684 ((DWORD
*)source
)[i
],
687 rc
= sizeof (DWORD
) * i
;
694 memcpy( target
, source
, min(slen
,tlen
));
702 CopyCompOffsetIMEtoClient(InputContextData
*data
, DWORD offset
, LPBYTE ssource
, BOOL unicode
)
706 if (is_himc_ime_unicode(data
) && !unicode
)
708 rc
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)ssource
, offset
, NULL
, 0, NULL
, NULL
);
710 else if (!is_himc_ime_unicode(data
) && unicode
)
712 rc
= MultiByteToWideChar(CP_ACP
, 0, (LPSTR
)ssource
, offset
, NULL
, 0);
721 ImmGetCompositionStringT(HIMC hIMC
, DWORD dwIndex
, LPVOID lpBuf
,
722 DWORD dwBufLen
, BOOL unicode
)
725 InputContextData
*data
= get_imc_data(hIMC
);
726 LPCOMPOSITIONSTRING compstr
;
729 TRACE("(%p, 0x%x, %p, %d)\n", hIMC
, dwIndex
, lpBuf
, dwBufLen
);
734 if (!data
->IMC
.hCompStr
)
737 compdata
= ImmLockIMCC(data
->IMC
.hCompStr
);
738 compstr
= (LPCOMPOSITIONSTRING
)compdata
;
743 TRACE("GCS_RESULTSTR\n");
744 rc
= CopyCompStringIMEtoClient(data
, compdata
+ compstr
->dwResultStrOffset
, compstr
->dwResultStrLen
, lpBuf
, dwBufLen
, unicode
);
747 TRACE("GCS_COMPSTR\n");
748 rc
= CopyCompStringIMEtoClient(data
, compdata
+ compstr
->dwCompStrOffset
, compstr
->dwCompStrLen
, lpBuf
, dwBufLen
, unicode
);
751 TRACE("GCS_COMPATTR\n");
752 rc
= CopyCompAttrIMEtoClient(data
, compdata
+ compstr
->dwCompAttrOffset
, compstr
->dwCompAttrLen
,
753 compdata
+ compstr
->dwCompStrOffset
, compstr
->dwCompStrLen
,
754 lpBuf
, dwBufLen
, unicode
);
757 TRACE("GCS_COMPCLAUSE\n");
758 rc
= CopyCompClauseIMEtoClient(data
, compdata
+ compstr
->dwCompClauseOffset
,compstr
->dwCompClauseLen
,
759 compdata
+ compstr
->dwCompStrOffset
,
760 lpBuf
, dwBufLen
, unicode
);
762 case GCS_RESULTCLAUSE
:
763 TRACE("GCS_RESULTCLAUSE\n");
764 rc
= CopyCompClauseIMEtoClient(data
, compdata
+ compstr
->dwResultClauseOffset
,compstr
->dwResultClauseLen
,
765 compdata
+ compstr
->dwResultStrOffset
,
766 lpBuf
, dwBufLen
, unicode
);
768 case GCS_RESULTREADSTR
:
769 TRACE("GCS_RESULTREADSTR\n");
770 rc
= CopyCompStringIMEtoClient(data
, compdata
+ compstr
->dwResultReadStrOffset
, compstr
->dwResultReadStrLen
, lpBuf
, dwBufLen
, unicode
);
772 case GCS_RESULTREADCLAUSE
:
773 TRACE("GCS_RESULTREADCLAUSE\n");
774 rc
= CopyCompClauseIMEtoClient(data
, compdata
+ compstr
->dwResultReadClauseOffset
,compstr
->dwResultReadClauseLen
,
775 compdata
+ compstr
->dwResultStrOffset
,
776 lpBuf
, dwBufLen
, unicode
);
778 case GCS_COMPREADSTR
:
779 TRACE("GCS_COMPREADSTR\n");
780 rc
= CopyCompStringIMEtoClient(data
, compdata
+ compstr
->dwCompReadStrOffset
, compstr
->dwCompReadStrLen
, lpBuf
, dwBufLen
, unicode
);
782 case GCS_COMPREADATTR
:
783 TRACE("GCS_COMPREADATTR\n");
784 rc
= CopyCompAttrIMEtoClient(data
, compdata
+ compstr
->dwCompReadAttrOffset
, compstr
->dwCompReadAttrLen
,
785 compdata
+ compstr
->dwCompReadStrOffset
, compstr
->dwCompReadStrLen
,
786 lpBuf
, dwBufLen
, unicode
);
788 case GCS_COMPREADCLAUSE
:
789 TRACE("GCS_COMPREADCLAUSE\n");
790 rc
= CopyCompClauseIMEtoClient(data
, compdata
+ compstr
->dwCompReadClauseOffset
,compstr
->dwCompReadClauseLen
,
791 compdata
+ compstr
->dwCompStrOffset
,
792 lpBuf
, dwBufLen
, unicode
);
795 TRACE("GCS_CURSORPOS\n");
796 rc
= CopyCompOffsetIMEtoClient(data
, compstr
->dwCursorPos
, compdata
+ compstr
->dwCompStrOffset
, unicode
);
799 TRACE("GCS_DELTASTART\n");
800 rc
= CopyCompOffsetIMEtoClient(data
, compstr
->dwDeltaStart
, compdata
+ compstr
->dwCompStrOffset
, unicode
);
803 FIXME("Unhandled index 0x%x\n",dwIndex
);
807 ImmUnlockIMCC(data
->IMC
.hCompStr
);
812 /***********************************************************************
813 * ImmGetCompositionStringA (IMM32.@)
815 LONG WINAPI
ImmGetCompositionStringA(HIMC hIMC
, DWORD dwIndex
, LPVOID lpBuf
, DWORD dwBufLen
)
817 return ImmGetCompositionStringT(hIMC
, dwIndex
, lpBuf
, dwBufLen
, FALSE
);
820 /***********************************************************************
821 * ImmGetCompositionStringW (IMM32.@)
823 LONG WINAPI
ImmGetCompositionStringW(HIMC hIMC
, DWORD dwIndex
, LPVOID lpBuf
, DWORD dwBufLen
)
825 return ImmGetCompositionStringT(hIMC
, dwIndex
, lpBuf
, dwBufLen
, TRUE
);
828 /***********************************************************************
829 * ImmGetContext (IMM32.@)
831 HIMC WINAPI
ImmGetContext(HWND hWnd
)
833 TRACE("(%p)\n", hWnd
);
836 return Imm32GetContextEx(hWnd
, 2);
839 /***********************************************************************
840 * CtfImmIsCiceroEnabled (IMM32.@)
842 BOOL WINAPI
CtfImmIsCiceroEnabled(VOID
)
844 return (g_psi
&& (g_psi
->dwSRVIFlags
& SRVINFO_CICERO_ENABLED
));
847 /***********************************************************************
848 * ImmInstallIMEA (IMM32.@)
850 HKL WINAPI
ImmInstallIMEA(LPCSTR lpszIMEFileName
, LPCSTR lpszLayoutText
)
853 LPWSTR pszFileNameW
= NULL
, pszLayoutTextW
= NULL
;
855 TRACE("(%s, %s)\n", debugstr_a(lpszIMEFileName
), debugstr_a(lpszLayoutText
));
857 pszFileNameW
= Imm32WideFromAnsi(lpszIMEFileName
);
858 if (pszFileNameW
== NULL
)
861 pszLayoutTextW
= Imm32WideFromAnsi(lpszLayoutText
);
862 if (pszLayoutTextW
== NULL
)
865 hKL
= ImmInstallIMEW(pszFileNameW
, pszLayoutTextW
);
869 HeapFree(g_hImm32Heap
, 0, pszFileNameW
);
871 HeapFree(g_hImm32Heap
, 0, pszLayoutTextW
);
875 /***********************************************************************
876 * ImmInstallIMEW (IMM32.@)
878 HKL WINAPI
ImmInstallIMEW(LPCWSTR lpszIMEFileName
, LPCWSTR lpszLayoutText
)
880 INT lcid
= GetUserDefaultLCID();
885 WCHAR regKey
[ARRAY_SIZE(szImeRegFmt
)+8];
887 TRACE ("(%s, %s):\n", debugstr_w(lpszIMEFileName
),
888 debugstr_w(lpszLayoutText
));
890 /* Start with 2. e001 will be blank and so default to the wine internal IME */
893 while (count
< 0xfff)
895 DWORD disposition
= 0;
897 hkl
= (HKL
)MAKELPARAM( lcid
, 0xe000 | count
);
898 wsprintfW( regKey
, szImeRegFmt
, (ULONG_PTR
)hkl
);
900 rc
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
, regKey
, 0, NULL
, 0, KEY_WRITE
, NULL
, &hkey
, &disposition
);
901 if (rc
== ERROR_SUCCESS
&& disposition
== REG_CREATED_NEW_KEY
)
903 else if (rc
== ERROR_SUCCESS
)
911 WARN("Unable to find slot to install IME\n");
915 if (rc
== ERROR_SUCCESS
)
917 rc
= RegSetValueExW(hkey
, szImeFileW
, 0, REG_SZ
, (const BYTE
*)lpszIMEFileName
,
918 (lstrlenW(lpszIMEFileName
) + 1) * sizeof(WCHAR
));
919 if (rc
== ERROR_SUCCESS
)
920 rc
= RegSetValueExW(hkey
, szLayoutTextW
, 0, REG_SZ
, (const BYTE
*)lpszLayoutText
,
921 (lstrlenW(lpszLayoutText
) + 1) * sizeof(WCHAR
));
927 WARN("Unable to set IME registry values\n");
932 /***********************************************************************
933 * ImmLockIMC(IMM32.@)
935 LPINPUTCONTEXT WINAPI
ImmLockIMC(HIMC hIMC
)
937 InputContextData
*data
= get_imc_data(hIMC
);
945 /***********************************************************************
946 * ImmUnlockIMC(IMM32.@)
948 BOOL WINAPI
ImmUnlockIMC(HIMC hIMC
)
950 PCLIENTIMC pClientImc
;
953 pClientImc
= ImmLockClientImc(hIMC
);
954 if (pClientImc
== NULL
)
957 hClientImc
= pClientImc
->hImc
;
959 LocalUnlock(hClientImc
);
961 InterlockedDecrement(&pClientImc
->cLockObj
);
962 ImmUnlockClientImc(pClientImc
);
966 /***********************************************************************
967 * ImmRequestMessageA(IMM32.@)
969 LRESULT WINAPI
ImmRequestMessageA(HIMC hIMC
, WPARAM wParam
, LPARAM lParam
)
971 InputContextData
*data
= get_imc_data(hIMC
);
973 TRACE("%p %ld %ld\n", hIMC
, wParam
, wParam
);
975 if (data
) return SendMessageA(data
->IMC
.hWnd
, WM_IME_REQUEST
, wParam
, lParam
);
977 SetLastError(ERROR_INVALID_HANDLE
);
981 /***********************************************************************
982 * ImmRequestMessageW(IMM32.@)
984 LRESULT WINAPI
ImmRequestMessageW(HIMC hIMC
, WPARAM wParam
, LPARAM lParam
)
986 InputContextData
*data
= get_imc_data(hIMC
);
988 TRACE("%p %ld %ld\n", hIMC
, wParam
, wParam
);
990 if (data
) return SendMessageW(data
->IMC
.hWnd
, WM_IME_REQUEST
, wParam
, lParam
);
992 SetLastError(ERROR_INVALID_HANDLE
);
996 /***********************************************************************
997 * ImmReleaseContext (IMM32.@)
999 BOOL WINAPI
ImmReleaseContext(HWND hWnd
, HIMC hIMC
)
1001 TRACE("(%p, %p)\n", hWnd
, hIMC
);
1002 UNREFERENCED_PARAMETER(hWnd
);
1003 UNREFERENCED_PARAMETER(hIMC
);
1004 return TRUE
; // Do nothing. This is correct.
1007 /***********************************************************************
1008 * ImmSetCompositionStringA (IMM32.@)
1011 ImmSetCompositionStringA(HIMC hIMC
, DWORD dwIndex
,
1012 LPCVOID lpComp
, DWORD dwCompLen
,
1013 LPCVOID lpRead
, DWORD dwReadLen
)
1017 WCHAR
*CompBuffer
= NULL
;
1018 WCHAR
*ReadBuffer
= NULL
;
1020 InputContextData
*data
= get_imc_data(hIMC
);
1022 TRACE("(%p, %d, %p, %d, %p, %d):\n",
1023 hIMC
, dwIndex
, lpComp
, dwCompLen
, lpRead
, dwReadLen
);
1028 if (!(dwIndex
== SCS_SETSTR
||
1029 dwIndex
== SCS_CHANGEATTR
||
1030 dwIndex
== SCS_CHANGECLAUSE
||
1031 dwIndex
== SCS_SETRECONVERTSTRING
||
1032 dwIndex
== SCS_QUERYRECONVERTSTRING
))
1035 if (!is_himc_ime_unicode(data
))
1036 return data
->immKbd
->pImeSetCompositionString(hIMC
, dwIndex
, lpComp
,
1037 dwCompLen
, lpRead
, dwReadLen
);
1039 comp_len
= MultiByteToWideChar(CP_ACP
, 0, lpComp
, dwCompLen
, NULL
, 0);
1042 CompBuffer
= HeapAlloc(GetProcessHeap(),0,comp_len
* sizeof(WCHAR
));
1043 MultiByteToWideChar(CP_ACP
, 0, lpComp
, dwCompLen
, CompBuffer
, comp_len
);
1046 read_len
= MultiByteToWideChar(CP_ACP
, 0, lpRead
, dwReadLen
, NULL
, 0);
1049 ReadBuffer
= HeapAlloc(GetProcessHeap(),0,read_len
* sizeof(WCHAR
));
1050 MultiByteToWideChar(CP_ACP
, 0, lpRead
, dwReadLen
, ReadBuffer
, read_len
);
1053 rc
= ImmSetCompositionStringW(hIMC
, dwIndex
, CompBuffer
, comp_len
,
1054 ReadBuffer
, read_len
);
1056 HeapFree(GetProcessHeap(), 0, CompBuffer
);
1057 HeapFree(GetProcessHeap(), 0, ReadBuffer
);
1062 /***********************************************************************
1063 * ImmSetCompositionStringW (IMM32.@)
1066 ImmSetCompositionStringW(HIMC hIMC
, DWORD dwIndex
,
1067 LPCVOID lpComp
, DWORD dwCompLen
,
1068 LPCVOID lpRead
, DWORD dwReadLen
)
1072 CHAR
*CompBuffer
= NULL
;
1073 CHAR
*ReadBuffer
= NULL
;
1075 InputContextData
*data
= get_imc_data(hIMC
);
1077 TRACE("(%p, %d, %p, %d, %p, %d):\n",
1078 hIMC
, dwIndex
, lpComp
, dwCompLen
, lpRead
, dwReadLen
);
1083 if (!(dwIndex
== SCS_SETSTR
||
1084 dwIndex
== SCS_CHANGEATTR
||
1085 dwIndex
== SCS_CHANGECLAUSE
||
1086 dwIndex
== SCS_SETRECONVERTSTRING
||
1087 dwIndex
== SCS_QUERYRECONVERTSTRING
))
1090 if (is_himc_ime_unicode(data
))
1091 return data
->immKbd
->pImeSetCompositionString(hIMC
, dwIndex
, lpComp
,
1092 dwCompLen
, lpRead
, dwReadLen
);
1094 comp_len
= WideCharToMultiByte(CP_ACP
, 0, lpComp
, dwCompLen
, NULL
, 0, NULL
,
1098 CompBuffer
= HeapAlloc(GetProcessHeap(),0,comp_len
);
1099 WideCharToMultiByte(CP_ACP
, 0, lpComp
, dwCompLen
, CompBuffer
, comp_len
,
1103 read_len
= WideCharToMultiByte(CP_ACP
, 0, lpRead
, dwReadLen
, NULL
, 0, NULL
,
1107 ReadBuffer
= HeapAlloc(GetProcessHeap(),0,read_len
);
1108 WideCharToMultiByte(CP_ACP
, 0, lpRead
, dwReadLen
, ReadBuffer
, read_len
,
1112 rc
= ImmSetCompositionStringA(hIMC
, dwIndex
, CompBuffer
, comp_len
,
1113 ReadBuffer
, read_len
);
1115 HeapFree(GetProcessHeap(), 0, CompBuffer
);
1116 HeapFree(GetProcessHeap(), 0, ReadBuffer
);
1121 /***********************************************************************
1122 * ImmCreateSoftKeyboard(IMM32.@)
1124 HWND WINAPI
ImmCreateSoftKeyboard(UINT uType
, UINT hOwner
, int x
, int y
)
1126 FIXME("(%d, %d, %d, %d): stub\n", uType
, hOwner
, x
, y
);
1127 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1131 /***********************************************************************
1132 * ImmDestroySoftKeyboard(IMM32.@)
1134 BOOL WINAPI
ImmDestroySoftKeyboard(HWND hSoftWnd
)
1136 TRACE("(%p)\n", hSoftWnd
);
1137 return DestroyWindow(hSoftWnd
);
1140 /***********************************************************************
1141 * ImmShowSoftKeyboard(IMM32.@)
1143 BOOL WINAPI
ImmShowSoftKeyboard(HWND hSoftWnd
, int nCmdShow
)
1145 TRACE("(%p, %d)\n", hSoftWnd
, nCmdShow
);
1147 return ShowWindow(hSoftWnd
, nCmdShow
);
1151 /***********************************************************************
1152 * ImmDisableTextFrameService(IMM32.@)
1154 BOOL WINAPI
ImmDisableTextFrameService(DWORD dwThreadId
)
1160 /***********************************************************************
1161 * ImmEnumInputContext(IMM32.@)
1163 BOOL WINAPI
ImmEnumInputContext(DWORD dwThreadId
, IMCENUMPROC lpfn
, LPARAM lParam
)
1166 DWORD dwIndex
, dwCount
;
1170 TRACE("(%lu, %p, %p)\n", dwThreadId
, lpfn
, lParam
);
1172 dwCount
= Imm32AllocAndBuildHimcList(dwThreadId
, &phList
);
1176 for (dwIndex
= 0; dwIndex
< dwCount
; ++dwIndex
)
1178 hIMC
= phList
[dwIndex
];
1179 ret
= (*lpfn
)(hIMC
, lParam
);
1184 HeapFree(g_hImm32Heap
, 0, phList
);
1188 /***********************************************************************
1189 * ImmSetActiveContext(IMM32.@)
1191 BOOL WINAPI
ImmSetActiveContext(HWND hwnd
, HIMC hIMC
, BOOL fFlag
)
1193 FIXME("(%p, %p, %d): stub\n", hwnd
, hIMC
, fFlag
);
1197 /***********************************************************************
1198 * ImmSetActiveContextConsoleIME(IMM32.@)
1200 BOOL WINAPI
ImmSetActiveContextConsoleIME(HWND hwnd
, BOOL fFlag
)
1203 TRACE("(%p, %d)\n", hwnd
, fFlag
);
1205 hIMC
= ImmGetContext(hwnd
);
1207 return ImmSetActiveContext(hwnd
, hIMC
, fFlag
);
1211 /***********************************************************************
1212 * ImmGetImeMenuItemsA (IMM32.@)
1215 ImmGetImeMenuItemsA(HIMC hIMC
, DWORD dwFlags
, DWORD dwType
,
1216 LPIMEMENUITEMINFOA lpImeParentMenu
,
1217 LPIMEMENUITEMINFOA lpImeMenu
, DWORD dwSize
)
1219 InputContextData
*data
= get_imc_data(hIMC
);
1220 TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC
, dwFlags
, dwType
,
1221 lpImeParentMenu
, lpImeMenu
, dwSize
);
1225 SetLastError(ERROR_INVALID_HANDLE
);
1229 if (data
->immKbd
->hIME
&& data
->immKbd
->pImeGetImeMenuItems
)
1231 if (!is_himc_ime_unicode(data
) || (!lpImeParentMenu
&& !lpImeMenu
))
1232 return data
->immKbd
->pImeGetImeMenuItems(hIMC
, dwFlags
, dwType
,
1233 (IMEMENUITEMINFOW
*)lpImeParentMenu
,
1234 (IMEMENUITEMINFOW
*)lpImeMenu
, dwSize
);
1237 IMEMENUITEMINFOW lpImeParentMenuW
;
1238 IMEMENUITEMINFOW
*lpImeMenuW
, *parent
= NULL
;
1241 if (lpImeParentMenu
)
1242 parent
= &lpImeParentMenuW
;
1245 int count
= dwSize
/ sizeof(LPIMEMENUITEMINFOA
);
1246 dwSize
= count
* sizeof(IMEMENUITEMINFOW
);
1247 lpImeMenuW
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
1252 rc
= data
->immKbd
->pImeGetImeMenuItems(hIMC
, dwFlags
, dwType
,
1253 parent
, lpImeMenuW
, dwSize
);
1255 if (lpImeParentMenu
)
1257 memcpy(lpImeParentMenu
,&lpImeParentMenuW
,sizeof(IMEMENUITEMINFOA
));
1258 lpImeParentMenu
->hbmpItem
= lpImeParentMenuW
.hbmpItem
;
1259 WideCharToMultiByte(CP_ACP
, 0, lpImeParentMenuW
.szString
,
1260 -1, lpImeParentMenu
->szString
, IMEMENUITEM_STRING_SIZE
,
1263 if (lpImeMenu
&& rc
)
1266 for (i
= 0; i
< rc
; i
++)
1268 memcpy(&lpImeMenu
[i
],&lpImeMenuW
[1],sizeof(IMEMENUITEMINFOA
));
1269 lpImeMenu
[i
].hbmpItem
= lpImeMenuW
[i
].hbmpItem
;
1270 WideCharToMultiByte(CP_ACP
, 0, lpImeMenuW
[i
].szString
,
1271 -1, lpImeMenu
[i
].szString
, IMEMENUITEM_STRING_SIZE
,
1275 HeapFree(GetProcessHeap(),0,lpImeMenuW
);
1283 /***********************************************************************
1284 * ImmGetImeMenuItemsW (IMM32.@)
1287 ImmGetImeMenuItemsW(HIMC hIMC
, DWORD dwFlags
, DWORD dwType
,
1288 LPIMEMENUITEMINFOW lpImeParentMenu
,
1289 LPIMEMENUITEMINFOW lpImeMenu
, DWORD dwSize
)
1291 InputContextData
*data
= get_imc_data(hIMC
);
1292 TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC
, dwFlags
, dwType
,
1293 lpImeParentMenu
, lpImeMenu
, dwSize
);
1297 SetLastError(ERROR_INVALID_HANDLE
);
1301 if (data
->immKbd
->hIME
&& data
->immKbd
->pImeGetImeMenuItems
)
1303 if (is_himc_ime_unicode(data
) || (!lpImeParentMenu
&& !lpImeMenu
))
1304 return data
->immKbd
->pImeGetImeMenuItems(hIMC
, dwFlags
, dwType
,
1305 lpImeParentMenu
, lpImeMenu
, dwSize
);
1308 IMEMENUITEMINFOA lpImeParentMenuA
;
1309 IMEMENUITEMINFOA
*lpImeMenuA
, *parent
= NULL
;
1312 if (lpImeParentMenu
)
1313 parent
= &lpImeParentMenuA
;
1316 int count
= dwSize
/ sizeof(LPIMEMENUITEMINFOW
);
1317 dwSize
= count
* sizeof(IMEMENUITEMINFOA
);
1318 lpImeMenuA
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
1323 rc
= data
->immKbd
->pImeGetImeMenuItems(hIMC
, dwFlags
, dwType
,
1324 (IMEMENUITEMINFOW
*)parent
,
1325 (IMEMENUITEMINFOW
*)lpImeMenuA
, dwSize
);
1327 if (lpImeParentMenu
)
1329 memcpy(lpImeParentMenu
,&lpImeParentMenuA
,sizeof(IMEMENUITEMINFOA
));
1330 lpImeParentMenu
->hbmpItem
= lpImeParentMenuA
.hbmpItem
;
1331 MultiByteToWideChar(CP_ACP
, 0, lpImeParentMenuA
.szString
,
1332 -1, lpImeParentMenu
->szString
, IMEMENUITEM_STRING_SIZE
);
1334 if (lpImeMenu
&& rc
)
1337 for (i
= 0; i
< rc
; i
++)
1339 memcpy(&lpImeMenu
[i
],&lpImeMenuA
[1],sizeof(IMEMENUITEMINFOA
));
1340 lpImeMenu
[i
].hbmpItem
= lpImeMenuA
[i
].hbmpItem
;
1341 MultiByteToWideChar(CP_ACP
, 0, lpImeMenuA
[i
].szString
,
1342 -1, lpImeMenu
[i
].szString
, IMEMENUITEM_STRING_SIZE
);
1345 HeapFree(GetProcessHeap(),0,lpImeMenuA
);
1353 BOOL WINAPI
User32InitializeImmEntryTable(DWORD
);
1355 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpReserved
)
1361 TRACE("(%p, 0x%X, %p)\n", hinstDLL
, fdwReason
, lpReserved
);
1365 case DLL_PROCESS_ATTACH
:
1366 //Imm32GenerateRandomSeed(hinstDLL, 1, lpReserved); // Non-sense
1367 if (!Imm32InitInstance(hinstDLL
))
1369 ERR("Imm32InitInstance failed\n");
1372 if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC
))
1374 ERR("User32InitializeImmEntryTable failed\n");
1379 case DLL_THREAD_ATTACH
:
1382 case DLL_THREAD_DETACH
:
1383 if (g_psi
== NULL
|| !(g_psi
->dwSRVIFlags
& SRVINFO_IMM32
))
1386 pTeb
= NtCurrentTeb();
1387 if (pTeb
->Win32ThreadInfo
== NULL
)
1390 hKL
= GetKeyboardLayout(0);
1391 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
1392 hIMC
= (HIMC
)NtUserGetThreadState(4);
1393 Imm32CleanupContext(hIMC
, hKL
, TRUE
);
1396 case DLL_PROCESS_DETACH
:
1397 RtlDeleteCriticalSection(&g_csImeDpi
);
1398 TRACE("imm32.dll is unloaded\n");