You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
5.0 KiB
156 lines
5.0 KiB
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) |
|
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) |
|
|
|
using System; |
|
using System.Linq; |
|
using System.Runtime.CompilerServices; |
|
using System.Runtime.InteropServices; |
|
using System.Security; |
|
using System.Windows; |
|
using System.Windows.Input; |
|
using System.Windows.Interop; |
|
using System.Windows.Media; |
|
using System.Windows.Media.TextFormatting; |
|
|
|
using ICSharpCode.AvalonEdit; |
|
using ICSharpCode.AvalonEdit.Document; |
|
using ICSharpCode.AvalonEdit.Rendering; |
|
using ICSharpCode.AvalonEdit.Utils; |
|
|
|
namespace ICSharpCode.AvalonEdit.Editing |
|
{ |
|
/// <summary> |
|
/// Native API required for IME support. |
|
/// </summary> |
|
static class ImeNativeWrapper |
|
{ |
|
[StructLayout(LayoutKind.Sequential)] |
|
struct CompositionForm |
|
{ |
|
public int dwStyle; |
|
public POINT ptCurrentPos; |
|
public RECT rcArea; |
|
} |
|
|
|
[StructLayout(LayoutKind.Sequential)] |
|
struct POINT |
|
{ |
|
public int x; |
|
public int y; |
|
} |
|
|
|
[StructLayout(LayoutKind.Sequential)] |
|
struct RECT |
|
{ |
|
public int left; |
|
public int top; |
|
public int right; |
|
public int bottom; |
|
} |
|
|
|
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)] |
|
class LOGFONT |
|
{ |
|
public int lfHeight = 0; |
|
public int lfWidth = 0; |
|
public int lfEscapement = 0; |
|
public int lfOrientation = 0; |
|
public int lfWeight = 0; |
|
public byte lfItalic = 0; |
|
public byte lfUnderline = 0; |
|
public byte lfStrikeOut = 0; |
|
public byte lfCharSet = 0; |
|
public byte lfOutPrecision = 0; |
|
public byte lfClipPrecision = 0; |
|
public byte lfQuality = 0; |
|
public byte lfPitchAndFamily = 0; |
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)] public string lfFaceName = null; |
|
} |
|
|
|
const int CPS_CANCEL = 0x4; |
|
const int NI_COMPOSITIONSTR = 0x15; |
|
const int GCS_COMPSTR = 0x0008; |
|
public const int WM_IME_COMPOSITION = 0x10F; |
|
|
|
[DllImport("imm32.dll")] |
|
static extern IntPtr ImmAssociateContext(IntPtr hWnd, IntPtr hIMC); |
|
[DllImport("imm32.dll")] |
|
static extern IntPtr ImmGetContext(IntPtr hWnd); |
|
[DllImport("imm32.dll")] |
|
[return: MarshalAs(UnmanagedType.Bool)] |
|
static extern bool ImmNotifyIME(IntPtr hIMC, int dwAction, int dwIndex, int dwValue = 0); |
|
[DllImport("imm32.dll")] |
|
[return: MarshalAs(UnmanagedType.Bool)] |
|
static extern bool ImmReleaseContext(IntPtr hWnd, IntPtr hIMC); |
|
[DllImport("imm32.dll")] |
|
[return: MarshalAs(UnmanagedType.Bool)] |
|
static extern bool ImmSetCompositionWindow(IntPtr hIMC, ref CompositionForm form); |
|
|
|
public static IntPtr AssociateContext(HwndSource source, IntPtr hIMC) |
|
{ |
|
if (source == null) |
|
throw new ArgumentNullException("source"); |
|
return ImmAssociateContext(source.Handle, hIMC); |
|
} |
|
|
|
public static bool NotifyIme(IntPtr hIMC) |
|
{ |
|
return ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL); |
|
} |
|
|
|
public static IntPtr GetContext(HwndSource source) |
|
{ |
|
if (source == null) |
|
return IntPtr.Zero; |
|
return ImmGetContext(source.Handle); |
|
} |
|
|
|
public static bool ReleaseContext(HwndSource source, IntPtr hIMC) |
|
{ |
|
return source != null && hIMC != IntPtr.Zero && ImmReleaseContext(source.Handle, hIMC); |
|
} |
|
|
|
public static bool SetCompositionWindow(HwndSource source, IntPtr hIMC, TextArea textArea) |
|
{ |
|
if (textArea == null) |
|
throw new ArgumentNullException("textArea"); |
|
Rect textViewBounds = textArea.TextView.GetBounds(); |
|
Rect characterBounds = textArea.TextView.GetCharacterBounds(textArea.Caret.Position, source); |
|
if (source != null) { |
|
Matrix transformToDevice = source.CompositionTarget.TransformToDevice; |
|
textViewBounds.Transform(transformToDevice); |
|
characterBounds.Transform(transformToDevice); |
|
} |
|
CompositionForm form = new CompositionForm(); |
|
form.dwStyle = 0x0020; |
|
form.ptCurrentPos.x = (int)Math.Max(characterBounds.Left, textViewBounds.Left); |
|
form.ptCurrentPos.y = (int)Math.Max(characterBounds.Top, textViewBounds.Top); |
|
form.rcArea.left = (int)textViewBounds.Left; |
|
form.rcArea.top = (int)textViewBounds.Top; |
|
form.rcArea.right = (int)textViewBounds.Right; |
|
form.rcArea.bottom = (int)textViewBounds.Bottom; |
|
return ImmSetCompositionWindow(hIMC, ref form); |
|
} |
|
|
|
static Rect GetBounds(this TextView textView) |
|
{ |
|
Point location = textView.TranslatePoint(new Point(0,0), textView); |
|
return new Rect(location, new Size(textView.ActualWidth, textView.ActualHeight)); |
|
} |
|
|
|
static Rect GetCharacterBounds(this TextView textView, TextViewPosition pos, HwndSource source) |
|
{ |
|
VisualLine vl = textView.GetVisualLine(pos.Line); |
|
if (vl == null) |
|
throw new Exception(); |
|
TextLine line = vl.GetTextLine(pos.VisualColumn); |
|
double offset = vl.GetTextLineVisualYPosition(line, VisualYPosition.LineTop) - textView.ScrollOffset.Y; |
|
Rect r = line.GetTextBounds(pos.VisualColumn, 1).First().Rectangle; |
|
r.Offset(-textView.ScrollOffset.X, offset); |
|
Point pointOnRootVisual = textView.TransformToAncestor(source.RootVisual).Transform(r.Location); |
|
Point pointOnHwnd = pointOnRootVisual.TransformToDevice(source.RootVisual); |
|
r.Location = pointOnHwnd; |
|
return r; |
|
} |
|
} |
|
}
|
|
|