mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-09 04:15:52 +00:00
event_filter: new touch-key filter
The new <touch-key> filter type can be used to trigger artificial press/release events for predefined touch-screen areas. Fixes #4587
This commit is contained in:
parent
59f1fe7625
commit
236ebecf44
@ -88,6 +88,7 @@ append config {
|
||||
<driver name="usb"/>
|
||||
<driver name="ps2"/>
|
||||
|
||||
|
||||
<message string="test merging of two input sources"/>
|
||||
|
||||
<filter_config>
|
||||
@ -483,6 +484,7 @@ append config {
|
||||
<usb> <press code="KEY_A"/> <release code="KEY_A"/> </usb>
|
||||
<expect_press code="KEY_A" char="b"/> <expect_release code="KEY_A"/>
|
||||
|
||||
|
||||
<message string="test remap of KEY_UNKNOWN"/>
|
||||
|
||||
<filter_config>
|
||||
@ -502,6 +504,7 @@ append config {
|
||||
<expect_press code="KEY_A" />
|
||||
<expect_release code="KEY_A" />
|
||||
|
||||
|
||||
<message string="test ignore-key"/>
|
||||
|
||||
<filter_config>
|
||||
@ -524,6 +527,7 @@ append config {
|
||||
<not_expect_press code="KEY_A" />
|
||||
<not_expect_release code="KEY_A" />
|
||||
|
||||
|
||||
<message string="test log output"/>
|
||||
|
||||
<filter_config>
|
||||
@ -545,6 +549,29 @@ append config {
|
||||
<release code="KEY_UNKNOWN"/>
|
||||
</usb>
|
||||
|
||||
<message string="test touch key"/>
|
||||
|
||||
<filter_config>
|
||||
<output>
|
||||
<touch-key>
|
||||
<tap xpos="0" ypos="400" width="50" height="600" key="KEY_DASHBOARD"/>
|
||||
<input name="usb"/>
|
||||
</touch-key>
|
||||
</output>
|
||||
<policy label_suffix="usb" input="usb"/>
|
||||
</filter_config>
|
||||
<sleep ms="100"/>
|
||||
<usb>
|
||||
<touch x="10" y="500" /> <!-- hits special area -->
|
||||
<touch-release/>
|
||||
<touch x="100" y="500" /> <!-- besides special area -->
|
||||
<touch-release/>
|
||||
</usb>
|
||||
<expect_press code="KEY_DASHBOARD" />
|
||||
<expect_release code="KEY_DASHBOARD" />
|
||||
<expect_touch x="100" y="500"/>
|
||||
<expect_touch_release/>
|
||||
|
||||
</config>
|
||||
<route>
|
||||
<service name="Event"> <child name="event_filter"/> </service>
|
||||
|
@ -86,6 +86,14 @@ one of the following filters:
|
||||
touch input. The original touch events are preserved, enabling touch-aware
|
||||
applications to interpet touch gestures.
|
||||
|
||||
:<touch-key>:
|
||||
|
||||
Triggers an artificial key tap (a press event followed by a release event)
|
||||
when touching a preconfigured area on a touch screen. The filter node can
|
||||
host any number of '<tap>' sub nodes. Each sub node must define a
|
||||
rectangular area - using the attributes 'xpos', 'ypos', 'width', and
|
||||
'height' - and the name of the tapped key as 'key' attribute.
|
||||
|
||||
|
||||
Character generator rules
|
||||
-------------------------
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <accelerate_source.h>
|
||||
#include <log_source.h>
|
||||
#include <touch_click_source.h>
|
||||
#include <touch_key_source.h>
|
||||
#include <event_session.h>
|
||||
|
||||
namespace Event_filter { struct Main; }
|
||||
@ -254,6 +255,9 @@ struct Event_filter::Main : Source::Factory, Source::Trigger
|
||||
if (node.type() == Touch_click_source::name())
|
||||
return *new (_heap) Touch_click_source(owner, node, *this);
|
||||
|
||||
if (node.type() == Touch_key_source::name())
|
||||
return *new (_heap) Touch_key_source(owner, node, *this, _heap);
|
||||
|
||||
warning("unknown <", node.type(), "> input-source node type");
|
||||
throw Source::Invalid_config();
|
||||
}
|
||||
|
@ -48,7 +48,8 @@ class Event_filter::Source
|
||||
|| node.type() == "button-scroll"
|
||||
|| node.type() == "accelerate"
|
||||
|| node.type() == "log"
|
||||
|| node.type() == "touch-click";
|
||||
|| node.type() == "touch-click"
|
||||
|| node.type() == "touch-key";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
128
repos/os/src/server/event_filter/touch_key_source.h
Normal file
128
repos/os/src/server/event_filter/touch_key_source.h
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* \brief Input-event source that generates press/release from touch events
|
||||
* \author Norman Feske
|
||||
* \date 2022-08-22
|
||||
*
|
||||
* This filter generates artificial key press/release event pairs when touching
|
||||
* pre-defined areas on a touch screen. All events occurring while such a
|
||||
* special area is touched are suppressed.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
#ifndef _EVENT_FILTER__TOUCH_KEY_SOURCE_H_
|
||||
#define _EVENT_FILTER__TOUCH_KEY_SOURCE_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <input/keycodes.h>
|
||||
#include <util/geometry.h>
|
||||
#include <base/allocator.h>
|
||||
|
||||
/* local includes */
|
||||
#include <source.h>
|
||||
|
||||
namespace Event_filter { class Touch_key_source; }
|
||||
|
||||
|
||||
class Event_filter::Touch_key_source : public Source, Source::Filter
|
||||
{
|
||||
private:
|
||||
|
||||
using Rect = Genode::Rect<>;
|
||||
|
||||
Owner _owner;
|
||||
|
||||
Source &_source;
|
||||
|
||||
Allocator &_alloc;
|
||||
|
||||
bool _pressed = false; /* true during touch sequence */
|
||||
|
||||
struct Tap : Interface
|
||||
{
|
||||
Rect const rect;
|
||||
|
||||
Input::Keycode const code;
|
||||
|
||||
static Input::Keycode code_from_xml(Xml_node const &node)
|
||||
{
|
||||
try {
|
||||
return key_code_by_name(node.attribute_value("key", Key_name()));
|
||||
}
|
||||
catch (Unknown_key) { }
|
||||
warning("ignoring tap rule ", node);
|
||||
return Input::KEY_UNKNOWN;
|
||||
}
|
||||
|
||||
Tap(Xml_node const &node)
|
||||
: rect(Rect::from_xml(node)), code(code_from_xml(node)) { }
|
||||
};
|
||||
|
||||
Registry<Registered<Tap>> _tap_rules { };
|
||||
|
||||
/**
|
||||
* Filter interface
|
||||
*/
|
||||
void filter_event(Sink &destination, Input::Event const &event) override
|
||||
{
|
||||
Input::Event ev = event;
|
||||
|
||||
ev.handle_touch([&] (Input::Touch_id id, float x, float y) {
|
||||
|
||||
/* respond to initial touch of first finger only */
|
||||
if (id.value != 0 || _pressed)
|
||||
return;
|
||||
|
||||
_tap_rules.for_each([&] (Tap const &tap) {
|
||||
if (tap.rect.contains(Point((int)(x), (int)(y)))) {
|
||||
destination.submit(Input::Press { tap.code });
|
||||
destination.submit(Input::Release { tap.code });
|
||||
_pressed = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/* filter out all events during the touch sequence */
|
||||
if (!_pressed)
|
||||
destination.submit(ev);
|
||||
|
||||
ev.handle_touch_release([&] (Input::Touch_id id) {
|
||||
if (id.value == 0)
|
||||
_pressed = false;
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
static char const *name() { return "touch-key"; }
|
||||
|
||||
Touch_key_source(Owner &owner, Xml_node config,
|
||||
Source::Factory &factory, Allocator &alloc)
|
||||
:
|
||||
Source(owner),
|
||||
_owner(factory),
|
||||
_source(factory.create_source(_owner, input_sub_node(config))),
|
||||
_alloc(alloc)
|
||||
{
|
||||
config.for_each_sub_node("tap", [&] (Xml_node const &node) {
|
||||
new (_alloc) Registered<Tap>(_tap_rules, node); });
|
||||
}
|
||||
|
||||
~Touch_key_source()
|
||||
{
|
||||
_tap_rules.for_each([&] (Registered<Tap> &tap) {
|
||||
destroy(_alloc, &tap); });
|
||||
}
|
||||
|
||||
void generate(Sink &destination) override
|
||||
{
|
||||
Source::Filter::apply(destination, *this, _source);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _EVENT_FILTER__TOUCH_KEY_SOURCE_H_*/
|
@ -259,6 +259,13 @@ class Test::Input_to_filter
|
||||
if (motion && rel)
|
||||
batch.submit(Input::Relative_motion{(int)node.attribute_value("rx", 0L),
|
||||
(int)node.attribute_value("ry", 0L)});
|
||||
|
||||
if (node.has_type("touch"))
|
||||
batch.submit(Input::Touch{ { 0 }, (float)node.attribute_value("x", 0.0),
|
||||
(float)node.attribute_value("y", 0.0)});
|
||||
|
||||
if (node.has_type("touch-release"))
|
||||
batch.submit(Input::Touch_release { { 0 } } );
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -337,6 +344,8 @@ struct Test::Main : Input_from_filter::Event_handler
|
||||
step.type() == "expect_release" ||
|
||||
step.type() == "not_expect_press" ||
|
||||
step.type() == "not_expect_release" ||
|
||||
step.type() == "expect_touch" ||
|
||||
step.type() == "expect_touch_release" ||
|
||||
step.type() == "expect_char" ||
|
||||
step.type() == "expect_motion" ||
|
||||
step.type() == "expect_wheel");
|
||||
@ -399,6 +408,7 @@ struct Test::Main : Input_from_filter::Event_handler
|
||||
|
||||
if (step.type() == "expect_press" || step.type() == "expect_release"
|
||||
|| step.type() == "not_expect_press" || step.type() == "not_expect_release"
|
||||
|| step.type() == "expect_touch" || step.type() == "expect_touch_release"
|
||||
|| step.type() == "expect_char" || step.type() == "expect_motion"
|
||||
|| step.type() == "expect_wheel")
|
||||
return;
|
||||
@ -485,6 +495,18 @@ struct Test::Main : Input_from_filter::Event_handler
|
||||
&& (!step.has_attribute("ay") || step.attribute_value("ay", 0L) == y))
|
||||
step_succeeded = true; });
|
||||
|
||||
ev.handle_touch([&] (Input::Touch_id, float x, float y) {
|
||||
if (step.type() == "expect_touch"
|
||||
&& ((float)step.attribute_value("x", 0.0) == x)
|
||||
&& ((float)step.attribute_value("y", 0.0) == y))
|
||||
step_succeeded = true;
|
||||
});
|
||||
|
||||
ev.handle_touch_release([&] (Input::Touch_id) {
|
||||
if (step.type() == "expect_touch_release")
|
||||
step_succeeded = true;
|
||||
});
|
||||
|
||||
if (step_failed) {
|
||||
error("got unexpected event: ", step);
|
||||
throw Exception();
|
||||
|
Loading…
x
Reference in New Issue
Block a user