Browse Source

Simplify IME integration a bit

pull/28/head
Daniel Grunwald 13 years ago
parent
commit
827dbee0d4
  1. 4
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Caret.cs
  2. 11
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/ImeNativeWrapper.cs
  3. 43
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/ImeSupport.cs
  4. 6
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextArea.cs

4
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Caret.cs

@ -22,7 +22,6 @@ namespace ICSharpCode.AvalonEdit.Editing
{ {
readonly TextArea textArea; readonly TextArea textArea;
readonly TextView textView; readonly TextView textView;
readonly ImeSupport ime;
readonly CaretLayer caretAdorner; readonly CaretLayer caretAdorner;
bool visible; bool visible;
@ -31,7 +30,6 @@ namespace ICSharpCode.AvalonEdit.Editing
this.textArea = textArea; this.textArea = textArea;
this.textView = textArea.TextView; this.textView = textArea.TextView;
position = new TextViewPosition(1, 1, 0); position = new TextViewPosition(1, 1, 0);
ime = new ImeSupport(textArea);
caretAdorner = new CaretLayer(textView); caretAdorner = new CaretLayer(textView);
textView.InsertLayer(caretAdorner, KnownLayer.Caret, LayerInsertionPosition.Replace); textView.InsertLayer(caretAdorner, KnownLayer.Caret, LayerInsertionPosition.Replace);
@ -436,7 +434,7 @@ namespace ICSharpCode.AvalonEdit.Editing
} else { } else {
caretAdorner.Hide(); caretAdorner.Hide();
} }
ime.UpdateCompositionWindow(); textArea.ime.UpdateCompositionWindow();
} }
} }

11
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/ImeNativeWrapper.cs

