|
|
|
@ -27,24 +27,62 @@ namespace ICSharpCode.AvalonEdit.Editing
@@ -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
@@ -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
@@ -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(); |
|
|
|
|