Atlas - SDL_waylandkeyboard.c
Home / ext / SDL / src / video / wayland Lines: 1 | Size: 11664 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22 23#if SDL_VIDEO_DRIVER_WAYLAND 24 25#include "../SDL_sysvideo.h" 26#include "SDL_waylandvideo.h" 27#include "SDL_waylandevents_c.h" 28#include "../../events/SDL_keyboard_c.h" 29#include "text-input-unstable-v3-client-protocol.h" 30 31bool Wayland_InitKeyboard(SDL_VideoDevice *_this) 32{ 33#ifdef SDL_USE_IME 34 SDL_VideoData *internal = _this->internal; 35 if (!internal->text_input_manager) { 36 SDL_IME_Init(); 37 } 38#endif 39 SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu"); 40 41 return true; 42} 43 44void Wayland_QuitKeyboard(SDL_VideoDevice *_this) 45{ 46#ifdef SDL_USE_IME 47 SDL_VideoData *internal = _this->internal; 48 if (!internal->text_input_manager) { 49 SDL_IME_Quit(); 50 } 51#endif 52} 53 54void Wayland_SeatUpdateTextInput(SDL_WaylandSeat *seat) 55{ 56 if (seat->text_input.zwp_text_input) { 57 SDL_WindowData *focus = seat->keyboard.focus; 58 59 if (focus && focus->text_input_props.active) { 60 SDL_Window *window = focus->sdlwindow; 61 62 // Enabling will reset all state, so don't do it redundantly. 63 if (!seat->text_input.enabled) { 64 seat->text_input.enabled = true; 65 zwp_text_input_v3_enable(seat->text_input.zwp_text_input); 66 67 // Now that it's enabled, set the input properties 68 zwp_text_input_v3_set_content_type(seat->text_input.zwp_text_input, focus->text_input_props.hint, focus->text_input_props.purpose); 69 if (!SDL_RectEmpty(&window->text_input_rect)) { 70 const SDL_Rect scaled_rect = { 71 (int)SDL_floor(window->text_input_rect.x / focus->pointer_scale.x), 72 (int)SDL_floor(window->text_input_rect.y / focus->pointer_scale.y), 73 (int)SDL_ceil(window->text_input_rect.w / focus->pointer_scale.x), 74 (int)SDL_ceil(window->text_input_rect.h / focus->pointer_scale.y) 75 }; 76 const int scaled_cursor = (int)SDL_floor(window->text_input_cursor / focus->pointer_scale.x); 77 78 SDL_copyp(&seat->text_input.text_input_rect, &scaled_rect); 79 seat->text_input.text_input_cursor = scaled_cursor; 80 81 // Clamp the x value so it doesn't run too far past the end of the text input area. 82 zwp_text_input_v3_set_cursor_rectangle(seat->text_input.zwp_text_input, 83 SDL_min(scaled_rect.x + scaled_cursor, scaled_rect.x + scaled_rect.w), 84 scaled_rect.y, 85 1, 86 scaled_rect.h); 87 } 88 zwp_text_input_v3_commit(seat->text_input.zwp_text_input); 89 90 if (seat->keyboard.xkb.compose_state) { 91 // Reset compose state so composite and dead keys don't carry over 92 WAYLAND_xkb_compose_state_reset(seat->keyboard.xkb.compose_state); 93 } 94 } 95 } else { 96 if (seat->text_input.enabled) { 97 seat->text_input.enabled = false; 98 SDL_zero(seat->text_input.text_input_rect); 99 seat->text_input.text_input_cursor = 0; 100 zwp_text_input_v3_disable(seat->text_input.zwp_text_input); 101 zwp_text_input_v3_commit(seat->text_input.zwp_text_input); 102 } 103 104 if (seat->keyboard.xkb.compose_state) { 105 // Reset compose state so composite and dead keys don't carry over 106 WAYLAND_xkb_compose_state_reset(seat->keyboard.xkb.compose_state); 107 } 108 } 109 } 110} 111 112bool Wayland_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props) 113{ 114 SDL_VideoData *display = _this->internal; 115 116 if (display->text_input_manager) { 117 SDL_WindowData *wind = window->internal; 118 wind->text_input_props.hint = ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE; 119 120 switch (SDL_GetTextInputType(props)) { 121 default: 122 case SDL_TEXTINPUT_TYPE_TEXT: 123 wind->text_input_props.purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL; 124 break; 125 case SDL_TEXTINPUT_TYPE_TEXT_NAME: 126 wind->text_input_props.purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NAME; 127 break; 128 case SDL_TEXTINPUT_TYPE_TEXT_EMAIL: 129 wind->text_input_props.purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_EMAIL; 130 break; 131 case SDL_TEXTINPUT_TYPE_TEXT_USERNAME: 132 wind->text_input_props.purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL; 133 wind->text_input_props.hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_SENSITIVE_DATA; 134 break; 135 case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN: 136 wind->text_input_props.purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PASSWORD; 137 wind->text_input_props.hint |= (ZWP_TEXT_INPUT_V3_CONTENT_HINT_HIDDEN_TEXT | ZWP_TEXT_INPUT_V3_CONTENT_HINT_SENSITIVE_DATA); 138 break; 139 case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_VISIBLE: 140 wind->text_input_props.purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PASSWORD; 141 wind->text_input_props.hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_SENSITIVE_DATA; 142 break; 143 case SDL_TEXTINPUT_TYPE_NUMBER: 144 wind->text_input_props.purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NUMBER; 145 break; 146 case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN: 147 wind->text_input_props.purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PIN; 148 wind->text_input_props.hint |= (ZWP_TEXT_INPUT_V3_CONTENT_HINT_HIDDEN_TEXT | ZWP_TEXT_INPUT_V3_CONTENT_HINT_SENSITIVE_DATA); 149 break; 150 case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_VISIBLE: 151 wind->text_input_props.purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PIN; 152 wind->text_input_props.hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_SENSITIVE_DATA; 153 break; 154 } 155 156 switch (SDL_GetTextInputCapitalization(props)) { 157 default: 158 case SDL_CAPITALIZE_NONE: 159 break; 160 case SDL_CAPITALIZE_LETTERS: 161 wind->text_input_props.hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_UPPERCASE; 162 break; 163 case SDL_CAPITALIZE_WORDS: 164 wind->text_input_props.hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_TITLECASE; 165 break; 166 case SDL_CAPITALIZE_SENTENCES: 167 wind->text_input_props.hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_AUTO_CAPITALIZATION; 168 break; 169 } 170 171 if (SDL_GetTextInputAutocorrect(props)) { 172 wind->text_input_props.hint |= (ZWP_TEXT_INPUT_V3_CONTENT_HINT_COMPLETION | ZWP_TEXT_INPUT_V3_CONTENT_HINT_SPELLCHECK); 173 } 174 if (SDL_GetTextInputMultiline(props)) { 175 wind->text_input_props.hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_MULTILINE; 176 } 177 178 wind->text_input_props.active = true; 179 180 SDL_WaylandSeat *seat; 181 wl_list_for_each (seat, &display->seat_list, link) { 182 if (seat->keyboard.focus == wind) { 183 Wayland_SeatUpdateTextInput(seat); 184 } 185 } 186 187 return true; 188 } 189 190 return SDL_SetError("wayland: cannot enable text input; compositor lacks support for the required zwp_text_input_v3 protocol"); 191} 192 193bool Wayland_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window) 194{ 195 SDL_VideoData *display = _this->internal; 196 197 if (display->text_input_manager) { 198 SDL_WaylandSeat *seat; 199 SDL_WindowData *wind = window->internal; 200 wind->text_input_props.active = false; 201 202 wl_list_for_each (seat, &display->seat_list, link) { 203 if (seat->keyboard.focus == wind) { 204 Wayland_SeatUpdateTextInput(seat); 205 } 206 } 207 } 208#ifdef SDL_USE_IME 209 else { 210 SDL_IME_Reset(); 211 } 212#endif 213 214 return true; 215} 216 217bool Wayland_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window) 218{ 219 SDL_VideoData *internal = _this->internal; 220 if (internal->text_input_manager) { 221 SDL_WaylandSeat *seat; 222 SDL_WindowData *wind = window->internal; 223 224 wl_list_for_each (seat, &internal->seat_list, link) { 225 if (seat->text_input.zwp_text_input && seat->keyboard.focus == wind) { 226 const SDL_Rect scaled_rect = { 227 (int)SDL_floor(window->text_input_rect.x / wind->pointer_scale.x), 228 (int)SDL_floor(window->text_input_rect.y / wind->pointer_scale.y), 229 (int)SDL_ceil(window->text_input_rect.w / wind->pointer_scale.x), 230 (int)SDL_ceil(window->text_input_rect.h / wind->pointer_scale.y) 231 }; 232 const int scaled_cursor = (int)SDL_floor(window->text_input_cursor / wind->pointer_scale.x); 233 234 if (!SDL_RectsEqual(&scaled_rect, &seat->text_input.text_input_rect) || scaled_cursor != seat->text_input.text_input_cursor) { 235 SDL_copyp(&seat->text_input.text_input_rect, &scaled_rect); 236 seat->text_input.text_input_cursor = scaled_cursor; 237 238 // Clamp the x value so it doesn't run too far past the end of the text input area. 239 zwp_text_input_v3_set_cursor_rectangle(seat->text_input.zwp_text_input, 240 SDL_min(scaled_rect.x + scaled_cursor, scaled_rect.x + scaled_rect.w), 241 scaled_rect.y, 242 1, 243 scaled_rect.h); 244 zwp_text_input_v3_commit(seat->text_input.zwp_text_input); 245 } 246 } 247 } 248 } 249#ifdef SDL_USE_IME 250 else { 251 SDL_IME_UpdateTextInputArea(window); 252 } 253#endif 254 return true; 255} 256 257bool Wayland_HasScreenKeyboardSupport(SDL_VideoDevice *_this) 258{ 259 /* In reality, we just want to return true when the screen keyboard is the 260 * _only_ way to get text input. So, in addition to checking for the text 261 * input protocol, make sure we don't have any physical keyboards either. 262 */ 263 SDL_VideoData *internal = _this->internal; 264 SDL_WaylandSeat *seat; 265 bool hastextmanager = (internal->text_input_manager != NULL); 266 bool haskeyboard = false; 267 268 // Check for at least one keyboard object on one seat. 269 wl_list_for_each (seat, &internal->seat_list, link) { 270 if (seat->keyboard.wl_keyboard) { 271 haskeyboard = true; 272 break; 273 } 274 } 275 276 return !haskeyboard && hastextmanager; 277} 278 279#endif // SDL_VIDEO_DRIVER_WAYLAND 280[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.