Generic keyboard IME bump: supports auto seperation when code is unique

reviewable/pr9631/r1
weijiuqiao 2 years ago committed by poire-z
parent e424fcf5de
commit 6a5a13dfc8

@ -1,6 +1,6 @@
----------------------------------------- ---------------------------------
-- General Chinese input method engine -- -- Generic input method engine --
----------------------------------------- ---------------------------------
local logger = require("logger") local logger = require("logger")
local util = require("util") local util = require("util")
@ -54,9 +54,10 @@ local IME = {
iter_map = nil, -- next code when using wildcard iter_map = nil, -- next code when using wildcard
iter_map_last_key = nil, iter_map_last_key = nil,
show_candi_callback = function() end, show_candi_callback = function() end,
switch_char = "下一字", -- default switch_char = "SWITCH",
separator = "分隔", -- default separator = "SEPARATOR",
use_space_as_separator = true, partial_separators = { " " }, -- when in state act as separator, otherwise input itself
auto_separate_callback = function() return false end,
local_del = "", -- default local_del = "", -- default
W = nil -- default no wildcard W = nil -- default no wildcard
} }
@ -102,6 +103,7 @@ function IME:clear_stack()
self.last_key = "" self.last_key = ""
self.last_index = 0 self.last_index = 0
self.hint_char_count = 0 self.hint_char_count = 0
self.on_stage_char_count = 0
end end
function IME:reset_status() function IME:reset_status()
@ -109,6 +111,31 @@ function IME:reset_status()
self.last_index = 0 self.last_index = 0
end end
function IME:uniqueMap(code)
-- Here we find out if given code has only one candidate and no other code
-- starts with the given one, so that auto separation can take place.
if not code then return true end
if self.W and code:find(self.W) then
return false -- with wildcard, we just return false even if its unique
else
if type(self.code_map[code]) == "table" then
return false
end
local idx = binarysearch(self.sorted_codes, code, function(v) return v end)
if idx == #self.sorted_codes then
return true
elseif not idx then
idx = binarysearch(self.sorted_codes, code, function(v) return string.sub(v or "", 1, #code) end )
if not idx or idx == #self.sorted_codes then
return true
end
end
local next_code = self.sorted_codes[idx+1]
local unique = next_code:sub(1, #code) ~= code
return unique
end
end
function IME:searchStartWith(code) function IME:searchStartWith(code)
local result = binarysearch(self.sorted_codes, code, function(v) return string.sub(v or "", 1, #code) end) local result = binarysearch(self.sorted_codes, code, function(v) return string.sub(v or "", 1, #code) end)
if result then if result then
@ -197,13 +224,21 @@ function IME:delHintChars(inputbox)
end end
end end
function IME:delOnStageAndHintChars(inputbox)
self:delHintChars(inputbox)
for i=1, self.on_stage_char_count do
inputbox.delChar:raw_method_call()
end
end
function IME:getHintChars() function IME:getHintChars()
self.hint_char_count = 0 self.hint_char_count = 0
self.on_stage_char_count = 0
local hint_chars = "" local hint_chars = ""
for i=1, #_stack do for i=1, #_stack do
hint_chars = hint_chars .. _stack[i].char hint_chars = hint_chars .. _stack[i].char
if _stack[i].char ~= "" then if _stack[i].char ~= "" then
self.hint_char_count = self.hint_char_count + #util.splitToChars(_stack[i].char) self.on_stage_char_count = self.on_stage_char_count + #util.splitToChars(_stack[i].char)
end end
end end
local imex = _stack[#_stack] local imex = _stack[#_stack]
@ -244,21 +279,17 @@ function IME:getHintChars()
end end
function IME:refreshHintChars(inpuxbox) function IME:refreshHintChars(inpuxbox)
self:delHintChars(inpuxbox) self:delOnStageAndHintChars(inpuxbox)
inpuxbox.addChars:raw_method_call(self:getHintChars()) inpuxbox.addChars:raw_method_call(self:getHintChars())
end end
function IME:wrappedSeparate(inputbox) function IME:separate(inputbox)
local imex = _stack[#_stack] if self.hint_char_count then
if self:show_candi_callback() and ( #imex.candi > 1 or self.W and imex.code:find(self.W) ) then self:delHintChars(inputbox)
imex.candi = {}
self:refreshHintChars(inputbox)
end end
self:clear_stack() self:clear_stack()
end end
function IME:wrappedDelChar(inputbox) function IME:wrappedDelChar(inputbox)
local imex = _stack[#_stack] local imex = _stack[#_stack]
-- stepped deletion -- stepped deletion
@ -275,7 +306,7 @@ function IME:wrappedDelChar(inputbox)
self:refreshHintChars(inputbox) self:refreshHintChars(inputbox)
elseif #imex.code == 1 then elseif #imex.code == 1 then
-- one char with one stroke -- one char with one stroke
self:delHintChars(inputbox) self:delOnStageAndHintChars(inputbox)
self:clear_stack() self:clear_stack()
else else
inputbox.delChar:raw_method_call() inputbox.delChar:raw_method_call()
@ -304,11 +335,9 @@ function IME:wrappedAddChars(inputbox, char)
end end
self:refreshHintChars(inputbox) self:refreshHintChars(inputbox)
elseif char == self.separator or elseif char == self.separator or
self.use_space_as_separator and char == " " and _stack[1].code ~= "" then _stack[1].code ~= "" and self.partial_separators and util.arrayContains(self.partial_separators, char) then
imex.candi = {} self:separate(inputbox)
self:refreshHintChars(inputbox) return
self:clear_stack()
return
elseif char == self.local_del then elseif char == self.local_del then
if #imex.code > 0 then if #imex.code > 0 then
imex.candi = {} imex.candi = {}
@ -335,17 +364,23 @@ function IME:wrappedAddChars(inputbox, char)
imex.char = new_candi[1] imex.char = new_candi[1]
imex.candi = new_candi imex.candi = new_candi
self:refreshHintChars(inputbox) self:refreshHintChars(inputbox)
if self.auto_separate_callback() and self:uniqueMap(imex.code) then
self:separate(inputbox)
end
else else
if self.auto_separate_callback() then -- flush current stack
self:separate(inputbox)
end
new_candi,imex.last_candi = self:getCandidates(key) or {},nil -- single stroke new_candi,imex.last_candi = self:getCandidates(key) or {},nil -- single stroke
table.insert(_stack, {code=key, index=1, char=new_candi[1], candi=new_candi}) if self.auto_separate_callback() then
_stack[1] = { code=key, index=1, char=new_candi[1] or "", candi=new_candi }
else
table.insert(_stack, {code=key, index=1, char=new_candi[1] or "", candi=new_candi} )
end
self:refreshHintChars(inputbox) self:refreshHintChars(inputbox)
end end
else else
if #imex.candi > 1 then self:separate(inputbox)
imex.candi = {}
self:refreshHintChars(inputbox)
end
self:clear_stack()
inputbox.addChars:raw_method_call(char) inputbox.addChars:raw_method_call(char)
end end
end end

@ -15,7 +15,7 @@ rf. https://en.wikipedia.org/wiki/Stroke_count_method
--]] --]]
local IME = require("frontend/ui/data/keyboardlayouts/zh_ime") local IME = require("frontend/ui/data/keyboardlayouts/generic_ime")
local util = require("util") local util = require("util")
local JA = require("ui/data/keyboardlayouts/ja_keyboard_keys") local JA = require("ui/data/keyboardlayouts/ja_keyboard_keys")
local _ = require("gettext") local _ = require("gettext")
@ -95,6 +95,8 @@ local ime = IME:new{
show_candi_callback = function() show_candi_callback = function()
return G_reader_settings:nilOrTrue(SHOW_CANDI_KEY) return G_reader_settings:nilOrTrue(SHOW_CANDI_KEY)
end, end,
separator = "分隔",
switch_char = "下一字",
W = W -- has wildcard function W = W -- has wildcard function
} }
@ -102,8 +104,8 @@ local wrappedAddChars = function(inputbox, char)
ime:wrappedAddChars(inputbox, char) ime:wrappedAddChars(inputbox, char)
end end
local function wrappedSeparate(inputbox) local function seperate(inputbox)
ime:wrappedSeparate(inputbox) ime:separate(inputbox)
end end
local function wrappedDelChar(inputbox) local function wrappedDelChar(inputbox)
@ -128,19 +130,19 @@ local wrapInputBox = function(inputbox)
table.insert(wrappers, util.wrapMethod(inputbox, "delToStartOfLine", nil, clear_stack)) table.insert(wrappers, util.wrapMethod(inputbox, "delToStartOfLine", nil, clear_stack))
table.insert(wrappers, util.wrapMethod(inputbox, "clear", nil, clear_stack)) table.insert(wrappers, util.wrapMethod(inputbox, "clear", nil, clear_stack))
-- -- Navigation. -- -- Navigation.
table.insert(wrappers, util.wrapMethod(inputbox, "leftChar", nil, wrappedSeparate)) table.insert(wrappers, util.wrapMethod(inputbox, "leftChar", nil, seperate))
table.insert(wrappers, util.wrapMethod(inputbox, "rightChar", nil, wrappedSeparate)) table.insert(wrappers, util.wrapMethod(inputbox, "rightChar", nil, seperate))
table.insert(wrappers, util.wrapMethod(inputbox, "upLine", nil, wrappedSeparate)) table.insert(wrappers, util.wrapMethod(inputbox, "upLine", nil, seperate))
table.insert(wrappers, util.wrapMethod(inputbox, "downLine", nil, wrappedSeparate)) table.insert(wrappers, util.wrapMethod(inputbox, "downLine", nil, seperate))
-- -- Move to other input box. -- -- Move to other input box.
table.insert(wrappers, util.wrapMethod(inputbox, "unfocus", nil, wrappedSeparate)) table.insert(wrappers, util.wrapMethod(inputbox, "unfocus", nil, seperate))
table.insert(wrappers, util.wrapMethod(inputbox, "onCloseKeyboard", nil, wrappedSeparate)) table.insert(wrappers, util.wrapMethod(inputbox, "onCloseKeyboard", nil, seperate))
-- -- Gestures to move cursor. -- -- Gestures to move cursor.
table.insert(wrappers, util.wrapMethod(inputbox, "onTapTextBox", nil, wrappedSeparate)) table.insert(wrappers, util.wrapMethod(inputbox, "onTapTextBox", nil, seperate))
table.insert(wrappers, util.wrapMethod(inputbox, "onHoldTextBox", nil, wrappedSeparate)) table.insert(wrappers, util.wrapMethod(inputbox, "onHoldTextBox", nil, seperate))
table.insert(wrappers, util.wrapMethod(inputbox, "onSwipeTextBox", nil, wrappedSeparate)) table.insert(wrappers, util.wrapMethod(inputbox, "onSwipeTextBox", nil, seperate))
-- -- Others -- -- Others
table.insert(wrappers, util.wrapMethod(inputbox, "onSwitchingKeyboardLayout", nil, wrappedSeparate)) table.insert(wrappers, util.wrapMethod(inputbox, "onSwitchingKeyboardLayout", nil, seperate))
-- addChars is the only method we need a more complicated wrapper for. -- addChars is the only method we need a more complicated wrapper for.
table.insert(wrappers, util.wrapMethod(inputbox, "addChars", wrappedAddChars, nil)) table.insert(wrappers, util.wrapMethod(inputbox, "addChars", wrappedAddChars, nil))

Loading…
Cancel
Save