private static void GetCompositionUnderlines(IntPtr hIMC, int targetStart, int targetEnd, List <CompositionUnderline> underlines) { var clauseSize = ImeNative.ImmGetCompositionString(hIMC, ImeNative.GCS_COMPCLAUSE, null, 0); if (clauseSize <= 0) { return; } int clauseLength = (int)clauseSize / sizeof(Int32); // buffer contains 32 bytes (4 bytes) array var clauseData = new byte[(int)clauseSize]; ImeNative.ImmGetCompositionString(hIMC, ImeNative.GCS_COMPCLAUSE, clauseData, clauseSize); var clauseLength_1 = clauseLength - 1; for (int i = 0; i < clauseLength_1; i++) { int from = BitConverter.ToInt32(clauseData, i * sizeof(Int32)); int to = BitConverter.ToInt32(clauseData, (i + 1) * sizeof(Int32)); var range = new Range(from, to); bool thick = (range.From >= targetStart && range.To <= targetEnd); underlines.Add(new CompositionUnderline(range, ColorUNDERLINE, ColorBKCOLOR, thick)); } }
/// <summary> /// Change composition range. /// </summary> /// <param name="selectionRange">The selection range.</param> /// <param name="characterBounds">The character bounds.</param> public void ChangeCompositionRange(Range selectionRange, Rect[] characterBounds) { if (!isActive) { return; } var screenInfo = ((IRenderWebBrowser)owner).GetScreenInfo(); var scaleFactor = screenInfo.HasValue ? screenInfo.Value.DeviceScaleFactor : 1.0f; //This is called on the CEF UI thread, we need to invoke back onte main UI thread to //access the UI controls owner.UiThreadRunAsync(() => { //TODO: Getting the root window for every composition range change seems expensive, //we should cache the position and update it on window move. var parentWindow = Window.GetWindow(owner); if (parentWindow != null) { //TODO: What are we calculating here exactly??? var point = owner.TransformToAncestor(parentWindow).Transform(new Point(0, 0)); var rects = new List <Rect>(); foreach (var item in characterBounds) { rects.Add(new Rect( (int)((point.X + item.X) * scaleFactor), (int)((point.Y + item.Y) * scaleFactor), (int)(item.Width * scaleFactor), (int)(item.Height * scaleFactor))); } compositionBounds = rects; MoveImeWindow(source.Handle); } }); }
void IRenderWebBrowser.OnImeCompositionRangeChanged(Range selectedRange, Rect[] characterBounds) { RenderHandler?.OnImeCompositionRangeChanged(selectedRange, characterBounds); }
private static void GetCompositionInfo(IntPtr hwnd, uint lParam, string text, List <CompositionUnderline> underlines, ref int compositionStart) { var hIMC = ImeNative.ImmGetContext(hwnd); underlines.Clear(); int targetStart = text.Length; int targetEnd = text.Length; if (IsParam(lParam, ImeNative.GCS_COMPATTR)) { GetCompositionSelectionRange(hIMC, ref targetStart, ref targetEnd); } // Retrieve the selection range information. If CS_NOMOVECARET is specified // it means the cursor should not be moved and we therefore place the caret at // the beginning of the composition string. Otherwise we should honour the // GCS_CURSORPOS value if it's available. if (!IsParam(lParam, ImeNative.CS_NOMOVECARET) && IsParam(lParam, ImeNative.GCS_CURSORPOS)) { // IMM32 does not support non-zero-width selection in a composition. So // always use the caret position as selection range. int cursor = (int)ImeNative.ImmGetCompositionString(hIMC, ImeNative.GCS_CURSORPOS, null, 0); compositionStart = cursor; } else { compositionStart = 0; } if (IsParam(lParam, ImeNative.GCS_COMPCLAUSE)) { GetCompositionUnderlines(hIMC, targetStart, targetEnd, underlines); } if (underlines.Count == 0) { var range = new Range(); bool thick = false; if (targetStart > 0) { range = new Range(0, targetStart); } if (targetEnd > targetStart) { range = new Range(targetStart, targetEnd); thick = true; } if (targetEnd < text.Length) { range = new Range(targetEnd, text.Length); } underlines.Add(new CompositionUnderline(range, ColorUNDERLINE, ColorBKCOLOR, thick)); } ImeNative.ImmReleaseContext(hwnd, hIMC); }
/// <summary> /// Called when the IME composition range has changed. /// </summary> /// <param name="selectedRange">is the range of characters that have been selected</param> /// <param name="characterBounds">is the bounds of each character in view coordinates.</param> public virtual void OnImeCompositionRangeChanged(Range selectedRange, Rect[] characterBounds) { }
public void OnImeCompositionRangeChanged(CefSharp.Structs.Range selectedRange, Rect[] characterBounds) { }
private static void GetCompositionInfo(IntPtr hwnd, uint lParam, string text, List <CompositionUnderline> underlines, ref int compositionStart) { var hIMC = ImeNative.ImmGetContext(hwnd); underlines.Clear(); byte[] attributes = null; int targetStart = text.Length; int targetEnd = text.Length; if (IsParam(lParam, ImeNative.GCS_COMPATTR)) { attributes = GetCompositionSelectionRange(hIMC, ref targetStart, ref targetEnd); } // Retrieve the selection range information. If CS_NOMOVECARET is specified // it means the cursor should not be moved and we therefore place the caret at // the beginning of the composition string. Otherwise we should honour the // GCS_CURSORPOS value if it's available. if (!IsParam(lParam, ImeNative.CS_NOMOVECARET) && IsParam(lParam, ImeNative.GCS_CURSORPOS)) { // IMM32 does not support non-zero-width selection in a composition. So // always use the caret position as selection range. int cursor = (int)ImeNative.ImmGetCompositionString(hIMC, ImeNative.GCS_CURSORPOS, null, 0); compositionStart = cursor; } else { compositionStart = 0; } if (attributes != null && // character before ((compositionStart > 0 && (compositionStart - 1) < attributes.Length && attributes[compositionStart - 1] == ImeNative.ATTR_INPUT) || // character after (compositionStart >= 0 && compositionStart < attributes.Length && attributes[compositionStart] == ImeNative.ATTR_INPUT))) { // as MS does with their ime implementation we should only use the GCS_CURSORPOS if the character // before or after is new input. // https://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/windows/Documents/ImmComposition.cs,1079 } else { compositionStart = text.Length; } if (IsParam(lParam, ImeNative.GCS_COMPCLAUSE)) { GetCompositionUnderlines(hIMC, targetStart, targetEnd, underlines); } if (underlines.Count == 0) { var range = new Range(); bool thick = false; if (targetStart > 0) { range = new Range(0, targetStart); } if (targetEnd > targetStart) { range = new Range(targetStart, targetEnd); thick = true; } if (targetEnd < text.Length) { range = new Range(targetEnd, text.Length); } underlines.Add(new CompositionUnderline(range, ColorUNDERLINE, ColorBKCOLOR, thick)); } ImeNative.ImmReleaseContext(hwnd, hIMC); }