Skip to content

Commit

Permalink
shell,core: add support for IMEs and on-screen keyboards
Browse files Browse the repository at this point in the history
  • Loading branch information
takase1121 committed May 9, 2024
1 parent c155fdf commit c423b85
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 2 deletions.
22 changes: 22 additions & 0 deletions core/connector.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,26 @@ static int f_set_clipboard(lua_State *L) {
return 1;
}

static int f_focus_text_input(lua_State *L) {
EM_ASM({ document.getElementById("textinput").focus(); });
return 0;
}

static int f_set_text_input_rect(lua_State *L) {
lua_Number x = luaL_checknumber(L, 1);
lua_Number y = luaL_checknumber(L, 2);
lua_Number w = luaL_checknumber(L, 3);
lua_Number h = luaL_checknumber(L, 4);
EM_ASM({
const el = document.getElementById("textinput");
el.style.left = ($0 / window.devicePixelRatio) + "px";
el.style.top = ($1 / window.devicePixelRatio) + "px";
el.style.width = ($2 / window.devicePixelRatio) + "px";
el.style.height = ($3 / window.devicePixelRatio) + "px";
}, x, y, w, h);
return 0;
}

static luaL_Reg lib[] = {
{ "idbsync_set_interval", f_idbsync_set_interval },
{ "idbsync_get_interval", f_idbsync_get_interval },
Expand All @@ -193,6 +213,8 @@ static luaL_Reg lib[] = {
{ "download_files", f_download_files },
{ "get_clipboard", f_get_clipboard },
{ "set_clipboard", f_set_clipboard },
{ "focus_text_input", f_focus_text_input },
{ "set_text_input_rect", f_set_text_input_rect },
{ NULL, NULL },
};

Expand Down
39 changes: 39 additions & 0 deletions core/plugins/wasm_input.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
--mod-version:3

local core = require "core"

local DocView = require "core.docview"
local connector = require "libraries.connector"

local last_x, last_y, last_w, last_h
local function set_text_input_rect(x, y, w, h)
if x ~= last_x or y ~= last_y or w ~= last_w or h ~= last_h then
last_x, last_y, last_w, last_h = x, y, w, h
connector.set_text_input_rect(x, y, w, h)
end
end

local function recalculate_input_rect(view)
-- set caret position
local line1, col1, line2, col2 = view.doc:get_selection(true)
local x, y = view:get_line_screen_position(line1)
local h = view:get_line_height()
local col = math.min(col1, col2)

local x1, x2 = 0, 0

-- focus the whole text
x1 = view:get_col_x_offset(line1, col1)
x2 = view:get_col_x_offset(line2, col2)

set_text_input_rect(x + x1, y, x2 - x1, h)
end

local docview_update = DocView.update
function DocView:update(...)
docview_update(self, ...)
if core.active_view == self then
connector.focus_text_input()
recalculate_input_rect(self)
end
end
2 changes: 1 addition & 1 deletion shell/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ canvas {
visibility: visible;
}

#clipping {
.hidden {
width: 0;
height: 0;
border: 0;
Expand Down
3 changes: 2 additions & 1 deletion shell/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@

<body>
<canvas id="canvas"></canvas>
<textarea id="clipping" aria-hidden="true"></textarea>
<textarea id="clipping" class="hidden" aria-hidden="true"></textarea>
<textarea id="textinput" class="hidden" aria-hidden="true" autocapitalize="off" spellcheck="false" autocorrect="off" autocomplete="off" aria-autocomplete="none" autofocus></textarea>
<div class="modal" id="loading">
<h2>Loading...</h2>
<p>Status: <span id="status">Unknown</span></p>
Expand Down
35 changes: 35 additions & 0 deletions shell/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -428,5 +428,40 @@ var Module = {
Module.setStatus = (s) => {
status.textContent = s === "" ? "Initializing..." : s;
};

// hook up our text input
const textInput = document.getElementById("textinput");

/**
* Writes a string
* @param {InputEvent|CompositionEvent} e
*/
function addInput(e) {
if (e.data) {
// emulate keypress events
for (const char of [...e.data]) {
window.dispatchEvent(
new KeyboardEvent("keypress", {
key: char,
isComposing: e.isComposing,
charCode: char.charCodeAt(char.length - 1),
})
);
}
}
}
// ignore composition text, only get end result
textInput.addEventListener("compositionend", addInput);
textInput.addEventListener("input", (e) => {
if (e.inputType == "deleteContentBackward") {
const ev = {
isComposing: e.isComposing,
code: "Backspace",
};
// keypress does not send backspace events
window.dispatchEvent(new KeyboardEvent("keydown", ev));
window.dispatchEvent(new KeyboardEvent("keyup", ev));
} else if (!e.isComposing) addInput(e);
});
};
})();

0 comments on commit c423b85

Please sign in to comment.