mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-29 15:44:02 +00:00
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:
parent
df3ceda052
commit
afcad2a968
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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); }
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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_ */
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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 */
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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> ®istry,
|
||||
Conditions conditions,
|
||||
Input::Event::Utf8 character)
|
||||
Rule(Registry<Rule> ®istry,
|
||||
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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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()));
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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); }
|
||||
|
@ -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()
|
||||
|
@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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); });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user