Path: blob/master/platform/android/android_input_handler.cpp
20852 views
/**************************************************************************/1/* android_input_handler.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "android_input_handler.h"3132#include "core/input/input.h"3334#include "android_keys_utils.h"35#include "display_server_android.h"3637void AndroidInputHandler::process_joy_event(AndroidInputHandler::JoypadEvent p_event) {38switch (p_event.type) {39case JOY_EVENT_BUTTON:40Input::get_singleton()->joy_button(p_event.device, (JoyButton)p_event.index, p_event.pressed);41break;42case JOY_EVENT_AXIS:43Input::get_singleton()->joy_axis(p_event.device, (JoyAxis)p_event.index, p_event.value);44break;45case JOY_EVENT_HAT:46Input::get_singleton()->joy_hat(p_event.device, p_event.hat);47break;48default:49return;50}51}5253void AndroidInputHandler::_set_key_modifier_state(Ref<InputEventWithModifiers> ev, Key p_keycode) {54if (p_keycode != Key::SHIFT) {55ev->set_shift_pressed(shift_mem);56}57if (p_keycode != Key::ALT) {58ev->set_alt_pressed(alt_mem);59}60if (p_keycode != Key::META) {61ev->set_meta_pressed(meta_mem);62}63if (p_keycode != Key::CTRL) {64ev->set_ctrl_pressed(control_mem);65}66}6768void AndroidInputHandler::process_key_event(int p_physical_keycode, int p_unicode, int p_key_label, bool p_pressed, bool p_echo) {69static char32_t prev_wc = 0;70char32_t unicode = p_unicode;71if ((p_unicode & 0xfffffc00) == 0xd800) {72if (prev_wc != 0) {73ERR_PRINT("invalid utf16 surrogate input");74}75prev_wc = unicode;76return; // Skip surrogate.77} else if ((unicode & 0xfffffc00) == 0xdc00) {78if (prev_wc == 0) {79ERR_PRINT("invalid utf16 surrogate input");80return; // Skip invalid surrogate.81}82unicode = (prev_wc << 10UL) + unicode - ((0xd800 << 10UL) + 0xdc00 - 0x10000);83prev_wc = 0;84} else {85prev_wc = 0;86}8788Ref<InputEventKey> ev;89ev.instantiate();9091Key physical_keycode = godot_code_from_android_code(p_physical_keycode);92Key keycode;93if (unicode == '\b') { // 0x0894keycode = Key::BACKSPACE;95} else if (unicode == '\t') { // 0x0996keycode = Key::TAB;97} else if (unicode == '\n') { // 0x0A98keycode = Key::ENTER;99} else if (unicode == 0x1B) {100keycode = Key::ESCAPE;101} else if (unicode == 0x1F) {102keycode = Key::KEY_DELETE;103} else {104keycode = fix_keycode(unicode, physical_keycode);105}106107switch (physical_keycode) {108case Key::SHIFT: {109shift_mem = p_pressed;110} break;111case Key::ALT: {112alt_mem = p_pressed;113} break;114case Key::CTRL: {115control_mem = p_pressed;116} break;117case Key::META: {118meta_mem = p_pressed;119} break;120default:121break;122}123124ev->set_keycode(keycode);125ev->set_physical_keycode(physical_keycode);126ev->set_key_label(fix_key_label(p_key_label, keycode));127ev->set_unicode(fix_unicode(unicode));128ev->set_location(godot_location_from_android_code(p_physical_keycode));129ev->set_pressed(p_pressed);130ev->set_echo(p_echo);131132_set_key_modifier_state(ev, keycode);133134if (p_physical_keycode == AKEYCODE_BACK && p_pressed) {135if (DisplayServerAndroid *dsa = Object::cast_to<DisplayServerAndroid>(DisplayServer::get_singleton())) {136dsa->send_window_event(DisplayServer::WINDOW_EVENT_GO_BACK_REQUEST, true);137}138}139140Input::get_singleton()->parse_input_event(ev);141}142143void AndroidInputHandler::_cancel_all_touch() {144_parse_all_touch(false, true);145touch.clear();146}147148void AndroidInputHandler::_parse_all_touch(bool p_pressed, bool p_canceled, bool p_double_tap) {149if (touch.size()) {150//end all if exist151for (int i = 0; i < touch.size(); i++) {152Ref<InputEventScreenTouch> ev;153ev.instantiate();154ev->set_index(touch[i].id);155ev->set_pressed(p_pressed);156ev->set_canceled(p_canceled);157ev->set_position(touch[i].pos);158ev->set_double_tap(p_double_tap);159Input::get_singleton()->parse_input_event(ev);160}161}162}163164void AndroidInputHandler::_release_all_touch() {165_parse_all_touch(false, false);166touch.clear();167}168169void AndroidInputHandler::process_touch_event(int p_event, int p_pointer, const Vector<TouchPos> &p_points, bool p_double_tap) {170switch (p_event) {171case AMOTION_EVENT_ACTION_DOWN: { //gesture begin172// Release any remaining touches or mouse event173_release_mouse_event_info();174_release_all_touch();175176touch.resize(p_points.size());177for (int i = 0; i < p_points.size(); i++) {178touch.write[i].id = p_points[i].id;179touch.write[i].pos = p_points[i].pos;180touch.write[i].pressure = p_points[i].pressure;181touch.write[i].tilt = p_points[i].tilt;182}183184//send touch185_parse_all_touch(true, false, p_double_tap);186187} break;188case AMOTION_EVENT_ACTION_MOVE: { //motion189if (touch.size() != p_points.size()) {190return;191}192193for (int i = 0; i < touch.size(); i++) {194int idx = -1;195for (int j = 0; j < p_points.size(); j++) {196if (touch[i].id == p_points[j].id) {197idx = j;198break;199}200}201202ERR_CONTINUE(idx == -1);203204if (touch[i].pos == p_points[idx].pos) {205continue; // Don't move unnecessarily.206}207208Ref<InputEventScreenDrag> ev;209ev.instantiate();210ev->set_index(touch[i].id);211ev->set_position(p_points[idx].pos);212ev->set_relative(p_points[idx].pos - touch[i].pos);213ev->set_relative_screen_position(ev->get_relative());214ev->set_pressure(p_points[idx].pressure);215ev->set_tilt(p_points[idx].tilt);216Input::get_singleton()->parse_input_event(ev);217touch.write[i].pos = p_points[idx].pos;218}219220} break;221case AMOTION_EVENT_ACTION_CANCEL: {222_cancel_all_touch();223} break;224case AMOTION_EVENT_ACTION_UP: { //release225_release_all_touch();226} break;227case AMOTION_EVENT_ACTION_POINTER_DOWN: { // add touch228for (int i = 0; i < p_points.size(); i++) {229if (p_points[i].id == p_pointer) {230TouchPos tp = p_points[i];231touch.push_back(tp);232233Ref<InputEventScreenTouch> ev;234ev.instantiate();235236ev->set_index(tp.id);237ev->set_pressed(true);238ev->set_position(tp.pos);239Input::get_singleton()->parse_input_event(ev);240241break;242}243}244} break;245case AMOTION_EVENT_ACTION_POINTER_UP: { // remove touch246for (int i = 0; i < touch.size(); i++) {247if (touch[i].id == p_pointer) {248Ref<InputEventScreenTouch> ev;249ev.instantiate();250ev->set_index(touch[i].id);251ev->set_pressed(false);252ev->set_position(touch[i].pos);253Input::get_singleton()->parse_input_event(ev);254touch.remove_at(i);255256break;257}258}259} break;260}261}262263void AndroidInputHandler::_cancel_mouse_event_info(bool p_source_mouse_relative) {264buttons_state = BitField<MouseButtonMask>();265_parse_mouse_event_info(BitField<MouseButtonMask>(), false, true, false, p_source_mouse_relative);266mouse_event_info.valid = false;267}268269void AndroidInputHandler::_parse_mouse_event_info(BitField<MouseButtonMask> event_buttons_mask, bool p_pressed, bool p_canceled, bool p_double_click, bool p_source_mouse_relative) {270if (!mouse_event_info.valid) {271return;272}273274Ref<InputEventMouseButton> ev;275ev.instantiate();276_set_key_modifier_state(ev, Key::NONE);277if (p_source_mouse_relative) {278ev->set_position(hover_prev_pos);279ev->set_global_position(hover_prev_pos);280} else {281ev->set_position(mouse_event_info.pos);282ev->set_global_position(mouse_event_info.pos);283hover_prev_pos = mouse_event_info.pos;284}285ev->set_pressed(p_pressed);286ev->set_canceled(p_canceled);287BitField<MouseButtonMask> changed_button_mask = buttons_state.get_different(event_buttons_mask);288289buttons_state = event_buttons_mask;290291ev->set_button_index(_button_index_from_mask(changed_button_mask));292ev->set_button_mask(event_buttons_mask);293ev->set_double_click(p_double_click);294Input::get_singleton()->parse_input_event(ev);295}296297void AndroidInputHandler::_release_mouse_event_info(bool p_source_mouse_relative) {298_parse_mouse_event_info(BitField<MouseButtonMask>(), false, false, false, p_source_mouse_relative);299mouse_event_info.valid = false;300}301302void AndroidInputHandler::process_mouse_event(int p_event_action, int p_event_android_buttons_mask, Point2 p_event_pos, Vector2 p_delta, bool p_double_click, bool p_source_mouse_relative, float p_pressure, Vector2 p_tilt) {303BitField<MouseButtonMask> event_buttons_mask = _android_button_mask_to_godot_button_mask(p_event_android_buttons_mask);304switch (p_event_action) {305case AMOTION_EVENT_ACTION_HOVER_MOVE: // hover move306case AMOTION_EVENT_ACTION_HOVER_ENTER: // hover enter307case AMOTION_EVENT_ACTION_HOVER_EXIT: { // hover exit308// https://developer.android.com/reference/android/view/MotionEvent.html#ACTION_HOVER_ENTER309Ref<InputEventMouseMotion> ev;310ev.instantiate();311_set_key_modifier_state(ev, Key::NONE);312ev->set_position(p_event_pos);313ev->set_global_position(p_event_pos);314ev->set_relative(p_event_pos - hover_prev_pos);315ev->set_relative_screen_position(ev->get_relative());316Input::get_singleton()->parse_input_event(ev);317hover_prev_pos = p_event_pos;318} break;319320case AMOTION_EVENT_ACTION_DOWN:321case AMOTION_EVENT_ACTION_BUTTON_PRESS: {322// Release any remaining touches or mouse event323_release_mouse_event_info();324_release_all_touch();325326mouse_event_info.valid = true;327mouse_event_info.pos = p_event_pos;328_parse_mouse_event_info(event_buttons_mask, true, false, p_double_click, p_source_mouse_relative);329} break;330331case AMOTION_EVENT_ACTION_CANCEL: {332_cancel_mouse_event_info(p_source_mouse_relative);333} break;334335case AMOTION_EVENT_ACTION_UP:336case AMOTION_EVENT_ACTION_BUTTON_RELEASE: {337_release_mouse_event_info(p_source_mouse_relative);338} break;339340case AMOTION_EVENT_ACTION_MOVE: {341if (!p_source_mouse_relative && !mouse_event_info.valid) {342return;343}344345Ref<InputEventMouseMotion> ev;346ev.instantiate();347_set_key_modifier_state(ev, Key::NONE);348if (p_source_mouse_relative) {349ev->set_position(hover_prev_pos);350ev->set_global_position(hover_prev_pos);351ev->set_relative(p_event_pos);352ev->set_relative_screen_position(p_event_pos);353} else {354ev->set_position(p_event_pos);355ev->set_global_position(p_event_pos);356ev->set_relative(p_event_pos - hover_prev_pos);357ev->set_relative_screen_position(ev->get_relative());358mouse_event_info.pos = p_event_pos;359hover_prev_pos = p_event_pos;360}361ev->set_button_mask(event_buttons_mask);362ev->set_pressure(p_pressure);363ev->set_tilt(p_tilt);364Input::get_singleton()->parse_input_event(ev);365} break;366367case AMOTION_EVENT_ACTION_SCROLL: {368Ref<InputEventMouseButton> ev;369ev.instantiate();370_set_key_modifier_state(ev, Key::NONE);371if (p_source_mouse_relative) {372ev->set_position(hover_prev_pos);373ev->set_global_position(hover_prev_pos);374} else {375ev->set_position(p_event_pos);376ev->set_global_position(p_event_pos);377}378ev->set_pressed(true);379buttons_state = event_buttons_mask;380if (p_delta.y > 0) {381_wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_UP, p_delta.y);382} else if (p_delta.y < 0) {383_wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_DOWN, -p_delta.y);384}385386if (p_delta.x > 0) {387_wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_RIGHT, p_delta.x);388} else if (p_delta.x < 0) {389_wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_LEFT, -p_delta.x);390}391} break;392}393}394395void AndroidInputHandler::_wheel_button_click(BitField<MouseButtonMask> event_buttons_mask, const Ref<InputEventMouseButton> &ev, MouseButton wheel_button, float factor) {396Ref<InputEventMouseButton> evd = ev->duplicate();397_set_key_modifier_state(evd, Key::NONE);398evd->set_button_index(wheel_button);399evd->set_button_mask(event_buttons_mask.get_different(mouse_button_to_mask(wheel_button)));400evd->set_factor(factor);401Input::get_singleton()->parse_input_event(evd);402Ref<InputEventMouseButton> evdd = evd->duplicate();403evdd->set_pressed(false);404evdd->set_button_mask(event_buttons_mask);405Input::get_singleton()->parse_input_event(evdd);406}407408void AndroidInputHandler::process_magnify(Point2 p_pos, float p_factor) {409Ref<InputEventMagnifyGesture> magnify_event;410magnify_event.instantiate();411_set_key_modifier_state(magnify_event, Key::NONE);412magnify_event->set_position(p_pos);413magnify_event->set_factor(p_factor);414Input::get_singleton()->parse_input_event(magnify_event);415}416417void AndroidInputHandler::process_pan(Point2 p_pos, Vector2 p_delta) {418Ref<InputEventPanGesture> pan_event;419pan_event.instantiate();420_set_key_modifier_state(pan_event, Key::NONE);421pan_event->set_position(p_pos);422pan_event->set_delta(p_delta);423Input::get_singleton()->parse_input_event(pan_event);424}425426MouseButton AndroidInputHandler::_button_index_from_mask(BitField<MouseButtonMask> button_mask) {427switch (button_mask) {428case MouseButtonMask::LEFT:429return MouseButton::LEFT;430case MouseButtonMask::RIGHT:431return MouseButton::RIGHT;432case MouseButtonMask::MIDDLE:433return MouseButton::MIDDLE;434case MouseButtonMask::MB_XBUTTON1:435return MouseButton::MB_XBUTTON1;436case MouseButtonMask::MB_XBUTTON2:437return MouseButton::MB_XBUTTON2;438default:439return MouseButton::NONE;440}441}442443BitField<MouseButtonMask> AndroidInputHandler::_android_button_mask_to_godot_button_mask(int android_button_mask) {444BitField<MouseButtonMask> godot_button_mask = MouseButtonMask::NONE;445if (android_button_mask & AMOTION_EVENT_BUTTON_PRIMARY) {446godot_button_mask.set_flag(MouseButtonMask::LEFT);447}448if (android_button_mask & AMOTION_EVENT_BUTTON_SECONDARY) {449godot_button_mask.set_flag(MouseButtonMask::RIGHT);450}451if (android_button_mask & AMOTION_EVENT_BUTTON_TERTIARY) {452godot_button_mask.set_flag(MouseButtonMask::MIDDLE);453}454if (android_button_mask & AMOTION_EVENT_BUTTON_BACK) {455godot_button_mask.set_flag(MouseButtonMask::MB_XBUTTON1);456}457if (android_button_mask & AMOTION_EVENT_BUTTON_FORWARD) {458godot_button_mask.set_flag(MouseButtonMask::MB_XBUTTON2);459}460461return godot_button_mask;462}463464465