os: new Input::Event representation

This commit changes the 'Input::Event' type to be more safe and to
deliver symbolic character information along with press events.

Issue #2761
Fixes #2786
This commit is contained in:
Norman Feske 2018-04-20 14:27:45 +02:00 committed by Christian Helmuth
parent df3ceda052
commit afcad2a968
46 changed files with 1170 additions and 1209 deletions

View File

@ -200,12 +200,12 @@ if { [have_include "power_on/qemu"] || ![get_cmd_switch --autopilot] } { run_gen
# autopilot test
run_genode_until {\[init -\> test-input\] Input event #1\t} 60
run_genode_until {\[init -\> test-input\] Input event #0\t} 60
# remove everything before the first interesting line
regexp {(\[init -\> test-input\] Input event #1\t.*)} $output all output
regexp {(\[init -\> test-input\] Input event #0\t.*)} $output all output
run_genode_until {\[init -\> test-input\] Input event #12.*\n} 40 [output_spawn_id]
run_genode_until {\[init -\> test-input\] Input event #11.*\n} 40 [output_spawn_id]
# pay only attention to the output of init and its children
grep_output {^\[init }
@ -220,22 +220,22 @@ filter_out_color_escape_sequences
trim_lines
compare_output_to {
[init -> test-input] Input event #1 type=PRESS code=45 rx=0 ry=0 ax=0 ay=0 key_cnt=1 KEY_X
[init -> test-input] Input event #2 type=RELEASE code=45 rx=0 ry=0 ax=0 ay=0 key_cnt=0 KEY_X
[init -> test-input] Input event #3 type=PRESS code=272 rx=0 ry=0 ax=0 ay=0 key_cnt=1 BTN_LEFT
[init -> test-input] Input event #4 type=MOTION code=0 rx=-1 ry=0 ax=0 ay=0 key_cnt=1
[init -> test-input] Input event #5 type=MOTION code=0 rx=0 ry=1 ax=0 ay=0 key_cnt=1
[init -> test-input] Input event #6 type=RELEASE code=272 rx=0 ry=0 ax=0 ay=0 key_cnt=0 BTN_LEFT
[init -> test-input] Input event #0 PRESS KEY_X 0
[init -> test-input] Input event #1 RELEASE KEY_X
[init -> test-input] Input event #2 PRESS BTN_LEFT 0
[init -> test-input] Input event #3 REL_MOTION -1+0
[init -> test-input] Input event #4 REL_MOTION +0+1
[init -> test-input] Input event #5 RELEASE BTN_LEFT
[init -> usb_drv] dev_info: USB disconnect, device
[init -> usb_drv] dev_info: new full-speed USB device
[init -> usb_drv] dev_info: D L
[init -> usb_drv] dev_info: input: USB HID v1.11 Keyboard [D L]
[init -> usb_drv] dev_info: D L
[init -> usb_drv] dev_info: input: USB HID v1.11 Mouse [D L]
[init -> test-input] Input event #7 type=PRESS code=45 rx=0 ry=0 ax=0 ay=0 key_cnt=1 KEY_X
[init -> test-input] Input event #8 type=RELEASE code=45 rx=0 ry=0 ax=0 ay=0 key_cnt=0 KEY_X
[init -> test-input] Input event #9 type=PRESS code=272 rx=0 ry=0 ax=0 ay=0 key_cnt=1 BTN_LEFT
[init -> test-input] Input event #10 type=MOTION code=0 rx=-1 ry=0 ax=0 ay=0 key_cnt=1
[init -> test-input] Input event #11 type=MOTION code=0 rx=0 ry=1 ax=0 ay=0 key_cnt=1
[init -> test-input] Input event #12 type=RELEASE code=272 rx=0 ry=0 ax=0 ay=0 key_cnt=0 BTN_LEFT
[init -> test-input] Input event #6 PRESS KEY_X 0
[init -> test-input] Input event #7 RELEASE KEY_X
[init -> test-input] Input event #8 PRESS BTN_LEFT 0
[init -> test-input] Input event #9 REL_MOTION -1+0
[init -> test-input] Input event #10 REL_MOTION +0+1
[init -> test-input] Input event #11 RELEASE BTN_LEFT
}

View File

@ -41,22 +41,33 @@ static Genode::Constructible<Input::Root_component> _input_root;
* Input event call-back function
*/
static void input_callback(enum input_event_type type,
unsigned code,
int absolute_x, int absolute_y,
int relative_x, int relative_y)
unsigned code, int ax, int ay, int rx, int ry)
{
Input::Event::Type t = Input::Event::INVALID;
switch (type) {
case EVENT_TYPE_PRESS: t = Input::Event::PRESS; break;
case EVENT_TYPE_RELEASE: t = Input::Event::RELEASE; break;
case EVENT_TYPE_MOTION: t = Input::Event::MOTION; break;
case EVENT_TYPE_WHEEL: t = Input::Event::WHEEL; break;
case EVENT_TYPE_TOUCH: t = Input::Event::TOUCH; break;
}
using namespace Input;
_input_session->submit(Input::Event(t, code,
absolute_x, absolute_y,
relative_x, relative_y));
auto submit = [&] (Event const &ev) { _input_session->submit(ev); };
switch (type) {
case EVENT_TYPE_PRESS: submit(Press{Keycode(code)}); break;
case EVENT_TYPE_RELEASE: submit(Release{Keycode(code)}); break;
case EVENT_TYPE_MOTION:
if (rx == 0 && ry == 0)
submit(Absolute_motion{ax, ay});
else
submit(Relative_motion{rx, ry});
break;
case EVENT_TYPE_WHEEL: submit(Wheel{rx, ry}); break;
case EVENT_TYPE_TOUCH:
{
Touch_id const id { (int)code };
if (rx == -1 && ry == -1)
submit(Touch_release{id});
else
submit(Touch{id, (float)ax, (float)ay});
break;
}
}
}

View File

@ -95,28 +95,25 @@ class Scout::Platform
{
if (_input.pending() == false) return;
for (int i = 0, num = _input.flush(); i < num; i++)
{
for (int i = 0, num = _input.flush(); i < num; i++) {
Event ev;
Input::Event e = _ev_buf[i];
_event_pending = i + 1 < num;
if (e.type() == Input::Event::RELEASE
|| e.type() == Input::Event::PRESS) {
_mx = e.ax();
_my = e.ay();
ev.assign(e.type() == Input::Event::PRESS ? Event::PRESS : Event::RELEASE,
e.ax(), e.ay(), e.code());
_handle_event(ev);
}
e.handle_press([&] (Input::Keycode key, Genode::Codepoint) {
ev.assign(Event::PRESS, _mx, _my, key); });
if (e.type() == Input::Event::MOTION) {
_mx = e.ax();
_my = e.ay();
ev.assign(Event::MOTION, e.ax(), e.ay(), e.code());
e.handle_release([&] (Input::Keycode key) {
ev.assign(Event::RELEASE, _mx, _my, key); });
e.handle_absolute_motion([&] (int x, int y) {
_mx = x; _my = y;
ev.assign(Event::MOTION, _mx, _my, 0);
});
if (ev.type != Event::UNDEFINED)
_handle_event(ev);
}
}
}

View File

@ -61,23 +61,16 @@ class Window_content : public Scout::Element
Point mouse_position = ev.mouse_position - _element->abs_position();
int code = 0;
auto motion = [&] (Point p) { return Input::Absolute_motion{p.x(), p.y()}; };
if (ev.type == Event::PRESS || ev.type == Event::RELEASE)
code = ev.code;
if (ev.type == Event::MOTION)
_input_session.submit(motion(mouse_position));
Input::Event::Type type;
if (ev.type == Event::PRESS)
_input_session.submit(Input::Press{Input::Keycode(ev.code)});
type = (ev.type == Event::MOTION) ? Input::Event::MOTION
: (ev.type == Event::PRESS) ? Input::Event::PRESS
: (ev.type == Event::RELEASE) ? Input::Event::RELEASE
: Input::Event::INVALID;
if (type != Input::Event::INVALID)
_input_session.submit(Input::Event(type, code, mouse_position.x(),
mouse_position.y(),
mouse_position.x() - _old_mouse_position.x(),
mouse_position.y() - _old_mouse_position.y()));
if (ev.type == Event::RELEASE)
_input_session.submit(Input::Release{Input::Keycode(ev.code)});
_old_mouse_position = mouse_position;
}

View File

@ -448,7 +448,9 @@ struct Nitlog::Main
Attached_dataspace _ev_ds { _env.rm(), _nitpicker.input()->dataspace() };
Nitpicker::Point _old_mouse_pos { };
Nitpicker::Point const _initial_mouse_pos { -1, -1 };
Nitpicker::Point _old_mouse_pos = _initial_mouse_pos;
unsigned _key_cnt = 0;
@ -463,20 +465,24 @@ struct Nitlog::Main
Input::Event const &ev = ev_buf[i];
if (ev.type() == Input::Event::PRESS) _key_cnt++;
if (ev.type() == Input::Event::RELEASE) _key_cnt--;
Nitpicker::Point mouse_pos(ev.ax(), ev.ay());
if (ev.press()) _key_cnt++;
if (ev.release()) _key_cnt--;
/* move view */
if (ev.type() == Input::Event::MOTION && _key_cnt > 0)
_view.move(_view.pos() + mouse_pos - _old_mouse_pos);
ev.handle_absolute_motion([&] (int x, int y) {
Nitpicker::Point const mouse_pos(x, y);
if (_key_cnt && _old_mouse_pos != _initial_mouse_pos)
_view.move(_view.pos() + mouse_pos - _old_mouse_pos);
_old_mouse_pos = mouse_pos;
});
/* find selected view and bring it to front */
if (ev.type() == Input::Event::PRESS && _key_cnt == 1)
if (ev.press() && _key_cnt == 1)
_view.top();
_old_mouse_pos = mouse_pos;
}
}

View File

@ -206,24 +206,24 @@ class Floating_window_layouter::Key_sequence_tracker
* to preserver the invariant that each key is present only
* once.
*/
if (ev.type() == Input::Event::PRESS) {
_stack.flush(Stack::Entry(Stack::Entry::PRESS, ev.keycode()));
_stack.flush(Stack::Entry(Stack::Entry::RELEASE, ev.keycode()));
}
ev.handle_press([&] (Input::Keycode key, Codepoint) {
_stack.flush(Stack::Entry(Stack::Entry::PRESS, key));
_stack.flush(Stack::Entry(Stack::Entry::RELEASE, key));
});
Xml_node curr_node = _xml_by_path(config);
if (ev.type() == Input::Event::PRESS) {
ev.handle_press([&] (Input::Keycode key, Codepoint) {
Stack::Entry const entry(Stack::Entry::PRESS, ev.keycode());
Stack::Entry const entry(Stack::Entry::PRESS, key);
_execute_action(_matching_sub_node(curr_node, entry), func);
_stack.push(entry);
}
});
if (ev.type() == Input::Event::RELEASE) {
ev.handle_release([&] (Input::Keycode key) {
Stack::Entry const entry(Stack::Entry::RELEASE, ev.keycode());
Stack::Entry const entry(Stack::Entry::RELEASE, key);
Xml_node const next_node = _matching_sub_node(curr_node, entry);
@ -239,10 +239,10 @@ class Floating_window_layouter::Key_sequence_tracker
} else {
Stack::Entry entry(Stack::Entry::PRESS, ev.keycode());
Stack::Entry entry(Stack::Entry::PRESS, key);
_stack.flush(entry);
}
}
});
}
};

View File

@ -75,13 +75,22 @@ class Floating_window_layouter::User_state
Focus_history &_focus_history;
/*
* Return true if key is potentially part of a key sequence
*/
static bool _key(Input::Keycode key) { return key != Input::BTN_LEFT; }
bool _key(Input::Event const &ev) const
{
if (ev.type() != Input::Event::PRESS
&& ev.type() != Input::Event::RELEASE)
return false;
bool relevant = false;
return ev.keycode() != Input::BTN_LEFT;
ev.handle_press([&] (Input::Keycode key, Codepoint) {
relevant |= _key(key); });
ev.handle_release([&] (Input::Keycode key) {
relevant |= _key(key); });
return relevant;
}
inline void _handle_event(Input::Event const &, Xml_node);
@ -214,10 +223,10 @@ class Floating_window_layouter::User_state
void Floating_window_layouter::User_state::_handle_event(Input::Event const &e,
Xml_node config)
{
if (e.type() == Input::Event::MOTION
|| e.type() == Input::Event::FOCUS) {
e.handle_absolute_motion([&] (int x, int y) {
_pointer_curr = Point(x, y); });
_pointer_curr = Point(e.ax(), e.ay());
if (e.absolute_motion() || e.focus_enter()) {
if (_drag_state && _drag_init_done)
_operations.drag(_dragged_window_id, _dragged_element,
@ -225,13 +234,11 @@ void Floating_window_layouter::User_state::_handle_event(Input::Event const &e,
}
/* track number of pressed buttons/keys */
if (e.type() == Input::Event::PRESS) _key_cnt++;
if (e.type() == Input::Event::RELEASE) _key_cnt--;
if (e.press()) _key_cnt++;
if (e.release()) _key_cnt--;
/* handle pointer click */
if (e.type() == Input::Event::PRESS
&& e.keycode() == Input::BTN_LEFT
&& _key_cnt == 1) {
if (e.key_press(Input::BTN_LEFT) && _key_cnt == 1) {
/*
* Initiate drag operation if possible
@ -266,9 +273,7 @@ void Floating_window_layouter::User_state::_handle_event(Input::Event const &e,
}
/* detect end of drag operation */
if (e.type() == Input::Event::RELEASE
&& _key_cnt == 0
&& _dragged_window_id.valid()) {
if (e.release() && _key_cnt == 0 && _dragged_window_id.valid()) {
_drag_state = false;
@ -288,7 +293,7 @@ void Floating_window_layouter::User_state::_handle_event(Input::Event const &e,
/* handle key sequences */
if (_key(e)) {
if (e.type() == Input::Event::PRESS && _key_cnt == 1)
if (e.press() && _key_cnt == 1)
_key_sequence_tracker.reset();
_key_sequence_tracker.apply(e, config, [&] (Action action) {
@ -320,7 +325,7 @@ void Floating_window_layouter::User_state::_handle_event(Input::Event const &e,
}
/* update focus history after key/button action is completed */
if (e.type() == Input::Event::RELEASE && _key_cnt == 0)
if (e.release() && _key_cnt == 0)
_focus_history.focus(_focused_window_id);
}

View File

@ -169,7 +169,7 @@ class Launcher::Context_dialog : Input_event_handler, Dialog_generator,
*/
bool handle_input_event(Input::Event const &ev) override
{
if (ev.type() == Input::Event::MOTION) {
if (ev.absolute_motion()) {
/*
* Re-enable the visibility of the menu if we detect motion
@ -182,17 +182,15 @@ class Launcher::Context_dialog : Input_event_handler, Dialog_generator,
return true;
}
if (ev.type() == Input::Event::LEAVE) {
if (ev.hover_leave()) {
visible(false);
return true;
}
if (ev.type() == Input::Event::PRESS) _key_cnt++;
if (ev.type() == Input::Event::RELEASE) _key_cnt--;
if (ev.press()) _key_cnt++;
if (ev.release()) _key_cnt--;
if (ev.type() == Input::Event::PRESS
&& ev.keycode() == Input::BTN_LEFT
&& _key_cnt == 1) {
if (ev.key_press(Input::BTN_LEFT) && _key_cnt == 1) {
Label const hovered = _hovered();
@ -202,8 +200,7 @@ class Launcher::Context_dialog : Input_event_handler, Dialog_generator,
dialog_changed();
}
if (ev.type() == Input::Event::RELEASE
&& _click_in_progress && _key_cnt == 0) {
if (ev.release() && _click_in_progress && _key_cnt == 0) {
Label const hovered = _hovered();

View File

@ -137,8 +137,8 @@ void Launcher::Main::_handle_config()
void Launcher::Main::_handle_input()
{
_nitpicker.input()->for_each_event([&] (Input::Event const &e) {
if (e.type() == Input::Event::PRESS) _key_cnt++;
if (e.type() == Input::Event::RELEASE) _key_cnt--;
if (e.press()) _key_cnt++;
if (e.release()) _key_cnt--;
/*
* The _key_cnt can become 2 only when the global key (as configured
@ -146,11 +146,8 @@ void Launcher::Main::_handle_input()
* Hence, the following condition triggers on key combinations with
* the global modifier key, whatever the global modifier key is.
*/
if (e.type() == Input::Event::PRESS && _key_cnt == 2) {
if (e.keycode() == Input::KEY_TAB)
_panel_dialog.focus_next();
}
if (e.key_press(Input::KEY_TAB) && _key_cnt == 2)
_panel_dialog.focus_next();
});
}

View File

@ -185,12 +185,12 @@ class Launcher::Menu_dialog : Input_event_handler, Dialog_generator,
*/
bool handle_input_event(Input::Event const &ev) override
{
if (ev.type() == Input::Event::LEAVE) {
if (ev.hover_leave()) {
_response_handler.handle_menu_leave();
return false;
}
if (ev.type() == Input::Event::MOTION) {
if (ev.absolute_motion()) {
_response_handler.handle_menu_motion();
@ -205,15 +205,11 @@ class Launcher::Menu_dialog : Input_event_handler, Dialog_generator,
return true;
}
if (ev.type() == Input::Event::PRESS) _key_cnt++;
if (ev.type() == Input::Event::RELEASE) _key_cnt--;
if (ev.press()) _key_cnt++;
if (ev.release()) _key_cnt--;
if (ev.type() == Input::Event::PRESS
&& ev.keycode() == Input::BTN_LEFT
&& _key_cnt == 1) {
_response_handler.handle_selection(_hovered());
}
if (ev.key_press(Input::BTN_LEFT) && _key_cnt == 1)
_response_handler.handle_selection(_hovered());
return false;
}

View File

@ -345,7 +345,7 @@ class Launcher::Panel_dialog : Input_event_handler, Dialog_generator,
*/
bool handle_input_event(Input::Event const &ev) override
{
if (ev.type() == Input::Event::LEAVE) {
if (ev.hover_leave()) {
/*
* Let menu dialog disappear when the panel is unhovered. One
@ -362,15 +362,13 @@ class Launcher::Panel_dialog : Input_event_handler, Dialog_generator,
return true;
}
if (ev.type() == Input::Event::MOTION)
if (ev.absolute_motion())
return true;
if (ev.type() == Input::Event::PRESS) _key_cnt++;
if (ev.type() == Input::Event::RELEASE) _key_cnt--;
if (ev.press()) _key_cnt++;
if (ev.release()) _key_cnt--;
if (ev.type() == Input::Event::PRESS
&& ev.keycode() == Input::BTN_LEFT
&& _key_cnt == 1) {
if (ev.key_press(Input::BTN_LEFT) && _key_cnt == 1) {
_context_dialog.visible(false);
@ -412,9 +410,7 @@ class Launcher::Panel_dialog : Input_event_handler, Dialog_generator,
/*
* Open context dialog on right click
*/
if (ev.type() == Input::Event::PRESS
&& ev.keycode() == Input::BTN_RIGHT
&& _key_cnt == 1) {
if (ev.key_press(Input::BTN_RIGHT) && _key_cnt == 1) {
Element *hovered = _hovered();
@ -422,8 +418,7 @@ class Launcher::Panel_dialog : Input_event_handler, Dialog_generator,
_open_context_dialog(hovered->label);
}
if (ev.type() == Input::Event::RELEASE
&& _click_in_progress && _key_cnt == 0) {
if (ev.release() && _click_in_progress && _key_cnt == 0) {
Element *hovered = _hovered();

View File

@ -234,9 +234,9 @@ void Menu_view::Main::_handle_config()
void Menu_view::Main::_handle_input()
{
_nitpicker.input()->for_each_event([&] (Input::Event const &ev) {
if (ev.absolute_motion()) {
ev.handle_absolute_motion([&] (int x, int y) {
Point const at = Point(ev.ax(), ev.ay()) - _position;
Point const at = Point(x, y) - _position;
Widget::Unique_id const new_hovered = _root_widget.hovered(at);
if (_hovered != new_hovered) {
@ -249,14 +249,12 @@ void Menu_view::Main::_handle_input()
_hovered = new_hovered;
}
}
});
/*
* Reset hover model when losing the focus
*/
if ((ev.type() == Input::Event::FOCUS && ev.code() == 0)
|| (ev.type() == Input::Event::LEAVE)) {
if (ev.focus_leave() || ev.hover_leave()) {
_hovered = Widget::Unique_id();
if (_hover_reporter.enabled()) {

View File

@ -220,11 +220,30 @@ void Terminal::Main::_handle_input()
{
_input.for_each_event([&] (Input::Event const &event) {
if (event.type() == Input::Event::CHARACTER) {
Input::Event::Utf8 const utf8 = event.utf8();
event.handle_press([&] (Input::Keycode, Codepoint codepoint) {
char const sequence[] { (char)utf8.b0, (char)utf8.b1,
(char)utf8.b2, (char)utf8.b3, 0 };
struct Utf8 { char b0, b1, b2, b3, b4; };
auto utf8_from_codepoint = [] (unsigned c) {
/* extract 'n' bits 'at' bit position of value 'c' */
auto bits = [c] (unsigned at, unsigned n) {
return (c >> at) & ((1 << n) - 1); };
return (c < 2<<7) ? Utf8 { char(bits( 0, 7)), 0, 0, 0, 0 }
: (c < 2<<11) ? Utf8 { char(bits( 6, 5) | 0xc0),
char(bits( 0, 6) | 0x80), 0, 0, 0 }
: (c < 2<<16) ? Utf8 { char(bits(12, 4) | 0xe0),
char(bits( 6, 6) | 0x80),
char(bits( 0, 6) | 0x80), 0, 0 }
: (c < 2<<21) ? Utf8 { char(bits(18, 3) | 0xf0),
char(bits(12, 6) | 0x80),
char(bits( 6, 6) | 0x80),
char(bits( 0, 6) | 0x80), 0 }
: Utf8 { };
};
Utf8 const sequence = utf8_from_codepoint(codepoint.value);
/* function-key unicodes */
enum {
@ -241,8 +260,6 @@ void Terminal::Main::_handle_input()
CODEPOINT_PAGEUP = 0xf72c, CODEPOINT_PAGEDOWN = 0xf72d,
};
Codepoint const codepoint = Utf8_ptr(sequence).codepoint();
char const *special_sequence = nullptr;
switch (codepoint.value) {
case CODEPOINT_UP: special_sequence = "\EOA"; break;
@ -272,8 +289,8 @@ void Terminal::Main::_handle_input()
if (special_sequence)
_read_buffer.add(special_sequence);
else
_read_buffer.add(sequence);
}
_read_buffer.add(&sequence.b0);
});
});
}

View File

@ -225,18 +225,18 @@ struct Wm::Decorator_nitpicker_session : Genode::Rpc_object<Nitpicker::Session>,
while (_nitpicker_session.input()->pending())
_nitpicker_session.input()->for_each_event([&] (Input::Event const &ev) {
if (ev.type() == Input::Event::MOTION) {
ev.handle_absolute_motion([&] (int x, int y) {
_last_motion = LAST_MOTION_DECORATOR;
Reporter::Xml_generator xml(_pointer_reporter, [&] ()
{
xml.attribute("xpos", ev.ax());
xml.attribute("ypos", ev.ay());
xml.attribute("xpos", x);
xml.attribute("ypos", y);
});
}
});
if (ev.type() == Input::Event::LEAVE) {
if (ev.hover_leave()) {
/*
* Invalidate pointer as reported to the decorator if the

View File

@ -451,6 +451,8 @@ class Wm::Nitpicker::Session_component : public Rpc_object<Nitpicker::Session>,
Area _requested_size;
bool _resize_requested = false;
bool _has_alpha = false;
Point const _initial_pointer_pos { -1, -1 };
Point _pointer_pos = _initial_pointer_pos;
/*
* Command buffer
@ -492,34 +494,14 @@ class Wm::Nitpicker::Session_component : public Rpc_object<Nitpicker::Session>,
/**
* Translate input event to the client's coordinate system
*/
Input::Event _translate_event(Input::Event const ev, Point const input_origin)
Input::Event _translate_event(Input::Event ev, Point const origin)
{
switch (ev.type()) {
ev.handle_absolute_motion([&] (int x, int y) {
Point p = Point(x, y) + origin;
ev = Input::Absolute_motion{p.x(), p.y()};
});
case Input::Event::MOTION:
case Input::Event::PRESS:
case Input::Event::RELEASE:
case Input::Event::FOCUS:
case Input::Event::LEAVE:
{
Point abs_pos = Point(ev.ax(), ev.ay()) + input_origin;
return Input::Event(ev.type(), ev.code(),
abs_pos.x(), abs_pos.y(), 0, 0);
}
case Input::Event::TOUCH:
case Input::Event::CHARACTER:
case Input::Event::WHEEL:
{
Point abs_pos = Point(ev.ax(), ev.ay()) + input_origin;
return Input::Event(ev.type(), ev.code(),
abs_pos.x(), abs_pos.y(), ev.rx(), ev.ry());
}
case Input::Event::INVALID:
return ev;
}
return Input::Event();
return ev;
}
bool _click_into_unfocused_view(Input::Event const ev)
@ -530,7 +512,7 @@ class Wm::Nitpicker::Session_component : public Rpc_object<Nitpicker::Session>,
* Right now, we report more butten events to the layouter
* than the layouter really needs.
*/
if (ev.type() == Input::Event::PRESS && ev.keycode() == Input::BTN_LEFT)
if (ev.key_press(Input::BTN_LEFT))
return true;
return false;
@ -555,20 +537,24 @@ class Wm::Nitpicker::Session_component : public Rpc_object<Nitpicker::Session>,
Input::Event const ev = events[i];
/* keep track of pointer position */
ev.handle_absolute_motion([&] (int x, int y) {
_pointer_pos = Point(x, y); });
/* propagate layout-affecting events to the layouter */
if (_click_into_unfocused_view(ev))
_click_handler.handle_click(Point(ev.ax(), ev.ay()));
_click_handler.handle_click(_pointer_pos);
/*
* Reset pointer model for the decorator once the pointer
* enters the application area of a window.
*/
if (ev.type() == Input::Event::MOTION && _first_motion) {
_click_handler.handle_enter(Point(ev.ax(), ev.ay()));
if (ev.absolute_motion() && _first_motion) {
_click_handler.handle_enter(_pointer_pos);
_first_motion = false;
}
if (ev.type() == Input::Event::LEAVE)
if (ev.hover_leave())
_first_motion = true;
/* submit event to the client */
@ -1016,12 +1002,6 @@ class Wm::Nitpicker::Root : public Genode::Rpc_object<Genode::Typed_root<Session
Reporter &pointer_reporter;
Last_motion &last_motion;
void _submit_button_event(Input::Event::Type type, Nitpicker::Point pos)
{
window_layouter_input.submit(Input::Event(type, Input::BTN_LEFT,
pos.x(), pos.y(), 0, 0));
}
void handle_enter(Nitpicker::Point pos) override
{
last_motion = LAST_MOTION_NITPICKER;
@ -1049,8 +1029,9 @@ class Wm::Nitpicker::Root : public Genode::Rpc_object<Genode::Typed_root<Session
* Supply artificial mouse click to the decorator's input session
* (which is routed to the layouter).
*/
_submit_button_event(Input::Event::PRESS, pos);
_submit_button_event(Input::Event::RELEASE, pos);
window_layouter_input.submit(Input::Absolute_motion{pos.x(), pos.y()});
window_layouter_input.submit(Input::Press{Input::BTN_LEFT});
window_layouter_input.submit(Input::Release{Input::BTN_LEFT});
}
Click_handler(Input::Session_component &window_layouter_input,

View File

@ -185,6 +185,7 @@ proc drivers_start_nodes { feature_arg } {
if { [use_input_filter feature] } {
exec cp -f [genode_dir]/repos/os/src/server/input_filter/[language_chargen].chargen bin/
exec cp -f [genode_dir]/repos/os/src/server/input_filter/special.chargen bin/
append start_nodes {
<start name="input_filter">
@ -222,6 +223,7 @@ proc drivers_start_nodes { feature_arg } {
append start_nodes "
<include rom=\"[language_chargen].chargen\"/>"
append start_nodes {
<include rom="special.chargen"/>
</chargen>
</output>
</config>
@ -310,6 +312,7 @@ proc drivers_boot_modules { feature_arg } {
lappend_if [use_gpio_drv feature] boot_modules [gpio_drv]
lappend_if [use_input_filter feature] boot_modules input_filter
lappend_if [use_input_filter feature] boot_modules [language_chargen].chargen
lappend_if [use_input_filter feature] boot_modules special.chargen
lappend_if [use_nic_drv feature] boot_modules [nic_drv_binary]
lappend_if [use_ps2_drv feature] boot_modules ps2_drv
lappend_if [use_timer feature] boot_modules timer

View File

@ -377,12 +377,10 @@ struct Main
void _handle_input()
{
_input.for_each_event([&] (Input::Event const &ev) {
if (ev.type() == Input::Event::PRESS) {
int const ascii = keycode_to_ascii(ev.code());
ev.handle_press([&] (Input::Keycode key, Genode::Codepoint) {
int const ascii = keycode_to_ascii(key);
if (ascii) { _pdf_view.handle_key(ascii); }
}
});
});
}

View File

@ -24,15 +24,15 @@
void Control_bar::_rewind()
{
/* mouse click at horizontal position 0 */
_input.submit(Input::Event(Input::Event::PRESS, Input::BTN_LEFT, 0, 0, 0, 0));
_input.submit(Input::Event(Input::Event::RELEASE, Input::BTN_LEFT, 0, 0, 0, 0));
_input.submit(Input::Press {Input::BTN_LEFT});
_input.submit(Input::Release{Input::BTN_LEFT});
}
void Control_bar::_pause_resume()
{
_input.submit(Input::Event(Input::Event::PRESS, Input::KEY_SPACE, 0, 0, 0, 0));
_input.submit(Input::Event(Input::Event::RELEASE, Input::KEY_SPACE, 0, 0, 0, 0));
_input.submit(Input::Press {Input::KEY_SPACE});
_input.submit(Input::Release{Input::KEY_SPACE});
_playing = !_playing;
if (_playing)

View File

@ -53,130 +53,133 @@ void QNitpickerPlatformWindow::_process_touch_events(QList<Input::Event> const &
QList<QWindowSystemInterface::TouchPoint> touch_points;
for (QList<Input::Event>::const_iterator i = events.begin(); i != events.end(); ++i) {
/*
* Coordinates must be normalized to positions of the platform window.
* We lack information about the value ranges (min and max) of touch
* coordinates to normalize ourselves.
*/
QPointF const pos((qreal)i->ax(), (qreal)i->ay() );
i->handle_touch([&] (Input::Touch_id id, int x, int y) {
QWindowSystemInterface::TouchPoint &otp = _touch_points[i->code()];
QWindowSystemInterface::TouchPoint tp;
if (id.value >= _touch_points.size()) {
Genode::warning("drop touch input, out of bounds");
return;
}
tp.id = i->code();
tp.area = QRectF(QPointF(0, 0), QSize(1, 1));
QWindowSystemInterface::TouchPoint &otp = _touch_points[id.value];
QWindowSystemInterface::TouchPoint tp;
/* report 1x1 rectangular area centered at screen coordinates */
tp.area.moveCenter(QPointF(i->ax(), i->ay()));
tp.id = id.value;
tp.area = QRectF(QPointF(0, 0), QSize(1, 1));
/* report 1x1 rectangular area centered at screen coordinates */
tp.area.moveCenter(QPointF(x, y));
if (i->rx() == -1 && i->ry() == -1) {
tp.state = Qt::TouchPointReleased;
tp.pressure = 0;
} else {
tp.state = otp.state == Qt::TouchPointReleased
? Qt::TouchPointPressed : Qt::TouchPointMoved;
tp.pressure = 1;
}
otp = tp;
touch_points.push_back(tp);
otp = tp;
touch_points.push_back(tp);
});
i->handle_touch_release([&] (Input::Touch_id id) {
if (id.value >= _touch_points.size()) {
Genode::warning("drop touch input, out of bounds");
return;
}
QWindowSystemInterface::TouchPoint &otp = _touch_points[id.value];
QWindowSystemInterface::TouchPoint tp;
tp.id = id.value;
tp.area = QRectF(QPointF(0, 0), QSize(1, 1));
tp.state = Qt::TouchPointReleased;
tp.pressure = 0;
otp = tp;
touch_points.push_back(tp);
});
}
QWindowSystemInterface::handleTouchEvent(0, _touch_device, touch_points);
}
void QNitpickerPlatformWindow::_process_mouse_event(Input::Event const &ev)
static Qt::Key translate_keycode(Input::Keycode key)
{
QPoint global_position(ev.ax(), ev.ay());
QPoint local_position(global_position.x() - geometry().x(),
global_position.y() - geometry().y());
switch (ev.type()) {
case Input::Event::PRESS:
/* make this window the focused window */
requestActivateWindow();
switch (ev.code()) {
case Input::BTN_LEFT:
_mouse_button_state |= Qt::LeftButton;
break;
case Input::BTN_RIGHT:
_mouse_button_state |= Qt::RightButton;
break;
case Input::BTN_MIDDLE:
_mouse_button_state |= Qt::MidButton;
break;
case Input::BTN_SIDE:
_mouse_button_state |= Qt::XButton1;
break;
case Input::BTN_EXTRA:
_mouse_button_state |= Qt::XButton2;
break;
}
break;
case Input::Event::RELEASE:
switch (ev.code()) {
case Input::BTN_LEFT:
_mouse_button_state &= ~Qt::LeftButton;
break;
case Input::BTN_RIGHT:
_mouse_button_state &= ~Qt::RightButton;
break;
case Input::BTN_MIDDLE:
_mouse_button_state &= ~Qt::MidButton;
break;
case Input::BTN_SIDE:
_mouse_button_state &= ~Qt::XButton1;
break;
case Input::BTN_EXTRA:
_mouse_button_state &= ~Qt::XButton2;
break;
}
break;
case Input::Event::WHEEL:
QWindowSystemInterface::handleWheelEvent(window(),
local_position,
local_position,
ev.ry() * 120,
Qt::Vertical);
return;
default:
break;
}
QWindowSystemInterface::handleMouseEvent(window(),
local_position,
global_position,
_mouse_button_state);
}
void QNitpickerPlatformWindow::_process_key_event(Input::Event const &ev)
{
const bool pressed = (ev.type() == Input::Event::PRESS);
const int keycode = ev.code();
if (pressed) {
_last_keycode = keycode;
_key_repeat_timer->start(KEY_REPEAT_DELAY_MS);
} else
_key_repeat_timer->stop();
_keyboard_handler.processKeycode(keycode, pressed, false);
}
void QNitpickerPlatformWindow::_key_repeat()
{
_key_repeat_timer->start(KEY_REPEAT_RATE_MS);
_keyboard_handler.processKeycode(_last_keycode, true, true);
switch (key) {
case Input::KEY_ENTER: return Qt::Key_Return;
case Input::KEY_ESC: return Qt::Key_Escape;
case Input::KEY_TAB: return Qt::Key_Tab;
case Input::KEY_BACKSPACE: return Qt::Key_Backspace;
case Input::KEY_INSERT: return Qt::Key_Insert;
case Input::KEY_DELETE: return Qt::Key_Delete;
case Input::KEY_PRINT: return Qt::Key_Print;
case Input::KEY_CLEAR: return Qt::Key_Clear;
case Input::KEY_HOME: return Qt::Key_Home;
case Input::KEY_END: return Qt::Key_End;
case Input::KEY_LEFT: return Qt::Key_Left;
case Input::KEY_UP: return Qt::Key_Up;
case Input::KEY_RIGHT: return Qt::Key_Right;
case Input::KEY_DOWN: return Qt::Key_Down;
case Input::KEY_PAGEUP: return Qt::Key_PageUp;
case Input::KEY_PAGEDOWN: return Qt::Key_PageDown;
case Input::KEY_LEFTSHIFT: return Qt::Key_Shift;
case Input::KEY_LEFTCTRL: return Qt::Key_Control;
case Input::KEY_LEFTMETA: return Qt::Key_Meta;
case Input::KEY_LEFTALT: return Qt::Key_Alt;
case Input::KEY_RIGHTALT: return Qt::Key_AltGr;
case Input::KEY_CAPSLOCK: return Qt::Key_CapsLock;
case Input::KEY_F1: return Qt::Key_F1;
case Input::KEY_F2: return Qt::Key_F2;
case Input::KEY_F3: return Qt::Key_F3;
case Input::KEY_F4: return Qt::Key_F4;
case Input::KEY_F5: return Qt::Key_F5;
case Input::KEY_F6: return Qt::Key_F6;
case Input::KEY_F7: return Qt::Key_F7;
case Input::KEY_F8: return Qt::Key_F8;
case Input::KEY_F9: return Qt::Key_F9;
case Input::KEY_F10: return Qt::Key_F10;
case Input::KEY_F11: return Qt::Key_F11;
case Input::KEY_F12: return Qt::Key_F12;
case Input::KEY_SPACE: return Qt::Key_Space;
case Input::KEY_0: return Qt::Key_0;
case Input::KEY_1: return Qt::Key_1;
case Input::KEY_2: return Qt::Key_2;
case Input::KEY_3: return Qt::Key_3;
case Input::KEY_4: return Qt::Key_4;
case Input::KEY_5: return Qt::Key_5;
case Input::KEY_6: return Qt::Key_6;
case Input::KEY_7: return Qt::Key_7;
case Input::KEY_8: return Qt::Key_8;
case Input::KEY_9: return Qt::Key_9;
case Input::KEY_A: return Qt::Key_A;
case Input::KEY_B: return Qt::Key_B;
case Input::KEY_C: return Qt::Key_C;
case Input::KEY_D: return Qt::Key_D;
case Input::KEY_E: return Qt::Key_E;
case Input::KEY_F: return Qt::Key_F;
case Input::KEY_G: return Qt::Key_G;
case Input::KEY_H: return Qt::Key_H;
case Input::KEY_I: return Qt::Key_I;
case Input::KEY_J: return Qt::Key_J;
case Input::KEY_K: return Qt::Key_K;
case Input::KEY_L: return Qt::Key_L;
case Input::KEY_M: return Qt::Key_M;
case Input::KEY_N: return Qt::Key_N;
case Input::KEY_O: return Qt::Key_O;
case Input::KEY_P: return Qt::Key_P;
case Input::KEY_Q: return Qt::Key_Q;
case Input::KEY_R: return Qt::Key_R;
case Input::KEY_S: return Qt::Key_S;
case Input::KEY_T: return Qt::Key_T;
case Input::KEY_U: return Qt::Key_U;
case Input::KEY_V: return Qt::Key_V;
case Input::KEY_W: return Qt::Key_W;
case Input::KEY_X: return Qt::Key_X;
case Input::KEY_Y: return Qt::Key_Y;
case Input::KEY_Z: return Qt::Key_Z;
case Input::KEY_BACK: return Qt::Key_Back;
case Input::KEY_FORWARD: return Qt::Key_Forward;
default: break;
};
return Qt::Key_unknown;
}
@ -186,55 +189,106 @@ void QNitpickerPlatformWindow::_handle_input(unsigned int)
_input_session.for_each_event([&] (Input::Event const &event) {
bool const is_key_event = event.type() == Input::Event::PRESS ||
event.type() == Input::Event::RELEASE;
QPoint const orig_mouse_position = _mouse_position;
Qt::MouseButtons const orig_mouse_button_state = _mouse_button_state;
bool const is_mouse_button_event =
is_key_event && (event.code() == Input::BTN_LEFT ||
event.code() == Input::BTN_MIDDLE ||
event.code() == Input::BTN_RIGHT);
event.handle_absolute_motion([&] (int x, int y) {
_mouse_position = QPoint(x, y); });
if (event.type() == Input::Event::MOTION ||
event.type() == Input::Event::WHEEL ||
is_mouse_button_event) {
event.handle_press([&] (Input::Keycode key, Genode::Codepoint codepoint) {
_process_mouse_event(event);
} else if (event.type() == Input::Event::TOUCH) {
touch_events.push_back(event);
} else if (event.type() == Input::Event::CHARACTER) {
Input::Event::Utf8 const utf8 = event.utf8();
if ((utf8.b0 >= 1) && (utf8.b0 <= 26)) {
/* Ctrl-A .. Ctrl-Z */
QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyPress,
Qt::Key_A + (utf8.b0 - 1),
Qt::ControlModifier);
QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyRelease,
Qt::Key_A + (utf8.b0 - 1),
Qt::ControlModifier);
} else {
char const utf8_string[] = { (char)utf8.b0, (char)utf8.b1,
(char)utf8.b2, (char)utf8.b3,
'\0' };
QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyPress, 0, 0,
QString::fromUtf8(utf8_string));
QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyRelease, 0, 0,
QString::fromUtf8(utf8_string));
switch (key) {
case Input::BTN_LEFT: _mouse_button_state |= Qt::LeftButton; break;
case Input::BTN_RIGHT: _mouse_button_state |= Qt::RightButton; break;
case Input::BTN_MIDDLE: _mouse_button_state |= Qt::MidButton; break;
case Input::BTN_SIDE: _mouse_button_state |= Qt::XButton1; break;
case Input::BTN_EXTRA: _mouse_button_state |= Qt::XButton2; break;
default: break;
}
} else if (is_key_event && (event.code() < 128)) {
/* on mouse click, make this window the focused window */
if (_mouse_button_state != orig_mouse_button_state)
requestActivateWindow();
_process_key_event(event);
QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyPress,
translate_keycode(key), 0,
QString() + QChar(codepoint.value));
});
/* handle repeat of special keys */
event.handle_repeat([&] (Genode::Codepoint codepoint) {
/* function-key unicodes */
enum {
CODEPOINT_UP = 0xf700, CODEPOINT_DOWN = 0xf701,
CODEPOINT_LEFT = 0xf702, CODEPOINT_RIGHT = 0xf703,
CODEPOINT_HOME = 0xf729, CODEPOINT_INSERT = 0xf727,
CODEPOINT_DELETE = 0xf728, CODEPOINT_END = 0xf72b,
CODEPOINT_PAGEUP = 0xf72c, CODEPOINT_PAGEDOWN = 0xf72d,
CODEPOINT_BACKSPACE = 8, CODEPOINT_LINEFEED = 10,
};
Qt::Key repeated_key = Qt::Key_unknown;
switch (codepoint.value) {
case CODEPOINT_UP: repeated_key = Qt::Key_Up; break;
case CODEPOINT_DOWN: repeated_key = Qt::Key_Down; break;
case CODEPOINT_LEFT: repeated_key = Qt::Key_Left; break;
case CODEPOINT_RIGHT: repeated_key = Qt::Key_Right; break;
case CODEPOINT_HOME: repeated_key = Qt::Key_Home; break;
case CODEPOINT_INSERT: repeated_key = Qt::Key_Insert; break;
case CODEPOINT_DELETE: repeated_key = Qt::Key_Delete; break;
case CODEPOINT_END: repeated_key = Qt::Key_End; break;
case CODEPOINT_PAGEUP: repeated_key = Qt::Key_PageUp; break;
case CODEPOINT_PAGEDOWN: repeated_key = Qt::Key_PageDown; break;
case CODEPOINT_BACKSPACE: repeated_key = Qt::Key_Backspace; break;
case CODEPOINT_LINEFEED: repeated_key = Qt::Key_Return; break;
default: return /* from lambda */;
};
/*
* A key repeat is triggered while a key is already pressed. We
* respond to it by simulating a tempoary release of the key.
*/
QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyRelease,
repeated_key, 0, QString());
QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyPress,
repeated_key, 0, QString());
});
event.handle_release([&] (Input::Keycode key) {
switch (key) {
case Input::BTN_LEFT: _mouse_button_state &= ~Qt::LeftButton; break;
case Input::BTN_RIGHT: _mouse_button_state &= ~Qt::RightButton; break;
case Input::BTN_MIDDLE: _mouse_button_state &= ~Qt::MidButton; break;
case Input::BTN_SIDE: _mouse_button_state &= ~Qt::XButton1; break;
case Input::BTN_EXTRA: _mouse_button_state &= ~Qt::XButton2; break;
default: break;
}
QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyRelease,
translate_keycode(key),
0, QString());
});
event.handle_wheel([&] (int x, int y) {
QWindowSystemInterface::handleWheelEvent(window(),
_local_position(),
_local_position(),
y * 120,
Qt::Vertical); });
if (_mouse_button_state != orig_mouse_button_state
|| _mouse_position != orig_mouse_position) {
QWindowSystemInterface::handleMouseEvent(window(),
_local_position(),
_mouse_position,
_mouse_button_state);
}
if (event.touch() || event.touch_release())
touch_events.push_back(event);
});
/* process all gathered touch events */
@ -338,12 +392,9 @@ QNitpickerPlatformWindow::QNitpickerPlatformWindow(Genode::Env &env, QWindow *wi
_view_handle(_create_view()),
_input_session(env.rm(), _nitpicker_session.input_session()),
_ev_buf(env.rm(), _input_session.dataspace()),
_keyboard_handler("", _evdevkeyboard_fd, false, false, ""),
_resize_handle(!window->flags().testFlag(Qt::Popup)),
_decoration(!window->flags().testFlag(Qt::Popup)),
_egl_surface(EGL_NO_SURFACE),
_key_repeat_timer(this),
_last_keycode(0),
_input_signal_dispatcher(_signal_receiver, *this,
&QNitpickerPlatformWindow::_input),
_mode_changed_signal_dispatcher(_signal_receiver, *this,
@ -375,9 +426,6 @@ QNitpickerPlatformWindow::QNitpickerPlatformWindow(Genode::Env &env, QWindow *wi
connect(this, SIGNAL(_mode_changed(unsigned int)),
this, SLOT(_handle_mode_changed(unsigned int)),
Qt::QueuedConnection);
connect(_key_repeat_timer, SIGNAL(timeout()),
this, SLOT(_key_repeat()));
}
QWindow *QNitpickerPlatformWindow::window() const

View File

@ -39,11 +39,6 @@ class QNitpickerPlatformWindow : public QObject, public QPlatformWindow
private:
enum {
KEY_REPEAT_DELAY_MS = 500, /* 500 ms delay before first repetition */
KEY_REPEAT_RATE_MS = 50 /* 50 ms delay between repetitions */
};
Genode::Env &_env;
Nitpicker::Connection _nitpicker_session;
Framebuffer::Session_client _framebuffer_session;
@ -55,15 +50,18 @@ class QNitpickerPlatformWindow : public QObject, public QPlatformWindow
Nitpicker::Session::View_handle _view_handle;
Input::Session_client _input_session;
Genode::Attached_dataspace _ev_buf;
QPoint _mouse_position;
Qt::MouseButtons _mouse_button_state;
QFdContainer _evdevkeyboard_fd { -1 };
QEvdevKeyboardHandler _keyboard_handler;
QByteArray _title;
bool _resize_handle;
bool _decoration;
EGLSurface _egl_surface;
QMember<QTimer> _key_repeat_timer;
int _last_keycode;
QPoint _local_position() const
{
return QPoint(_mouse_position.x() - geometry().x(),
_mouse_position.y() - geometry().y());
}
Genode::Signal_dispatcher<QNitpickerPlatformWindow> _input_signal_dispatcher;
Genode::Signal_dispatcher<QNitpickerPlatformWindow> _mode_changed_signal_dispatcher;
@ -72,8 +70,6 @@ class QNitpickerPlatformWindow : public QObject, public QPlatformWindow
QTouchDevice *_touch_device;
QTouchDevice * _init_touch_device();
void _process_mouse_event(Input::Event const &ev);
void _process_key_event(Input::Event const &ev);
void _process_touch_events(QList<Input::Event> const &events);
Nitpicker::Session::View_handle _create_view();
@ -83,7 +79,6 @@ class QNitpickerPlatformWindow : public QObject, public QPlatformWindow
void _handle_input(unsigned int);
void _handle_mode_changed(unsigned int);
void _key_repeat();
Q_SIGNALS:

View File

@ -77,13 +77,13 @@ extern "C" {
static int buttonmap[KEYNUM_MAX];
inline SDL_keysym *Genode_Fb_TranslateKey(int keycode, SDL_keysym *k)
inline SDL_keysym Genode_Fb_TranslateKey(Input::Keycode keycode,
Genode::Codepoint codepoint)
{
k->scancode = keycode;
k->sym = keymap[keycode];
k->mod = SDL_GetModState();
k->unicode = keymap[keycode];
return k;
return SDL_keysym { .scancode = (uint8_t)keycode,
.sym = keymap[keycode],
.mod = SDL_GetModState(),
.unicode = (uint16_t)codepoint.value };
}
@ -101,43 +101,39 @@ extern "C" {
return;
input->for_each_event([&] (Input::Event const &curr) {
SDL_keysym ksym;
switch(curr.type())
{
case Input::Event::MOTION:
if (curr.absolute_motion())
SDL_PrivateMouseMotion(0, 0, curr.ax(), curr.ay());
else
SDL_PrivateMouseMotion(0, 1, curr.rx(), curr.ry());
break;
case Input::Event::PRESS:
if(curr.code() >= Input::BTN_MISC &&
curr.code() <= Input::BTN_GEAR_UP)
SDL_PrivateMouseButton(SDL_PRESSED,
buttonmap[curr.code()],
0, 0);
else
SDL_PrivateKeyboard(SDL_PRESSED,
Genode_Fb_TranslateKey(curr.code(),
&ksym));
break;
case Input::Event::RELEASE:
if(curr.code() >= Input::BTN_MISC &&
curr.code() <= Input::BTN_GEAR_UP)
SDL_PrivateMouseButton(SDL_RELEASED,
buttonmap[curr.code()],
0, 0);
else
SDL_PrivateKeyboard(SDL_RELEASED,
Genode_Fb_TranslateKey(curr.code(),
&ksym));
break;
case Input::Event::WHEEL:
Genode::warning("mouse wheel, not implemented yet");
break;
default:
break;
}
curr.handle_absolute_motion([&] (int x, int y) {
SDL_PrivateMouseMotion(0, 0, x, y); });
curr.handle_relative_motion([&] (int x, int y) {
SDL_PrivateMouseMotion(0, 1, x, y); });
/* return true if keycode refers to a button */
auto mouse_button = [] (Input::Keycode key) {
return key >= Input::BTN_MISC && key <= Input::BTN_GEAR_UP; };
curr.handle_press([&] (Input::Keycode key, Genode::Codepoint codepoint) {
if (mouse_button(key))
SDL_PrivateMouseButton(SDL_PRESSED, buttonmap[key], 0, 0);
else {
SDL_keysym ksym = Genode_Fb_TranslateKey(key, codepoint);
SDL_PrivateKeyboard(SDL_PRESSED, &ksym);
}
});
curr.handle_release([&] (Input::Keycode key) {
if (mouse_button(key))
SDL_PrivateMouseButton(SDL_RELEASED, buttonmap[key], 0, 0);
else {
Genode::Codepoint const invalid { Genode::Codepoint::INVALID };
SDL_keysym ksym = Genode_Fb_TranslateKey(key, invalid);
SDL_PrivateKeyboard(SDL_RELEASED, &ksym);
}
});
});
}

View File

@ -298,12 +298,11 @@ struct Transform::Main {
if (key->type() == Keys::Type::PRESS_RELEASE ||
key->type() == Keys::Type::PRESS)
_session.submit(Input::Event(Input::Event::PRESS, key->key_code(),
0, 0, 0, 0));
_session.submit(Input::Press{key->key_code()});
if (key->type() == Keys::Type::PRESS_RELEASE ||
key->type() == Keys::Type::RELEASE)
_session.submit(Input::Event(Input::Event::RELEASE,
key->key_code(), 0, 0, 0, 0));
_session.submit(Input::Release{key->key_code()});
}
void check_acpi_fixed()

View File

@ -14,127 +14,198 @@
#ifndef _INCLUDE__INPUT__EVENT_H_
#define _INCLUDE__INPUT__EVENT_H_
#include <base/output.h>
#include <input/keycodes.h>
#include <util/geometry.h>
#include <util/utf8.h>
namespace Input { class Event; }
namespace Input {
typedef Genode::Codepoint Codepoint;
struct Touch_id { int value; };
/*
* Event attributes
*/
struct Press { Keycode key; };
struct Press_char { Keycode key; Codepoint codepoint; };
struct Release { Keycode key; };
struct Wheel { int x, y; };
struct Focus_enter { };
struct Focus_leave { };
struct Hover_leave { };
struct Absolute_motion { int x, y; };
struct Relative_motion { int x, y; };
struct Touch { Touch_id id; float x, y; };
struct Touch_release { Touch_id id; };
class Event;
}
class Input::Event
{
public:
enum Type { INVALID, MOTION, PRESS, RELEASE, WHEEL, FOCUS, LEAVE, TOUCH,
CHARACTER };
private:
enum Type { INVALID, PRESS, RELEASE, REL_MOTION, ABS_MOTION, WHEEL,
FOCUS_ENTER, FOCUS_LEAVE, HOVER_LEAVE, TOUCH, TOUCH_RELEASE };
Type _type = INVALID;
/*
* For PRESS and RELEASE events, '_code' contains the key code.
* For FOCUS events, '_code' is set to 1 (focus) or 0 (unfocus).
*/
int _code = 0;
struct Attr
{
union {
Press_char press;
Release release;
Wheel wheel;
Absolute_motion abs_motion;
Relative_motion rel_motion;
Touch touch;
Touch_release touch_release;
};
} _attr { };
/*
* Absolute pointer position coordinates
*/
int _ax = 0, _ay = 0;
static bool _valid(Keycode key) { return key > KEY_RESERVED && key < KEY_MAX; }
/*
* Relative pointer motion vector
/**
* Return point representation of attribute 'a'
*/
int _rx = 0, _ry = 0;
template <typename R, typename T>
static Genode::Point<R> _xy(T const &a) { return Genode::Point<R>(a.x, a.y); }
public:
/**
* UTF8-encoded symbolic character
*/
struct Utf8
{
typedef unsigned char byte;
byte b0, b1, b2, b3;
Utf8(byte b0, byte b1 = 0, byte b2 = 0, byte b3 = 0)
: b0(b0), b1(b1), b2(b2), b3(b3) { }
};
/**
* Default constructor creates an invalid event
*
* This constructor can be used for creating an array of events.
*/
Event() { }
/**
* Constructor creates a low-level event
*/
Event(Type type, int code, int ax, int ay, int rx, int ry):
_type(type), _code(code),
_ax(ax), _ay(ay), _rx(rx), _ry(ry) { }
/**
* Constructor creates a symbolic character event
*/
Event(Utf8 const &utf8)
:
_type(CHARACTER),
_code(((unsigned)utf8.b3 << 24) | ((unsigned)utf8.b2 << 16) |
((unsigned)utf8.b1 << 8) | ((unsigned)utf8.b0 << 0))
{ }
/**
* Return event type
*/
Type type() const
{
/* prevent obnoxious events from being processed by clients */
if ((_type == PRESS || _type == RELEASE)
&& (_code <= KEY_RESERVED || _code >= KEY_UNKNOWN))
return INVALID;
return _type;
}
/**
* Accessors
*/
int code() const { return _code; }
int ax() const { return _ax; }
int ay() const { return _ay; }
int rx() const { return _rx; }
int ry() const { return _ry; }
/**
* Return symbolic character encoded as UTF8 byte sequence
*
* This method must only be called if type is CHARACTER.
*/
Utf8 utf8() const { return Utf8(_code, _code >> 8, _code >> 16, _code >> 24); }
/**
* Return key code for press/release events
*/
Keycode keycode() const
{
return _type == PRESS || _type == RELEASE ? (Keycode)_code : KEY_UNKNOWN;
}
bool absolute_motion() const { return _type == MOTION && !_rx && !_ry; }
bool relative_motion() const { return _type == MOTION && (_rx || _ry); }
bool touch_release() const { return _type == TOUCH && (_rx == -1) && (_ry == -1); }
/*
* \deprecated use methods without the 'is_' prefix instead
* Constructors for creating input events of various types
*
* These constructors can be used implicitly for the given attribute
* types for assignments or for passing an event as return value.
*/
bool is_absolute_motion() const { return absolute_motion(); }
bool is_relative_motion() const { return relative_motion(); }
bool is_touch_release() const { return touch_release(); }
Event(Press_char arg) : _type(PRESS) { _attr.press = arg; }
Event(Press arg) : Event(Press_char{arg.key, Codepoint{INVALID}}) { }
Event(Release arg) : _type(RELEASE) { _attr.release = arg; }
Event(Relative_motion arg) : _type(REL_MOTION) { _attr.rel_motion = arg; }
Event(Absolute_motion arg) : _type(ABS_MOTION) { _attr.abs_motion = arg; }
Event(Wheel arg) : _type(WHEEL) { _attr.wheel = arg; }
Event(Focus_enter) : _type(FOCUS_ENTER) { }
Event(Focus_leave) : _type(FOCUS_LEAVE) { }
Event(Hover_leave) : _type(HOVER_LEAVE) { }
Event(Touch arg) : _type(TOUCH) { _attr.touch = arg; }
Event(Touch_release arg) : _type(TOUCH_RELEASE) { _attr.touch_release = arg; }
static Event create_touch_event(int ax, int ay, int id, bool last = false)
/************************************
** Methods for handling the event **
************************************/
bool valid() const { return _type != INVALID; }
bool press() const { return _type == PRESS; }
bool release() const { return _type == RELEASE; }
bool absolute_motion() const { return _type == ABS_MOTION; }
bool relative_motion() const { return _type == REL_MOTION; }
bool wheel() const { return _type == WHEEL; }
bool focus_enter() const { return _type == FOCUS_ENTER; }
bool focus_leave() const { return _type == FOCUS_LEAVE; }
bool hover_leave() const { return _type == HOVER_LEAVE; }
bool touch() const { return _type == TOUCH; }
bool touch_release() const { return _type == TOUCH_RELEASE; }
bool key_press(Keycode key) const
{
return Event(Type::TOUCH, id, ax, ay, last ? -1 : 0, last ? -1 : 0);
return press() && _attr.press.key == key;
}
bool key_release(Keycode key) const
{
return release() && _attr.release.key == key;
}
template <typename FN>
void handle_press(FN const &fn) const
{
if (press() && _valid(_attr.press.key))
fn(_attr.press.key, _attr.press.codepoint);
}
template <typename FN>
void handle_repeat(FN const &fn) const
{
if (key_press(KEY_UNKNOWN) && _attr.press.codepoint.value)
fn(_attr.press.codepoint);
}
template <typename FN>
void handle_release(FN const &fn) const
{
if (release() && _valid(_attr.release.key))
fn(_attr.release.key);
}
template <typename FN>
void handle_relative_motion(FN const &fn) const
{
if (relative_motion())
fn(_attr.rel_motion.x, _attr.rel_motion.y);
}
template <typename FN>
void handle_absolute_motion(FN const &fn) const
{
if (absolute_motion())
fn(_attr.abs_motion.x, _attr.abs_motion.y);
}
template <typename FN>
void handle_wheel(FN const &fn) const
{
if (wheel())
fn(_attr.wheel.x, _attr.wheel.y);
}
template <typename FN>
void handle_touch(FN const &fn) const
{
if (touch())
fn(_attr.touch.id, _attr.touch.x, _attr.touch.y);
}
template <typename FN>
void handle_touch_release(FN const &fn) const
{
if (touch_release())
fn(_attr.touch_release.id);
}
inline void print(Genode::Output &out) const;
};
void Input::Event::print(Genode::Output &out) const
{
using Genode::print;
switch (_type) {
case INVALID: print(out, "INVALID"); break;
case PRESS: print(out, "PRESS ", key_name(_attr.press.key),
" ", _attr.press.codepoint.value); break;
case RELEASE: print(out, "RELEASE ", key_name(_attr.release.key)); break;
case REL_MOTION: print(out, "REL_MOTION ", _xy<int>(_attr.rel_motion)); break;
case ABS_MOTION: print(out, "ABS_MOTION ", _xy<int>(_attr.abs_motion)); break;
case WHEEL: print(out, "WHEEL ", _xy<int>(_attr.wheel)); break;
case FOCUS_ENTER: print(out, "FOCUS_ENTER"); break;
case FOCUS_LEAVE: print(out, "FOCUS_LEAVE"); break;
case HOVER_LEAVE: print(out, "HOVER_LEAVE"); break;
case TOUCH_RELEASE: print(out, "TOUCH_RELEASE ", _attr.touch.id.value); break;
case TOUCH: print(out, "TOUCH ", _attr.touch.id.value, " ",
_xy<float>(_attr.touch)); break;
};
}
#endif /* _INCLUDE__INPUT__EVENT_H_ */

View File

@ -184,17 +184,14 @@ append config {
<press code="KEY_A"/> <release code="KEY_A"/>
<release code="KEY_RIGHTSHIFT"/>
</usb>
<expect_press code="KEY_A"/>
<expect_char char="a"/>
<expect_press code="KEY_A" char="a"/>
<expect_release code="KEY_A"/>
<expect_press code="KEY_LEFTSHIFT"/>
<expect_press code="KEY_A"/>
<expect_char char="A"/>
<expect_press code="KEY_A" char="A"/>
<expect_release code="KEY_A"/>
<expect_release code="KEY_LEFTSHIFT"/>
<expect_press code="KEY_RIGHTSHIFT"/>
<expect_press code="KEY_A"/>
<expect_char char="A"/>
<expect_press code="KEY_A" char="A"/>
<expect_release code="KEY_A"/>
<expect_release code="KEY_RIGHTSHIFT"/>}
@ -219,13 +216,12 @@ append_if [test_char_repeat] config {
<!-- periodic characters should stop now -->
<sleep ms="1000"/>
<usb> <press code="KEY_B"/> <release code="KEY_B"/> </usb>
<expect_press code="KEY_A"/>
<expect_char char="a"/> <!-- original press (0 ms) -->
<expect_char char="a"/> <!-- character after delay (600 ms) -->
<expect_char char="a"/> <!-- periodic character (800 ms) -->
<expect_char char="a"/> <!-- periodic character (1000 ms) -->
<expect_char char="a"/> <!-- periodic character (1200 ms) -->
<expect_char char="a"/> <!-- periodic character (1400 ms) -->
<expect_press code="KEY_A" char="a"/> <!-- original press (0 ms) -->
<expect_press code="KEY_UNKNOWN" char="a"/> <!-- character after delay (600 ms) -->
<expect_press code="KEY_UNKNOWN" char="a"/> <!-- periodic character (800 ms) -->
<expect_press code="KEY_UNKNOWN" char="a"/> <!-- periodic character (1000 ms) -->
<expect_press code="KEY_UNKNOWN" char="a"/> <!-- periodic character (1200 ms) -->
<expect_press code="KEY_UNKNOWN" char="a"/> <!-- periodic character (1400 ms) -->
<expect_release code="KEY_A"/>
<expect_press code="KEY_B"/>
<expect_release code="KEY_B"/>}
@ -257,15 +253,15 @@ append config {
<capslock enabled="no"/>
<sleep ms="250"/>
<usb> <press code="KEY_A"/> <release code="KEY_A"/> </usb>
<expect_press code="KEY_A"/> <expect_char char="a"/> <expect_release code="KEY_A"/>
<expect_press code="KEY_A" char="a"/> <expect_release code="KEY_A"/>
<capslock enabled="yes"/>
<sleep ms="250"/>
<usb> <press code="KEY_A"/> <release code="KEY_A"/> </usb>
<expect_press code="KEY_A"/> <expect_char char="A"/> <expect_release code="KEY_A"/>
<expect_press code="KEY_A" char="A"/> <expect_release code="KEY_A"/>
<capslock enabled="no"/>
<sleep ms="250"/>
<usb> <press code="KEY_A"/> <release code="KEY_A"/> </usb>
<expect_press code="KEY_A"/> <expect_char char="a"/> <expect_release code="KEY_A"/>
<expect_press code="KEY_A" char="a"/> <expect_release code="KEY_A"/>
<message string="button-scroll feature"/>
@ -418,7 +414,7 @@ append config {
</filter_config>
<sleep ms="100"/>
<usb> <press code="KEY_A"/> <release code="KEY_A"/> </usb>
<expect_press code="KEY_A"/> <expect_char char="a"/> <expect_release code="KEY_A"/>
<expect_press code="KEY_A" char="a"/> <expect_release code="KEY_A"/>
<message string="update included chargen ROM"/>
@ -428,7 +424,7 @@ append config {
</chargen_include>
<sleep ms="100"/>
<usb> <press code="KEY_A"/> <release code="KEY_A"/> </usb>
<expect_press code="KEY_A"/> <expect_char char="b"/> <expect_release code="KEY_A"/>
<expect_press code="KEY_A" char="b"/> <expect_release code="KEY_A"/>
</config>
<route>

View File

@ -292,19 +292,15 @@ void Global_keys_handler::Main::_apply_input_events(unsigned num_ev,
Input::Event const &ev = events[i];
if (ev.type() != Input::Event::PRESS
&& ev.type() != Input::Event::RELEASE)
if (!ev.press() && !ev.release())
continue;
if (ev.type() == Input::Event::PRESS) _key_cnt++;
if (ev.type() == Input::Event::RELEASE) _key_cnt--;
if (ev.press()) _key_cnt++;
if (ev.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) {
@ -312,17 +308,24 @@ void Global_keys_handler::Main::_apply_input_events(unsigned num_ev,
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)
typedef String<32> Key_name;
Key_name const expected = node.attribute_value("name", Key_name());
bool key_matches = false;
if (node.has_type("press"))
ev.handle_press([&] (Input::Keycode key, Codepoint) {
key_matches = (expected == Input::key_name(key)); });
if (node.has_type("release"))
ev.handle_release([&] (Input::Keycode key) {
key_matches = (expected == Input::key_name(key)); });
if (!key_matches)
return;
/*

View File

@ -26,7 +26,7 @@
/**
* Convert SDL keycode to Genode keycode
*/
static long convert_keycode(int sdl_keycode)
static Input::Keycode convert_keycode(int sdl_keycode)
{
using namespace Input;
@ -135,7 +135,7 @@ static long convert_keycode(int sdl_keycode)
case SDLK_RMETA: return KEY_RIGHTMETA;
case SDLK_LMETA: return KEY_LEFTMETA;
default: return 0;
default: return KEY_UNKNOWN;
}
};
@ -158,11 +158,11 @@ static Input::Event wait_for_sdl_event()
if (ox == mx && oy == my)
return Event();
return Event(Event::MOTION, 0, mx, my, mx - ox, my - oy);
return Absolute_motion{mx, my};
}
/* determine keycode */
long keycode = 0;
/* determine key code */
Keycode keycode = KEY_UNKNOWN;
switch (event.type) {
case SDL_KEYUP:
case SDL_KEYDOWN:
@ -177,12 +177,11 @@ static Input::Event wait_for_sdl_event()
case SDL_BUTTON_LEFT: keycode = BTN_LEFT; break;
case SDL_BUTTON_MIDDLE: keycode = BTN_MIDDLE; break;
case SDL_BUTTON_RIGHT: keycode = BTN_RIGHT; break;
default: keycode = 0;
default: break;
}
}
/* determine event type */
Event::Type type = Event::INVALID;
switch (event.type) {
case SDL_KEYUP:
@ -192,32 +191,27 @@ static Input::Event wait_for_sdl_event()
/* ignore */
return Event();
type = Event::RELEASE;
break;
return Release{keycode};
case SDL_KEYDOWN:
case SDL_MOUSEBUTTONDOWN:
if (event.button.button == SDL_BUTTON_WHEELUP) {
type = Event::WHEEL;
return Event(type, 0, 0, 0, 0, 1);
} else if (event.button.button == SDL_BUTTON_WHEELDOWN) {
type = Event::WHEEL;
return Event(type, 0, 0, 0, 0, -1);
}
type = Event::PRESS;
break;
if (event.button.button == SDL_BUTTON_WHEELUP)
return Wheel{0, 1};
else if (event.button.button == SDL_BUTTON_WHEELDOWN)
return Wheel{0, -1};
return Press{keycode};
default:
return Event();
break;
}
return Event(type, keycode, 0, 0, 0, 0);
return Event();
}
namespace Input {
struct Backend;
}
namespace Input { struct Backend; }
struct Input::Backend : Genode::Thread
{
@ -237,9 +231,7 @@ struct Input::Backend : Genode::Thread
Input::Event e;
/* prevent flooding of client with invalid events */
do {
e = wait_for_sdl_event();
} while (e.type() == Input::Event::INVALID);
do { e = wait_for_sdl_event(); } while (!e.valid());
handler.event(e);
}

View File

@ -81,14 +81,14 @@ class Input::Touchscreen {
y = 76800 / (3276700 / y);
/* motion event */
ev_queue.add(Input::Event(Input::Event::MOTION, 0, x, y, 0, 0));
ev_queue.add(Input::Absolute_motion{x, y});
/* button event */
if ((down && (_state == RELEASED)) ||
(!down && (_state == PRESSED))) {
ev_queue.add(Input::Event(down ? Input::Event::PRESS
: Input::Event::RELEASE,
Input::BTN_LEFT, 0, 0, 0, 0));
if ((down && (_state == RELEASED)) || (!down && (_state == PRESSED))) {
if (down) ev_queue.add(Input::Press {Input::BTN_LEFT});
else ev_queue.add(Input::Release{Input::BTN_LEFT});
_state = down ? PRESSED : RELEASED;
}
}

View File

@ -95,9 +95,11 @@ class Input::Buttons {
for (unsigned i = 0; i < (sizeof(buttons)/sizeof(int)); i++) {
if ((_state & buttons[i]) == (buf & buttons[i]))
continue;
Input::Event::Type event = (buf & buttons[i]) ?
Input::Event::PRESS : Input::Event::RELEASE;
ev_queue.add(Input::Event(event, codes[i], 0, 0, 0, 0));
Input::Keycode const key = Input::Keycode(codes[i]);
if (buf & buttons[i]) ev_queue.add(Input::Press {key});
else ev_queue.add(Input::Release{key});
};
_state = buf;
}

View File

@ -467,8 +467,8 @@ class Ps2::Keyboard : public Input_driver
if (!_state_machine->ready())
return;
bool press = _state_machine->press();
unsigned key_code = _state_machine->key_code();
bool press = _state_machine->press();
Input::Keycode key_code = Input::Keycode(_state_machine->key_code());
/*
* The old key state should not equal the state after the event.
@ -484,7 +484,7 @@ class Ps2::Keyboard : public Input_driver
if (_verbose.keyboard)
Genode::log("post ", press ? "PRESS" : "RELEASE", ", "
"key_code = ", key_code);
"key_code = ", Input::key_name(key_code));
if (_ev_queue.avail_capacity() == 0) {
Genode::warning("event queue overflow - dropping events");
@ -492,9 +492,10 @@ class Ps2::Keyboard : public Input_driver
}
/* post event to event queue */
_ev_queue.add(Input::Event(press ? Input::Event::PRESS
: Input::Event::RELEASE,
key_code, 0, 0, 0, 0));
if (press)
_ev_queue.add(Input::Press{key_code});
else
_ev_queue.add(Input::Release{key_code});
/* start with new packet */
_state_machine->reset();

View File

@ -111,9 +111,11 @@ class Ps2::Mouse : public Input_driver
_check_for_event_queue_overflow();
_ev_queue.add(Input::Event(new_state ? Input::Event::PRESS
: Input::Event::RELEASE,
key_code, 0, 0, 0, 0));
if (new_state)
_ev_queue.add(Input::Press{Input::Keycode(key_code)});
else
_ev_queue.add(Input::Release{Input::Keycode(key_code)});
*old_state = new_state;
}
@ -242,8 +244,7 @@ class Ps2::Mouse : public Input_driver
_check_for_event_queue_overflow();
_ev_queue.add(Input::Event(Input::Event::MOTION,
0, 0, 0, rel_x, rel_y));
_ev_queue.add(Input::Relative_motion{rel_x, rel_y});
}
/* generate wheel event */
@ -264,8 +265,7 @@ class Ps2::Mouse : public Input_driver
_check_for_event_queue_overflow();
_ev_queue.add(Input::Event(Input::Event::WHEEL,
0, 0, 0, 0, rel_z));
_ev_queue.add(Input::Wheel{0, rel_z});
}
/* detect changes of mouse-button state and post corresponding events */

View File

@ -74,11 +74,11 @@ class Input_filter::Accelerate_source : public Source, Source::Sink
*/
long const _max;
long _apply_acceleration(long v) const
int _apply_acceleration(int v) const
{
long const sign = (v < 0) ? -1 : 1,
index = max(0, min(255, (sign*v*_sensitivity_percent)/100)),
accel = (_lut.values[index]*_max)/256;
int const sign = (v < 0) ? -1 : 1,
index = max(0, min(255, (sign*v*_sensitivity_percent)/100)),
accel = (_lut.values[index]*_max)/256;
return v + sign*accel;
}
@ -88,15 +88,14 @@ class Input_filter::Accelerate_source : public Source, Source::Sink
*/
void submit_event(Input::Event const &event) override
{
/* forward unrelated events */
if (!event.relative_motion()) {
_destination.submit_event(event);
return;
}
using namespace Input;
_destination.submit_event(Input::Event(Input::Event::MOTION, 0, 0, 0,
_apply_acceleration(event.rx()),
_apply_acceleration(event.ry())));
Event ev = event;
ev.handle_relative_motion([&] (int x, int y) {
ev = Relative_motion{_apply_acceleration(x),
_apply_acceleration(y)}; });
_destination.submit_event(ev);
}
public:

View File

@ -56,18 +56,6 @@ class Input_filter::Button_scroll_source : public Source, Source::Sink
*/
int _accumulated_motion = 0;
bool _magic_button_press_event(Input::Event const &event) const
{
return (event.type() == Input::Event::PRESS)
&& (event.keycode() == _button);
}
bool _magic_button_release_event(Input::Event const &event) const
{
return (event.type() == Input::Event::RELEASE)
&& (event.keycode() == _button);
}
Wheel(Xml_node config)
:
_button(key_code_by_name(_button_attribute(config).string())),
@ -78,7 +66,7 @@ class Input_filter::Button_scroll_source : public Source, Source::Sink
{
switch (_state) {
case IDLE:
if (_magic_button_press_event(event)) {
if (event.key_press(_button)) {
_state = BUTTON_PRESSED;
_accumulated_motion = 0;
}
@ -103,7 +91,7 @@ class Input_filter::Button_scroll_source : public Source, Source::Sink
*/
bool handle_deactivation(Input::Event const &event)
{
if (_magic_button_release_event(event)) {
if (event.key_release(_button)) {
bool const emit_press_release = (_state == BUTTON_PRESSED);
_state = IDLE;
_accumulated_motion = 0;
@ -144,8 +132,7 @@ class Input_filter::Button_scroll_source : public Source, Source::Sink
bool suppressed(Input::Event const event)
{
return (_state == ACTIVE && event.relative_motion())
|| _magic_button_press_event(event)
|| _magic_button_release_event(event);
|| event.key_press(_button);
}
};
@ -167,18 +154,17 @@ class Input_filter::Button_scroll_source : public Source, Source::Sink
_vertical_wheel .handle_activation(event);
_horizontal_wheel.handle_activation(event);
if (event.relative_motion()) {
_vertical_wheel .apply_relative_motion(event.ry());
_horizontal_wheel.apply_relative_motion(event.rx());
}
event.handle_relative_motion([&] (int x, int y) {
_vertical_wheel .apply_relative_motion(y);
_horizontal_wheel.apply_relative_motion(x);
});
/* emit artificial wheel event */
int const wheel_x = _horizontal_wheel.pending_motion(),
wheel_y = _vertical_wheel .pending_motion();
if (wheel_x || wheel_y)
_destination.submit_event(Event(Event::WHEEL, 0, 0, 0,
wheel_x, wheel_y));
_destination.submit_event(Input::Wheel{wheel_x, wheel_y});
/*
* Submit both press event and release event of magic button at
@ -188,19 +174,18 @@ class Input_filter::Button_scroll_source : public Source, Source::Sink
* both conditions regardless of the result of the first call of
* 'handle_activation'.
*/
if (_vertical_wheel .handle_deactivation(event)
| _horizontal_wheel.handle_deactivation(event)) {
event.handle_release([&] (Input::Keycode key) {
if (_vertical_wheel .handle_deactivation(event)
| _horizontal_wheel.handle_deactivation(event)) {
_destination.submit_event(Event(Event::PRESS, event.code(), 0, 0, 0, 0));
_destination.submit_event(event);
return;
}
_destination.submit_event(Input::Press{key});
}
});
/* hide consumed relative motion and magic-button press events */
if (_vertical_wheel .suppressed(event)) return;
if (_horizontal_wheel.suppressed(event)) return;
/* forward unrelated events */
_destination.submit_event(event);
}

View File

@ -29,6 +29,8 @@ class Input_filter::Chargen_source : public Source, Source::Sink
{
private:
typedef Input::Event Event;
Allocator &_alloc;
Timer_accessor &_timer_accessor;
Include_accessor &_include_accessor;
@ -179,11 +181,11 @@ class Input_filter::Chargen_source : public Source, Source::Sink
Conditions const _conditions;
Input::Event::Utf8 const _character;
Codepoint const _character;
Rule(Registry<Rule> &registry,
Conditions conditions,
Input::Event::Utf8 character)
Rule(Registry<Rule> &registry,
Conditions conditions,
Codepoint character)
:
_reg_elem(registry, *this),
_conditions(conditions),
@ -205,19 +207,19 @@ class Input_filter::Chargen_source : public Source, Source::Sink
return 1 + _conditions.num_modifier_constraints();
}
Input::Event::Utf8 character() const { return _character; }
Codepoint character() const { return _character; }
};
Registry<Rule> rules { };
/**
* Call functor 'fn' with the 'Input::Event::Utf8' character
* defined for the best matching rule
* Call functor 'fn' with the codepoint of the character defined
* for the best matching rule
*/
template <typename FN>
void apply_best_matching_rule(Modifier_map const &mod_map, FN const &fn) const
{
Input::Event::Utf8 best_match { 0 };
Codepoint best_match { Codepoint::INVALID };
unsigned max_score = 0;
@ -291,10 +293,13 @@ class Input_filter::Chargen_source : public Source, Source::Sink
*
* \throw Missing_character_definition
*/
static Input::Event::Utf8 _utf8_from_xml_node(Xml_node node)
static Codepoint _codepoint_from_xml_node(Xml_node node)
{
if (node.has_attribute("ascii"))
return Input::Event::Utf8(node.attribute_value("ascii", 0UL));
return Codepoint { node.attribute_value<uint32_t>("ascii", 0) };
if (node.has_attribute("code"))
return Codepoint { node.attribute_value<uint32_t>("code", 0) };
if (node.has_attribute("char")) {
@ -304,7 +309,7 @@ class Input_filter::Chargen_source : public Source, Source::Sink
unsigned char const ascii = value.string()[0];
if (ascii < 128)
return Input::Event::Utf8(ascii);
return Codepoint { ascii };
warning("char attribute with non-ascii character "
"'", value, "'");
@ -312,12 +317,13 @@ class Input_filter::Chargen_source : public Source, Source::Sink
}
if (node.has_attribute("b0")) {
unsigned char const b0 = node.attribute_value("b0", 0UL),
b1 = node.attribute_value("b1", 0UL),
b2 = node.attribute_value("b2", 0UL),
b3 = node.attribute_value("b3", 0UL);
char const b0 = node.attribute_value("b0", 0L),
b1 = node.attribute_value("b1", 0L),
b2 = node.attribute_value("b2", 0L),
b3 = node.attribute_value("b3", 0L);
return Input::Event::Utf8(b0, b1, b2, b3);
char const buf[5] { b0, b1, b2, b3, 0 };
return Utf8_ptr(buf).codepoint();
}
throw Missing_character_definition();
@ -340,7 +346,7 @@ class Input_filter::Chargen_source : public Source, Source::Sink
Input::Keycode const code = key_code_by_name(name);
new (_alloc) Key::Rule(key(code).rules, cond,
_utf8_from_xml_node(key_node));
_codepoint_from_xml_node(key_node));
});
}
@ -377,14 +383,16 @@ class Input_filter::Chargen_source : public Source, Source::Sink
Microseconds const _delay;
Microseconds const _rate;
Input::Event::Utf8 _curr_character { 0 };
Codepoint _curr_character { Codepoint::INVALID };
enum State { IDLE, REPEAT } _state { IDLE };
void _handle_timeout(Duration)
{
if (_state == REPEAT) {
_destination.submit_event(Input::Event(_curr_character));
_destination.submit_event(Input::Press_char{Input::KEY_UNKNOWN,
_curr_character});
_destination.submit_event(Input::Release{Input::KEY_UNKNOWN});
_timeout.schedule(_rate);
}
}
@ -400,7 +408,7 @@ class Input_filter::Chargen_source : public Source, Source::Sink
_rate (node.attribute_value("rate_ms", 0UL)*1000)
{ }
void schedule_repeat(Input::Event::Utf8 character)
void schedule_repeat(Codepoint character)
{
_curr_character = character;
_state = REPEAT;
@ -410,7 +418,7 @@ class Input_filter::Chargen_source : public Source, Source::Sink
void cancel()
{
_curr_character = Input::Event::Utf8(0);
_curr_character = Codepoint { Codepoint::INVALID };
_state = IDLE;
}
};
@ -420,43 +428,40 @@ class Input_filter::Chargen_source : public Source, Source::Sink
/**
* Sink interface (called from our child node)
*/
void submit_event(Input::Event const &event) override
void submit_event(Event const &event) override
{
using Input::Event;
Event ev = event;
/* forward event as is */
_destination.submit_event(event);
ev.handle_press([&] (Input::Keycode keycode, Codepoint /* ignored */) {
/* don't do anything for non-press/release events */
if (event.type() != Event::PRESS && event.type() != Event::RELEASE)
return;
Key &key = _key_map.key(keycode);
key.state = Key::PRESSED;
Key &key = _key_map.key(event.keycode());
if (key.type == Key::MODIFIER) _update_modifier_state();
/* track key state */
if (event.type() == Event::PRESS) key.state = Key::PRESSED;
if (event.type() == Event::RELEASE) key.state = Key::RELEASED;
/* supplement codepoint information to press event */
key.apply_best_matching_rule(_mod_map, [&] (Codepoint codepoint) {
if (key.type == Key::MODIFIER) {
_update_modifier_state();
/* never emit a character when pressing a modifier key */
return;
}
if (event.type() == Event::PRESS) {
key.apply_best_matching_rule(_mod_map, [&] (Event::Utf8 utf8) {
_destination.submit_event(Event(utf8));
ev = Event(Input::Press_char{keycode, codepoint});
if (_char_repeater.constructed())
_char_repeater->schedule_repeat(utf8);
_char_repeater->schedule_repeat(codepoint);
});
}
});
ev.handle_release([&] (Input::Keycode keycode) {
Key &key = _key_map.key(keycode);
key.state = Key::RELEASED;
if (key.type == Key::MODIFIER) _update_modifier_state();
if (event.type() == Event::RELEASE)
if (_char_repeater.constructed())
_char_repeater->cancel();
});
/* forward filtered event */
_destination.submit_event(ev);
}
Source &_source;

View File

@ -82,8 +82,8 @@ class Input_filter::Input_connection
auto update_key_cnt = [&] (Input::Event const &event)
{
if (event.type() == Input::Event::PRESS) _key_cnt++;
if (event.type() == Input::Event::RELEASE) _key_cnt--;
if (event.press()) _key_cnt++;
if (event.release()) _key_cnt--;
};
for_each_event(update_key_cnt);

View File

@ -51,22 +51,25 @@ class Input_filter::Remap_source : public Source, Source::Sink
{
using Input::Event;
bool const key_event =
event.type() == Event::PRESS || event.type() == Event::RELEASE;
bool const code_valid =
event.keycode() >= 0 && event.keycode() < Input::KEY_MAX;
/* forward events that are unrelated to the remapper */
if (!key_event || !code_valid) {
if (!event.press() && !event.release()) {
_destination.submit_event(event);
return;
}
/* remap the key code */
Key &key = _keys[event.keycode()];
/*
* remap the key code for press and release events
*
* The range of the 'key' is checked by the 'Event' handle methods,
* so it is safe to use as array index.
*/
auto remap = [&] (Input::Keycode key) { return _keys[key].code; };
_destination.submit_event(Event(event.type(), key.code, 0, 0, 0, 0));
event.handle_press([&] (Input::Keycode key, Codepoint codepoint) {
_destination.submit_event(Input::Press_char{remap(key), codepoint}); });
event.handle_release([&] (Input::Keycode key) {
_destination.submit_event(Input::Release{remap(key)}); });
}
void _apply_config(Xml_node const config, unsigned const max_recursion = 4)

View File

@ -85,19 +85,10 @@ class Input::Session_component : public Rpc_object<Session>
Input::Event &ev = _ev_buf[i];
if ((ev.type() == Input::Event::MOTION)
|| (ev.type() == Input::Event::WHEEL)
|| (ev.code() == Input::BTN_LEFT)
|| (ev.code() == Input::BTN_RIGHT)
|| (ev.code() == Input::BTN_MIDDLE)) {
ev = Input::Event(ev.type(),
ev.code(),
ev.ax() + delta.x(),
ev.ay() + delta.y(),
ev.rx(),
ev.ry());
}
ev.handle_absolute_motion([&] (int x, int y) {
Point<> p = Point<>(x, y) + delta;
ev = Input::Absolute_motion{p.x(), p.y()};
});
}
return num_ev;

View File

@ -42,42 +42,31 @@ namespace Nit_fb {
/**
* Translate input event
*/
static Input::Event translate_event(Input::Event const ev,
static Input::Event translate_event(Input::Event ev,
Nit_fb::Point const input_origin,
Nit_fb::Area const boundary)
{
switch (ev.type()) {
using Nit_fb::Point;
case Input::Event::MOTION:
case Input::Event::PRESS:
case Input::Event::RELEASE:
case Input::Event::FOCUS:
case Input::Event::LEAVE:
case Input::Event::TOUCH:
{
Nit_fb::Point abs_pos = Nit_fb::Point(ev.ax(), ev.ay()) -
input_origin;
/* function to clamp point to bounday */
auto clamp = [boundary] (Point p) {
return Point(Genode::min((int)boundary.w() - 1, Genode::max(0, p.x())),
Genode::min((int)boundary.h() - 1, Genode::max(0, p.y()))); };
using Genode::min;
using Genode::max;
using Input::Event;
/* function to translate point to 'input_origin' */
auto translate = [input_origin] (Point p) { return p - input_origin; };
int const ax = min((int)boundary.w() - 1, max(0, abs_pos.x()));
int const ay = min((int)boundary.h() - 1, max(0, abs_pos.y()));
ev.handle_absolute_motion([&] (int x, int y) {
Point p = clamp(translate(Point(x, y)));
ev = Input::Absolute_motion{p.x(), p.y()};
});
if (ev.type() == Event::TOUCH)
return Event::create_touch_event(ax, ay, ev.code(),
ev.is_touch_release());
ev.handle_touch([&] (Input::Touch_id id, float x, float y) {
Point p = clamp(translate(Point(x, y)));
ev = Input::Touch{id, (float)p.x(), (float)p.y()};
});
return Event(ev.type(), ev.code(), ax, ay, 0, 0);
}
case Input::Event::INVALID:
case Input::Event::WHEEL:
case Input::Event::CHARACTER:
return ev;
}
return Input::Event();
return ev;
}
@ -424,9 +413,7 @@ struct Nit_fb::Main : View_updater
bool update = false;
for (unsigned i = 0; i < num; i++) {
if (events[i].type() == Input::Event::FOCUS)
update = events[i].code();
update |= events[i].focus_enter();
input_session.submit(translate_event(events[i], position, fb_session.size()));
}

View File

@ -238,14 +238,14 @@ void Session_component::submit_input_event(Input::Event e)
Point const origin_offset = _phys_pos(Point(0, 0), _view_stack.size());
/*
* Transpose absolute coordinates by session-specific vertical
* offset.
* Transpose absolute coordinates by session-specific vertical offset.
*/
if (e.ax() || e.ay())
e = Event(e.type(), e.code(),
max(0, e.ax() - origin_offset.x()),
max(0, e.ay() - origin_offset.y()),
e.rx(), e.ry());
e.handle_absolute_motion([&] (int x, int y) {
e = Absolute_motion{max(0, x - origin_offset.x()),
max(0, y - origin_offset.y())}; });
e.handle_touch([&] (Touch_id id, float x, float y) {
e = Touch{ id, max(0.0f, x - origin_offset.x()),
max(0.0f, y - origin_offset.y())}; });
_input_session_component.submit(&e);
}

View File

@ -37,16 +37,16 @@ static inline bool _mouse_button(Keycode keycode) {
static unsigned num_consecutive_events(Input::Event const *ev, unsigned max)
{
if (max < 1) return 0;
if (ev->type() != Input::Event::MOTION) return 1;
bool const first_absolute = ev->absolute_motion();
bool const first_is_absolute_motion = ev->absolute_motion();
bool const first_is_relative_motion = ev->relative_motion();
/* iterate until we get a different event type, start at second */
unsigned cnt = 1;
for (ev++ ; cnt < max; cnt++, ev++) {
if (ev->type() != Input::Event::MOTION) break;
if (first_absolute != ev->absolute_motion()) break;
}
if (first_is_absolute_motion && ev->absolute_motion()) continue;
if (first_is_relative_motion && ev->relative_motion()) continue;
break;
};
return cnt;
}
@ -60,11 +60,26 @@ static unsigned num_consecutive_events(Input::Event const *ev, unsigned max)
*/
static Input::Event merge_motion_events(Input::Event const *ev, unsigned n)
{
Input::Event res;
for (unsigned i = 0; i < n; i++, ev++)
res = Input::Event(Input::Event::MOTION, 0, ev->ax(), ev->ay(),
res.rx() + ev->rx(), res.ry() + ev->ry());
return res;
if (n == 0) return Event();
if (ev->relative_motion()) {
int rx = 0, ry = 0;
for (unsigned i = 0; i < n; i++, ev++)
ev->handle_relative_motion([&] (int x, int y) { rx += x; ry += y; });
if (rx || ry)
return Relative_motion{rx, ry};
}
if (ev->absolute_motion()) {
int ax = 0, ay = 0;
for (unsigned i = 0; i < n; i++, ev++)
ev->handle_absolute_motion([&] (int x, int y) { ax = x; ay = y; });
return Absolute_motion{ax, ay};
}
return Event();
}
@ -74,62 +89,40 @@ static Input::Event merge_motion_events(Input::Event const *ev, unsigned n)
void User_state::_handle_input_event(Input::Event ev)
{
Input::Keycode const keycode = ev.keycode();
Input::Event::Type const type = ev.type();
/* transparently convert relative into absolute motion event */
ev.handle_relative_motion([&] (int x, int y) {
/*
* Mangle incoming events
*/
int ax = _pointer_pos.x(), ay = _pointer_pos.y();
int rx = 0, ry = 0; /* skip info about relative motion by default */
int const ox = _pointer_pos.x(),
oy = _pointer_pos.y();
/* transparently handle absolute and relative motion events */
if (type == Event::MOTION) {
if ((ev.rx() || ev.ry()) && ev.ax() == 0 && ev.ay() == 0) {
ax = max(0, min((int)_view_stack.size().w() - 1, ax + ev.rx()));
ay = max(0, min((int)_view_stack.size().h() - 1, ay + ev.ry()));
} else {
ax = ev.ax();
ay = ev.ay();
}
}
int const ax = max(0, min((int)_view_stack.size().w() - 1, ox + x)),
ay = max(0, min((int)_view_stack.size().h() - 1, oy + y));
/* propagate relative motion for wheel events */
if (type == Event::WHEEL) {
rx = ev.rx();
ry = ev.ry();
}
ev = Absolute_motion{ax, ay};
});
if (type == Event::TOUCH) {
ax = ev.ax();
ay = ev.ay();
ev = Input::Event::create_touch_event(ax, ay, ev.code(),
ev.touch_release());
} else if (type == Event::CHARACTER) {
ev = Input::Event(type, ev.code(), ax, ay, rx, ry);
} else
ev = Input::Event(type, keycode, ax, ay, rx, ry);
_pointer_pos = Point(ax, ay);
/* respond to motion events by updating the pointer position */
ev.handle_absolute_motion([&] (int x, int y) {
_pointer_pos = Point(x, y); });
bool const drag = _key_cnt > 0;
/* count keys */
if (type == Event::PRESS) _key_cnt++;
if (type == Event::RELEASE && drag) _key_cnt--;
if (ev.press()) _key_cnt++;
if (ev.release() && drag) _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);
}
ev.handle_press([&] (Keycode key, Codepoint) {
if (_key_array.pressed(key))
Genode::warning("suspicious double press of ", Input::key_name(key));
_key_array.pressed(key, 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);
}
ev.handle_release([&] (Keycode key) {
if (!_key_array.pressed(key))
Genode::warning("suspicious double release of ", Input::key_name(key));
_key_array.pressed(key, false);
});
View_component const * const pointed_view = _view_stack.find_view(_pointer_pos);
@ -138,18 +131,18 @@ void User_state::_handle_input_event(Input::Event ev)
/*
* Deliver a leave event if pointed-to session changed
*/
if (_hovered && (hovered != _hovered)) {
Input::Event leave_ev(Input::Event::LEAVE, 0, ax, ay, 0, 0);
_hovered->submit_input_event(leave_ev);
}
if (_hovered && (hovered != _hovered))
_hovered->submit_input_event(Hover_leave());
_hovered = hovered;
/*
* Handle start of a key sequence
*/
if (type == Event::PRESS && (_key_cnt == 1)) {
ev.handle_press([&] (Keycode keycode, Codepoint) {
if (_key_cnt != 1)
return;
View_owner *global_receiver = nullptr;
@ -163,14 +156,13 @@ void User_state::_handle_input_event(Input::Event ev)
/*
* Notify both the old focused session and the new one.
*/
if (_focused) {
Input::Event unfocus_ev(Input::Event::FOCUS, 0, ax, ay, 0, 0);
_focused->submit_input_event(unfocus_ev);
}
if (_focused)
_focused->submit_input_event(Focus_leave());
if (_hovered) {
Input::Event focus_ev(Input::Event::FOCUS, 1, ax, ay, 0, 0);
_hovered->submit_input_event(focus_ev);
_hovered->submit_input_event(Absolute_motion{_pointer_pos.x(),
_pointer_pos.y()});
_hovered->submit_input_event(Focus_enter());
}
if (_hovered->has_transient_focusable_domain()) {
@ -219,12 +211,12 @@ void User_state::_handle_input_event(Input::Event ev)
*/
if (!global_receiver)
_input_receiver = _focused;
}
});
/*
* Deliver event to session
*/
if (type == Event::MOTION || type == Event::WHEEL || type == Event::TOUCH) {
if (ev.absolute_motion() || ev.wheel() || ev.touch() || ev.touch_release()) {
if (_key_cnt == 0) {
@ -248,30 +240,28 @@ void User_state::_handle_input_event(Input::Event ev)
* Deliver press/release event to focused session or the receiver of global
* key.
*/
if ((type == Event::PRESS) && _input_receiver) {
if (!_mouse_button(ev.keycode())
ev.handle_press([&] (Keycode key, Codepoint) {
if (!_input_receiver)
return;
if (!_mouse_button(key)
|| (_hovered
&& (_hovered->has_focusable_domain()
|| _hovered->has_same_domain(_focused))))
_input_receiver->submit_input_event(ev);
else
_input_receiver = nullptr;
}
});
if ((type == Event::RELEASE) && _input_receiver)
_input_receiver->submit_input_event(ev);
/*
* Forward character events
*/
if (type == Event::CHARACTER && _input_receiver)
if (ev.release() && _input_receiver)
_input_receiver->submit_input_event(ev);
/*
* Detect end of global key sequence
*/
if (ev.type() == Event::RELEASE && (_key_cnt == 0) && _global_key_sequence) {
_input_receiver = _focused;
if (ev.release() && (_key_cnt == 0) && _global_key_sequence) {
_input_receiver = _focused;
_global_key_sequence = false;
}
}
@ -299,22 +289,14 @@ User_state::handle_input_events(Input::Event const * const ev_buf,
Input::Event const *e = &ev_buf[src_ev_cnt];
Input::Event curr = *e;
if (e->type() == Input::Event::MOTION) {
unsigned n = num_consecutive_events(e, num_ev - src_ev_cnt);
if (e->absolute_motion() || e->relative_motion()) {
unsigned const n = num_consecutive_events(e, num_ev - src_ev_cnt);
curr = merge_motion_events(e, n);
/* skip merged events */
src_ev_cnt += n - 1;
}
/*
* 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->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
@ -331,7 +313,7 @@ User_state::handle_input_events(Input::Event const * const ev_buf,
* updates the pointed session, which might have changed by other
* means, for example view movement.
*/
_handle_input_event(Input::Event());
_handle_input_event(Event());
}
/*
@ -341,8 +323,7 @@ User_state::handle_input_events(Input::Event const * const ev_buf,
bool key_state_affected = false;
for (unsigned i = 0; i < num_ev; i++)
key_state_affected |= (ev_buf[i].type() == Input::Event::PRESS) ||
(ev_buf[i].type() == Input::Event::RELEASE);
key_state_affected |= (ev_buf[i].press() || ev_buf[i].release());
_apply_pending_focus_change();

View File

@ -133,13 +133,9 @@ struct Main
void _handle()
{
for (int i = 0, num_ev = _input.flush(); i < num_ev; ++i) {
Input::Event const ev = _ev_ds.local_addr<Input::Event const>()[i];
if (ev.type() == Input::Event::PRESS) {
_click.play();
break;
}
}
_input.for_each_event([&] (Input::Event const &ev) {
if (ev.press())
_click.play(); });
}
Main(Env & env) : _env(env)

View File

@ -19,69 +19,25 @@
using namespace Genode;
static char const * ev_type(Input::Event::Type type)
{
switch (type) {
case Input::Event::INVALID: return "INVALID";
case Input::Event::MOTION: return "MOTION ";
case Input::Event::PRESS: return "PRESS ";
case Input::Event::RELEASE: return "RELEASE";
case Input::Event::WHEEL: return "WHEEL ";
case Input::Event::FOCUS: return "FOCUS ";
case Input::Event::LEAVE: return "LEAVE ";
case Input::Event::TOUCH: return "TOUCH ";
case Input::Event::CHARACTER: return "CHARACTER";
}
return "";
}
static char const * key_name(Input::Event const &ev)
{
if (ev.type() == Input::Event::MOTION)
return "";
return Input::key_name(static_cast<Input::Keycode>(ev.code()));
}
struct Main
{
Env &env;
Input::Connection input { env };
Signal_handler<Main> input_sigh { env.ep(), *this, &Main::handle_input };
int key_cnt { 0 };
unsigned event_cnt { 0 };
Env &_env;
Input::Connection _input { _env };
Signal_handler<Main> _input_sigh { _env.ep(), *this, &Main::_handle_input };
unsigned _event_cnt { 0 };
void handle_input();
void _handle_input()
{
_input.for_each_event([&] (Input::Event const &ev) {
log("Input event #", _event_cnt++, "\t", ev); });
}
Main(Env &env) : env(env)
Main(Env &env) : _env(env)
{
log("--- Input test ---");
input.sigh(input_sigh);
_input.sigh(_input_sigh);
}
};
void Main::handle_input()
{
input.for_each_event([&] (Input::Event const &ev) {
event_cnt++;
if (ev.type() == Input::Event::PRESS) key_cnt++;
if (ev.type() == Input::Event::RELEASE) key_cnt--;
log("Input event #", event_cnt, "\t"
"type=", ev_type(ev.type()), "\t"
"code=", ev.code(), "\t"
"rx=", ev.rx(), "\t"
"ry=", ev.ry(), "\t"
"ax=", ev.ax(), "\t"
"ay=", ev.ay(), "\t"
"key_cnt=", key_cnt, "\t", key_name(ev));
});
}
void Component::construct(Env &env) { static Main main(env); }

View File

@ -31,28 +31,7 @@ namespace Test {
class Input_root;
class Main;
using namespace Genode;
}
namespace Genode {
static inline void print(Output &output, Input::Event const &ev)
{
switch (ev.type()) {
case Input::Event::INVALID: print(output, "INVALID"); break;
case Input::Event::MOTION: print(output, "MOTION"); break;
case Input::Event::PRESS: print(output, "PRESS"); break;
case Input::Event::RELEASE: print(output, "RELEASE"); break;
case Input::Event::WHEEL: print(output, "WHEEL"); break;
case Input::Event::FOCUS: print(output, "FOCUS"); break;
case Input::Event::LEAVE: print(output, "LEAVE"); break;
case Input::Event::TOUCH: print(output, "TOUCH"); break;
case Input::Event::CHARACTER: print(output, "CHARACTER"); break;
};
if (ev.type() == Input::Event::PRESS || ev.type() == Input::Event::RELEASE)
print(output, " (", Input::key_name(ev.keycode()), ")");
}
using Input::Event;
}
@ -62,7 +41,7 @@ class Test::Input_from_filter
struct Event_handler : Interface
{
virtual void handle_event_from_filter(Input::Event const &) = 0;
virtual void handle_event_from_filter(Event const &) = 0;
};
private:
@ -82,7 +61,7 @@ class Test::Input_from_filter
_handle_input_in_progress = true;
if (_input_expected)
_connection.for_each_event([&] (Input::Event const &event) {
_connection.for_each_event([&] (Event const &event) {
_event_handler.handle_event_from_filter(event); });
_handle_input_in_progress = false;
@ -211,24 +190,28 @@ class Test::Input_to_filter
step.for_each_sub_node([&] (Xml_node node) {
Input::Event::Type const type =
node.type() == "press" ? Input::Event::PRESS :
node.type() == "release" ? Input::Event::RELEASE :
node.type() == "motion" ? Input::Event::MOTION :
Input::Event::INVALID;
bool const press = node.has_type("press"),
release = node.has_type("release");
if (press || release) {
if (type == Input::Event::PRESS || type == Input::Event::RELEASE) {
Key_name const key_name = node.attribute_value("code", Key_name());
dst.submit(Input::Event(type, _code(key_name), 0, 0, 0, 0));
if (press) dst.submit(Input::Press {_code(key_name)});
if (release) dst.submit(Input::Release{_code(key_name)});
}
if (type == Input::Event::MOTION) {
dst.submit(Input::Event(type, 0,
node.attribute_value("ax", 0L),
node.attribute_value("ay", 0L),
node.attribute_value("rx", 0L),
node.attribute_value("ry", 0L)));
}
bool const motion = node.has_type("motion");
bool const rel = node.has_attribute("rx") || node.has_attribute("ry");
bool const abs = node.has_attribute("ax") || node.has_attribute("ay");
if (motion && abs)
dst.submit(Input::Absolute_motion{(int)node.attribute_value("ax", 0L),
(int)node.attribute_value("ay", 0L)});
if (motion && rel)
dst.submit(Input::Relative_motion{(int)node.attribute_value("rx", 0L),
(int)node.attribute_value("ry", 0L)});
});
}
};
@ -379,52 +362,53 @@ struct Test::Main : Input_from_filter::Event_handler
/**
* Input_to_filter::Event_handler interface
*/
void handle_event_from_filter(Input::Event const &ev) override
void handle_event_from_filter(Event const &ev) override
{
typedef Genode::String<20> Value;
Xml_node const step = _curr_step_xml();
switch (ev.type()) {
case Input::Event::PRESS:
bool step_succeeded = false;
ev.handle_press([&] (Input::Keycode key, Codepoint codepoint) {
auto codepoint_of_step = [] (Xml_node step) {
return Utf8_ptr(step.attribute_value("char", Value()).string()).codepoint(); };
if (step.type() == "expect_press"
&& step.attribute_value("code", Value()) == Input::key_name(ev.keycode()))
break;
&& step.attribute_value("code", Value()) == Input::key_name(key)
&& (!step.has_attribute("char") ||
codepoint_of_step(step).value == codepoint.value))
step_succeeded = true;
});
case Input::Event::RELEASE:
ev.handle_release([&] (Input::Keycode key) {
if (step.type() == "expect_release"
&& step.attribute_value("code", Value()) == Input::key_name(ev.keycode()))
break;
&& step.attribute_value("code", Value()) == Input::key_name(key))
step_succeeded = true; });
case Input::Event::WHEEL:
ev.handle_wheel([&] (int x, int y) {
if (step.type() == "expect_wheel"
&& step.attribute_value("rx", 0L) == ev.rx()
&& step.attribute_value("ry", 0L) == ev.ry())
break;
&& step.attribute_value("rx", 0L) == x
&& step.attribute_value("ry", 0L) == y)
step_succeeded = true; });
case Input::Event::MOTION:
ev.handle_relative_motion([&] (int x, int y) {
if (step.type() == "expect_motion"
&& (!step.has_attribute("rx") || step.attribute_value("rx", 0L) == ev.rx())
&& (!step.has_attribute("ry") || step.attribute_value("ry", 0L) == ev.ry())
&& (!step.has_attribute("ax") || step.attribute_value("ax", 0L) == ev.ax())
&& (!step.has_attribute("ay") || step.attribute_value("ay", 0L) == ev.ay()))
break;
&& (!step.has_attribute("rx") || step.attribute_value("rx", 0L) == x)
&& (!step.has_attribute("ry") || step.attribute_value("ry", 0L) == y))
step_succeeded = true; });
case Input::Event::CHARACTER:
if (step.type() == "expect_char"
&& step.attribute_value("char", Value()) == Value(Char(ev.utf8().b0)))
break;
ev.handle_absolute_motion([&] (int x, int y) {
if (step.type() == "expect_motion"
&& (!step.has_attribute("ax") || step.attribute_value("ax", 0L) == x)
&& (!step.has_attribute("ay") || step.attribute_value("ay", 0L) == y))
step_succeeded = true; });
case Input::Event::INVALID:
case Input::Event::FOCUS:
case Input::Event::LEAVE:
case Input::Event::TOUCH:
error("unexpected event: ", ev);
throw Exception();
};
_advance_step();
_execute_curr_step();
if (step_succeeded) {
_advance_step();
_execute_curr_step();
}
}
void _handle_timer()

View File

@ -203,30 +203,32 @@ void Component::construct(Genode::Env &env)
/*
* Handle input events
*/
int omx = 0, omy = 0, key_cnt = 0;
Test_view *tv = 0;
int mx = 0, my = 0, key_cnt = 0;
Test_view *tv = nullptr;
while (1) {
while (!nitpicker.input()->pending()) timer.msleep(20);
nitpicker.input()->for_each_event([&] (Input::Event const &ev) {
if (ev.type() == Input::Event::PRESS) key_cnt++;
if (ev.type() == Input::Event::RELEASE) key_cnt--;
/* move selected view */
if (ev.type() == Input::Event::MOTION && key_cnt > 0 && tv)
tv->move(tv->x() + ev.ax() - omx, tv->y() + ev.ay() - omy);
if (ev.press()) key_cnt++;
if (ev.release()) key_cnt--;
ev.handle_absolute_motion([&] (int x, int y) {
/* move selected view */
if (key_cnt > 0 && tv)
tv->move(tv->x() + x - mx, tv->y() + y - my);
mx = x; my = y;
});
/* find selected view and bring it to front */
if (ev.type() == Input::Event::PRESS && key_cnt == 1) {
tv = tvs.find(ev.ax(), ev.ay());
if (ev.press() && key_cnt == 1) {
tv = tvs.find(mx, my);
if (tv)
tvs.top(tv);
}
omx = ev.ax(); omy = ev.ay();
});
}

View File

@ -66,17 +66,22 @@ struct Ps2_mouse_packet : Genode::Register<32>
static bool mouse_event(Input::Event const &ev)
{
using Input::Event;
if (ev.type() == Event::PRESS || ev.type() == Event::RELEASE) {
if (ev.code() == Input::BTN_LEFT) return true;
if (ev.code() == Input::BTN_MIDDLE) return true;
if (ev.code() == Input::BTN_RIGHT) return true;
}
using namespace Input;
if (ev.type() == Event::MOTION)
return true;
bool result = false;
return false;
auto mouse_button = [] (Keycode key) {
return key == BTN_LEFT || key == BTN_MIDDLE || key == BTN_RIGHT; };
ev.handle_press([&] (Keycode key, Genode::Codepoint) {
result |= mouse_button(key); });
ev.handle_release([&] (Keycode key) {
result |= mouse_button(key); });
result |= ev.absolute_motion() || ev.relative_motion();
return result;
}
@ -88,26 +93,25 @@ static bool mouse_event(Input::Event const &ev)
unsigned Seoul::Console::_input_to_ps2mouse(Input::Event const &ev)
{
/* track state of mouse buttons */
using Input::Event;
if (ev.type() == Event::PRESS || ev.type() == Event::RELEASE) {
bool const pressed = ev.type() == Event::PRESS;
if (ev.code() == Input::BTN_LEFT) _left = pressed;
if (ev.code() == Input::BTN_MIDDLE) _middle = pressed;
if (ev.code() == Input::BTN_RIGHT) _right = pressed;
}
auto apply_button = [] (Input::Event const &ev, Input::Keycode key, bool &state) {
if (ev.key_press (key)) state = true;
if (ev.key_release(key)) state = false;
};
int rx;
int ry;
apply_button(ev, Input::BTN_LEFT, _left);
apply_button(ev, Input::BTN_MIDDLE, _middle);
apply_button(ev, Input::BTN_RIGHT, _right);
if (ev.absolute_motion()) {
static Input::Event last_event;
rx = ev.ax() - last_event.ax();
ry = ev.ay() - last_event.ay();
last_event = ev;
} else {
rx = ev.rx();
ry = ev.ry();
}
int rx = 0;
int ry = 0;
ev.handle_absolute_motion([&] (int x, int y) {
static int ox = 0, oy = 0;
rx = x - ox; ry = y - oy;
ox = x; oy = y;
});
ev.handle_relative_motion([&] (int x, int y) { rx = x; ry = y; });
/* clamp relative motion vector to bounds */
int const boundary = 200;
@ -316,16 +320,13 @@ void Seoul::Console::_handle_input()
_motherboard()->bus_input.send(msg);
}
if (ev.type() == Input::Event::PRESS) {
if (ev.code() <= 0xee) {
_vkeyb.handle_keycode_press(ev.code());
}
}
if (ev.type() == Input::Event::RELEASE) {
if (ev.code() <= 0xee) { /* keyboard event */
_vkeyb.handle_keycode_release(ev.code());
}
}
ev.handle_press([&] (Input::Keycode key, Genode::Codepoint) {
if (key <= 0xee)
_vkeyb.handle_keycode_press(key); });
ev.handle_release([&] (Input::Keycode key) {
if (key <= 0xee)
_vkeyb.handle_keycode_release(key); });
});
}

View File

@ -203,18 +203,11 @@ void GenodeConsole::handle_input()
if (!_vbox_keyboard || !_vbox_mouse)
return;
bool const press = ev.type() == Input::Event::PRESS;
bool const release = ev.type() == Input::Event::RELEASE;
bool const key = press || release;
bool const motion = ev.type() == Input::Event::MOTION;
bool const wheel = ev.type() == Input::Event::WHEEL;
bool const touch = ev.type() == Input::Event::TOUCH;
auto keyboard_submit = [&] (Input::Keycode key, bool release) {
if (key) {
Scan_code scan_code(ev.keycode());
Scan_code scan_code(key);
unsigned char const release_bit =
(ev.type() == Input::Event::RELEASE) ? 0x80 : 0;
unsigned char const release_bit = release ? 0x80 : 0;
if (scan_code.normal())
_vbox_keyboard->PutScancode(scan_code.code() | release_bit);
@ -223,122 +216,116 @@ void GenodeConsole::handle_input()
_vbox_keyboard->PutScancode(0xe0);
_vbox_keyboard->PutScancode(scan_code.ext() | release_bit);
}
}
};
/*
* Track press/release status of keys and buttons. Currently,
* only the mouse-button states are actually used.
*/
if (press)
_key_status[ev.keycode()] = true;
/* obtain bit mask of currently pressed mouse buttons */
auto curr_mouse_button_bits = [&] () {
return (_key_status[Input::BTN_LEFT] ? MouseButtonState_LeftButton : 0)
| (_key_status[Input::BTN_RIGHT] ? MouseButtonState_RightButton : 0)
| (_key_status[Input::BTN_MIDDLE] ? MouseButtonState_MiddleButton : 0);
};
if (release)
_key_status[ev.keycode()] = false;
unsigned const old_mouse_button_bits = curr_mouse_button_bits();
bool const mouse_button_event =
key && _mouse_button(ev.keycode());
ev.handle_press([&] (Input::Keycode key, Genode::Codepoint) {
keyboard_submit(key, false);
_key_status[key] = true;
});
bool const mouse_event = mouse_button_event || motion;
ev.handle_release([&] (Input::Keycode key) {
keyboard_submit(key, true);
_key_status[key] = false;
});
if (mouse_event) {
unsigned const buttons = (_key_status[Input::BTN_LEFT] ? MouseButtonState_LeftButton : 0)
| (_key_status[Input::BTN_RIGHT] ? MouseButtonState_RightButton : 0)
| (_key_status[Input::BTN_MIDDLE] ? MouseButtonState_MiddleButton : 0);
if (ev.absolute_motion()) {
unsigned const mouse_button_bits = curr_mouse_button_bits();
_last_received_motion_event_was_absolute = true;
if (mouse_button_bits != old_mouse_button_bits) {
/* transform absolute to relative if guest is so odd */
if (!guest_abs && guest_rel) {
int const boundary = 20;
int rx = ev.ax() - _ax;
int ry = ev.ay() - _ay;
rx = Genode::min(boundary, Genode::max(-boundary, rx));
ry = Genode::min(boundary, Genode::max(-boundary, ry));
_vbox_mouse->PutMouseEvent(rx, ry, 0, 0, buttons);
} else
_vbox_mouse->PutMouseEventAbsolute(ev.ax(), ev.ay(), 0,
0, buttons);
_ax = ev.ax();
_ay = ev.ay();
} else if (ev.relative_motion()) {
_last_received_motion_event_was_absolute = false;
/* prefer relative motion event */
if (_last_received_motion_event_was_absolute) {
/* prefer absolute button event */
if (guest_abs)
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, mouse_button_bits);
else if (guest_rel)
_vbox_mouse->PutMouseEvent(0, 0, 0, 0, mouse_button_bits);
} else {
/* prefer relative button event */
if (guest_rel)
_vbox_mouse->PutMouseEvent(ev.rx(), ev.ry(), 0, 0, buttons);
else if (guest_abs) {
_ax += ev.rx();
_ay += ev.ry();
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons);
}
}
/* only the buttons changed */
else {
if (_last_received_motion_event_was_absolute) {
/* prefer absolute button event */
if (guest_abs)
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons);
else if (guest_rel)
_vbox_mouse->PutMouseEvent(0, 0, 0, 0, buttons);
} else {
/* prefer relative button event */
if (guest_rel)
_vbox_mouse->PutMouseEvent(0, 0, 0, 0, buttons);
else if (guest_abs)
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons);
}
_vbox_mouse->PutMouseEvent(0, 0, 0, 0, mouse_button_bits);
else if (guest_abs)
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, mouse_button_bits);
}
}
if (wheel) {
ev.handle_absolute_motion([&] (int x, int y) {
_last_received_motion_event_was_absolute = true;
/* transform absolute to relative if guest is so odd */
if (!guest_abs && guest_rel) {
int const boundary = 20;
int rx = x - _ax;
int ry = y - _ay;
rx = Genode::min(boundary, Genode::max(-boundary, rx));
ry = Genode::min(boundary, Genode::max(-boundary, ry));
_vbox_mouse->PutMouseEvent(rx, ry, 0, 0, mouse_button_bits);
} else
_vbox_mouse->PutMouseEventAbsolute(x, y, 0, 0, mouse_button_bits);
_ax = x;
_ay = y;
});
ev.handle_relative_motion([&] (int x, int y) {
_last_received_motion_event_was_absolute = false;
/* prefer relative motion event */
if (guest_rel)
_vbox_mouse->PutMouseEvent(x, y, 0, 0, mouse_button_bits);
else if (guest_abs) {
_ax += x;
_ay += y;
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, mouse_button_bits);
}
});
ev.handle_wheel([&] (int x, int y) {
if (_last_received_motion_event_was_absolute)
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, -ev.ry(), -ev.rx(), 0);
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, -y, -x, 0);
else
_vbox_mouse->PutMouseEvent(0, 0, -ev.ry(), -ev.rx(), 0);
}
_vbox_mouse->PutMouseEvent(0, 0, -y, -x, 0);
});
ev.handle_touch([&] (Input::Touch_id id, int x, int y) {
if (touch) {
/* if multitouch queue is full - send it */
if (mt_number >= sizeof(mt_events) / sizeof(mt_events[0])) {
_vbox_mouse->PutEventMultiTouch(mt_number, mt_number,
mt_events, RTTimeMilliTS());
mt_events, RTTimeMilliTS());
mt_number = 0;
}
int x = ev.ax();
int y = ev.ay();
int slot = ev.code();
/* Mouse::putEventMultiTouch drops values of 0 */
if (x <= 0) x = 1;
if (y <= 0) y = 1;
enum MultiTouch {
None = 0x0,
InContact = 0x01,
InRange = 0x02
};
enum { IN_CONTACT = 0x01, IN_RANGE = 0x02 };
int status = MultiTouch::InContact | MultiTouch::InRange;
if (ev.touch_release())
status = MultiTouch::None;
uint16_t const s = RT_MAKE_U16(slot, status);
uint16_t const s = RT_MAKE_U16(id.value, IN_CONTACT | IN_RANGE);
mt_events[mt_number++] = RT_MAKE_U64_FROM_U16(x, y, s, 0);
}
});
ev.handle_touch_release([&] (Input::Touch_id id) {
uint16_t const s = RT_MAKE_U16(id.value, 0);
mt_events[mt_number++] = RT_MAKE_U64_FROM_U16(0, 0, s, 0);
});
});
/* if there are elements - send it */
/* if there are elements in multi-touch queue - send it */
if (mt_number)
_vbox_mouse->PutEventMultiTouch(mt_number, mt_number, mt_events,
RTTimeMilliTS());
RTTimeMilliTS());
}
void GenodeConsole::handle_mode_change()

View File

@ -148,18 +148,11 @@ void GenodeConsole::handle_input()
if (!_vbox_keyboard || !_vbox_mouse)
return;
bool const press = ev.type() == Input::Event::PRESS;
bool const release = ev.type() == Input::Event::RELEASE;
bool const key = press || release;
bool const motion = ev.type() == Input::Event::MOTION;
bool const wheel = ev.type() == Input::Event::WHEEL;
bool const touch = ev.type() == Input::Event::TOUCH;
auto keyboard_submit = [&] (Input::Keycode key, bool release) {
if (key) {
Scan_code scan_code(ev.keycode());
Scan_code scan_code(key);
unsigned char const release_bit =
(ev.type() == Input::Event::RELEASE) ? 0x80 : 0;
unsigned char const release_bit = release ? 0x80 : 0;
if (scan_code.normal())
_vbox_keyboard->PutScancode(scan_code.code() | release_bit);
@ -168,122 +161,116 @@ void GenodeConsole::handle_input()
_vbox_keyboard->PutScancode(0xe0);
_vbox_keyboard->PutScancode(scan_code.ext() | release_bit);
}
}
};
/*
* Track press/release status of keys and buttons. Currently,
* only the mouse-button states are actually used.
*/
if (press)
_key_status[ev.keycode()] = true;
/* obtain bit mask of currently pressed mouse buttons */
auto curr_mouse_button_bits = [&] () {
return (_key_status[Input::BTN_LEFT] ? MouseButtonState_LeftButton : 0)
| (_key_status[Input::BTN_RIGHT] ? MouseButtonState_RightButton : 0)
| (_key_status[Input::BTN_MIDDLE] ? MouseButtonState_MiddleButton : 0);
};
if (release)
_key_status[ev.keycode()] = false;
unsigned const old_mouse_button_bits = curr_mouse_button_bits();
bool const mouse_button_event =
key && _mouse_button(ev.keycode());
ev.handle_press([&] (Input::Keycode key, Genode::Codepoint) {
keyboard_submit(key, false);
_key_status[key] = true;
});
bool const mouse_event = mouse_button_event || motion;
ev.handle_release([&] (Input::Keycode key) {
keyboard_submit(key, true);
_key_status[key] = false;
});
if (mouse_event) {
unsigned const buttons = (_key_status[Input::BTN_LEFT] ? MouseButtonState_LeftButton : 0)
| (_key_status[Input::BTN_RIGHT] ? MouseButtonState_RightButton : 0)
| (_key_status[Input::BTN_MIDDLE] ? MouseButtonState_MiddleButton : 0);
if (ev.absolute_motion()) {
unsigned const mouse_button_bits = curr_mouse_button_bits();
_last_received_motion_event_was_absolute = true;
if (mouse_button_bits != old_mouse_button_bits) {
/* transform absolute to relative if guest is so odd */
if (!guest_abs && guest_rel) {
int const boundary = 20;
int rx = ev.ax() - _ax;
int ry = ev.ay() - _ay;
rx = Genode::min(boundary, Genode::max(-boundary, rx));
ry = Genode::min(boundary, Genode::max(-boundary, ry));
_vbox_mouse->PutMouseEvent(rx, ry, 0, 0, buttons);
} else
_vbox_mouse->PutMouseEventAbsolute(ev.ax(), ev.ay(), 0,
0, buttons);
_ax = ev.ax();
_ay = ev.ay();
} else if (ev.relative_motion()) {
_last_received_motion_event_was_absolute = false;
/* prefer relative motion event */
if (_last_received_motion_event_was_absolute) {
/* prefer absolute button event */
if (guest_abs)
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, mouse_button_bits);
else if (guest_rel)
_vbox_mouse->PutMouseEvent(0, 0, 0, 0, mouse_button_bits);
} else {
/* prefer relative button event */
if (guest_rel)
_vbox_mouse->PutMouseEvent(ev.rx(), ev.ry(), 0, 0, buttons);
else if (guest_abs) {
_ax += ev.rx();
_ay += ev.ry();
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons);
}
}
/* only the buttons changed */
else {
if (_last_received_motion_event_was_absolute) {
/* prefer absolute button event */
if (guest_abs)
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons);
else if (guest_rel)
_vbox_mouse->PutMouseEvent(0, 0, 0, 0, buttons);
} else {
/* prefer relative button event */
if (guest_rel)
_vbox_mouse->PutMouseEvent(0, 0, 0, 0, buttons);
else if (guest_abs)
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons);
}
_vbox_mouse->PutMouseEvent(0, 0, 0, 0, mouse_button_bits);
else if (guest_abs)
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, mouse_button_bits);
}
}
if (wheel) {
ev.handle_absolute_motion([&] (int x, int y) {
_last_received_motion_event_was_absolute = true;
/* transform absolute to relative if guest is so odd */
if (!guest_abs && guest_rel) {
int const boundary = 20;
int rx = x - _ax;
int ry = y - _ay;
rx = Genode::min(boundary, Genode::max(-boundary, rx));
ry = Genode::min(boundary, Genode::max(-boundary, ry));
_vbox_mouse->PutMouseEvent(rx, ry, 0, 0, mouse_button_bits);
} else
_vbox_mouse->PutMouseEventAbsolute(x, y, 0, 0, mouse_button_bits);
_ax = x;
_ay = y;
});
ev.handle_relative_motion([&] (int x, int y) {
_last_received_motion_event_was_absolute = false;
/* prefer relative motion event */
if (guest_rel)
_vbox_mouse->PutMouseEvent(x, y, 0, 0, mouse_button_bits);
else if (guest_abs) {
_ax += x;
_ay += y;
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, mouse_button_bits);
}
});
ev.handle_wheel([&] (int x, int y) {
if (_last_received_motion_event_was_absolute)
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, -ev.ry(), -ev.rx(), 0);
_vbox_mouse->PutMouseEventAbsolute(_ax, _ay, -y, -x, 0);
else
_vbox_mouse->PutMouseEvent(0, 0, -ev.ry(), -ev.rx(), 0);
}
_vbox_mouse->PutMouseEvent(0, 0, -y, -x, 0);
});
ev.handle_touch([&] (Input::Touch_id id, int x, int y) {
if (touch) {
/* if multitouch queue is full - send it */
if (mt_number >= sizeof(mt_events) / sizeof(mt_events[0])) {
_vbox_mouse->PutEventMultiTouch(mt_number, mt_number,
mt_events, RTTimeMilliTS());
mt_events, RTTimeMilliTS());
mt_number = 0;
}
int x = ev.ax();
int y = ev.ay();
int slot = ev.code();
/* Mouse::putEventMultiTouch drops values of 0 */
if (x <= 0) x = 1;
if (y <= 0) y = 1;
enum MultiTouch {
None = 0x0,
InContact = 0x01,
InRange = 0x02
};
enum { IN_CONTACT = 0x01, IN_RANGE = 0x02 };
int status = MultiTouch::InContact | MultiTouch::InRange;
if (ev.touch_release())
status = MultiTouch::None;
uint16_t const s = RT_MAKE_U16(slot, status);
uint16_t const s = RT_MAKE_U16(id.value, IN_CONTACT | IN_RANGE);
mt_events[mt_number++] = RT_MAKE_U64_FROM_U16(x, y, s, 0);
}
});
ev.handle_touch_release([&] (Input::Touch_id id) {
uint16_t const s = RT_MAKE_U16(id.value, 0);
mt_events[mt_number++] = RT_MAKE_U64_FROM_U16(0, 0, s, 0);
});
});
/* if there are elements - send it */
/* if there are elements in multi-touch queue - send it */
if (mt_number)
_vbox_mouse->PutEventMultiTouch(mt_number, mt_number, mt_events,
RTTimeMilliTS());
RTTimeMilliTS());
}
void GenodeConsole::handle_mode_change()