/// <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 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 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 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); }
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: { float vscroll = @event.getAxisValue(android.view.MotionEvent.AXIS_VSCROLL); if (vscroll < 0) { pacedScroll(false); return true; } else { if (vscroll > 0) { pacedScroll(true); return true; } } break; } } } return base.onGenericMotionEvent(@event); }
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 vscroll = @event.getAxisValue(android.view.MotionEvent.AXIS_VSCROLL); if (vscroll != 0) { int delta = (int)(vscroll * getVerticalScrollFactor()); int range = getScrollRange(); int oldScrollY = mScrollY; int newScrollY = oldScrollY - delta; if (newScrollY < 0) { newScrollY = 0; } else { if (newScrollY > range) { newScrollY = range; } } if (newScrollY != oldScrollY) { base.scrollTo(mScrollX, newScrollY); return true; } } } break; } } } return base.onGenericMotionEvent(@event); }
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; }