mirror of
https://github.com/godotengine/godot.git
synced 2024-11-22 04:06:14 +00:00
Implement universal translation of touch to mouse
Now generating mouse events from touch is optional (on by default) and it's performed by `InputDefault` instead of having each OS abstraction doing it. (*) The translation algorithm waits for a touch index to be pressed and tracks it translating its events to mouse events until it is raised, while ignoring other pointers. Furthermore, to avoid an stuck "touch mouse", since not all platforms may report touches raised when the window is unfocused, it checks if touches are still down by the time it's focused again and if so it resets the state of the emulated mouse. *: In the case of Windows, since it already provides touch-to-mouse translation by itself, "echo" mouse events are filtered out to have it working like the rest. On X11 a little hack has been needed to avoid a case of a spurious mouse motion event that is generated during touch interaction. Plus: Improve/fix tracking of current mouse position. ** Summary of changes to settings: ** - `display/window/handheld/emulate_touchscreen` becomes `input/pointing_devices/emulate_touch_from_mouse` - New setting: `input/pointing_devices/emulate_mouse_from_touch`
This commit is contained in:
parent
3a5b25d5b4
commit
de9d40a953
@ -117,7 +117,8 @@ public:
|
||||
|
||||
void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;
|
||||
|
||||
virtual bool is_emulating_touchscreen() const = 0;
|
||||
virtual bool is_emulating_touch_from_mouse() const = 0;
|
||||
virtual bool is_emulating_mouse_from_touch() const = 0;
|
||||
|
||||
virtual CursorShape get_default_cursor_shape() = 0;
|
||||
virtual void set_default_cursor_shape(CursorShape p_shape) = 0;
|
||||
|
@ -411,7 +411,7 @@ Error OS::set_cwd(const String &p_cwd) {
|
||||
bool OS::has_touchscreen_ui_hint() const {
|
||||
|
||||
//return false;
|
||||
return Input::get_singleton() && Input::get_singleton()->is_emulating_touchscreen();
|
||||
return Input::get_singleton() && Input::get_singleton()->is_emulating_touch_from_mouse();
|
||||
}
|
||||
|
||||
int OS::get_free_static_memory() const {
|
||||
|
@ -4886,7 +4886,7 @@ EditorNode::EditorNode() {
|
||||
|
||||
if (!OS::get_singleton()->has_touchscreen_ui_hint() && Input::get_singleton()) {
|
||||
//only if no touchscreen ui hint, set emulation
|
||||
id->set_emulate_touch(false); //just disable just in case
|
||||
id->set_emulate_touch_from_mouse(false); //just disable just in case
|
||||
}
|
||||
id->set_custom_mouse_cursor(RES());
|
||||
}
|
||||
|
@ -250,6 +250,11 @@ Vector3 InputDefault::get_gyroscope() const {
|
||||
|
||||
void InputDefault::parse_input_event(const Ref<InputEvent> &p_event) {
|
||||
|
||||
_parse_input_event_impl(p_event, false);
|
||||
}
|
||||
|
||||
void InputDefault::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated) {
|
||||
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
Ref<InputEventKey> k = p_event;
|
||||
@ -273,25 +278,30 @@ void InputDefault::parse_input_event(const Ref<InputEvent> &p_event) {
|
||||
mouse_button_mask &= ~(1 << (mb->get_button_index() - 1));
|
||||
}
|
||||
|
||||
if (main_loop && emulate_touch && mb->get_button_index() == 1) {
|
||||
Point2 pos = mb->get_global_position();
|
||||
if (mouse_pos != pos) {
|
||||
set_mouse_position(pos);
|
||||
}
|
||||
|
||||
if (main_loop && emulate_touch_from_mouse && !p_is_emulated && mb->get_button_index() == 1) {
|
||||
Ref<InputEventScreenTouch> touch_event;
|
||||
touch_event.instance();
|
||||
touch_event->set_pressed(mb->is_pressed());
|
||||
touch_event->set_position(mb->get_position());
|
||||
main_loop->input_event(touch_event);
|
||||
}
|
||||
|
||||
Point2 pos = mb->get_global_position();
|
||||
if (mouse_pos != pos) {
|
||||
set_mouse_position(pos);
|
||||
}
|
||||
}
|
||||
|
||||
Ref<InputEventMouseMotion> mm = p_event;
|
||||
|
||||
if (mm.is_valid()) {
|
||||
|
||||
if (main_loop && emulate_touch && mm->get_button_mask() & 1) {
|
||||
Point2 pos = mm->get_global_position();
|
||||
if (mouse_pos != pos) {
|
||||
set_mouse_position(pos);
|
||||
}
|
||||
|
||||
if (main_loop && emulate_touch_from_mouse && !p_is_emulated && mm->get_button_mask() & 1) {
|
||||
Ref<InputEventScreenDrag> drag_event;
|
||||
drag_event.instance();
|
||||
|
||||
@ -303,6 +313,58 @@ void InputDefault::parse_input_event(const Ref<InputEvent> &p_event) {
|
||||
}
|
||||
}
|
||||
|
||||
if (emulate_mouse_from_touch) {
|
||||
|
||||
Ref<InputEventScreenTouch> st = p_event;
|
||||
|
||||
if (st.is_valid()) {
|
||||
bool translate = false;
|
||||
if (st->is_pressed()) {
|
||||
if (mouse_from_touch_index == -1) {
|
||||
translate = true;
|
||||
mouse_from_touch_index = st->get_index();
|
||||
}
|
||||
} else {
|
||||
if (st->get_index() == mouse_from_touch_index) {
|
||||
translate = true;
|
||||
mouse_from_touch_index = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (translate) {
|
||||
Ref<InputEventMouseButton> button_event;
|
||||
button_event.instance();
|
||||
|
||||
button_event->set_position(st->get_position());
|
||||
button_event->set_global_position(st->get_position());
|
||||
button_event->set_pressed(st->is_pressed());
|
||||
button_event->set_button_index(BUTTON_LEFT);
|
||||
if (st->is_pressed()) {
|
||||
button_event->set_button_mask(mouse_button_mask | (1 << BUTTON_LEFT - 1));
|
||||
} else {
|
||||
button_event->set_button_mask(mouse_button_mask & ~(1 << BUTTON_LEFT - 1));
|
||||
}
|
||||
|
||||
_parse_input_event_impl(button_event, true);
|
||||
}
|
||||
}
|
||||
|
||||
Ref<InputEventScreenDrag> sd = p_event;
|
||||
|
||||
if (sd.is_valid() && sd->get_index() == mouse_from_touch_index) {
|
||||
Ref<InputEventMouseMotion> motion_event;
|
||||
motion_event.instance();
|
||||
|
||||
motion_event->set_position(sd->get_position());
|
||||
motion_event->set_global_position(sd->get_position());
|
||||
motion_event->set_relative(sd->get_relative());
|
||||
motion_event->set_speed(sd->get_speed());
|
||||
motion_event->set_button_mask(mouse_button_mask);
|
||||
|
||||
_parse_input_event_impl(motion_event, true);
|
||||
}
|
||||
}
|
||||
|
||||
Ref<InputEventJoypadButton> jb = p_event;
|
||||
|
||||
if (jb.is_valid()) {
|
||||
@ -485,14 +547,44 @@ void InputDefault::action_release(const StringName &p_action) {
|
||||
action_state[p_action] = action;
|
||||
}
|
||||
|
||||
void InputDefault::set_emulate_touch(bool p_emulate) {
|
||||
void InputDefault::set_emulate_touch_from_mouse(bool p_emulate) {
|
||||
|
||||
emulate_touch = p_emulate;
|
||||
emulate_touch_from_mouse = p_emulate;
|
||||
}
|
||||
|
||||
bool InputDefault::is_emulating_touchscreen() const {
|
||||
bool InputDefault::is_emulating_touch_from_mouse() const {
|
||||
|
||||
return emulate_touch;
|
||||
return emulate_touch_from_mouse;
|
||||
}
|
||||
|
||||
// Calling this whenever the game window is focused helps unstucking the "touch mouse"
|
||||
// if the OS or its abstraction class hasn't properly reported that touch pointers raised
|
||||
void InputDefault::ensure_touch_mouse_raised() {
|
||||
|
||||
if (mouse_from_touch_index != -1) {
|
||||
mouse_from_touch_index = -1;
|
||||
|
||||
Ref<InputEventMouseButton> button_event;
|
||||
button_event.instance();
|
||||
|
||||
button_event->set_position(mouse_pos);
|
||||
button_event->set_global_position(mouse_pos);
|
||||
button_event->set_pressed(false);
|
||||
button_event->set_button_index(BUTTON_LEFT);
|
||||
button_event->set_button_mask(mouse_button_mask & ~(1 << BUTTON_LEFT - 1));
|
||||
|
||||
_parse_input_event_impl(button_event, true);
|
||||
}
|
||||
}
|
||||
|
||||
void InputDefault::set_emulate_mouse_from_touch(bool p_emulate) {
|
||||
|
||||
emulate_mouse_from_touch = p_emulate;
|
||||
}
|
||||
|
||||
bool InputDefault::is_emulating_mouse_from_touch() const {
|
||||
|
||||
return emulate_mouse_from_touch;
|
||||
}
|
||||
|
||||
Input::CursorShape InputDefault::get_default_cursor_shape() {
|
||||
@ -529,7 +621,9 @@ void InputDefault::set_mouse_in_window(bool p_in_window) {
|
||||
InputDefault::InputDefault() {
|
||||
|
||||
mouse_button_mask = 0;
|
||||
emulate_touch = false;
|
||||
emulate_touch_from_mouse = false;
|
||||
emulate_mouse_from_touch = false;
|
||||
mouse_from_touch_index = -1;
|
||||
main_loop = NULL;
|
||||
|
||||
hat_map_default[HAT_UP].type = TYPE_BUTTON;
|
||||
|
@ -59,7 +59,10 @@ class InputDefault : public Input {
|
||||
|
||||
Map<StringName, Action> action_state;
|
||||
|
||||
bool emulate_touch;
|
||||
bool emulate_touch_from_mouse;
|
||||
bool emulate_mouse_from_touch;
|
||||
|
||||
int mouse_from_touch_index;
|
||||
|
||||
struct VibrationInfo {
|
||||
float weak_magnitude;
|
||||
@ -175,6 +178,8 @@ private:
|
||||
void _axis_event(int p_device, int p_axis, float p_value);
|
||||
float _handle_deadzone(int p_device, int p_axis, float p_value);
|
||||
|
||||
void _parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated);
|
||||
|
||||
public:
|
||||
virtual bool is_key_pressed(int p_scancode) const;
|
||||
virtual bool is_mouse_button_pressed(int p_button) const;
|
||||
@ -223,8 +228,12 @@ public:
|
||||
|
||||
void iteration(float p_step);
|
||||
|
||||
void set_emulate_touch(bool p_emulate);
|
||||
virtual bool is_emulating_touchscreen() const;
|
||||
void set_emulate_touch_from_mouse(bool p_emulate);
|
||||
virtual bool is_emulating_touch_from_mouse() const;
|
||||
void ensure_touch_mouse_raised();
|
||||
|
||||
void set_emulate_mouse_from_touch(bool p_emulate);
|
||||
virtual bool is_emulating_mouse_from_touch() const;
|
||||
|
||||
virtual CursorShape get_default_cursor_shape();
|
||||
virtual void set_default_cursor_shape(CursorShape p_shape);
|
||||
|
@ -1141,13 +1141,16 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
|
||||
GLOBAL_DEF("application/config/icon", String());
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("application/config/icon", PropertyInfo(Variant::STRING, "application/config/icon", PROPERTY_HINT_FILE, "*.png,*.webp"));
|
||||
|
||||
if (bool(GLOBAL_DEF("display/window/handheld/emulate_touchscreen", false))) {
|
||||
if (!OS::get_singleton()->has_touchscreen_ui_hint() && Input::get_singleton() && !(editor || project_manager)) {
|
||||
//only if no touchscreen ui hint, set emulation
|
||||
InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
|
||||
if (id)
|
||||
id->set_emulate_touch(true);
|
||||
InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
|
||||
if (id) {
|
||||
if (bool(GLOBAL_DEF("input/pointing_devices/emulate_touch_from_mouse", false)) && !(editor || project_manager)) {
|
||||
if (!OS::get_singleton()->has_touchscreen_ui_hint()) {
|
||||
//only if no touchscreen ui hint, set emulation
|
||||
id->set_emulate_touch_from_mouse(true);
|
||||
}
|
||||
}
|
||||
|
||||
id->set_emulate_mouse_from_touch(bool(GLOBAL_DEF("input/pointing_devices/emulate_mouse_from_touch", true)));
|
||||
}
|
||||
|
||||
MAIN_PRINT("Main: Load Remaps");
|
||||
|
@ -330,17 +330,6 @@ void OS_Android::process_touch(int p_what, int p_pointer, const Vector<TouchPos>
|
||||
|
||||
if (touch.size()) {
|
||||
//end all if exist
|
||||
{
|
||||
Ref<InputEventMouseButton> ev;
|
||||
ev.instance();
|
||||
ev->set_button_index(BUTTON_LEFT);
|
||||
ev->set_button_mask(BUTTON_MASK_LEFT);
|
||||
ev->set_pressed(false);
|
||||
ev->set_position(touch[0].pos);
|
||||
ev->set_global_position(touch[0].pos);
|
||||
input->parse_input_event(ev);
|
||||
}
|
||||
|
||||
for (int i = 0; i < touch.size(); i++) {
|
||||
|
||||
Ref<InputEventScreenTouch> ev;
|
||||
@ -358,21 +347,6 @@ void OS_Android::process_touch(int p_what, int p_pointer, const Vector<TouchPos>
|
||||
touch[i].pos = p_points[i].pos;
|
||||
}
|
||||
|
||||
{
|
||||
//send mouse
|
||||
Ref<InputEventMouseButton> ev;
|
||||
ev.instance();
|
||||
// ev.type = Ref<InputEvent>::MOUSE_BUTTON;
|
||||
ev->set_button_index(BUTTON_LEFT);
|
||||
ev->set_button_mask(BUTTON_MASK_LEFT);
|
||||
ev->set_pressed(true);
|
||||
ev->set_position(touch[0].pos);
|
||||
ev->set_global_position(touch[0].pos);
|
||||
input->set_mouse_position(Point2(touch[0].pos.x, touch[0].pos.y));
|
||||
last_mouse = touch[0].pos;
|
||||
input->parse_input_event(ev);
|
||||
}
|
||||
|
||||
//send touch
|
||||
for (int i = 0; i < touch.size(); i++) {
|
||||
|
||||
@ -387,19 +361,6 @@ void OS_Android::process_touch(int p_what, int p_pointer, const Vector<TouchPos>
|
||||
} break;
|
||||
case 1: { //motion
|
||||
|
||||
if (p_points.size()) {
|
||||
//send mouse, should look for point 0?
|
||||
Ref<InputEventMouseMotion> ev;
|
||||
ev.instance();
|
||||
ev->set_button_mask(BUTTON_MASK_LEFT);
|
||||
ev->set_position(p_points[0].pos);
|
||||
input->set_mouse_position(Point2(ev->get_position().x, ev->get_position().y));
|
||||
ev->set_speed(input->get_last_mouse_speed());
|
||||
ev->set_relative(p_points[0].pos - last_mouse);
|
||||
last_mouse = p_points[0].pos;
|
||||
input->parse_input_event(ev);
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(touch.size() != p_points.size());
|
||||
|
||||
for (int i = 0; i < touch.size(); i++) {
|
||||
@ -432,16 +393,6 @@ void OS_Android::process_touch(int p_what, int p_pointer, const Vector<TouchPos>
|
||||
|
||||
if (touch.size()) {
|
||||
//end all if exist
|
||||
Ref<InputEventMouseButton> ev;
|
||||
ev.instance();
|
||||
ev->set_button_index(BUTTON_LEFT);
|
||||
ev->set_button_mask(BUTTON_MASK_LEFT);
|
||||
ev->set_pressed(false);
|
||||
ev->set_position(touch[0].pos);
|
||||
ev->set_global_position(touch[0].pos);
|
||||
input->set_mouse_position(Point2(touch[0].pos.x, touch[0].pos.y));
|
||||
input->parse_input_event(ev);
|
||||
|
||||
for (int i = 0; i < touch.size(); i++) {
|
||||
|
||||
Ref<InputEventScreenTouch> ev;
|
||||
|
@ -93,7 +93,6 @@ public:
|
||||
private:
|
||||
Vector<TouchPos> touch;
|
||||
|
||||
Point2 last_mouse;
|
||||
GFXInitFunc gfx_init_func;
|
||||
void *gfx_init_ud;
|
||||
|
||||
|
@ -497,7 +497,7 @@ static void clear_touches() {
|
||||
int tid = get_touch_id(touch);
|
||||
ERR_FAIL_COND(tid == -1);
|
||||
CGPoint touchPoint = [touch locationInView:self];
|
||||
OSIPhone::get_singleton()->mouse_button(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, true, touch.tapCount > 1, tid == 0);
|
||||
OSIPhone::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, true, touch.tapCount > 1);
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -514,10 +514,9 @@ static void clear_touches() {
|
||||
continue;
|
||||
int tid = get_touch_id(touch);
|
||||
ERR_FAIL_COND(tid == -1);
|
||||
int first = get_first_id(touch);
|
||||
CGPoint touchPoint = [touch locationInView:self];
|
||||
CGPoint prev_point = [touch previousLocationInView:self];
|
||||
OSIPhone::get_singleton()->mouse_move(tid, prev_point.x * self.contentScaleFactor, prev_point.y * self.contentScaleFactor, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, first == tid);
|
||||
OSIPhone::get_singleton()->touch_drag(tid, prev_point.x * self.contentScaleFactor, prev_point.y * self.contentScaleFactor, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor);
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -533,9 +532,9 @@ static void clear_touches() {
|
||||
continue;
|
||||
int tid = get_touch_id(touch);
|
||||
ERR_FAIL_COND(tid == -1);
|
||||
int rem = remove_touch(touch);
|
||||
remove_touch(touch);
|
||||
CGPoint touchPoint = [touch locationInView:self];
|
||||
OSIPhone::get_singleton()->mouse_button(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, false, false, rem == 0);
|
||||
OSIPhone::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, false, false);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -190,7 +190,7 @@ void OSIPhone::key(uint32_t p_key, bool p_pressed) {
|
||||
queue_event(ev);
|
||||
};
|
||||
|
||||
void OSIPhone::mouse_button(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick, bool p_use_as_mouse) {
|
||||
void OSIPhone::touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick) {
|
||||
|
||||
if (!GLOBAL_DEF("debug/disable_touch", false)) {
|
||||
Ref<InputEventScreenTouch> ev;
|
||||
@ -202,28 +202,10 @@ void OSIPhone::mouse_button(int p_idx, int p_x, int p_y, bool p_pressed, bool p_
|
||||
queue_event(ev);
|
||||
};
|
||||
|
||||
mouse_list.pressed[p_idx] = p_pressed;
|
||||
|
||||
if (p_use_as_mouse) {
|
||||
|
||||
Ref<InputEventMouseButton> ev;
|
||||
ev.instance();
|
||||
|
||||
ev->set_position(Vector2(p_x, p_y));
|
||||
ev->set_global_position(Vector2(p_x, p_y));
|
||||
|
||||
//mouse_list.pressed[p_idx] = p_pressed;
|
||||
|
||||
input->set_mouse_position(ev->get_position());
|
||||
ev->set_button_index(BUTTON_LEFT);
|
||||
ev->set_doubleclick(p_doubleclick);
|
||||
ev->set_pressed(p_pressed);
|
||||
|
||||
queue_event(ev);
|
||||
};
|
||||
touch_list.pressed[p_idx] = p_pressed;
|
||||
};
|
||||
|
||||
void OSIPhone::mouse_move(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, bool p_use_as_mouse) {
|
||||
void OSIPhone::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y) {
|
||||
|
||||
if (!GLOBAL_DEF("debug/disable_touch", false)) {
|
||||
|
||||
@ -234,21 +216,6 @@ void OSIPhone::mouse_move(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_
|
||||
ev->set_relative(Vector2(p_x - p_prev_x, p_y - p_prev_y));
|
||||
queue_event(ev);
|
||||
};
|
||||
|
||||
if (p_use_as_mouse) {
|
||||
Ref<InputEventMouseMotion> ev;
|
||||
ev.instance();
|
||||
|
||||
ev->set_position(Vector2(p_x, p_y));
|
||||
ev->set_global_position(Vector2(p_x, p_y));
|
||||
ev->set_relative(Vector2(p_x - p_prev_x, p_y - p_prev_y));
|
||||
|
||||
input->set_mouse_position(ev->get_position());
|
||||
ev->set_speed(input->get_last_mouse_speed());
|
||||
ev->set_button_mask(BUTTON_LEFT); // pressed
|
||||
|
||||
queue_event(ev);
|
||||
};
|
||||
};
|
||||
|
||||
void OSIPhone::queue_event(const Ref<InputEvent> &p_event) {
|
||||
@ -262,10 +229,10 @@ void OSIPhone::touches_cancelled() {
|
||||
|
||||
for (int i = 0; i < MAX_MOUSE_COUNT; i++) {
|
||||
|
||||
if (mouse_list.pressed[i]) {
|
||||
if (touch_list.pressed[i]) {
|
||||
|
||||
// send a mouse_up outside the screen
|
||||
mouse_button(i, -1, -1, false, false, false);
|
||||
touch_press(i, -1, -1, false, false);
|
||||
};
|
||||
};
|
||||
};
|
||||
@ -376,7 +343,7 @@ Point2 OSIPhone::get_mouse_position() const {
|
||||
|
||||
int OSIPhone::get_mouse_button_state() const {
|
||||
|
||||
return mouse_list.pressed[0];
|
||||
return 0;
|
||||
};
|
||||
|
||||
void OSIPhone::set_window_title(const String &p_title){};
|
||||
|
@ -106,7 +106,7 @@ private:
|
||||
};
|
||||
};
|
||||
|
||||
MouseList mouse_list;
|
||||
MouseList touch_list;
|
||||
|
||||
Vector3 last_accel;
|
||||
|
||||
@ -127,8 +127,8 @@ public:
|
||||
|
||||
uint8_t get_orientations() const;
|
||||
|
||||
void mouse_button(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick, bool p_use_as_mouse);
|
||||
void mouse_move(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, bool p_use_as_mouse);
|
||||
void touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick);
|
||||
void touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y);
|
||||
void touches_cancelled();
|
||||
void key(uint32_t p_key, bool p_pressed);
|
||||
void set_virtual_keyboard_height(int p_height);
|
||||
|
@ -285,23 +285,6 @@ static EM_BOOL _touchpress_callback(int event_type, const EmscriptenTouchEvent *
|
||||
|
||||
_input->parse_input_event(ev);
|
||||
}
|
||||
|
||||
if (touch_event->touches[lowest_id_index].isChanged) {
|
||||
|
||||
Ref<InputEventMouseButton> ev_mouse;
|
||||
ev_mouse.instance();
|
||||
ev_mouse->set_button_mask(_input->get_mouse_button_mask());
|
||||
dom2godot_mod(touch_event, ev_mouse);
|
||||
|
||||
const EmscriptenTouchPoint &first_touch = touch_event->touches[lowest_id_index];
|
||||
ev_mouse->set_position(Point2(first_touch.canvasX, first_touch.canvasY));
|
||||
ev_mouse->set_global_position(ev_mouse->get_position());
|
||||
|
||||
ev_mouse->set_button_index(BUTTON_LEFT);
|
||||
ev_mouse->set_pressed(event_type == EMSCRIPTEN_EVENT_TOUCHSTART);
|
||||
|
||||
_input->parse_input_event(ev_mouse);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -327,24 +310,6 @@ static EM_BOOL _touchmove_callback(int event_type, const EmscriptenTouchEvent *t
|
||||
|
||||
_input->parse_input_event(ev);
|
||||
}
|
||||
|
||||
if (touch_event->touches[lowest_id_index].isChanged) {
|
||||
|
||||
Ref<InputEventMouseMotion> ev_mouse;
|
||||
ev_mouse.instance();
|
||||
dom2godot_mod(touch_event, ev_mouse);
|
||||
ev_mouse->set_button_mask(_input->get_mouse_button_mask());
|
||||
|
||||
const EmscriptenTouchPoint &first_touch = touch_event->touches[lowest_id_index];
|
||||
ev_mouse->set_position(Point2(first_touch.canvasX, first_touch.canvasY));
|
||||
ev_mouse->set_global_position(ev_mouse->get_position());
|
||||
|
||||
ev_mouse->set_relative(ev_mouse->get_position() - _input->get_mouse_position());
|
||||
_input->set_mouse_position(ev_mouse->get_position());
|
||||
ev_mouse->set_speed(_input->get_last_mouse_speed());
|
||||
|
||||
_input->parse_input_event(ev_mouse);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -85,8 +85,7 @@ App::App() :
|
||||
mWindowHeight(0),
|
||||
mEglDisplay(EGL_NO_DISPLAY),
|
||||
mEglContext(EGL_NO_CONTEXT),
|
||||
mEglSurface(EGL_NO_SURFACE),
|
||||
number_of_contacts(0) {
|
||||
mEglSurface(EGL_NO_SURFACE) {
|
||||
}
|
||||
|
||||
// The first method called when the IFrameworkView is being created.
|
||||
@ -271,48 +270,44 @@ void App::pointer_event(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Cor
|
||||
last_touch_y[screen_touch->get_index()] = pos.Y;
|
||||
|
||||
os->input_event(screen_touch);
|
||||
if (number_of_contacts > 1)
|
||||
return;
|
||||
} else {
|
||||
|
||||
}; // fallthrought of sorts
|
||||
Ref<InputEventMouseButton> mouse_button;
|
||||
mouse_button.instance();
|
||||
mouse_button->set_device(0);
|
||||
mouse_button->set_pressed(p_pressed);
|
||||
mouse_button->set_button_index(but);
|
||||
mouse_button->set_position(Vector2(pos.X, pos.Y));
|
||||
mouse_button->set_global_position(Vector2(pos.X, pos.Y));
|
||||
|
||||
Ref<InputEventMouseButton> mouse_button;
|
||||
mouse_button.instance();
|
||||
mouse_button->set_device(0);
|
||||
mouse_button->set_pressed(p_pressed);
|
||||
mouse_button->set_button_index(but);
|
||||
mouse_button->set_position(Vector2(pos.X, pos.Y));
|
||||
mouse_button->set_global_position(Vector2(pos.X, pos.Y));
|
||||
|
||||
if (p_is_wheel) {
|
||||
if (point->Properties->MouseWheelDelta > 0) {
|
||||
mouse_button->set_button_index(point->Properties->IsHorizontalMouseWheel ? BUTTON_WHEEL_RIGHT : BUTTON_WHEEL_UP);
|
||||
} else if (point->Properties->MouseWheelDelta < 0) {
|
||||
mouse_button->set_button_index(point->Properties->IsHorizontalMouseWheel ? BUTTON_WHEEL_LEFT : BUTTON_WHEEL_DOWN);
|
||||
if (p_is_wheel) {
|
||||
if (point->Properties->MouseWheelDelta > 0) {
|
||||
mouse_button->set_button_index(point->Properties->IsHorizontalMouseWheel ? BUTTON_WHEEL_RIGHT : BUTTON_WHEEL_UP);
|
||||
} else if (point->Properties->MouseWheelDelta < 0) {
|
||||
mouse_button->set_button_index(point->Properties->IsHorizontalMouseWheel ? BUTTON_WHEEL_LEFT : BUTTON_WHEEL_DOWN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
last_touch_x[31] = pos.X;
|
||||
last_touch_y[31] = pos.Y;
|
||||
last_touch_x[31] = pos.X;
|
||||
last_touch_y[31] = pos.Y;
|
||||
|
||||
os->input_event(mouse_button);
|
||||
|
||||
if (p_is_wheel) {
|
||||
// Send release for mouse wheel
|
||||
mouse_button->set_pressed(false);
|
||||
os->input_event(mouse_button);
|
||||
|
||||
if (p_is_wheel) {
|
||||
// Send release for mouse wheel
|
||||
mouse_button->set_pressed(false);
|
||||
os->input_event(mouse_button);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void App::OnPointerPressed(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::PointerEventArgs ^ args) {
|
||||
|
||||
number_of_contacts++;
|
||||
pointer_event(sender, args, true);
|
||||
};
|
||||
|
||||
void App::OnPointerReleased(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::PointerEventArgs ^ args) {
|
||||
|
||||
number_of_contacts--;
|
||||
pointer_event(sender, args, false);
|
||||
};
|
||||
|
||||
@ -351,7 +346,7 @@ void App::OnPointerMoved(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Co
|
||||
Windows::UI::Input::PointerPoint ^ point = args->CurrentPoint;
|
||||
Windows::Foundation::Point pos = _get_pixel_position(window, point->Position, os);
|
||||
|
||||
if (point->IsInContact && _is_touch(point)) {
|
||||
if (_is_touch(point)) {
|
||||
|
||||
Ref<InputEventScreenDrag> screen_drag;
|
||||
screen_drag.instance();
|
||||
@ -361,25 +356,23 @@ void App::OnPointerMoved(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Co
|
||||
screen_drag->set_relative(Vector2(screen_drag->get_position().x - last_touch_x[screen_drag->get_index()], screen_drag->get_position().y - last_touch_y[screen_drag->get_index()]));
|
||||
|
||||
os->input_event(screen_drag);
|
||||
if (number_of_contacts > 1)
|
||||
} else {
|
||||
|
||||
// In case the mouse grabbed, MouseMoved will handle this
|
||||
if (os->get_mouse_mode() == OS::MouseMode::MOUSE_MODE_CAPTURED)
|
||||
return;
|
||||
|
||||
}; // fallthrought of sorts
|
||||
Ref<InputEventMouseMotion> mouse_motion;
|
||||
mouse_motion.instance();
|
||||
mouse_motion->set_device(0);
|
||||
mouse_motion->set_position(Vector2(pos.X, pos.Y));
|
||||
mouse_motion->set_global_position(Vector2(pos.X, pos.Y));
|
||||
mouse_motion->set_relative(Vector2(pos.X - last_touch_x[31], pos.Y - last_touch_y[31]));
|
||||
|
||||
// In case the mouse grabbed, MouseMoved will handle this
|
||||
if (os->get_mouse_mode() == OS::MouseMode::MOUSE_MODE_CAPTURED)
|
||||
return;
|
||||
last_mouse_pos = pos;
|
||||
|
||||
Ref<InputEventMouseMotion> mouse_motion;
|
||||
mouse_motion.instance();
|
||||
mouse_motion->set_device(0);
|
||||
mouse_motion->set_position(Vector2(pos.X, pos.Y));
|
||||
mouse_motion->set_global_position(Vector2(pos.X, pos.Y));
|
||||
mouse_motion->set_relative(Vector2(pos.X - last_touch_x[31], pos.Y - last_touch_y[31]));
|
||||
|
||||
last_mouse_pos = pos;
|
||||
|
||||
os->input_event(mouse_motion);
|
||||
os->input_event(mouse_motion);
|
||||
}
|
||||
}
|
||||
|
||||
void App::OnMouseMoved(MouseDevice ^ mouse_device, MouseEventArgs ^ args) {
|
||||
|
@ -107,7 +107,6 @@ namespace GodotUWP
|
||||
|
||||
int last_touch_x[32]; // 20 fingers, index 31 reserved for the mouse
|
||||
int last_touch_y[32];
|
||||
int number_of_contacts;
|
||||
Windows::Foundation::Point last_mouse_pos;
|
||||
};
|
||||
}
|
||||
|
@ -342,6 +342,14 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
} break;
|
||||
case WM_MOUSEMOVE: {
|
||||
|
||||
if (input->is_emulating_mouse_from_touch()) {
|
||||
// Universal translation enabled; ignore OS translation
|
||||
LPARAM extra = GetMessageExtraInfo();
|
||||
if (IsPenEvent(extra)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (outside) {
|
||||
//mouse enter
|
||||
|
||||
@ -367,18 +375,6 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
// Don't calculate relative mouse movement if we don't have focus in CAPTURED mode.
|
||||
if (!window_has_focus && mouse_mode == MOUSE_MODE_CAPTURED)
|
||||
break;
|
||||
/*
|
||||
LPARAM extra = GetMessageExtraInfo();
|
||||
if (IsPenEvent(extra)) {
|
||||
|
||||
int idx = extra & 0x7f;
|
||||
_drag_event(idx, uMsg, wParam, lParam);
|
||||
if (idx != 0) {
|
||||
return 0;
|
||||
};
|
||||
// fallthrough for mouse event
|
||||
};
|
||||
*/
|
||||
|
||||
Ref<InputEventMouseMotion> mm;
|
||||
mm.instance();
|
||||
@ -448,18 +444,13 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
/*case WM_XBUTTONDOWN:
|
||||
case WM_XBUTTONUP: */ {
|
||||
|
||||
/*
|
||||
LPARAM extra = GetMessageExtraInfo();
|
||||
if (IsPenEvent(extra)) {
|
||||
|
||||
int idx = extra & 0x7f;
|
||||
_touch_event(idx, uMsg, wParam, lParam);
|
||||
if (idx != 0) {
|
||||
return 0;
|
||||
};
|
||||
// fallthrough for mouse event
|
||||
};
|
||||
*/
|
||||
if (input->is_emulating_mouse_from_touch()) {
|
||||
// Universal translation enabled; ignore OS translation
|
||||
LPARAM extra = GetMessageExtraInfo();
|
||||
if (IsPenEvent(extra)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ref<InputEventMouseButton> mb;
|
||||
mb.instance();
|
||||
|
@ -1690,6 +1690,11 @@ void OS_X11::process_xevents() {
|
||||
if (touch.state.has(index)) // Defensive
|
||||
break;
|
||||
touch.state[index] = pos;
|
||||
if (touch.state.size() == 1) {
|
||||
// X11 may send a motion event when a touch gesture begins, that would result
|
||||
// in a spurious mouse motion event being sent to Godot; remember it to be able to filter it out
|
||||
touch.mouse_pos_to_filter = pos;
|
||||
}
|
||||
input->parse_input_event(st);
|
||||
} else {
|
||||
if (!touch.state.has(index)) // Defensive
|
||||
@ -1896,6 +1901,18 @@ void OS_X11::process_xevents() {
|
||||
// to be able to send relative motion events.
|
||||
Point2i pos(event.xmotion.x, event.xmotion.y);
|
||||
|
||||
// Avoidance of spurious mouse motion (see handling of touch)
|
||||
bool filter = false;
|
||||
// Adding some tolerance to match better Point2i to Vector2
|
||||
if (touch.state.size() && Vector2(pos).distance_squared_to(touch.mouse_pos_to_filter) < 2) {
|
||||
filter = true;
|
||||
}
|
||||
// Invalidate to avoid filtering a possible legitimate similar event coming later
|
||||
touch.mouse_pos_to_filter = Vector2(1e10, 1e10);
|
||||
if (filter) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (mouse_mode == MOUSE_MODE_CAPTURED) {
|
||||
|
||||
if (pos == Point2i(current_videomode.width / 2, current_videomode.height / 2)) {
|
||||
|
@ -127,6 +127,7 @@ class OS_X11 : public OS_Unix {
|
||||
Vector<int> devices;
|
||||
XIEventMask event_mask;
|
||||
Map<int, Vector2> state;
|
||||
Vector2 mouse_pos_to_filter;
|
||||
} touch;
|
||||
#endif
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "editor/editor_node.h"
|
||||
#include "io/marshalls.h"
|
||||
#include "io/resource_loader.h"
|
||||
#include "main/input_default.h"
|
||||
#include "message_queue.h"
|
||||
#include "node.h"
|
||||
#include "os/keyboard.h"
|
||||
@ -620,6 +621,13 @@ void SceneTree::_notification(int p_notification) {
|
||||
case NOTIFICATION_WM_FOCUS_IN:
|
||||
case NOTIFICATION_WM_FOCUS_OUT: {
|
||||
|
||||
if (p_notification == NOTIFICATION_WM_FOCUS_IN) {
|
||||
InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
|
||||
if (id) {
|
||||
id->ensure_touch_mouse_raised();
|
||||
}
|
||||
}
|
||||
|
||||
get_root()->propagate_notification(p_notification);
|
||||
} break;
|
||||
case NOTIFICATION_TRANSLATION_CHANGED: {
|
||||
|
Loading…
Reference in New Issue
Block a user