nitpicker: provide user activity in focus reports

This patch supplements the existing focus reports with the new attribute
'active', which indicates recent user activity when set to "yes". This
information is consumed by the clipboard to dynamically adjust its
information-flow policy depending on the user activity.

Issue #1712
This commit is contained in:
Norman Feske 2015-09-24 14:48:08 +02:00 committed by Christian Helmuth
parent 59014a50f1
commit 1460105f71
3 changed files with 75 additions and 12 deletions

View File

@ -62,14 +62,23 @@ static Input::Event merge_motion_events(Input::Event const *ev, unsigned n)
}
static void import_input_events(Input::Event *ev_buf, unsigned num_ev,
/**
* Feed input event to the user state
*
* \return true if user has been active. A user is active as long as at
* least one key/button is pressed (during drag operations)
* and when a key/button changes it state.
*/
static bool import_input_events(Input::Event *ev_buf, unsigned num_ev,
User_state &user_state)
{
bool user_is_active = false;
if (num_ev > 0) {
/*
* Take events from input event buffer, merge consecutive motion
* events, and pass result to the user state.
*/
* Take events from input event buffer, merge consecutive motion
* events, and pass result to the user state.
*/
for (unsigned src_ev_cnt = 0; src_ev_cnt < num_ev; src_ev_cnt++) {
Input::Event *e = &ev_buf[src_ev_cnt];
@ -84,13 +93,20 @@ static void import_input_events(Input::Event *ev_buf, unsigned num_ev,
}
/*
* If subsequential relative motion events are merged to
* a zero-motion event, drop it. Otherwise, it would be
* misinterpreted as absolute event pointing to (0, 0).
*/
* If subsequential relative motion events are merged to
* a zero-motion event, drop it. Otherwise, it would be
* misinterpreted as absolute event pointing to (0, 0).
*/
if (e->is_relative_motion() && curr.rx() == 0 && curr.ry() == 0)
continue;
/*
* If we detect a pressed key sometime during the event processing,
* we regard the user as active. This check captures the presence
* of press-release combinations within one batch of input events.
*/
user_is_active |= user_state.key_is_pressed();
/* pass event to user state */
user_state.handle_event(curr);
}
@ -102,6 +118,13 @@ static void import_input_events(Input::Event *ev_buf, unsigned num_ev,
*/
user_state.handle_event(Input::Event());
}
/*
* If at least one key is kept pressed, we regard the user as active.
*/
user_is_active |= user_state.key_is_pressed();
return user_is_active;
}
#endif /* _INPUT_H_ */

View File

@ -76,7 +76,8 @@ Framebuffer::Session *tmp_fb;
** Utilities **
***************/
static void report_session(Genode::Reporter &reporter, Session *session)
static void report_session(Genode::Reporter &reporter, Session *session,
bool active = false)
{
if (!reporter.is_enabled())
return;
@ -92,6 +93,8 @@ static void report_session(Genode::Reporter &reporter, Session *session)
Genode::snprintf(buf, sizeof(buf), "#%02x%02x%02x",
color.r, color.g, color.b);
xml.attribute("color", buf);
if (active) xml.attribute("active", "yes");
}
});
}
@ -1194,6 +1197,30 @@ struct Nitpicker::Main
*/
Timer::Connection timer;
/**
* Counter that is incremented periodically
*/
unsigned period_cnt = 0;
/**
* Period counter when the user was active the last time
*/
unsigned last_active_period = 0;
/**
* Number of periods after the last user activity when we regard the user
* as becoming inactive
*/
unsigned activity_threshold = 50;
/**
* True if the user was recently active
*
* This state is reported as part of focus reports to allow the clipboard
* to dynamically adjust its information-flow policy to the user activity.
*/
bool user_active = false;
/**
* Perform redraw and flush pixels to the framebuffer
*/
@ -1225,6 +1252,8 @@ struct Nitpicker::Main
void Nitpicker::Main::handle_input(unsigned)
{
period_cnt++;
/*
* If kill mode is already active, we got recursively called from
* within this 'input_func' (via 'wait_and_dispatch_one_signal').
@ -1240,9 +1269,13 @@ void Nitpicker::Main::handle_input(unsigned)
::Session * const old_focused_session = user_state.Mode::focused_session();
bool const old_kill_mode = user_state.kill();
bool const old_xray_mode = user_state.xray();
bool const old_user_active = user_active;
/* handle batch of pending events */
import_input_events(ev_buf, input.flush(), user_state);
if (import_input_events(ev_buf, input.flush(), user_state)) {
last_active_period = period_cnt;
user_active = true;
}
Point const new_pointer_pos = user_state.pointer_pos();
::Session * const new_pointed_session = user_state.pointed_session();
@ -1250,6 +1283,10 @@ void Nitpicker::Main::handle_input(unsigned)
bool const new_kill_mode = user_state.kill();
bool const new_xray_mode = user_state.xray();
/* flag user as inactive after activity threshold is reached */
if (period_cnt == last_active_period + activity_threshold)
user_active = false;
/* report mouse-position updates */
if (pointer_reporter.is_enabled() && old_pointer_pos != new_pointer_pos) {
@ -1273,8 +1310,9 @@ void Nitpicker::Main::handle_input(unsigned)
report_session(hover_reporter, new_pointed_session);
/* report focus changes */
if (old_focused_session != new_focused_session)
report_session(focus_reporter, new_focused_session);
if (old_focused_session != new_focused_session
|| old_user_active != user_active)
report_session(focus_reporter, new_focused_session, user_active);
/* report kill mode */
if (old_kill_mode != new_kill_mode) {

View File

@ -53,6 +53,8 @@ class Mode
bool has_key_cnt(unsigned cnt) const { return cnt == _key_cnt; }
bool key_is_pressed() const { return _key_cnt > 0; }
Session *focused_session() { return _focused_session; }
Session const *focused_session() const { return _focused_session; }