From b3993b684e30bf20fca66cf25308f627420a199d Mon Sep 17 00:00:00 2001 From: Jean-Philippe Andre Date: Wed, 31 Aug 2016 15:41:12 +0900 Subject: [PATCH] win: Add EO API to query state of multi touch points This combines evas canvas functions to list and query touch points into a single iterator: - evas_touch_point_list_count - evas_touch_point_list_nth_xy_get - evas_touch_point_list_nth_id_get - evas_touch_point_list_nth_state_get This also fixes a number of issues related to feeding fake input events. Note: I wanted to add delta x,y information as well but it's in fact not really possible outside the event callback itself, as the previous x,y position will not be updated unless there's an event. @feature --- src/lib/efl/interfaces/efl_input_types.eot | 3 +- src/lib/elementary/efl_ui_win.c | 223 ++++++++++++++++++++++++----- src/lib/elementary/efl_ui_win.eo | 1 + src/lib/evas/canvas/efl_input_interface.eo | 22 +++ src/lib/evas/canvas/efl_input_pointer.c | 13 +- src/lib/evas/canvas/evas_canvas.eo | 55 +------ src/lib/evas/canvas/evas_events.c | 4 + src/lib/evas/canvas/evas_touch_point.c | 13 +- src/lib/evas/include/evas_private.h | 7 +- src/tests/elementary/elm_test_win.c | 198 +++++++++++++++++++++++++ 10 files changed, 442 insertions(+), 97 deletions(-) diff --git a/src/lib/efl/interfaces/efl_input_types.eot b/src/lib/efl/interfaces/efl_input_types.eot index 8a9211e..fdd9df2 100644 --- a/src/lib/efl/interfaces/efl_input_types.eot +++ b/src/lib/efl/interfaces/efl_input_types.eot @@ -4,7 +4,8 @@ enum Efl.Pointer.Action @since 1.19 ]] - none, [[Not a valid event.]] + none, [[Not a valid event, or nothing new happened (eg. when querying + current state of touch points).]] move, [[Mouse or equivalent pointer moved.]] down, [[Mouse button or equivalent pointer pressed down. Always followed by up or cancel.]] diff --git a/src/lib/elementary/efl_ui_win.c b/src/lib/elementary/efl_ui_win.c index 90f16ab..7751ee8 100644 --- a/src/lib/elementary/efl_ui_win.c +++ b/src/lib/elementary/efl_ui_win.c @@ -4,7 +4,7 @@ #define ELM_INTERFACE_ATSPI_ACCESSIBLE_PROTECTED #define ELM_INTERFACE_ATSPI_WIDGET_ACTION_PROTECTED -#define ELM_WIN_PROTECTED +#define EFL_INPUT_EVENT_PROTECTED #include #include @@ -89,6 +89,7 @@ static const Elm_Win_Trap *trap = NULL; typedef struct _Efl_Ui_Win_Data Efl_Ui_Win_Data; typedef struct _Box_Item_Iterator Box_Item_Iterator; +typedef struct _Input_Pointer_Iterator Input_Pointer_Iterator; struct _Efl_Ui_Win_Data { @@ -223,6 +224,9 @@ struct _Efl_Ui_Win_Data short pointer_out; short pointer_cancel; short pointer_wheel; + short finger_move; + short finger_down; + short finger_up; short key_down; short key_up; short render_pre; @@ -261,6 +265,14 @@ struct _Box_Item_Iterator Eo *object; }; +struct _Input_Pointer_Iterator +{ + Eina_Iterator iterator; + Eina_List *list; + Eina_Iterator *real_iterator; + const Eo *object; +}; + static const char SIG_DELETE_REQUEST[] = "delete,request"; static const char SIG_FOCUS_OUT[] = "focus,out"; // deprecated. use "unfocused" instead. static const char SIG_FOCUS_IN[] = "focus,in"; // deprecated. use "focused" instead. @@ -1678,7 +1690,7 @@ _evas_event_key_cb(void *data, const Efl_Event *ev) if (evas_focus_get(evas_object_evas_get(win)) == win) return; - efl_event_callback_legacy_call(win, ev->desc, evt); + efl_event_callback_call(win, ev->desc, evt); } static void @@ -1692,7 +1704,7 @@ _evas_event_pointer_cb(void *data, const Efl_Event *ev) if (!evdata || evdata->win_fed) return; - efl_event_callback_legacy_call(win, ev->desc, evt); + efl_event_callback_call(win, ev->desc, evt); } /* feed events from the window to evas - for fake inputs */ @@ -1711,7 +1723,7 @@ _evas_event_key_feed_fake_cb(void *data, const Efl_Event *ev) return; evdata->win_fed = EINA_TRUE; - efl_event_callback_legacy_call(evas, ev->desc, evt); + efl_event_callback_call(evas, ev->desc, evt); evdata->win_fed = EINA_FALSE; evdata->evas_done = EINA_FALSE; } @@ -1731,7 +1743,7 @@ _evas_event_pointer_feed_fake_cb(void *data, const Efl_Event *ev) return; evdata->win_fed = EINA_TRUE; - efl_event_callback_legacy_call(evas, ev->desc, evt); + efl_event_callback_call(evas, ev->desc, evt); evdata->win_fed = EINA_FALSE; evdata->evas_done = EINA_FALSE; } @@ -1744,6 +1756,9 @@ EFL_CALLBACKS_ARRAY_DEFINE(_elm_win_evas_feed_fake_callbacks, { EFL_EVENT_POINTER_OUT, _evas_event_pointer_feed_fake_cb }, { EFL_EVENT_POINTER_CANCEL, _evas_event_pointer_feed_fake_cb }, { EFL_EVENT_POINTER_WHEEL, _evas_event_pointer_feed_fake_cb }, +{ EFL_EVENT_FINGER_MOVE, _evas_event_pointer_feed_fake_cb }, +{ EFL_EVENT_FINGER_DOWN, _evas_event_pointer_feed_fake_cb }, +{ EFL_EVENT_FINGER_UP, _evas_event_pointer_feed_fake_cb }, { EFL_EVENT_KEY_DOWN, _evas_event_key_feed_fake_cb }, { EFL_EVENT_KEY_UP, _evas_event_key_feed_fake_cb }) @@ -1841,97 +1856,115 @@ _win_event_add_cb(void *data, const Efl_Event *ev) for (i = 0; array[i].desc; i++) { - if (ev->info == EFL_EVENT_POINTER_MOVE) + if (array[i].desc == EFL_EVENT_POINTER_MOVE) { if (!(sd->event_forward.pointer_move++)) efl_event_callback_add(sd->evas, array[i].desc, _evas_event_pointer_cb, win); } - else if (ev->info == EFL_EVENT_POINTER_DOWN) + else if (array[i].desc == EFL_EVENT_POINTER_DOWN) { if (!(sd->event_forward.pointer_down++)) efl_event_callback_add(sd->evas, array[i].desc, _evas_event_pointer_cb, win); } - else if (ev->info == EFL_EVENT_POINTER_UP) + else if (array[i].desc == EFL_EVENT_POINTER_UP) { if (!(sd->event_forward.pointer_up++)) efl_event_callback_add(sd->evas, array[i].desc, _evas_event_pointer_cb, win); } - else if (ev->info == EFL_EVENT_POINTER_IN) + else if (array[i].desc == EFL_EVENT_POINTER_IN) { if (!(sd->event_forward.pointer_in++)) efl_event_callback_add(sd->evas, array[i].desc, _evas_event_pointer_cb, win); } - else if (ev->info == EFL_EVENT_POINTER_OUT) + else if (array[i].desc == EFL_EVENT_POINTER_OUT) { if (!(sd->event_forward.pointer_out++)) efl_event_callback_add(sd->evas, array[i].desc, _evas_event_pointer_cb, win); } - else if (ev->info == EFL_EVENT_POINTER_CANCEL) + else if (array[i].desc == EFL_EVENT_POINTER_CANCEL) { if (!(sd->event_forward.pointer_cancel++)) efl_event_callback_add(sd->evas, array[i].desc, _evas_event_pointer_cb, win); } - else if (ev->info == EFL_EVENT_POINTER_WHEEL) + else if (array[i].desc == EFL_EVENT_POINTER_WHEEL) { if (!(sd->event_forward.pointer_wheel++)) efl_event_callback_add(sd->evas, array[i].desc, _evas_event_pointer_cb, win); } - else if (ev->info == EFL_EVENT_KEY_DOWN) + else if (array[i].desc == EFL_EVENT_FINGER_MOVE) + { + if (!(sd->event_forward.finger_move++)) + efl_event_callback_add(sd->evas, array[i].desc, + _evas_event_pointer_cb, win); + } + else if (array[i].desc == EFL_EVENT_FINGER_DOWN) + { + if (!(sd->event_forward.finger_down++)) + efl_event_callback_add(sd->evas, array[i].desc, + _evas_event_pointer_cb, win); + } + else if (array[i].desc == EFL_EVENT_FINGER_UP) + { + if (!(sd->event_forward.finger_up++)) + efl_event_callback_add(sd->evas, array[i].desc, + _evas_event_pointer_cb, win); + } + else if (array[i].desc == EFL_EVENT_KEY_DOWN) { if (!(sd->event_forward.key_down++)) efl_event_callback_add(sd->evas, array[i].desc, _evas_event_key_cb, win); } - else if (ev->info == EFL_EVENT_KEY_UP) + else if (array[i].desc == EFL_EVENT_KEY_UP) { if (!(sd->event_forward.key_up++)) efl_event_callback_add(sd->evas, array[i].desc, _evas_event_key_cb, win); } - else if (ev->info == EFL_CANVAS_EVENT_RENDER_POST) + else if (array[i].desc == EFL_CANVAS_EVENT_RENDER_POST) { if (!(sd->event_forward.render_post++)) evas_object_event_callback_add(sd->evas, EVAS_CALLBACK_RENDER_POST, _elm_win_evas_render_post, win); } - else if (ev->info == EFL_CANVAS_EVENT_RENDER_PRE) + else if (array[i].desc == EFL_CANVAS_EVENT_RENDER_PRE) { if (!(sd->event_forward.render_pre++)) evas_object_event_callback_add(sd->evas, EVAS_CALLBACK_RENDER_PRE, _elm_win_evas_render_pre, win); } - else if (ev->info == EFL_CANVAS_EVENT_FOCUS_IN) + else if (array[i].desc == EFL_CANVAS_EVENT_FOCUS_IN) { if (!(sd->event_forward.focus_in++)) evas_object_event_callback_add(sd->evas, EVAS_CALLBACK_FOCUS_IN, _elm_win_evas_focus_in, win); } - else if (ev->info == EFL_CANVAS_EVENT_FOCUS_OUT) + else if (array[i].desc == EFL_CANVAS_EVENT_FOCUS_OUT) { if (!(sd->event_forward.focus_out++)) evas_object_event_callback_add(sd->evas, EVAS_CALLBACK_FOCUS_OUT, _elm_win_evas_focus_out, win); } - else if (ev->info == EFL_CANVAS_EVENT_OBJECT_FOCUS_IN) + else if (array[i].desc == EFL_CANVAS_EVENT_OBJECT_FOCUS_IN) { if (!(sd->event_forward.object_focus_in++)) evas_object_event_callback_add(sd->evas, EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_IN, _elm_win_evas_object_focus_in, win); } - else if (ev->info == EFL_CANVAS_EVENT_OBJECT_FOCUS_OUT) + else if (array[i].desc == EFL_CANVAS_EVENT_OBJECT_FOCUS_OUT) { if (!(sd->event_forward.object_focus_out++)) evas_object_event_callback_add(sd->evas, EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_OUT, _elm_win_evas_object_focus_out, win); } - else if (ev->info == EFL_CANVAS_EVENT_DEVICE_CHANGED) + else if (array[i].desc == EFL_CANVAS_EVENT_DEVICE_CHANGED) { if (!(sd->event_forward.device_changed++)) evas_object_event_callback_add(sd->evas, EVAS_CALLBACK_DEVICE_CHANGED, @@ -1950,97 +1983,115 @@ _win_event_del_cb(void *data, const Efl_Event *ev) for (i = 0; array[i].desc; i++) { - if (ev->info == EFL_EVENT_POINTER_MOVE) + if (array[i].desc == EFL_EVENT_POINTER_MOVE) { if (!(--sd->event_forward.pointer_move)) efl_event_callback_add(sd->evas, array[i].desc, _evas_event_pointer_cb, win); } - else if (ev->info == EFL_EVENT_POINTER_DOWN) + else if (array[i].desc == EFL_EVENT_POINTER_DOWN) { if (!(--sd->event_forward.pointer_down)) efl_event_callback_add(sd->evas, array[i].desc, _evas_event_pointer_cb, win); } - else if (ev->info == EFL_EVENT_POINTER_UP) + else if (array[i].desc == EFL_EVENT_POINTER_UP) { if (!(--sd->event_forward.pointer_up)) efl_event_callback_add(sd->evas, array[i].desc, _evas_event_pointer_cb, win); } - else if (ev->info == EFL_EVENT_POINTER_IN) + else if (array[i].desc == EFL_EVENT_POINTER_IN) { if (!(--sd->event_forward.pointer_in)) efl_event_callback_add(sd->evas, array[i].desc, _evas_event_pointer_cb, win); } - else if (ev->info == EFL_EVENT_POINTER_OUT) + else if (array[i].desc == EFL_EVENT_POINTER_OUT) { if (!(--sd->event_forward.pointer_out)) efl_event_callback_add(sd->evas, array[i].desc, _evas_event_pointer_cb, win); } - else if (ev->info == EFL_EVENT_POINTER_CANCEL) + else if (array[i].desc == EFL_EVENT_POINTER_CANCEL) { if (!(--sd->event_forward.pointer_cancel)) efl_event_callback_add(sd->evas, array[i].desc, _evas_event_pointer_cb, win); } - else if (ev->info == EFL_EVENT_POINTER_WHEEL) + else if (array[i].desc == EFL_EVENT_POINTER_WHEEL) { if (!(--sd->event_forward.pointer_wheel)) efl_event_callback_add(sd->evas, array[i].desc, _evas_event_pointer_cb, win); } - else if (ev->info == EFL_EVENT_KEY_DOWN) + else if (array[i].desc == EFL_EVENT_FINGER_MOVE) + { + if (!(--sd->event_forward.finger_move)) + efl_event_callback_add(sd->evas, array[i].desc, + _evas_event_pointer_cb, win); + } + else if (array[i].desc == EFL_EVENT_FINGER_DOWN) + { + if (!(--sd->event_forward.finger_down)) + efl_event_callback_add(sd->evas, array[i].desc, + _evas_event_pointer_cb, win); + } + else if (array[i].desc == EFL_EVENT_FINGER_UP) + { + if (!(--sd->event_forward.finger_up)) + efl_event_callback_add(sd->evas, array[i].desc, + _evas_event_pointer_cb, win); + } + else if (array[i].desc == EFL_EVENT_KEY_DOWN) { if (!(--sd->event_forward.key_down)) efl_event_callback_add(sd->evas, array[i].desc, _evas_event_key_cb, win); } - else if (ev->info == EFL_EVENT_KEY_UP) + else if (array[i].desc == EFL_EVENT_KEY_UP) { if (!(--sd->event_forward.key_up)) efl_event_callback_add(sd->evas, array[i].desc, _evas_event_key_cb, win); } - else if (ev->info == EFL_CANVAS_EVENT_RENDER_POST) + else if (array[i].desc == EFL_CANVAS_EVENT_RENDER_POST) { if (!(--sd->event_forward.render_post)) evas_object_event_callback_add(sd->evas, EVAS_CALLBACK_RENDER_POST, _elm_win_evas_render_post, win); } - else if (ev->info == EFL_CANVAS_EVENT_RENDER_PRE) + else if (array[i].desc == EFL_CANVAS_EVENT_RENDER_PRE) { if (!(--sd->event_forward.render_pre)) evas_object_event_callback_add(sd->evas, EVAS_CALLBACK_RENDER_PRE, _elm_win_evas_render_pre, win); } - else if (ev->info == EFL_CANVAS_EVENT_FOCUS_IN) + else if (array[i].desc == EFL_CANVAS_EVENT_FOCUS_IN) { if (!(--sd->event_forward.focus_in)) evas_object_event_callback_add(sd->evas, EVAS_CALLBACK_FOCUS_IN, _elm_win_evas_focus_in, win); } - else if (ev->info == EFL_CANVAS_EVENT_FOCUS_OUT) + else if (array[i].desc == EFL_CANVAS_EVENT_FOCUS_OUT) { if (!(--sd->event_forward.focus_out)) evas_object_event_callback_add(sd->evas, EVAS_CALLBACK_FOCUS_OUT, _elm_win_evas_focus_out, win); } - else if (ev->info == EFL_CANVAS_EVENT_OBJECT_FOCUS_IN) + else if (array[i].desc == EFL_CANVAS_EVENT_OBJECT_FOCUS_IN) { if (!(--sd->event_forward.object_focus_in)) evas_object_event_callback_add(sd->evas, EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_IN, _elm_win_evas_object_focus_in, win); } - else if (ev->info == EFL_CANVAS_EVENT_OBJECT_FOCUS_OUT) + else if (array[i].desc == EFL_CANVAS_EVENT_OBJECT_FOCUS_OUT) { if (!(--sd->event_forward.object_focus_out)) evas_object_event_callback_add(sd->evas, EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_OUT, _elm_win_evas_object_focus_out, win); } - else if (ev->info == EFL_CANVAS_EVENT_DEVICE_CHANGED) + else if (array[i].desc == EFL_CANVAS_EVENT_DEVICE_CHANGED) { if (!(--sd->event_forward.device_changed)) evas_object_event_callback_add(sd->evas, EVAS_CALLBACK_DEVICE_CHANGED, @@ -2157,6 +2208,104 @@ _efl_ui_win_efl_input_interface_pointer_inside_get(Eo *obj EINA_UNUSED, Efl_Ui_W return evas_pointer_inside_get(sd->evas); } +/* multi touch support */ +static Eina_Bool +_input_pointer_iterator_next(Input_Pointer_Iterator *it, void **data) +{ + Eo *sub; + + if (!eina_iterator_next(it->real_iterator, (void **) &sub)) + return EINA_FALSE; + + if (data) *data = sub; + return EINA_TRUE; +} + +static Eo * +_input_pointer_iterator_get_container(Input_Pointer_Iterator *it) +{ + return (Eo *) it->object; +} + +static void +_input_pointer_iterator_free(Input_Pointer_Iterator *it) +{ + Efl_Input_Pointer *ptr; + + EINA_LIST_FREE(it->list, ptr) + efl_del(ptr); + eina_iterator_free(it->real_iterator); + free(it); +} + +EOLIAN static Eina_Iterator * +_efl_ui_win_efl_input_interface_pointer_iterate(const Eo *obj, Efl_Ui_Win_Data *sd, + Eina_Bool hover EINA_UNUSED) +{ + Input_Pointer_Iterator *it; + Eina_List *list = NULL; + int i, cnt; + + // Note: "hover" is here as a possible extension to this API. At the moment + // I don't have any device that could track the position of hovering fingers + // and Evas also wouldn't track those. + + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, NULL); + + cnt = evas_canvas_touch_point_list_count(sd->evas); + if (!cnt) return NULL; + + it = calloc(1, sizeof(*it)); + if (!it) return NULL; + + EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); + + for (i = 0; i < cnt; i++) + { + Efl_Input_Pointer_Data *ptrdata; + Evas_Touch_Point_State state; + Efl_Input_Pointer *ptr; + double x, y; + + ptr = efl_input_instance_get(EFL_INPUT_POINTER_CLASS, (Eo *) obj, (void **) &ptrdata); + if (!ptrdata) break; + + ptrdata->tool = evas_canvas_touch_point_list_nth_id_get(sd->evas, i); + _efl_input_value_mark(ptrdata, EFL_INPUT_VALUE_TOOL); + + // Note that "still" maps to "down" here. + state = evas_canvas_touch_point_list_nth_state_get(sd->evas, i); + switch (state) + { + case EVAS_TOUCH_POINT_DOWN: ptrdata->action = EFL_POINTER_ACTION_DOWN; break; + case EVAS_TOUCH_POINT_UP: ptrdata->action = EFL_POINTER_ACTION_UP; break; + case EVAS_TOUCH_POINT_MOVE: ptrdata->action = EFL_POINTER_ACTION_MOVE; break; + case EVAS_TOUCH_POINT_STILL: ptrdata->action = EFL_POINTER_ACTION_DOWN; break; + case EVAS_TOUCH_POINT_CANCEL: ptrdata->action = EFL_POINTER_ACTION_CANCEL; break; + default: ptrdata->action = EFL_POINTER_ACTION_NONE; break; + } + + evas_canvas_touch_point_list_nth_xy_get(sd->evas, i, &x, &y); + _efl_input_value_mark(ptrdata, EFL_INPUT_VALUE_X); + _efl_input_value_mark(ptrdata, EFL_INPUT_VALUE_Y); + ptrdata->cur.x = x; + ptrdata->cur.y = y; + ptrdata->prev = ptrdata->cur; + + list = eina_list_append(list, ptr); + } + + it->list = list; + it->real_iterator = eina_list_iterator_new(it->list); + it->iterator.version = EINA_ITERATOR_VERSION; + it->iterator.next = FUNC_ITERATOR_NEXT(_input_pointer_iterator_next); + it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_input_pointer_iterator_get_container); + it->iterator.free = FUNC_ITERATOR_FREE(_input_pointer_iterator_free); + it->object = obj; + + return &it->iterator; +} + EOLIAN static Eina_Bool _efl_ui_win_efl_canvas_image_max_size_get(Eo *obj EINA_UNUSED, Efl_Ui_Win_Data *sd, int *maxw, int *maxh) { diff --git a/src/lib/elementary/efl_ui_win.eo b/src/lib/elementary/efl_ui_win.eo index 425cbfe..4118026 100644 --- a/src/lib/elementary/efl_ui_win.eo +++ b/src/lib/elementary/efl_ui_win.eo @@ -846,6 +846,7 @@ class Efl.Ui.Win (Elm.Widget, Efl.Canvas, Elm.Interface.Atspi.Window, Efl.Text.text.get; Efl.Input.Interface.pointer_xy.get; Efl.Input.Interface.pointer_inside.get; + Efl.Input.Interface.pointer_iterate; Efl.Canvas.image_max_size.get; Efl.Canvas.smart_objects_calculate; Efl.Canvas.objects_at_xy_get; diff --git a/src/lib/evas/canvas/efl_input_interface.eo b/src/lib/evas/canvas/efl_input_interface.eo index 754dd62..64bec13 100644 --- a/src/lib/evas/canvas/efl_input_interface.eo +++ b/src/lib/evas/canvas/efl_input_interface.eo @@ -57,6 +57,28 @@ interface Efl.Input.Interface () return: bool; } } + pointer_iterate @const { + [[Returns an iterator over the current known pointer positions. + + This is used to iterate over the current known multi-touch positions, + including the first finger. Each pointer position is represented by + an object of type @Efl.Input.Pointer. + + Each finger in a multi touch environment can then be identified + by the @Efl.Input.Pointer.tool property. The order of the pointers + in this iterator is not defined. + + Note: If the input surface supports hovering input, some pointers + may not be in a "down" state. To retrieve the list of such pointers, + set the $hover value to $true. Remember though that most devices + currently don't support this. + ]] + params { + hover: bool @optional; [[$false by default, $true means to include + fingers that are currently hovering.]] + } + return: iterator; + } } events { pointer,move: Efl.Input.Pointer; [[Main pointer move (current and previous positions are known).]] diff --git a/src/lib/evas/canvas/efl_input_pointer.c b/src/lib/evas/canvas/efl_input_pointer.c index cd06f7d..cfbb6a0 100644 --- a/src/lib/evas/canvas/efl_input_pointer.c +++ b/src/lib/evas/canvas/efl_input_pointer.c @@ -80,9 +80,10 @@ _efl_input_pointer_class_destructor(Efl_Class *klass EINA_UNUSED) } EOLIAN static Efl_Object * -_efl_input_pointer_efl_object_constructor(Eo *obj, Efl_Input_Pointer_Data *pd EINA_UNUSED) +_efl_input_pointer_efl_object_constructor(Eo *obj, Efl_Input_Pointer_Data *pd) { obj = efl_constructor(efl_super(obj, MY_CLASS)); + pd->fake = 1; efl_input_reset(obj); return obj; } @@ -375,6 +376,16 @@ _efl_input_pointer_value_has_get(Eo *obj EINA_UNUSED, Efl_Input_Pointer_Data *pd { if (!pd || (key <= EFL_INPUT_VALUE_NONE) || (key > EFL_INPUT_VALUE_SLIDER)) return EINA_FALSE; + if (key == EFL_INPUT_VALUE_DX) + { + return _efl_input_value_has(pd, EFL_INPUT_VALUE_X) && + _efl_input_value_has(pd, EFL_INPUT_VALUE_PREVIOUS_X); + } + if (key == EFL_INPUT_VALUE_DY) + { + return _efl_input_value_has(pd, EFL_INPUT_VALUE_Y) && + _efl_input_value_has(pd, EFL_INPUT_VALUE_PREVIOUS_Y); + } return _efl_input_value_has(pd, key); } diff --git a/src/lib/evas/canvas/evas_canvas.eo b/src/lib/evas/canvas/evas_canvas.eo index a9a76dd..b1104b3 100644 --- a/src/lib/evas/canvas/evas_canvas.eo +++ b/src/lib/evas/canvas/evas_canvas.eo @@ -597,16 +597,6 @@ class Evas.Canvas (Efl.Object, Efl.Canvas, Efl.Animator, Efl.Input.Interface) evas and point is removed whenever removing touched point from the evas. ]] - /* FIXME-doc - Example: - @code - extern Evas *evas; - int count; - - count = evas_touch_point_list_count(evas); - printf("The count of touch points: %i\n", count); - @endcode - */ return: uint; [[The number of touched point on the evas.]] } nochange_pop { @@ -753,19 +743,6 @@ class Evas.Canvas (Efl.Object, Efl.Canvas, Efl.Animator, Efl.Input.Interface) which comes from Multi Event has $id that is same as Multi Event's device id. ]] - /* FIXME-doc - Example: - @code - extern Evas *evas; - int id; - - if (evas_touch_point_list_count(evas)) - { - id = evas_touch_point_nth_id_get(evas, 0); - printf("The first touch point's id: %i\n", id); - } - @endcode - */ return: int; [[id of nth touch point, if the call succeeded, -1 otherwise.]] params { @in n: uint; [[The number of the touched point (0 being the first).]] @@ -786,24 +763,13 @@ class Evas.Canvas (Efl.Object, Efl.Canvas, Efl.Animator, Efl.Input.Interface) Touch point's coordinates is updated whenever moving that point on the canvas. ]] - /* FIXME-doc - Example: - @code - extern Evas *evas; - Evas_Coord x, y; - - if (evas_touch_point_list_count(evas)) - { - evas_touch_point_nth_xy_get(evas, 0, &x, &y); - printf("The first touch point's coordinate: (%i, %i)\n", x, y); - } - @endcode - */ params { @in n: uint; [[The number of the touched point (0 being the first).]] - @out x: Evas.Coord; [[The pointer to a Evas_Coord to be filled in.]] - @out y: Evas.Coord; [[The pointer to a Evas_Coord to be filled in.]] + @out x: double; [[Last known X position in window coordinates]] + @out y: double; [[Last known Y position in window coordinates]] } + /* Legacy uses int. */ + legacy: null; } key_lock_del { [[Removes the $keyname key from the current list of lock keys on @@ -945,19 +911,6 @@ class Evas.Canvas (Efl.Object, Efl.Canvas, Efl.Animator, Efl.Input.Interface) EVAS_TOUCH_POINT_MOVE when moved at least once after pressed and EVAS_TOUCH_POINT_UP when released. ]] - /* FIXME-doc - Example: - @code - extern Evas *evas; - Evas_Touch_Point_State state; - - if (evas_touch_point_list_count(evas)) - { - state = evas_touch_point_nth_state_get(evas, 0); - printf("The first touch point's state: %i\n", state); - } - @endcode - */ return: Evas.Touch_Point_State; [[ $state of nth touch point, if the call succeeded, EVAS_TOUCH_POINT_CANCEL otherwise. diff --git a/src/lib/evas/canvas/evas_events.c b/src/lib/evas/canvas/evas_events.c index 71655a9..cd79d7e 100644 --- a/src/lib/evas/canvas/evas_events.c +++ b/src/lib/evas/canvas/evas_events.c @@ -1590,6 +1590,7 @@ _canvas_event_feed_mouse_cancel_internal(Evas_Public_Data *e, Efl_Input_Pointer_ ev->tool = point->id; ev->cur.x = point->x; ev->cur.y = point->y; + ev->prev = ev->cur; _canvas_event_feed_multi_up_internal(e, ev); } } @@ -3459,6 +3460,9 @@ EFL_CALLBACKS_ARRAY_DEFINE(_evas_canvas_event_pointer_callbacks, { EFL_EVENT_POINTER_CANCEL, _evas_canvas_event_pointer_cb }, { EFL_EVENT_POINTER_WHEEL, _evas_canvas_event_pointer_cb }, { EFL_EVENT_POINTER_AXIS, _evas_canvas_event_pointer_cb }, +{ EFL_EVENT_FINGER_MOVE, _evas_canvas_event_pointer_cb }, +{ EFL_EVENT_FINGER_DOWN, _evas_canvas_event_pointer_cb }, +{ EFL_EVENT_FINGER_UP, _evas_canvas_event_pointer_cb }, { EFL_EVENT_KEY_DOWN, _evas_canvas_event_key_cb }, { EFL_EVENT_KEY_UP, _evas_canvas_event_key_cb }) diff --git a/src/lib/evas/canvas/evas_touch_point.c b/src/lib/evas/canvas/evas_touch_point.c index a03ad9c..8d05753 100644 --- a/src/lib/evas/canvas/evas_touch_point.c +++ b/src/lib/evas/canvas/evas_touch_point.c @@ -60,7 +60,8 @@ _evas_canvas_touch_point_list_count(Eo *eo_e EINA_UNUSED, Evas_Public_Data *e) } EOLIAN void -_evas_canvas_touch_point_list_nth_xy_get(Eo *eo_e EINA_UNUSED, Evas_Public_Data *e, unsigned int n, Evas_Coord *x, Evas_Coord *y) +_evas_canvas_touch_point_list_nth_xy_get(Eo *eo_e EINA_UNUSED, Evas_Public_Data *e, + unsigned int n, double *x, double *y) { Evas_Coord_Touch_Point *point = NULL; @@ -75,6 +76,16 @@ _evas_canvas_touch_point_list_nth_xy_get(Eo *eo_e EINA_UNUSED, Evas_Public_Data if (y) *y = point->y; } +EAPI void +evas_touch_point_list_nth_xy_get(Evas_Canvas *obj, unsigned int n, Evas_Coord *x, Evas_Coord *y) +{ + double X = 0, Y = 0; + + evas_canvas_touch_point_list_nth_xy_get(obj, n, &X, &Y); + if (x) *x = X; + if (y) *y = Y; +} + EOLIAN int _evas_canvas_touch_point_list_nth_id_get(Eo *eo_e EINA_UNUSED, Evas_Public_Data *e, unsigned int n) { diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h index 0e09c99..845c7c4 100644 --- a/src/lib/evas/include/evas_private.h +++ b/src/lib/evas/include/evas_private.h @@ -646,7 +646,7 @@ MAGIC_CHECK_FAILED(o, t, m) struct _Evas_Coord_Touch_Point { - Evas_Coord x, y; // point's x, y position + double x, y; int id; // id in order to distinguish each point Evas_Touch_Point_State state; }; @@ -1768,11 +1768,6 @@ void _canvas_render_dump(Eo *obj, void *_pd, va_list *list); void _canvas_object_bottom_get(Eo *e, void *_pd, va_list *list); void _canvas_object_top_get(Eo *e, void *_pd, va_list *list); -void _canvas_touch_point_list_count(Eo *obj, void *_pd, va_list *list); -void _canvas_touch_point_list_nth_xy_get(Eo *obj, void *_pd, va_list *list); -void _canvas_touch_point_list_nth_id_get(Eo *obj, void *_pd, va_list *list); -void _canvas_touch_point_list_nth_state_get(Eo *obj, void *_pd, va_list *list); - void _canvas_image_cache_flush(Eo *e, void *_pd, va_list *list); void _canvas_image_cache_reload(Eo *e, void *_pd, va_list *list); void _canvas_image_cache_set(Eo *e, void *_pd, va_list *list); diff --git a/src/tests/elementary/elm_test_win.c b/src/tests/elementary/elm_test_win.c index d315463..49cc6db 100644 --- a/src/tests/elementary/elm_test_win.c +++ b/src/tests/elementary/elm_test_win.c @@ -12,6 +12,7 @@ static const double _timeout1 = 0.1; static const double _timeout2 = 0.2; +static const double _timeout3 = 0.3; static const double _timeout_fail = 2.0; static void @@ -193,12 +194,209 @@ START_TEST (elm_win_autohide_and_policy_quit_last_window_hidden) } END_TEST +/* a very lax definition of == for doubles */ +#define VALEQ(a, b) ((fabs((a) - (b))) <= 0.001) + +typedef struct +{ + double x, y; +} point_t; + +static point_t points[2][4] = +{ + { + { 20, 20 }, + { 40, 10 }, + { 60, 120 }, + { 80, 80 } + }, + { + { 30, 30 }, + { 50, 50 }, + { 70, 60 }, + { 80, 80 } + }, +}; + +static Eina_Bool +_inputs_timer1_cb(void *data) +{ + Efl_Input_Pointer *ptr; + Eo *win = data; + + /* Send down events first (note: stupid, all at once) */ + for (size_t i = 0; i < 4; i++) + { + ptr = efl_add(EFL_INPUT_POINTER_CLASS, win); + efl_input_pointer_position_set(ptr, points[0][i].x, points[0][i].y); + efl_input_pointer_tool_set(ptr, i); + efl_input_pointer_button_set(ptr, 1); + + if (i == 0) + { + /* in first */ + efl_input_pointer_action_set(ptr, EFL_POINTER_ACTION_IN); + efl_event_callback_call(win, EFL_EVENT_POINTER_IN, ptr); + + /* move second */ + efl_input_pointer_position_set(ptr, points[0][i].x, points[0][i].y); + efl_input_pointer_action_set(ptr, EFL_POINTER_ACTION_MOVE); + efl_event_callback_call(win, EFL_EVENT_POINTER_MOVE, ptr); + } + + /* down finally */ + efl_input_pointer_action_set(ptr, EFL_POINTER_ACTION_DOWN); + efl_event_callback_call(win, EFL_EVENT_POINTER_DOWN, ptr); + } + + return ECORE_CALLBACK_DONE; +} + +static Eina_Bool +_inputs_timer2_cb(void *data) +{ + Efl_Input_Pointer *ptr; + Eina_Iterator *it; + Eo *win = data; + size_t i = 0, cnt = 0; + + it = efl_input_pointer_iterate(win, 0); + EINA_ITERATOR_FOREACH(it, ptr) + { + double x, y; + int tool, ok = 0; + + fail_if(!efl_input_pointer_value_has_get(ptr, EFL_INPUT_VALUE_X)); + fail_if(!efl_input_pointer_value_has_get(ptr, EFL_INPUT_VALUE_Y)); + fail_if(!efl_input_pointer_value_has_get(ptr, EFL_INPUT_VALUE_TOOL)); + fail_if(efl_input_pointer_action_get(ptr) != EFL_POINTER_ACTION_DOWN); + + x = efl_input_pointer_value_get(ptr, EFL_INPUT_VALUE_X); + y = efl_input_pointer_value_get(ptr, EFL_INPUT_VALUE_Y); + tool = efl_input_pointer_tool_get(ptr); + + for (i = 0; i < 4; i++) + if (tool == i) + { + fail_if(!VALEQ(x, points[0][i].x)); + fail_if(!VALEQ(y, points[0][i].y)); + ok = 1; + break; + } + fail_if(!ok); + + cnt++; + } + eina_iterator_free(it); + fail_if(cnt != 4); + + /* Send some moves */ + for (i = 0; i < 4; i++) + { + ptr = efl_add(EFL_INPUT_POINTER_CLASS, win); + efl_input_pointer_position_set(ptr, points[1][i].x, points[1][i].y); + efl_input_pointer_tool_set(ptr, i); + efl_input_pointer_button_set(ptr, 1); + + /* move first */ + efl_input_pointer_action_set(ptr, EFL_POINTER_ACTION_MOVE); + efl_event_callback_call(win, EFL_EVENT_POINTER_MOVE, ptr); + + /* then up (one 2 fingers up: #1 and #3) */ + if ((i % 2) == 1) + { + efl_input_pointer_action_set(ptr, EFL_POINTER_ACTION_UP); + efl_event_callback_call(win, EFL_EVENT_POINTER_UP, ptr); + } + } + + return ECORE_CALLBACK_DONE; +} + +static Eina_Bool +_inputs_timer3_cb(void *data) +{ + Efl_Input_Pointer *ptr; + Eina_Iterator *it; + Eo *win = data; + size_t i = 0, cnt = 0; + + it = efl_input_pointer_iterate(win, 0); + EINA_ITERATOR_FOREACH(it, ptr) + { + int tool, ok = 0; + double x, y; + + fail_if(!efl_input_pointer_value_has_get(ptr, EFL_INPUT_VALUE_X)); + fail_if(!efl_input_pointer_value_has_get(ptr, EFL_INPUT_VALUE_Y)); + fail_if(!efl_input_pointer_value_has_get(ptr, EFL_INPUT_VALUE_TOOL)); + fail_if(efl_input_pointer_action_get(ptr) != EFL_POINTER_ACTION_MOVE); + + x = efl_input_pointer_value_get(ptr, EFL_INPUT_VALUE_X); + y = efl_input_pointer_value_get(ptr, EFL_INPUT_VALUE_Y); + tool = efl_input_pointer_tool_get(ptr); + + for (i = 0; i < 4; i++) + if (tool == i) + { + fail_if(!VALEQ(x, points[1][i].x)); + fail_if(!VALEQ(y, points[1][i].y)); + ok = 1; + break; + } + fail_if(!ok); + + cnt++; + } + eina_iterator_free(it); + fail_if(cnt != 2); // 2 moves (in the list), 2 ups (gone) + + elm_exit(); + + return ECORE_CALLBACK_DONE; +} + +START_TEST (efl_ui_win_multi_touch_inputs) +{ + Eina_Bool fail_flag = EINA_FALSE; + Eo *win; + + /* this tests only multi touch inputs - a lot of code but quite basic + * faking events is quite hard, as an exact sequence must be followed: + * + * pointer 0: in, move, down, move, move, ... + * pointer x: down, move, move, ... + */ + + elm_init(0, NULL); + + elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); + + win = elm_win_add(NULL, "win", ELM_WIN_BASIC); + elm_win_autohide_set(win, EINA_TRUE); + efl_gfx_visible_set(win, EINA_TRUE); + efl_gfx_size_set(win, 100, 100); + + ecore_timer_add(_timeout1, _inputs_timer1_cb, win); + ecore_timer_add(_timeout2, _inputs_timer2_cb, win); + ecore_timer_add(_timeout3, _inputs_timer3_cb, win); + ecore_timer_add(_timeout_fail, _timer_fail_flag_cb, &fail_flag); + + elm_run(); + + fail_if(fail_flag != EINA_FALSE); + + elm_shutdown(); +} +END_TEST + void elm_test_win(TCase *tc) { tcase_add_test(tc, elm_atspi_role_get); tcase_add_test(tc, elm_atspi_component_position); tcase_add_test(tc, elm_atspi_component_size); tcase_add_test(tc, elm_win_policy_quit_last_window_hidden); + tcase_add_test(tc, efl_ui_win_multi_touch_inputs); #ifdef HAVE_ELEMENTARY_X tcase_add_test(tc, elm_win_autohide); tcase_add_test(tc, elm_win_autohide_and_policy_quit_last_window_hidden); -- 2.7.4