Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keyboard support #9

Merged
merged 14 commits into from
Mar 31, 2022
Merged

Conversation

charafau
Copy link
Contributor

This PR targets https://github.com/PlayPulseCom/flutter_wlroots/issues/1

Current status:

  • Forward input from wlroots backend to the flutter engine. This includes handling the new keyboard signal emitted by wlroots and registering handlers for key events which call into the flutter engine API.

  • Implement keyboard event handling in SurfaceWidget. This would involve introducing a focus node and adding a handler for keyboard events. Implementing focus-on-click vs focus-on-hover (or some other mechanism) is best left to the consumer, but the dart library should make this easy.

  • Make sure the surface receives keyboard events correctly. This involves making a new message handler for keyboard events in native code which forwards the events to wlroots. This would be called by the SurfaceWidget when input events are received.

  • Make sure the surface receives/loses keyboard focus when the focus node receives/loses focus. This involves making a new message handler for managing focus changes in the native code, then forwarding that to wlroots. This would then be called by the SurfaceWidget when the focus node changes state.

^ We might want to add this in separate request when we have more than 1 SurfaceWidget and easy way to switch between them

charafau added 9 commits March 7, 2022 22:25
Add json serialization lib
Add collection lib
Add key mappings
Add sending key to flutter
Add sending key from flutter to wlroots
Add passing key from wlroots to view
Add sending key events from flutter to wayland client
Add json serialization library
Add collections header lib
Add key maps for xcb to flutter keys

// DO NOT EDIT -- DO NOT EDIT -- DO NOT EDIT
// This file is generated by
// flutter/flutter@dev/tools/gen_keycodes/bin/gen_keycodes.dart and should not
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this file unmodified from the generator, or has there been modifications?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

original is from generator, this one is not. I will remove comment

const int pointerKindUnknown = 3;

const Map<int, int> physicalToXkbMap = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this mapping from? Is there any reason not to do this on the C side where the other parts of the mapping live?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is taken from the gtk embedding iirc and it's just a reversed version of the xkb to physical map. Imo it should be in dart as it's easier to handle there as in c, but I'm open to anything really

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 127 to 137
platform.channel
.invokeMethod("testing")
.then((value) => {print("testing message response")})
.catchError((error) => {print("error")});

