/// <summary> /// Marks the specified region of <code>content</code> as having /// contained <code>original</code> prior to AutoText replacement. /// </summary> /// <remarks> /// Marks the specified region of <code>content</code> as having /// contained <code>original</code> prior to AutoText replacement. /// Call this method when you have done or are about to do an /// AutoText-style replacement on a region of text and want to let /// the same mechanism (the user pressing DEL immediately after the /// change) undo the replacement. /// </remarks> /// <param name="content">the Editable text where the replacement was made</param> /// <param name="start">the start of the replaced region</param> /// <param name="end">the end of the replaced region; the location of the cursor</param> /// <param name="original">the text to be restored if the user presses DEL</param> public static void markAsReplaced(android.text.Spannable content, int start, int end, string original) { android.text.method.QwertyKeyListener.Replaced[] repl = content.getSpans<android.text.method.QwertyKeyListener .Replaced>(0, content.Length); { for (int a = 0; a < repl.Length; a++) { content.removeSpan(repl[a]); } } int len = original.Length; char[] orig = new char[len]; Sharpen.StringHelper.GetCharsForString(original, 0, len, orig, 0); content.setSpan(new android.text.method.QwertyKeyListener.Replaced(orig), start, end, android.text.SpannedClass.SPAN_EXCLUSIVE_EXCLUSIVE); }
public override bool onKeyDown(android.view.View view, android.text.Editable content , int keyCode, android.view.KeyEvent @event) { int selStart; int selEnd; int pref = 0; if (view != null) { pref = android.text.method.TextKeyListener.getInstance().getPrefs(view.getContext ()); } { int a = android.text.Selection.getSelectionStart(content); int b = android.text.Selection.getSelectionEnd(content); selStart = System.Math.Min(a, b); selEnd = System.Math.Max(a, b); if (selStart < 0 || selEnd < 0) { selStart = selEnd = 0; android.text.Selection.setSelection(content, 0, 0); } } int activeStart = content.getSpanStart(android.text.method.TextKeyListener.ACTIVE ); int activeEnd = content.getSpanEnd(android.text.method.TextKeyListener.ACTIVE); // QWERTY keyboard normal case int i = @event.getUnicodeChar(@event.getMetaState() | getMetaState(content)); if (!mFullKeyboard) { int count = @event.getRepeatCount(); if (count > 0 && selStart == selEnd && selStart > 0) { char c = content[selStart - 1]; if (c == i || c == Sharpen.CharHelper.ToUpper(i) && view != null) { if (showCharacterPicker(view, content, c, false, count)) { resetMetaState(content); return true; } } } } if (i == android.view.KeyCharacterMap.PICKER_DIALOG_INPUT) { if (view != null) { showCharacterPicker(view, content, android.view.KeyCharacterMap.PICKER_DIALOG_INPUT , true, 1); } resetMetaState(content); return true; } if (i == android.view.KeyCharacterMap.HEX_INPUT) { int start; if (selStart == selEnd) { start = selEnd; while (start > 0 && selEnd - start < 4 && Sharpen.CharHelper.Digit(content[start - 1], 16) >= 0) { start--; } } else { start = selStart; } int ch = -1; try { string hex = android.text.TextUtils.substring(content, start, selEnd); ch = System.Convert.ToInt32(hex, 16); } catch (System.ArgumentException) { } if (ch >= 0) { selStart = start; android.text.Selection.setSelection(content, selStart, selEnd); i = ch; } else { i = 0; } } if (i != 0) { bool dead = false; if ((i & android.view.KeyCharacterMap.COMBINING_ACCENT) != 0) { dead = true; i = i & android.view.KeyCharacterMap.COMBINING_ACCENT_MASK; } if (activeStart == selStart && activeEnd == selEnd) { bool replace = false; if (selEnd - selStart - 1 == 0) { char accent = content[selStart]; int composed = android.view.KeyEvent.getDeadChar(accent, i); if (composed != 0) { i = composed; replace = true; } } if (!replace) { android.text.Selection.setSelection(content, selEnd); content.removeSpan(android.text.method.TextKeyListener.ACTIVE); selStart = selEnd; } } if ((pref & android.text.method.TextKeyListener.AUTO_CAP) != 0 && Sharpen.CharHelper.IsLower (i) && android.text.method.TextKeyListener.shouldCap(mAutoCap, content, selStart )) { int where = content.getSpanEnd(android.text.method.TextKeyListener.CAPPED); int flags = content.getSpanFlags(android.text.method.TextKeyListener.CAPPED); if (where == selStart && (((flags >> 16) & unchecked((int)(0xFFFF))) == i)) { content.removeSpan(android.text.method.TextKeyListener.CAPPED); } else { flags = i << 16; i = Sharpen.CharHelper.ToUpper(i); if (selStart == 0) { content.setSpan(android.text.method.TextKeyListener.CAPPED, 0, 0, android.text.SpannedClass.SPAN_MARK_MARK | flags); } else { content.setSpan(android.text.method.TextKeyListener.CAPPED, selStart - 1, selStart , android.text.SpannedClass.SPAN_EXCLUSIVE_EXCLUSIVE | flags); } } } if (selStart != selEnd) { android.text.Selection.setSelection(content, selEnd); } content.setSpan(OLD_SEL_START, selStart, selStart, android.text.SpannedClass.SPAN_MARK_MARK ); content.replace(selStart, selEnd, java.lang.CharSequenceProxy.Wrap(((char)i).ToString ())); int oldStart = content.getSpanStart(OLD_SEL_START); selEnd = android.text.Selection.getSelectionEnd(content); if (oldStart < selEnd) { content.setSpan(android.text.method.TextKeyListener.LAST_TYPED, oldStart, selEnd, android.text.SpannedClass.SPAN_EXCLUSIVE_EXCLUSIVE); if (dead) { android.text.Selection.setSelection(content, oldStart, selEnd); content.setSpan(android.text.method.TextKeyListener.ACTIVE, oldStart, selEnd, android.text.SpannedClass.SPAN_EXCLUSIVE_EXCLUSIVE ); } } adjustMetaAfterKeypress(content); // potentially do autotext replacement if the character // that was typed was an autotext terminator if ((pref & android.text.method.TextKeyListener.AUTO_TEXT) != 0 && mAutoText && ( i == ' ' || i == '\t' || i == '\n' || i == ',' || i == '.' || i == '!' || i == '?' || i == '"' || Sharpen.CharHelper.GetType(i) == Sharpen.CharHelper.END_PUNCTUATION ) && content.getSpanEnd(android.text.method.TextKeyListener.INHIBIT_REPLACEMENT) != oldStart) { int x; for (x = oldStart; x > 0; x--) { char c = content[x - 1]; if (c != '\'' && !System.Char.IsLetter(c)) { break; } } string rep = getReplacement(content, x, oldStart, view); if (rep != null) { android.text.method.QwertyKeyListener.Replaced[] repl = content.getSpans<android.text.method.QwertyKeyListener .Replaced>(0, content.Length); { for (int a = 0; a < repl.Length; a++) { content.removeSpan(repl[a]); } } char[] orig = new char[oldStart - x]; android.text.TextUtils.getChars(content, x, oldStart, orig, 0); content.setSpan(new android.text.method.QwertyKeyListener.Replaced(orig), x, oldStart , android.text.SpannedClass.SPAN_EXCLUSIVE_EXCLUSIVE); content.replace(x, oldStart, java.lang.CharSequenceProxy.Wrap(rep)); } } // Replace two spaces by a period and a space. if ((pref & android.text.method.TextKeyListener.AUTO_PERIOD) != 0 && mAutoText) { selEnd = android.text.Selection.getSelectionEnd(content); if (selEnd - 3 >= 0) { if (content[selEnd - 1] == ' ' && content[selEnd - 2] == ' ') { char c = content[selEnd - 3]; { for (int j = selEnd - 3; j > 0; j--) { if (c == '"' || Sharpen.CharHelper.GetType(c) == Sharpen.CharHelper.END_PUNCTUATION) { c = content[j - 1]; } else { break; } } } if (System.Char.IsLetter(c) || System.Char.IsDigit(c)) { content.replace(selEnd - 2, selEnd - 1, java.lang.CharSequenceProxy.Wrap(".")); } } } } return true; } else { if (keyCode == android.view.KeyEvent.KEYCODE_DEL && (@event.hasNoModifiers() || @event .hasModifiers(android.view.KeyEvent.META_ALT_ON)) && selStart == selEnd) { // special backspace case for undoing autotext int consider = 1; // if backspacing over the last typed character, // it undoes the autotext prior to that character // (unless the character typed was newline, in which // case this behavior would be confusing) if (content.getSpanEnd(android.text.method.TextKeyListener.LAST_TYPED) == selStart) { if (content[selStart - 1] != '\n') { consider = 2; } } android.text.method.QwertyKeyListener.Replaced[] repl = content.getSpans<android.text.method.QwertyKeyListener .Replaced>(selStart - consider, selStart); if (repl.Length > 0) { int st = content.getSpanStart(repl[0]); int en = content.getSpanEnd(repl[0]); string old = new string(repl[0].mText); content.removeSpan(repl[0]); // only cancel the autocomplete if the cursor is at the end of // the replaced span (or after it, because the user is // backspacing over the space after the word, not the word // itself). if (selStart >= en) { content.setSpan(android.text.method.TextKeyListener.INHIBIT_REPLACEMENT, en, en, android.text.SpannedClass.SPAN_POINT_POINT); content.replace(st, en, java.lang.CharSequenceProxy.Wrap(old)); en = content.getSpanStart(android.text.method.TextKeyListener.INHIBIT_REPLACEMENT ); if (en - 1 >= 0) { content.setSpan(android.text.method.TextKeyListener.INHIBIT_REPLACEMENT, en - 1, en, android.text.SpannedClass.SPAN_EXCLUSIVE_EXCLUSIVE); } else { content.removeSpan(android.text.method.TextKeyListener.INHIBIT_REPLACEMENT); } adjustMetaAfterKeypress(content); } else { adjustMetaAfterKeypress(content); return base.onKeyDown(view, content, keyCode, @event); } return true; } } } return base.onKeyDown(view, content, keyCode, @event); }
public static void clearMetaKeyState(android.text.Editable content, int states) { if ((states & META_SHIFT_ON) != 0) { content.removeSpan(CAP); } if ((states & META_ALT_ON) != 0) { content.removeSpan(ALT); } if ((states & META_SYM_ON) != 0) { content.removeSpan(SYM); } if ((states & META_SELECTING) != 0) { content.removeSpan(SELECTING); } }
/// <summary>Remove the selection or cursor, if any, from the text.</summary> /// <remarks>Remove the selection or cursor, if any, from the text.</remarks> public static void removeSelection(android.text.Spannable text) { text.removeSpan(SELECTION_START); text.removeSpan(SELECTION_END); }
/// <summary>Stop selecting text.</summary> /// <remarks> /// Stop selecting text. This does not actually collapse the selection; /// call /// <see cref="android.text.Selection.setSelection(android.text.Spannable, int)">android.text.Selection.setSelection(android.text.Spannable, int) /// </see> /// too. /// </remarks> /// <hide>pending API review</hide> public static void stopSelecting(android.view.View view, android.text.Spannable content ) { content.removeSpan(SELECTING); }
// no super to call through to private void release(android.text.Editable content, object what, android.view.KeyEvent @event) { int current = content.getSpanFlags(what); switch (@event.getKeyCharacterMap().getModifierBehavior()) { case android.view.KeyCharacterMap.MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED: { if (current == USED) { content.removeSpan(what); } else { if (current == PRESSED) { content.setSpan(what, 0, 0, RELEASED); } } break; } default: { content.removeSpan(what); break; } } }
private static void resetLock(android.text.Spannable content, object what) { int current = content.getSpanFlags(what); if (current == LOCKED) { content.removeSpan(what); } }
// no super to call through to private void press(android.text.Editable content, object what) { int state = content.getSpanFlags(what); if (state == PRESSED) { } else { // repeat before use if (state == RELEASED) { content.setSpan(what, 0, 0, LOCKED); } else { if (state == USED) { } else { // repeat after use if (state == LOCKED) { content.removeSpan(what); } else { content.setSpan(what, 0, 0, PRESSED); } } } } }
private static void adjust(android.text.Spannable content, object what) { int current = content.getSpanFlags(what); if (current == PRESSED) { content.setSpan(what, 0, 0, USED); } else { if (current == RELEASED) { content.removeSpan(what); } } }
// These bits are privately used by the meta key key listener. // They are deliberately assigned values outside of the representable range of an 'int' // so as not to conflict with any meta key states publicly defined by KeyEvent. /// <summary>Resets all meta state to inactive.</summary> /// <remarks>Resets all meta state to inactive.</remarks> public static void resetMetaState(android.text.Spannable text) { text.removeSpan(CAP); text.removeSpan(ALT); text.removeSpan(SYM); text.removeSpan(SELECTING); }
public override bool onTouchEvent(android.widget.TextView widget, android.text.Spannable buffer, android.view.MotionEvent @event) { int initialScrollX = -1; int initialScrollY = -1; int action = @event.getAction(); if (action == android.view.MotionEvent.ACTION_UP) { initialScrollX = android.text.method.Touch.getInitialScrollX(widget, buffer); initialScrollY = android.text.method.Touch.getInitialScrollY(widget, buffer); } bool handled = android.text.method.Touch.onTouchEvent(widget, buffer, @event); if (widget.isFocused() && !widget.didTouchFocusSelect()) { if (action == android.view.MotionEvent.ACTION_DOWN) { if (isSelecting(buffer)) { int offset = widget.getOffsetForPosition(@event.getX(), @event.getY()); buffer.setSpan(LAST_TAP_DOWN, offset, offset, android.text.SpannedClass.SPAN_POINT_POINT ); // Disallow intercepting of the touch events, so that // users can scroll and select at the same time. // without this, users would get booted out of select // mode once the view detected it needed to scroll. widget.getParent().requestDisallowInterceptTouchEvent(true); } } else { if (action == android.view.MotionEvent.ACTION_MOVE) { if (isSelecting(buffer) && handled) { // Before selecting, make sure we've moved out of the "slop". // handled will be true, if we're in select mode AND we're // OUT of the slop // Turn long press off while we're selecting. User needs to // re-tap on the selection to enable long press widget.cancelLongPress(); // Update selection as we're moving the selection area. // Get the current touch position int offset = widget.getOffsetForPosition(@event.getX(), @event.getY()); android.text.Selection.extendSelection(buffer, offset); return true; } } else { if (action == android.view.MotionEvent.ACTION_UP) { // If we have scrolled, then the up shouldn't move the cursor, // but we do need to make sure the cursor is still visible at // the current scroll offset to avoid the scroll jumping later // to show it. if ((initialScrollY >= 0 && initialScrollY != widget.getScrollY()) || (initialScrollX >= 0 && initialScrollX != widget.getScrollX())) { widget.moveCursorToVisibleOffset(); return true; } int offset = widget.getOffsetForPosition(@event.getX(), @event.getY()); if (isSelecting(buffer)) { buffer.removeSpan(LAST_TAP_DOWN); android.text.Selection.extendSelection(buffer, offset); } else { if (!widget.shouldIgnoreActionUpEvent()) { android.text.Selection.setSelection(buffer, offset); } } android.text.method.MetaKeyKeyListener.adjustMetaAfterKeypress(buffer); android.text.method.MetaKeyKeyListener.resetLockedMeta(buffer); return true; } } } } return handled; }
public virtual void onSpanChanged(android.text.Spannable s, object what, int start , int end, int st, int en) { if (what == android.text.Selection.SELECTION_END) { s.removeSpan(ACTIVE); } }
/// <summary> /// Clear all the input state (autotext, autocap, multitap, undo) /// from the specified Editable, going beyond Editable.clear(), which /// just clears the text but not the input state. /// </summary> /// <remarks> /// Clear all the input state (autotext, autocap, multitap, undo) /// from the specified Editable, going beyond Editable.clear(), which /// just clears the text but not the input state. /// </remarks> /// <param name="e">the buffer whose text and state are to be cleared.</param> public static void clear(android.text.Editable e) { e.clear(); e.removeSpan(ACTIVE); e.removeSpan(CAPPED); e.removeSpan(INHIBIT_REPLACEMENT); e.removeSpan(LAST_TYPED); android.text.method.QwertyKeyListener.Replaced[] repl = e.getSpans<android.text.method.QwertyKeyListener .Replaced>(0, e.Length); int count = repl.Length; { for (int i = 0; i < count; i++) { e.removeSpan(repl[i]); } } }