1/* vi:set ts=8 sts=4 sw=4:
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>
41extern "C" {
42#include "vim.h"
43}
44#include "dimm.h"
45#include "glbl_ime.h"
46
47static IActiveIMMApp *pIApp = NULL;
48static IActiveIMMMessagePumpOwner *pIMsg = NULL;
49static HWND s_hWnd = NULL;
50static BOOL s_bStatus = FALSE; /* for evacuate */
51
52/*
53 * Initialize Global IME.
54 * "atom" must be return value of RegisterClass(Ex).
55 */
56    void
57global_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
104global_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
130global_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    {
137#if defined(WIN3264) && defined(FEAT_MBYTE)
138	if (wide_WindowProc)
139	    lResult = DefWindowProcW(hWnd, Msg, wParam, lParam);
140	else
141#endif
142	    lResult = DefWindowProc(hWnd, Msg, wParam, lParam);
143    }
144    return lResult;
145}
146
147/*
148 * Replace with TranslateMessage()
149 */
150    BOOL WINAPI
151global_ime_TranslateMessage(CONST MSG *lpMsg)
152{
153    if (pIMsg == NULL || pIMsg->OnTranslateMessage(lpMsg) == S_FALSE)
154	return TranslateMessage(lpMsg);
155    return TRUE;
156}
157
158/*
159 * Set position of IME compotision window.
160 *
161 * You have to call this before starting composition.  If once composition
162 * started, this can take no effect until that composition have finished.  So
163 * you should handle WM_IME_STARTCOMPOSITION and call this function.
164 */
165    void WINAPI
166global_ime_set_position(POINT *pPoint)
167{
168    HIMC hImc = NULL;
169
170    if (pIApp == NULL || pPoint == NULL)
171	return;
172
173    if (SUCCEEDED(pIApp->GetContext(s_hWnd, &hImc)))
174    {
175	COMPOSITIONFORM CompForm;
176
177	CompForm.dwStyle = CFS_POINT;
178	CompForm.ptCurrentPos = *pPoint;
179	pIApp->SetCompositionWindow(hImc, &CompForm);
180	pIApp->ReleaseContext(s_hWnd, hImc);
181    }
182}
183
184/*
185 * Set font to Global IME
186 */
187/* GIME_TEST */
188    void WINAPI
189global_ime_set_font(LOGFONT *pFont)
190{
191    HIMC hImc = NULL;
192
193    if (pIApp == NULL || pFont == NULL)
194	return;
195
196    if (SUCCEEDED(pIApp->GetContext(s_hWnd, &hImc)))
197    {
198	pIApp->SetCompositionFontA(hImc, pFont);
199	pIApp->ReleaseContext(s_hWnd, hImc);
200    }
201}
202
203#if 0
204/*
205 * for IME control.  Save current status of IME, and set force new-status to
206 * English (turn off).
207 */
208    void WINAPI
209global_ime_status_evacuate()
210{
211    HIMC    hImc;
212
213    if (pIApp != NULL && SUCCEEDED(pIApp->GetContext(s_hWnd, &hImc)))
214    {
215	s_bStatus = (pIApp->GetOpenStatus(hImc) == 0) ? TRUE : FALSE;
216	pIApp->SetOpenStatus(hImc, FALSE);
217	pIApp->ReleaseContext(s_hWnd, hImc);
218    }
219}
220
221/*
222 * for IME control.  Change IME status to last saved one.
223 */
224    void WINAPI
225global_ime_status_restore()
226{
227    HIMC    hImc;
228
229    if (pIApp != NULL && SUCCEEDED(pIApp->GetContext(s_hWnd, &hImc)))
230    {
231	pIApp->SetOpenStatus(hImc, s_bStatus);
232	pIApp->ReleaseContext(s_hWnd, hImc);
233    }
234}
235#endif
236
237    void WINAPI
238global_ime_set_status(int status)
239{
240    HIMC    hImc;
241
242    if (pIApp != NULL && SUCCEEDED(pIApp->GetContext(s_hWnd, &hImc)))
243    {
244	pIApp->SetOpenStatus(hImc, status ? TRUE : FALSE);
245	pIApp->ReleaseContext(s_hWnd, hImc);
246    }
247}
248
249    int WINAPI
250global_ime_get_status()
251{
252    int status = 0;
253    HIMC    hImc;
254
255    if (pIApp != NULL && SUCCEEDED(pIApp->GetContext(s_hWnd, &hImc)))
256    {
257	status = pIApp->GetOpenStatus(hImc) ? 1 : 0;
258	pIApp->ReleaseContext(s_hWnd, hImc);
259    }
260    return status;
261}
262
263#endif /* GLOBAL_IME */
264