Skip to content

wayland: Add multi-seat support #12626

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

Merged
merged 1 commit into from
Apr 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 44 additions & 29 deletions src/events/SDL_keyboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,6 @@ typedef struct SDL_Keyboard
Uint8 keysource[SDL_SCANCODE_COUNT];
bool keystate[SDL_SCANCODE_COUNT];
SDL_Keymap *keymap;
bool french_numbers;
bool latin_letters;
bool thai_keyboard;
Uint32 keycode_options;
bool autorelease_pending;
Uint64 hardware_timestamp;
Expand Down Expand Up @@ -175,6 +172,19 @@ void SDL_RemoveKeyboard(SDL_KeyboardID keyboardID, bool send_event)
}
}

void SDL_SetKeyboardName(SDL_KeyboardID keyboardID, const char *name)
{
SDL_assert(keyboardID != 0);

const int keyboard_index = SDL_GetKeyboardIndex(keyboardID);

if (keyboard_index >= 0) {
SDL_KeyboardInstance *instance = &SDL_keyboards[keyboard_index];
SDL_free(instance->name);
instance->name = SDL_strdup(name ? name : "");
}
}

bool SDL_HasKeyboard(void)
{
return (SDL_keyboard_count > 0);
Expand Down Expand Up @@ -232,14 +242,15 @@ void SDL_ResetKeyboard(void)
SDL_Keymap *SDL_GetCurrentKeymap(void)
{
SDL_Keyboard *keyboard = &SDL_keyboard;
SDL_Keymap *keymap = SDL_keyboard.keymap;

if (keyboard->thai_keyboard) {
if (keymap && keymap->thai_keyboard) {
// Thai keyboards are QWERTY plus Thai characters, use the default QWERTY keymap
return NULL;
}

if ((keyboard->keycode_options & KEYCODE_OPTION_LATIN_LETTERS) &&
!keyboard->latin_letters) {
keymap && !keymap->latin_letters) {
// We'll use the default QWERTY keymap
return NULL;
}
Expand All @@ -251,35 +262,39 @@ void SDL_SetKeymap(SDL_Keymap *keymap, bool send_event)
{
SDL_Keyboard *keyboard = &SDL_keyboard;

if (keyboard->keymap) {
if (keyboard->keymap && keyboard->keymap->auto_release) {
SDL_DestroyKeymap(keyboard->keymap);
}

keyboard->keymap = keymap;

// Detect French number row (all symbols)
keyboard->french_numbers = true;
for (int i = SDL_SCANCODE_1; i <= SDL_SCANCODE_0; ++i) {
if (SDL_isdigit(SDL_GetKeymapKeycode(keymap, (SDL_Scancode)i, SDL_KMOD_NONE)) ||
!SDL_isdigit(SDL_GetKeymapKeycode(keymap, (SDL_Scancode)i, SDL_KMOD_SHIFT))) {
keyboard->french_numbers = false;
break;
}
}
if (keymap && !keymap->layout_determined) {
keymap->layout_determined = true;

// Detect non-Latin keymap
keyboard->thai_keyboard = false;
keyboard->latin_letters = false;
for (int i = SDL_SCANCODE_A; i <= SDL_SCANCODE_D; ++i) {
SDL_Keycode key = SDL_GetKeymapKeycode(keymap, (SDL_Scancode)i, SDL_KMOD_NONE);
if (key <= 0xFF) {
keyboard->latin_letters = true;
break;
// Detect French number row (all symbols)
keymap->french_numbers = true;
for (int i = SDL_SCANCODE_1; i <= SDL_SCANCODE_0; ++i) {
if (SDL_isdigit(SDL_GetKeymapKeycode(keymap, (SDL_Scancode)i, SDL_KMOD_NONE)) ||
!SDL_isdigit(SDL_GetKeymapKeycode(keymap, (SDL_Scancode)i, SDL_KMOD_SHIFT))) {
keymap->french_numbers = false;
break;
}
}

if (key >= 0x0E00 && key <= 0x0E7F) {
keyboard->thai_keyboard = true;
break;
// Detect non-Latin keymap
keymap->thai_keyboard = false;
keymap->latin_letters = false;
for (int i = SDL_SCANCODE_A; i <= SDL_SCANCODE_D; ++i) {
SDL_Keycode key = SDL_GetKeymapKeycode(keymap, (SDL_Scancode)i, SDL_KMOD_NONE);
if (key <= 0xFF) {
keymap->latin_letters = true;
break;
}

if (key >= 0x0E00 && key <= 0x0E7F) {
keymap->thai_keyboard = true;
break;
}
}
}

Expand Down Expand Up @@ -308,7 +323,7 @@ static void SetKeymapEntry(SDL_Scancode scancode, SDL_Keymod modstate, SDL_Keyco
SDL_Keyboard *keyboard = &SDL_keyboard;

if (!keyboard->keymap) {
keyboard->keymap = SDL_CreateKeymap();
keyboard->keymap = SDL_CreateKeymap(true);
}

SDL_SetKeymapEntry(keyboard->keymap, scancode, modstate, keycode);
Expand Down Expand Up @@ -483,7 +498,7 @@ SDL_Keycode SDL_GetKeyFromScancode(SDL_Scancode scancode, SDL_Keymod modstate, b
modstate = SDL_KMOD_NONE;

if ((keyboard->keycode_options & KEYCODE_OPTION_FRENCH_NUMBERS) &&
keyboard->french_numbers &&
keymap && keymap->french_numbers &&
(scancode >= SDL_SCANCODE_1 && scancode <= SDL_SCANCODE_0)) {
// Add the shift state to generate a numeric keycode
modstate |= SDL_KMOD_SHIFT;
Expand Down Expand Up @@ -876,7 +891,7 @@ void SDL_QuitKeyboard(void)
SDL_free(SDL_keyboards);
SDL_keyboards = NULL;

if (SDL_keyboard.keymap) {
if (SDL_keyboard.keymap && SDL_keyboard.keymap->auto_release) {
SDL_DestroyKeymap(SDL_keyboard.keymap);
SDL_keyboard.keymap = NULL;
}
Expand Down
3 changes: 3 additions & 0 deletions src/events/SDL_keyboard_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ extern void SDL_AddKeyboard(SDL_KeyboardID keyboardID, const char *name, bool se
// A keyboard has been removed from the system
extern void SDL_RemoveKeyboard(SDL_KeyboardID keyboardID, bool send_event);

// Set or update the name of a keyboard instance.
extern void SDL_SetKeyboardName(SDL_KeyboardID keyboardID, const char *name);

// Set the mapping of scancode to key codes
extern void SDL_SetKeymap(SDL_Keymap *keymap, bool send_event);

Expand Down
11 changes: 3 additions & 8 deletions src/events/SDL_keymap.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,17 @@
#include "SDL_keymap_c.h"
#include "SDL_keyboard_c.h"

struct SDL_Keymap
{
SDL_HashTable *scancode_to_keycode;
SDL_HashTable *keycode_to_scancode;
};

static SDL_Keycode SDL_GetDefaultKeyFromScancode(SDL_Scancode scancode, SDL_Keymod modstate);
static SDL_Scancode SDL_GetDefaultScancodeFromKey(SDL_Keycode key, SDL_Keymod *modstate);

SDL_Keymap *SDL_CreateKeymap(void)
SDL_Keymap *SDL_CreateKeymap(bool auto_release)
{
SDL_Keymap *keymap = (SDL_Keymap *)SDL_malloc(sizeof(*keymap));
SDL_Keymap *keymap = (SDL_Keymap *)SDL_calloc(1, sizeof(*keymap));
if (!keymap) {
return NULL;
}

keymap->auto_release = auto_release;
keymap->scancode_to_keycode = SDL_CreateHashTable(256, false, SDL_HashID, SDL_KeyMatchID, NULL, NULL);
keymap->keycode_to_scancode = SDL_CreateHashTable(256, false, SDL_HashID, SDL_KeyMatchID, NULL, NULL);
if (!keymap->scancode_to_keycode || !keymap->keycode_to_scancode) {
Expand Down
13 changes: 11 additions & 2 deletions src/events/SDL_keymap_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,19 @@
#ifndef SDL_keymap_c_h_
#define SDL_keymap_c_h_

typedef struct SDL_Keymap SDL_Keymap;
typedef struct SDL_Keymap
{
SDL_HashTable *scancode_to_keycode;
SDL_HashTable *keycode_to_scancode;
bool auto_release;
bool layout_determined;
bool french_numbers;
bool latin_letters;
bool thai_keyboard;
} SDL_Keymap;

SDL_Keymap *SDL_GetCurrentKeymap(void);
SDL_Keymap *SDL_CreateKeymap(void);
SDL_Keymap *SDL_CreateKeymap(bool auto_release);
void SDL_SetKeymapEntry(SDL_Keymap *keymap, SDL_Scancode scancode, SDL_Keymod modstate, SDL_Keycode keycode);
SDL_Keycode SDL_GetKeymapKeycode(SDL_Keymap *keymap, SDL_Scancode scancode, SDL_Keymod modstate);
SDL_Scancode SDL_GetKeymapScancode(SDL_Keymap *keymap, SDL_Keycode keycode, SDL_Keymod *modstate);
Expand Down
13 changes: 13 additions & 0 deletions src/events/SDL_mouse.c
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,19 @@ void SDL_RemoveMouse(SDL_MouseID mouseID, bool send_event)
}
}

void SDL_SetMouseName(SDL_MouseID mouseID, const char *name)
{
SDL_assert(mouseID != 0);

const int mouse_index = SDL_GetMouseIndex(mouseID);

if (mouse_index >= 0) {
SDL_MouseInstance *instance = &SDL_mice[mouse_index];
SDL_free(instance->name);
instance->name = SDL_strdup(name ? name : "");
}
}

bool SDL_HasMouse(void)
{
return (SDL_mouse_count > 0);
Expand Down
3 changes: 3 additions & 0 deletions src/events/SDL_mouse_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,9 @@ extern void SDL_AddMouse(SDL_MouseID mouseID, const char *name, bool send_event)
// A mouse has been removed from the system
extern void SDL_RemoveMouse(SDL_MouseID mouseID, bool send_event);

// Set or update the name of a mouse instance.
extern void SDL_SetMouseName(SDL_MouseID mouseID, const char *name);

// Get the mouse state structure
extern SDL_Mouse *SDL_GetMouse(void);

Expand Down
10 changes: 10 additions & 0 deletions src/events/SDL_touch.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,16 @@ int SDL_AddTouch(SDL_TouchID touchID, SDL_TouchDeviceType type, const char *name
return index;
}

// Set or update the name of a touch.
void SDL_SetTouchName(SDL_TouchID id, const char *name)
{
SDL_Touch *touch = SDL_GetTouch(id);
if (touch) {
SDL_free(touch->name);
touch->name = SDL_strdup(name ? name : "");
}
}

static bool SDL_AddFinger(SDL_Touch *touch, SDL_FingerID fingerid, float x, float y, float pressure)
{
SDL_Finger *finger;
Expand Down
3 changes: 3 additions & 0 deletions src/events/SDL_touch_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ extern bool SDL_TouchDevicesAvailable(void);
// Add a touch, returning the index of the touch, or -1 if there was an error.
extern int SDL_AddTouch(SDL_TouchID id, SDL_TouchDeviceType type, const char *name);

// Set or update the name of a touch.
extern void SDL_SetTouchName(SDL_TouchID id, const char *name);

// Get the touch with a given id
extern SDL_Touch *SDL_GetTouch(SDL_TouchID id);

Expand Down
8 changes: 7 additions & 1 deletion src/test/SDL_test_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -2511,7 +2511,13 @@ SDL_AppResult SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const
/* Ctrl-G toggle mouse grab */
SDL_Window *window = SDL_GetWindowFromEvent(event);
if (window) {
SDL_SetWindowMouseGrab(window, !SDL_GetWindowMouseGrab(window));
if (SDL_RectEmpty(SDL_GetWindowMouseRect(window))) {
SDL_Rect r = { 10, 10, 200, 200};
SDL_SetWindowMouseRect(window, &r);
} else {
SDL_SetWindowMouseRect(window, NULL);
}
//SDL_SetWindowMouseGrab(window, !SDL_GetWindowMouseGrab(window));
}
}
break;
Expand Down
2 changes: 1 addition & 1 deletion src/video/cocoa/SDL_cocoakeyboard.m
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ static void UpdateKeymap(SDL_CocoaVideoData *data, bool send_event)

UInt32 keyboard_type = LMGetKbdType();

SDL_Keymap *keymap = SDL_CreateKeymap();
SDL_Keymap *keymap = SDL_CreateKeymap(true);
for (int m = 0; m < SDL_arraysize(mods); ++m) {
for (int i = 0; i < SDL_arraysize(darwin_scancode_table); i++) {
OSStatus err;
Expand Down
48 changes: 29 additions & 19 deletions src/video/wayland/SDL_waylandclipboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,16 @@
bool Wayland_SetClipboardData(SDL_VideoDevice *_this)
{
SDL_VideoData *video_data = _this->internal;
SDL_WaylandDataDevice *data_device = NULL;
bool result = true;
SDL_WaylandSeat *seat = video_data->last_implicit_grab_seat;
bool result = false;

// If no implicit grab is available yet, just attach it to the first available seat.
if (!seat && !WAYLAND_wl_list_empty(&video_data->seat_list)) {
seat = wl_container_of(video_data->seat_list.next, seat, link);
}

if (video_data->input && video_data->input->data_device) {
data_device = video_data->input->data_device;
if (seat && seat->data_device) {
SDL_WaylandDataDevice *data_device = seat->data_device;

if (_this->clipboard_callback && _this->clipboard_mime_types) {
SDL_WaylandDataSource *source = Wayland_data_source_create(_this);
Expand All @@ -57,11 +62,11 @@ bool Wayland_SetClipboardData(SDL_VideoDevice *_this)
void *Wayland_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *length)
{
SDL_VideoData *video_data = _this->internal;
SDL_WaylandDataDevice *data_device = NULL;
SDL_WaylandSeat *seat = video_data->last_incoming_data_offer_seat;
void *buffer = NULL;

if (video_data->input && video_data->input->data_device) {
data_device = video_data->input->data_device;
if (seat && seat->data_device) {
SDL_WaylandDataDevice *data_device = seat->data_device;
if (data_device->selection_source) {
buffer = SDL_GetInternalClipboardData(_this, mime_type, length);
} else if (Wayland_data_offer_has_mime(data_device->selection_offer, mime_type)) {
Expand All @@ -75,11 +80,11 @@ void *Wayland_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, si
bool Wayland_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type)
{
SDL_VideoData *video_data = _this->internal;
SDL_WaylandDataDevice *data_device = NULL;
SDL_WaylandSeat *seat = video_data->last_incoming_data_offer_seat;
bool result = false;

if (video_data->input && video_data->input->data_device) {
data_device = video_data->input->data_device;
if (seat && seat->data_device) {
SDL_WaylandDataDevice *data_device = seat->data_device;
if (data_device->selection_source) {
result = SDL_HasInternalClipboardData(_this, mime_type);
} else {
Expand All @@ -106,11 +111,16 @@ const char **Wayland_GetTextMimeTypes(SDL_VideoDevice *_this, size_t *num_mime_t
bool Wayland_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text)
{
SDL_VideoData *video_data = _this->internal;
SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL;
SDL_WaylandSeat *seat = video_data->last_implicit_grab_seat;
bool result;

if (video_data->input && video_data->input->primary_selection_device) {
primary_selection_device = video_data->input->primary_selection_device;
// If no implicit grab is available yet, just attach it to the first available seat.
if (!seat && !WAYLAND_wl_list_empty(&video_data->seat_list)) {
seat = wl_container_of(video_data->seat_list.next, seat, link);
}

if (seat && seat->primary_selection_device) {
SDL_WaylandPrimarySelectionDevice *primary_selection_device = seat->primary_selection_device;
if (text[0] != '\0') {
SDL_WaylandPrimarySelectionSource *source = Wayland_primary_selection_source_create(_this);
Wayland_primary_selection_source_set_callback(source, SDL_ClipboardTextCallback, SDL_strdup(text));
Expand All @@ -134,12 +144,12 @@ bool Wayland_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text)
char *Wayland_GetPrimarySelectionText(SDL_VideoDevice *_this)
{
SDL_VideoData *video_data = _this->internal;
SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL;
SDL_WaylandSeat *seat = video_data->last_incoming_primary_selection_seat;
char *text = NULL;
size_t length = 0;

if (video_data->input && video_data->input->primary_selection_device) {
primary_selection_device = video_data->input->primary_selection_device;
if (seat && seat->primary_selection_device) {
SDL_WaylandPrimarySelectionDevice *primary_selection_device = seat->primary_selection_device;
if (primary_selection_device->selection_source) {
text = Wayland_primary_selection_source_get_data(primary_selection_device->selection_source, TEXT_MIME, &length);
} else {
Expand All @@ -162,11 +172,11 @@ char *Wayland_GetPrimarySelectionText(SDL_VideoDevice *_this)
bool Wayland_HasPrimarySelectionText(SDL_VideoDevice *_this)
{
SDL_VideoData *video_data = _this->internal;
SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL;
SDL_WaylandSeat *seat = video_data->last_incoming_primary_selection_seat;
bool result = false;

if (video_data->input && video_data->input->primary_selection_device) {
primary_selection_device = video_data->input->primary_selection_device;
if (seat && seat->primary_selection_device) {
SDL_WaylandPrimarySelectionDevice *primary_selection_device = seat->primary_selection_device;
if (primary_selection_device->selection_source) {
result = true;
} else {
Expand Down
Loading
Loading