Browse Source

Disable IME while the caret is within a read-only section.

pull/39/merge
Daniel Grunwald 13 years ago
parent
commit
b7c439bb97
  1. 78
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/ImeSupport.cs
  2. 1
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextArea.cs

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

@ -27,21 +27,59 @@ namespace ICSharpCode.AvalonEdit.Editing
IntPtr previousContext; IntPtr previousContext;
IntPtr defaultImeWnd; IntPtr defaultImeWnd;
HwndSource hwndSource; HwndSource hwndSource;
EventHandler requerySuggestedHandler; // we need to keep the event handler instance alive because CommandManager.RequerySuggested uses weak references
bool isReadOnly;
public ImeSupport(TextArea textArea) public ImeSupport(TextArea textArea)
{ {
if (textArea == null) if (textArea == null)
throw new ArgumentNullException("textArea"); throw new ArgumentNullException("textArea");
this.textArea = textArea; this.textArea = textArea;
InputMethod.SetIsInputMethodSuspended(this.textArea, true); InputMethod.SetIsInputMethodSuspended(this.textArea, textArea.Options.EnableImeSupport);
// We listen to CommandManager.RequerySuggested for both caret offset changes and changes to the set of read-only sections.
// This is because there's no dedicated event for read-only section changes; but RequerySuggested needs to be raised anyways
// to invalidate the Paste command.
requerySuggestedHandler = OnRequerySuggested;
CommandManager.RequerySuggested += requerySuggestedHandler;
textArea.OptionChanged += TextAreaOptionChanged; textArea.OptionChanged += TextAreaOptionChanged;
currentContext = IntPtr.Zero; }
void OnRequerySuggested(object sender, EventArgs e)
{
UpdateImeEnabled();
} }
void TextAreaOptionChanged(object sender, PropertyChangedEventArgs e) void TextAreaOptionChanged(object sender, PropertyChangedEventArgs e)
{ {
if (e.PropertyName == "EnableImeSupport" && textArea.IsKeyboardFocused) { if (e.PropertyName == "EnableImeSupport") {
CreateContext(); InputMethod.SetIsInputMethodSuspended(this.textArea, textArea.Options.EnableImeSupport);
UpdateImeEnabled();
}
}
public void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
UpdateImeEnabled();
}
public void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
if (e.OldFocus == textArea && currentContext != IntPtr.Zero)
ImeNativeWrapper.NotifyIme(currentContext);
ClearContext();
}
void UpdateImeEnabled()
{
if (textArea.Options.EnableImeSupport && textArea.IsKeyboardFocused) {
bool newReadOnly = !textArea.ReadOnlySectionProvider.CanInsert(textArea.Caret.Offset);
if (hwndSource == null || isReadOnly != newReadOnly) {
ClearContext(); // clear existing context (on read-only change)
isReadOnly = newReadOnly;
CreateContext();
}
} else {
ClearContext();
} }
} }
@ -57,20 +95,17 @@ namespace ICSharpCode.AvalonEdit.Editing
} }
} }
public void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
CreateContext();
}
void CreateContext() void CreateContext()
{ {
ClearContext(); // clear old context if necessary
if (!textArea.Options.EnableImeSupport)
return;
hwndSource = (HwndSource)PresentationSource.FromVisual(this.textArea); hwndSource = (HwndSource)PresentationSource.FromVisual(this.textArea);
if (hwndSource != null) { if (hwndSource != null) {
defaultImeWnd = ImeNativeWrapper.ImmGetDefaultIMEWnd(IntPtr.Zero); if (isReadOnly) {
currentContext = ImeNativeWrapper.ImmGetContext(defaultImeWnd); defaultImeWnd = IntPtr.Zero;
currentContext = IntPtr.Zero;
} else {
defaultImeWnd = ImeNativeWrapper.ImmGetDefaultIMEWnd(IntPtr.Zero);
currentContext = ImeNativeWrapper.ImmGetContext(defaultImeWnd);
}
previousContext = ImeNativeWrapper.ImmAssociateContext(hwndSource.Handle, currentContext); previousContext = ImeNativeWrapper.ImmAssociateContext(hwndSource.Handle, currentContext);
Debug.Assert(hwndSource != null); Debug.Assert(hwndSource != null);
Debug.Assert(currentContext != null); Debug.Assert(currentContext != null);
@ -86,21 +121,18 @@ namespace ICSharpCode.AvalonEdit.Editing
} }
} }
public void OnLostKeyboardFocus(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) IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{ {
switch (msg) { switch (msg) {
case ImeNativeWrapper.WM_INPUTLANGCHANGE: case ImeNativeWrapper.WM_INPUTLANGCHANGE:
// Don't mark the message as handled; other windows // Don't mark the message as handled; other windows
// might want to handle it as well. // might want to handle it as well.
ClearContext();
CreateContext(); // If we have a context, recreate it
if (hwndSource != null) {
ClearContext();
CreateContext();
}
break; break;
case ImeNativeWrapper.WM_IME_COMPOSITION: case ImeNativeWrapper.WM_IME_COMPOSITION:
UpdateCompositionWindow(); UpdateCompositionWindow();

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

@ -596,6 +596,7 @@ namespace ICSharpCode.AvalonEdit.Editing
if (value == null) if (value == null)
throw new ArgumentNullException("value"); throw new ArgumentNullException("value");
readOnlySectionProvider = value; readOnlySectionProvider = value;
CommandManager.InvalidateRequerySuggested(); // the read-only status effects Paste.CanExecute and the IME
} }
} }
#endregion #endregion

Loading…
Cancel
Save