/******************************************************************** * Process the next input event. *******************************************************************/ static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) { if(app==NULL) return 0; struct engine* engine = (struct engine*)app->userData; if(engine == NULL || event == NULL) return 0; if (AInputEvent_getType(event) != AINPUT_EVENT_TYPE_MOTION) return 0; switch(AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK) { case AMOTION_EVENT_ACTION_DOWN: { engine->state.x = (((int)AMotionEvent_getX(event, 1))<<16) | (int)AMotionEvent_getX(event, 0); engine->state.y = (((int)AMotionEvent_getY(event, 1))<<16) | (int)AMotionEvent_getY(event, 0); opengl_touch(engine->state.x, engine->state.y, 0); int32_t idx = (AMotionEvent_getAction(event)& AMOTION_EVENT_ACTION_POINTER_INDEX_MASK); LOGI("AMOTION_EVENT_ACTION_DOWN,idx=%d",idx>>8); } return 1; case AMOTION_EVENT_ACTION_UP: { engine->state.x = (((int)AMotionEvent_getX(event, 1))<<16) | (int)AMotionEvent_getX(event, 0); engine->state.y = (((int)AMotionEvent_getY(event, 1))<<16) | (int)AMotionEvent_getY(event, 0); opengl_touch(engine->state.x, engine->state.y, 2); int32_t idx = (AMotionEvent_getAction(event)& AMOTION_EVENT_ACTION_POINTER_INDEX_MASK); LOGI("AMOTION_EVENT_ACTION_UP,idx=%d",idx>>8); } return 1; case AMOTION_EVENT_ACTION_MOVE: engine->state.x = (((int)AMotionEvent_getX(event, 1))<<16) | (int)AMotionEvent_getX(event, 0); engine->state.y = (((int)AMotionEvent_getY(event, 1))<<16) | (int)AMotionEvent_getY(event, 0); opengl_touch(engine->state.x, engine->state.y, 1); return 1; case AMOTION_EVENT_ACTION_POINTER_DOWN: { engine->state.x = (((int)AMotionEvent_getX(event, 1))<<16) | (int)AMotionEvent_getX(event, 0); engine->state.y = (((int)AMotionEvent_getY(event, 1))<<16) | (int)AMotionEvent_getY(event, 0); int32_t idx = (AMotionEvent_getAction(event)& AMOTION_EVENT_ACTION_POINTER_INDEX_MASK); opengl_touch(engine->state.x, engine->state.y, 3); LOGI("AMOTION_EVENT_ACTION_POINTER_DOWN,idx=%d",idx>>8); } return 1; case AMOTION_EVENT_ACTION_POINTER_UP: { engine->state.x = (((int)AMotionEvent_getX(event, 1))<<16) | (int)AMotionEvent_getX(event, 0); engine->state.y = (((int)AMotionEvent_getY(event, 1))<<16) | (int)AMotionEvent_getY(event, 0); int32_t idx = (AMotionEvent_getAction(event)& AMOTION_EVENT_ACTION_POINTER_INDEX_MASK); opengl_touch(engine->state.x, engine->state.y, 4); LOGI("AMOTION_EVENT_ACTION_POINTER_UP,idx=%d",idx>>8); } return 1; default: break; } /* if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) { engine->state.x = AMotionEvent_getX(event, 0); engine->state.y = AMotionEvent_getY(event, 0); opengl_touch(engine->state.x, engine->state.y, 0); return 1; }*/ return 0; }
int 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; return 0; } // 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); lJNIEnv->DeleteLocalRef(ClassMotionEvent); lJNIEnv->DeleteLocalRef(ObjectMotionEvent); // 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); // Detach this thread from the JVM lJavaVM->DetachCurrentThread(); return 1; }
static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) { engine* e = (engine*)app->userData; if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY) { int32_t key = AKeyEvent_getKeyCode(event); int32_t key_action = AKeyEvent_getAction(event); if (key == AKEYCODE_BACK) { LOGD( "engine_handle_input", "AKEYCODE_BACK"); if (key_action == AKEY_EVENT_ACTION_UP) { LOGD("engine_handle_input", "AKEY_EVENT_ACTION_UP"); } return 1; // <-- prevent default handler } if (key == AKEYCODE_MENU) { LOGD( "engine_handle_input", "AKEYCODE_MENU"); if (key_action == AKEY_EVENT_ACTION_UP) { LOGD("engine_handle_input", "AKEY_EVENT_ACTION_UP"); } return 1; // <-- prevent default handler } /* if (key == AKEYCODE_HOME) { LOGD( "engine_handle_input", "AKEYCODE_HOME"); if (key_action == AKEY_EVENT_ACTION_UP) { LOGD("engine_handle_input", "AKEY_EVENT_ACTION_UP"); } return 1; // <-- prevent default handler } if (key == AKEYCODE_VOLUME_UP) { LOGD( "engine_handle_input", "AKEYCODE_VOLUME_UP"); if (key_action == AKEY_EVENT_ACTION_UP) { LOGD("engine_handle_input", "AKEY_EVENT_ACTION_UP"); } return 1; // <-- prevent default handler } if (key == AKEYCODE_VOLUME_DOWN) { LOGD( "engine_handle_input", "AKEYCODE_VOLUME_DOWN"); if (key_action == AKEY_EVENT_ACTION_UP) { LOGD("engine_handle_input", "AKEY_EVENT_ACTION_UP"); } return 1; // <-- prevent default handler }*/ } int index = 0; int touch_max = 5; if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) { if (touch_enabled) { int p; int action = AKeyEvent_getAction(event); switch (action & AMOTION_EVENT_ACTION_MASK) { case AMOTION_EVENT_ACTION_DOWN: LOGDw("engine_handle_input", "AMOTION_EVENT_ACTION_DOWN"); touch_branching(AMotionEvent_getX(event, 0), AMotionEvent_getY(event, 0)); e->animating = 1; break; case AMOTION_EVENT_ACTION_POINTER_DOWN: LOGDw( "engine_handle_input", "AMOTION_EVENT_ACTION_POINTER_DOWN"); /* Bits in the action code that represent a pointer index, used with * AMOTION_EVENT_ACTION_POINTER_DOWN and AMOTION_EVENT_ACTION_POINTER_UP. Shifting * down by AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT provides the actual pointer * index where the data for the pointer going up or down can be found. */ // AMOTION_EVENT_ACTION_POINTER_INDEX_MASK = 0xff00, // マルチタッチバグを解決するため、こうやれば一番いい。 size_t pointer_index_mask = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; trigger_note(AMotionEvent_getX(event, pointer_index_mask), AMotionEvent_getY(event, pointer_index_mask)); set_parts_active(); LOGD("engine_handle_input", "pointer_index_mask: %d", pointer_index_mask); break; } return 1; } } return 0; }
/** * Process the next input event. */ int32_t handle_input(struct android_app* app, AInputEvent* event) { SFG_Window* window = fgStructure.CurrentWindow; /* FIXME: in Android, when key is repeated, down and up events happen most often at the exact same time. This makes it impossible to animate based on key press time. */ /* e.g. down/up/wait/down/up rather than down/wait/down/wait/up */ if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY) { /* LOGI("action: %d", AKeyEvent_getAction(event)); */ /* LOGI("keycode: %d", code); */ int32_t code = AKeyEvent_getKeyCode(event); if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN) { int32_t keypress = 0; unsigned char ascii = 0; if ((keypress = key_a2fg[code]) && FETCH_WCB(*window, Special)) { INVOKE_WCB(*window, Special, (keypress, window->State.MouseX, window->State.MouseY)); return EVENT_HANDLED; } else if ((ascii = key_ascii(app, event)) && FETCH_WCB(*window, Keyboard)) { INVOKE_WCB(*window, Keyboard, (ascii, window->State.MouseX, window->State.MouseY)); return EVENT_HANDLED; } } else if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_UP) { int32_t keypress = 0; unsigned char ascii = 0; if ((keypress = key_a2fg[code]) && FETCH_WCB(*window, Special)) { INVOKE_WCB(*window, SpecialUp, (keypress, window->State.MouseX, window->State.MouseY)); return EVENT_HANDLED; } else if ((ascii = key_ascii(app, event)) && FETCH_WCB(*window, Keyboard)) { INVOKE_WCB(*window, KeyboardUp, (ascii, window->State.MouseX, window->State.MouseY)); return EVENT_HANDLED; } } } if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) { int32_t action = AMotionEvent_getAction(event); float x = AMotionEvent_getX(event, 0); float y = AMotionEvent_getY(event, 0); LOGI("motion %.01f,%.01f action=%d", x, y, AMotionEvent_getAction(event)); /* Virtual arrows PAD */ // Don't interfere with existing mouse move event if (!touchscreen.in_mmotion) { struct vpad_state prev_vpad = touchscreen.vpad; touchscreen.vpad.left = touchscreen.vpad.right = touchscreen.vpad.up = touchscreen.vpad.down = false; int32_t width = ANativeWindow_getWidth(window->Window.Handle); int32_t height = ANativeWindow_getHeight(window->Window.Handle); if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_MOVE) { if ((x > 0 && x < 100) && (y > (height - 100) && y < height)) touchscreen.vpad.left = true; if ((x > 200 && x < 300) && (y > (height - 100) && y < height)) touchscreen.vpad.right = true; if ((x > 100 && x < 200) && (y > (height - 100) && y < height)) touchscreen.vpad.down = true; if ((x > 100 && x < 200) && (y > (height - 200) && y < (height - 100))) touchscreen.vpad.up = true; } if (action == AMOTION_EVENT_ACTION_DOWN && (touchscreen.vpad.left || touchscreen.vpad.right || touchscreen.vpad.down || touchscreen.vpad.up)) touchscreen.vpad.on = true; if (action == AMOTION_EVENT_ACTION_UP) touchscreen.vpad.on = false; if (prev_vpad.left != touchscreen.vpad.left || prev_vpad.right != touchscreen.vpad.right || prev_vpad.up != touchscreen.vpad.up || prev_vpad.down != touchscreen.vpad.down || prev_vpad.on != touchscreen.vpad.on) { if (FETCH_WCB(*window, Special)) { if (prev_vpad.left == false && touchscreen.vpad.left == true) INVOKE_WCB(*window, Special, (GLUT_KEY_LEFT, x, y)); else if (prev_vpad.right == false && touchscreen.vpad.right == true) INVOKE_WCB(*window, Special, (GLUT_KEY_RIGHT, x, y)); else if (prev_vpad.up == false && touchscreen.vpad.up == true) INVOKE_WCB(*window, Special, (GLUT_KEY_UP, x, y)); else if (prev_vpad.down == false && touchscreen.vpad.down == true) INVOKE_WCB(*window, Special, (GLUT_KEY_DOWN, x, y)); } if (FETCH_WCB(*window, SpecialUp)) { if (prev_vpad.left == true && touchscreen.vpad.left == false) INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_LEFT, x, y)); if (prev_vpad.right == true && touchscreen.vpad.right == false) INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_RIGHT, x, y)); if (prev_vpad.up == true && touchscreen.vpad.up == false) INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_UP, x, y)); if (prev_vpad.down == true && touchscreen.vpad.down == false) INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_DOWN, x, y)); } return EVENT_HANDLED; } } /* Normal mouse events */ if (!touchscreen.vpad.on) { window->State.MouseX = x; window->State.MouseY = y; LOGI("Changed mouse position: %d,%d", x, y); if (action == AMOTION_EVENT_ACTION_DOWN && FETCH_WCB(*window, Mouse)) { touchscreen.in_mmotion = true; INVOKE_WCB(*window, Mouse, (GLUT_LEFT_BUTTON, GLUT_DOWN, x, y)); } else if (action == AMOTION_EVENT_ACTION_UP && FETCH_WCB(*window, Mouse)) { touchscreen.in_mmotion = false; INVOKE_WCB(*window, Mouse, (GLUT_LEFT_BUTTON, GLUT_UP, x, y)); } else if (action == AMOTION_EVENT_ACTION_MOVE && FETCH_WCB(*window, Motion)) { INVOKE_WCB(*window, Motion, (x, y)); } } return EVENT_HANDLED; } /* Let Android handle other events (e.g. Back and Menu buttons) */ return EVENT_NOT_HANDLED; }
int32_t processInput(struct android_app* androidApp, AInputEvent* event) { if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) { const int32_t action = AMotionEvent_getAction(event); const int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; const int32_t pointerCount = AMotionEvent_getPointerCount(event); const int32_t pointerId = AMotionEvent_getPointerId(event, pointerIndex); const float x = AMotionEvent_getX(event, pointerIndex); const float y = AMotionEvent_getY(event, pointerIndex); const int32_t actionMasked = (action & AMOTION_EVENT_ACTION_MASK); switch (actionMasked) { case AMOTION_EVENT_ACTION_DOWN: case AMOTION_EVENT_ACTION_POINTER_DOWN: { deviceEventQueue.pushButtonEvent(InputDeviceType::TOUCHSCREEN , 0 , pointerId , true ); } break; case AMOTION_EVENT_ACTION_UP: case AMOTION_EVENT_ACTION_POINTER_UP: { deviceEventQueue.pushButtonEvent(InputDeviceType::TOUCHSCREEN , 0 , pointerId , false ); } break; case AMOTION_EVENT_ACTION_OUTSIDE: case AMOTION_EVENT_ACTION_CANCEL: { deviceEventQueue.pushButtonEvent(InputDeviceType::TOUCHSCREEN , 0 , pointerId , false ); } break; case AMOTION_EVENT_ACTION_MOVE: { for (int index = 0; index < pointerCount; index++) { const float xx = AMotionEvent_getX(event, index); const float yy = AMotionEvent_getY(event, index); const int32_t pointerId = AMotionEvent_getPointerId(event, index); deviceEventQueue.pushAxisEvent(InputDeviceType::TOUCHSCREEN , 0 , pointerId , xx , yy , 0.0f ); } } break; } return 1; } else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY)
void StWindowImpl::onAndroidInput(const AInputEvent* theEvent, bool& theIsProcessed) { const int anEventType = AInputEvent_getType(theEvent); switch(anEventType) { case AINPUT_EVENT_TYPE_KEY: { StVirtKey aVKeySt = ST_VK_NULL; int32_t aKeySym = AKeyEvent_getKeyCode(theEvent); if(aKeySym < ST_ANDROID2ST_VK_SIZE) { aVKeySt = (StVirtKey )ST_ANDROID2ST_VK[aKeySym]; } if(aVKeySt == ST_VK_NULL) { return; } myStEvent.Key.Time = getEventTime(); //AKeyEvent_getEventTime(theEvent); myStEvent.Key.VKey = aVKeySt; myStEvent.Key.Char = 0; const int32_t aKeyAction = AKeyEvent_getAction(theEvent); if(aKeyAction == AKEY_EVENT_ACTION_DOWN) { postKeyDown(myStEvent); } else if(aKeyAction == AKEY_EVENT_ACTION_UP) { postKeyUp(myStEvent); }// else if(aKeyAction == AKEY_EVENT_ACTION_MULTIPLE) {} return; } case AINPUT_EVENT_TYPE_MOTION: { theIsProcessed = true; const int32_t aSource = AInputEvent_getSource(theEvent); const int32_t anActionPak = AMotionEvent_getAction(theEvent); const int32_t anAction = anActionPak & AMOTION_EVENT_ACTION_MASK; const size_t anActionPntIndex = anActionPak & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK; //const StRectI_t& aWinRect = attribs.IsFullScreen ? myRectFull : myRectNorm; const StRectI_t& aWinRect = myRectNorm; const float aWinSizeX = aWinRect.width(); const float aWinSizeY = aWinRect.height(); // at least single point is defined StPointD_t aPos0(double(AMotionEvent_getX(theEvent, 0)) / double(aWinSizeX), double(AMotionEvent_getY(theEvent, 0)) / double(aWinSizeY)); myStEvent.Type = stEvent_None; myStEvent.Base.Time = getEventTime(); /// int64_t AMotionEvent_getEventTime(theEvent); switch(aSource) { case AINPUT_SOURCE_TOUCHSCREEN: case AINPUT_SOURCE_TOUCHPAD: { const size_t aNbTouches = AMotionEvent_getPointerCount(theEvent); myStEvent.Touch.NbTouches = std::min(aNbTouches, (size_t )ST_MAX_TOUCHES); bool isUp = anAction == AMOTION_EVENT_ACTION_UP || anAction == AMOTION_EVENT_ACTION_POINTER_UP; if(isUp) { myStEvent.Touch.NbTouches = std::max(myStEvent.Touch.NbTouches - 1, 0); } for(size_t aTouchIter = 0; aTouchIter < ST_MAX_TOUCHES; ++aTouchIter) { StTouch& aTouch = myStEvent.Touch.Touches[aTouchIter]; aTouch = StTouch::Empty(); if(aTouchIter == anActionPntIndex && isUp) { continue; } if(aTouchIter >= aNbTouches) { continue; } aTouch.Id = AMotionEvent_getPointerId(theEvent, aTouchIter); aTouch.DeviceId = AInputEvent_getDeviceId(theEvent); aTouch.OnScreen = aSource == AINPUT_SOURCE_TOUCHSCREEN; const float aPosX = AMotionEvent_getX(theEvent, aTouchIter); const float aPosY = AMotionEvent_getY(theEvent, aTouchIter); aTouch.PointX = (aPosX - float(aWinRect.left())) / aWinSizeX; aTouch.PointY = (aPosY - float(aWinRect.top())) / aWinSizeY; } switch(anAction) { case AMOTION_EVENT_ACTION_DOWN: case AMOTION_EVENT_ACTION_POINTER_DOWN: { myStEvent.Type = stEvent_TouchDown; doTouch(myStEvent.Touch); if(aNbTouches == 1) { // simulate mouse click myMousePt = aPos0; myIsPreciseCursor = false; myStEvent.Type = stEvent_MouseDown; myStEvent.Button.Button = ST_MOUSE_LEFT; myStEvent.Button.Buttons = 0; myStEvent.Button.PointX = myMousePt.x(); myStEvent.Button.PointY = myMousePt.y(); signals.onMouseDown->emit(myStEvent.Button); } else if(aNbTouches == 2) { // emit special event to cancel previously simulated click myStEvent.Type = stEvent_MouseCancel; myStEvent.Button.Button = ST_MOUSE_LEFT; myStEvent.Button.Buttons = 0; myStEvent.Button.PointX = myMousePt.x(); myStEvent.Button.PointY = myMousePt.y(); signals.onMouseUp->emit(myStEvent.Button); } break; } case AMOTION_EVENT_ACTION_MOVE: { myStEvent.Type = stEvent_TouchMove; if(aNbTouches == 1) { // simulate mouse move myMousePt = aPos0; myIsPreciseCursor = false; } doTouch(myStEvent.Touch); break; } case AMOTION_EVENT_ACTION_UP: case AMOTION_EVENT_ACTION_POINTER_UP: { myStEvent.Type = stEvent_TouchUp; doTouch(myStEvent.Touch); if(aNbTouches == 1) { // simulate mouse unclick myMousePt = aPos0; myIsPreciseCursor = false; myStEvent.Type = stEvent_MouseUp; myStEvent.Button.Button = ST_MOUSE_LEFT; myStEvent.Button.Buttons = 0; myStEvent.Button.PointX = myMousePt.x(); myStEvent.Button.PointY = myMousePt.y(); signals.onMouseUp->emit(myStEvent.Button); } break; } case AMOTION_EVENT_ACTION_CANCEL: { myStEvent.Type = stEvent_TouchCancel; doTouch(myStEvent.Touch); break; } } return; } } myMousePt = aPos0; myIsPreciseCursor = aSource == AINPUT_SOURCE_MOUSE; // || AINPUT_SOURCE_STYLUS StVirtButton aMouseBtn = ST_MOUSE_LEFT; myStEvent.Button.Button = aMouseBtn; myStEvent.Button.Buttons = 0; myStEvent.Button.PointX = myMousePt.x(); myStEvent.Button.PointY = myMousePt.y(); if(anAction == AMOTION_EVENT_ACTION_DOWN) { myStEvent.Type = stEvent_MouseDown; signals.onMouseDown->emit(myStEvent.Button); } else if(anAction == AMOTION_EVENT_ACTION_UP) { myStEvent.Type = stEvent_MouseUp; signals.onMouseUp->emit(myStEvent.Button); } return; } } }
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; }
/** * Process the next input event. */ int32_t Engine::handleInput(AInputEvent* event) { if (mCallbacks && mGamepad->pollGamepads(event, mPadChangedMask)) return true; else if (NULL==mCallbacks) return false; if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) { bool handled = false; int32_t pointerCount = AMotionEvent_getPointerCount(event); int32_t action = amotion_getActionMasked(event); int32_t pointerIndex = amotion_getActionIndex(event); float x=0, y=0; NvPointerEvent p[20]; // !!!!!TBD should use linkedlist or app-member struct or something? TODO NvInputDeviceType::Enum dev = NvInputDeviceType::TOUCH; // loop over pointercount and copy data // !!!!TBD TODO, might need to ensure that p[0] is always the data from the first-finger-touched ID... for (int i=0; i<pointerCount; i++) { x = AMotionEvent_getX(event, i); y = AMotionEvent_getY(event, i); p[i].m_x = x; p[i].m_y = y; p[i].m_id = AMotionEvent_getPointerId(event, i); // then figure out tool/device enum... int32_t tool = AMotionEvent_getToolType(event, i); if (tool==AMOTION_EVENT_TOOL_TYPE_STYLUS || tool==AMOTION_EVENT_TOOL_TYPE_ERASER)//!!!!TBD TODO dev = NvInputDeviceType::STYLUS; else if (tool==AMOTION_EVENT_TOOL_TYPE_MOUSE) dev = NvInputDeviceType::MOUSE; else dev = NvInputDeviceType::TOUCH; // else we assume == FINGER... if unknown, treat as FINGER. TODO. p[i].m_device = dev; } mState.x = x; mState.y = y; NvPointerActionType::Enum pact; switch(action) { case AMOTION_EVENT_ACTION_DOWN: pact = NvPointerActionType::DOWN; break; case AMOTION_EVENT_ACTION_POINTER_DOWN: pact = NvPointerActionType::EXTRA_DOWN; break; case AMOTION_EVENT_ACTION_UP: pact = NvPointerActionType::UP; break; case AMOTION_EVENT_ACTION_POINTER_UP: pact = NvPointerActionType::EXTRA_UP; break; case AMOTION_EVENT_ACTION_MOVE: pact = NvPointerActionType::MOTION; break; case AMOTION_EVENT_ACTION_CANCEL: pact = NvPointerActionType::UP; pointerCount = 0; // clear. break; } const int64_t timestamp = AMotionEvent_getEventTime((const AInputEvent*)event); handled = mCallbacks->pointerInput(dev, pact, 0, pointerCount, p, timestamp); // return code handling... if (pact==NvPointerActionType::UP) return 1; return handled ? 1 : 0; } else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY) { bool handled = false; int32_t source = AInputEvent_getSource(event); int32_t code = AKeyEvent_getKeyCode((const AInputEvent*)event); int32_t action = AKeyEvent_getAction((const AInputEvent*)event); bool down = (action != AKEY_EVENT_ACTION_UP) ? true : false; if (mCallbacks) { handled = mCallbacks->keyInput(code, down ? NvKeyActionType::DOWN : NvKeyActionType::UP); if (!handled && down) { uint8_t c = mapAndroidCodeToChar(code); if (c) handled = mCallbacks->characterInput(c); } } return handled ? 1 : 0; } return 0; }
static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) { struct engine* engine = (struct engine*)app->userData; int pointers = AMotionEvent_getPointerCount(event); if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) { int pointers = AMotionEvent_getPointerCount(event); switch(pointers) { case 1: //rotation if(AKeyEvent_getAction(event) == AMOTION_EVENT_ACTION_DOWN ) { X1 = AMotionEvent_getX(event, 0); Y1 = AMotionEvent_getY(event, 0); return 1; } else if(AKeyEvent_getAction(event) == AMOTION_EVENT_ACTION_UP) { // Do nothing } else if(AKeyEvent_getAction(event) == AMOTION_EVENT_ACTION_MOVE ) { float dx = AMotionEvent_getX(event, 0) - X1; float dy = AMotionEvent_getY(event, 0) - Y1; touchRotate(-dx,-dy); X1 = AMotionEvent_getX(event, 0); Y1 = AMotionEvent_getY(event, 0); } break; case 2: //pinch/zoom (multitouch) if(AKeyEvent_getAction(event) == AMOTION_EVENT_ACTION_DOWN ) { X1 = AMotionEvent_getX(event, 0); Y1 = AMotionEvent_getY(event, 0); X2 = AMotionEvent_getX(event, 1); Y2 = AMotionEvent_getY(event, 1); double dx = abs((double) (X2 - X1)); double dy = abs((double) (Y2 - Y1)); S = (float) sqrt((dx * dx) + (dy * dy)); } else if(AKeyEvent_getAction(event) == AMOTION_EVENT_ACTION_MOVE ) { float x1 = 0.0F; float y1 = 0.0F; float x2 = 0.0F; float y2 = 0.0F; // some unknown device throws an exception here x1 = AMotionEvent_getX(event, 0); y1 = AMotionEvent_getY(event, 0); x2 = AMotionEvent_getX(event, 1); y2 = AMotionEvent_getY(event, 1); double dx = abs((double) (x2 - x1)); double dy = abs((double) (y2 - y1)); float s = (float) sqrt((dx * dx) + (dy * dy)); touchScale(4.0f * (S - s)); //LOGI("S-s: %f",S-s); X1 = x1; Y1 = y1; X2 = x2; Y2 = y2; S = s; } break; case 3: //3 finger tap to switch shaders //LOGI("action: %i%",AKeyEvent_getAction(event)); if(AKeyEvent_getAction(event) == AMOTION_EVENT_ACTION_UP || AKeyEvent_getAction(event) == AMOTION_EVENT_ACTION_POINTER_UP ) { LOGI("3 finger tap UP"); ShaderToUse ++; if(ShaderToUse>2) ShaderToUse=0; } } } return 0; }
/***************************************************************************** Global code *****************************************************************************/ static int32_t handle_input(struct android_app* app, AInputEvent* event) { PVRShellInit* init = (PVRShellInit*) app->userData; if(init) { switch(AInputEvent_getType(event)) { case AINPUT_EVENT_TYPE_KEY: // Handle keyboard events { switch(AKeyEvent_getAction(event)) { case AKEY_EVENT_ACTION_DOWN: { switch(AKeyEvent_getKeyCode(event)) { case AKEYCODE_Q: init->KeyPressed(PVRShellKeyNameQUIT); break; case AKEYCODE_BACK: init->KeyPressed(PVRShellKeyNameQUIT); break; case AKEYCODE_DPAD_CENTER: init->KeyPressed(PVRShellKeyNameSELECT); break; case AKEYCODE_SPACE: init->KeyPressed(PVRShellKeyNameACTION1); break; case AKEYCODE_SHIFT_LEFT: init->KeyPressed(PVRShellKeyNameACTION2); break; case AKEYCODE_DPAD_UP: init->KeyPressed(init->m_eKeyMapUP); break; case AKEYCODE_DPAD_DOWN: init->KeyPressed(init->m_eKeyMapDOWN); break; case AKEYCODE_DPAD_LEFT: init->KeyPressed(init->m_eKeyMapLEFT); break; case AKEYCODE_DPAD_RIGHT: init->KeyPressed(init->m_eKeyMapRIGHT); break; case AKEYCODE_S: init->KeyPressed(PVRShellKeyNameScreenshot);break; default: break; } } return 1; default: break; } return 1; } case AINPUT_EVENT_TYPE_MOTION: // Handle touch events { switch(AMotionEvent_getAction(event)) { case AMOTION_EVENT_ACTION_DOWN: { PVRShell *pShell = init->m_pShell; if(pShell) { float vec2TouchPosition[2] = { AMotionEvent_getX(event, 0) / pShell->PVRShellGet(prefWidth), AMotionEvent_getY(event, 0) / pShell->PVRShellGet(prefHeight) }; init->TouchBegan(vec2TouchPosition); } break; } case AMOTION_EVENT_ACTION_MOVE: { PVRShell *pShell = init->m_pShell; if(pShell) { float vec2TouchPosition[2] = { AMotionEvent_getX(event, 0) / pShell->PVRShellGet(prefWidth), AMotionEvent_getY(event, 0) / pShell->PVRShellGet(prefHeight) }; init->TouchMoved(vec2TouchPosition); } break; } case AMOTION_EVENT_ACTION_UP: { PVRShell *pShell = init->m_pShell; if(pShell) { float vec2TouchPosition[2] = { AMotionEvent_getX(event, 0) / pShell->PVRShellGet(prefWidth), AMotionEvent_getY(event, 0) / pShell->PVRShellGet(prefHeight) }; init->TouchEnded(vec2TouchPosition); } break; } } return 1; } } } return 1; }
/** * Process the next input event. */ static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) { struct engine* androidEngine = (struct engine*)app->userData; int touchCount = 0; static int previousTouchCount; int numButton; touch_t* touch; touch_t* currentTouchSet; struct TOUCHSTATE *touchstate = 0; struct TOUCHSTATE *prev_touchstate = 0; int nSourceId = AInputEvent_getSource( event ); if (nSourceId == AINPUT_SOURCE_TOUCHPAD) touchstate = engine.touchstate_pad; // GJT: For Xperia Play...and other devices? else if (nSourceId == AINPUT_SOURCE_TOUCHSCREEN) touchstate = engine.touchstate_screen; else return 0; // GJT: Volume? Keyboard? Let the system handle it... if (engine.menuVisible) { numButton = MENU_GetNumButtonsTouches(); currentTouchSet = MENU_GetCurrentButtonTouches(); } else { numButton = NUM_BUTTONS; currentTouchSet = touches; } if (engine.menuVisible || engine.controlMode == CONTROL_MODE_VIRT_PAD) { size_t pointerCount = AMotionEvent_getPointerCount(event); size_t i; for (i = 0; i < pointerCount; i++) { size_t pointerId = AMotionEvent_getPointerId(event, i); size_t action = AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK; touchstate[pointerId].x = AMotionEvent_getX( event, i ); touchstate[pointerId].y = AMotionEvent_getY( event, i ); LOGI("DEBUG BEFORE x %f y %f", touchstate[pointerId].x, touchstate[pointerId].y); // Transforming from whatever screen resolution we have to the original iPhone 320*480 touchstate[pointerId].x = ( touchstate[pointerId].x - renderer.viewPortDimensions[VP_X] ) * commScale[X] ; touchstate[pointerId].y = ( touchstate[pointerId].y - renderer.viewPortDimensions[VP_Y] ) * commScale[Y] ; LOGI("DEBUG AFTER x %f y %f", touchstate[pointerId].x, touchstate[pointerId].y); touchCount++; // find which one it is closest to int minDist = INT_MAX; // allow up to 64 unit moves to be drags int minIndex = -1; int dist; touch_t *t2 = currentTouchSet; int i; for ( i = 0 ; i < numButton ; i++ ) { dist = SQUARE( t2->iphone_coo_SysPos[X] - touchstate[pointerId].x ) + SQUARE( t2->iphone_coo_SysPos[Y] - touchstate[pointerId].y ) ; LOGI("DEBUG dist %i minDist %i", dist, minDist); if ( dist < minDist ) { minDist = dist; minIndex = i; touch = t2; } t2++; } if ( minIndex != -1 ) { if (action == AMOTION_EVENT_ACTION_UP) { touch->down = 0; } else { if (action == AMOTION_EVENT_ACTION_DOWN) { } touch->down = 1; touch->dist[X] = MIN(1,(touchstate[pointerId].x - touches[minIndex].iphone_coo_SysPos[X])/touches[minIndex].iphone_size); touch->dist[Y] = MIN(1,(touches[minIndex].iphone_coo_SysPos[Y] - touchstate[pointerId].y)/touches[minIndex].iphone_size); LOGI("DEBUG minIndexIphone %i", touches[minIndex].iphone_size); } } } LOGI("DEBUG touchcount %i previous %i", touchCount, previousTouchCount); if ( touchCount == 5 && previousTouchCount != 5 ) { MENU_Set(MENU_HOME); engine.requiredSceneId = 0; } previousTouchCount = touchCount; return 1; } else { size_t pointerCount = AMotionEvent_getPointerCount(event); size_t i; for (i = 0; i < pointerCount; i++) { size_t pointerCount = AMotionEvent_getPointerCount(event); size_t pointerId = AMotionEvent_getPointerId(event, i); size_t action = AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK; size_t pointerIndex = i; int historySize = AMotionEvent_getHistorySize(event); touchstate[pointerId].x = AMotionEvent_getX( event, pointerIndex ); touchstate[pointerId].y = AMotionEvent_getY( event, pointerIndex ); LOGI("DEBUG history %i", historySize); LOGI("DEBUG nomenu x %f y %f", touchstate[pointerId].x, touchstate[pointerId].y); if (historySize > 0) { //prev_touchstate[pointerId].x = AMotionEvent_getX( event, pointerIndex ); //prev_touchstate[pointerId].y = AMotionEvent_getY( event, pointerIndex ); LOGI("DEBUG nomenu prevx %f prevy %f", prev_touchstate[pointerId].x, prev_touchstate[pointerId].y); } //Transforming from whatever screen resolution we have to the original iPHone 320*480 /*touchstate[pointerId].x = ( touchstate[pointerId].x- renderer.viewPortDimensions[VP_X] ) * commScale[X] ;//* renderer.resolution ; touchstate[pointerId].y = ( touchstate[pointerId].y- renderer.viewPortDimensions[VP_Y] ) * commScale[Y] ;//* renderer.resolution; prev_touchstate[pointerId].x = ( prev_touchstate[pointerId].x- renderer.viewPortDimensions[VP_X] ) * commScale[X] ;//* renderer.resolution ; prev_touchstate[pointerId].y = ( prev_touchstate[pointerId].y- renderer.viewPortDimensions[VP_Y] ) * commScale[Y] ;//* renderer.resolution;*/ touchCount++; if (action == AMOTION_EVENT_ACTION_UP) { if (touchCount == 1) //Last finger ended touches[BUTTON_FIRE].down = 0; } else { if (action == AMOTION_EVENT_ACTION_MOVE) { //printf("m\n"); LOGI("DEBUG MOVE x %f y %f", touchstate[pointerId].x, touchstate[pointerId].y); //LOGI("DEBUG MOVE prevx %f prevy %f", prev_touchstate[pointerId].x, prev_touchstate[pointerId].y); touches[BUTTON_MOVE].down = 1; //touches[BUTTON_MOVE].dist[X] = (touchstate[pointerId].x - prev_touchstate[pointerId].x)*40/(float)320; //touches[BUTTON_MOVE].dist[Y] = (touchstate[pointerId].y - prev_touchstate[pointerId].y)*-40/(float)480; } if (action == AMOTION_EVENT_ACTION_DOWN) { int currTime = E_Sys_Milliseconds(); if (currTime-lastTouchBegan < 200) touches[BUTTON_GHOST].down = 1; lastTouchBegan = currTime ; touches[BUTTON_FIRE].down = 1; } } } if ( touchCount == 5 && previousTouchCount != 5 ) { MENU_Set(MENU_HOME); engine.requiredSceneId=0; } previousTouchCount = touchCount; return 1; } return 0; }
int32_t on_motion_event(android_app *app, AInputEvent *event) { /* AMotionEvent_getAction(); AMotionEvent_getEventTime(); AMotionEvent_getPointerCount(); AMotionEvent_getPointerId(); AMotionEvent_getX(); AMotionEvent_getY(); AMOTION_EVENT_ACTION_DOWN AMOTION_EVENT_ACTION_UP AMOTION_EVENT_ACTION_MOVE AMOTION_EVENT_ACTION_CANCEL AMOTION_EVENT_ACTION_POINTER_DOWN AMOTION_EVENT_ACTION_POINTER_UP */ user_data *p = (user_data *)app->userData; pan_state *pan = &p->motion.pan; pan->stick = {}; uint action = AMotionEvent_getAction(event); uint num_pointers = AMotionEvent_getPointerCount(event); if (num_pointers != 2 || action == AMOTION_EVENT_ACTION_UP || action == AMOTION_EVENT_ACTION_CANCEL) { if (pan->in_pan) { __android_log_print(ANDROID_LOG_INFO, p->app_name, "ending pan"); } pan->in_pan = 0; } else { uint pointer_id_0 = AMotionEvent_getPointerId(event, 0); uint pointer_id_1 = AMotionEvent_getPointerId(event, 1); v2 pointer_pos_0 = {AMotionEvent_getX(event, pointer_id_0), AMotionEvent_getY(event, pointer_id_0)}; v2 pointer_pos_1 = {AMotionEvent_getX(event, pointer_id_1), AMotionEvent_getY(event, pointer_id_1)}; v2 center_pos = (pointer_pos_0 + pointer_pos_1) * 0.5f; if (!pan->in_pan) { __android_log_print(ANDROID_LOG_INFO, p->app_name, "starting pan"); __android_log_print(ANDROID_LOG_INFO, p->app_name, "pointer_pos_0: %0.2f, %0.2f", pointer_pos_0.X, pointer_pos_0.Y); __android_log_print(ANDROID_LOG_INFO, p->app_name, "pointer_pos_1: %0.2f, %0.2f", pointer_pos_1.X, pointer_pos_1.Y); __android_log_print(ANDROID_LOG_INFO, p->app_name, "center_pos: %0.2f, %0.2f", center_pos.X, center_pos.Y); pan->in_pan = 1; pan->start_pos = center_pos; } if (pan->in_pan) { v2 distance = center_pos - pan->start_pos; if ((abs(distance.X) > 100) || (abs(distance.Y) > 100)) { if (abs(distance.X) > 100) { pan->stick.X = distance.X > 0 ? 1.0 : -1.0; } if (abs(distance.Y) > 100) { pan->stick.Y = distance.Y < 0 ? 1.0 : -1.0; } } __android_log_print(ANDROID_LOG_INFO, p->app_name, "pan->stick: %0.2f, %0.2f", pan->stick.X, pan->stick.Y); } } return 1; }
//Called from the event process thread static int32_t HandleInputCB(struct android_app* app, AInputEvent* event) { // FPlatformMisc::LowLevelOutputDebugStringf(L"INPUT - type: %x, action: %x, source: %x, keycode: %x, buttons: %x", AInputEvent_getType(event), // AMotionEvent_getAction(event), AInputEvent_getSource(event), AKeyEvent_getKeyCode(event), AMotionEvent_getButtonState(event)); if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) { int action = AMotionEvent_getAction(event); int actionType = action & AMOTION_EVENT_ACTION_MASK; size_t actionPointer = (size_t)((action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); bool isActionTargeted = (actionType == AMOTION_EVENT_ACTION_POINTER_DOWN || actionType == AMOTION_EVENT_ACTION_POINTER_UP); // trap Joystick events first, with fallthrough if there is no joystick support if (((AInputEvent_getSource(event) & AINPUT_SOURCE_CLASS_JOYSTICK) != 0) && (GetAxes != NULL) && (actionType == AMOTION_EVENT_ACTION_MOVE)) { const int axisCount = sizeof(AxisList)/sizeof(int32_t); int device = AInputEvent_getDeviceId(event); for (int axis = 0; axis < axisCount; axis++) { float val = GetAxes( event, AxisList[axis], 0); FAndroidInputInterface::JoystickAxisEvent( device, AxisList[axis], val); } } else { TArray<TouchInput> TouchesArray; TouchType type = TouchEnded; switch (actionType) { case AMOTION_EVENT_ACTION_DOWN: case AMOTION_EVENT_ACTION_POINTER_DOWN: type = TouchBegan; break; case AMOTION_EVENT_ACTION_MOVE: type = TouchMoved; break; case AMOTION_EVENT_ACTION_UP: case AMOTION_EVENT_ACTION_POINTER_UP: case AMOTION_EVENT_ACTION_CANCEL: case AMOTION_EVENT_ACTION_OUTSIDE: type = TouchEnded; break; } size_t pointerCount = AMotionEvent_getPointerCount(event); if (pointerCount == 0) { return 1; } ANativeWindow* Window = (ANativeWindow*)FPlatformMisc::GetHardwareWindow(); if (!Window) { return 0; } int32_t Width = 0 ; int32_t Height = 0 ; if(Window) { FAndroidWindow::CalculateSurfaceSize(Window, Width, Height); } // make sure OpenGL context created before accepting touch events.. FAndroidWindow::GetScreenRect() may try to create it early from wrong thread if this is the first call if (!GAndroidGPUInfoReady) { return 1; } FPlatformRect ScreenRect = FAndroidWindow::GetScreenRect(); if(isActionTargeted) { if(actionPointer < 0 || pointerCount < (int)actionPointer) { return 1; } int pointerId = AMotionEvent_getPointerId(event, actionPointer); float x = FMath::Min<float>(AMotionEvent_getX(event, actionPointer) / Width, 1.f); x *= (ScreenRect.Right - 1); float y = FMath::Min<float>(AMotionEvent_getY(event, actionPointer) / Height, 1.f); y *= (ScreenRect.Bottom - 1); UE_LOG(LogAndroid, Verbose, TEXT("Received targeted motion event from pointer %u (id %d) action %d: (%.2f, %.2f)"), actionPointer, pointerId, action, x, y); TouchInput TouchMessage; TouchMessage.Handle = pointerId; TouchMessage.Type = type; TouchMessage.Position = FVector2D(x, y); TouchMessage.LastPosition = FVector2D(x, y); //@todo android: AMotionEvent_getHistoricalRawX TouchesArray.Add(TouchMessage); } else { for (size_t i = 0; i < pointerCount; ++i) { int pointerId = AMotionEvent_getPointerId(event, i); float x = FMath::Min<float>(AMotionEvent_getX(event, i) / Width, 1.f); x *= (ScreenRect.Right - 1); float y = FMath::Min<float>(AMotionEvent_getY(event, i) / Height, 1.f); y *= (ScreenRect.Bottom - 1); UE_LOG(LogAndroid, Verbose, TEXT("Received motion event from pointer %u (id %d) action %d: (%.2f, %.2f)"), i, action, AMotionEvent_getPointerId(event,i), x, y); TouchInput TouchMessage; TouchMessage.Handle = AMotionEvent_getPointerId(event, i); TouchMessage.Type = type; TouchMessage.Position = FVector2D(x, y); TouchMessage.LastPosition = FVector2D(x, y); //@todo android: AMotionEvent_getHistoricalRawX TouchesArray.Add(TouchMessage); } } FAndroidInputInterface::QueueTouchInput(TouchesArray); #if !UE_BUILD_SHIPPING if ((pointerCount >= 4) && (type == TouchBegan)) { bool bShowConsole = true; GConfig->GetBool(TEXT("/Script/Engine.InputSettings"), TEXT("bShowConsoleOnFourFingerTap"), bShowConsole, GInputIni); if (bShowConsole) { GShowConsoleWindowNextTick = true; } } #endif } return 1; }
/** * Process the next input event. */ static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) { struct engine* engine = (struct engine*)app->userData; const int32_t input_type = AInputEvent_getType(event); if (input_type == AINPUT_EVENT_TYPE_MOTION) { engine->has_focus = 1; const float x = AMotionEvent_getX(event, 0); const float y = AMotionEvent_getY(event, 0); const int32_t actionAndPtr = AMotionEvent_getAction(event); const int32_t action = AMOTION_EVENT_ACTION_MASK & actionAndPtr; // const int32_t ptrindex = (AMOTION_EVENT_ACTION_POINTER_INDEX_MASK & actionAndPtr) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; const size_t num_ptrs = AMotionEvent_getPointerCount(event); switch(action) { case AMOTION_EVENT_ACTION_UP: case AMOTION_EVENT_ACTION_POINTER_UP: UnpressAll(); break; case AMOTION_EVENT_ACTION_DOWN: case AMOTION_EVENT_ACTION_POINTER_DOWN: UnpressAll(); if(num_ptrs <=2) { const int button = (num_ptrs==1) ? 0 : 2; pangolin::process::Mouse(button, 0, x, y); } break; case AMOTION_EVENT_ACTION_MOVE: if(num_ptrs == 3) { const double dx = x - process::last_x; const double dy = y - process::last_y; process::last_x = x; process::last_y = y; pangolin::process::Scroll(dx,dy); }else{ pangolin::process::MouseMotion(x,y); } break; default: break; } return 1; }else if(AINPUT_EVENT_TYPE_KEY) { static bool shift = false; const int32_t action = AKeyEvent_getAction(event); const int32_t keycode = AKeyEvent_getKeyCode(event); if(keycode == AKEYCODE_SHIFT_LEFT) { shift = (action == AKEY_EVENT_ACTION_DOWN); return 1; } unsigned char key = PangolinKeyFromAndroidKeycode(keycode, shift); if(action == AKEY_EVENT_ACTION_DOWN) { pangolin::process::Keyboard(key, pangolin::process::last_x,pangolin::process::last_y); }else{ pangolin::process::KeyboardUp(key, pangolin::process::last_x,pangolin::process::last_y); } } return 1; }
static bool android_input_set_sensor_state(void *data, unsigned port, enum retro_sensor_action action, unsigned event_rate); extern float AMotionEvent_getAxisValue(const AInputEvent* motion_event, int32_t axis, size_t pointer_idx); static typeof(AMotionEvent_getAxisValue) *p_AMotionEvent_getAxisValue; #define AMotionEvent_getAxisValue (*p_AMotionEvent_getAxisValue) static void engine_handle_dpad_default(android_input_t *android, AInputEvent *event, int port, int source) { size_t motion_pointer = AMotionEvent_getAction(event) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; float x = AMotionEvent_getX(event, motion_pointer); float y = AMotionEvent_getY(event, motion_pointer); android->analog_state[port][0] = (int16_t)(x * 32767.0f); android->analog_state[port][1] = (int16_t)(y * 32767.0f); } static void engine_handle_dpad_getaxisvalue(android_input_t *android, AInputEvent *event, int port, int source) { size_t motion_pointer = AMotionEvent_getAction(event) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; float x = AMotionEvent_getAxisValue(event, AXIS_X, motion_pointer); float y = AMotionEvent_getAxisValue(event, AXIS_Y, motion_pointer); float z = AMotionEvent_getAxisValue(event, AXIS_Z, motion_pointer); float rz = AMotionEvent_getAxisValue(event, AXIS_RZ, motion_pointer);
//callback extern int32_t __android_handle_input(struct android_app* app, AInputEvent* event){ /* Input source */ int nSourceId = AInputEvent_getSource( event ); //not supported device? if (!(nSourceId == AINPUT_SOURCE_TOUCHPAD || nSourceId == AINPUT_SOURCE_KEYBOARD || nSourceId == AINPUT_SOURCE_TOUCHSCREEN)) return 0; //keyboard if(nSourceId == AINPUT_SOURCE_KEYBOARD) { if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY) { //keybord down //get key code unsigned int keyAction = AKeyEvent_getAction(event); // if( keyDown && keyAction == AKEY_EVENT_ACTION_DOWN ) { keyDown(app->userData,AKeyEvent_getKeyCode(event)); } else if( keyUp && keyAction == AKEY_EVENT_ACTION_UP ) { keyUp(app->userData,AKeyEvent_getKeyCode(event)); } else { return 0; } return 1; } return 0; } //action unsigned int unmaskAction = AMotionEvent_getAction(event); //base action unsigned int action = unmaskAction & AMOTION_EVENT_ACTION_MASK; //pointer action unsigned int actionPointerIndex = (unmaskAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK); actionPointerIndex >>= AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; if (action == AMOTION_EVENT_ACTION_DOWN) { //all down if(fingerDown){ int count = AMotionEvent_getPointerCount(event); int i = 0; for(;i < count ; i++) { unsigned int pointerFingerId = AMotionEvent_getPointerId(event, i); fingerDown(app->userData,pointerFingerId, AMotionEvent_getX(event, i), AMotionEvent_getY(event, i), AMotionEvent_getPressure(event, i)); } } } else if (action == AMOTION_EVENT_ACTION_POINTER_DOWN ) { //one down if(fingerDown){ int count = AMotionEvent_getPointerCount(event); int i = 0; for(;i < count ; i++) { unsigned int pointerFingerId = AMotionEvent_getPointerId(event, i); if( pointerFingerId==actionPointerIndex ) { fingerDown(app->userData,pointerFingerId, AMotionEvent_getX(event, i), AMotionEvent_getY(event, i), AMotionEvent_getPressure(event, i)); } } } } else if (action == AMOTION_EVENT_ACTION_UP) { //up all if(fingerUp){ int count = AMotionEvent_getPointerCount(event); int i = 0; for(;i < count ; i++) { unsigned int pointerFingerId = AMotionEvent_getPointerId(event, i); fingerUp(app->userData,pointerFingerId, AMotionEvent_getX(event, i), AMotionEvent_getY(event, i), AMotionEvent_getPressure(event, i)); } } } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) { //up one if(fingerUp){ int count = AMotionEvent_getPointerCount(event); int i = 0; for(;i < count ; i++) { unsigned int pointerFingerId = AMotionEvent_getPointerId(event, i); if( pointerFingerId==actionPointerIndex ) { fingerUp(app->userData,pointerFingerId, AMotionEvent_getX(event, i), AMotionEvent_getY(event, i), AMotionEvent_getPressure(event, i)); } } } } else if (action == AMOTION_EVENT_ACTION_MOVE) { //move if(fingerMove){ int count = AMotionEvent_getPointerCount(event); int i = 0; for(;i < count ; i++) { unsigned int pointerFingerId = AMotionEvent_getPointerId(event, i); fingerMove(app->userData,pointerFingerId, AMotionEvent_getX(event, i), AMotionEvent_getY(event, i), AMotionEvent_getPressure(event, i)); } } } else if (action == AMOTION_EVENT_ACTION_CANCEL) { } else { return 0; } return 1; }
static void android_input_poll(void *data) { (void)data; RARCH_PERFORMANCE_INIT(input_poll); RARCH_PERFORMANCE_START(input_poll); bool debug_enable = g_settings.input.debug_enable; struct android_app* android_app = (struct android_app*)g_android; uint64_t *lifecycle_state = &g_extern.lifecycle_state; *lifecycle_state &= ~((1ULL << RARCH_RESET) | (1ULL << RARCH_REWIND) | (1ULL << RARCH_FAST_FORWARD_KEY) | (1ULL << RARCH_FAST_FORWARD_HOLD_KEY) | (1ULL << RARCH_MUTE) | (1ULL << RARCH_SAVE_STATE_KEY) | (1ULL << RARCH_LOAD_STATE_KEY) | (1ULL << RARCH_STATE_SLOT_PLUS) | (1ULL << RARCH_STATE_SLOT_MINUS)); // Read all pending events. while (AInputQueue_hasEvents(android_app->inputQueue) > 0) { AInputEvent* event = NULL; if (AInputQueue_getEvent(android_app->inputQueue, &event) < 0) break; bool long_msg_enable = false; int32_t handled = 1; int action = 0; char msg[128]; msg[0] = 0; int source = AInputEvent_getSource(event); int id = AInputEvent_getDeviceId(event); if (id == zeus_second_id) id = zeus_id; int keycode = AKeyEvent_getKeyCode(event); int type_event = AInputEvent_getType(event); int state_id = -1; if (source & (AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD)) state_id = 0; // touch overlay is always player 1 else { for (unsigned i = 0; i < pads_connected; i++) if (state_device_ids[i] == id) state_id = i; } if (state_id < 0) { state_id = pads_connected; state_device_ids[pads_connected++] = id; input_autodetect_setup(android_app, msg, sizeof(msg), state_id, id, source); long_msg_enable = true; } if (keycode == AKEYCODE_BACK ) { int meta = AKeyEvent_getMetaState(event); if (!(meta & AMETA_ALT_ON)) { *lifecycle_state |= (1ULL << RARCH_QUIT_KEY); AInputQueue_finishEvent(android_app->inputQueue, event, handled); break; } } if (type_event == AINPUT_EVENT_TYPE_MOTION) { float x = 0.0f; float y = 0.0f; action = AMotionEvent_getAction(event); size_t motion_pointer = action >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; action &= AMOTION_EVENT_ACTION_MASK; if (source & ~(AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_MOUSE)) { if (g_settings.input.dpad_emulation[state_id] != DPAD_EMULATION_NONE) { uint64_t *state_cur = &state[state_id]; x = AMotionEvent_getX(event, motion_pointer); y = AMotionEvent_getY(event, motion_pointer); *state_cur &= ~((1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT) | (1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT) | (1ULL << RETRO_DEVICE_ID_JOYPAD_UP) | (1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN)); *state_cur |= PRESSED_LEFT(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT) : 0; *state_cur |= PRESSED_RIGHT(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT) : 0; *state_cur |= PRESSED_UP(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_UP) : 0; *state_cur |= PRESSED_DOWN(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN) : 0; } } else { bool keyup = (action == AMOTION_EVENT_ACTION_UP || action == AMOTION_EVENT_ACTION_CANCEL || action == AMOTION_EVENT_ACTION_POINTER_UP) || (source == AINPUT_SOURCE_MOUSE && action != AMOTION_EVENT_ACTION_DOWN); if (keyup && motion_pointer < MAX_TOUCH) { memmove(pointer + motion_pointer, pointer + motion_pointer + 1, (MAX_TOUCH - motion_pointer - 1) * sizeof(struct input_pointer)); if (pointer_count > 0) pointer_count--; } else { int pointer_max = min(AMotionEvent_getPointerCount(event), MAX_TOUCH); for (motion_pointer = 0; motion_pointer < pointer_max; motion_pointer++) { x = AMotionEvent_getX(event, motion_pointer); y = AMotionEvent_getY(event, motion_pointer); input_translate_coord_viewport(x, y, &pointer[motion_pointer].x, &pointer[motion_pointer].y, &pointer[motion_pointer].full_x, &pointer[motion_pointer].full_y); pointer_count = max(pointer_count, motion_pointer + 1); } } } if (debug_enable) snprintf(msg, sizeof(msg), "Pad %d : x = %.2f, y = %.2f, src %d.\n", state_id, x, y, source); } else if (type_event == AINPUT_EVENT_TYPE_KEY)
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; 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); 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; } } } else { // os::Printer::log("keyCode: ", core::stringc(keyCode).c_str(), ELL_DEBUG); event.KeyInput.Char = 0; } device->postEventFromUser(event); } break; default: break; } return status; }
/* * Handle Touch Inputs */ static int32_t handle_touch_input(AInputEvent *event) { pthread_t thisthread = pthread_self(); LOG_EVENTS_DEBUG("handle_touch_input(%X), pthread_self() = %X", event, thisthread); switch(AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK) { case AMOTION_EVENT_ACTION_DOWN: { LOG_EVENTS_DEBUG("AMOTION_EVENT_ACTION_DOWN"); int pointerId = AMotionEvent_getPointerId(event, 0); float xP = AMotionEvent_getX(event,0); float yP = AMotionEvent_getY(event,0); LOG_EVENTS_DEBUG("Event: Action DOWN x=%f y=%f pointerID=%d\n", xP, yP, pointerId); float x = xP; float y = yP; cocos2d::Director::getInstance()->getOpenGLView()->handleTouchesBegin(1, &pointerId, &x, &y); return 1; } break; case AMOTION_EVENT_ACTION_POINTER_DOWN: { LOG_EVENTS_DEBUG("AMOTION_EVENT_ACTION_POINTER_DOWN"); int pointerIndex = AMotionEvent_getAction(event) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; int pointerId = AMotionEvent_getPointerId(event, pointerIndex); float xP = AMotionEvent_getX(event,pointerIndex); float yP = AMotionEvent_getY(event,pointerIndex); LOG_EVENTS_DEBUG("Event: Action POINTER DOWN x=%f y=%f pointerID=%d\n", xP, yP, pointerId); float x = xP; float y = yP; cocos2d::Director::getInstance()->getOpenGLView()->handleTouchesBegin(1, &pointerId, &x, &y); return 1; } break; case AMOTION_EVENT_ACTION_MOVE: { LOG_EVENTS_DEBUG("AMOTION_EVENT_ACTION_MOVE"); int pointerCount = AMotionEvent_getPointerCount(event); int ids[pointerCount]; float xs[pointerCount], ys[pointerCount]; getTouchPos(event, ids, xs, ys); cocos2d::Director::getInstance()->getOpenGLView()->handleTouchesMove(pointerCount, ids, xs, ys); return 1; } break; case AMOTION_EVENT_ACTION_UP: { LOG_EVENTS_DEBUG("AMOTION_EVENT_ACTION_UP"); int pointerId = AMotionEvent_getPointerId(event, 0); float xP = AMotionEvent_getX(event,0); float yP = AMotionEvent_getY(event,0); LOG_EVENTS_DEBUG("Event: Action UP x=%f y=%f pointerID=%d\n", xP, yP, pointerId); float x = xP; float y = yP; cocos2d::Director::getInstance()->getOpenGLView()->handleTouchesEnd(1, &pointerId, &x, &y); return 1; } break; case AMOTION_EVENT_ACTION_POINTER_UP: { LOG_EVENTS_DEBUG("AMOTION_EVENT_ACTION_POINTER_UP"); int pointerIndex = AMotionEvent_getAction(event) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; int pointerId = AMotionEvent_getPointerId(event, pointerIndex); float xP = AMotionEvent_getX(event,pointerIndex); float yP = AMotionEvent_getY(event,pointerIndex); LOG_EVENTS_DEBUG("Event: Action POINTER UP x=%f y=%f pointerID=%d\n", xP, yP, pointerIndex); float x = xP; float y = yP; cocos2d::Director::getInstance()->getOpenGLView()->handleTouchesEnd(1, &pointerId, &x, &y); return 1; } break; case AMOTION_EVENT_ACTION_CANCEL: { LOG_EVENTS_DEBUG("AMOTION_EVENT_ACTION_CANCEL"); int pointerCount = AMotionEvent_getPointerCount(event); int ids[pointerCount]; float xs[pointerCount], ys[pointerCount]; getTouchPos(event, ids, xs, ys); cocos2d::Director::getInstance()->getOpenGLView()->handleTouchesCancel(pointerCount, ids, xs, ys); return 1; } break; default: LOG_EVENTS_DEBUG("handle_touch_input() default case.... NOT HANDLE"); return 0; break; } }
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; }
/** * Process the next input event. */ static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) { struct engine* engine = (struct engine*)app->userData; switch(AInputEvent_getType(event)) { case AINPUT_EVENT_TYPE_MOTION: { int32_t action = AMotionEvent_getAction(event ); int pointer = ( action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK ) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; int p = AMotionEvent_getPointerCount( event ); #ifdef DEBUG_TOUCH_INPUT LOGI( "pointer (full action)%04x (pointer)%d (number points)%d", action, pointer, p ); #endif { int n; for( n = 0; n < engine->nPoints; n++ ) { engine->points[n].flags.new_event = 0; if( engine->points[n].flags.end_event ) { int m; for( m = n; m < (engine->nPoints-1); m++ ) { if( engine->input_point_map[m+1] == m+1 ) engine->input_point_map[m] = m; else { if( engine->input_point_map[m+1] < n ) engine->input_point_map[m] = engine->input_point_map[m+1]; else engine->input_point_map[m] = engine->input_point_map[m+1] - 1; } engine->points[m] = engine->points[m+1]; } engine->nPoints--; n--; } } } switch( action & AMOTION_EVENT_ACTION_MASK ) { case AMOTION_EVENT_ACTION_DOWN: // primary pointer down. //if( engine->nPoints ) //{ // LOGI( "Pointer Event Down (pointer0) and there's already pointers..." ); //} engine->points[0].x = AMotionEvent_getX( event, pointer ); engine->points[0].y = AMotionEvent_getY( event, pointer ); engine->points[0].flags.new_event = 1; engine->points[0].flags.end_event = 0; engine->nPoints++; engine->input_point_map[0] = 0; break; case AMOTION_EVENT_ACTION_UP: // primary pointer up. engine->points[0].flags.new_event = 0; engine->points[0].flags.end_event = 1; break; case AMOTION_EVENT_ACTION_MOVE: { int n; for( n = 0; n < p; n++ ) { // points may have come in as 'new' in the wrong order, // reference the input point map to fill in the correct point location int actual = engine->input_point_map[n]; engine->points[actual].x = AMotionEvent_getX( event, n ); engine->points[actual].y = AMotionEvent_getY( event, n ); engine->points[actual].flags.new_event = 0; engine->points[actual].flags.end_event = 0; } } break; case AMOTION_EVENT_ACTION_POINTER_DOWN: // the new pointer might not be the last one, so we insert it. // at the end, before dispatch, new points are moved to the end // and mapping begins. this code should not reference the map if( pointer < engine->nPoints ) { int c; #ifdef DEBUG_TOUCH_INPUT LOGI( "insert point new. %d", engine->nPoints-1 ); #endif for( c = engine->nPoints; c >= pointer; c-- ) { #ifdef DEBUG_TOUCH_INPUT LOGI( "Set %d to %d", c, engine->input_point_map[c-1] ); #endif engine->input_point_map[c] = engine->input_point_map[c-1]; // save still in the same target... } #ifdef DEBUG_TOUCH_INPUT LOGI( "Set %d to %d", pointer, engine->nPoints ); #endif engine->input_point_map[pointer] = engine->nPoints; // and the new one maps to the last. // now just save in last and don't swap twice. engine->points[engine->nPoints].x = AMotionEvent_getX( event, pointer ); engine->points[engine->nPoints].y = AMotionEvent_getY( event, pointer ); pointer = engine->nPoints; } else { engine->points[pointer].x = AMotionEvent_getX( event, pointer ); engine->points[pointer].y = AMotionEvent_getY( event, pointer ); engine->input_point_map[pointer] = pointer; } // primary pointer down. engine->points[pointer].flags.new_event = 1; engine->points[pointer].flags.end_event = 0; // always initialize the engine->nPoints++; break; case AMOTION_EVENT_ACTION_POINTER_UP: { // a up pointer may be remapped already, set the actual entry for the point int actual = engine->input_point_map[pointer]; int n; engine->points[actual].flags.new_event = 0; engine->points[actual].flags.end_event = 1; #ifdef DEBUG_TOUCH_INPUT LOGI( "Set point %d (map %d) to ended", pointer, actual ); #endif // any release event will reset the other input points appropriately(?) for( n = 0; n < engine->nPoints; n++ ) { int other; if( engine->input_point_map[n] != n ) { int m; #ifdef DEBUG_TOUCH_INPUT LOGI( "reorder to natural input order" ); #endif memcpy( engine->tmp_points, engine->points, engine->nPoints * sizeof( struct input_point ) ); // m is the point currently mapped to this position. // data from engine[n] and engine[m] need to swap for( m = 0; m < engine->nPoints; m++ ) { engine->points[m] = engine->tmp_points[other = engine->input_point_map[m]]; engine->input_point_map[m] = m; #ifdef DEBUG_TOUCH_INPUT LOGI( "move point %d to %d", other, m ); #endif } break; } } } break; default: #ifdef DEBUG_TOUCH_INPUT LOGI( "Motion Event ignored..." ); #endif break; } { int n; #ifdef DEBUG_TOUCH_INPUT for( n = 0; n < engine->nPoints; n++ ) { LOGI( "Point : %d %d %g %g %d %d", n, engine->input_point_map[n], engine->points[n].x , engine->points[n].y, engine->points[n].flags.new_event, engine->points[n].flags.end_event ); } #endif } BagVidlibPureglSendTouchEvents( engine->nPoints, engine->points ); //engine->state.animating = 1; //engine->state.x = AMotionEvent_getX(event, 0); //engine->state.y = AMotionEvent_getY(event, 0); return 1; } case AINPUT_EVENT_TYPE_KEY: { int32_t key_val = AKeyEvent_getKeyCode(event); //int32_t key_char = AKeyEvent_getKeyChar(event); int32_t key_mods = AKeyEvent_getMetaState( event ); int32_t key_pressed = AKeyEvent_getAction( event ); int realmod = 0; //lprintf( "key char is %d (%c)", key_char, key_char ); if( ( key_mods & 0x3000 ) == 0x3000 ) realmod |= KEY_MOD_CTRL; if( ( key_mods & 0x12 ) == 0x12 ) realmod |= KEY_MOD_ALT; if( ( key_mods & 0x41 ) == 0x41 ) realmod |= KEY_MOD_SHIFT; key_mods = realmod; #ifdef DEBUG_KEY_INPUT LOGI("Received key event: %d %d %d\n", key_pressed, key_val, key_mods ); #endif { engine->key_text = AndroidGetKeyText( event ); lprintf( "Event translates to %d(%04x)%c", engine->key_text, engine->key_text ,engine->key_text ); } if( key_val ) { int used; if( key_pressed == AKEY_EVENT_ACTION_MULTIPLE ) { int count = AKeyEvent_getRepeatCount( event ); int n; for( n = 0; n < count; n++ ) { used = BagVidlibPureglSendKeyEvents( 1, key_val, key_mods ); used = BagVidlibPureglSendKeyEvents( 0, key_val, key_mods ); } } else used = BagVidlibPureglSendKeyEvents( (key_pressed==AKEY_EVENT_ACTION_DOWN)?1:0, key_val, key_mods ); return used; } break; } default: LOGI( "Unhandled Motion Event ignored..." ); break; } return 0; }
/** * Process the next input event. */ static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) { struct engine* engine = (struct engine*)app->userData; if (!engine->os) return 0; switch(AInputEvent_getType(event)) { case AINPUT_EVENT_TYPE_KEY: { int ac = AKeyEvent_getAction(event); switch(ac) { case AKEY_EVENT_ACTION_DOWN: { int32_t code = AKeyEvent_getKeyCode(event); if (code==AKEYCODE_BACK) { //AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled); if (engine->os) engine->os->main_loop_request_quit(); return 1; } } break; case AKEY_EVENT_ACTION_UP: { } break; } } break; case AINPUT_EVENT_TYPE_MOTION: { Vector<OS_Android::TouchPos> touchvec; int pc = AMotionEvent_getPointerCount(event); touchvec.resize(pc); for(int i=0;i<pc;i++) { touchvec[i].pos.x=AMotionEvent_getX(event,i); touchvec[i].pos.y=AMotionEvent_getY(event,i); touchvec[i].id=AMotionEvent_getPointerId(event,i); } //System.out.printf("gaction: %d\n",event.getAction()); int pidx=(AMotionEvent_getAction(event)&AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)>>8; switch(AMotionEvent_getAction(event)&AMOTION_EVENT_ACTION_MASK) { case AMOTION_EVENT_ACTION_DOWN: { engine->os->process_touch(0,0,touchvec); //System.out.printf("action down at: %f,%f\n", event.getX(),event.getY()); } break; case AMOTION_EVENT_ACTION_MOVE: { engine->os->process_touch(1,0,touchvec); //for(int i=0;i<event.getPointerCount();i++) { // System.out.printf("%d - moved to: %f,%f\n",i, event.getX(i),event.getY(i)); //} } break; case AMOTION_EVENT_ACTION_POINTER_UP: { engine->os->process_touch(4,pidx,touchvec); //System.out.printf("%d - s.up at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx)); } break; case AMOTION_EVENT_ACTION_POINTER_DOWN: { engine->os->process_touch(3,pidx,touchvec); //System.out.printf("%d - s.down at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx)); } break; case AMOTION_EVENT_ACTION_CANCEL: case AMOTION_EVENT_ACTION_UP: { engine->os->process_touch(2,0,touchvec); //for(int i=0;i<event.getPointerCount();i++) { // System.out.printf("%d - up! %f,%f\n",i, event.getX(i),event.getY(i)); //} } break; } return 1; } break; } return 0; }
/** * Process the next input event. */ 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) { if (AMotionEvent_getAction(event) == AMOTION_EVENT_ACTION_DOWN) { engine->state.x0 = AMotionEvent_getX(event, 0); engine->state.y0 = AMotionEvent_getY(event, 0); return 1; } if (AMotionEvent_getAction(event) == AMOTION_EVENT_ACTION_UP && (AMotionEvent_getPointerCount(event) == 1)) { engine->kiwiApp->handleSingleTouchUp(); return 1; } // When transitioning from one touch to two touches, we record the position // of of the new touch and return. When transitioning from two touches to // one touch, we record the position of the single remaining touch and return. if (AMotionEvent_getPointerCount(event) > 1) { if (!engine->state.isTwoTouches) { engine->state.x1 = AMotionEvent_getX(event, 1); engine->state.y1 = AMotionEvent_getY(event, 1); engine->state.isTwoTouches = true; return 1; } } else if (engine->state.isTwoTouches) { engine->state.isTwoTouches = false; engine->state.x0 = AMotionEvent_getX(event, 0); engine->state.y0 = AMotionEvent_getY(event, 0); return 1; } if (AMotionEvent_getPointerCount(event) > 1 && !engine->state.isTwoTouches) { return 1; } engine->animating = 1; float px0 = engine->state.x0; float py0 = engine->state.y0; float px1 = engine->state.x1; float py1 = engine->state.y1; float x0 = AMotionEvent_getX(event, 0); float y0 = AMotionEvent_getY(event, 0); float x1 = x0; float y1 = y0; if (AMotionEvent_getPointerCount(event) > 1) { x1 = AMotionEvent_getX(event, 1); y1 = AMotionEvent_getY(event, 1); } if (AMotionEvent_getPointerCount(event) == 1) { float dx0 = x0 - px0; float dy0 = y0 - py0; engine->kiwiApp->handleSingleTouchPanGesture(dx0, dy0); } else { int viewHeight = engine->kiwiApp->viewHeight(); // Average positions of current and previous two touches. // Invert y since vesCamera expects y to go in opposite direction. float pcx = (px0 + px1)/2.0; float pcy = viewHeight - (py0 + py1)/2.0; float cx = (x0 + x1)/2.0; float cy = viewHeight - (y0 + y1)/2.0; engine->kiwiApp->handleTwoTouchPanGesture(pcx, pcy, cx, cy); // zoom and rotate too double previousDist = sqrt((px0 - px1) * (px0 - px1) + (py0 - py1) * (py0 - py1)); double currentDist = sqrt((x0 - x1) * (x0 - x1) + (y0 - y1) * (y0 - y1)); double dy = currentDist - previousDist; double dyf = 10.0 * dy / (viewHeight/2.0); double factor = pow(1.1, dyf); engine->kiwiApp->handleTwoTouchPinchGesture(factor); double pi = 3.14159265358979; double newAngle = atan2(y0 - y1, x0 - x1); double oldAngle = atan2(py0 - py1, px0 - px1); double rotation = newAngle - oldAngle; engine->kiwiApp->handleTwoTouchRotationGesture(rotation); } engine->state.x0 = x0; engine->state.y0 = y0; if (AMotionEvent_getPointerCount(event) > 1) { engine->state.x1 = x1; engine->state.y1 = y1; } return 1; } return 0; }
static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) { struct engineState* engine = (struct engineState*)app->userData; if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) { int source = AInputEvent_getSource(event); if (source == AINPUT_SOURCE_TOUCHSCREEN) { float x = AMotionEvent_getX(event, 0); float y = AMotionEvent_getY(event, 0); engine->instance->getAndroidInputSystem()->handleTouchInput(x, y); return 1; } if (source == AINPUT_SOURCE_JOYSTICK) { float x = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_X, 0); float y = AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_Y, 0); int devId = AInputEvent_getDeviceId(event); LOG_INFO("dev: " << devId << " pos: " << x << ":" << y); } return 0; } if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY) { int32_t source = AInputEvent_getSource(event); int32_t code = AKeyEvent_getKeyCode(event); int32_t action = AKeyEvent_getAction(event); LOG_INFO("Code: " << code << " Action: " << action); engine::input::KeyCode keycode = engine::input::KEY_VOID; switch (code) { case 96: keycode = engine::input::BUTTON_A; break; case 99: keycode = engine::input::BUTTON_X; break; case 100: keycode = engine::input::BUTTON_Y; break; case 97: keycode = engine::input::BUTTON_B; break; } if (action == 1) engine->instance->getInputSystem()->keyUp(keycode); else engine->instance->getInputSystem()->keyDown(keycode); return 1; } return 0; }
static bool android_input_set_sensor_state(void *data, unsigned port, enum retro_sensor_action action, unsigned event_rate); extern float AMotionEvent_getAxisValue(const AInputEvent* motion_event, int32_t axis, size_t pointer_idx); static typeof(AMotionEvent_getAxisValue) *p_AMotionEvent_getAxisValue; #define AMotionEvent_getAxisValue (*p_AMotionEvent_getAxisValue) static void engine_handle_dpad_default(android_input_t *android, AInputEvent *event, int port, int source) { size_t motion_ptr = AMotionEvent_getAction(event) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; float x = AMotionEvent_getX(event, motion_ptr); float y = AMotionEvent_getY(event, motion_ptr); android->analog_state[port][0] = (int16_t)(x * 32767.0f); android->analog_state[port][1] = (int16_t)(y * 32767.0f); } static void engine_handle_dpad_getaxisvalue(android_input_t *android, AInputEvent *event, int port, int source) { size_t motion_ptr = AMotionEvent_getAction(event) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; float x = AMotionEvent_getAxisValue(event, AXIS_X, motion_ptr); float y = AMotionEvent_getAxisValue(event, AXIS_Y, motion_ptr); float z = AMotionEvent_getAxisValue(event, AXIS_Z, motion_ptr); float rz = AMotionEvent_getAxisValue(event, AXIS_RZ, motion_ptr);
static void android_input_poll(void *data) { (void)data; RARCH_PERFORMANCE_INIT(input_poll); RARCH_PERFORMANCE_START(input_poll); struct android_app* android_app = g_android.app; g_extern.lifecycle_state &= ~((1ULL << RARCH_RESET) | (1ULL << RARCH_REWIND) | (1ULL << RARCH_FAST_FORWARD_KEY) | (1ULL << RARCH_FAST_FORWARD_HOLD_KEY) | (1ULL << RARCH_MUTE) | (1ULL << RARCH_SAVE_STATE_KEY) | (1ULL << RARCH_LOAD_STATE_KEY) | (1ULL << RARCH_STATE_SLOT_PLUS) | (1ULL << RARCH_STATE_SLOT_MINUS)); // Read all pending events. while(AInputQueue_hasEvents(android_app->inputQueue)) { AInputEvent* event = NULL; AInputQueue_getEvent(android_app->inputQueue, &event); if (AInputQueue_preDispatchEvent(android_app->inputQueue, event)) continue; int32_t handled = 1; int source = AInputEvent_getSource(event); int id = AInputEvent_getDeviceId(event); int type_event = AInputEvent_getType(event); int state_id = state_device_ids[id]; if(state_id == -1) state_id = state_device_ids[id] = pads_connected++; int action = 0; #ifdef RARCH_INPUT_DEBUG char msg[128]; #endif if(type_event == AINPUT_EVENT_TYPE_MOTION) { action = AMotionEvent_getAction(event); int8_t motion_action = action & AMOTION_EVENT_ACTION_MASK; size_t motion_pointer = action >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; float x = AMotionEvent_getX(event, motion_pointer); float y = AMotionEvent_getY(event, motion_pointer); if(source & ~(AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_MOUSE)) { state[state_id] &= ~((1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT) | (1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT) | (1ULL << RETRO_DEVICE_ID_JOYPAD_UP) | (1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN)); state[state_id] |= PRESSED_LEFT(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT) : 0; state[state_id] |= PRESSED_RIGHT(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT) : 0; state[state_id] |= PRESSED_UP(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_UP) : 0; state[state_id] |= PRESSED_DOWN(x, y) ? (1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN) : 0; } else { bool mouse_is_not_dirty = (source == AINPUT_SOURCE_MOUSE && action != AMOTION_EVENT_ACTION_DOWN); bool pointer_is_not_dirty = (action == AMOTION_EVENT_ACTION_UP || action == AMOTION_EVENT_ACTION_CANCEL || action == AMOTION_EVENT_ACTION_POINTER_UP); pointer_dirty = !(mouse_is_not_dirty || pointer_is_not_dirty); if (pointer_dirty) input_translate_coord_viewport(x, y, &pointer_x, &pointer_y); } #ifdef RARCH_INPUT_DEBUG snprintf(msg, sizeof(msg), "Pad %d : x = %.2f, y = %.2f, src %d.\n", state_id, x, y, source); #endif } else {
int WindowImplAndroid::processPointerEvent(bool isDown, AInputEvent* _event, ActivityStates* states) { int32_t device = AInputEvent_getSource(_event); int32_t action = AMotionEvent_getAction(_event); int index = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; int id = AMotionEvent_getPointerId(_event, index); float x = AMotionEvent_getX(_event, index); float y = AMotionEvent_getY(_event, index); Event event; if (isDown) { if (device == AINPUT_SOURCE_MOUSE) { event.type = Event::MouseButtonPressed; event.mouseButton.button = static_cast<Mouse::Button>(id); event.mouseButton.x = x; event.mouseButton.y = y; if (id >= 0 && id < Mouse::ButtonCount) states->isButtonPressed[id] = true; } else if (device & AINPUT_SOURCE_TOUCHSCREEN) { event.type = Event::TouchBegan; event.touch.finger = id; event.touch.x = x; event.touch.y = y; states->touchEvents[id] = Vector2i(event.touch.x, event.touch.y); } } else { if (device == AINPUT_SOURCE_MOUSE) { event.type = Event::MouseButtonReleased; event.mouseButton.button = static_cast<Mouse::Button>(id); event.mouseButton.x = x; event.mouseButton.y = y; if (id >= 0 && id < Mouse::ButtonCount) states->isButtonPressed[id] = false; } else if (device & AINPUT_SOURCE_TOUCHSCREEN) { event.type = Event::TouchEnded; event.touch.finger = id; event.touch.x = x; event.touch.y = y; states->touchEvents.erase(id); } } forwardEvent(event); return 1; }
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; }
static int32_t _onInputEvent(struct android_app* app, AInputEvent* event) { if (!event || !::g_defaultWindow.get()) { return 1; } int32_t source = AInputEvent_getSource(event); if (source == AINPUT_SOURCE_MOUSE) { int32_t x = (int32_t)AMotionEvent_getX(event, 0); int32_t y = (int32_t)AMotionEvent_getY(event, 0); g_defaultWindow->getMouseInput().setLocation(glm::ivec2(x, y)); int32_t buttonState = AMotionEvent_getButtonState(event); g_defaultWindow->getMouseInput().setButton(VKTS_MOUSE_BUTTON_LEFT, buttonState & AMOTION_EVENT_BUTTON_PRIMARY); g_defaultWindow->getMouseInput().setButton(VKTS_MOUSE_BUTTON_RIGHT, buttonState & AMOTION_EVENT_BUTTON_SECONDARY); g_defaultWindow->getMouseInput().setButton(VKTS_MOUSE_BUTTON_MIDDLE, buttonState & AMOTION_EVENT_BUTTON_TERTIARY); int32_t vscroll = (int32_t)AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_VSCROLL, 0); g_defaultWindow->getMouseInput().setMouseWheel(vscroll); return 1; } else if (source == AINPUT_SOURCE_KEYBOARD) { VkBool32 pressed = (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN); int32_t scanCode = AKeyEvent_getScanCode(event); int32_t key = vkts::_visualTranslateKey(scanCode); if (pressed && key == VKTS_KEY_ESCAPE) { g_app->destroyRequested = 1; } else if (key != VKTS_KEY_UNKNOWN) { g_defaultWindow->getKeyInput().setKey(key, pressed); } return 1; } else if (source == AINPUT_SOURCE_JOYSTICK) { int32_t pointerIndex = (AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; if (pointerIndex >= 0 && pointerIndex < VKTS_MAX_GAMEPADS) { for (int32_t axis = AMOTION_EVENT_AXIS_X; axis <= AMOTION_EVENT_AXIS_RTRIGGER; axis++) { int32_t axisIndex = -1; float axisValue = AMotionEvent_getAxisValue(event, axis, pointerIndex); switch (axis) { case AMOTION_EVENT_AXIS_X: axisIndex = VKTS_GAMEPAD_LEFT_STICK_X; break; case AMOTION_EVENT_AXIS_Y: axisIndex = VKTS_GAMEPAD_LEFT_STICK_Y; axisValue = -axisValue; break; case AMOTION_EVENT_AXIS_Z: axisIndex = VKTS_GAMEPAD_RIGHT_STICK_X; break; case AMOTION_EVENT_AXIS_RZ: axisIndex = VKTS_GAMEPAD_RIGHT_STICK_Y; axisValue = -axisValue; break; case AMOTION_EVENT_AXIS_LTRIGGER: axisIndex = VKTS_GAMEPAD_LEFT_TRIGGER; break; case AMOTION_EVENT_AXIS_RTRIGGER: axisIndex = VKTS_GAMEPAD_RIGHT_TRIGGER; break; case AMOTION_EVENT_AXIS_HAT_X: { VkBool32 buttonPressed = axisValue < 0.0f ? VK_TRUE : VK_FALSE; g_defaultWindow->getGamepadInput(pointerIndex).setButton(VKTS_GAMEPAD_DPAD_LEFT, buttonPressed); buttonPressed = axisValue > 0.0f ? VK_TRUE : VK_FALSE; g_defaultWindow->getGamepadInput(pointerIndex).setButton(VKTS_GAMEPAD_DPAD_RIGHT, buttonPressed); } break; case AMOTION_EVENT_AXIS_HAT_Y: { VkBool32 buttonPressed = axisValue > 0.0f ? VK_TRUE : VK_FALSE; g_defaultWindow->getGamepadInput(pointerIndex).setButton(VKTS_GAMEPAD_DPAD_DOWN, buttonPressed); buttonPressed = axisValue < 0.0f ? VK_TRUE : VK_FALSE; g_defaultWindow->getGamepadInput(pointerIndex).setButton(VKTS_GAMEPAD_DPAD_UP, buttonPressed); } break; } if (axisIndex == -1) { continue; } g_defaultWindow->getGamepadInput(pointerIndex).setAxis(axisIndex, axisValue); } } return 1; }
int Engine::handleInput(AInputEvent* event) { if( !event ) return 0; //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 actionUnmasked = AMotionEvent_getAction(event); int32_t action = (actionUnmasked & AMOTION_EVENT_ACTION_MASK); static int l_siIgnoreTime = 0; bool l_bTouch = false; if(AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN || AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_MULTIPLE ) { l_bTouch = true; } if( cGameApp::m_sbGamePause ) l_siIgnoreTime = 1; if( g_pAndroidTestApp && !cGameApp::m_sbGamePause && l_siIgnoreTime == 0 ) { if(g_pAndroidTestApp->m_sbDoMultiTouch) { int numEvents = AMotionEvent_getPointerCount(event); for (int index=0; index<numEvents; index++) { int id = AMotionEvent_getPointerId(event, index); float l_fPosX = AMotionEvent_getX(event, index); float l_fPosY = AMotionEvent_getY(event, index); float l_fpressure = AMotionEvent_getPressure(event, index); float l_fSize =AMotionEvent_getSize(event, index); g_pAndroidTestApp->m_spMultiTouchPoints->Touch(l_bTouch,(int)l_fPosX,(int)l_fPosY,id); g_pAndroidTestApp->TouchSignalProcess(l_fPosX,l_fPosY,l_bTouch); } g_pAndroidTestApp->m_spMultiTouchPoints->Update(0); } else { int32_t iX = AMotionEvent_getX(event, 0); int32_t iY = AMotionEvent_getY(event, 0); g_pAndroidTestApp->TouchSignalProcess(iX,iY,l_bTouch); } } if( l_siIgnoreTime > 0 ) { if( l_bTouch == false ) l_siIgnoreTime = 0; } //int32_t action = AMOTION_EVENT_ACTION_MASK & AMotionEvent_getAction((const AInputEvent*)event); // A tap on the screen takes us out of autopause into gameplay mode if // we were paused. No other touch processing is done. if (action == AMOTION_EVENT_ACTION_DOWN) { setGameplayMode(true); g_pAndroidTestApp->m_spMultiTouchPoints->Init(); } //, return 1; } else if (eventType == AINPUT_EVENT_TYPE_KEY) { int32_t code = AKeyEvent_getKeyCode((const AInputEvent*)event); int32_t action = AKeyEvent_getAction((const AInputEvent*)event); // if we are in gameplay mode, we eat the back button and move into // pause mode. If we are already in pause mode, we allow the back // button to be handled by the OS, which means we'll be shut down if ((code == AKEYCODE_BACK) && mGameplayMode) { setGameplayMode(false); return 1; } std::string l_strDebugInfo = "Code:"; l_strDebugInfo += ValueToString(code); l_strDebugInfo += "___Action"; l_strDebugInfo += ValueToString(action); cGameApp::OutputDebugInfoString(l_strDebugInfo); bool l_bVaildKey = false; bool l_bKeyDown = action==0?true:false; if((code >= AKEYCODE_A && code <= AKEYCODE_Z)) {//windows 65-90 code -= AKEYCODE_A; code += 65; l_bVaildKey = true; } else if((code >= AKEYCODE_0 && code <= AKEYCODE_9)) {//windows 45-97 code -= AKEYCODE_0; code += 45; l_bVaildKey = true; } if( l_bVaildKey ) { if( l_bKeyDown ) { g_pAndroidTestApp->KeyDown((char)code); } else { g_pAndroidTestApp->KeyUp((char)code); } } } return 0; }