2 * PROJECT: ReactOS IMM32
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: Implementing IMM32 helper functions
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 HANDLE g_hImm32Heap
= NULL
;
19 BOOL WINAPI
Imm32IsImcAnsi(HIMC hIMC
)
22 PCLIENTIMC pClientImc
= ImmLockClientImc(hIMC
);
25 ret
= !(pClientImc
->dwFlags
& CLIENTIMC_WIDE
);
26 ImmUnlockClientImc(pClientImc
);
30 LPWSTR APIENTRY
Imm32WideFromAnsi(LPCSTR pszA
)
32 INT cch
= lstrlenA(pszA
);
33 LPWSTR pszW
= Imm32HeapAlloc(0, (cch
+ 1) * sizeof(WCHAR
));
36 cch
= MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, pszA
, cch
, pszW
, cch
+ 1);
41 LPSTR APIENTRY
Imm32AnsiFromWide(LPCWSTR pszW
)
43 INT cchW
= lstrlenW(pszW
);
44 INT cchA
= (cchW
+ 1) * sizeof(WCHAR
);
45 LPSTR pszA
= Imm32HeapAlloc(0, cchA
);
48 cchA
= WideCharToMultiByte(CP_ACP
, 0, pszW
, cchW
, pszA
, cchA
, NULL
, NULL
);
53 /* Converts the character index */
54 LONG APIENTRY
IchWideFromAnsi(LONG cchAnsi
, LPCSTR pchAnsi
, UINT uCodePage
)
57 for (cchWide
= 0; cchAnsi
> 0; ++cchWide
)
59 if (IsDBCSLeadByteEx(uCodePage
, *pchAnsi
) && pchAnsi
[1])
73 /* Converts the character index */
74 LONG APIENTRY
IchAnsiFromWide(LONG cchWide
, LPCWSTR pchWide
, UINT uCodePage
)
77 for (cchAnsi
= 0; cchWide
> 0; ++cchAnsi
, ++pchWide
, --cchWide
)
79 cb
= WideCharToMultiByte(uCodePage
, 0, pchWide
, 1, NULL
, 0, NULL
, NULL
);
86 BOOL
Imm32GetSystemLibraryPath(LPWSTR pszPath
, DWORD cchPath
, LPCWSTR pszFileName
)
88 if (!pszFileName
[0] || !GetSystemDirectoryW(pszPath
, cchPath
))
90 StringCchCatW(pszPath
, cchPath
, L
"\\");
91 StringCchCatW(pszPath
, cchPath
, pszFileName
);
95 VOID APIENTRY
LogFontAnsiToWide(const LOGFONTA
*plfA
, LPLOGFONTW plfW
)
98 RtlCopyMemory(plfW
, plfA
, offsetof(LOGFONTA
, lfFaceName
));
99 StringCchLengthA(plfA
->lfFaceName
, _countof(plfA
->lfFaceName
), &cch
);
100 cch
= MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, plfA
->lfFaceName
, (INT
)cch
,
101 plfW
->lfFaceName
, _countof(plfW
->lfFaceName
));
102 if (cch
> _countof(plfW
->lfFaceName
) - 1)
103 cch
= _countof(plfW
->lfFaceName
) - 1;
104 plfW
->lfFaceName
[cch
] = 0;
107 VOID APIENTRY
LogFontWideToAnsi(const LOGFONTW
*plfW
, LPLOGFONTA plfA
)
110 RtlCopyMemory(plfA
, plfW
, offsetof(LOGFONTW
, lfFaceName
));
111 StringCchLengthW(plfW
->lfFaceName
, _countof(plfW
->lfFaceName
), &cch
);
112 cch
= WideCharToMultiByte(CP_ACP
, 0, plfW
->lfFaceName
, (INT
)cch
,
113 plfA
->lfFaceName
, _countof(plfA
->lfFaceName
), NULL
, NULL
);
114 if (cch
> _countof(plfA
->lfFaceName
) - 1)
115 cch
= _countof(plfA
->lfFaceName
) - 1;
116 plfA
->lfFaceName
[cch
] = 0;
119 LPVOID FASTCALL
ValidateHandleNoErr(HANDLE hObject
, UINT uType
)
122 PUSER_HANDLE_TABLE ht
;
123 PUSER_HANDLE_ENTRY he
;
126 if (!NtUserValidateHandleSecure(hObject
))
129 ht
= g_SharedInfo
.aheList
; /* handle table */
131 /* ReactOS-Specific! */
132 ASSERT(g_SharedInfo
.ulSharedDelta
!= 0);
133 he
= (PUSER_HANDLE_ENTRY
)((ULONG_PTR
)ht
->handles
- g_SharedInfo
.ulSharedDelta
);
135 index
= (LOWORD(hObject
) - FIRST_USER_HANDLE
) >> 1;
136 if (index
< 0 || ht
->nb_handles
<= index
|| he
[index
].type
!= uType
)
139 generation
= HIWORD(hObject
);
140 if (generation
!= he
[index
].generation
&& generation
&& generation
!= 0xFFFF)
146 PWND FASTCALL
ValidateHwndNoErr(HWND hwnd
)
148 /* See if the window is cached */
149 PCLIENTINFO ClientInfo
= GetWin32ClientInfo();
150 if (hwnd
== ClientInfo
->CallbackWnd
.hWnd
)
151 return ClientInfo
->CallbackWnd
.pWnd
;
153 return ValidateHandleNoErr(hwnd
, TYPE_WINDOW
);
156 BOOL APIENTRY
Imm32CheckImcProcess(PIMC pIMC
)
160 if (pIMC
->head
.pti
== NtCurrentTeb()->Win32ThreadInfo
)
164 dwProcessID
= NtUserQueryInputContext(hIMC
, 0);
165 return dwProcessID
== (DWORD_PTR
)NtCurrentTeb()->ClientId
.UniqueProcess
;
168 LPVOID APIENTRY
Imm32HeapAlloc(DWORD dwFlags
, DWORD dwBytes
)
172 g_hImm32Heap
= RtlGetProcessHeap();
173 if (g_hImm32Heap
== NULL
)
176 return HeapAlloc(g_hImm32Heap
, dwFlags
, dwBytes
);
180 Imm32NotifyAction(HIMC hIMC
, HWND hwnd
, DWORD dwAction
, DWORD_PTR dwIndex
, DWORD_PTR dwValue
,
181 DWORD_PTR dwCommand
, DWORD_PTR dwData
)
189 dwThreadId
= NtUserQueryInputContext(hIMC
, 1);
192 /* find keyboard layout and lock it */
193 hKL
= GetKeyboardLayout(dwThreadId
);
194 pImeDpi
= ImmLockImeDpi(hKL
);
198 pImeDpi
->NotifyIME(hIMC
, dwAction
, dwIndex
, dwValue
);
200 ImmUnlockImeDpi(pImeDpi
); /* unlock */
205 if (hwnd
&& dwCommand
)
206 SendMessageW(hwnd
, WM_IME_NOTIFY
, dwCommand
, dwData
);
211 DWORD APIENTRY
Imm32AllocAndBuildHimcList(DWORD dwThreadId
, HIMC
**pphList
)
213 #define INITIAL_COUNT 0x40
216 DWORD dwCount
= INITIAL_COUNT
, cRetry
= 0;
219 phNewList
= Imm32HeapAlloc(0, dwCount
* sizeof(HIMC
));
220 if (phNewList
== NULL
)
223 Status
= NtUserBuildHimcList(dwThreadId
, dwCount
, phNewList
, &dwCount
);
224 while (Status
== STATUS_BUFFER_TOO_SMALL
)
226 Imm32HeapFree(phNewList
);
227 if (cRetry
++ >= MAX_RETRY
)
230 phNewList
= Imm32HeapAlloc(0, dwCount
* sizeof(HIMC
));
231 if (phNewList
== NULL
)
234 Status
= NtUserBuildHimcList(dwThreadId
, dwCount
, phNewList
, &dwCount
);
237 if (NT_ERROR(Status
) || !dwCount
)
239 Imm32HeapFree(phNewList
);
243 *pphList
= phNewList
;
250 Imm32ImeMenuAnsiToWide(const IMEMENUITEMINFOA
*pItemA
, LPIMEMENUITEMINFOW pItemW
,
251 UINT uCodePage
, BOOL bBitmap
)
254 pItemW
->cbSize
= pItemA
->cbSize
;
255 pItemW
->fType
= pItemA
->fType
;
256 pItemW
->fState
= pItemA
->fState
;
257 pItemW
->wID
= pItemA
->wID
;
260 pItemW
->hbmpChecked
= pItemA
->hbmpChecked
;
261 pItemW
->hbmpUnchecked
= pItemA
->hbmpUnchecked
;
262 pItemW
->hbmpItem
= pItemA
->hbmpItem
;
264 pItemW
->dwItemData
= pItemA
->dwItemData
;
265 ret
= MultiByteToWideChar(uCodePage
, 0, pItemA
->szString
, -1,
266 pItemW
->szString
, _countof(pItemW
->szString
));
267 if (ret
>= _countof(pItemW
->szString
))
270 pItemW
->szString
[0] = 0;
276 Imm32ImeMenuWideToAnsi(const IMEMENUITEMINFOW
*pItemW
, LPIMEMENUITEMINFOA pItemA
,
280 pItemA
->cbSize
= pItemW
->cbSize
;
281 pItemA
->fType
= pItemW
->fType
;
282 pItemA
->fState
= pItemW
->fState
;
283 pItemA
->wID
= pItemW
->wID
;
284 pItemA
->hbmpChecked
= pItemW
->hbmpChecked
;
285 pItemA
->hbmpUnchecked
= pItemW
->hbmpUnchecked
;
286 pItemA
->dwItemData
= pItemW
->dwItemData
;
287 pItemA
->hbmpItem
= pItemW
->hbmpItem
;
288 ret
= WideCharToMultiByte(uCodePage
, 0, pItemW
->szString
, -1,
289 pItemA
->szString
, _countof(pItemA
->szString
), NULL
, NULL
);
290 if (ret
>= _countof(pItemA
->szString
))
293 pItemA
->szString
[0] = 0;
299 Imm32FetchImeState(LPINPUTCONTEXTDX pIC
, HKL hKL
)
302 WORD Lang
= PRIMARYLANGID(LOWORD(hKL
));
303 for (pState
= pIC
->pState
; pState
; pState
= pState
->pNext
)
305 if (pState
->wLang
== Lang
)
310 pState
= Imm32HeapAlloc(HEAP_ZERO_MEMORY
, sizeof(IME_STATE
));
313 pState
->wLang
= Lang
;
314 pState
->pNext
= pIC
->pState
;
315 pIC
->pState
= pState
;
321 PIME_SUBSTATE APIENTRY
322 Imm32FetchImeSubState(PIME_STATE pState
, HKL hKL
)
324 PIME_SUBSTATE pSubState
;
325 for (pSubState
= pState
->pSubState
; pSubState
; pSubState
= pSubState
->pNext
)
327 if (pSubState
->hKL
== hKL
)
330 pSubState
= Imm32HeapAlloc(0, sizeof(IME_SUBSTATE
));
333 pSubState
->dwValue
= 0;
334 pSubState
->hKL
= hKL
;
335 pSubState
->pNext
= pState
->pSubState
;
336 pState
->pSubState
= pSubState
;
341 Imm32LoadImeStateSentence(LPINPUTCONTEXTDX pIC
, PIME_STATE pState
, HKL hKL
)
343 PIME_SUBSTATE pSubState
= Imm32FetchImeSubState(pState
, hKL
);
346 pIC
->fdwSentence
|= pSubState
->dwValue
;
353 Imm32SaveImeStateSentence(LPINPUTCONTEXTDX pIC
, PIME_STATE pState
, HKL hKL
)
355 PIME_SUBSTATE pSubState
= Imm32FetchImeSubState(pState
, hKL
);
358 pSubState
->dwValue
= (pIC
->fdwSentence
& 0xffff0000);
364 /***********************************************************************
365 * CtfImmIsTextFrameServiceDisabled(IMM32.@)
367 BOOL WINAPI
CtfImmIsTextFrameServiceDisabled(VOID
)
369 return !!(GetWin32ClientInfo()->CI_flags
& CI_TFSDISABLED
);
372 /***********************************************************************
373 * ImmCreateIMCC(IMM32.@)
375 HIMCC WINAPI
ImmCreateIMCC(DWORD size
)
377 if (size
< sizeof(DWORD
))
378 size
= sizeof(DWORD
);
379 return LocalAlloc(LHND
, size
);
382 /***********************************************************************
383 * ImmDestroyIMCC(IMM32.@)
385 HIMCC WINAPI
ImmDestroyIMCC(HIMCC block
)
388 return LocalFree(block
);
392 /***********************************************************************
393 * ImmLockIMCC(IMM32.@)
395 LPVOID WINAPI
ImmLockIMCC(HIMCC imcc
)
398 return LocalLock(imcc
);
402 /***********************************************************************
403 * ImmUnlockIMCC(IMM32.@)
405 BOOL WINAPI
ImmUnlockIMCC(HIMCC imcc
)
408 return LocalUnlock(imcc
);
412 /***********************************************************************
413 * ImmGetIMCCLockCount(IMM32.@)
415 DWORD WINAPI
ImmGetIMCCLockCount(HIMCC imcc
)
417 return LocalFlags(imcc
) & LMEM_LOCKCOUNT
;
420 /***********************************************************************
421 * ImmReSizeIMCC(IMM32.@)
423 HIMCC WINAPI
ImmReSizeIMCC(HIMCC imcc
, DWORD size
)
427 return LocalReAlloc(imcc
, size
, LHND
);
430 /***********************************************************************
431 * ImmGetIMCCSize(IMM32.@)
433 DWORD WINAPI
ImmGetIMCCSize(HIMCC imcc
)
436 return LocalSize(imcc
);
440 /***********************************************************************
441 * ImmGetIMCLockCount(IMM32.@)
443 DWORD WINAPI
ImmGetIMCLockCount(HIMC hIMC
)
446 HANDLE hInputContext
;
447 PCLIENTIMC pClientImc
;
449 pClientImc
= ImmLockClientImc(hIMC
);
450 if (pClientImc
== NULL
)
454 hInputContext
= pClientImc
->hInputContext
;
456 ret
= (LocalFlags(hInputContext
) & LMEM_LOCKCOUNT
);
458 ImmUnlockClientImc(pClientImc
);
462 /***********************************************************************
463 * ImmIMPGetIMEA(IMM32.@)
465 BOOL WINAPI
ImmIMPGetIMEA(HWND hWnd
, LPIMEPROA pImePro
)
467 FIXME("(%p, %p)\n", hWnd
, pImePro
);
471 /***********************************************************************
472 * ImmIMPGetIMEW(IMM32.@)
474 BOOL WINAPI
ImmIMPGetIMEW(HWND hWnd
, LPIMEPROW pImePro
)
476 FIXME("(%p, %p)\n", hWnd
, pImePro
);
480 /***********************************************************************
481 * ImmIMPQueryIMEA(IMM32.@)
483 BOOL WINAPI
ImmIMPQueryIMEA(LPIMEPROA pImePro
)
485 FIXME("(%p)\n", pImePro
);
489 /***********************************************************************
490 * ImmIMPQueryIMEW(IMM32.@)
492 BOOL WINAPI
ImmIMPQueryIMEW(LPIMEPROW pImePro
)
494 FIXME("(%p)\n", pImePro
);
498 /***********************************************************************
499 * ImmIMPSetIMEA(IMM32.@)
501 BOOL WINAPI
ImmIMPSetIMEA(HWND hWnd
, LPIMEPROA pImePro
)
503 FIXME("(%p, %p)\n", hWnd
, pImePro
);
507 /***********************************************************************
508 * ImmIMPSetIMEW(IMM32.@)
510 BOOL WINAPI
ImmIMPSetIMEW(HWND hWnd
, LPIMEPROW pImePro
)
512 FIXME("(%p, %p)\n", hWnd
, pImePro
);