void WindowImplAndroid::processScrollEvent(AInputEvent* _event, ActivityStates* states) { // Prepare the java virtual machine jint lResult; jint lFlags = 0; JavaVM* lJavaVM = states->activity->vm; JNIEnv* lJNIEnv = states->activity->env; JavaVMAttachArgs lJavaVMAttachArgs; lJavaVMAttachArgs.version = JNI_VERSION_1_6; lJavaVMAttachArgs.name = "NativeThread"; lJavaVMAttachArgs.group = NULL; lResult=lJavaVM->AttachCurrentThread(&lJNIEnv, &lJavaVMAttachArgs); if (lResult == JNI_ERR) err() << "Failed to initialize JNI, couldn't get the unicode value" << std::endl; // Retrieve everything we need to create this MotionEvent in java jlong downTime = AMotionEvent_getDownTime(_event); jlong eventTime = AMotionEvent_getEventTime(_event); jint action = AMotionEvent_getAction(_event); jfloat x = AMotionEvent_getX(_event, 0); jfloat y = AMotionEvent_getY(_event, 0); jfloat pressure = AMotionEvent_getPressure(_event, 0); jfloat size = AMotionEvent_getSize(_event, 0); jint metaState = AMotionEvent_getMetaState(_event); jfloat xPrecision = AMotionEvent_getXPrecision(_event); jfloat yPrecision = AMotionEvent_getYPrecision(_event); jint deviceId = AInputEvent_getDeviceId(_event); jint edgeFlags = AMotionEvent_getEdgeFlags(_event); // Create the MotionEvent object in java trough its static constructor obtain() jclass ClassMotionEvent = lJNIEnv->FindClass("android/view/MotionEvent"); jmethodID StaticMethodObtain = lJNIEnv->GetStaticMethodID(ClassMotionEvent, "obtain", "(JJIFFFFIFFII)Landroid/view/MotionEvent;"); jobject ObjectMotionEvent = lJNIEnv->CallStaticObjectMethod(ClassMotionEvent, StaticMethodObtain, downTime, eventTime, action, x, y, pressure, size, metaState, xPrecision, yPrecision, deviceId, edgeFlags); // Call its getAxisValue() method to get the delta value of our wheel move event jmethodID MethodGetAxisValue = lJNIEnv->GetMethodID(ClassMotionEvent, "getAxisValue", "(I)F"); jfloat delta = lJNIEnv->CallFloatMethod(ObjectMotionEvent, MethodGetAxisValue, 0x00000001); // Create and send our mouse wheel event Event event; event.type = Event::MouseWheelMoved; event.mouseWheel.delta = static_cast<double>(delta); event.mouseWheel.x = AMotionEvent_getX(_event, 0); event.mouseWheel.y = AMotionEvent_getY(_event, 0); forwardEvent(event); // Dettach this thread from the JVM lJavaVM->DetachCurrentThread(); }
bool InputService::onTouchEvent(AInputEvent* pEvent) { #ifdef INPUTSERVICE_LOG_EVENTS packt_Log_debug("AMotionEvent_getAction=%d", AMotionEvent_getAction(pEvent)); packt_Log_debug("AMotionEvent_getFlags=%d", AMotionEvent_getFlags(pEvent)); packt_Log_debug("AMotionEvent_getMetaState=%d", AMotionEvent_getMetaState(pEvent)); packt_Log_debug("AMotionEvent_getEdgeFlags=%d", AMotionEvent_getEdgeFlags(pEvent)); packt_Log_debug("AMotionEvent_getDownTime=%lld", AMotionEvent_getDownTime(pEvent)); packt_Log_debug("AMotionEvent_getEventTime=%lld", AMotionEvent_getEventTime(pEvent)); packt_Log_debug("AMotionEvent_getXOffset=%f", AMotionEvent_getXOffset(pEvent)); packt_Log_debug("AMotionEvent_getYOffset=%f", AMotionEvent_getYOffset(pEvent)); packt_Log_debug("AMotionEvent_getXPrecision=%f", AMotionEvent_getXPrecision(pEvent)); packt_Log_debug("AMotionEvent_getYPrecision=%f", AMotionEvent_getYPrecision(pEvent)); packt_Log_debug("AMotionEvent_getPointerCount=%d", AMotionEvent_getPointerCount(pEvent)); packt_Log_debug("AMotionEvent_getRawX=%f", AMotionEvent_getRawX(pEvent, 0)); packt_Log_debug("AMotionEvent_getRawY=%f", AMotionEvent_getRawY(pEvent, 0)); packt_Log_debug("AMotionEvent_getX=%f", AMotionEvent_getX(pEvent, 0)); packt_Log_debug("AMotionEvent_getY=%f", AMotionEvent_getY(pEvent, 0)); packt_Log_debug("AMotionEvent_getPressure=%f", AMotionEvent_getPressure(pEvent, 0)); packt_Log_debug("AMotionEvent_getSize=%f", AMotionEvent_getSize(pEvent, 0)); packt_Log_debug("AMotionEvent_getOrientation=%f", AMotionEvent_getOrientation(pEvent, 0)); packt_Log_debug("AMotionEvent_getTouchMajor=%f", AMotionEvent_getTouchMajor(pEvent, 0)); packt_Log_debug("AMotionEvent_getTouchMinor=%f", AMotionEvent_getTouchMinor(pEvent, 0)); #endif const float TOUCH_MAX_RANGE = 65.0f; // In pixels. if (mRefPoint != NULL) { if (AMotionEvent_getAction(pEvent) == AMOTION_EVENT_ACTION_MOVE) { // Needs a conversion to proper coordinates // (origin at bottom/left). Only lMoveY needs it. float lMoveX = AMotionEvent_getX(pEvent, 0) - mRefPoint->mPosX; float lMoveY = mHeight - AMotionEvent_getY(pEvent, 0) - mRefPoint->mPosY; float lMoveRange = sqrt((lMoveX * lMoveX) + (lMoveY * lMoveY)); if (lMoveRange > TOUCH_MAX_RANGE) { float lCropFactor = TOUCH_MAX_RANGE / lMoveRange; lMoveX *= lCropFactor; lMoveY *= lCropFactor; } mHorizontal = lMoveX / TOUCH_MAX_RANGE; mVertical = lMoveY / TOUCH_MAX_RANGE; } else { mHorizontal = 0.0f; mVertical = 0.0f; } } return true; }
s32 CIrrDeviceAndroid::handleInput(android_app* app, AInputEvent* androidEvent) { CIrrDeviceAndroid* device = (CIrrDeviceAndroid*)app->userData; s32 status = 0; switch ( AInputEvent_getType(androidEvent) ) { case AINPUT_EVENT_TYPE_MOTION: { SEvent event; event.EventType = EET_TOUCH_INPUT_EVENT; s32 eventAction = AMotionEvent_getAction(androidEvent); s32 eventType = eventAction & AMOTION_EVENT_ACTION_MASK; #if 0 // Useful for debugging. We might have to pass some of those infos on at some point. // but preferably device independent (so iphone can use same irrlicht flags). int32_t flags = AMotionEvent_getFlags(androidEvent); os::Printer::log("flags: ", core::stringc(flags).c_str(), ELL_DEBUG); int32_t metaState = AMotionEvent_getMetaState(androidEvent); os::Printer::log("metaState: ", core::stringc(metaState).c_str(), ELL_DEBUG); int32_t edgeFlags = AMotionEvent_getEdgeFlags(androidEvent); os::Printer::log("edgeFlags: ", core::stringc(flags).c_str(), ELL_DEBUG); #endif bool touchReceived = true; switch (eventType) { case AMOTION_EVENT_ACTION_DOWN: case AMOTION_EVENT_ACTION_POINTER_DOWN: event.TouchInput.Event = ETIE_PRESSED_DOWN; break; case AMOTION_EVENT_ACTION_MOVE: event.TouchInput.Event = ETIE_MOVED; break; case AMOTION_EVENT_ACTION_UP: case AMOTION_EVENT_ACTION_POINTER_UP: case AMOTION_EVENT_ACTION_CANCEL: event.TouchInput.Event = ETIE_LEFT_UP; break; default: touchReceived = false; break; } if (touchReceived) { // Process all touches for move action. if (event.TouchInput.Event == ETIE_MOVED) { s32 pointerCount = AMotionEvent_getPointerCount(androidEvent); for (s32 i = 0; i < pointerCount; ++i) { event.TouchInput.ID = AMotionEvent_getPointerId(androidEvent, i); event.TouchInput.X = AMotionEvent_getX(androidEvent, i); event.TouchInput.Y = AMotionEvent_getY(androidEvent, i); device->postEventFromUser(event); } } else // Process one touch for other actions. { s32 pointerIndex = (eventAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; event.TouchInput.ID = AMotionEvent_getPointerId(androidEvent, pointerIndex); event.TouchInput.X = AMotionEvent_getX(androidEvent, pointerIndex); event.TouchInput.Y = AMotionEvent_getY(androidEvent, pointerIndex); device->postEventFromUser(event); } status = 1; } } break; case AINPUT_EVENT_TYPE_KEY: { SEvent event; event.EventType = EET_KEY_INPUT_EVENT; int32_t keyCode = AKeyEvent_getKeyCode(androidEvent); // os::Printer::log("keyCode: ", core::stringc(keyCode).c_str(), ELL_DEBUG); int32_t keyAction = AKeyEvent_getAction(androidEvent); int32_t keyMetaState = AKeyEvent_getMetaState(androidEvent); if ( keyCode >= 0 && (u32)keyCode < device->KeyMap.size() ) event.KeyInput.Key = device->KeyMap[keyCode]; else event.KeyInput.Key = KEY_UNKNOWN; event.KeyInput.SystemKeyCode = (u32)keyCode; if ( keyAction == AKEY_EVENT_ACTION_DOWN ) event.KeyInput.PressedDown = true; else if ( keyAction == AKEY_EVENT_ACTION_UP ) event.KeyInput.PressedDown = false; else if ( keyAction == AKEY_EVENT_ACTION_MULTIPLE ) { // TODO: Multiple duplicate key events have occurred in a row, // or a complex string is being delivered. The repeat_count // property of the key event contains the number of times the // given key code should be executed. // I guess this might necessary for more complicated i18n key input, // but don't see yet how to handle this correctly. } /* no use for meta keys so far. if ( keyMetaState & AMETA_ALT_ON || keyMetaState & AMETA_ALT_LEFT_ON || keyMetaState & AMETA_ALT_RIGHT_ON ) ; // what is a sym? if ( keyMetaState & AMETA_SYM_ON ) ; */ if ( keyMetaState & AMETA_SHIFT_ON || keyMetaState & AMETA_SHIFT_LEFT_ON || keyMetaState & AMETA_SHIFT_RIGHT_ON ) event.KeyInput.Shift = true; else event.KeyInput.Shift = false; event.KeyInput.Control = false; // Having memory allocations + going through JNI for each key-press is pretty bad (slow). // So we do it only for those keys which are likely text-characters and avoid it for all other keys. // So it's fast for keys like game controller input and special keys. And text keys are typically // only used or entering text and not for gaming on Android, so speed likely doesn't matter there too much. if ( event.KeyInput.Key > 0 ) { // TODO: // Not sure why we have to attach a JNIEnv here, but it won't work when doing that in the constructor or // trying to use the activity->env. My best guess is that the event-handling happens in an own thread. // It means JNIEnvAttachedToVM will never get detached as I don't know a safe way where to do that // (we could attach & detach each time, but that would probably be slow) // Also - it has to be each time as it get's invalid when the application mode changes. if ( device->Initialized && device->Android && device->Android->activity && device->Android->activity->vm ) { JavaVMAttachArgs attachArgs; attachArgs.version = JNI_VERSION_1_6; attachArgs.name = 0; attachArgs.group = NULL; // Not a big problem calling it each time - it's a no-op when the thread already is attached. // And we have to do that as someone else can have detached the thread in the meantime. jint result = device->Android->activity->vm->AttachCurrentThread(&device->JNIEnvAttachedToVM, &attachArgs); if(result == JNI_ERR) { os::Printer::log("AttachCurrentThread for the JNI environment failed.", ELL_WARNING); device->JNIEnvAttachedToVM = 0; } if ( device->JNIEnvAttachedToVM ) { jni::CKeyEventWrapper * keyEventWrapper = new jni::CKeyEventWrapper(device->JNIEnvAttachedToVM, keyAction, keyCode); event.KeyInput.Char = keyEventWrapper->getUnicodeChar(keyMetaState); delete keyEventWrapper; } } if ( event.KeyInput.Key == KEY_BACK ) { event.KeyInput.Char = 0x08; // same key-code as on other operating systems. Otherwise we have to handle too much system specific stuff in the editbox. } //os::Printer::log("char-code: ", core::stringc((int)event.KeyInput.Char).c_str(), ELL_DEBUG); } else { // os::Printer::log("keyCode: ", core::stringc(keyCode).c_str(), ELL_DEBUG); event.KeyInput.Char = 0; } device->postEventFromUser(event); } break; default: break; } return status; }
bool InputService::onTrackballEvent(AInputEvent* pEvent) { #ifdef INPUTSERVICE_LOG_EVENTS packt_Log_debug("AMotionEvent_getAction=%d", AMotionEvent_getAction(pEvent)); packt_Log_debug("AMotionEvent_getFlags=%d", AMotionEvent_getFlags(pEvent)); packt_Log_debug("AMotionEvent_getMetaState=%d", AMotionEvent_getMetaState(pEvent)); packt_Log_debug("AMotionEvent_getEdgeFlags=%d", AMotionEvent_getEdgeFlags(pEvent)); packt_Log_debug("AMotionEvent_getDownTime=%lld", AMotionEvent_getDownTime(pEvent)); packt_Log_debug("AMotionEvent_getEventTime=%lld", AMotionEvent_getEventTime(pEvent)); packt_Log_debug("AMotionEvent_getXOffset=%f", AMotionEvent_getXOffset(pEvent)); packt_Log_debug("AMotionEvent_getYOffset=%f", AMotionEvent_getYOffset(pEvent)); packt_Log_debug("AMotionEvent_getXPrecision=%f", AMotionEvent_getXPrecision(pEvent)); packt_Log_debug("AMotionEvent_getYPrecision=%f", AMotionEvent_getYPrecision(pEvent)); packt_Log_debug("AMotionEvent_getPointerCount=%d", AMotionEvent_getPointerCount(pEvent)); packt_Log_debug("AMotionEvent_getRawX=%f", AMotionEvent_getRawX(pEvent, 0)); packt_Log_debug("AMotionEvent_getRawY=%f", AMotionEvent_getRawY(pEvent, 0)); packt_Log_debug("AMotionEvent_getX=%f", AMotionEvent_getX(pEvent, 0)); packt_Log_debug("AMotionEvent_getY=%f", AMotionEvent_getY(pEvent, 0)); packt_Log_debug("AMotionEvent_getPressure=%f", AMotionEvent_getPressure(pEvent, 0)); packt_Log_debug("AMotionEvent_getSize=%f", AMotionEvent_getSize(pEvent, 0)); packt_Log_debug("AMotionEvent_getOrientation=%f", AMotionEvent_getOrientation(pEvent, 0)); packt_Log_debug("AMotionEvent_getTouchMajor=%f", AMotionEvent_getTouchMajor(pEvent, 0)); packt_Log_debug("AMotionEvent_getTouchMinor=%f", AMotionEvent_getTouchMinor(pEvent, 0)); #endif const float ORTHOGONAL_MOVE = 1.0f; const float DIAGONAL_MOVE = 0.707f; const float THRESHOLD = (1/100.0f); if (AMotionEvent_getAction(pEvent) == AMOTION_EVENT_ACTION_MOVE) { float lDirectionX = AMotionEvent_getX(pEvent, 0); float lDirectionY = AMotionEvent_getY(pEvent, 0); float lHorizontal, lVertical; if (lDirectionX < -THRESHOLD) { if (lDirectionY < -THRESHOLD) { lHorizontal = -DIAGONAL_MOVE; lVertical = DIAGONAL_MOVE; } else if (lDirectionY > THRESHOLD) { lHorizontal = -DIAGONAL_MOVE; lVertical = -DIAGONAL_MOVE; } else { lHorizontal = -ORTHOGONAL_MOVE; lVertical = 0.0f; } } else if (lDirectionX > THRESHOLD) { if (lDirectionY < -THRESHOLD) { lHorizontal = DIAGONAL_MOVE; lVertical = DIAGONAL_MOVE; } else if (lDirectionY > THRESHOLD) { lHorizontal = DIAGONAL_MOVE; lVertical = -DIAGONAL_MOVE; } else { lHorizontal = ORTHOGONAL_MOVE; lVertical = 0.0f; } } else if (lDirectionY < -THRESHOLD) { lHorizontal = 0.0f; lVertical = ORTHOGONAL_MOVE; } else if (lDirectionY > THRESHOLD) { lHorizontal = 0.0f; lVertical = -ORTHOGONAL_MOVE; } // Ends movement if there is a counter movement. if ((lHorizontal < 0.0f) && (mHorizontal > 0.0f)) { mHorizontal = 0.0f; } else if ((lHorizontal > 0.0f) && (mHorizontal < 0.0f)) { mHorizontal = 0.0f; } else { mHorizontal = lHorizontal; } if ((lVertical < 0.0f) && (mVertical > 0.0f)) { mVertical = 0.0f; } else if ((lVertical > 0.0f) && (mVertical < 0.0f)) { mVertical = 0.0f; } else { mVertical = lVertical; } } else { mHorizontal = 0.0f; mVertical = 0.0f; } return true; }
int Engine::handleInput(AInputEvent* event) { //We only handle motion events (touchscreen) and key (button/key) events int32_t eventType = AInputEvent_getType(event); if (eventType == AINPUT_EVENT_TYPE_MOTION) { int32_t edgeFlags = AMotionEvent_getEdgeFlags(event); if(edgeFlags == AMOTION_EVENT_EDGE_FLAG_NONE) { //The current motion event (touch) is within screen bounds int32_t action = AMOTION_EVENT_ACTION_MASK & AMotionEvent_getAction((const AInputEvent*)event); int32_t iX = AMotionEvent_getX(event, 0); int32_t iY = AMotionEvent_getY(event, 0); if (checkUIHandledMotion(iX, iY, action)) return 0; if (AMOTION_EVENT_ACTION_UP == action) { mGlobeApp->pauseAnim(false); mLastX = mEgl.getWidth() / 2; mLastY = mEgl.getHeight() / 2; } else if (AMOTION_EVENT_ACTION_DOWN == action) { mGlobeApp->pauseAnim(true); mLastX = iX; mLastY = iY; } else if (AMOTION_EVENT_ACTION_MOVE == action) { // Empirical value (how many degrees to rotate when dragging finger on screen so // it looks like finger is "anchored" const static float DEGS_PER_PIXEL_DRAG = 0.25f; float fRotX = (float)(iY - mLastY) * DEGS_PER_PIXEL_DRAG; float fRotY = (float)(iX - mLastX) * DEGS_PER_PIXEL_DRAG; mGlobeApp->addRotation(fRotX, fRotY); mGlobeApp->positionCamera(); mLastX = iX; mLastY = iY; } return 1; } else // if(edgeFlags == AMOTION_EVENT_EDGE_FLAG_NONE) { //The current motion event (touch) has reached an edge. //We process it the same way as if we were touching and we had lifted //the finger off the screen mGlobeApp->pauseAnim(false); mLastX = mEgl.getWidth() / 2; mLastY = mEgl.getHeight() / 2; return 1; } } else if (eventType == AINPUT_EVENT_TYPE_KEY) { int32_t action = AKeyEvent_getAction((const AInputEvent*)event); int32_t code = AKeyEvent_getKeyCode((const AInputEvent*)event); int returnCode = 1; // pass to the on-screen UI, which will return what our "handled" code should be // or will return false to us, which indicates that the UI is allowing default // behavior for the key if (checkUIHandledKey(code, action, returnCode)) return returnCode; } return 0; }
bool OuyaInputView::dispatchGenericMotionEvent(AInputEvent* motionEvent) { int64_t downTime = AMotionEvent_getDownTime(motionEvent); int64_t eventTime = AMotionEvent_getEventTime(motionEvent); int32_t action = AMotionEvent_getAction(motionEvent); int32_t metaState = AMotionEvent_getMetaState(motionEvent); int32_t pointerCount = AMotionEvent_getPointerCount(motionEvent); int32_t buttonState = AMotionEvent_getButtonState(motionEvent); float xPrecision = AMotionEvent_getXPrecision(motionEvent); float yPrecision = AMotionEvent_getYPrecision(motionEvent); int32_t deviceId = AInputEvent_getDeviceId(motionEvent); int32_t edgeFlags = AMotionEvent_getEdgeFlags(motionEvent); int32_t flags = AMotionEvent_getFlags(motionEvent); int32_t source = AInputEvent_getSource(motionEvent); int* pointerPropertiesId = new int[pointerCount]; int* pointerPropertiesToolType = new int[pointerCount]; float* pointerCoordsOrientation = new float[pointerCount]; float* pointerCoordsPressure = new float[pointerCount]; float* pointerCoordsSize = new float[pointerCount]; float* pointerCoordsToolMajor = new float[pointerCount]; float* pointerCoordsToolMinor = new float[pointerCount]; float* pointerCoordsTouchMajor = new float[pointerCount]; float* pointerCoordsTouchMinor = new float[pointerCount]; float* pointerCoordsX = new float[pointerCount]; float* pointerCoordsY = new float[pointerCount]; std::vector<int> listAxisIndices; std::vector<float> listAxisValues; if (pointerCount > 0) { #if ENABLE_VERBOSE_LOGGING __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "pointerCount=%d deviceId=%d source=%d", pointerCount, deviceId, source); #endif // MotionEvent.PointerProperties long long pointerId = AMotionEvent_getPointerId(motionEvent, 0); int32_t toolType = AMotionEvent_getToolType(motionEvent, 0); #if ENABLE_VERBOSE_LOGGING __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "PointerProperties pointerId=%lld toolType-%d", pointerId, toolType); #endif pointerPropertiesId[0] = pointerId; pointerPropertiesToolType[0] = toolType; // MotionEvent.PointerCoords float orientation = AMotionEvent_getOrientation(motionEvent, pointerId); float pressure = AMotionEvent_getPressure(motionEvent, pointerId); float size = AMotionEvent_getSize(motionEvent, pointerId); float toolMajor = AMotionEvent_getTouchMajor(motionEvent, pointerId); float toolMinor = AMotionEvent_getToolMinor(motionEvent, pointerId); float touchMajor = AMotionEvent_getTouchMajor(motionEvent, pointerId); float touchMinor = AMotionEvent_getTouchMinor(motionEvent, pointerId); float x = AMotionEvent_getX(motionEvent, pointerId); float y = AMotionEvent_getY(motionEvent, pointerId); #if ENABLE_VERBOSE_LOGGING __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "PointerCoords orientation=%f pressure=%f size=%f toolMajor=%f toolMinor=%f touchMajor=%f touchMinor=%f x=%f y=%f", orientation, pressure, size, toolMajor, toolMinor, touchMajor, touchMinor, x, y); #endif pointerCoordsOrientation[0] = orientation; pointerCoordsPressure[0] = pressure; pointerCoordsSize[0] = size; pointerCoordsToolMajor[0] = toolMajor; pointerCoordsToolMinor[0] = toolMinor; pointerCoordsTouchMajor[0] = touchMajor; pointerCoordsTouchMinor[0] = touchMinor; pointerCoordsX[0] = x; pointerCoordsY[0] = y; for (int32_t axis = 0; axis < 50; ++axis) // 50 is based on the AXIS_value range I saw in the documentation { float val = AMotionEvent_getAxisValue(motionEvent, axis, pointerId); if (val != 0.0f) { #if ENABLE_VERBOSE_LOGGING __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "axis=%d val=%f", axis, val); #endif listAxisIndices.push_back(axis); listAxisValues.push_back(val); } } } int axisCount = listAxisIndices.size(); int* axisIndexes = new int[axisCount]; float* axisValues = new float[axisCount]; for (int index = 0; index < axisCount; ++index) { axisIndexes[index] = listAxisIndices[index]; axisValues[index] = listAxisValues[index]; } listAxisIndices.clear(); listAxisValues.clear(); bool handled = javaDispatchGenericMotionEvent( downTime, eventTime, action, pointerCount, metaState, buttonState, xPrecision, yPrecision, deviceId, edgeFlags, source, flags, pointerPropertiesId, pointerPropertiesToolType, pointerCoordsOrientation, pointerCoordsPressure, pointerCoordsSize, pointerCoordsToolMajor, pointerCoordsToolMinor, pointerCoordsTouchMajor, pointerCoordsTouchMinor, pointerCoordsX, pointerCoordsY, axisCount, axisIndexes, axisValues); delete pointerPropertiesId; delete pointerPropertiesToolType; delete pointerCoordsOrientation; delete pointerCoordsPressure; delete pointerCoordsSize; delete pointerCoordsToolMajor; delete pointerCoordsToolMinor; delete pointerCoordsTouchMajor; delete pointerCoordsTouchMinor; delete pointerCoordsX; delete pointerCoordsY; delete axisIndexes; delete axisValues; return handled; }