Skip to content

Commit cc7c070

Browse files
committed
Adjust active window to SDL "safe area"
Text entry on Android and iOS devices is accomplished by displaying an "Input Method Editor", or IME (soft keyboard), over the running application. The UI model is such that the application is supposed to adjust its graphical layout so that the text-entry field is repositioned to fit above the newly-displayed keyboard. This change adds support for discovering what the IME's insets are, and adjusting the top-level window to be displayed within the area not covered.
1 parent d01b243 commit cc7c070

5 files changed

Lines changed: 54 additions & 2 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Subject: [PATCH] Add consideration for IME insets to Safe Area
2+
---
3+
Index: android/src/main/java/org/libsdl/app/SDLSurface.java
4+
IDEA additional info:
5+
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
6+
<+>UTF-8
7+
===================================================================
8+
diff --git a/android/src/main/java/org/libsdl/app/SDLSurface.java b/android/src/main/java/org/libsdl/app/SDLSurface.java
9+
--- a/android/src/main/java/org/libsdl/app/SDLSurface.java (revision a162be9609af731e5a0f0b78351fc8d32ee899b0)
10+
+++ b/android/src/main/java/org/libsdl/app/SDLSurface.java (date 1769037984477)
11+
@@ -199,7 +199,8 @@
12+
WindowInsets.Type.systemGestures() |
13+
WindowInsets.Type.mandatorySystemGestures() |
14+
WindowInsets.Type.tappableElement() |
15+
- WindowInsets.Type.displayCutout());
16+
+ WindowInsets.Type.displayCutout() |
17+
+ WindowInsets.Type.ime());
18+
19+
SDLActivity.onNativeInsetsChanged(combined.left, combined.right, combined.top, combined.bottom);
20+
}

android/src/main/java/org/libsdl/app/SDLSurface.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,8 @@ public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
199199
WindowInsets.Type.systemGestures() |
200200
WindowInsets.Type.mandatorySystemGestures() |
201201
WindowInsets.Type.tappableElement() |
202-
WindowInsets.Type.displayCutout());
202+
WindowInsets.Type.displayCutout() |
203+
WindowInsets.Type.ime());
203204

204205
SDLActivity.onNativeInsetsChanged(combined.left, combined.right, combined.top, combined.bottom);
205206
}

ui/UISystem.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@
173173
#include "pserror.h"
174174
#include "renderer.h"
175175
#include "Macros.h"
176+
#include "SDLHelpers.h"
176177

177178
constexpr float kDefaultMouseScale = 20;
178179

@@ -456,6 +457,7 @@ void ui_DoWindowFocus() {
456457
UIWindowFocus = NULL;
457458
}
458459
// returns a result and processes input of a window in focus
460+
extern SDL_Window* GSDLWindow;
459461
int ui_ProcessFocusedWindow() {
460462
int res = -1;
461463
int res2;
@@ -465,6 +467,11 @@ int ui_ProcessFocusedWindow() {
465467
// get keys. get mouse while real events (non ui manuipulated) are there.
466468
ui_MousePoll(false);
467469
if (UIWindowFocus) {
470+
SDL_Rect safeArea{};
471+
SDL_GetWindowSafeArea(GSDLWindow, &safeArea);
472+
auto const& [safeX, safeY, safeW, safeH] = SDLWindowToGameRenderer(safeArea);
473+
UIWindowFocus->AdjustToSafeArea(safeX, safeY, safeW, safeH);
474+
468475
UI_input.b1_count = 0; // button one state reset.
469476
ui_KeyPoll();
470477
ui_MousePoll(true);

ui/UIWindow.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,10 @@ void UIWindow::Create(int x, int y, int w, int h, int flags) {
198198
y = UI_screen_height / 2 - h / 2;
199199
}
200200

201+
m_RealX = x;
202+
m_RealY = y;
203+
m_RealW = w;
204+
m_RealH = h;
201205
UIObject::Create(x, y, w, h);
202206
}
203207

@@ -216,6 +220,14 @@ void UIWindow::Destroy() {
216220
UIObject::Destroy();
217221
}
218222

223+
void UIWindow::Move(int x, int y, int w, int h) {
224+
m_RealX = x;
225+
m_RealY = y;
226+
m_RealW = w;
227+
m_RealH = h;
228+
UIObject::Move(x, y, w, h);
229+
}
230+
219231
// interface functions
220232
// adds a UIObject to the interface's draw list.
221233
void UIWindow::AddGadget(UIGadget *gadget) {
@@ -292,6 +304,13 @@ void UIWindow::UnlockFocusOnGadget() { m_LockedGadget = NULL; }
292304
// forces all keyinput onto one gadget.
293305
void UIWindow::LockKeyFocusOnGadget(UIGadget *gadget) {}
294306

307+
void UIWindow::AdjustToSafeArea(int safeX, int safeY, int safeW, int safeH) {
308+
m_W = std::min(m_RealW, safeW);
309+
m_H = std::min(m_RealH, safeH);
310+
m_X = std::clamp(m_RealX, safeX, safeX + safeW - m_W);
311+
m_Y = std::clamp(m_RealY, safeY, safeY + safeH - m_H);
312+
}
313+
295314
// Process
296315
// run this to handle user input inside an interface
297316
// sets focus on a control

ui/ui.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ class UIObject {
316316
int H() const { return m_H; };
317317

318318
// moves the object.
319-
void Move(int x, int y, int w, int h);
319+
virtual void Move(int x, int y, int w, int h);
320320

321321
// inheritable operations
322322
public:
@@ -1033,6 +1033,8 @@ class UIWindow : public UIObject {
10331033
} m_Accelerators[N_WINDOW_ACCELS]; // used for quick key press interaction
10341034
int m_naccels;
10351035

1036+
int m_RealX, m_RealY, m_RealW, m_RealH;
1037+
10361038
static int m_WindowFont; // global window default font
10371039

10381040
private:
@@ -1085,6 +1087,9 @@ class UIWindow : public UIObject {
10851087
void Open(); // adds window to ui list.
10861088
void Close(); // removes window from ui list.
10871089

1090+
void Move(int x, int y, int w, int h) override;
1091+
void AdjustToSafeArea(int safeX, int safeY, int safeW, int safeH);
1092+
10881093
// settings
10891094
void SetFont(int handle); // sets window's font.
10901095
void SetBackItem(UIItem *item) { // sets the background drawing item.

0 commit comments

Comments
 (0)