2 * Copyright (C) 2013 FooProject
\r
3 * * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
\r
4 * the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
\r
6 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
7 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
\r
9 You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
\r
12 using System.Drawing;
\r
13 using System.Windows.Forms;
\r
14 using System.Runtime.InteropServices;
\r
16 using GDIP = System.Drawing;
\r
18 namespace FooEditEngine.Windows
\r
20 internal class StartCompstionEventArgs : EventArgs
\r
24 internal class EndCompstionEventArgs : EventArgs
\r
28 internal class ImeCompstionEventArgs : EventArgs
\r
33 public string InputText;
\r
34 public ImeCompstionEventArgs(string text)
\r
36 this.InputText = text;
\r
40 internal class ImeDocumentFeedEventArgs : EventArgs
\r
45 public string Pragraph = string.Empty;
\r
52 internal class ImeQueryRecovertStringEventArgs : EventArgs
\r
55 /// IMEによって調整された再変換文字列の開始位置
\r
59 /// IMEによって調整された再変換文字列の長さ
\r
62 public ImeQueryRecovertStringEventArgs(int offset, int length)
\r
64 this.offset = offset;
\r
65 this.length = length;
\r
69 internal class ImeReconvertStringEventArgs : EventArgs
\r
72 /// IMEに再変換の対象となる文字列を調整させる場合は真
\r
74 public bool AutoAdjust = false;
\r
78 public string TargetString = string.Empty;
\r
82 public GDIP.Point CaretPostion = GDIP.Point.Empty;
\r
85 internal delegate void StartCompstionEventHandeler(object sender, StartCompstionEventArgs e);
\r
86 internal delegate void EndCompstionEventHandeler(object sender, EndCompstionEventArgs e);
\r
87 internal delegate void ImeCompstionEventHandeler(object sender, ImeCompstionEventArgs e);
\r
88 internal delegate void ImeDocumentFeedEventHandler(object sender, ImeDocumentFeedEventArgs e);
\r
89 internal delegate void ImeReconvertStringEventHandler(object sender, ImeReconvertStringEventArgs e);
\r
90 internal delegate void ImeQueryReconvertStringEventHandler(object sender,ImeQueryRecovertStringEventArgs e);
\r
92 internal class WinIME : NativeWindow
\r
94 [StructLayout(LayoutKind.Sequential)]
\r
97 public POINT(int x, int y) { this.x = x; this.y = y; }
\r
98 public POINT(GDIP.Point pt) { x = pt.X; y = pt.Y; }
\r
102 [StructLayout(LayoutKind.Sequential)]
\r
105 public RECT(System.Drawing.Rectangle rect)
\r
109 right = rect.Right;
\r
110 bottom = rect.Bottom;
\r
112 public Int32 left, top, right, bottom;
\r
115 [StructLayout(LayoutKind.Sequential)]
\r
116 struct COMPOSITIONFORM
\r
118 public UInt32 style;
\r
119 public POINT currentPos;
\r
123 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
\r
124 struct RECONVERTSTRING
\r
126 public UInt32 dwSize;
\r
127 public UInt32 dwVersion;
\r
128 public UInt32 dwStrLen;
\r
129 public UInt32 dwStrOffset;
\r
130 public UInt32 dwCompStrLen;
\r
131 public UInt32 dwCompStrOffset;
\r
132 public UInt32 dwTargetStrLen;
\r
133 public UInt32 dwTargetStrOffset;
\r
136 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
\r
139 public const int LF_FACESIZE = 32;
\r
140 public int lfHeight;
\r
141 public int lfWidth;
\r
142 public int lfEscapement;
\r
143 public int lfOrientation;
\r
144 public int lfWeight;
\r
145 public byte lfItalic;
\r
146 public byte lfUnderline;
\r
147 public byte lfStrikeOut;
\r
148 public byte lfCharSet;
\r
149 public byte lfOutPrecision;
\r
150 public byte lfClipPrecision;
\r
151 public byte lfQuality;
\r
152 public byte lfPitchAndFamily;
\r
153 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = LF_FACESIZE)]
\r
154 public string lfFaceName;
\r
157 const Int32 GCS_COMPREADSTR = 0x0001;
\r
158 const Int32 GCS_COMPSTR = 0x0008;
\r
159 const Int32 GCS_RESULTSTR = 0x0800;
\r
160 const Int32 SCS_SETSTR = (GCS_COMPREADSTR | GCS_COMPSTR);
\r
161 const int WM_IME_STARTCOMPOSITION = 0x010D;
\r
162 const int WM_IME_ENDCOMPOSITION = 0x010E;
\r
163 const int WM_IME_COMPOSITION = 0x010F;
\r
164 const int WM_IME_NOTIFY = 0x0282;
\r
165 const int WM_IME_CHAR = 0x0286;
\r
166 const int WM_IME_REQUEST = 0x0288;
\r
167 const int CFS_POINT = 0x0002;
\r
168 const int IMR_RECONVERTSTRING = 0x0004;
\r
169 const int IMR_DOCUMENTFEED = 0x0007;
\r
170 const int SCS_QUERYRECONVERTSTRING = 0x00020000;
\r
172 [DllImport("imm32.dll")]
\r
173 static extern IntPtr ImmGetContext(IntPtr hWnd);
\r
175 [DllImport("imm32.dll")]
\r
176 static extern Int32 ImmReleaseContext(IntPtr hWnd, IntPtr context);
\r
178 [DllImport("imm32.dll")]
\r
179 static unsafe extern Int32 ImmGetCompositionStringW(IntPtr imContext, UInt32 index, void* out_string, UInt32 maxStringLen);
\r
181 [DllImport("imm32.dll")]
\r
182 static unsafe extern Int32 ImmSetCompositionStringW(IntPtr imContext, UInt32 index, void* lpComp, UInt32 dwCompLen, void* lpRead, UInt32 readLen);
\r
184 [DllImport("imm32.dll")]
\r
185 static unsafe extern Int32 ImmSetCompositionWindow(IntPtr imContext, COMPOSITIONFORM* compForm);
\r
187 [DllImport("imm32.dll")]
\r
188 static unsafe extern Int32 ImmSetCompositionFontW (IntPtr hIMC,[In, MarshalAs(UnmanagedType.LPStruct)] LOGFONT lplf);
\r
190 [DllImport("imm32.dll")]
\r
191 static extern UInt32 ImmGetProperty(IntPtr inputLocale, UInt32 index);
\r
193 [DllImport("user32.dll")]
\r
194 static extern IntPtr GetKeyboardLayout(UInt32 threadID);
\r
196 public WinIME(Control ctrl)
\r
198 if (ctrl.IsHandleCreated)
\r
199 this.AssignHandle(ctrl.Handle);
\r
200 ctrl.HandleCreated += new EventHandler(ctrl_HandleCreated);
\r
201 ctrl.HandleDestroyed += new EventHandler(ctrl_HandleDestroyed);
\r
202 this.StartCompstion += new StartCompstionEventHandeler((s,e)=>{});
\r
203 this.EndCompstion +=new EndCompstionEventHandeler((s,e)=>{});
\r
204 this.ImeCompstion +=new ImeCompstionEventHandeler((s,e)=>{});
\r
205 this.ImeDocumentFeed += new ImeDocumentFeedEventHandler((s,e)=>{});
\r
206 this.ImeReconvert += new ImeReconvertStringEventHandler((s, e) => { });
\r
207 this.ImeQueryReconvert += new ImeQueryReconvertStringEventHandler((s,e)=>{});
\r
210 public event StartCompstionEventHandeler StartCompstion;
\r
211 public event EndCompstionEventHandeler EndCompstion;
\r
212 public event ImeCompstionEventHandeler ImeCompstion;
\r
213 public event ImeDocumentFeedEventHandler ImeDocumentFeed;
\r
214 public event ImeReconvertStringEventHandler ImeReconvert;
\r
215 public event ImeQueryReconvertStringEventHandler ImeQueryReconvert;
\r
218 /// コンポジッションウィンドウの位置
\r
220 public GDIP.Point Location
\r
222 get { throw new NotImplementedException(); }
\r
225 this.SetImeCompstionWindowPos(this.Handle, value.X,value.Y);
\r
234 get { throw new NotImplementedException(); }
\r
237 SetImeWindowFont(this.Handle, value);
\r
241 protected override void WndProc(ref Message m)
\r
245 case WinIME.WM_IME_CHAR:
\r
246 m.Result = IntPtr.Zero;
\r
248 case WinIME.WM_IME_COMPOSITION:
\r
249 if ((m.LParam.ToInt32() & WinIME.GCS_RESULTSTR) != 0)
\r
251 string text = GetImeCompstionString(this.Handle);
\r
252 this.ImeCompstion(this, new ImeCompstionEventArgs(text));
\r
255 case WinIME.WM_IME_STARTCOMPOSITION:
\r
256 this.StartCompstion(this, new StartCompstionEventArgs());
\r
258 case WinIME.WM_IME_ENDCOMPOSITION:
\r
259 this.EndCompstion(this, new EndCompstionEventArgs());
\r
261 case WinIME.WM_IME_REQUEST:
\r
262 if ((int)m.WParam == WinIME.IMR_DOCUMENTFEED)
\r
264 m.Result = HandleIMR_DocumnetFeed(m.LParam);
\r
267 if ((int)m.WParam == WinIME.IMR_RECONVERTSTRING)
\r
269 m.Result = HandleIMR_ReconvertString(m.LParam);
\r
274 base.WndProc(ref m);
\r
277 unsafe private IntPtr HandleIMR_ReconvertString(IntPtr lParam)
\r
279 ImeReconvertStringEventArgs e = new ImeReconvertStringEventArgs();
\r
280 this.ImeReconvert(this, e);
\r
281 RECONVERTSTRING* reconv = (RECONVERTSTRING*)lParam.ToPointer();
\r
282 char* paragraph = (char*)((byte*)reconv + sizeof(RECONVERTSTRING));
\r
283 int reconvlen = sizeof(RECONVERTSTRING) + e.TargetString.Length * sizeof(char);
\r
284 if (reconv != null)
\r
286 reconv->dwSize = (uint)sizeof(RECONVERTSTRING);
\r
287 reconv->dwVersion = 0;
\r
288 reconv->dwStrLen = (uint)e.TargetString.Length;
\r
289 reconv->dwStrOffset = (uint)sizeof(RECONVERTSTRING);
\r
290 reconv->dwTargetStrLen = 0;
\r
291 reconv->dwTargetStrOffset = 0;
\r
292 for (int i = 0; i < e.TargetString.Length; i++)
\r
293 paragraph[i] = e.TargetString[i];
\r
296 IntPtr ime = ImmGetContext(this.Handle);
\r
297 ImmSetCompositionStringW(ime, SCS_QUERYRECONVERTSTRING, reconv, (uint)reconvlen, (void*)IntPtr.Zero, 0);
\r
298 ImmReleaseContext(this.Handle, ime);
\r
299 this.ImeQueryReconvert(this, new ImeQueryRecovertStringEventArgs((int)reconv->dwTargetStrOffset, (int)reconv->dwTargetStrLen));
\r
303 reconv->dwCompStrLen = (uint)e.TargetString.Length;
\r
304 reconv->dwCompStrOffset = 0;
\r
307 this.Location = e.CaretPostion;
\r
309 return new IntPtr(reconvlen);
\r
312 unsafe private IntPtr HandleIMR_DocumnetFeed(IntPtr lParam)
\r
314 ImeDocumentFeedEventArgs e = new ImeDocumentFeedEventArgs();
\r
315 this.ImeDocumentFeed(this, e);
\r
316 if (lParam.ToInt32() != 0)
\r
318 if (e.pos > e.Pragraph.Length)
\r
319 e.pos = e.Pragraph.Length;
\r
320 else if (e.pos < 0)
\r
323 RECONVERTSTRING* reconv = (RECONVERTSTRING*)lParam.ToPointer();
\r
324 char* paragraph = (char*)((byte*)reconv + sizeof(RECONVERTSTRING));
\r
325 reconv->dwSize = (uint)sizeof(RECONVERTSTRING);
\r
326 reconv->dwVersion = 0;
\r
327 reconv->dwStrLen = (uint)e.Pragraph.Length;
\r
328 reconv->dwStrOffset = (uint)sizeof(RECONVERTSTRING);
\r
329 reconv->dwCompStrLen = 0;
\r
330 reconv->dwCompStrOffset = 0;
\r
331 reconv->dwTargetStrLen = 0;
\r
332 reconv->dwTargetStrOffset = (uint)e.pos * sizeof(char);
\r
333 for (int i = 0; i < e.Pragraph.Length; i++)
\r
334 paragraph[i] = e.Pragraph[i];
\r
336 return new IntPtr(sizeof(RECONVERTSTRING) + e.Pragraph.Length * sizeof(char));
\r
339 void ctrl_HandleCreated(object sender, EventArgs e)
\r
341 Control ctrl = (Control)sender;
\r
342 this.AssignHandle(ctrl.Handle);
\r
345 void ctrl_HandleDestroyed(object sender, EventArgs e)
\r
347 this.ReleaseHandle();
\r
350 string GetImeCompstionString(IntPtr window)
\r
358 ime = ImmGetContext(window);
\r
359 len = ImmGetCompositionStringW(ime, GCS_RESULTSTR, null, 0);
\r
360 fixed (char* buf = new char[len + 1])
\r
362 ImmGetCompositionStringW(ime, GCS_RESULTSTR, (void*)buf, (uint)len);
\r
364 text = new String(buf);
\r
366 ImmReleaseContext(window, ime);
\r
371 void SetImeCompstionWindowPos(IntPtr window, int x,int y)
\r
374 imContext = ImmGetContext(window);
\r
376 COMPOSITIONFORM compForm = new COMPOSITIONFORM();
\r
379 compForm.style = CFS_POINT;
\r
380 compForm.currentPos = new POINT(x, y);
\r
381 compForm.area = new RECT();
\r
383 ImmSetCompositionWindow(imContext, &compForm);
\r
386 ImmReleaseContext(window, imContext);
\r
389 void SetImeWindowFont(IntPtr window, Font font)
\r
392 LOGFONT logicalFont = new LOGFONT();
\r
394 font.ToLogFont(logicalFont);
\r
396 imContext = ImmGetContext(window);
\r
399 ImmSetCompositionFontW(imContext, logicalFont);
\r
401 ImmReleaseContext(window, imContext);
\r