diff --git a/include/ipc.h b/include/ipc.h index 6063f69c5..7ae21ab31 100644 --- a/include/ipc.h +++ b/include/ipc.h @@ -34,6 +34,7 @@ enum ipc_command_type { // sway-specific event types IPC_EVENT_BAR_STATE_UPDATE = ((1<<31) | 20), + IPC_EVENT_INPUT = ((1<<31) | 21), }; #endif diff --git a/include/sway/input/keyboard.h b/include/sway/input/keyboard.h index 90214af91..1ff63c941 100644 --- a/include/sway/input/keyboard.h +++ b/include/sway/input/keyboard.h @@ -52,6 +52,7 @@ struct sway_keyboard { struct sway_seat_device *seat_device; struct xkb_keymap *keymap; + xkb_layout_index_t effective_layout; struct wl_listener keyboard_key; struct wl_listener keyboard_modifiers; diff --git a/include/sway/ipc-server.h b/include/sway/ipc-server.h index 3c43f74d2..bc4f781ad 100644 --- a/include/sway/ipc-server.h +++ b/include/sway/ipc-server.h @@ -2,6 +2,7 @@ #define _SWAY_IPC_SERVER_H #include #include "sway/config.h" +#include "sway/input/input-manager.h" #include "sway/tree/container.h" #include "ipc.h" @@ -19,5 +20,6 @@ void ipc_event_bar_state_update(struct bar_config *bar); void ipc_event_mode(const char *mode, bool pango); void ipc_event_shutdown(const char *reason); void ipc_event_binding(struct sway_binding *binding); +void ipc_event_input(const char *change, struct sway_input_device *device); #endif diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index 4fd980c49..dd84a0b38 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -12,6 +12,7 @@ #include "sway/config.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" +#include "sway/ipc-server.h" #include "sway/server.h" #include "stringop.h" #include "list.h" @@ -584,6 +585,8 @@ static void handle_device_destroy(struct wl_listener *listener, void *data) { seat_remove_device(seat, input_device); } + ipc_event_input("removed", input_device); + wl_list_remove(&input_device->link); wl_list_remove(&input_device->device_destroy.link); free(input_device->identifier); @@ -656,6 +659,8 @@ static void handle_new_input(struct wl_listener *listener, void *data) { "device '%s' is not configured on any seats", input_device->identifier); } + + ipc_event_input("added", input_device); } static void handle_inhibit_activate(struct wl_listener *listener, void *data) { diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 1f7ed8494..328458fa9 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -473,6 +473,11 @@ static void handle_keyboard_modifiers(struct wl_listener *listener, uint32_t modifiers = wlr_keyboard_get_modifiers(wlr_device->keyboard); determine_bar_visibility(modifiers); + + if (wlr_device->keyboard->modifiers.group != keyboard->effective_layout) { + keyboard->effective_layout = wlr_device->keyboard->modifiers.group; + ipc_event_input("xkb_layout", keyboard->seat_device->input_device); + } } struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, @@ -603,8 +608,23 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) { } } + bool keymap_changed = false; + bool effective_layout_changed = keyboard->effective_layout != 0; + if (keyboard->keymap) { + char *old_keymap_string = xkb_keymap_get_as_string(keyboard->keymap, + XKB_KEYMAP_FORMAT_TEXT_V1); + char *new_keymap_string = xkb_keymap_get_as_string(keymap, + XKB_KEYMAP_FORMAT_TEXT_V1); + keymap_changed = strcmp(old_keymap_string, new_keymap_string); + free(old_keymap_string); + free(new_keymap_string); + } else { + keymap_changed = true; + } + xkb_keymap_unref(keyboard->keymap); keyboard->keymap = keymap; + keyboard->effective_layout = 0; wlr_keyboard_set_keymap(wlr_device->keyboard, keyboard->keymap); xkb_mod_mask_t locked_mods = 0; @@ -654,6 +674,14 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) { wl_signal_add(&wlr_device->keyboard->events.modifiers, &keyboard->keyboard_modifiers); keyboard->keyboard_modifiers.notify = handle_keyboard_modifiers; + + if (keymap_changed) { + ipc_event_input("xkb_keymap", + keyboard->seat_device->input_device); + } else if (effective_layout_changed) { + ipc_event_input("xkb_layout", + keyboard->seat_device->input_device); + } } void sway_keyboard_destroy(struct sway_keyboard *keyboard) { diff --git a/sway/ipc-server.c b/sway/ipc-server.c index ca1c1b120..773e90fdd 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -487,6 +487,21 @@ static void ipc_event_tick(const char *payload) { json_object_put(json); } +void ipc_event_input(const char *change, struct sway_input_device *device) { + if (!ipc_has_event_listeners(IPC_EVENT_INPUT)) { + return; + } + sway_log(SWAY_DEBUG, "Sending input event"); + + json_object *json = json_object_new_object(); + json_object_object_add(json, "change", json_object_new_string(change)); + json_object_object_add(json, "input", ipc_json_describe_input(device)); + + const char *json_string = json_object_to_json_string(json); + ipc_send_event(json_string, IPC_EVENT_INPUT); + json_object_put(json); +} + int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) { struct ipc_client *client = data; @@ -716,6 +731,8 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt } else if (strcmp(event_type, "tick") == 0) { client->subscribed_events |= event_mask(IPC_EVENT_TICK); is_tick = true; + } else if (strcmp(event_type, "input") == 0) { + client->subscribed_events |= event_mask(IPC_EVENT_INPUT); } else { const char msg[] = "{\"success\": false}"; ipc_send_reply(client, payload_type, msg, strlen(msg)); diff --git a/sway/sway-ipc.7.scd b/sway/sway-ipc.7.scd index 3657dcd61..4688e46d1 100644 --- a/sway/sway-ipc.7.scd +++ b/sway/sway-ipc.7.scd @@ -1371,6 +1371,9 @@ available: |- 0x80000014 : bar_status_update : Send when the visibility of a bar should change due to a modifier +|- 0x80000015 +: input +: Sent when something related to input devices changes ## 0x80000000. WORKSPACE @@ -1702,6 +1705,56 @@ event is a single object with the following properties: } ``` +## 0x80000015. INPUT + +Sent when something related to the input devices changes. The event is a single +object with the following properties: + +[- *PROPERTY* +:- *DATA TYPE* +:- *DESCRIPTION* +|- change +: string +:[ What has changed +|- input +: object +: An object representing the input that is identical the ones GET_INPUTS gives + +The following change types are currently available: +[- *TYPE* +:- *DESCRIPTION* +|- added +:[ The input device became available +|- removed +: The input device is no longer available +|- xkb_keymap +: (Keyboards only) The keymap for the keyboard has changed +|- xkb_layout +: (Keyboards only) The effective layout in the keymap has changed + +*Example Event:* +``` +{ + "change": "xkb_layout", + "input": { + "identifier": "1:1:AT_Translated_Set_2_keyboard", + "name": "AT Translated Set 2 keyboard", + "vendor": 1, + "product": 1, + "type": "keyboard", + "xkb_layout_names": [ + "English (US)", + "English (Dvorak)" + ], + "xkb_active_layout_index": 1, + "xkb_active_layout_name": "English (Dvorak)", + "libinput": { + "send_events": "enabled" + } + } +} +``` + # SEE ALSO *sway*(1) *sway*(5) *sway-bar*(5) *swaymsg*(1) *sway-input*(5) *sway-output*(5)