Ecore_input: Add "ECORE_EVENT_MOUSE_BUTTON_CANCEL" event

If ecore get the mouse cancel event(ex: display off, or window stack change) from below, we need to deal with.
Currently, evas also generates up event using evas_event_feed_mouse_cancel function when window hide is called.
if cancel event occurs, ecore also call evas_event_mouse_feed_cancel like window hide situation.
cancel event means all button or touch event should be canceled, but in the future, if we need to deal each cancel event according to touch point,
we need to add api like evas_event_feed_multi_cancel

@feature
This commit is contained in:
Ji-Youn Park 2015-06-16 15:33:43 +09:00
parent 0ee9a4ac63
commit 5cb6cdbc5e
6 changed files with 205 additions and 47 deletions

View File

@ -54,6 +54,7 @@ extern "C" {
EAPI extern int ECORE_EVENT_MOUSE_IN;
EAPI extern int ECORE_EVENT_MOUSE_OUT;
EAPI extern int ECORE_EVENT_AXIS_UPDATE; /**< @since 1.13 */
EAPI extern int ECORE_EVENT_MOUSE_BUTTON_CANCEL; /**< @since 1.19 */
#define ECORE_EVENT_MODIFIER_SHIFT 0x0001
#define ECORE_EVENT_MODIFIER_CTRL 0x0002
@ -106,7 +107,8 @@ extern "C" {
typedef enum _Ecore_Event_Press
{
ECORE_DOWN,
ECORE_UP
ECORE_UP,
ECORE_CANCEL
} Ecore_Event_Press;
/**

View File

@ -23,6 +23,7 @@ EAPI int ECORE_EVENT_MOUSE_WHEEL = 0;
EAPI int ECORE_EVENT_MOUSE_IN = 0;
EAPI int ECORE_EVENT_MOUSE_OUT = 0;
EAPI int ECORE_EVENT_AXIS_UPDATE = 0;
EAPI int ECORE_EVENT_MOUSE_BUTTON_CANCEL = 0;
static int _ecore_event_init_count = 0;
@ -54,6 +55,7 @@ ecore_event_init(void)
ECORE_EVENT_MOUSE_IN = ecore_event_type_new();
ECORE_EVENT_MOUSE_OUT = ecore_event_type_new();
ECORE_EVENT_AXIS_UPDATE = ecore_event_type_new();
ECORE_EVENT_MOUSE_BUTTON_CANCEL = ecore_event_type_new();
return _ecore_event_init_count;
}
@ -73,6 +75,7 @@ ecore_event_shutdown(void)
ECORE_EVENT_MOUSE_IN = 0;
ECORE_EVENT_MOUSE_OUT = 0;
ECORE_EVENT_AXIS_UPDATE = 0;
ECORE_EVENT_MOUSE_BUTTON_CANCEL = 0;
eina_log_domain_unregister(_ecore_input_log_dom);
_ecore_input_log_dom = -1;
ecore_shutdown();

View File

@ -50,6 +50,7 @@ EAPI Eina_Bool ecore_event_evas_mouse_move(void *data, int type, void *event);
EAPI Eina_Bool ecore_event_evas_mouse_in(void *data, int type, void *event);
EAPI Eina_Bool ecore_event_evas_mouse_out(void *data, int type, void *event);
EAPI Eina_Bool ecore_event_evas_axis_update(void *data, int type, void *event); /**< @since 1.13 */
EAPI Eina_Bool ecore_event_evas_mouse_button_cancel(void *data, int type, void *event); /**< @since 1.19 */
EAPI void ecore_event_window_register(Ecore_Window id, void *window, Evas *evas, Ecore_Event_Mouse_Move_Cb move_mouse, Ecore_Event_Multi_Move_Cb move_multi, Ecore_Event_Multi_Down_Cb down_multi, Ecore_Event_Multi_Up_Cb up_multi);
EAPI void ecore_event_window_unregister(Ecore_Window id);

View File

@ -29,9 +29,16 @@ typedef enum _Ecore_Input_State {
ECORE_INPUT_NONE = 0,
ECORE_INPUT_DOWN,
ECORE_INPUT_MOVE,
ECORE_INPUT_UP
ECORE_INPUT_UP,
ECORE_INPUT_CANCEL
} Ecore_Input_State;
typedef enum _Ecore_Input_Action {
ECORE_INPUT_CONTINUE = 0,
ECORE_INPUT_IGNORE,
ECORE_INPUT_FAKE_UP
} Ecore_Input_Action;
typedef struct _Ecore_Input_Last Ecore_Event_Last;
struct _Ecore_Input_Last
{
@ -46,7 +53,7 @@ struct _Ecore_Input_Last
};
static int _ecore_event_evas_init_count = 0;
static Ecore_Event_Handler *ecore_event_evas_handlers[9];
static Ecore_Event_Handler *ecore_event_evas_handlers[10];
static Eina_Hash *_window_hash = NULL;
static Eina_List *_last_events = NULL;
@ -57,6 +64,59 @@ static Eina_Bool _ecore_event_evas_mouse_button(Ecore_Event_Mouse_Button *e,
Ecore_Event_Press press,
Eina_Bool faked);
static Ecore_Input_Action
_ecore_event_last_check(Ecore_Event_Last *eel, Ecore_Event_Press press)
{
switch (eel->state)
{
case ECORE_INPUT_NONE:
/* 1. ECORE_INPUT_NONE => ECORE_UP : impossible
* 2. ECORE_INPUT_NONE => ECORE_CANCEL : impossible
* 3. ECORE_INPUT_NONE => ECORE_DOWN : ok
*/
return ECORE_INPUT_CONTINUE;
case ECORE_INPUT_DOWN:
/* 1. ECORE_INPUT_DOWN => ECORE_UP : ok
* 2. ECORE_INPUT_DOWN => ECORE_CANCEL : ok
*/
if ((press == ECORE_UP) || (press == ECORE_CANCEL))
return ECORE_INPUT_CONTINUE;
/* 3. ECORE_INPUT_DOWN => ECORE_DOWN : emit a faked UP then */
INF("Down event occurs twice. device(%d), button(%d)", eel->device, eel->buttons);
return ECORE_INPUT_FAKE_UP;
case ECORE_INPUT_MOVE:
/* 1. ECORE_INPUT_MOVE => ECORE_UP : ok
* 2. ECORE_INPUT_MOVE => ECORE_CANCEL : ok
*/
if ((press == ECORE_UP) || (press == ECORE_CANCEL))
return ECORE_INPUT_CONTINUE;
/* 3. ECORE_INPUT_MOVE => ECORE_DOWN : ok
* FIXME: handle fake button up and push for more delay here */
//TODO: How to deal with down event after move event?
INF("Down event occurs after move event. device(%d), button(%d)", eel->device, eel->buttons);
return ECORE_INPUT_FAKE_UP;
case ECORE_INPUT_UP:
case ECORE_INPUT_CANCEL:
/* 1. ECORE_INPUT_UP => ECORE_DOWN : ok */
/* 2. ECORE_INPUT_CANCEL => ECORE_DOWN : ok */
if (press == ECORE_DOWN)
return ECORE_INPUT_CONTINUE;
/* 3. ECORE_INPUT_UP => ECORE_UP : ignore */
/* 4. ECORE_INPUT_UP => ECORE_CANCEL : ignore */
/* 5. ECORE_INPUT_CANCEL => ECORE_UP : ignore */
/* 6. ECORE_INPUT_CANCEL => ECORE_CANCEL : ignore */
INF("Up/cancel event occurs after up/cancel event. device(%d), button(%d)", eel->device, eel->buttons);
return ECORE_INPUT_IGNORE;
}
return ECORE_INPUT_IGNORE;
}
static Ecore_Event_Last *
_ecore_event_evas_lookup(unsigned int device, unsigned int buttons, Eina_Bool create_new)
{
@ -91,6 +151,7 @@ _ecore_event_evas_push_fake(void *data)
{
case ECORE_INPUT_NONE:
case ECORE_INPUT_UP:
case ECORE_INPUT_CANCEL:
/* should not happen */
break;
case ECORE_INPUT_DOWN:
@ -109,48 +170,45 @@ _ecore_event_evas_push_fake(void *data)
return EINA_FALSE;
}
static void
static Eina_Bool
_ecore_event_evas_push_mouse_button(Ecore_Event_Mouse_Button *e, Ecore_Event_Press press)
{
Ecore_Event_Last *eel;
Ecore_Input_Action action;
if (!_last_events_enable) return;
//_ecore_event_evas_mouse_button already check press or cancel without history
eel = _ecore_event_evas_lookup(e->multi.device, e->buttons, EINA_TRUE);
if (!eel) return;
if (!eel) return EINA_FALSE;
INF("dev(%d), button(%d), last_press(%d), press(%d)", e->multi.device, e->buttons, eel->state, press);
switch (eel->state)
action = _ecore_event_last_check(eel, press);
INF("action(%d)", action);
switch (action)
{
case ECORE_INPUT_NONE:
goto fine;
case ECORE_INPUT_DOWN:
if (press == ECORE_UP)
goto fine;
/* press == ECORE_DOWN => emit a faked UP then */
_ecore_event_evas_mouse_button(e, ECORE_UP, EINA_TRUE);
break;
case ECORE_INPUT_MOVE:
if (press == ECORE_UP)
goto fine;
/* FIXME: handle fake button up and push for more delay here */
/* press == ECORE_DOWN */
_ecore_event_evas_mouse_button(e, ECORE_DOWN, EINA_TRUE);
break;
case ECORE_INPUT_UP:
if (press == ECORE_DOWN)
goto fine;
/* press == ECORE_UP */
case ECORE_INPUT_FAKE_UP:
_ecore_event_evas_mouse_button(e, ECORE_UP, EINA_TRUE);
case ECORE_INPUT_CONTINUE:
break;
case ECORE_INPUT_IGNORE:
default:
return EINA_FALSE;
}
fine:
eel->state = (press == ECORE_DOWN) ? ECORE_INPUT_DOWN : ECORE_INPUT_UP;
if (_last_events_timeout)
switch (press)
{
case ECORE_DOWN:
eel->state = ECORE_INPUT_DOWN;
break;
case ECORE_UP:
eel->state = ECORE_INPUT_UP;
break;
default:
break;
}
//if up event not occurs from under layers of ecore
//up event is generated by ecore
if (_last_events_enable && _last_events_timeout)
{
if (eel->timer) ecore_timer_del(eel->timer);
eel->timer = NULL;
@ -158,7 +216,7 @@ _ecore_event_evas_push_mouse_button(Ecore_Event_Mouse_Button *e, Ecore_Event_Pre
{
/* Save the Ecore_Event somehow */
if (!eel->ev) eel->ev = malloc(sizeof (Ecore_Event_Mouse_Button));
if (!eel->ev) return;
if (!eel->ev) return EINA_FALSE;
memcpy(eel->ev, e, sizeof (Ecore_Event_Mouse_Button));
eel->timer = ecore_timer_add(_last_events_timeout, _ecore_event_evas_push_fake, eel);
}
@ -168,6 +226,7 @@ _ecore_event_evas_push_mouse_button(Ecore_Event_Mouse_Button *e, Ecore_Event_Pre
eel->ev = NULL;
}
}
return EINA_TRUE;
}
static void
@ -183,7 +242,8 @@ _ecore_event_evas_push_mouse_move(Ecore_Event_Mouse_Move *e)
{
case ECORE_INPUT_NONE:
case ECORE_INPUT_UP:
/* none or up and moving, sounds fine to me */
case ECORE_INPUT_CANCEL:
/* (none, up, or cancel) => move, sounds fine to me */
break;
case ECORE_INPUT_DOWN:
case ECORE_INPUT_MOVE:
@ -354,6 +414,30 @@ _ecore_event_evas_key(Ecore_Event_Key *e, Ecore_Event_Press press)
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_ecore_event_evas_mouse_button_cancel(Ecore_Event_Mouse_Button *e)
{
Ecore_Input_Window *lookup;
Ecore_Event_Last *eel;
Eina_List *l;
lookup = _ecore_event_window_match(e->event_window);
if (!lookup) return ECORE_CALLBACK_PASS_ON;
INF("ButtonEvent cancel, device(%d), button(%d)", e->multi.device, e->buttons);
evas_event_feed_mouse_cancel(lookup->evas, e->timestamp, NULL);
//the number of last event is small, simple check is ok.
EINA_LIST_FOREACH(_last_events, l, eel)
{
Ecore_Input_Action act = _ecore_event_last_check(eel, ECORE_CANCEL);
INF("ButtonEvent cancel, dev(%d), button(%d), last_press(%d), action(%d)", eel->device, eel->buttons, eel->state, act);
if (act == ECORE_INPUT_CONTINUE) eel->state = ECORE_INPUT_CANCEL;
}
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_ecore_event_evas_mouse_button(Ecore_Event_Mouse_Button *e, Ecore_Event_Press press, Eina_Bool faked)
{
@ -366,21 +450,35 @@ _ecore_event_evas_mouse_button(Ecore_Event_Mouse_Button *e, Ecore_Event_Press pr
if (e->double_click) flags |= EVAS_BUTTON_DOUBLE_CLICK;
if (e->triple_click) flags |= EVAS_BUTTON_TRIPLE_CLICK;
INF("\tButtonEvent:ecore_event_evas press(%d), device(%d), button(%d), fake(%d)", press, e->multi.device, e->buttons, faked);
if (_last_events_enable)
//handle all mouse error from under layers of ecore
//error handle
// 1. ecore up without ecore down
// 2. ecore cancel without ecore down
if (press != ECORE_DOWN)
{
//error handle: if ecore up without ecore down
if (press == ECORE_UP)
//ECORE_UP or ECORE_CANCEL
eel = _ecore_event_evas_lookup(e->multi.device, e->buttons, EINA_FALSE);
if (!eel)
if ((!eel) || (eel->state == ECORE_INPUT_UP) || (eel->state == ECORE_INPUT_CANCEL))
{
eel = _ecore_event_evas_lookup(e->multi.device, e->buttons, EINA_FALSE);
if ((!eel) || (eel->state == ECORE_INPUT_UP))
{
INF("ButtonEvent: up event without down event.");
return ECORE_CALLBACK_PASS_ON;
}
if (!eel)
WRN("ButtonEvent has no history.");
else
WRN("ButtonEvent has wrong history. Last state=%d", eel->state);
return ECORE_CALLBACK_PASS_ON;
}
}
if (!faked) _ecore_event_evas_push_mouse_button(e, press);
if (!faked)
{
Eina_Bool ret = EINA_FALSE;
ret = _ecore_event_evas_push_mouse_button(e, press);
/* This ButtonEvent is worng */
if (!ret) return ECORE_CALLBACK_PASS_ON;
}
if (e->multi.device == 0)
{
ecore_event_evas_modifier_lock_update(lookup->evas, e->modifiers);
@ -481,6 +579,12 @@ ecore_event_evas_mouse_button_up(void *data EINA_UNUSED, int type EINA_UNUSED, v
return _ecore_event_evas_mouse_button((Ecore_Event_Mouse_Button *)event, ECORE_UP, EINA_FALSE);
}
EAPI Eina_Bool
ecore_event_evas_mouse_button_cancel(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
return _ecore_event_evas_mouse_button_cancel((Ecore_Event_Mouse_Button *)event);
}
static Eina_Bool
_ecore_event_evas_mouse_io(Ecore_Event_Mouse_IO *e, Ecore_Event_IO io)
{
@ -609,6 +713,9 @@ ecore_event_evas_init(void)
ecore_event_evas_handlers[8] = ecore_event_handler_add(ECORE_EVENT_AXIS_UPDATE,
ecore_event_evas_axis_update,
NULL);
ecore_event_evas_handlers[9] = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_CANCEL,
ecore_event_evas_mouse_button_cancel,
NULL);
_window_hash = eina_hash_pointer_new(free);

View File

@ -452,6 +452,18 @@ _ecore_mouse_button(int event,
if (down_info)
{
//If mouse cancel event occred, should reset down info related with double & triple click
if (event == ECORE_EVENT_MOUSE_BUTTON_CANCEL)
{
down_info->last_win = 0;
down_info->last_last_win = 0;
down_info->last_event_win = 0;
down_info->last_last_event_win = 0;
down_info->last_time = 0;
down_info->last_last_time = 0;
down_info->did_double = EINA_FALSE;
down_info->did_triple = EINA_FALSE;
}
if ((event == ECORE_EVENT_MOUSE_BUTTON_DOWN) &&
down_info->did_triple)
{
@ -498,7 +510,7 @@ _ecore_mouse_button(int event,
down_info->did_triple = EINA_FALSE;
}
}
else
else if (event == ECORE_EVENT_MOUSE_BUTTON_UP)
{
if (down_info->did_double)
e->double_click = 1;

View File

@ -468,6 +468,36 @@ _ecore_x_input_multi_handler(XEvent *xevent)
_ecore_x_input_touch_index_clear(devid, i);
}
break;
#ifdef XI_TouchCancel
case XI_TouchCancel:
{
XIDeviceEvent *evd = (XIDeviceEvent *)(xevent->xcookie.data);
int devid = evd->deviceid;
int i = _ecore_x_input_touch_index_get(devid, evd->detail, XI_TouchEnd);
/* X maybe send several cancel events, but ecore_x only deals with cancel event of first touch
* But ecore keeps all Xevent info for future */
if ((i != 0) || !(evd->flags & XITouchEmulatingPointer)) return;
INF("ButtonEvent: cancel time=%u x=%d y=%d devid=%d", (unsigned int)evd->time, (int)evd->event_x, (int)evd->event_y, devid);
_ecore_mouse_button(ECORE_EVENT_MOUSE_BUTTON_CANCEL,
evd->time,
0, // state
0, // button
evd->event_x, evd->event_y,
evd->root_x, evd->root_y,
evd->event,
(evd->child ? evd->child : evd->event),
evd->root,
1, // same_screen
i, 1, 1,
1.0, // pressure
0.0, // angle
evd->event_x, evd->event_y,
evd->root_x, evd->root_y);
}
break;
#endif
#endif /* ifdef ECORE_XI2_2 */
default:
break;
@ -791,6 +821,9 @@ _ecore_x_input_touch_devices_grab(Ecore_X_Window grab_win, Eina_Bool grab)
XISetMask(mask, XI_TouchUpdate);
XISetMask(mask, XI_TouchBegin);
XISetMask(mask, XI_TouchEnd);
#ifdef XI_TouchCancel
XISetMask(mask, XI_TouchCancel);
#endif
update = 1;
free(info);
}