You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-04 12:00:25 +00:00
Merge pull request #102641 from Riteo/modifying-spacetime-itself
Wayland: Unstuck keys with same keycode
This commit is contained in:
@@ -369,33 +369,6 @@ void KeyMappingXKB::initialize() {
|
|||||||
location_map[0x86] = KeyLocation::RIGHT;
|
location_map[0x86] = KeyLocation::RIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KeyMappingXKB::is_sym_numpad(xkb_keysym_t p_keysym) {
|
|
||||||
switch (p_keysym) {
|
|
||||||
case XKB_KEY_KP_Equal:
|
|
||||||
case XKB_KEY_KP_Add:
|
|
||||||
case XKB_KEY_KP_Subtract:
|
|
||||||
case XKB_KEY_KP_Multiply:
|
|
||||||
case XKB_KEY_KP_Divide:
|
|
||||||
case XKB_KEY_KP_Separator:
|
|
||||||
case XKB_KEY_KP_Decimal:
|
|
||||||
case XKB_KEY_KP_Delete:
|
|
||||||
case XKB_KEY_KP_0:
|
|
||||||
case XKB_KEY_KP_1:
|
|
||||||
case XKB_KEY_KP_2:
|
|
||||||
case XKB_KEY_KP_3:
|
|
||||||
case XKB_KEY_KP_4:
|
|
||||||
case XKB_KEY_KP_5:
|
|
||||||
case XKB_KEY_KP_6:
|
|
||||||
case XKB_KEY_KP_7:
|
|
||||||
case XKB_KEY_KP_8:
|
|
||||||
case XKB_KEY_KP_9: {
|
|
||||||
return true;
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Key KeyMappingXKB::get_keycode(xkb_keycode_t p_keysym) {
|
Key KeyMappingXKB::get_keycode(xkb_keycode_t p_keysym) {
|
||||||
if (p_keysym >= 0x20 && p_keysym < 0x7E) { // ASCII, maps 1-1
|
if (p_keysym >= 0x20 && p_keysym < 0x7E) { // ASCII, maps 1-1
|
||||||
if (p_keysym > 0x60 && p_keysym < 0x7B) { // Lowercase ASCII.
|
if (p_keysym > 0x60 && p_keysym < 0x7B) { // Lowercase ASCII.
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ class KeyMappingXKB {
|
|||||||
public:
|
public:
|
||||||
static void initialize();
|
static void initialize();
|
||||||
|
|
||||||
static bool is_sym_numpad(xkb_keysym_t p_keysym);
|
|
||||||
static Key get_keycode(xkb_keysym_t p_keysym);
|
static Key get_keycode(xkb_keysym_t p_keysym);
|
||||||
static xkb_keycode_t get_xkb_keycode(Key p_keycode);
|
static xkb_keycode_t get_xkb_keycode(Key p_keycode);
|
||||||
static Key get_scancode(unsigned int p_code);
|
static Key get_scancode(unsigned int p_code);
|
||||||
|
|||||||
@@ -191,31 +191,34 @@ Vector<uint8_t> WaylandThread::_wp_primary_selection_offer_read(struct wl_displa
|
|||||||
return Vector<uint8_t>();
|
return Vector<uint8_t>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets up an `InputEventKey` and returns whether it has any meaningful value.
|
Ref<InputEventKey> WaylandThread::_seat_state_get_key_event(SeatState *p_ss, xkb_keycode_t p_keycode, bool p_pressed) {
|
||||||
bool WaylandThread::_seat_state_configure_key_event(SeatState &p_ss, Ref<InputEventKey> p_event, xkb_keycode_t p_keycode, bool p_pressed) {
|
Ref<InputEventKey> event;
|
||||||
xkb_keysym_t shifted_sym = xkb_state_key_get_one_sym(p_ss.xkb_state, p_keycode);
|
|
||||||
|
|
||||||
xkb_keysym_t plain_sym = XKB_KEY_NoSymbol;
|
ERR_FAIL_NULL_V(p_ss, event);
|
||||||
|
|
||||||
|
Key shifted_key = KeyMappingXKB::get_keycode(xkb_state_key_get_one_sym(p_ss->xkb_state, p_keycode));
|
||||||
|
|
||||||
|
Key plain_key = Key::NONE;
|
||||||
// NOTE: xkbcommon's API really encourages to apply the modifier state but we
|
// NOTE: xkbcommon's API really encourages to apply the modifier state but we
|
||||||
// only want a "plain" symbol so that we can convert it into a godot keycode.
|
// only want a "plain" symbol so that we can convert it into a godot keycode.
|
||||||
const xkb_keysym_t *syms = nullptr;
|
const xkb_keysym_t *syms = nullptr;
|
||||||
int num_sys = xkb_keymap_key_get_syms_by_level(p_ss.xkb_keymap, p_keycode, p_ss.current_layout_index, 0, &syms);
|
int num_sys = xkb_keymap_key_get_syms_by_level(p_ss->xkb_keymap, p_keycode, p_ss->current_layout_index, 0, &syms);
|
||||||
if (num_sys > 0 && syms) {
|
if (num_sys > 0 && syms) {
|
||||||
plain_sym = syms[0];
|
plain_key = KeyMappingXKB::get_keycode(syms[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Key physical_keycode = KeyMappingXKB::get_scancode(p_keycode);
|
Key physical_keycode = KeyMappingXKB::get_scancode(p_keycode);
|
||||||
KeyLocation key_location = KeyMappingXKB::get_location(p_keycode);
|
KeyLocation key_location = KeyMappingXKB::get_location(p_keycode);
|
||||||
uint32_t unicode = xkb_state_key_get_utf32(p_ss.xkb_state, p_keycode);
|
uint32_t unicode = xkb_state_key_get_utf32(p_ss->xkb_state, p_keycode);
|
||||||
|
|
||||||
Key keycode = Key::NONE;
|
Key keycode = Key::NONE;
|
||||||
|
|
||||||
if (KeyMappingXKB::is_sym_numpad(shifted_sym) || KeyMappingXKB::is_sym_numpad(plain_sym)) {
|
if ((shifted_key & Key::SPECIAL) != Key::NONE || (plain_key & Key::SPECIAL) != Key::NONE) {
|
||||||
keycode = KeyMappingXKB::get_keycode(shifted_sym);
|
keycode = shifted_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keycode == Key::NONE) {
|
if (keycode == Key::NONE) {
|
||||||
keycode = KeyMappingXKB::get_keycode(plain_sym);
|
keycode = plain_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keycode == Key::NONE) {
|
if (keycode == Key::NONE) {
|
||||||
@@ -227,41 +230,70 @@ bool WaylandThread::_seat_state_configure_key_event(SeatState &p_ss, Ref<InputEv
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (physical_keycode == Key::NONE && keycode == Key::NONE && unicode == 0) {
|
if (physical_keycode == Key::NONE && keycode == Key::NONE && unicode == 0) {
|
||||||
return false;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
p_event->set_window_id(DisplayServer::MAIN_WINDOW_ID);
|
event.instantiate();
|
||||||
|
|
||||||
|
event->set_window_id(DisplayServer::MAIN_WINDOW_ID);
|
||||||
|
|
||||||
// Set all pressed modifiers.
|
// Set all pressed modifiers.
|
||||||
p_event->set_shift_pressed(p_ss.shift_pressed);
|
event->set_shift_pressed(p_ss->shift_pressed);
|
||||||
p_event->set_ctrl_pressed(p_ss.ctrl_pressed);
|
event->set_ctrl_pressed(p_ss->ctrl_pressed);
|
||||||
p_event->set_alt_pressed(p_ss.alt_pressed);
|
event->set_alt_pressed(p_ss->alt_pressed);
|
||||||
p_event->set_meta_pressed(p_ss.meta_pressed);
|
event->set_meta_pressed(p_ss->meta_pressed);
|
||||||
|
|
||||||
p_event->set_pressed(p_pressed);
|
event->set_pressed(p_pressed);
|
||||||
p_event->set_keycode(keycode);
|
event->set_keycode(keycode);
|
||||||
p_event->set_physical_keycode(physical_keycode);
|
event->set_physical_keycode(physical_keycode);
|
||||||
p_event->set_location(key_location);
|
event->set_location(key_location);
|
||||||
|
|
||||||
if (unicode != 0) {
|
if (unicode != 0) {
|
||||||
p_event->set_key_label(fix_key_label(unicode, keycode));
|
event->set_key_label(fix_key_label(unicode, keycode));
|
||||||
} else {
|
} else {
|
||||||
p_event->set_key_label(keycode);
|
event->set_key_label(keycode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_pressed) {
|
if (p_pressed) {
|
||||||
p_event->set_unicode(fix_unicode(unicode));
|
event->set_unicode(fix_unicode(unicode));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Taken from DisplayServerX11.
|
// Taken from DisplayServerX11.
|
||||||
if (p_event->get_keycode() == Key::BACKTAB) {
|
if (event->get_keycode() == Key::BACKTAB) {
|
||||||
// Make it consistent across platforms.
|
// Make it consistent across platforms.
|
||||||
p_event->set_keycode(Key::TAB);
|
event->set_keycode(Key::TAB);
|
||||||
p_event->set_physical_keycode(Key::TAB);
|
event->set_physical_keycode(Key::TAB);
|
||||||
p_event->set_shift_pressed(true);
|
event->set_shift_pressed(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Due to the nature of the way keys are encoded, there's an ambiguity
|
||||||
|
// regarding "special" keys. In other words: there's no reliable way of
|
||||||
|
// switching between a special key and a character key if not marking a
|
||||||
|
// different Godot keycode, even if we're actually using the same XKB raw
|
||||||
|
// keycode. This means that, during this switch, the old key will get "stuck",
|
||||||
|
// as it will never receive a release event. This method returns the necessary
|
||||||
|
// event to fix this if needed.
|
||||||
|
Ref<InputEventKey> WaylandThread::_seat_state_get_unstuck_key_event(SeatState *p_ss, xkb_keycode_t p_keycode, bool p_pressed, Key p_key) {
|
||||||
|
Ref<InputEventKey> event;
|
||||||
|
|
||||||
|
if (p_pressed) {
|
||||||
|
Key *old_key = p_ss->pressed_keycodes.getptr(p_keycode);
|
||||||
|
if (old_key != nullptr && *old_key != p_key) {
|
||||||
|
print_verbose(vformat("%s and %s have same keycode. Generating release event for %s", keycode_get_string(*old_key), keycode_get_string(p_key), keycode_get_string(*old_key)));
|
||||||
|
event = _seat_state_get_key_event(p_ss, p_keycode, false);
|
||||||
|
if (event.is_valid()) {
|
||||||
|
event->set_keycode(*old_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p_ss->pressed_keycodes[p_keycode] = p_key;
|
||||||
|
} else {
|
||||||
|
p_ss->pressed_keycodes.erase(p_keycode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaylandThread::_set_current_seat(struct wl_seat *p_seat) {
|
void WaylandThread::_set_current_seat(struct wl_seat *p_seat) {
|
||||||
@@ -1920,13 +1952,19 @@ void WaylandThread::_wl_keyboard_on_key(void *data, struct wl_keyboard *wl_keybo
|
|||||||
ss->repeating_keycode = XKB_KEYCODE_INVALID;
|
ss->repeating_keycode = XKB_KEYCODE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<InputEventKey> k;
|
Ref<InputEventKey> k = _seat_state_get_key_event(ss, xkb_keycode, pressed);
|
||||||
k.instantiate();
|
if (k.is_null()) {
|
||||||
|
|
||||||
if (!_seat_state_configure_key_event(*ss, k, xkb_keycode, pressed)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ref<InputEventKey> uk = _seat_state_get_unstuck_key_event(ss, xkb_keycode, pressed, k->get_keycode());
|
||||||
|
if (uk.is_valid()) {
|
||||||
|
Ref<InputEventMessage> u_msg;
|
||||||
|
u_msg.instantiate();
|
||||||
|
u_msg->event = uk;
|
||||||
|
wayland_thread->push_message(u_msg);
|
||||||
|
}
|
||||||
|
|
||||||
Ref<InputEventMessage> msg;
|
Ref<InputEventMessage> msg;
|
||||||
msg.instantiate();
|
msg.instantiate();
|
||||||
msg->event = k;
|
msg->event = k;
|
||||||
@@ -3236,15 +3274,18 @@ void WaylandThread::seat_state_echo_keys(SeatState *p_ss) {
|
|||||||
int keys_amount = (ticks_delta / p_ss->repeat_key_delay_msec);
|
int keys_amount = (ticks_delta / p_ss->repeat_key_delay_msec);
|
||||||
|
|
||||||
for (int i = 0; i < keys_amount; i++) {
|
for (int i = 0; i < keys_amount; i++) {
|
||||||
Ref<InputEventKey> k;
|
Ref<InputEventKey> k = _seat_state_get_key_event(p_ss, p_ss->repeating_keycode, true);
|
||||||
k.instantiate();
|
if (k.is_null()) {
|
||||||
|
|
||||||
if (!_seat_state_configure_key_event(*p_ss, k, p_ss->repeating_keycode, true)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
k->set_echo(true);
|
k->set_echo(true);
|
||||||
|
|
||||||
|
Ref<InputEventKey> uk = _seat_state_get_unstuck_key_event(p_ss, p_ss->repeating_keycode, true, k->get_keycode());
|
||||||
|
if (uk.is_valid()) {
|
||||||
|
Input::get_singleton()->parse_input_event(uk);
|
||||||
|
}
|
||||||
|
|
||||||
Input::get_singleton()->parse_input_event(k);
|
Input::get_singleton()->parse_input_event(k);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -428,6 +428,8 @@ public:
|
|||||||
const char *keymap_buffer = nullptr;
|
const char *keymap_buffer = nullptr;
|
||||||
uint32_t keymap_buffer_size = 0;
|
uint32_t keymap_buffer_size = 0;
|
||||||
|
|
||||||
|
HashMap<xkb_keycode_t, Key> pressed_keycodes;
|
||||||
|
|
||||||
xkb_layout_index_t current_layout_index = 0;
|
xkb_layout_index_t current_layout_index = 0;
|
||||||
|
|
||||||
int32_t repeat_key_delay_msec = 0;
|
int32_t repeat_key_delay_msec = 0;
|
||||||
@@ -903,7 +905,8 @@ private:
|
|||||||
static Vector<uint8_t> _wp_primary_selection_offer_read(struct wl_display *wl_display, const char *p_mime, struct zwp_primary_selection_offer_v1 *wp_primary_selection_offer);
|
static Vector<uint8_t> _wp_primary_selection_offer_read(struct wl_display *wl_display, const char *p_mime, struct zwp_primary_selection_offer_v1 *wp_primary_selection_offer);
|
||||||
|
|
||||||
static void _seat_state_set_current(WaylandThread::SeatState &p_ss);
|
static void _seat_state_set_current(WaylandThread::SeatState &p_ss);
|
||||||
static bool _seat_state_configure_key_event(WaylandThread::SeatState &p_seat, Ref<InputEventKey> p_event, xkb_keycode_t p_keycode, bool p_pressed);
|
static Ref<InputEventKey> _seat_state_get_key_event(SeatState *p_ss, xkb_keycode_t p_keycode, bool p_pressed);
|
||||||
|
static Ref<InputEventKey> _seat_state_get_unstuck_key_event(SeatState *p_ss, xkb_keycode_t p_keycode, bool p_pressed, Key p_key);
|
||||||
|
|
||||||
static void _wayland_state_update_cursor();
|
static void _wayland_state_update_cursor();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user