Skip to content

android/soft-keyboard/soft-keyboard-geometry

Decides whether the Android soft keyboard is up, and where to touch to raise it — from geometry alone.

Nothing in the page reports the keyboard. innerHeight, visualViewport and the modal container all stay at their full height with the keyboard shown and dumpsys input_method reporting mInputShown=true — Obsidian Mobile keeps a full-screen container and lifts its contents inside it. The only signal is that the field moves, which is why the detection here is geometric rather than an API call. Two runs failed on that before a framebuffer dump said so, which is also why the diagnostic below exists.

The signal is a DELTA against a baseline read before the touch, not the field’s absolute offset from the bottom. The absolute offset was the original test and it is right only for a bottom-anchored field — a suggester, a command palette — where “clear of the bottom” and “lifted” are the same sentence. For a centred modal the condition is already true with no keyboard at all, so the test passed vacuously and raiseSoftKeyboard returned success having dispatched no touch (measured 2026-09-12 against a centred prompt modal: the field’s top read 352.4453125 before and after real taps and the check said the keyboard was up both times). A delta is the same public API for both shapes, and it costs a field that cannot move its verdict — see checkIsSoftKeyboardUp for the one case that trades away.

Pure and unit-tested; the touching and the capture live in soft-keyboard.

Interface Description
BuildSoftKeyboardDiagnosticMessageParams Parameters for buildSoftKeyboardDiagnosticMessage.
CheckIsSoftKeyboardUpParams Parameters for checkIsSoftKeyboardUp.
ElementRect A rectangle as the renderer reports it, in CSS pixels.
ResolveSoftKeyboardTapPointsParams Parameters for resolveSoftKeyboardTapPoints.
SoftKeyboardTapPoint A point on the device’s screen, in device pixels.
SoftKeyboardViewportSnapshot What the renderer knows about its own geometry.
Function Description
buildSoftKeyboardDiagnosticMessage Builds the message a failed raise reports. A bare “the keyboard did not come up” is unreadable — what the reader needs is what the page saw and what the device thought, side by side, because the two disagreeing is the whole diagnosis. The page’s half is the lift and the two tops it came from, since the lift is the verdict; a lift of zero gets a sentence of its own, saying what is left once an already-up keyboard has been ruled out.
checkIsInputMethodShown Decides whether the device reports an IME showing, from dumpsys input_method. This is the DEVICE’s answer, and it is the one raiseSoftKeyboard asks before it measures anything: nothing in the page reports the keyboard, and the geometric proof in checkIsSoftKeyboardUp cannot see a keyboard that was already up when its baseline was read. It is deliberately NOT the proof that a raise worked — a device reports mInputShown=true just as readily for an IME drawn over a field that never moved, which is exactly the unproved frame the geometric delta exists to refuse.
checkIsSoftKeyboardUp Decides whether the IME is up, from how far the field moved. The verdict is a delta: the field must have risen from where it sat before the touch, by at least minimumKeyboardHeightInPixels. Obsidian Mobile lifts whatever is on screen to make room for the IME, so a field that has not moved has had no keyboard arrive under it — whether it is a bottom-anchored suggester or a centred modal. The one case this gets wrong, deliberately: a keyboard that was already up before the baseline was read. The field has nowhere left to lift to, so the answer is false. No amount of geometry separates that from a centred modal with no keyboard — both read as “clear of the bottom and not moving” — and of the two possible wrong answers, a loud false is the one worth keeping: it fails a capture rather than silently returning a screenshot of a keyboard that is not there. Read the baseline with the keyboard down. raiseSoftKeyboard guarantees that itself: it asks the device (checkIsInputMethodShown) and puts a showing keyboard down before it reads the baseline, so every call proves its own lift rather than taking the device’s word for one.
parseInputMethodState Reduces dumpsys input_method to the handful of fields that say whether the IME is showing.
resolveSoftKeyboardTapPoints Works out where to touch, in the device pixels adb shell input tap speaks. Two candidates, not one: the WebView may or may not start at the top of the screen, and the page cannot tell which. Both land inside the field — it is taller than the offset — so a wrong guess costs one touch rather than a mis-tap on whatever sits below.
Variable Description
DEFAULT_MINIMUM_KEYBOARD_HEIGHT_IN_PIXELS The least a raised keyboard lifts the field by, so a stray rounding pixel is not read as one. Exported because it is the number both checkIsSoftKeyboardUp and raiseSoftKeyboard default to, and a suite tightening it wants to say so relative to this rather than in the abstract.