From b7c439bb975a28dd3af8a5b1e555afc304ff1037 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Wed, 13 Mar 2013 21:26:37 +0100 Subject: [PATCH] Disable IME while the caret is within a read-only section. --- .../Editing/ImeSupport.cs | 80 +++++++++++++------ .../Editing/TextArea.cs | 1 + 2 files changed, 57 insertions(+), 24 deletions(-) diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/ImeSupport.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/ImeSupport.cs index 23c3c41c36..91d7cdc0fb 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/ImeSupport.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/ImeSupport.cs @@ -27,24 +27,62 @@ namespace ICSharpCode.AvalonEdit.Editing IntPtr previousContext; IntPtr defaultImeWnd; 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) { if (textArea == null) throw new ArgumentNullException("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; - currentContext = IntPtr.Zero; } + void OnRequerySuggested(object sender, EventArgs e) + { + UpdateImeEnabled(); + } + void TextAreaOptionChanged(object sender, PropertyChangedEventArgs e) { - if (e.PropertyName == "EnableImeSupport" && textArea.IsKeyboardFocused) { - CreateContext(); + if (e.PropertyName == "EnableImeSupport") { + 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(); + } + } + void ClearContext() { if (hwndSource != null) { @@ -57,20 +95,17 @@ namespace ICSharpCode.AvalonEdit.Editing } } - public void OnGotKeyboardFocus(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) { - defaultImeWnd = ImeNativeWrapper.ImmGetDefaultIMEWnd(IntPtr.Zero); - currentContext = ImeNativeWrapper.ImmGetContext(defaultImeWnd); + if (isReadOnly) { + defaultImeWnd = IntPtr.Zero; + currentContext = IntPtr.Zero; + } else { + defaultImeWnd = ImeNativeWrapper.ImmGetDefaultIMEWnd(IntPtr.Zero); + currentContext = ImeNativeWrapper.ImmGetContext(defaultImeWnd); + } previousContext = ImeNativeWrapper.ImmAssociateContext(hwndSource.Handle, currentContext); Debug.Assert(hwndSource != 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) { switch (msg) { case ImeNativeWrapper.WM_INPUTLANGCHANGE: // Don't mark the message as handled; other windows // might want to handle it as well. - ClearContext(); - CreateContext(); + + // If we have a context, recreate it + if (hwndSource != null) { + ClearContext(); + CreateContext(); + } break; case ImeNativeWrapper.WM_IME_COMPOSITION: UpdateCompositionWindow(); diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextArea.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextArea.cs index 31607759f8..13a95958f1 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextArea.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextArea.cs @@ -596,6 +596,7 @@ namespace ICSharpCode.AvalonEdit.Editing if (value == null) throw new ArgumentNullException("value"); readOnlySectionProvider = value; + CommandManager.InvalidateRequerySuggested(); // the read-only status effects Paste.CanExecute and the IME } } #endregion