// 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.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Windows;
using System.Windows.Controls;
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;
namespace ICSharpCode.AvalonEdit.Editing
{
class ImeSupport
{
readonly TextArea textArea;
IntPtr currentContext;
//IntPtr previousContext;
HwndSource hwndSource;
public ImeSupport(TextArea textArea)
{
if (textArea == null)
throw new ArgumentNullException("textArea");
this.textArea = textArea;
InputMethod.SetIsInputMethodSuspended(this.textArea, true);
textArea.OptionChanged += TextAreaOptionChanged;
currentContext = IntPtr.Zero;
}
void TextAreaOptionChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "EnableImeSupport" && textArea.IsKeyboardFocused) {
CreateContext();
}
}
void ClearContext()
{
if (hwndSource != null) {
//ImeNativeWrapper.AssociateContext(hwndSource, previousContext);
//ImeNativeWrapper.ImmDestroyContext(currentContext);
ImeNativeWrapper.ReleaseContext(hwndSource, currentContext);
currentContext = IntPtr.Zero;
hwndSource.RemoveHook(WndProc);
hwndSource = null;
}
}
public void OnGotFocus(KeyboardFocusChangedEventArgs e)
{
CreateContext();
}
void CreateContext()
{
ClearContext(); // clear old context if necessary
if (!textArea.Options.EnableImeSupport)
return;
hwndSource = (HwndSource)PresentationSource.FromVisual(this.textArea);
if (hwndSource != null) {
//currentContext = ImeNativeWrapper.ImmCreateContext();
//previousContext = ImeNativeWrapper.AssociateContext(hwndSource, currentContext);
currentContext = ImeNativeWrapper.GetContext(hwndSource);
hwndSource.AddHook(WndProc);
// UpdateCompositionWindow() will be called by the caret becoming visible
var threadMgr = ImeNativeWrapper.GetTextFrameworkThreadManager();
if (threadMgr != null) {
// Even though the docu says passing null is invalid, this seems to help
// activating the IME on the default input context that is shared with WPF
threadMgr.SetFocus(IntPtr.Zero);
}
}
}
public void OnLostFocus(KeyboardFocusChangedEventArgs e)
{
if (e.OldFocus == textArea && currentContext != IntPtr.Zero)
ImeNativeWrapper.NotifyIme(currentContext);
ClearContext();
}
IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg) {
case ImeNativeWrapper.WM_INPUTLANGCHANGE:
// Don't mark the message as handled; other windows
// might want to handle it as well.
ClearContext();
CreateContext();
break;
case ImeNativeWrapper.WM_IME_COMPOSITION:
UpdateCompositionWindow();
break;
}
return IntPtr.Zero;
}
public void UpdateCompositionWindow()
{
if (currentContext != IntPtr.Zero) {
ImeNativeWrapper.SetCompositionFont(hwndSource, currentContext, textArea);
ImeNativeWrapper.SetCompositionWindow(hwndSource, currentContext, textArea);
}
}
}
}