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 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; }
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; }
static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) { struct engine* engine = (struct engine*)app->userData; if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) { // touch event int action = AMotionEvent_getAction( event ) & 0xff; int pointer = (AMotionEvent_getAction( event ) >> 8) & 0xff; int flags = AMotionEvent_getFlags( event ); int pointers = AMotionEvent_getPointerCount( event ); int id = AMotionEvent_getPointerId( event, pointer ); float x = AMotionEvent_getX( event, pointer ); float y = AMotionEvent_getY( event, pointer ); //if ( action != 2 ) LOGW("Action: %d, pointer: %d, count: %d, id: %d", action, pointer, pointers, id); //__android_log_print(ANDROID_LOG_VERBOSE, "test", "Action: %d, pointer: %d, count: %d, id: %d, lx: %f, ly: %f, rx: %f, ry: %f", action, pointer, pointers, id, lx, ly, rx, ry); switch ( action ) { case 0: case 5: touchdown( id, x, y ); break; case 1: case 3: case 6: touchup( id, x, y ); break; case 2: { float lx = AMotionEvent_getAxisValue(event, AXIS_X, pointer); float ly = AMotionEvent_getAxisValue(event, AXIS_Y, pointer); float rx = AMotionEvent_getAxisValue(event, AXIS_Z, pointer); float ry = AMotionEvent_getAxisValue(event, AXIS_RZ, pointer); if((lx > joystick_treshold || lx < -joystick_treshold) || (ly > joystick_treshold || ly < -joystick_treshold)) { touchdown( 0, lx*1000.0f, ly*1000.0f ); // touchmoved( 0, x*100.0f, y*100.0f ); } else touchup( 0, lx*1000.0f, ly*1000.0f ); if((rx > joystick_treshold || rx < -joystick_treshold) || (ry > joystick_treshold || ry < -joystick_treshold)) { touchdown( 1, rx*1000.0f, ry*1000.0f ); // touchmoved( -1, x*255.0f, y*255.0f ); // __android_log_print(ANDROID_LOG_VERBOSE, "test", "right joystick moved"); } else touchup( 1, rx*1000.0f, ry*1000.0f ); // only the primary pointer sends move messages so get the other pointer positions while we are here if ( pointers > 1 ) { int i = 1; for ( i = 1; i < pointers; i++ ) { int id = AMotionEvent_getPointerId( event, i ); x = AMotionEvent_getX( event, i ); y = AMotionEvent_getY( event, i ); touchmoved( id, x, y ); } } break; } default: break; } return 1; }