diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c
index 5e17e12ff..62a2557ec 100644
--- a/src/video/wayland/SDL_waylandevents.c
+++ b/src/video/wayland/SDL_waylandevents.c
@@ -216,6 +216,12 @@ Wayland_PumpEvents(_THIS)
 
     WAYLAND_wl_display_flush(d->display);
 
+#ifdef SDL_USE_IME
+    if (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE) {
+        SDL_IME_PumpEvents();
+    }
+#endif
+
     if (input) {
         uint32_t now = SDL_GetTicks();
         keyboard_repeat_handle(&input->keyboard_repeat, now);
@@ -677,6 +683,9 @@ keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
         window->keyboard_device = input;
         SDL_SetKeyboardFocus(window->sdlwindow);
     }
+#ifdef SDL_USE_IME
+    SDL_IME_SetFocus(SDL_TRUE);
+#endif
 }
 
 static void
@@ -690,10 +699,13 @@ keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
 
     /* This will release any keys still pressed */ 
     SDL_SetKeyboardFocus(NULL);
+#ifdef SDL_USE_IME
+    SDL_IME_SetFocus(SDL_FALSE);
+#endif
 }
 
 static SDL_bool
-keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint32_t key)
+keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint32_t key, SDL_bool *handled_by_ime)
 {
     SDL_WindowData *window = input->keyboard_focus;
     const xkb_keysym_t *syms;
@@ -707,6 +719,13 @@ keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint
         return SDL_FALSE;
     }
 
+#ifdef SDL_USE_IME
+    if (SDL_IME_ProcessKeyEvent(syms[0], key + 8)) {
+        *handled_by_ime = SDL_TRUE;
+        return SDL_TRUE;
+    }
+#endif
+
     return WAYLAND_xkb_keysym_to_utf8(syms[0], text, 8) > 0;
 }
 
@@ -719,8 +738,14 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
     enum wl_keyboard_key_state state = state_w;
     uint32_t scancode = SDL_SCANCODE_UNKNOWN;
     char text[8];
+    SDL_bool has_text = SDL_FALSE;
+    SDL_bool handled_by_ime = SDL_FALSE;
 
-    if (key < SDL_arraysize(xfree86_scancode_table2)) {
+    if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+        has_text = keyboard_input_get_text(text, input, key, &handled_by_ime);
+    }
+
+    if (!handled_by_ime && key < SDL_arraysize(xfree86_scancode_table2)) {
         scancode = xfree86_scancode_table2[key];
 
         if (scancode != SDL_SCANCODE_UNKNOWN) {
@@ -730,10 +755,11 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
     }
 
     if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
-        SDL_bool has_text = keyboard_input_get_text(text, input, key);
         if (has_text) {
             Wayland_data_device_set_serial(input->data_device, serial);
-            SDL_SendKeyboardText(text);
+            if (!handled_by_ime) {
+                SDL_SendKeyboardText(text);
+            }
         }
         keyboard_repeat_set(&input->keyboard_repeat, scancode, has_text, text);
     } else {
diff --git a/src/video/wayland/SDL_waylandkeyboard.c b/src/video/wayland/SDL_waylandkeyboard.c
new file mode 100644
index 000000000..88384b351
--- /dev/null
+++ b/src/video/wayland/SDL_waylandkeyboard.c
@@ -0,0 +1,75 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_WAYLAND
+
+#include "../SDL_sysvideo.h"
+#include "SDL_waylandvideo.h"
+
+int
+Wayland_InitKeyboard(_THIS)
+{
+#ifdef SDL_USE_IME
+    SDL_IME_Init();
+#endif
+
+    return 0;
+}
+
+void
+Wayland_QuitKeyboard(_THIS)
+{
+#ifdef SDL_USE_IME
+    SDL_IME_Quit();
+#endif
+}
+
+void
+Wayland_StartTextInput(_THIS)
+{
+    /* No-op */
+}
+
+void
+Wayland_StopTextInput(_THIS)
+{
+#ifdef SDL_USE_IME
+    SDL_IME_Reset();
+#endif
+}
+
+void
+Wayland_SetTextInputRect(_THIS, SDL_Rect *rect)
+{
+    if (!rect) {
+        SDL_InvalidParamError("rect");
+        return;
+    }
+       
+#ifdef SDL_USE_IME
+    SDL_IME_UpdateTextRect(rect);
+#endif
+}
+
+#endif /* SDL_VIDEO_DRIVER_WAYLAND */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/video/wayland/SDL_waylandkeyboard.h b/src/video/wayland/SDL_waylandkeyboard.h
new file mode 100644
index 000000000..cca8ac8d9
--- /dev/null
+++ b/src/video/wayland/SDL_waylandkeyboard.h
@@ -0,0 +1,34 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef SDL_waylandkeyboard_h_
+#define SDL_waylandkeyboard_h_
+
+extern int Wayland_InitKeyboard(_THIS);
+extern void Wayland_QuitKeyboard(_THIS);
+extern void Wayland_StartTextInput(_THIS);
+extern void Wayland_StopTextInput(_THIS);
+extern void Wayland_SetTextInputRect(_THIS, SDL_Rect *rect);
+
+#endif /* SDL_waylandkeyboard_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c
index 95b1af936..e43fb4cce 100644
--- a/src/video/wayland/SDL_waylandvideo.c
+++ b/src/video/wayland/SDL_waylandvideo.c
@@ -33,6 +33,7 @@
 #include "SDL_waylandwindow.h"
 #include "SDL_waylandopengles.h"
 #include "SDL_waylandmouse.h"
+#include "SDL_waylandkeyboard.h"
 #include "SDL_waylandtouch.h"
 #include "SDL_waylandclipboard.h"
 #include "SDL_waylandvulkan.h"
@@ -215,6 +216,9 @@ Wayland_CreateDevice(int devindex)
     device->SetClipboardText = Wayland_SetClipboardText;
     device->GetClipboardText = Wayland_GetClipboardText;
     device->HasClipboardText = Wayland_HasClipboardText;
+    device->StartTextInput = Wayland_StartTextInput;
+    device->StopTextInput = Wayland_StopTextInput;
+    device->SetTextInputRect = Wayland_SetTextInputRect;
 
 #if SDL_VIDEO_VULKAN
     device->Vulkan_LoadLibrary = Wayland_Vulkan_LoadLibrary;
@@ -478,6 +482,8 @@ Wayland_VideoInit(_THIS)
 
     WAYLAND_wl_display_flush(data->display);
 
+    Wayland_InitKeyboard(_this);
+
 #if SDL_USE_LIBDBUS
     SDL_DBus_Init();
 #endif
@@ -567,6 +573,8 @@ Wayland_VideoQuit(_THIS)
     if (data->registry)
         wl_registry_destroy(data->registry);
 
+    Wayland_QuitKeyboard(_this);
+
 /* !!! FIXME: other subsystems use D-Bus, so we shouldn't quit it here;
        have SDL.c do this at a higher level, or add refcounting. */
 #if SDL_USE_LIBDBUS
diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h
index e4b865d51..867422440 100644
--- a/src/video/wayland/SDL_waylandvideo.h
+++ b/src/video/wayland/SDL_waylandvideo.h
@@ -40,6 +40,7 @@
 #include "wayland-util.h"
 
 #include "../../core/linux/SDL_dbus.h"
+#include "../../core/linux/SDL_ime.h"
 
 struct xkb_context;
 struct SDL_WaylandInput;