diff --git a/lua/kp_number_processor.lua b/lua/kp_number_processor.lua index 09148e9..1fdc2b6 100644 --- a/lua/kp_number_processor.lua +++ b/lua/kp_number_processor.lua @@ -11,171 +11,234 @@ -- # auto : 空闲时直接上屏,输入中参与编码 -- # compose : 无论是否在输入中,小键盘都参与编码(不直接上屏) -- kp_number_mode: auto --- --- # 可选:命令模式 patterns(Lua pattern) --- # kp_number: --- # patterns: --- # - "^/[0-9]$" --- # - "^/[A-Za-z]+$" --- # - "^V.*$" --- # ... local wanxiang = require("wanxiang") -- 小键盘键码映射 local KP = { - [0xFFB1] = 1, [0xFFB2] = 2, [0xFFB3] = 3, - [0xFFB4] = 4, [0xFFB5] = 5, [0xFFB6] = 6, - [0xFFB7] = 7, [0xFFB8] = 8, [0xFFB9] = 9, - [0xFFB0] = 0, + [0xFFB1] = 1, -- KP_1 + [0xFFB2] = 2, + [0xFFB3] = 3, + [0xFFB4] = 4, + [0xFFB5] = 5, + [0xFFB6] = 6, + [0xFFB7] = 7, + [0xFFB8] = 8, + [0xFFB9] = 9, + [0xFFB0] = 0, -- KP_0 } local P = {} --- 加载配置中的正则模式 +-- 从 schema 读取 kp_number/patterns 列表 local function load_function_patterns(config) local patterns = {} - local ok_list, list = pcall(function() return config:get_list("kp_number/patterns") end) - + + local ok_list, list = pcall(function() + return config:get_list("kp_number/patterns") + end) if ok_list and list and list.size and list.size > 0 then for i = 0, list.size - 1 do local item = list:get_value_at(i) - if item then table.insert(patterns, item:get_string()) end + if item then + local pat = item:get_string() + if pat and pat ~= "" then + table.insert(patterns, pat) + end + end end end - -- 默认保底配置 + -- 如果用户没配,给一份保底的默认集合(等价你现在用的那些) if #patterns == 0 then patterns = { - "^/[0-9]$", "^/10$", "^/[A-Za-z]+$", "^`[A-Za-z]*$", "^``[A-Za-z/`']*$", - "^U[%da-f]+$", "^R[0-9]+%.?[0-9]*$", - "^N0[1-9]?0?[1-9]?$", "^N1[02]?0?[1-9]?$", "^N0[1-9]?[1-2]?[1-9]?$", - "^N1[02]?[1-2]?[1-9]?$", "^N0[1-9]?3?[01]?$", "^N1[02]?3?[01]?$", - "^N19?[0-9]?[0-9]?[01]?[0-2]?[0-3]?[0-9]?$", + "^/[0-9]$", "^/10$", "^/[A-Za-z]+$", + "^`[A-Za-z]*$", + "^``[A-Za-z/`']*$", + "^U[%da-f]+$", + "^R[0-9]+%.?[0-9]*$", + "^N0[1-9]?0?[1-9]?$", + "^N1[02]?0?[1-9]?$", + "^N0[1-9]?[1-2]?[1-9]?$", + "^N1[02]?[1-2]?[1-9]?$", + "^N0[1-9]?3?[01]?$", + "^N1[02]?3?[01]?$", + "^N19?[0-9]?[0-9]?[01]?[0-2]?[0-3]?[0-9]?$", "^N20?[0-9]?[0-9]?[01]?[0-2]?[0-3]?[0-9]?$", "^V.*$", } end + return patterns end --- 判断是否为命令模式 +-- 根据“当前编码 + 这次按下的数字字符”判断是否属于命令模式 local function is_function_code_after_digit(env, context, digit_char) - if not context or not digit_char or digit_char == "" then return false end + if not context or not digit_char or digit_char == "" then + return false + end local code = context.input or "" local s = code .. digit_char + local pats = env.function_patterns - if not pats then return false end - + if not pats or #pats == 0 then + return false + end + for _, pat in ipairs(pats) do - if s:match(pat) then return true end + -- 这里 pat 必须是 Lua pattern 语法 + if s:match(pat) then + return true + end end return false end +---@param env Env function P.init(env) - local engine = env.engine - local config = engine.schema.config + local engine = env.engine + local config = engine.schema.config local context = engine.context - -- 核心:判断并缓存设备类型 - env.is_mobile = wanxiang.is_mobile_device() - + -- 读数字选词个数 env.page_size = config:get_int("menu/page_size") or 6 - - local m = config:get_string("kp_number/kp_number_mode") or "auto" - env.kp_mode = (m == "compose") and "compose" or "auto" - env.context = context + -- 读小键盘模式:auto / compose,默认 auto + local m = config:get_string("kp_number/kp_number_mode") or "auto" + if m ~= "auto" and m ~= "compose" then + m = "auto" + end + env.kp_mode = m + + -- 初始化状态快照 + env.context = context env.is_composing = context:is_composing() - env.has_menu = context:has_menu() + env.has_menu = context:has_menu() + + -- 读取命令模式 Lua pattern 集合 env.function_patterns = load_function_patterns(config) + -- 用 update_notifier 同步 context / is_composing / has_menu env.kp_update_connection = context.update_notifier:connect(function(ctx) - env.context = ctx + env.context = ctx env.is_composing = ctx:is_composing() - env.has_menu = ctx:has_menu() + env.has_menu = ctx:has_menu() end) end +---@param env Env function P.fini(env) if env.kp_update_connection then env.kp_update_connection:disconnect() env.kp_update_connection = nil end - env.context = nil + env.context = nil + env.is_composing = nil + env.has_menu = nil env.function_patterns = nil end +---@param key KeyEvent +---@param env Env +---@return ProcessResult function P.func(key, env) - if key:release() then - return wanxiang.RIME_PROCESS_RESULTS.kNoop + -- 只处理按下 + if key:release() then + return wanxiang.RIME_PROCESS_RESULTS.kNoop end - local context = env.context + local engine = env.engine + local context = env.context or engine.context + local mode = env.kp_mode or "auto" + local page_sz = env.page_size + + local is_composing = env.is_composing + local has_menu = env.has_menu + + ------------------------------------------------------------------ + -- 1) 小键盘数字:auto / compose + -- 如果“加上本次数字后”还匹配某个命令模式 pattern: + -- 只作为编码输入,不 commit、不选词。 + ------------------------------------------------------------------ local kp_num = KP[key.keycode] + if kp_num ~= nil then + local ch = tostring(kp_num) -- "0".."9" - ----------------------------------------------------------- - -- 1. 桌面端小键盘专用逻辑 (非 Mobile 才执行) - -- Mobile 端直接跳过此段,进入下方通用逻辑 - ----------------------------------------------------------- - if kp_num ~= nil and not env.is_mobile then - local ch = tostring(kp_num) - - -- 检查命令模式 if is_function_code_after_digit(env, context, ch) then - context:push_input(ch) + if context then + if context.push_input then + context:push_input(ch) + else + context.input = (context.input or "") .. ch + end + end return wanxiang.RIME_PROCESS_RESULTS.kAccepted end - -- Auto / Compose 模式处理 - if env.kp_mode == "auto" then - if env.is_composing then - context:push_input(ch) + if mode == "auto" then + -- 输入中:参与编码;空闲:直接上屏 + if is_composing then + if context.push_input then + context:push_input(ch) + else + context.input = (context.input or "") .. ch + end else - env.engine:commit_text(ch) + engine:commit_text(ch) end else - context:push_input(ch) + -- compose:始终参与编码 + if context.push_input then + context:push_input(ch) + else + context.input = (context.input or "") .. ch + end end + return wanxiang.RIME_PROCESS_RESULTS.kAccepted end - ----------------------------------------------------------- - -- 2. 主键盘数字 / 移动端小键盘逻辑 - ----------------------------------------------------------- + ------------------------------------------------------------------ + -- 2) 主键盘数字: + -- 2.1 若“加上本次数字后”匹配命令模式 → 只当编码输入 + -- 2.2 否则: + -- 有菜单时:选第 n 个候选 + -- 空闲时:直接上屏 + ------------------------------------------------------------------ local r = key:repr() or "" - -- 特殊处理:如果是移动端且按下了小键盘,强制将其视为普通数字 - if kp_num ~= nil and env.is_mobile then - r = tostring(kp_num) - end - - -- 仅处理数字键 if r:match("^[0-9]$") then - -- 优先检查:是否匹配命令模式(参与编码) + -- 命令模式:只作为编码输入 if is_function_code_after_digit(env, context, r) then - context:push_input(r) + if context then + if context.push_input then + context:push_input(r) + else + context.input = (context.input or "") .. r + end + end return wanxiang.RIME_PROCESS_RESULTS.kAccepted end - -- 其次检查:是否有菜单(用于选词) - -- 这就是移动端小键盘想要的效果:有菜单时选词 - if env.has_menu then + -- 有候选菜单时,用数字选「当前页」的第 n 个候选 + if has_menu then local d = tonumber(r) - local page_sz = env.page_size - if d and d >= 1 and d <= page_sz then - local composition = context.composition + local composition = context and context.composition if composition and not composition:empty() then - local seg = composition:back() - local menu = seg.menu - + local seg = composition:back() -- 当前正在编辑的 segment + local menu = seg and seg.menu if menu and not menu:empty() then + -- 当前高亮候选的全局下标(0 开始) local sel_index = seg.selected_index or 0 - local page_no = math.floor(sel_index / page_sz) - local index = (page_no * page_sz) + (d - 1) + local page_size = page_sz + -- 当前页号 = 高亮索引 / 每页大小 + local page_no = math.floor(sel_index / page_size) + local page_start = page_no * page_size + -- 当前页第 n 个候选的全局下标 + local index = page_start + (d - 1) + -- 防止越界(最后一页候选不足一整页) if index < menu:candidate_count() then if context:select(index) then return wanxiang.RIME_PROCESS_RESULTS.kAccepted @@ -184,12 +247,10 @@ function P.func(key, env) end end end - -- 如果是数字键但没选中(例如超出页码),不做处理,交由系统(通常会上屏数字) return wanxiang.RIME_PROCESS_RESULTS.kNoop end end - return wanxiang.RIME_PROCESS_RESULTS.kNoop end -return P \ No newline at end of file +return P