ReactOS 0.4.16-dev-1520-gb558596
imemenu.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Keyboard Layout Switcher
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: IME menu handling
5 * COPYRIGHT: Copyright 2025 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
6 */
7
8#include "kbswitch.h"
9#include "imemenu.h"
10
11#include <wine/debug.h>
13
16
17static BOOL MakeImeMenu(_In_ HMENU hMenu, _In_ const IMEMENUNODE *pMenu);
18
19static VOID
21{
22 if (!g_pMenuList)
23 {
24 g_pMenuList = pMenu;
25 return;
26 }
27
28 pMenu->m_pNext = g_pMenuList;
29 g_pMenuList = pMenu;
30}
31
32static PIMEMENUNODE
34{
35 SIZE_T cbMenu = sizeof(IMEMENUNODE) + (itemCount - 1) * sizeof(IMEMENUITEM);
36 PIMEMENUNODE pMenu = LocalAlloc(LPTR, cbMenu);
37 if (!pMenu)
38 return NULL;
39 pMenu->m_nItems = itemCount;
40 AddImeMenuNode(pMenu);
41 return pMenu;
42}
43
44static VOID
46 _In_ HIMC hIMC,
47 _Out_ PIMEMENUITEMINFO lpImeParentMenu,
48 _In_ BOOL bRightMenu,
49 _Out_ PIMEMENUITEM pItem)
50{
51 ZeroMemory(pItem, sizeof(IMEMENUITEM));
52 pItem->m_Info = *lpImeParentMenu;
53
54 if (lpImeParentMenu->fType & IMFT_SUBMENU)
55 pItem->m_pSubMenu = CreateImeMenu(hIMC, lpImeParentMenu, bRightMenu);
56
57 pItem->m_nRealID = pItem->m_Info.wID;
58 pItem->m_Info.wID = ID_STARTIMEMENU + g_nNextMenuID++;
59}
60
63 _In_ HIMC hIMC,
64 _Inout_opt_ PIMEMENUITEMINFO lpImeParentMenu,
65 _In_ BOOL bRightMenu)
66{
67 const DWORD dwFlags = (bRightMenu ? IGIMIF_RIGHTMENU : 0);
68 const DWORD dwTypes = IGIMII_CMODE |
69 IGIMII_SMODE |
70 IGIMII_CONFIGURE |
71 IGIMII_TOOLS |
72 IGIMII_HELP |
73 IGIMII_OTHER;
74 DWORD itemCount = ImmGetImeMenuItems(hIMC, dwFlags, dwTypes, lpImeParentMenu, NULL, 0);
75 if (!itemCount)
76 return NULL;
77
78 PIMEMENUNODE pMenu = AllocateImeMenu(itemCount);
79 if (!pMenu)
80 return NULL;
81
82 DWORD cbItems = sizeof(IMEMENUITEMINFO) * itemCount;
83 PIMEMENUITEMINFO pImeMenuItems = LocalAlloc(LPTR, cbItems);
84 if (!pImeMenuItems)
85 {
86 LocalFree(pMenu);
87 return NULL;
88 }
89
90 itemCount = ImmGetImeMenuItems(hIMC, dwFlags, dwTypes, lpImeParentMenu, pImeMenuItems, cbItems);
91 if (!itemCount)
92 {
93 LocalFree(pImeMenuItems);
94 LocalFree(pMenu);
95 return NULL;
96 }
97
99 for (DWORD iItem = 0; iItem < itemCount; ++iItem)
100 {
101 GetImeMenuItem(hIMC, &pImeMenuItems[iItem], bRightMenu, &pItems[iItem]);
102 }
103
104 LocalFree(pImeMenuItems);
105 return pMenu;
106}
107
108static BOOL
110{
111 ZeroMemory(pItemInfo, sizeof(MENUITEMINFO));
112 pItemInfo->cbSize = sizeof(MENUITEMINFO);
113 pItemInfo->fMask = MIIM_ID | MIIM_STATE | MIIM_DATA;
114 pItemInfo->wID = pItem->m_Info.wID;
115 pItemInfo->fState = pItem->m_Info.fState;
116 pItemInfo->dwItemData = pItem->m_Info.dwItemData;
117
118 if (pItem->m_Info.fType)
119 {
120 pItemInfo->fMask |= MIIM_FTYPE;
121 pItemInfo->fType = 0;
122 if (pItem->m_Info.fType & IMFT_RADIOCHECK)
123 pItemInfo->fType |= MFT_RADIOCHECK;
124 if (pItem->m_Info.fType & IMFT_SEPARATOR)
125 pItemInfo->fType |= MFT_SEPARATOR;
126 }
127
128 if (pItem->m_Info.fType & IMFT_SUBMENU)
129 {
130 pItemInfo->fMask |= MIIM_SUBMENU;
131 pItemInfo->hSubMenu = CreatePopupMenu();
132 if (!MakeImeMenu(pItemInfo->hSubMenu, pItem->m_pSubMenu))
133 {
134 DestroyMenu(pItemInfo->hSubMenu);
135 pItemInfo->hSubMenu = NULL;
136 return FALSE;
137 }
138 }
139
140 if (pItem->m_Info.hbmpChecked && pItem->m_Info.hbmpUnchecked)
141 {
142 pItemInfo->fMask |= MIIM_CHECKMARKS;
143 pItemInfo->hbmpChecked = pItem->m_Info.hbmpChecked;
144 pItemInfo->hbmpUnchecked = pItem->m_Info.hbmpUnchecked;
145 }
146
147 if (pItem->m_Info.hbmpItem)
148 {
149 pItemInfo->fMask |= MIIM_BITMAP;
150 pItemInfo->hbmpItem = pItem->m_Info.hbmpItem;
151 }
152
153 PCTSTR szString = pItem->m_Info.szString;
154 if (szString && szString[0])
155 {
156 pItemInfo->fMask |= MIIM_STRING;
157 pItemInfo->dwTypeData = (PTSTR)szString;
158 pItemInfo->cch = lstrlen(szString);
159 }
160
161 return TRUE;
162}
163
164static BOOL
166{
167 if (!pMenu || !pMenu->m_nItems)
168 return FALSE;
169
170 for (INT iItem = 0; iItem < pMenu->m_nItems; ++iItem)
171 {
172 MENUITEMINFO mi = { sizeof(mi) };
173 if (!FillImeMenuItem(&mi, &pMenu->m_Items[iItem]))
174 {
175 ERR("FillImeMenuItem failed\n");
176 return FALSE;
177 }
178 if (!InsertMenuItem(hMenu, iItem, TRUE, &mi))
179 {
180 ERR("InsertMenuItem failed\n");
181 return FALSE;
182 }
183 }
184
185 return TRUE;
186}
187
189{
190 HMENU hMenu = CreatePopupMenu();
191 if (!pMenu)
192 return hMenu;
193 if (!MakeImeMenu(hMenu, pMenu))
194 {
195 DestroyMenu(hMenu);
196 return NULL;
197 }
198 return hMenu;
199}
200
201INT
203{
204 if (!pMenu || !pMenu->m_nItems || nFakeID < ID_STARTIMEMENU)
205 return 0;
206
207 for (INT iItem = 0; iItem < pMenu->m_nItems; ++iItem)
208 {
209 const IMEMENUITEM *pItem = &pMenu->m_Items[iItem];
210 if (pItem->m_Info.wID == nFakeID)
211 return pItem->m_nRealID;
212
213 if (pItem->m_pSubMenu)
214 {
215 INT nRealID = GetRealImeMenuID(pItem->m_pSubMenu, nFakeID);
216 if (nRealID)
217 return nRealID;
218 }
219 }
220
221 return 0;
222}
223
224static BOOL
226{
227 if (!pMenuNode)
228 return FALSE;
229
230 for (INT iItem = 0; iItem < pMenuNode->m_nItems; ++iItem)
231 {
232 PIMEMENUITEM pItem = &pMenuNode->m_Items[iItem];
233 if (pItem->m_Info.hbmpChecked)
234 DeleteObject(pItem->m_Info.hbmpChecked);
235 if (pItem->m_Info.hbmpUnchecked)
236 DeleteObject(pItem->m_Info.hbmpUnchecked);
237 if (pItem->m_Info.hbmpItem)
238 DeleteObject(pItem->m_Info.hbmpItem);
239 }
240
241 LocalFree(pMenuNode);
242 return TRUE;
243}
244
245VOID
247{
248 if (!g_pMenuList)
249 return;
250
251 PIMEMENUNODE pNext;
252 for (PIMEMENUNODE pNode = g_pMenuList; pNode; pNode = pNext)
253 {
254 pNext = pNode->m_pNext;
255 FreeMenuNode(pNode);
256 }
257
259 g_nNextMenuID = 0;
260}
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
INT GetRealImeMenuID(_In_ const IMEMENUNODE *pMenu, _In_ INT nFakeID)
Definition: imemenu.c:202
PIMEMENUNODE CreateImeMenu(_In_ HIMC hIMC, _Inout_opt_ PIMEMENUITEMINFO lpImeParentMenu, _In_ BOOL bRightMenu)
Definition: imemenu.c:62
PIMEMENUNODE g_pMenuList
Definition: imemenu.c:14
static BOOL FreeMenuNode(_In_ PIMEMENUNODE pMenuNode)
Definition: imemenu.c:225
static VOID GetImeMenuItem(_In_ HIMC hIMC, _Out_ PIMEMENUITEMINFO lpImeParentMenu, _In_ BOOL bRightMenu, _Out_ PIMEMENUITEM pItem)
Definition: imemenu.c:45
INT g_nNextMenuID
Definition: imemenu.c:15
static BOOL FillImeMenuItem(_Out_ LPMENUITEMINFO pItemInfo, _In_ const IMEMENUITEM *pItem)
Definition: imemenu.c:109
VOID CleanupImeMenus(VOID)
Definition: imemenu.c:246
HMENU MenuFromImeMenu(_In_ const IMEMENUNODE *pMenu)
Definition: imemenu.c:188
static VOID AddImeMenuNode(_In_ PIMEMENUNODE pMenu)
Definition: imemenu.c:20
static PIMEMENUNODE AllocateImeMenu(_In_ DWORD itemCount)
Definition: imemenu.c:33
static BOOL MakeImeMenu(_In_ HMENU hMenu, _In_ const IMEMENUNODE *pMenu)
Definition: imemenu.c:165
#define ERR(fmt,...)
Definition: precomp.h:57
DWORD HIMC
Definition: dimm.idl:75
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
pKey DeleteObject()
HLOCAL NTAPI LocalAlloc(UINT uFlags, SIZE_T dwBytes)
Definition: heapmem.c:1390
HLOCAL NTAPI LocalFree(HLOCAL hMem)
Definition: heapmem.c:1594
#define ID_STARTIMEMENU
Definition: imemenu.h:12
struct tagIMEMENUNODE IMEMENUNODE
struct tagIMEMENUITEM IMEMENUITEM
LPCWSTR LPCWSTR LPCWSTR DWORD dwFlags
Definition: env.c:37
static const CLSID *static CLSID *static const GUID VARIANT VARIANT *static IServiceProvider DWORD *static HMENU
Definition: ordinal.c:63
static MONITORINFO mi
Definition: win.c:7338
static int int const SCRIPT_CONTROL const SCRIPT_STATE SCRIPT_ITEM * pItems
Definition: usp10.c:62
#define _Inout_opt_
Definition: no_sal2.h:216
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
LPCSTR PCTSTR
Definition: ntbasedef.h:500
UINT m_nRealID
Definition: imemenu.h:19
IMEMENUITEMINFO m_Info
Definition: imemenu.h:18
struct tagIMEMENUNODE * m_pSubMenu
Definition: imemenu.h:20
INT m_nItems
Definition: imemenu.h:26
IMEMENUITEM m_Items[ANYSIZE_ARRAY]
Definition: imemenu.h:27
struct tagIMEMENUNODE * m_pNext
Definition: imemenu.h:25
ULONG_PTR SIZE_T
Definition: typedefs.h:80
int32_t INT
Definition: typedefs.h:58
#define ZeroMemory
Definition: winbase.h:1753
#define LPTR
Definition: winbase.h:414
#define lstrlen
Definition: winbase.h:3917
HMENU WINAPI CreatePopupMenu(void)
Definition: menu.c:838
#define MIIM_STRING
Definition: winuser.h:738
#define MIIM_ID
Definition: winuser.h:733
#define MIIM_CHECKMARKS
Definition: winuser.h:735
#define MIIM_FTYPE
Definition: winuser.h:740
#define InsertMenuItem
Definition: winuser.h:5915
#define MFT_SEPARATOR
Definition: winuser.h:755
#define MIIM_STATE
Definition: winuser.h:732
#define MIIM_SUBMENU
Definition: winuser.h:734
#define MIIM_BITMAP
Definition: winuser.h:739
BOOL WINAPI DestroyMenu(_In_ HMENU)
MENUITEMINFOA MENUITEMINFO
Definition: winuser.h:5831
#define MIIM_DATA
Definition: winuser.h:737
#define MFT_RADIOCHECK
Definition: winuser.h:753
CHAR * PTSTR
Definition: xmlstorage.h:191