/// <summary> /// This method gets called when the IBus CommitText event is raised and indicates that /// the composition is ending. The temporarily inserted composition string will be /// replaced with <paramref name="ibusText"/>. /// It's in the discretion of the IBus 'keyboard' to decide when it calls OnCommitText. /// Typically this is done when the user selects a string in the pop-up composition /// window, or when he types a character that isn't part of the previous composition /// sequence. /// </summary> public void OnCommitText(object ibusText) { if (AssociatedSimpleRootSite.InvokeRequired) { AssociatedSimpleRootSite.InvokeAsync(() => OnCommitText(ibusText)); return; } OnCommitText(((IBusText)ibusText).Text, true); }
/// <summary> /// Called when the IBus DeleteSurroundingText is raised to delete surrounding /// characters. /// </summary> /// <param name="offset">The character offset from the cursor position of the text to be /// deleted. A negative value indicates a position before the cursor.</param> /// <param name="nChars">The number of characters to be deleted.</param> public void OnDeleteSurroundingText(int offset, int nChars) { if (AssociatedSimpleRootSite.InvokeRequired) { AssociatedSimpleRootSite.InvokeAsync(() => OnDeleteSurroundingText(offset, nChars)); return; } var selHelper = SetupForTypingEventHandler(true, false); if (selHelper == null || nChars <= 0) { return; } try { var selectionStart = selHelper.GetIch(SelectionHelper.SelLimitType.Top); var startIndex = selectionStart + offset; if (startIndex + nChars <= 0) { return; } var selectionProps = GetSelectionProps(selHelper); startIndex = Math.Max(startIndex, 0); selHelper.IchAnchor = startIndex; selHelper.IchEnd = startIndex + nChars; selHelper.SetSelection(true); ITsString str = CreateTsStringUsingSelectionProps(string.Empty, selectionProps, true); selHelper.Selection.ReplaceWithTsString(str); if (startIndex < selectionStart) { selectionStart = Math.Max(selectionStart - nChars, 0); } selHelper.IchAnchor = selectionStart; selHelper.IchEnd = selectionStart; // make the selection visible var selection = selHelper.SetSelection(true); selection.SetSelectionProps(selectionProps.Length, selectionProps); } finally { if (m_ActionHandler != null) { m_ActionHandler.EndUndoTask(); m_ActionHandler = null; } } }
/// <summary> /// Called when the IBus HidePreeditText event is raised to cancel/remove the composition, /// e.g. after the user pressed the ESC key or the application lost focus. /// </summary> public void OnHidePreeditText() { if (AssociatedSimpleRootSite.InvokeRequired) { AssociatedSimpleRootSite.InvokeAsync(OnHidePreeditText); return; } if (!AssociatedSimpleRootSite.Focused || AssociatedSimpleRootSite.ReadOnlyView) { return; } Reset(true); }
/// <summary> /// Called when the IBus ForwardKeyEvent is raised, i.e. when IBus wants the application /// to process a key event. One example is when IBus raises the ForwardKeyEvent and /// passes backspace to delete the character to the left of the cursor so that it can be /// replaced with a new modified character. /// </summary> /// <param name="keySym">Key symbol.</param> /// <param name="scanCode">Scan code.</param> /// <param name="index">Index of the KeyCode vector. This more or less tells the state of /// the modifier keys: 0=unshifted, 1=shifted (the other values I don't know and are irrelevant). /// </param> public void OnIbusKeyPress(int keySym, int scanCode, int index) { if (AssociatedSimpleRootSite.InvokeRequired) { AssociatedSimpleRootSite.InvokeAsync(() => OnIbusKeyPress(keySym, scanCode, index)); return; } if (!AssociatedSimpleRootSite.Focused || AssociatedSimpleRootSite.ReadOnlyView) { return; } var inChar = (char)(0x00FF & keySym); OnCommitText(inChar.ToString(), true); }
/// <summary> /// Called when the IBus UpdatePreeditText event is raised to update the composition. /// </summary> /// <param name="obj">New composition string that will replace the existing /// composition (sub-)string.</param> /// <param name="cursorPos">0-based position where the cursor should be put after /// updating the composition (pre-edit window). This position is relative to the /// composition/preedit text.</param> public void OnUpdatePreeditText(object obj, int cursorPos) { if (AssociatedSimpleRootSite.InvokeRequired) { AssociatedSimpleRootSite.InvokeAsync(() => OnUpdatePreeditText(obj, cursorPos)); return; } var selHelper = SetupForTypingEventHandler(true, false); if (selHelper == null) { return; } if (m_InitialSelection == null) { // Create a new, independent selection helper for m_InitialSelHelper - we want // to remember the current selection m_InitialSelection = new SelectionWrapper(AssociatedSimpleRootSite); OnPreeditOpened(); } var ibusText = obj as IBusText; var compositionText = ibusText.Text; CheckAttributesForCommittingKeyboard(ibusText); // Make the correct selection if (m_EndOfPreedit != null) { selHelper = m_EndOfPreedit; } var selectionProps = GetSelectionProps(selHelper); // Replace any previous pre-edit text. if (m_InitialSelection.SelectionHelper.Selection.EndBeforeAnchor) { // If we have a backwards selection we insert the pre-edit before the selected // text. selHelper points to the originally selected text (which got moved because // we inserted the pre-edit before it). The top of m_InitialSelection is the // start of the pre-edit, the top of selHelper is the position before the // originally selected text Debug.Assert(m_InitialSelection.SelectionHelper.IsRange); selHelper.IchEnd = selHelper.GetIch(SelectionHelper.SelLimitType.End); selHelper.IchAnchor = m_InitialSelection.SelectionHelper.GetIch(SelectionHelper.SelLimitType.Top); } else { // selHelper points to the position after inserting the previous pre-edit text, // so it will be the end of our range selection. The bottom of m_InitialSelection // is the position at the end of the initial range selection, so it will be part // of the anchor. selHelper.IchEnd = selHelper.GetIch(SelectionHelper.SelLimitType.Bottom); selHelper.IchAnchor = m_InitialSelection.SelectionHelper.GetIch(SelectionHelper.SelLimitType.Bottom); } selHelper.SetSelection(true); // Update the pre-edit text ITsString str = CreateTsStringUsingSelectionProps(compositionText, selectionProps, true); selHelper.Selection.ReplaceWithTsString(str); m_EndOfPreedit = new SelectionHelper( AssociatedSimpleRootSite.EditingHelper.CurrentSelection); if (m_InitialSelection.SelectionHelper.IsRange) { // keep the range selection if (m_InitialSelection.SelectionHelper.Selection.EndBeforeAnchor) { // we inserted before the original selection but we want to keep the original // text selected, so we have to adjust selHelper = new SelectionHelper(m_InitialSelection.SelectionHelper); selHelper.IchAnchor += str.Length; selHelper.IchEnd += str.Length; } else { selHelper = m_InitialSelection.SelectionHelper; } } else { // Set the IP to the position IBus told us. This is tricky because compositionText // might be in NFC but we have converted it to NFD, so the position needs to // change. To simplify this we expect for now that IBus sets the cursor always // either at the start or the end of the composition string. selHelper = new SelectionHelper(AssociatedSimpleRootSite.EditingHelper.CurrentSelection); selHelper.IchAnchor = m_InitialSelection.SelectionHelper.GetIch(SelectionHelper.SelLimitType.Bottom); if (compositionText.Length == cursorPos) { selHelper.IchAnchor += str.Length; } else { Debug.Assert(cursorPos == 0, "IBus told us a cursor position that changed because of nfc->nfd normalization"); selHelper.IchAnchor += cursorPos; } selHelper.IchEnd = selHelper.IchAnchor; } // make the selection visible selHelper.SetSelection(true); }