platform.addHandler("flutter/keyevent", (call) async {
print('got event: ${call.arguments["keymap"]}');
print('got event: ${call.arguments["keyCode"]}');
print('got event: ${call.arguments["type"]}');
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should likely be removed, debug code

status = KeyStatus.released;
}

int? keycode = physicalToXkbMap[event.physicalKey.usbHidUsage];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the function for this in the compositor

Comment on lines +92 to +96
if (event is KeyDownEvent) {
status = KeyStatus.pressed;
} else {
status = KeyStatus.released;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessarily Down OR Up? What about key repeat event?

It would at least be nice to do an is check on both of these branches, then debug print if we get an event type we didn't expect.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wlroots doesn't have a concept for repeat, instead it decides to "repeat" once it gets enough down events for the same key (at least by observing how it behaves + no enum entry for repeat)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does seem like wlroots has the concept of repeats, as evident by wlr_keyboard_set_repeat_info.

So wlroots uses subsequent PRESSED events as the signal of a repeat key then? This should be converted to the Repeat event in the flutter engine on the C side.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pardon, i corrected myself in a comment later on. As i stated there, as long as a key is signaled as being pressed then it will be "repeated". Once the key is signaled as up then it will stop being repeated

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically what @HrX03 said. wlroots will send up events which will work as repeat.

goto error;
}

wlr_seat_keyboard_notify_key(instance->seat, message.timestamp / NS_PER_MS, message.keycode - 8, type);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No management of active seat surface at all? Might be considered part of point 4?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By looking at various wl impls keyboard focus should be moved only on view focus, like when opening a new surface or when the user clicks the view to focus. We should change the flutter side to have one big global listener indeed instead of one for each surface as it doesn't really match with how wlroots handles keyboard

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's 1 surface for now.

src/input.c Outdated
Comment on lines 647 to 664


// void fwr_handle_key_press(struct fwr_instance *instance, const FlutterPlatformMessageResponseHandle *handle, struct dart_value *args){
// struct wlr_seat *seat = instance->seat;

// struct key_event_message message;
// if (!decode_key_event_message(args, &message)) {
// wlr_log(WLR_ERROR, "Invalid key event message");
// return;
// }

// uint32_t xkb_key = physical_to_xkb_key(message.physical_key_id - 8);
// // wlr_log(WLR_INFO, "should transform key %s", xkb_key);


// wlr_seat_keyboard_notify_key(seat, message.timestamp,
// xkb_key, message.key_state);
// }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove unused code

@@ -14,6 +15,43 @@ static void cb(const uint8_t *data, size_t size, void *user_data) {
wlr_log(WLR_INFO, "callback");
}

static void focus_view(struct fwr_view *view, struct wlr_surface *surface) {
/* Note: this function only deals with keyboard focus. */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inconsistent formatting

@@ -63,7 +101,10 @@ static void xdg_toplevel_map(struct wl_listener *listener, void *data) {

instance->fl_proc_table.PlatformMessageReleaseResponseHandle(instance->engine,
response_handle);

focus_view(view, view->surface);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No proper focus management? Part of point 4?

src/surface.c Outdated
Comment on lines 118 to 119
view->instance = instance;
view->surface = xdg_surface;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason for this move?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, was having some issues and moved stuff around to test, just forgot to put it back where it once was

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restored

include/jsmn.h Outdated
JSMN_UNDEFINED = 0,
JSMN_OBJECT = 1,
JSMN_ARRAY = 2,
JSMN_STRING = 3,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use 1 2 3 4 instead of the bit shifted constants?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like original lib has bitshift operatoions but flutter-pi has constants. I reverted to bit shift operators because I'd rather no to modify extrenal library

Comment on lines 1 to 41
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef KEYBOARD_MAP_H_
#define KEYBOARD_MAP_H_

#include <xkbcommon/xkbcommon.h>

#define WLR_USE_UNSTABLE
#include <wlr/types/wlr_keyboard.h>

#ifdef __cplusplus
extern "C" {
#endif


// Mask for the 32-bit value portion of the key code.
extern const uint64_t kValueMask;

// The plane value for keys which have a Unicode representation.
extern const uint64_t kUnicodePlane;

// The plane value for the private keys defined by the GTK embedding.
extern const uint64_t kGtkPlane;

uint64_t apply_id_plane(uint64_t logical_id, uint64_t plane);

uint64_t event_to_physical_key(struct wlr_event_keyboard_key *event);

uint64_t event_to_logical_key(struct wlr_event_keyboard_key *event, struct xkb_state *state);

uint32_t event_to_unicode(struct wlr_event_keyboard_key *event, struct xkb_state *state);

uint64_t event_to_timestamp(struct wlr_event_keyboard_key *event);

#ifdef __cplusplus
}
#endif

#endif // KEYBOARD_MAP_H_
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This + the c impl should be replaced with the xkb based methods

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you elaborate on that?

// uint32_t unicode = event_to_unicode(event, kb_state);

struct xkb_state *kb_state = keyboard->device->keyboard->xkb_state;
uint32_t modifiers = keyboard_state_is_shift_active(kb_state)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is directly taken from the flutter-pi docs but I think I should be able to get some docs from flutter code

| (keyboard_state_is_alt_active(kb_state) << 3)
| (keyboard_state_is_numlock_active(kb_state) << 4)
| (keyboard_state_is_meta_active(kb_state) << 28);
uint16_t scan_code = (uint16_t)event->keycode + 8;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, but instead of flutter some xkb/libinput docs

Comment on lines +301 to +311
switch(event->state) {
case WL_KEYBOARD_KEY_STATE_PRESSED:
type = "keydown";
flType = kFlutterKeyEventTypeDown;
break;
case WL_KEYBOARD_KEY_STATE_RELEASED:
default:
type = "keyup";
flType = kFlutterKeyEventTypeUp;
break;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is correct for the flutter part but wlroots has no concept of repeat as far as I'm concerned, until one key is kept pressed it's going to keep it pressed apparently

wlr_keyboard_set_keymap(device->keyboard, keymap);
xkb_keymap_unref(keymap);
xkb_context_unref(context);
wlr_keyboard_set_repeat_info(device->keyboard, 25, 600);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tinywl source code iirc

goto error;
}

wlr_seat_keyboard_notify_key(instance->seat, message.timestamp / NS_PER_MS, message.keycode - 8, type);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By looking at various wl impls keyboard focus should be moved only on view focus, like when opening a new surface or when the user clicks the view to focus. We should change the flutter side to have one big global listener indeed instead of one for each surface as it doesn't really match with how wlroots handles keyboard

src/surface.c Outdated
Comment on lines 118 to 119
view->instance = instance;
view->surface = xdg_surface;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, was having some issues and moved stuff around to test, just forgot to put it back where it once was

removed duplicated key map in surface
removed debug code
@hansihe
Copy link
Member

hansihe commented Mar 26, 2022

Todos:

  • Remove collections.h, put asserts part into asserts.h
  • Revert unnecessary changes in surface.c

Move assert code to asserts.h
Revert unnecessary code changes
@hansihe hansihe merged commit 0202384 into FlutterWayland:master Mar 31, 2022
@hansihe
Copy link
Member

hansihe commented Mar 31, 2022

Thanks!

@charafau charafau deleted the keyboard_support_send_key branch April 1, 2022 16:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants