Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.ExtLibs/HeuristicLab.AvalonEdit/5.0.1/AvalonEdit-5.0.1/Editing/ImeNativeWrapper.cs

Last change on this file was 11700, checked in by jkarder, 10 years ago

#2077: created branch and added first version

File size: 8.4 KB
Line 
1// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4// software and associated documentation files (the "Software"), to deal in the Software
5// without restriction, including without limitation the rights to use, copy, modify, merge,
6// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7// to whom the Software is furnished to do so, subject to the following conditions:
8//
9// The above copyright notice and this permission notice shall be included in all copies or
10// substantial portions of the Software.
11//
12// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17// DEALINGS IN THE SOFTWARE.
18
19using System;
20using System.Linq;
21using System.Runtime.CompilerServices;
22using System.Runtime.InteropServices;
23using System.Security;
24using System.Windows;
25using System.Windows.Input;
26using System.Windows.Interop;
27using System.Windows.Media;
28using System.Windows.Media.TextFormatting;
29
30using ICSharpCode.AvalonEdit;
31using ICSharpCode.AvalonEdit.Document;
32using ICSharpCode.AvalonEdit.Rendering;
33using ICSharpCode.AvalonEdit.Utils;
34using Draw = System.Drawing;
35
36namespace ICSharpCode.AvalonEdit.Editing
37{
38  /// <summary>
39  /// Native API required for IME support.
40  /// </summary>
41  static class ImeNativeWrapper
42  {
43    [StructLayout(LayoutKind.Sequential)]
44    struct CompositionForm
45    {
46      public int dwStyle;
47      public POINT ptCurrentPos;
48      public RECT rcArea;
49    }
50   
51    [StructLayout(LayoutKind.Sequential)]
52    struct POINT
53    {
54      public int x;
55      public int y;
56    }
57   
58    [StructLayout(LayoutKind.Sequential)]
59    struct RECT
60    {
61      public int left;
62      public int top;
63      public int right;
64      public int bottom;
65    }
66   
67    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
68    struct LOGFONT
69    {
70      public int lfHeight;
71      public int lfWidth;
72      public int lfEscapement;
73      public int lfOrientation;
74      public int lfWeight;
75      public byte lfItalic;
76      public byte lfUnderline;
77      public byte lfStrikeOut;
78      public byte lfCharSet;
79      public byte lfOutPrecision;
80      public byte lfClipPrecision;
81      public byte lfQuality;
82      public byte lfPitchAndFamily;
83      [MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)] public string lfFaceName;
84    }
85   
86    const int CPS_CANCEL = 0x4;
87    const int NI_COMPOSITIONSTR = 0x15;
88    const int GCS_COMPSTR = 0x0008;
89   
90    public const int WM_IME_COMPOSITION = 0x10F;
91    public const int WM_IME_SETCONTEXT = 0x281;
92    public const int WM_INPUTLANGCHANGE = 0x51;
93   
94    [DllImport("imm32.dll")]
95    public static extern IntPtr ImmAssociateContext(IntPtr hWnd, IntPtr hIMC);
96    [DllImport("imm32.dll")]
97    internal static extern IntPtr ImmGetContext(IntPtr hWnd);
98    [DllImport("imm32.dll")]
99    internal static extern IntPtr ImmGetDefaultIMEWnd(IntPtr hWnd);
100    [DllImport("imm32.dll")]
101    [return: MarshalAs(UnmanagedType.Bool)]
102    internal static extern bool ImmReleaseContext(IntPtr hWnd, IntPtr hIMC);
103    [DllImport("imm32.dll")]
104    [return: MarshalAs(UnmanagedType.Bool)]
105    static extern bool ImmNotifyIME(IntPtr hIMC, int dwAction, int dwIndex, int dwValue = 0);
106    [DllImport("imm32.dll")]
107    [return: MarshalAs(UnmanagedType.Bool)]
108    static extern bool ImmSetCompositionWindow(IntPtr hIMC, ref CompositionForm form);
109    [DllImport("imm32.dll", CharSet = CharSet.Unicode)]
110    [return: MarshalAs(UnmanagedType.Bool)]
111    static extern bool ImmSetCompositionFont(IntPtr hIMC, ref LOGFONT font);
112    [DllImport("imm32.dll")]
113    [return: MarshalAs(UnmanagedType.Bool)]
114    static extern bool ImmGetCompositionFont(IntPtr hIMC, out LOGFONT font);
115   
116    [DllImport("msctf.dll")]
117    static extern int TF_CreateThreadMgr(out ITfThreadMgr threadMgr);
118   
119    [ThreadStatic] static bool textFrameworkThreadMgrInitialized;
120    [ThreadStatic] static ITfThreadMgr textFrameworkThreadMgr;
121   
122    public static ITfThreadMgr GetTextFrameworkThreadManager()
123    {
124      if (!textFrameworkThreadMgrInitialized) {
125        textFrameworkThreadMgrInitialized = true;
126        TF_CreateThreadMgr(out textFrameworkThreadMgr);
127      }
128      return textFrameworkThreadMgr;
129    }
130   
131    public static bool NotifyIme(IntPtr hIMC)
132    {
133      return ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL);
134    }
135   
136    public static bool SetCompositionWindow(HwndSource source, IntPtr hIMC, TextArea textArea)
137    {
138      if (textArea == null)
139        throw new ArgumentNullException("textArea");
140      Rect textViewBounds = textArea.TextView.GetBounds(source);
141      Rect characterBounds = textArea.TextView.GetCharacterBounds(textArea.Caret.Position, source);
142      CompositionForm form = new CompositionForm();
143      form.dwStyle = 0x0020;
144      form.ptCurrentPos.x = (int)Math.Max(characterBounds.Left, textViewBounds.Left);
145      form.ptCurrentPos.y = (int)Math.Max(characterBounds.Top, textViewBounds.Top);
146      form.rcArea.left = (int)textViewBounds.Left;
147      form.rcArea.top = (int)textViewBounds.Top;
148      form.rcArea.right = (int)textViewBounds.Right;
149      form.rcArea.bottom = (int)textViewBounds.Bottom;
150      return ImmSetCompositionWindow(hIMC, ref form);
151    }
152   
153    public static bool SetCompositionFont(HwndSource source, IntPtr hIMC, TextArea textArea)
154    {
155      if (textArea == null)
156        throw new ArgumentNullException("textArea");
157      LOGFONT lf = new LOGFONT();
158      Rect characterBounds = textArea.TextView.GetCharacterBounds(textArea.Caret.Position, source);
159      lf.lfFaceName = textArea.FontFamily.Source;
160      lf.lfHeight = (int)characterBounds.Height;
161      return ImmSetCompositionFont(hIMC, ref lf);
162    }
163   
164    static Rect GetBounds(this TextView textView, HwndSource source)
165    {
166      // this may happen during layout changes in AvalonDock, so we just return an empty rectangle
167      // in those cases. It should be refreshed immediately.
168      if (source.RootVisual == null || !source.RootVisual.IsAncestorOf(textView))
169        return EMPTY_RECT;
170      Rect displayRect = new Rect(0, 0, textView.ActualWidth, textView.ActualHeight);
171      return textView
172        .TransformToAncestor(source.RootVisual).TransformBounds(displayRect) // rect on root visual
173        .TransformToDevice(source.RootVisual); // rect on HWND
174    }
175   
176    static readonly Rect EMPTY_RECT = new Rect(0, 0, 0, 0);
177   
178    static Rect GetCharacterBounds(this TextView textView, TextViewPosition pos, HwndSource source)
179    {
180      VisualLine vl = textView.GetVisualLine(pos.Line);
181      if (vl == null)
182        return EMPTY_RECT;
183      // this may happen during layout changes in AvalonDock, so we just return an empty rectangle
184      // in those cases. It should be refreshed immediately.
185      if (source.RootVisual == null || !source.RootVisual.IsAncestorOf(textView))
186        return EMPTY_RECT;
187      TextLine line = vl.GetTextLine(pos.VisualColumn, pos.IsAtEndOfLine);
188      Rect displayRect;
189      // calculate the display rect for the current character
190      if (pos.VisualColumn < vl.VisualLengthWithEndOfLineMarker) {
191        displayRect = line.GetTextBounds(pos.VisualColumn, 1).First().Rectangle;
192        displayRect.Offset(0, vl.GetTextLineVisualYPosition(line, VisualYPosition.LineTop));
193      } else {
194        // if we are in virtual space, we just use one wide-space as character width
195        displayRect = new Rect(vl.GetVisualPosition(pos.VisualColumn, VisualYPosition.TextTop),
196                               new Size(textView.WideSpaceWidth, textView.DefaultLineHeight));
197      }
198      // adjust to current scrolling
199      displayRect.Offset(-textView.ScrollOffset);
200      return textView
201        .TransformToAncestor(source.RootVisual).TransformBounds(displayRect) // rect on root visual
202        .TransformToDevice(source.RootVisual); // rect on HWND
203    }
204  }
205 
206  [ComImport, Guid("aa80e801-2021-11d2-93e0-0060b067b86e"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
207  interface ITfThreadMgr
208  {
209    void Activate(out int clientId);
210    void Deactivate();
211    void CreateDocumentMgr(out IntPtr docMgr);
212    void EnumDocumentMgrs(out IntPtr enumDocMgrs);
213    void GetFocus(out IntPtr docMgr);
214    void SetFocus(IntPtr docMgr);
215    void AssociateFocus(IntPtr hwnd, IntPtr newDocMgr, out IntPtr prevDocMgr);
216    void IsThreadFocus([MarshalAs(UnmanagedType.Bool)] out bool isFocus);
217    void GetFunctionProvider(ref Guid classId, out IntPtr funcProvider);
218    void EnumFunctionProviders(out IntPtr enumProviders);
219    void GetGlobalCompartment(out IntPtr compartmentMgr);
220  }
221}
Note: See TracBrowser for help on using the repository browser.