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
global_ime_init(ATOM atom,HWND hWnd)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
global_ime_end()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
global_ime_DefWindowProc(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam)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
global_ime_TranslateMessage(CONST MSG * lpMsg)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
global_ime_set_position(POINT * pPoint)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
global_ime_set_font(LOGFONT * pFont)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
global_ime_set_status(int status)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
global_ime_get_status()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