diff --git a/repos/os/src/server/nitpicker/README b/repos/os/src/server/nitpicker/README index 95daa9a34..6de5a5896 100644 --- a/repos/os/src/server/nitpicker/README +++ b/repos/os/src/server/nitpicker/README @@ -213,3 +213,4 @@ The 'hover' attribute enables the reporting of the currently hovered session. The 'focus' attribute enables the reporting of the currently focused session. The 'pointer' attribute enables the reporting of the current absolute pointer position. +The 'keystate' attribute enables the reporting of the currently pressed keys. diff --git a/repos/os/src/server/nitpicker/main.cc b/repos/os/src/server/nitpicker/main.cc index b8d8f4041..c00377c18 100644 --- a/repos/os/src/server/nitpicker/main.cc +++ b/repos/os/src/server/nitpicker/main.cc @@ -1179,9 +1179,10 @@ struct Nitpicker::Main */ Genode::Sliced_heap sliced_heap { env.ram(), env.rm() }; - Genode::Reporter pointer_reporter = { env, "pointer" }; - Genode::Reporter hover_reporter = { env, "hover" }; - Genode::Reporter focus_reporter = { env, "focus" }; + Genode::Reporter pointer_reporter = { env, "pointer" }; + Genode::Reporter hover_reporter = { env, "hover" }; + Genode::Reporter focus_reporter = { env, "focus" }; + Genode::Reporter keystate_reporter = { env, "keystate" }; Genode::Attached_rom_dataspace config { env, "config" }; @@ -1273,11 +1274,28 @@ void Nitpicker::Main::handle_input() bool const old_user_active = user_active; /* handle batch of pending events */ - if (import_input_events(ev_buf, input.flush(), user_state)) { + unsigned const num_events = input.flush(); + if (import_input_events(ev_buf, num_events, user_state)) { last_active_period = period_cnt; user_active = true; } + /* + * Report information about currently pressed keys whenever the key state + * is affected by the incoming events. + */ + if (keystate_reporter.enabled()) { + + bool key_state_affected = false; + for (unsigned i = 0; i < num_events; i++) + key_state_affected |= (ev_buf[i].type() == Input::Event::PRESS) || + (ev_buf[i].type() == Input::Event::RELEASE); + + if (key_state_affected) + Genode::Reporter::Xml_generator xml(keystate_reporter, [&] () { + user_state.report_keystate(xml); }); + } + user_state.Mode::apply_pending_focus_change(); Point const new_pointer_pos = user_state.pointer_pos(); @@ -1293,7 +1311,6 @@ void Nitpicker::Main::handle_input() /* report mouse-position updates */ if (pointer_reporter.enabled() && old_pointer_pos != new_pointer_pos) { - Genode::Reporter::Xml_generator xml(pointer_reporter, [&] () { xml.attribute("xpos", new_pointer_pos.x()); @@ -1364,6 +1381,7 @@ void Nitpicker::Main::handle_config() configure_reporter(config.xml(), pointer_reporter); configure_reporter(config.xml(), hover_reporter); configure_reporter(config.xml(), focus_reporter); + configure_reporter(config.xml(), keystate_reporter); /* update domain registry and session policies */ for (::Session *s = session_list.first(); s; s = s->next()) diff --git a/repos/os/src/server/nitpicker/mode.h b/repos/os/src/server/nitpicker/mode.h index 01b8a5b49..141830158 100644 --- a/repos/os/src/server/nitpicker/mode.h +++ b/repos/os/src/server/nitpicker/mode.h @@ -49,7 +49,7 @@ class Mode void inc_key_cnt() { _key_cnt++; } void dec_key_cnt() { _key_cnt--; } - bool has_key_cnt(unsigned cnt) const { return cnt == _key_cnt; } + unsigned key_cnt() const { return _key_cnt; } bool key_pressed() const { return _key_cnt > 0; } diff --git a/repos/os/src/server/nitpicker/user_state.cc b/repos/os/src/server/nitpicker/user_state.cc index d9d0b16df..cbe4c634f 100644 --- a/repos/os/src/server/nitpicker/user_state.cc +++ b/repos/os/src/server/nitpicker/user_state.cc @@ -87,6 +87,19 @@ void User_state::handle_event(Input::Event ev) if (type == Event::PRESS) Mode::inc_key_cnt(); if (type == Event::RELEASE && Mode::drag()) Mode::dec_key_cnt(); + /* track key states */ + if (type == Event::PRESS) { + if (_key_array.pressed(keycode)) + Genode::warning("suspicious double press of ", Input::key_name(keycode)); + _key_array.pressed(keycode, true); + } + + if (type == Event::RELEASE) { + if (!_key_array.pressed(keycode)) + Genode::warning("suspicious double release of ", Input::key_name(keycode)); + _key_array.pressed(keycode, false); + } + View const * const pointed_view = find_view(_pointer_pos); ::Session * const pointed_session = pointed_view ? &pointed_view->session() : 0; @@ -123,7 +136,7 @@ void User_state::handle_event(Input::Event ev) /* * Handle start of a key sequence */ - if (type == Event::PRESS && Mode::has_key_cnt(1)) { + if (type == Event::PRESS && (Mode::key_cnt() == 1)) { ::Session *global_receiver = nullptr; @@ -188,7 +201,7 @@ void User_state::handle_event(Input::Event ev) */ if (type == Event::MOTION || type == Event::WHEEL || type == Event::TOUCH) { - if (Mode::has_key_cnt(0)) { + if (Mode::key_cnt() == 0) { if (_pointed_session) { @@ -232,7 +245,7 @@ void User_state::handle_event(Input::Event ev) /* * Detect end of global key sequence */ - if (ev.type() == Event::RELEASE && Mode::has_key_cnt(0) && _global_key_sequence) { + if (ev.type() == Event::RELEASE && (Mode::key_cnt() == 0) && _global_key_sequence) { _input_receiver = Mode::focused_session(); @@ -243,6 +256,13 @@ void User_state::handle_event(Input::Event ev) } +void User_state::report_keystate(Genode::Xml_generator &xml) +{ + xml.attribute("count", Mode::key_cnt()); + _key_array.report_state(xml); +} + + /******************** ** Mode interface ** ********************/ diff --git a/repos/os/src/server/nitpicker/user_state.h b/repos/os/src/server/nitpicker/user_state.h index cbfbc1a58..4a59edc5c 100644 --- a/repos/os/src/server/nitpicker/user_state.h +++ b/repos/os/src/server/nitpicker/user_state.h @@ -18,6 +18,8 @@ #ifndef _USER_STATE_H_ #define _USER_STATE_H_ +#include + #include "mode.h" #include "view_stack.h" #include "global_keys.h" @@ -48,6 +50,36 @@ class User_state : public Mode, public View_stack void _update_all(); + /** + * Array for tracking the state of each key + */ + struct Key_array + { + struct State { bool pressed = false; }; + + State _states[Input::KEY_MAX + 1]; + + void pressed(Input::Keycode key, bool pressed) + { + if (key <= Input::KEY_MAX) + _states[key].pressed = pressed; + } + + bool pressed(Input::Keycode key) const + { + return (key <= Input::KEY_MAX) && _states[key].pressed; + } + + void report_state(Genode::Xml_generator &xml) const + { + for (unsigned i = 0; i <= Input::KEY_MAX; i++) + if (_states[i].pressed) + xml.node("pressed", [&] () { + xml.attribute("key", Input::key_name((Input::Keycode)i)); }); + } + + } _key_array; + public: /** @@ -63,6 +95,8 @@ class User_state : public Mode, public View_stack */ void handle_event(Input::Event ev); + void report_keystate(Genode::Xml_generator &); + /** * Accessors */