mirror of
https://github.com/koreader/koreader
synced 2024-11-13 19:11:25 +00:00
203 lines
6.4 KiB
Lua
203 lines
6.4 KiB
Lua
--[[--
|
||
|
||
Chinese stroke-based input method for Lua/KOReader.
|
||
|
||
Uses five basic strokes plus a wildcard stroke to input Chinese characters.
|
||
Supports both simplified and traditional.
|
||
Characters hardcoded on keys are uniform, no translation needed.
|
||
In-place candidates can be turned off in keyboard settings.
|
||
A Separation key 分隔 is used to finish inputting a character.
|
||
A Switch key 下一字 is used to iterate candidates.
|
||
Stroke-wise deletion (input not finished) mapped to the default Del key.
|
||
Character-wise deletion mapped to north of Separation key.
|
||
|
||
rf. https://en.wikipedia.org/wiki/Stroke_count_method
|
||
|
||
--]]
|
||
|
||
local IME = require("frontend/ui/data/keyboardlayouts/generic_ime")
|
||
local util = require("util")
|
||
local JA = require("ui/data/keyboardlayouts/ja_keyboard_keys")
|
||
local _ = require("gettext")
|
||
|
||
local SHOW_CANDI_KEY = "keyboard_chinese_stroke_show_candidates"
|
||
local s_3 = { alt_label = "%°#", "3", west = "%", north = "°", east = "#" }
|
||
local s_8 = { alt_label = "&-/", "8", west = "&", north = "-", east = "/" }
|
||
local comma_popup = { ",",
|
||
north = ";",
|
||
alt_label = ";",
|
||
northeast = "(",
|
||
northwest = "“",
|
||
east = "《",
|
||
west = "?",
|
||
south = ",",
|
||
southeast = "【",
|
||
southwest = "「",
|
||
"{",
|
||
"[",
|
||
";",
|
||
}
|
||
local period_popup = { "。",
|
||
north = ":",
|
||
alt_label = ":",
|
||
northeast = ")",
|
||
northwest = "”",
|
||
east = "…",
|
||
west = "!",
|
||
south = ".",
|
||
southeast = "】",
|
||
southwest = "」",
|
||
"}",
|
||
"]",
|
||
":",
|
||
}
|
||
|
||
local H = "H" -- stroke_h 横
|
||
local I = "I" -- stroke_s 竖
|
||
local J = "J" -- stroke_p 撇
|
||
local K = "K" -- stroke_n 捺
|
||
local L = "L" -- stroke_z 折
|
||
local W = "`" -- wildcard, * is not used because it can be input from symbols
|
||
|
||
local genMenuItems = function(self)
|
||
return {
|
||
{
|
||
text = _("Show character candidates"),
|
||
checked_func = function()
|
||
return G_reader_settings:nilOrTrue(SHOW_CANDI_KEY)
|
||
end,
|
||
callback = function()
|
||
G_reader_settings:flipNilOrTrue(SHOW_CANDI_KEY)
|
||
end,
|
||
},
|
||
}
|
||
end
|
||
|
||
local code_map = require("frontend/ui/data/keyboardlayouts/zh_stroke_data")
|
||
local ime = IME:new{
|
||
code_map = code_map,
|
||
key_map = {
|
||
["㇐"] = H,
|
||
["㇑"] = I,
|
||
["㇒"] = J,
|
||
["㇏"] = K,
|
||
["㇜"] = L,
|
||
[W] = W, -- wildcard
|
||
},
|
||
iter_map = {
|
||
H = I,
|
||
I = J,
|
||
J = K,
|
||
K = L,
|
||
L = H,
|
||
},
|
||
iter_map_last_key = L,
|
||
show_candi_callback = function()
|
||
return G_reader_settings:nilOrTrue(SHOW_CANDI_KEY)
|
||
end,
|
||
separator = "分隔",
|
||
switch_char = "下一字",
|
||
W = W -- has wildcard function
|
||
}
|
||
|
||
local wrappedAddChars = function(inputbox, char)
|
||
ime:wrappedAddChars(inputbox, char)
|
||
end
|
||
|
||
local function separate(inputbox)
|
||
ime:separate(inputbox)
|
||
end
|
||
|
||
local function wrappedDelChar(inputbox)
|
||
ime:wrappedDelChar(inputbox)
|
||
end
|
||
|
||
local function clear_stack()
|
||
ime:clear_stack()
|
||
end
|
||
|
||
local wrapInputBox = function(inputbox)
|
||
if inputbox._zh_stroke_wrapped == nil then
|
||
inputbox._zh_stroke_wrapped = true
|
||
local wrappers = {}
|
||
|
||
-- Wrap all of the navigation and non-single-character-input keys with
|
||
-- a callback to clear the tap window, but pass through to the
|
||
-- original function.
|
||
|
||
-- -- Delete text.
|
||
table.insert(wrappers, util.wrapMethod(inputbox, "delChar", wrappedDelChar, nil))
|
||
table.insert(wrappers, util.wrapMethod(inputbox, "delToStartOfLine", nil, clear_stack))
|
||
table.insert(wrappers, util.wrapMethod(inputbox, "clear", nil, clear_stack))
|
||
-- -- Navigation.
|
||
table.insert(wrappers, util.wrapMethod(inputbox, "leftChar", nil, separate))
|
||
table.insert(wrappers, util.wrapMethod(inputbox, "rightChar", nil, separate))
|
||
table.insert(wrappers, util.wrapMethod(inputbox, "upLine", nil, separate))
|
||
table.insert(wrappers, util.wrapMethod(inputbox, "downLine", nil, separate))
|
||
-- -- Move to other input box.
|
||
table.insert(wrappers, util.wrapMethod(inputbox, "unfocus", nil, separate))
|
||
table.insert(wrappers, util.wrapMethod(inputbox, "onCloseKeyboard", nil, separate))
|
||
-- -- Gestures to move cursor.
|
||
table.insert(wrappers, util.wrapMethod(inputbox, "onTapTextBox", nil, separate))
|
||
table.insert(wrappers, util.wrapMethod(inputbox, "onHoldTextBox", nil, separate))
|
||
table.insert(wrappers, util.wrapMethod(inputbox, "onSwipeTextBox", nil, separate))
|
||
-- -- Others
|
||
table.insert(wrappers, util.wrapMethod(inputbox, "onSwitchingKeyboardLayout", nil, separate))
|
||
|
||
-- addChars is the only method we need a more complicated wrapper for.
|
||
table.insert(wrappers, util.wrapMethod(inputbox, "addChars", wrappedAddChars, nil))
|
||
|
||
return function()
|
||
if inputbox._zh_stroke_wrapped then
|
||
for _, wrapper in ipairs(wrappers) do
|
||
wrapper:revert()
|
||
end
|
||
inputbox._zh_stroke_wrapped = nil
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
return {
|
||
min_layer = 1,
|
||
max_layer = 4,
|
||
symbolmode_keys = {["123"] = true},
|
||
utf8mode_keys = {["🌐"] = true},
|
||
keys = {
|
||
-- first row
|
||
{
|
||
{ label = "123" },
|
||
{ "", { label = "一", "㇐", north="——"}, "", JA.s_1 },
|
||
{ "", { label = "丨", "㇑"}, "", JA.s_2 },
|
||
{ "", { label = "丿", "㇒"}, "", s_3 },
|
||
{ label = "", bold = false } -- backspace
|
||
},
|
||
-- second row
|
||
{
|
||
{ label = "←" },
|
||
{ "", { label = "丶", "㇏", north="、" }, "", JA.s_4 },
|
||
{ "", { label = "𠃋", "㇜" }, "", JA.s_5 },
|
||
{ "", { ime.separator, north=ime.local_del, alt_label=ime.local_del }, "", JA.s_6 },
|
||
{ label = "→" },
|
||
},
|
||
-- third row
|
||
{
|
||
{ label = "↑" },
|
||
{ "", ime.switch_char, "", JA.s_7 },
|
||
{ "", comma_popup, "", s_8 },
|
||
{ "", period_popup, "", JA.s_9 },
|
||
{ label = "↓" },
|
||
},
|
||
-- fourth row
|
||
{
|
||
{ label = "🌐" },
|
||
{ label = "空格", " ", " ", " ", " ", width = 2.0 },
|
||
{ "", { label = "*", W }, "", JA.s_0 },
|
||
{ label = "⮠", "\n", "\n", "\n", "\n", bold = true }, -- return
|
||
},
|
||
},
|
||
|
||
wrapInputBox = wrapInputBox,
|
||
genMenuItems = genMenuItems,
|
||
}
|