@ -76,16 +76,23 @@ namespace ICSharpCode.AvalonEdit.Editing
public const int WM_IME_SETCONTEXT = 0x281; public const int WM_IME_SETCONTEXT = 0x281;
public const int WM_INPUTLANGCHANGE = 0x51; public const int WM_INPUTLANGCHANGE = 0x51;
[DllImport("imm32.dll")]
public static extern IntPtr ImmCreateContext();
[DllImport("imm32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ImmDestroyContext(IntPtr hIMC);
[DllImport("imm32.dll")] [DllImport("imm32.dll")]
static extern IntPtr ImmAssociateContext(IntPtr hWnd, IntPtr hIMC); static extern IntPtr ImmAssociateContext(IntPtr hWnd, IntPtr hIMC);
[DllImport("imm32.dll")] [DllImport("imm32.dll")]
static extern IntPtr ImmGetContext(IntPtr hWnd); static extern IntPtr ImmGetContext(IntPtr hWnd);
[DllImport("imm32.dll")] [DllImport("imm32.dll")]
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
static extern bool ImmNotifyIME(IntPtr hIMC, int dwAction, int dwIndex, int dwValue = 0); static extern bool ImmReleaseContext(IntPtr hWnd, IntPtr hIMC);
[DllImport("imm32.dll")] [DllImport("imm32.dll")]
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
static extern bool ImmReleaseContext(IntPtr hWnd, IntPtr hIMC); static extern bool ImmNotifyIME(IntPtr hIMC, int dwAction, int dwIndex, int dwValue = 0);
[DllImport("imm32.dll")] [DllImport("imm32.dll")]
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
static extern bool ImmSetCompositionWindow(IntPtr hIMC, ref CompositionForm form); static extern bool ImmSetCompositionWindow(IntPtr hIMC, ref CompositionForm form);

43
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/ImeSupport.cs

@ -19,11 +19,10 @@ using ICSharpCode.AvalonEdit.Rendering;
namespace ICSharpCode.AvalonEdit.Editing namespace ICSharpCode.AvalonEdit.Editing
{ {
class ImeSupport : IDisposable class ImeSupport
{ {
TextArea textArea; readonly TextArea textArea;
IntPtr currentContext; IntPtr currentContext;
IntPtr previousContext;
HwndSource hwndSource; HwndSource hwndSource;
public ImeSupport(TextArea textArea) public ImeSupport(TextArea textArea)
@ -32,47 +31,29 @@ namespace ICSharpCode.AvalonEdit.Editing
throw new ArgumentNullException("textArea"); throw new ArgumentNullException("textArea");
this.textArea = textArea; this.textArea = textArea;
InputMethod.SetIsInputMethodSuspended(this.textArea, true); InputMethod.SetIsInputMethodSuspended(this.textArea, true);
textArea.GotKeyboardFocus += TextAreaGotKeyboardFocus;
textArea.LostKeyboardFocus += TextAreaLostKeyboardFocus;
textArea.OptionChanged += TextAreaOptionChanged; textArea.OptionChanged += TextAreaOptionChanged;
currentContext = IntPtr.Zero; currentContext = IntPtr.Zero;
previousContext = IntPtr.Zero;
} }
void TextAreaOptionChanged(object sender, PropertyChangedEventArgs e) void TextAreaOptionChanged(object sender, PropertyChangedEventArgs e)
{ {
if (e.PropertyName == "EnableImeSupport" && textArea.IsKeyboardFocusWithin) { if (e.PropertyName == "EnableImeSupport" && textArea.IsKeyboardFocused) {
CreateContext(); CreateContext();
} }
} }
public void Dispose()
{
if (textArea != null) {
textArea.GotKeyboardFocus -= TextAreaGotKeyboardFocus;
textArea.LostKeyboardFocus -= TextAreaLostKeyboardFocus;
textArea.OptionChanged -= TextAreaOptionChanged;
textArea = null;
}
ClearContext();
}
void ClearContext() void ClearContext()
{ {
if (hwndSource != null) { if (hwndSource != null) {
hwndSource.RemoveHook(WndProc);
ImeNativeWrapper.AssociateContext(hwndSource, previousContext);
previousContext = IntPtr.Zero;
ImeNativeWrapper.ReleaseContext(hwndSource, currentContext); ImeNativeWrapper.ReleaseContext(hwndSource, currentContext);
hwndSource = null;
currentContext = IntPtr.Zero; currentContext = IntPtr.Zero;
hwndSource.RemoveHook(WndProc);
hwndSource = null;
} }
} }
void TextAreaGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) public void OnGotFocus(KeyboardFocusChangedEventArgs e)
{ {
if (e.OriginalSource != this.textArea)
return;
CreateContext(); CreateContext();
} }
@ -84,17 +65,15 @@ namespace ICSharpCode.AvalonEdit.Editing
hwndSource = (HwndSource)PresentationSource.FromVisual(this.textArea); hwndSource = (HwndSource)PresentationSource.FromVisual(this.textArea);
if (hwndSource != null) { if (hwndSource != null) {
currentContext = ImeNativeWrapper.GetContext(hwndSource); currentContext = ImeNativeWrapper.GetContext(hwndSource);
previousContext = ImeNativeWrapper.AssociateContext(hwndSource, currentContext);
// ImeNativeWrapper.SetCompositionFont(hwndSource, currentContext, textArea); // ImeNativeWrapper.SetCompositionFont(hwndSource, currentContext, textArea);
hwndSource.AddHook(WndProc); hwndSource.AddHook(WndProc);
// UpdateCompositionWindow() will be called by the caret becoming visible
} }
} }
void TextAreaLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) public void OnLostFocus(KeyboardFocusChangedEventArgs e)
{ {
if (e.OriginalSource != this.textArea) if (e.OldFocus == textArea && currentContext != IntPtr.Zero)
return;
if (currentContext != IntPtr.Zero)
ImeNativeWrapper.NotifyIme(currentContext); ImeNativeWrapper.NotifyIme(currentContext);
ClearContext(); ClearContext();
} }
@ -103,6 +82,8 @@ namespace ICSharpCode.AvalonEdit.Editing
{ {
switch (msg) { switch (msg) {
case ImeNativeWrapper.WM_INPUTLANGCHANGE: case ImeNativeWrapper.WM_INPUTLANGCHANGE:
// Don't mark the message as handled; other windows
// might want to handle it as well.
ClearContext(); ClearContext();
CreateContext(); CreateContext();
break; break;
@ -115,7 +96,7 @@ namespace ICSharpCode.AvalonEdit.Editing
public void UpdateCompositionWindow() public void UpdateCompositionWindow()
{ {
if (currentContext != IntPtr.Zero && textArea != null) { if (currentContext != IntPtr.Zero) {
ImeNativeWrapper.SetCompositionWindow(hwndSource, currentContext, textArea); ImeNativeWrapper.SetCompositionWindow(hwndSource, currentContext, textArea);
} }
} }

6
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextArea.cs

@ -29,6 +29,8 @@ namespace ICSharpCode.AvalonEdit.Editing
/// </summary> /// </summary>
public class TextArea : Control, IScrollInfo, IWeakEventListener, ITextEditorComponent, IServiceProvider public class TextArea : Control, IScrollInfo, IWeakEventListener, ITextEditorComponent, IServiceProvider
{ {
internal readonly ImeSupport ime;
#region Constructor #region Constructor
static TextArea() static TextArea()
{ {
@ -68,6 +70,7 @@ namespace ICSharpCode.AvalonEdit.Editing
caret = new Caret(this); caret = new Caret(this);
caret.PositionChanged += (sender, e) => RequestSelectionValidation(); caret.PositionChanged += (sender, e) => RequestSelectionValidation();
ime = new ImeSupport(this);
leftMargins.CollectionChanged += leftMargins_CollectionChanged; leftMargins.CollectionChanged += leftMargins_CollectionChanged;
@ -754,6 +757,8 @@ namespace ICSharpCode.AvalonEdit.Editing
protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e) protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
{ {
base.OnGotKeyboardFocus(e); base.OnGotKeyboardFocus(e);
// First activate IME, then show caret
ime.OnGotFocus(e);
caret.Show(); caret.Show();
} }
@ -762,6 +767,7 @@ namespace ICSharpCode.AvalonEdit.Editing
{ {
base.OnLostKeyboardFocus(e); base.OnLostKeyboardFocus(e);
caret.Hide(); caret.Hide();
ime.OnLostFocus(e);
} }
#endregion #endregion

Loading…
Cancel
Save