1 /* vi:set ts=8 sts=4 sw=4 noet: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * 5 * Do ":help uganda" in Vim to read copying and usage conditions. 6 * Do ":help credits" in Vim to see a list of people who contributed. 7 */ 8 9 /* 10 * DESCRIPTION: 11 * This module produces Global IME for Vim, on Windows with Internet 12 * Explorer 5.01 or higher. You need three files "dimm.idl", "dimm.h", and 13 * "dimm_i.c" when compile this module at your self. "dimm.h", and 14 * "dimm_i.c" are generated from "dimm.idl" by using MIDL.EXE as like 15 * "if_ole.h". You can get "dimm.idl" in MSDN web site. I got it below 16 * URL. 17 * 18 * WHAT IS THE GLOBAL IME?: 19 * Global IME makes capability input Chinese, Japanese, and Korean text into 20 * Vim buffer on any language version of Windows 98, Windows 95, and Windows 21 * NT 4.0. See below URL for detail of Global IME. You can also find 22 * various language version of Global IME at same place. 23 * 24 * RUNTIME REQUIREMENTS: 25 * - Internet Explorer 5.01 or higher. 26 * - Global IME (with language pack?). 27 * - Of course Vim for Windows. 28 * 29 * URLS: 30 * - Where you can probably get "dimm.idl". 31 * http://msdn.microsoft.com/downloads/samples/internet/libraries/ie5_lib/sample.asp 32 * - Global IME detailed information. 33 * http://www.microsoft.com/windows/ie/features/ime.asp 34 */ 35 36 #ifdef GLOBAL_IME 37 38 #define WIN32_LEAN_AND_MEAN 39 #include <windows.h> 40 #include <objbase.h> 41 extern "C" { 42 #include "vim.h" 43 } 44 #include "dimm.h" 45 #include "glbl_ime.h" 46 47 static IActiveIMMApp *pIApp = NULL; 48 static IActiveIMMMessagePumpOwner *pIMsg = NULL; 49 static HWND s_hWnd = NULL; 50 static BOOL s_bStatus = FALSE; /* for evacuate */ 51 52 /* 53 * Initialize Global IME. 54 * "atom" must be return value of RegisterClass(Ex). 55 */ 56 void 57 global_ime_init(ATOM atom, HWND hWnd) 58 { 59 IUnknown *pI; 60 HRESULT hr; 61 62 if (pIApp != NULL || pIMsg != NULL) 63 return; 64 OleInitialize(NULL); 65 66 /* 67 * Get interface IUnknown 68 */ 69 hr = CoCreateInstance(CLSID_CActiveIMM, NULL, CLSCTX_SERVER, 70 IID_IUnknown, (void**)&pI); 71 if (FAILED(hr) || !pI) 72 return; 73 74 /* 75 * Get interface IActiveIMMApp 76 */ 77 hr = pI->QueryInterface(IID_IActiveIMMApp, (void**)&pIApp); 78 if (FAILED(hr)) 79 pIApp = NULL; 80 81 /* 82 * Get interface IActiveIMMMessagePumpOwner 83 */ 84 hr = pI->QueryInterface(IID_IActiveIMMMessagePumpOwner, (void**)&pIMsg); 85 if (FAILED(hr)) 86 pIMsg = NULL; 87 88 if (pIApp != NULL) 89 { 90 pIApp->Activate(TRUE); 91 pIApp->FilterClientWindows(&atom, 1); 92 } 93 if (pIMsg != NULL) 94 pIMsg->Start(); 95 96 pI->Release(); 97 s_hWnd = hWnd; 98 } 99 100 /* 101 * Reset and clear Global IME. 102 */ 103 void 104 global_ime_end() 105 { 106 if (pIApp != NULL) 107 { 108 IActiveIMMApp *p = pIApp; 109 110 pIApp = NULL; 111 p->FilterClientWindows(NULL, 0); 112 p->Deactivate(); 113 p->Release(); 114 } 115 if (pIMsg != NULL) 116 { 117 IActiveIMMMessagePumpOwner *p = pIMsg; 118 119 pIMsg = NULL; 120 p->End(); 121 p->Release(); 122 } 123 OleUninitialize(); 124 } 125 126 /* 127 * Replacement for DefWindowProc(). 128 */ 129 LRESULT WINAPI 130 global_ime_DefWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) 131 { 132 LRESULT lResult; 133 134 if (pIApp == NULL || pIApp->OnDefWindowProc(hWnd, Msg, 135 wParam, lParam, &lResult) != S_OK) 136 lResult = DefWindowProcW(hWnd, Msg, wParam, lParam); 137 return lResult; 138 } 139 140 /* 141 * Replace with TranslateMessage() 142 */ 143 BOOL WINAPI 144 global_ime_TranslateMessage(CONST MSG *lpMsg) 145 { 146 if (pIMsg == NULL || pIMsg->OnTranslateMessage(lpMsg) == S_FALSE) 147 return TranslateMessage(lpMsg); 148 return TRUE; 149 } 150 151 /* 152 * Set position of IME composition window. 153 * 154 * You have to call this before starting composition. If once composition 155 * started, this can take no effect until that composition have finished. So 156 * you should handle WM_IME_STARTCOMPOSITION and call this function. 157 */ 158 void WINAPI 159 global_ime_set_position(POINT *pPoint) 160 { 161 HIMC hImc = NULL; 162 163 if (pIApp == NULL || pPoint == NULL) 164 return; 165 166 if (SUCCEEDED(pIApp->GetContext(s_hWnd, &hImc))) 167 { 168 COMPOSITIONFORM CompForm; 169 170 CompForm.dwStyle = CFS_POINT; 171 CompForm.ptCurrentPos = *pPoint; 172 pIApp->SetCompositionWindow(hImc, &CompForm); 173 pIApp->ReleaseContext(s_hWnd, hImc); 174 } 175 } 176 177 /* 178 * Set font to Global IME 179 */ 180 /* GIME_TEST */ 181 void WINAPI 182 global_ime_set_font(LOGFONT *pFont) 183 { 184 HIMC hImc = NULL; 185 186 if (pIApp == NULL || pFont == NULL) 187 return; 188 189 if (SUCCEEDED(pIApp->GetContext(s_hWnd, &hImc))) 190 { 191 pIApp->SetCompositionFontA(hImc, pFont); 192 pIApp->ReleaseContext(s_hWnd, hImc); 193 } 194 } 195 196 #if 0 197 /* 198 * for IME control. Save current status of IME, and set force new-status to 199 * English (turn off). 200 */ 201 void WINAPI 202 global_ime_status_evacuate() 203 { 204 HIMC hImc; 205 206 if (pIApp != NULL && SUCCEEDED(pIApp->GetContext(s_hWnd, &hImc))) 207 { 208 s_bStatus = (pIApp->GetOpenStatus(hImc) == 0) ? TRUE : FALSE; 209 pIApp->SetOpenStatus(hImc, FALSE); 210 pIApp->ReleaseContext(s_hWnd, hImc); 211 } 212 } 213 214 /* 215 * for IME control. Change IME status to last saved one. 216 */ 217 void WINAPI 218 global_ime_status_restore() 219 { 220 HIMC hImc; 221 222 if (pIApp != NULL && SUCCEEDED(pIApp->GetContext(s_hWnd, &hImc))) 223 { 224 pIApp->SetOpenStatus(hImc, s_bStatus); 225 pIApp->ReleaseContext(s_hWnd, hImc); 226 } 227 } 228 #endif 229 230 void WINAPI 231 global_ime_set_status(int status) 232 { 233 HIMC hImc; 234 235 if (pIApp != NULL && SUCCEEDED(pIApp->GetContext(s_hWnd, &hImc))) 236 { 237 pIApp->SetOpenStatus(hImc, status ? TRUE : FALSE); 238 pIApp->ReleaseContext(s_hWnd, hImc); 239 } 240 } 241 242 int WINAPI 243 global_ime_get_status() 244 { 245 int status = 0; 246 HIMC hImc; 247 248 if (pIApp != NULL && SUCCEEDED(pIApp->GetContext(s_hWnd, &hImc))) 249 { 250 status = pIApp->GetOpenStatus(hImc) ? 1 : 0; 251 pIApp->ReleaseContext(s_hWnd, hImc); 252 } 253 return status; 254 } 255 256 #endif /* GLOBAL_IME */ 257