1 /* 2 * PROJECT: ReactOS IMM32 3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 4 * PURPOSE: Implementing IMM32 Win3.x compatibility 5 * COPYRIGHT: Copyright 2020-2021 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 6 */ 7 8 #include "precomp.h" 9 10 WINE_DEFAULT_DEBUG_CHANNEL(imm); 11 12 #ifdef IMM_WIN3_SUPPORT /* 3.x support */ 13 14 DWORD APIENTRY 15 ImmNt3JTransCompA(LPINPUTCONTEXTDX pIC, LPCOMPOSITIONSTRING pCS, 16 const TRANSMSG *pSrc, LPTRANSMSG pDest) 17 { 18 // FIXME 19 *pDest = *pSrc; 20 return 1; 21 } 22 23 DWORD APIENTRY 24 ImmNt3JTransCompW(LPINPUTCONTEXTDX pIC, LPCOMPOSITIONSTRING pCS, 25 const TRANSMSG *pSrc, LPTRANSMSG pDest) 26 { 27 // FIXME 28 *pDest = *pSrc; 29 return 1; 30 } 31 32 typedef LRESULT (WINAPI *FN_SendMessage)(HWND, UINT, WPARAM, LPARAM); 33 34 DWORD APIENTRY 35 ImmNt3JTrans(DWORD dwCount, LPTRANSMSG pTrans, LPINPUTCONTEXTDX pIC, 36 LPCOMPOSITIONSTRING pCS, BOOL bAnsi) 37 { 38 DWORD ret = 0; 39 HWND hWnd, hwndDefIME; 40 LPTRANSMSG pTempList, pEntry, pNext; 41 DWORD dwIndex, iCandForm, dwNumber, cbTempList; 42 HGLOBAL hGlobal; 43 CANDIDATEFORM CandForm; 44 FN_SendMessage pSendMessage; 45 46 hWnd = pIC->hWnd; 47 hwndDefIME = ImmGetDefaultIMEWnd(hWnd); 48 pSendMessage = (IsWindowUnicode(hWnd) ? SendMessageW : SendMessageA); 49 50 // clone the message list 51 cbTempList = (dwCount + 1) * sizeof(TRANSMSG); 52 pTempList = ImmLocalAlloc(HEAP_ZERO_MEMORY, cbTempList); 53 if (pTempList == NULL) 54 return 0; 55 RtlCopyMemory(pTempList, pTrans, dwCount * sizeof(TRANSMSG)); 56 57 if (pIC->dwUIFlags & 0x2) 58 { 59 // find WM_IME_ENDCOMPOSITION 60 pEntry = pTempList; 61 for (dwIndex = 0; dwIndex < dwCount; ++dwIndex, ++pEntry) 62 { 63 if (pEntry->message == WM_IME_ENDCOMPOSITION) 64 break; 65 } 66 67 if (pEntry->message == WM_IME_ENDCOMPOSITION) // if found 68 { 69 // move WM_IME_ENDCOMPOSITION to the end of the list 70 for (pNext = pEntry + 1; pNext->message != 0; ++pEntry, ++pNext) 71 *pEntry = *pNext; 72 73 pEntry->message = WM_IME_ENDCOMPOSITION; 74 pEntry->wParam = 0; 75 pEntry->lParam = 0; 76 } 77 } 78 79 for (pEntry = pTempList; pEntry->message != 0; ++pEntry) 80 { 81 switch (pEntry->message) 82 { 83 case WM_IME_STARTCOMPOSITION: 84 if (!(pIC->dwUIFlags & 0x2)) 85 { 86 // send IR_OPENCONVERT 87 if (pIC->cfCompForm.dwStyle != CFS_DEFAULT) 88 pSendMessage(hWnd, WM_IME_REPORT, IR_OPENCONVERT, 0); 89 90 goto DoDefault; 91 } 92 break; 93 94 case WM_IME_ENDCOMPOSITION: 95 if (pIC->dwUIFlags & 0x2) 96 { 97 // send IR_UNDETERMINE 98 hGlobal = GlobalAlloc(GHND | GMEM_SHARE, sizeof(UNDETERMINESTRUCT)); 99 if (hGlobal) 100 { 101 pSendMessage(hWnd, WM_IME_REPORT, IR_UNDETERMINE, (LPARAM)hGlobal); 102 GlobalFree(hGlobal); 103 } 104 } 105 else 106 { 107 // send IR_CLOSECONVERT 108 if (pIC->cfCompForm.dwStyle != CFS_DEFAULT) 109 pSendMessage(hWnd, WM_IME_REPORT, IR_CLOSECONVERT, 0); 110 111 goto DoDefault; 112 } 113 break; 114 115 case WM_IME_COMPOSITION: 116 if (bAnsi) 117 dwNumber = ImmNt3JTransCompA(pIC, pCS, pEntry, pTrans); 118 else 119 dwNumber = ImmNt3JTransCompW(pIC, pCS, pEntry, pTrans); 120 121 ret += dwNumber; 122 pTrans += dwNumber; 123 124 // send IR_CHANGECONVERT 125 if (!(pIC->dwUIFlags & 0x2)) 126 { 127 if (pIC->cfCompForm.dwStyle != CFS_DEFAULT) 128 pSendMessage(hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0); 129 } 130 break; 131 132 case WM_IME_NOTIFY: 133 if (pEntry->wParam == IMN_OPENCANDIDATE) 134 { 135 if (IsWindow(hWnd) && (pIC->dwUIFlags & 0x2)) 136 { 137 // send IMC_SETCANDIDATEPOS 138 for (iCandForm = 0; iCandForm < MAX_CANDIDATEFORM; ++iCandForm) 139 { 140 if (!(pEntry->lParam & (1 << iCandForm))) 141 continue; 142 143 CandForm.dwIndex = iCandForm; 144 CandForm.dwStyle = CFS_EXCLUDE; 145 CandForm.ptCurrentPos = pIC->cfCompForm.ptCurrentPos; 146 CandForm.rcArea = pIC->cfCompForm.rcArea; 147 pSendMessage(hwndDefIME, WM_IME_CONTROL, IMC_SETCANDIDATEPOS, 148 (LPARAM)&CandForm); 149 } 150 } 151 } 152 153 if (!(pIC->dwUIFlags & 0x2)) 154 goto DoDefault; 155 156 // send a WM_IME_NOTIFY notification to the default ime window 157 pSendMessage(hwndDefIME, pEntry->message, pEntry->wParam, pEntry->lParam); 158 break; 159 160 DoDefault: 161 default: 162 // default processing 163 *pTrans++ = *pEntry; 164 ++ret; 165 break; 166 } 167 } 168 169 ImmLocalFree(pTempList); 170 return ret; 171 } 172 173 DWORD APIENTRY 174 ImmNt3KTrans(DWORD dwCount, LPTRANSMSG pEntries, LPINPUTCONTEXTDX pIC, 175 LPCOMPOSITIONSTRING pCS, BOOL bAnsi) 176 { 177 return dwCount; // FIXME 178 } 179 180 DWORD APIENTRY 181 ImmNt3Trans(DWORD dwCount, LPTRANSMSG pEntries, HIMC hIMC, BOOL bAnsi, WORD wLang) 182 { 183 BOOL ret = FALSE; 184 LPINPUTCONTEXTDX pIC; 185 LPCOMPOSITIONSTRING pCS; 186 187 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC); 188 if (pIC == NULL) 189 return 0; 190 191 pCS = ImmLockIMCC(pIC->hCompStr); 192 if (pCS) 193 { 194 if (wLang == LANG_JAPANESE) 195 ret = ImmNt3JTrans(dwCount, pEntries, pIC, pCS, bAnsi); 196 else if (wLang == LANG_KOREAN) 197 ret = ImmNt3KTrans(dwCount, pEntries, pIC, pCS, bAnsi); 198 ImmUnlockIMCC(pIC->hCompStr); 199 } 200 201 ImmUnlockIMC(hIMC); 202 return ret; 203 } 204 205 #endif /* IMM_WIN3_SUPPORT */ 206 207 /*********************************************************************** 208 * ImmSendIMEMessageExA(IMM32.@) 209 */ 210 WORD WINAPI ImmSendIMEMessageExA(HWND hWnd, LPARAM lParam) 211 { 212 FIXME("(%p, %p)\n", hWnd, lParam); 213 return 0; 214 } 215 216 /*********************************************************************** 217 * ImmSendIMEMessageExW(IMM32.@) 218 */ 219 WORD WINAPI ImmSendIMEMessageExW(HWND hWnd, LPARAM lParam) 220 { 221 FIXME("(%p, %p)\n", hWnd, lParam); 222 return 0; 223 } 224