private bool backspaceOrForwardDelete(android.view.View view, android.text.Editable content, int keyCode, android.view.KeyEvent @event, bool isForwardDelete) { // Ensure the key event does not have modifiers except ALT or SHIFT. if (!android.view.KeyEvent.metaStateHasNoModifiers(@event.getMetaState() & ~(android.view.KeyEvent .META_SHIFT_MASK | android.view.KeyEvent.META_ALT_MASK))) { return false; } // If there is a current selection, delete it. if (deleteSelection(view, content)) { return true; } // Alt+Backspace or Alt+ForwardDelete deletes the current line, if possible. if (@event.isAltPressed() || getMetaState(content, META_ALT_ON) == 1) { if (deleteLine(view, content)) { return true; } } // Delete a character. int start = android.text.Selection.getSelectionEnd(content); int end; if (isForwardDelete || @event.isShiftPressed() || getMetaState(content, META_SHIFT_ON ) == 1) { end = android.text.TextUtils.getOffsetAfter(content, start); } else { end = android.text.TextUtils.getOffsetBefore(content, start); } if (start != end) { content.delete(System.Math.Min(start, end), System.Math.Max(start, end)); return true; } return false; }
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); }
/// <summary>Checks a generic motion event.</summary> /// <remarks>Checks a generic motion event.</remarks> /// <param name="event">The event.</param> /// <param name="nestingLevel"> /// The nesting level: 0 if called from the base class, /// or 1 from a subclass. If the event was already checked by this consistency verifier /// at a higher nesting level, it will not be checked again. Used to handle the situation /// where a subclass dispatching method delegates to its superclass's dispatching method /// and both dispatching methods call into the consistency verifier. /// </param> public void onGenericMotionEvent(android.view.MotionEvent @event, int nestingLevel ) { if (!startEvent(@event, nestingLevel, EVENT_TYPE_GENERIC_MOTION)) { return; } try { ensureMetaStateIsNormalized(@event.getMetaState()); int action = @event.getAction(); int source = @event.getSource(); if ((source & android.view.InputDevice.SOURCE_CLASS_POINTER) != 0) { switch (action) { case android.view.MotionEvent.ACTION_HOVER_ENTER: { ensurePointerCountIsOneForThisAction(@event); mHoverEntered = true; break; } case android.view.MotionEvent.ACTION_HOVER_MOVE: { ensurePointerCountIsOneForThisAction(@event); break; } case android.view.MotionEvent.ACTION_HOVER_EXIT: { ensurePointerCountIsOneForThisAction(@event); if (!mHoverEntered) { problem("ACTION_HOVER_EXIT without prior ACTION_HOVER_ENTER"); } mHoverEntered = false; break; } case android.view.MotionEvent.ACTION_SCROLL: { ensureHistorySizeIsZeroForThisAction(@event); ensurePointerCountIsOneForThisAction(@event); break; } default: { problem("Invalid action for generic pointer event."); break; } } } else { if ((source & android.view.InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { switch (action) { case android.view.MotionEvent.ACTION_MOVE: { ensurePointerCountIsOneForThisAction(@event); break; } default: { problem("Invalid action for generic joystick event."); break; } } } } } finally { finishEvent(); } }
/// <summary>Checks a touch event.</summary> /// <remarks>Checks a touch event.</remarks> /// <param name="event">The event.</param> /// <param name="nestingLevel"> /// The nesting level: 0 if called from the base class, /// or 1 from a subclass. If the event was already checked by this consistency verifier /// at a higher nesting level, it will not be checked again. Used to handle the situation /// where a subclass dispatching method delegates to its superclass's dispatching method /// and both dispatching methods call into the consistency verifier. /// </param> public void onTouchEvent(android.view.MotionEvent @event, int nestingLevel) { if (!startEvent(@event, nestingLevel, EVENT_TYPE_TOUCH)) { return; } int action = @event.getAction(); bool newStream = action == android.view.MotionEvent.ACTION_DOWN || action == android.view.MotionEvent .ACTION_CANCEL; if (newStream && (mTouchEventStreamIsTainted || mTouchEventStreamUnhandled)) { mTouchEventStreamIsTainted = false; mTouchEventStreamUnhandled = false; mTouchEventStreamPointers = 0; } if (mTouchEventStreamIsTainted) { @event.setTainted(true); } try { ensureMetaStateIsNormalized(@event.getMetaState()); int deviceId = @event.getDeviceId(); int source = @event.getSource(); if (!newStream && mTouchEventStreamDeviceId != -1 && (mTouchEventStreamDeviceId != deviceId || mTouchEventStreamSource != source)) { problem("Touch event stream contains events from multiple sources: " + "previous device id " + mTouchEventStreamDeviceId + ", previous source " + Sharpen.Util.IntToHexString (mTouchEventStreamSource) + ", new device id " + deviceId + ", new source " + Sharpen.Util.IntToHexString (source)); } mTouchEventStreamDeviceId = deviceId; mTouchEventStreamSource = source; int pointerCount = @event.getPointerCount(); if ((source & android.view.InputDevice.SOURCE_CLASS_POINTER) != 0) { switch (action) { case android.view.MotionEvent.ACTION_DOWN: { if (mTouchEventStreamPointers != 0) { problem("ACTION_DOWN but pointers are already down. " + "Probably missing ACTION_UP from previous gesture." ); } ensureHistorySizeIsZeroForThisAction(@event); ensurePointerCountIsOneForThisAction(@event); mTouchEventStreamPointers = 1 << @event.getPointerId(0); break; } case android.view.MotionEvent.ACTION_UP: { ensureHistorySizeIsZeroForThisAction(@event); ensurePointerCountIsOneForThisAction(@event); mTouchEventStreamPointers = 0; mTouchEventStreamIsTainted = false; break; } case android.view.MotionEvent.ACTION_MOVE: { int expectedPointerCount = Sharpen.Util.IntGetBitCount(mTouchEventStreamPointers); if (pointerCount != expectedPointerCount) { problem("ACTION_MOVE contained " + pointerCount + " pointers but there are currently " + expectedPointerCount + " pointers down."); mTouchEventStreamIsTainted = true; } break; } case android.view.MotionEvent.ACTION_CANCEL: { mTouchEventStreamPointers = 0; mTouchEventStreamIsTainted = false; break; } case android.view.MotionEvent.ACTION_OUTSIDE: { if (mTouchEventStreamPointers != 0) { problem("ACTION_OUTSIDE but pointers are still down."); } ensureHistorySizeIsZeroForThisAction(@event); ensurePointerCountIsOneForThisAction(@event); mTouchEventStreamIsTainted = false; break; } default: { int actionMasked = @event.getActionMasked(); int actionIndex = @event.getActionIndex(); if (actionMasked == android.view.MotionEvent.ACTION_POINTER_DOWN) { if (mTouchEventStreamPointers == 0) { problem("ACTION_POINTER_DOWN but no other pointers were down."); mTouchEventStreamIsTainted = true; } if (actionIndex < 0 || actionIndex >= pointerCount) { problem("ACTION_POINTER_DOWN index is " + actionIndex + " but the pointer count is " + pointerCount + "."); mTouchEventStreamIsTainted = true; } else { int id = @event.getPointerId(actionIndex); int idBit = 1 << id; if ((mTouchEventStreamPointers & idBit) != 0) { problem("ACTION_POINTER_DOWN specified pointer id " + id + " which is already down." ); mTouchEventStreamIsTainted = true; } else { mTouchEventStreamPointers |= idBit; } } ensureHistorySizeIsZeroForThisAction(@event); } else { if (actionMasked == android.view.MotionEvent.ACTION_POINTER_UP) { if (actionIndex < 0 || actionIndex >= pointerCount) { problem("ACTION_POINTER_UP index is " + actionIndex + " but the pointer count is " + pointerCount + "."); mTouchEventStreamIsTainted = true; } else { int id = @event.getPointerId(actionIndex); int idBit = 1 << id; if ((mTouchEventStreamPointers & idBit) == 0) { problem("ACTION_POINTER_UP specified pointer id " + id + " which is not currently down." ); mTouchEventStreamIsTainted = true; } else { mTouchEventStreamPointers &= ~idBit; } } ensureHistorySizeIsZeroForThisAction(@event); } else { problem("Invalid action " + android.view.MotionEvent.actionToString(action) + " for touch event." ); } } break; } } } else { problem("Source was not SOURCE_CLASS_POINTER."); } } finally { finishEvent(); } }
/// <summary>Checks a trackball event.</summary> /// <remarks>Checks a trackball event.</remarks> /// <param name="event">The event.</param> /// <param name="nestingLevel"> /// The nesting level: 0 if called from the base class, /// or 1 from a subclass. If the event was already checked by this consistency verifier /// at a higher nesting level, it will not be checked again. Used to handle the situation /// where a subclass dispatching method delegates to its superclass's dispatching method /// and both dispatching methods call into the consistency verifier. /// </param> public void onTrackballEvent(android.view.MotionEvent @event, int nestingLevel) { if (!startEvent(@event, nestingLevel, EVENT_TYPE_TRACKBALL)) { return; } try { ensureMetaStateIsNormalized(@event.getMetaState()); int action = @event.getAction(); int source = @event.getSource(); if ((source & android.view.InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { switch (action) { case android.view.MotionEvent.ACTION_DOWN: { if (mTrackballDown && !mTrackballUnhandled) { problem("ACTION_DOWN but trackball is already down."); } else { mTrackballDown = true; mTrackballUnhandled = false; } ensureHistorySizeIsZeroForThisAction(@event); ensurePointerCountIsOneForThisAction(@event); break; } case android.view.MotionEvent.ACTION_UP: { if (!mTrackballDown) { problem("ACTION_UP but trackball is not down."); } else { mTrackballDown = false; mTrackballUnhandled = false; } ensureHistorySizeIsZeroForThisAction(@event); ensurePointerCountIsOneForThisAction(@event); break; } case android.view.MotionEvent.ACTION_MOVE: { ensurePointerCountIsOneForThisAction(@event); break; } default: { problem("Invalid action " + android.view.MotionEvent.actionToString(action) + " for trackball event." ); break; } } if (mTrackballDown && @event.getPressure() <= 0) { problem("Trackball is down but pressure is not greater than 0."); } else { if (!mTrackballDown && @event.getPressure() != 0) { problem("Trackball is up but pressure is not equal to 0."); } } } else { problem("Source was not SOURCE_CLASS_TRACKBALL."); } } finally { finishEvent(); } }
/// <summary>Checks a key event.</summary> /// <remarks>Checks a key event.</remarks> /// <param name="event">The event.</param> /// <param name="nestingLevel"> /// The nesting level: 0 if called from the base class, /// or 1 from a subclass. If the event was already checked by this consistency verifier /// at a higher nesting level, it will not be checked again. Used to handle the situation /// where a subclass dispatching method delegates to its superclass's dispatching method /// and both dispatching methods call into the consistency verifier. /// </param> public void onKeyEvent(android.view.KeyEvent @event, int nestingLevel) { if (!startEvent(@event, nestingLevel, EVENT_TYPE_KEY)) { return; } try { ensureMetaStateIsNormalized(@event.getMetaState()); int action = @event.getAction(); int deviceId = @event.getDeviceId(); int source = @event.getSource(); int keyCode = @event.getKeyCode(); switch (action) { case android.view.KeyEvent.ACTION_DOWN: { android.view.InputEventConsistencyVerifier.KeyState state = findKeyState(deviceId , source, keyCode, false); if (state != null) { // If the key is already down, ensure it is a repeat. // We don't perform this check when processing raw device input // because the input dispatcher itself is responsible for setting // the key repeat count before it delivers input events. if (state.unhandled) { state.unhandled = false; } else { if ((mFlags & FLAG_RAW_DEVICE_INPUT) == 0 && @event.getRepeatCount() == 0) { problem("ACTION_DOWN but key is already down and this event " + "is not a key repeat." ); } } } else { addKeyState(deviceId, source, keyCode); } break; } case android.view.KeyEvent.ACTION_UP: { android.view.InputEventConsistencyVerifier.KeyState state = findKeyState(deviceId , source, keyCode, true); if (state == null) { problem("ACTION_UP but key was not down."); } else { state.recycle(); } break; } case android.view.KeyEvent.ACTION_MULTIPLE: { break; } default: { problem("Invalid action " + android.view.KeyEvent.actionToString(action) + " for key event." ); break; } } } finally { finishEvent(); } }
public override bool onGenericMotionEvent(android.view.MotionEvent @event) { if ((@event.getSource() & android.view.InputDevice.SOURCE_CLASS_POINTER) != 0) { switch (@event.getAction()) { case android.view.MotionEvent.ACTION_SCROLL: { if (!mIsBeingDragged) { float hscroll; if ((@event.getMetaState() & android.view.KeyEvent.META_SHIFT_ON) != 0) { hscroll = [email protected](android.view.MotionEvent.AXIS_VSCROLL); } else { hscroll = @event.getAxisValue(android.view.MotionEvent.AXIS_HSCROLL); } if (hscroll != 0) { int delta = (int)(hscroll * getHorizontalScrollFactor()); int range = getScrollRange(); int oldScrollX = mScrollX; int newScrollX = oldScrollX + delta; if (newScrollX < 0) { newScrollX = 0; } else { if (newScrollX > range) { newScrollX = range; } } if (newScrollX != oldScrollX) { base.scrollTo(newScrollX, mScrollY); return true; } } } break; } } } return base.onGenericMotionEvent(@event); }
internal virtual [email protected] findItemWithShortcutForKey (int keyCode, android.view.KeyEvent @event) { // Get all items that can be associated directly or indirectly with the keyCode java.util.ArrayList<*****@*****.**> items = mTempShortcutItemList; items.clear(); findItemsWithShortcutForKey(items, keyCode, @event); if (items.isEmpty()) { return null; } int metaState = @event.getMetaState(); android.view.KeyCharacterMap.KeyData possibleChars = new android.view.KeyCharacterMap .KeyData(); // Get the chars associated with the keyCode (i.e using any chording combo) @event.getKeyData(possibleChars); // If we have only one element, we can safely returns it int size_1 = items.size(); if (size_1 == 1) { return items.get(0); } bool qwerty = isQwertyMode(); { // If we found more than one item associated with the key, // we have to return the exact match for (int i = 0; i < size_1; i++) { [email protected] item = items.get(i); char shortcutChar = qwerty ? item.getAlphabeticShortcut() : item.getNumericShortcut (); if ((shortcutChar == possibleChars.meta[0] && (metaState & android.view.KeyEvent. META_ALT_ON) == 0) || (shortcutChar == possibleChars.meta[2] && (metaState & android.view.KeyEvent .META_ALT_ON) != 0) || (qwerty && shortcutChar == '\b' && keyCode == android.view.KeyEvent .KEYCODE_DEL)) { return item; } } } return null; }
internal virtual void findItemsWithShortcutForKey(java.util.List<*****@*****.** > items, int keyCode, android.view.KeyEvent @event) { bool qwerty = isQwertyMode(); int metaState = @event.getMetaState(); android.view.KeyCharacterMap.KeyData possibleChars = new android.view.KeyCharacterMap .KeyData(); // Get the chars associated with the keyCode (i.e using any chording combo) bool isKeyCodeMapped = @event.getKeyData(possibleChars); // The delete key is not mapped to '\b' so we treat it specially if (!isKeyCodeMapped && (keyCode != android.view.KeyEvent.KEYCODE_DEL)) { return; } // Look for an item whose shortcut is this key. int N = mItems.size(); { for (int i = 0; i < N; i++) { [email protected] item = mItems.get(i); if (item.hasSubMenu()) { (([email protected])item.getSubMenu()).findItemsWithShortcutForKey (items, keyCode, @event); } char shortcutChar = qwerty ? item.getAlphabeticShortcut() : item.getNumericShortcut (); if (((metaState & (android.view.KeyEvent.META_SHIFT_ON | android.view.KeyEvent.META_SYM_ON )) == 0) && (shortcutChar != 0) && (shortcutChar == possibleChars.meta[0] || shortcutChar == possibleChars.meta[2] || (qwerty && shortcutChar == '\b' && keyCode == android.view.KeyEvent .KEYCODE_DEL)) && item.isEnabled()) { items.add(item); } } } }
public virtual bool onGenericMotionEvent(android.widget.TextView widget, android.text.Spannable text, android.view.MotionEvent @event) { if ((@event.getSource() & android.view.InputDevice.SOURCE_CLASS_POINTER) != 0) { switch (@event.getAction()) { case android.view.MotionEvent.ACTION_SCROLL: { float vscroll; float hscroll; if ((@event.getMetaState() & android.view.KeyEvent.META_SHIFT_ON) != 0) { vscroll = 0; hscroll = @event.getAxisValue(android.view.MotionEvent.AXIS_VSCROLL); } else { vscroll = [email protected](android.view.MotionEvent.AXIS_VSCROLL); hscroll = @event.getAxisValue(android.view.MotionEvent.AXIS_HSCROLL); } bool handled = false; if (hscroll < 0) { handled |= scrollLeft(widget, text, (int)System.Math.Ceiling(-hscroll)); } else { if (hscroll > 0) { handled |= scrollRight(widget, text, (int)System.Math.Ceiling(hscroll)); } } if (vscroll < 0) { handled |= scrollUp(widget, text, (int)System.Math.Ceiling(-vscroll)); } else { if (vscroll > 0) { handled |= scrollDown(widget, text, (int)System.Math.Ceiling(vscroll)); } } return handled; } } } return false; }
/// <summary> /// Gets the meta state used for movement using the modifiers tracked by the text /// buffer as well as those present in the key event. /// </summary> /// <remarks> /// Gets the meta state used for movement using the modifiers tracked by the text /// buffer as well as those present in the key event. /// The movement meta state excludes the state of locked modifiers or the SHIFT key /// since they are not used by movement actions (but they may be used for selection). /// </remarks> /// <param name="buffer">The text buffer.</param> /// <param name="event">The key event.</param> /// <returns>The keyboard meta states used for movement.</returns> protected internal virtual int getMovementMetaState(android.text.Spannable buffer , android.view.KeyEvent @event) { // We ignore locked modifiers and SHIFT. int metaState = (@event.getMetaState() | android.text.method.MetaKeyKeyListener.getMetaState (buffer)) & ~(android.text.method.MetaKeyKeyListener.META_ALT_LOCKED | android.text.method.MetaKeyKeyListener .META_SYM_LOCKED); return android.view.KeyEvent.normalizeMetaState(metaState) & ~android.view.KeyEvent .META_SHIFT_MASK; }