mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-21 12:05:14 +00:00
os: generalize xray trigger component
This commit replaces the old xray_trigger component by a new component called global_keys_handler. For details, please refer to the issue text and the accompanied README file. Fixes #2554
This commit is contained in:
parent
0b4b2b2fb2
commit
27c9e5c6e8
@ -66,9 +66,9 @@ install_config {
|
|||||||
<policy label_prefix="status_bar" domain="panel"/>
|
<policy label_prefix="status_bar" domain="panel"/>
|
||||||
<default-policy domain="default"/>
|
<default-policy domain="default"/>
|
||||||
|
|
||||||
<global-key name="KEY_SCROLLLOCK" label="xray_trigger -> input" />
|
<global-key name="KEY_SCROLLLOCK" label="global_keys_handler -> input" />
|
||||||
<global-key name="KEY_F1" label="xray_trigger -> input" />
|
<global-key name="KEY_F1" label="global_keys_handler -> input" />
|
||||||
<global-key name="KEY_F2" label="xray_trigger -> input" />
|
<global-key name="KEY_F2" label="global_keys_handler -> input" />
|
||||||
<global-key name="KEY_LEFTMETA" label="wm -> launcher" />
|
<global-key name="KEY_LEFTMETA" label="wm -> launcher" />
|
||||||
<global-key name="KEY_F3" label="wm -> launcher" />
|
<global-key name="KEY_F3" label="wm -> launcher" />
|
||||||
</config>
|
</config>
|
||||||
@ -86,14 +86,21 @@ install_config {
|
|||||||
</route>
|
</route>
|
||||||
</start>
|
</start>
|
||||||
|
|
||||||
<start name="xray_trigger">
|
<start name="global_keys_handler">
|
||||||
<resource name="RAM" quantum="1M"/>
|
<resource name="RAM" quantum="1M"/>
|
||||||
<config>
|
<config>
|
||||||
<press name="KEY_F1" xray="on"/>
|
<bool name="xray" initial="no"/>
|
||||||
<release name="KEY_F1" xray="off"/>
|
|
||||||
<press name="KEY_F2" xray="toggle"/>
|
<press name="KEY_SCROLLLOCK" bool="xray" change="toggle"/>
|
||||||
<hover domain="panel"/>
|
<press name="KEY_F1" bool="xray" change="on"/>
|
||||||
<hover domain="decorator"/>
|
<release name="KEY_F1" bool="xray" change="off"/>
|
||||||
|
<press name="KEY_F2" bool="xray" change="toggle"/>
|
||||||
|
|
||||||
|
<report name="xray" delay_ms="125">
|
||||||
|
<hovered domain="panel"/>
|
||||||
|
<hovered domain="decorator"/>
|
||||||
|
<bool name="xray"/>
|
||||||
|
</report>
|
||||||
</config>
|
</config>
|
||||||
<route>
|
<route>
|
||||||
<service name="ROM" label="hover"> <child name="report_rom"/> </service>
|
<service name="ROM" label="hover"> <child name="report_rom"/> </service>
|
||||||
@ -115,7 +122,7 @@ install_config {
|
|||||||
<resource name="RAM" quantum="1M"/>
|
<resource name="RAM" quantum="1M"/>
|
||||||
<provides> <service name="Report"/> <service name="ROM"/> </provides>
|
<provides> <service name="Report"/> <service name="ROM"/> </provides>
|
||||||
<config verbose="no">
|
<config verbose="no">
|
||||||
<policy label="decorator_config -> xray" report="xray_trigger -> xray"/>
|
<policy label="decorator_config -> xray" report="global_keys_handler -> xray"/>
|
||||||
<policy label="layouter -> window_list" report="wm -> window_list"/>
|
<policy label="layouter -> window_list" report="wm -> window_list"/>
|
||||||
<policy label="layouter -> focus_request" report="wm -> focus_request" />
|
<policy label="layouter -> focus_request" report="wm -> focus_request" />
|
||||||
<policy label="decorator -> window_layout" report="layouter -> window_layout"/>
|
<policy label="decorator -> window_layout" report="layouter -> window_layout"/>
|
||||||
@ -125,7 +132,7 @@ install_config {
|
|||||||
<policy label="wm -> focus" report="layouter -> focus"/>
|
<policy label="wm -> focus" report="layouter -> focus"/>
|
||||||
<policy label="status_bar -> focus" report="nitpicker -> focus"/>
|
<policy label="status_bar -> focus" report="nitpicker -> focus"/>
|
||||||
<policy label="launcher -> focus" report="nitpicker -> focus"/>
|
<policy label="launcher -> focus" report="nitpicker -> focus"/>
|
||||||
<policy label="xray_trigger -> hover" report="nitpicker -> hover"/>
|
<policy label="global_keys_handler -> hover" report="nitpicker -> hover"/>
|
||||||
<policy label="layouter -> decorator_margins" report="decorator -> decorator_margins"/>
|
<policy label="layouter -> decorator_margins" report="decorator -> decorator_margins"/>
|
||||||
</config>
|
</config>
|
||||||
</start>
|
</start>
|
||||||
@ -264,9 +271,9 @@ install_config {
|
|||||||
</start>
|
</start>
|
||||||
</config>}
|
</config>}
|
||||||
|
|
||||||
build { app/launcher test/nitpicker app/status_bar app/xray_trigger }
|
build { app/launcher test/nitpicker app/status_bar app/global_keys_handler }
|
||||||
|
|
||||||
build_boot_image { testnit launcher xray_trigger status_bar }
|
build_boot_image { testnit launcher global_keys_handler status_bar }
|
||||||
|
|
||||||
|
|
||||||
run_genode_until forever
|
run_genode_until forever
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
SRC_DIR := src/app/xray_trigger
|
SRC_DIR := src/app/global_keys_handler
|
||||||
include $(GENODE_DIR)/repos/base/recipes/src/content.inc
|
include $(GENODE_DIR)/repos/base/recipes/src/content.inc
|
@ -10,7 +10,7 @@ if {[have_spec odroid_xu]} {
|
|||||||
set build_components {
|
set build_components {
|
||||||
core init
|
core init
|
||||||
drivers/timer
|
drivers/timer
|
||||||
server/nitpicker app/pointer app/status_bar app/xray_trigger
|
server/nitpicker app/pointer app/status_bar app/global_keys_handler
|
||||||
server/liquid_framebuffer app/launchpad app/scout
|
server/liquid_framebuffer app/launchpad app/scout
|
||||||
test/nitpicker server/nitlog
|
test/nitpicker server/nitlog
|
||||||
drivers/framebuffer drivers/input
|
drivers/framebuffer drivers/input
|
||||||
@ -107,9 +107,9 @@ append config {
|
|||||||
<resource name="RAM" quantum="1M"/>
|
<resource name="RAM" quantum="1M"/>
|
||||||
<provides> <service name="Report"/> <service name="ROM"/> </provides>
|
<provides> <service name="Report"/> <service name="ROM"/> </provides>
|
||||||
<config>
|
<config>
|
||||||
<policy label="status_bar -> focus" report="nitpicker -> focus"/>
|
<policy label="status_bar -> focus" report="nitpicker -> focus"/>
|
||||||
<policy label="nitpicker_config -> xray" report="xray_trigger -> xray"/>
|
<policy label="nitpicker_config -> xray" report="global_keys_handler -> xray"/>
|
||||||
<policy label="xray_trigger -> hover" report="nitpicker -> hover"/>
|
<policy label="global_keys_handler -> hover" report="nitpicker -> hover"/>
|
||||||
</config>
|
</config>
|
||||||
</start>
|
</start>
|
||||||
|
|
||||||
@ -123,7 +123,7 @@ append config {
|
|||||||
|
|
||||||
<output node="config">
|
<output node="config">
|
||||||
<inline>
|
<inline>
|
||||||
<report focus="yes" xray="yes" hover="yes" />
|
<report focus="yes" xray="yes" hover="yes" keystate="yes"/>
|
||||||
<domain name="pointer" layer="1" origin="pointer"
|
<domain name="pointer" layer="1" origin="pointer"
|
||||||
content="client" label="no"/>
|
content="client" label="no"/>
|
||||||
<domain name="panel" layer="2"
|
<domain name="panel" layer="2"
|
||||||
@ -158,9 +158,9 @@ append config {
|
|||||||
<policy label_prefix="scout -> launchpad" domain="launchpad"/>
|
<policy label_prefix="scout -> launchpad" domain="launchpad"/>
|
||||||
<default-policy domain=""/>
|
<default-policy domain=""/>
|
||||||
|
|
||||||
<global-key name="KEY_SCROLLLOCK" label="xray_trigger -> input" />
|
<global-key name="KEY_SCROLLLOCK" label="global_keys_handler -> input" />
|
||||||
<global-key name="KEY_F1" label="xray_trigger -> input" />
|
<global-key name="KEY_F1" label="global_keys_handler -> input" />
|
||||||
<global-key name="KEY_F2" label="xray_trigger -> input" />
|
<global-key name="KEY_F2" label="global_keys_handler -> input" />
|
||||||
</inline>
|
</inline>
|
||||||
</output>
|
</output>
|
||||||
</config>
|
</config>
|
||||||
@ -170,13 +170,20 @@ append config {
|
|||||||
</route>
|
</route>
|
||||||
</start>
|
</start>
|
||||||
|
|
||||||
<start name="xray_trigger">
|
<start name="global_keys_handler">
|
||||||
<resource name="RAM" quantum="1M"/>
|
<resource name="RAM" quantum="1M"/>
|
||||||
<config>
|
<config>
|
||||||
<press name="KEY_F1" xray="on"/>
|
<bool name="xray" initial="no"/>
|
||||||
<release name="KEY_F1" xray="off"/>
|
|
||||||
<press name="KEY_F2" xray="toggle"/>
|
<press name="KEY_SCROLLLOCK" bool="xray" change="toggle"/>
|
||||||
<hover domain="panel"/>
|
<press name="KEY_F1" bool="xray" change="on"/>
|
||||||
|
<release name="KEY_F1" bool="xray" change="off"/>
|
||||||
|
<press name="KEY_F2" bool="xray" change="toggle"/>
|
||||||
|
|
||||||
|
<report name="xray" delay_ms="125">
|
||||||
|
<hovered domain="panel"/>
|
||||||
|
<bool name="xray"/>
|
||||||
|
</report>
|
||||||
</config>
|
</config>
|
||||||
<route>
|
<route>
|
||||||
<service name="Report"> <child name="report_rom"/> </service>
|
<service name="Report"> <child name="report_rom"/> </service>
|
||||||
@ -249,7 +256,7 @@ close $launchpad_config_fd
|
|||||||
set boot_modules {
|
set boot_modules {
|
||||||
core ld.lib.so init
|
core ld.lib.so init
|
||||||
timer
|
timer
|
||||||
nitpicker pointer status_bar report_rom rom_filter xray_trigger
|
nitpicker pointer status_bar report_rom rom_filter global_keys_handler
|
||||||
liquid_fb launchpad scout testnit nitlog
|
liquid_fb launchpad scout testnit nitlog
|
||||||
launchpad.config
|
launchpad.config
|
||||||
}
|
}
|
||||||
|
50
repos/os/src/app/global_keys_handler/README
Normal file
50
repos/os/src/app/global_keys_handler/README
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
The "global-key-handler" component transforms a stream of nitpicker input
|
||||||
|
events to state reports. The states and the ways of how the user input affects
|
||||||
|
the states is configurable. Examples for such states are the system-global
|
||||||
|
capslock and numlock states, or the nitpicker X-ray mode activated by a global
|
||||||
|
secure-attention key. The configuration looks as follows:
|
||||||
|
|
||||||
|
! <config>
|
||||||
|
! <bool name="xray" initial="no"/>
|
||||||
|
!
|
||||||
|
! <press name="KEY_F1" bool="xray" change="on"/>
|
||||||
|
! <release name="KEY_F1" bool="xray" change="off"/>
|
||||||
|
! <press name="KEY_F2" bool="xray" change="toggle"/>
|
||||||
|
!
|
||||||
|
! <report name="xray" delay_ms="125">
|
||||||
|
! <hovered domain="panel"/>
|
||||||
|
! <bool name="xray"/>
|
||||||
|
! </report>
|
||||||
|
! </config>
|
||||||
|
|
||||||
|
A '<bool>' node declares a boolean state variable with the given name and its
|
||||||
|
initial value (default is "no"). There may by any number of such variables.
|
||||||
|
|
||||||
|
The '<press>' and '<release>' nodes define how key events affect the state
|
||||||
|
variables. Each of those nodes refers to a specific state variable via the
|
||||||
|
'bool' attribute, and the operation as the 'change' attribute. Possible
|
||||||
|
'change' attribute values are "on", "off", and "toggle".
|
||||||
|
|
||||||
|
The '<report>' node defines a state-dependent report with the name as
|
||||||
|
specified in the 'name' attribute. The report-generation rate can be
|
||||||
|
artificially limited by the 'delay_ms' attribute. If specified, the report is
|
||||||
|
not issued immediately on a state change but after the specified amount of
|
||||||
|
milliseconds. The '<report>' node contains a number of conditions. Whenever
|
||||||
|
one of those conditions is true, a report of the following form is generated:
|
||||||
|
|
||||||
|
! <xray enabled="yes"/>
|
||||||
|
|
||||||
|
Otherwise, the report's 'enabled' attribute has the value "no". Possible
|
||||||
|
conditions are '<bool>' and '<hovered>'. The '<bool>' condition is true if the
|
||||||
|
named boolean state variable has the value true. The '<hovered>' condition is
|
||||||
|
true if the currently hovered nitpicker client belongs to the domain as
|
||||||
|
specified in the 'domain' attribute. The latter information is obtained from a
|
||||||
|
ROM module named "hover", which correponds to nitpicker's hover reports.
|
||||||
|
|
||||||
|
To use the global-keys-handler in practice, one needs to configure the
|
||||||
|
nitpicker GUI server such that the press/release events of the global keys of
|
||||||
|
interest are routed to the global-keys-handler. This can be achieved by
|
||||||
|
nitpicker's '<global-key>' configuration nodes. For example:
|
||||||
|
|
||||||
|
! <global-key name="KEY_F1" label="global_keys_handler -> input" />
|
||||||
|
! <global-key name="KEY_F2" label="global_keys_handler -> input" />
|
420
repos/os/src/app/global_keys_handler/main.cc
Normal file
420
repos/os/src/app/global_keys_handler/main.cc
Normal file
@ -0,0 +1,420 @@
|
|||||||
|
/*
|
||||||
|
* \brief Utility for generating state reports from global key events
|
||||||
|
* \author Norman Feske
|
||||||
|
* \date 2015-10-03
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2017 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <base/component.h>
|
||||||
|
#include <base/heap.h>
|
||||||
|
#include <base/attached_rom_dataspace.h>
|
||||||
|
#include <base/registry.h>
|
||||||
|
#include <nitpicker_session/connection.h>
|
||||||
|
#include <os/reporter.h>
|
||||||
|
#include <input/event.h>
|
||||||
|
#include <input/keycodes.h>
|
||||||
|
#include <timer_session/connection.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Global_keys_handler {
|
||||||
|
struct Main;
|
||||||
|
using namespace Genode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct Global_keys_handler::Main
|
||||||
|
{
|
||||||
|
Env &_env;
|
||||||
|
|
||||||
|
Heap _heap { _env.ram(), _env.rm() };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration buffer
|
||||||
|
*/
|
||||||
|
Attached_rom_dataspace _config_ds { _env, "config" };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nitpicker connection to obtain user input
|
||||||
|
*/
|
||||||
|
Nitpicker::Connection _nitpicker { _env, "input" };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Input-event buffer
|
||||||
|
*/
|
||||||
|
Attached_dataspace _ev_ds { _env.rm(), _nitpicker.input()->dataspace() };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of pressed keys, used to distinguish primary keys from key
|
||||||
|
* sequences.
|
||||||
|
*/
|
||||||
|
unsigned _key_cnt = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hover model as reported by nitpicker
|
||||||
|
*/
|
||||||
|
Constructible<Attached_rom_dataspace> _hover_ds;
|
||||||
|
|
||||||
|
struct Bool_state
|
||||||
|
{
|
||||||
|
Registry<Bool_state>::Element _element;
|
||||||
|
|
||||||
|
typedef String<64> Name;
|
||||||
|
|
||||||
|
Name const _name;
|
||||||
|
|
||||||
|
bool _state = false;
|
||||||
|
|
||||||
|
Bool_state(Registry<Bool_state> ®istry, Xml_node node)
|
||||||
|
:
|
||||||
|
_element(registry, *this),
|
||||||
|
_name(node.attribute_value("name", Name())),
|
||||||
|
_state(node.attribute_value("initial", false))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
bool enabled() const { return _state; }
|
||||||
|
|
||||||
|
void apply_change(Xml_node event)
|
||||||
|
{
|
||||||
|
/* modify state of matching name only */
|
||||||
|
if (event.attribute_value("bool", Bool_state::Name()) != _name)
|
||||||
|
return;
|
||||||
|
|
||||||
|
typedef String<16> Change;
|
||||||
|
Change const change = event.attribute_value("change", Change());
|
||||||
|
|
||||||
|
if (change == "on") _state = true;
|
||||||
|
if (change == "off") _state = false;
|
||||||
|
if (change == "toggle") _state = !_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_name(Name const &name) const { return name == _name; }
|
||||||
|
};
|
||||||
|
|
||||||
|
Registry<Bool_state> _bool_states;
|
||||||
|
|
||||||
|
struct Report
|
||||||
|
{
|
||||||
|
Deallocator &_alloc;
|
||||||
|
|
||||||
|
typedef String<64> Name;
|
||||||
|
Name const _name;
|
||||||
|
|
||||||
|
Registry<Report>::Element _element;
|
||||||
|
|
||||||
|
Registry<Bool_state> const &_bool_states;
|
||||||
|
|
||||||
|
struct Bool_condition
|
||||||
|
{
|
||||||
|
Registry<Bool_condition>::Element _element;
|
||||||
|
|
||||||
|
Bool_state::Name const _name;
|
||||||
|
|
||||||
|
Bool_condition(Registry<Bool_condition> ®istry, Xml_node node)
|
||||||
|
:
|
||||||
|
_element(registry, *this),
|
||||||
|
_name(node.attribute_value("name", Bool_state::Name()))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if boolean condition is true
|
||||||
|
*/
|
||||||
|
bool satisfied(Registry<Bool_state> const &bool_states) const
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
bool_states.for_each([&] (Bool_state const &state) {
|
||||||
|
if (state.has_name(_name))
|
||||||
|
result = state.enabled(); });
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Hover_condition
|
||||||
|
{
|
||||||
|
Registry<Hover_condition>::Element _element;
|
||||||
|
|
||||||
|
typedef String<160> Domain;
|
||||||
|
|
||||||
|
Domain const _domain;
|
||||||
|
|
||||||
|
Hover_condition(Registry<Hover_condition> ®istry, Xml_node node)
|
||||||
|
:
|
||||||
|
_element(registry, *this),
|
||||||
|
_domain(node.attribute_value("domain", Domain()))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if hovered domain equals expected domain
|
||||||
|
*/
|
||||||
|
bool satisfied(Domain const &hovered) const { return hovered == _domain; }
|
||||||
|
};
|
||||||
|
|
||||||
|
Registry<Bool_condition> _bool_conditions;
|
||||||
|
Registry<Hover_condition> _hover_conditions;
|
||||||
|
|
||||||
|
Reporter _reporter;
|
||||||
|
|
||||||
|
bool _initial_report = true;
|
||||||
|
|
||||||
|
bool _curr_value = false;
|
||||||
|
|
||||||
|
void _generate_report()
|
||||||
|
{
|
||||||
|
Reporter::Xml_generator xml(_reporter, [&] () {
|
||||||
|
xml.attribute("enabled", _curr_value ? "yes" : "no"); });
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handler used for generating delayed reports
|
||||||
|
*/
|
||||||
|
Constructible<Timer::Connection> _timer;
|
||||||
|
|
||||||
|
unsigned long const _delay_ms;
|
||||||
|
|
||||||
|
Signal_handler<Report> _timer_handler;
|
||||||
|
|
||||||
|
Report(Env &env, Allocator &alloc,
|
||||||
|
Registry<Report> &reports,
|
||||||
|
Registry<Bool_state> const &bool_states,
|
||||||
|
Xml_node node)
|
||||||
|
:
|
||||||
|
_alloc(alloc),
|
||||||
|
_name(node.attribute_value("name", Name())),
|
||||||
|
_element(reports, *this),
|
||||||
|
_bool_states(bool_states),
|
||||||
|
_reporter(env, _name.string()),
|
||||||
|
_delay_ms(node.attribute_value("delay_ms", 0UL)),
|
||||||
|
_timer_handler(env.ep(), *this, &Report::_generate_report)
|
||||||
|
{
|
||||||
|
_reporter.enabled(true);
|
||||||
|
|
||||||
|
node.for_each_sub_node("bool", [&] (Xml_node bool_node) {
|
||||||
|
new (alloc) Bool_condition(_bool_conditions, bool_node); });
|
||||||
|
|
||||||
|
node.for_each_sub_node("hovered", [&] (Xml_node hovered) {
|
||||||
|
new (alloc) Hover_condition(_hover_conditions, hovered); });
|
||||||
|
|
||||||
|
if (_delay_ms) {
|
||||||
|
_timer.construct(env);
|
||||||
|
_timer->sigh(_timer_handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~Report()
|
||||||
|
{
|
||||||
|
_bool_conditions.for_each([&] (Bool_condition &condition) {
|
||||||
|
destroy(_alloc, &condition); });
|
||||||
|
|
||||||
|
_hover_conditions.for_each([&] (Hover_condition &condition) {
|
||||||
|
destroy(_alloc, &condition); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void update(Hover_condition::Domain const &hovered_domain)
|
||||||
|
{
|
||||||
|
bool old_value = _curr_value;
|
||||||
|
|
||||||
|
_curr_value = false;
|
||||||
|
|
||||||
|
_bool_conditions.for_each([&] (Bool_condition const &cond) {
|
||||||
|
_curr_value |= cond.satisfied(_bool_states); });
|
||||||
|
|
||||||
|
_hover_conditions.for_each([&] (Hover_condition const &cond) {
|
||||||
|
_curr_value |= cond.satisfied(hovered_domain); });
|
||||||
|
|
||||||
|
if (!_initial_report && _curr_value == old_value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_initial_report = false;
|
||||||
|
|
||||||
|
if (_delay_ms)
|
||||||
|
_timer->trigger_once(_delay_ms*1000);
|
||||||
|
else
|
||||||
|
_generate_report();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool depends_on_hover_info() const
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
_hover_conditions.for_each([&] (Hover_condition const &) { result = true; });
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Registry<Report> _reports;
|
||||||
|
|
||||||
|
bool _reports_depend_on_hover_info() const
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
_reports.for_each([&] (Report const &report) {
|
||||||
|
result |= report.depends_on_hover_info(); });
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _apply_input_events(unsigned, Input::Event const []);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler that is called on config changes
|
||||||
|
*/
|
||||||
|
void _handle_config();
|
||||||
|
|
||||||
|
Signal_handler<Main> _config_handler =
|
||||||
|
{ _env.ep(), *this, &Main::_handle_config };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler that is called on hover changes or on the arrival of user input
|
||||||
|
*/
|
||||||
|
void _handle_input();
|
||||||
|
|
||||||
|
Signal_handler<Main> _input_handler = {
|
||||||
|
_env.ep(), *this, &Main::_handle_input };
|
||||||
|
|
||||||
|
Main(Env &env) : _env(env)
|
||||||
|
{
|
||||||
|
_config_ds.sigh(_config_handler);
|
||||||
|
_nitpicker.input()->sigh(_input_handler);
|
||||||
|
|
||||||
|
_handle_config();
|
||||||
|
_handle_input();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void Global_keys_handler::Main::_apply_input_events(unsigned num_ev,
|
||||||
|
Input::Event const events[])
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < num_ev; i++) {
|
||||||
|
|
||||||
|
Input::Event const &ev = events[i];
|
||||||
|
|
||||||
|
if (ev.type() != Input::Event::PRESS
|
||||||
|
&& ev.type() != Input::Event::RELEASE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ev.type() == Input::Event::PRESS) _key_cnt++;
|
||||||
|
if (ev.type() == Input::Event::RELEASE) _key_cnt--;
|
||||||
|
|
||||||
|
/* ignore key combinations */
|
||||||
|
if (_key_cnt > 1) continue;
|
||||||
|
|
||||||
|
typedef String<32> Key_name;
|
||||||
|
Key_name const ev_key_name(Input::key_name(ev.keycode()));
|
||||||
|
|
||||||
|
typedef Xml_node Xml_node;
|
||||||
|
|
||||||
|
auto lambda = [&] (Xml_node node) {
|
||||||
|
|
||||||
|
if (!node.has_type("press") && !node.has_type("release"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (node.has_type("press") && ev.type() != Input::Event::PRESS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (node.has_type("release") && ev.type() != Input::Event::RELEASE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XML node applies for current event type, check if the key
|
||||||
|
* matches.
|
||||||
|
*/
|
||||||
|
if (node.attribute_value("name", Key_name()) != ev_key_name)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Manipulate bool state as instructed by the XML node.
|
||||||
|
*/
|
||||||
|
_bool_states.for_each([&] (Bool_state &state) {
|
||||||
|
state.apply_change(node); });
|
||||||
|
};
|
||||||
|
|
||||||
|
_config_ds.xml().for_each_sub_node(lambda);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Global_keys_handler::Main::_handle_config()
|
||||||
|
{
|
||||||
|
_config_ds.update();
|
||||||
|
|
||||||
|
Xml_node const config = _config_ds.xml();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Import bool states
|
||||||
|
*/
|
||||||
|
_bool_states.for_each([&] (Bool_state &state)
|
||||||
|
{
|
||||||
|
bool keep_existing_state = false;
|
||||||
|
config.for_each_sub_node("bool", [&] (Xml_node node) {
|
||||||
|
if (state.has_name(node.attribute_value("name", Bool_state::Name())))
|
||||||
|
keep_existing_state = true; });
|
||||||
|
|
||||||
|
if (!keep_existing_state)
|
||||||
|
destroy(_heap, &state);
|
||||||
|
});
|
||||||
|
|
||||||
|
config.for_each_sub_node("bool", [&] (Xml_node node)
|
||||||
|
{
|
||||||
|
Bool_state::Name const name = node.attribute_value("name", Bool_state::Name());
|
||||||
|
|
||||||
|
bool state_already_exists = false;
|
||||||
|
_bool_states.for_each([&] (Bool_state const &state) {
|
||||||
|
if (state.has_name(name))
|
||||||
|
state_already_exists = true; });
|
||||||
|
|
||||||
|
if (!state_already_exists)
|
||||||
|
new (_heap) Bool_state(_bool_states, node);
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update report definitions
|
||||||
|
*/
|
||||||
|
_reports.for_each([&] (Report &report) { destroy(_heap, &report); });
|
||||||
|
|
||||||
|
config.for_each_sub_node("report", [&] (Xml_node report) {
|
||||||
|
new (_heap) Report(_env, _heap, _reports, _bool_states, report); });
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Obtain / update hover info if needed
|
||||||
|
*/
|
||||||
|
if (_reports_depend_on_hover_info() && !_hover_ds.constructed()) {
|
||||||
|
_hover_ds.construct(_env, "hover");
|
||||||
|
_hover_ds->sigh(_input_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Trigger initial creation of the reports
|
||||||
|
*/
|
||||||
|
_handle_input();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Global_keys_handler::Main::_handle_input()
|
||||||
|
{
|
||||||
|
while (unsigned const num_ev = _nitpicker.input()->flush())
|
||||||
|
_apply_input_events(num_ev, _ev_ds.local_addr<Input::Event const>());
|
||||||
|
|
||||||
|
/* determine currently hovered domain */
|
||||||
|
typedef Report::Hover_condition::Domain Domain;
|
||||||
|
Domain hovered_domain;
|
||||||
|
if (_hover_ds.constructed()) {
|
||||||
|
_hover_ds->update();
|
||||||
|
hovered_domain = _hover_ds->xml().attribute_value("domain", Domain());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* re-generate reports */
|
||||||
|
_reports.for_each([&] (Report &report) {
|
||||||
|
report.update(hovered_domain); });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***************
|
||||||
|
** Component **
|
||||||
|
***************/
|
||||||
|
|
||||||
|
void Component::construct(Genode::Env &env) {
|
||||||
|
static Global_keys_handler::Main main(env); }
|
@ -1,3 +1,3 @@
|
|||||||
TARGET = xray_trigger
|
TARGET = global_keys_handler
|
||||||
SRC_CC = main.cc
|
SRC_CC = main.cc
|
||||||
LIBS += base
|
LIBS += base
|
@ -1,257 +0,0 @@
|
|||||||
/*
|
|
||||||
* \brief Policy for activating the X-Ray mode
|
|
||||||
* \author Norman Feske
|
|
||||||
* \date 2015-10-03
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2015-2017 Genode Labs GmbH
|
|
||||||
*
|
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Genode includes */
|
|
||||||
#include <base/component.h>
|
|
||||||
#include <base/attached_rom_dataspace.h>
|
|
||||||
#include <nitpicker_session/connection.h>
|
|
||||||
#include <os/reporter.h>
|
|
||||||
#include <input/event.h>
|
|
||||||
#include <input/keycodes.h>
|
|
||||||
#include <timer_session/connection.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace Xray_trigger {
|
|
||||||
struct Main;
|
|
||||||
using namespace Genode;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct Xray_trigger::Main
|
|
||||||
{
|
|
||||||
Env &_env;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configuration buffer
|
|
||||||
*/
|
|
||||||
Attached_rom_dataspace _config { _env, "config" };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Nitpicker connection to obtain user input
|
|
||||||
*/
|
|
||||||
Nitpicker::Connection _nitpicker { _env, "input" };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Input-event buffer
|
|
||||||
*/
|
|
||||||
Attached_dataspace _ev_ds { _env.rm(), _nitpicker.input()->dataspace() };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of pressed keys, used to distinguish primary keys from key
|
|
||||||
* sequences.
|
|
||||||
*/
|
|
||||||
unsigned _key_cnt = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hover model as reported by nitpicker
|
|
||||||
*/
|
|
||||||
Constructible<Attached_rom_dataspace> _hover_ds;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reporter for posting the result of our policy decision
|
|
||||||
*/
|
|
||||||
Reporter _xray_reporter { _env, "xray" };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Timer to delay the xray report
|
|
||||||
*/
|
|
||||||
Timer::Connection _timer { _env };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* X-Ray criterion depending on key events
|
|
||||||
*/
|
|
||||||
bool _key_xray = false;
|
|
||||||
|
|
||||||
bool _key_xray_initialized = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* X-Ray criterion depending on hovered domain
|
|
||||||
*/
|
|
||||||
bool _hover_xray = false;
|
|
||||||
|
|
||||||
bool _xray() const { return _key_xray || _hover_xray; }
|
|
||||||
|
|
||||||
bool _evaluate_input(bool, unsigned, Input::Event const [], unsigned &) const;
|
|
||||||
bool _evaluate_hover(Xml_node) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler that is called on config changes, on hover-model changes, or on
|
|
||||||
* the arrival of user input
|
|
||||||
*/
|
|
||||||
void _handle_update();
|
|
||||||
|
|
||||||
Signal_handler<Main> _update_handler =
|
|
||||||
{ _env.ep(), *this, &Main::_handle_update };
|
|
||||||
|
|
||||||
void _report_xray()
|
|
||||||
{
|
|
||||||
Reporter::Xml_generator xml(_xray_reporter, [&] () {
|
|
||||||
xml.attribute("enabled", _xray() ? "yes" : "no");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler that is called after the xray report delay
|
|
||||||
*/
|
|
||||||
Signal_handler<Main> _timeout_handler =
|
|
||||||
{ _env.ep(), *this, &Main::_report_xray };
|
|
||||||
|
|
||||||
Main(Env &env) : _env(env)
|
|
||||||
{
|
|
||||||
_config.sigh(_update_handler);
|
|
||||||
|
|
||||||
_timer.sigh(_timeout_handler);
|
|
||||||
|
|
||||||
/* enable xray reporter and produce initial xray report */
|
|
||||||
_xray_reporter.enabled(true);
|
|
||||||
_report_xray();
|
|
||||||
|
|
||||||
_nitpicker.input()->sigh(_update_handler);
|
|
||||||
_handle_update();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
bool Xray_trigger::Main::_evaluate_input(bool key_xray, unsigned num_ev,
|
|
||||||
Input::Event const events[],
|
|
||||||
unsigned &key_cnt) const
|
|
||||||
{
|
|
||||||
/* adjust '_key_xray' according to user key input */
|
|
||||||
for (unsigned i = 0; i < num_ev; i++) {
|
|
||||||
|
|
||||||
Input::Event const &ev = events[i];
|
|
||||||
|
|
||||||
if (ev.type() != Input::Event::PRESS
|
|
||||||
&& ev.type() != Input::Event::RELEASE)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ev.type() == Input::Event::PRESS) key_cnt++;
|
|
||||||
if (ev.type() == Input::Event::RELEASE) key_cnt--;
|
|
||||||
|
|
||||||
/* ignore key combinations */
|
|
||||||
if (key_cnt > 1) continue;
|
|
||||||
|
|
||||||
typedef String<32> Key_name;
|
|
||||||
Key_name const ev_key_name(Input::key_name(ev.keycode()));
|
|
||||||
|
|
||||||
typedef Xml_node Xml_node;
|
|
||||||
|
|
||||||
auto lambda = [&] (Xml_node node) {
|
|
||||||
|
|
||||||
if (!node.has_type("press") && !node.has_type("release"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (node.has_type("press") && ev.type() != Input::Event::PRESS)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (node.has_type("release") && ev.type() != Input::Event::RELEASE)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* XML node applies for current event type, check if the key
|
|
||||||
* matches.
|
|
||||||
*/
|
|
||||||
|
|
||||||
Key_name const cfg_key_name =
|
|
||||||
node.attribute_value("name", Key_name());
|
|
||||||
|
|
||||||
if (cfg_key_name != ev_key_name)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Manipulate X-Ray mode as instructed by the XML node.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (node.attribute("xray").has_value("on"))
|
|
||||||
key_xray = true;
|
|
||||||
|
|
||||||
if (node.attribute("xray").has_value("off"))
|
|
||||||
key_xray = false;
|
|
||||||
|
|
||||||
if (node.attribute("xray").has_value("toggle"))
|
|
||||||
key_xray = !_key_xray;
|
|
||||||
};
|
|
||||||
|
|
||||||
_config.xml().for_each_sub_node(lambda);
|
|
||||||
}
|
|
||||||
return key_xray;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Xray_trigger::Main::_evaluate_hover(Xml_node nitpicker_hover) const
|
|
||||||
{
|
|
||||||
bool hover_xray = false;
|
|
||||||
|
|
||||||
using namespace Genode;
|
|
||||||
|
|
||||||
_config.xml().for_each_sub_node("hover", [&] (Xml_node node) {
|
|
||||||
|
|
||||||
typedef String<160> Domain;
|
|
||||||
Domain nitpicker_domain = nitpicker_hover.attribute_value("domain", Domain());
|
|
||||||
Domain expected_domain = node.attribute_value("domain", Domain());
|
|
||||||
|
|
||||||
if (nitpicker_domain == expected_domain)
|
|
||||||
hover_xray = true;
|
|
||||||
});
|
|
||||||
return hover_xray;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Xray_trigger::Main::_handle_update()
|
|
||||||
{
|
|
||||||
_config.update();
|
|
||||||
|
|
||||||
/* define initial state once */
|
|
||||||
if (!_key_xray_initialized) {
|
|
||||||
_key_xray = _config.xml().attribute_value("initial", false);
|
|
||||||
|
|
||||||
_key_xray_initialized = true;
|
|
||||||
_timer.trigger_once(10000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remember X-Ray mode prior applying the changes */
|
|
||||||
bool const orig_xray = _xray();
|
|
||||||
|
|
||||||
while (unsigned const num_ev = _nitpicker.input()->flush())
|
|
||||||
_key_xray = _evaluate_input(_key_xray, num_ev,
|
|
||||||
_ev_ds.local_addr<Input::Event const>(),
|
|
||||||
_key_cnt);
|
|
||||||
|
|
||||||
/* obtain / update hover model if needed */
|
|
||||||
if (_config.xml().has_sub_node("hover")) {
|
|
||||||
|
|
||||||
if (!_hover_ds.constructed()) {
|
|
||||||
_hover_ds.construct(_env, "hover");
|
|
||||||
_hover_ds->sigh(_update_handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
_hover_ds->update();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
_hover_xray = _evaluate_hover(Xml_node(_hover_ds->local_addr<char>(),
|
|
||||||
_hover_ds->size()));
|
|
||||||
} catch (...) { }
|
|
||||||
|
|
||||||
/* generate new X-Ray report if the X-Ray mode changed */
|
|
||||||
if (_xray() != orig_xray)
|
|
||||||
_timer.trigger_once(125000);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***************
|
|
||||||
** Component **
|
|
||||||
***************/
|
|
||||||
|
|
||||||
void Component::construct(Genode::Env &env) {
|
|
||||||
static Xray_trigger::Main main(env); }
|
|
Loading…
Reference in New Issue
Block a user