|
|
|
|
--[[--
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
}
|