mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
[i18n] Add Korean keyboard (2-beolsik) (#5053)
This commit is contained in:
committed by
Frans de Jonge
parent
8fdb7483a2
commit
53b6e3d018
440
frontend/ui/data/keyboardlayouts/ko_KR_helper.lua
Normal file
440
frontend/ui/data/keyboardlayouts/ko_KR_helper.lua
Normal file
@@ -0,0 +1,440 @@
|
||||
-- require('utf8')
|
||||
local BaseUtil = require("ffi/util")
|
||||
local logger = require("logger")
|
||||
|
||||
--------
|
||||
-- # Hangul-input-method Kit for Lua/KOReader
|
||||
--------
|
||||
-- ## Input method implemented: 2-beolsik (for simplicity, can retrieve many articles for implementation)
|
||||
-- ## Classes and their features
|
||||
-- * HgSylbls (= Hangul Syllables)
|
||||
-- - Determine if a character is in Hangul consonnant, vowel, initial, medial, or final character
|
||||
-- - Combine initial, medial[, and final] character into a complete syllables
|
||||
-- - Determine if a medial (or final) character can be a double one (can combine another medial (or final) one)
|
||||
-- * HgFSM (= Hangul Finite State Machine)
|
||||
-- - Process Hangul syllabus combination if the character that user inputs are valid one to be combined
|
||||
-- * UIHandler
|
||||
-- - To communicate with the actual UI text input box
|
||||
--
|
||||
-- ## References
|
||||
-- https://ehclub.co.kr/2482
|
||||
-- :: Hangul syllables combination formula, Hangul unicode composition, FSM reference
|
||||
-- https://en.wikipedia.org/wiki/Hangul_consonant_and_vowel_tables
|
||||
--------
|
||||
|
||||
----------------------
|
||||
-- Hangul Syllables --
|
||||
----------------------
|
||||
|
||||
local HgSylbls = {
|
||||
-- Hangul character ranges in Unicode
|
||||
UNI_HG_BASE = 0xac00,
|
||||
UNI_HG_UPPER = 0xd7af,
|
||||
|
||||
UNI_HG_CONSONNANT_BASE = 0x1100,
|
||||
UNI_HG_CONSONNANT_UPPER = 0x1112,
|
||||
|
||||
UNI_HG_VOWEL_BASE = 0x1161,
|
||||
UNI_HG_VOWEL_UPPER = 0x1175,
|
||||
|
||||
UNI_HG_COMPAT_CONSONNANT_BASE = 0x3131,
|
||||
UNI_HG_COMPAT_CONSONNANT_UPPER = 0x314e,
|
||||
UNI_HG_COMPAT_VOWEL_BASE = 0x314f,
|
||||
UNI_HG_COMPAT_VOWEL_UPPER = 0x3163,
|
||||
|
||||
-- Initial, medial, and final characters to be combined
|
||||
CHARS_INITIAL = {"ㄱ", "ㄲ", "ㄴ", "ㄷ", "ㄸ", "ㄹ", "ㅁ", "ㅂ", "ㅃ",
|
||||
"ㅅ", "ㅆ", "ㅇ", "ㅈ", "ㅉ", "ㅊ", "ㅋ", "ㅌ", "ㅍ", "ㅎ"},
|
||||
|
||||
CHARS_MEDIAL = {"ㅏ", "ㅐ", "ㅑ", "ㅒ", "ㅓ", "ㅔ", "ㅕ", "ㅖ", "ㅗ", "ㅗㅏ", "ㅗㅐ", "ㅗㅣ", "ㅛ",
|
||||
"ㅜ", "ㅜㅓ", "ㅜㅔ", "ㅜㅣ", "ㅠ", "ㅡ", "ㅡㅣ", "ㅣ"},
|
||||
CHARS_MEDIAL_COMBINABLE = {"ㅗ", "ㅜ", "ㅡ"},
|
||||
|
||||
CHARS_FINAL = {nil, "ㄱ", "ㄲ", "ㄱㅅ", "ㄴ", "ㄴㅈ", "ㄴㅎ", "ㄷ", "ㄹ", "ㄹㄱ", "ㄹㅁ", "ㄹㅂ", "ㄹㅅ",
|
||||
"ㄹㅌ", "ㄹㅍ", "ㄹㅎ",
|
||||
"ㅁ", "ㅂ", "ㅂㅅ", "ㅅ", "ㅆ", "ㅇ", "ㅈ", "ㅊ", "ㅋ", "ㅌ", "ㅍ", "ㅎ"},
|
||||
CHARS_FINAL_COMBINABLE = {"ㄴ", "ㄹ", "ㅂ"},
|
||||
|
||||
-- For faster search, inverse index tables will be constructed in runtime
|
||||
IDX_INITIAL = nil,
|
||||
IDX_MEDIAL = nil,
|
||||
IDX_MEDIAL_COMBINABLE = nil,
|
||||
IDX_FINAL = nil,
|
||||
IDX_FINAL_COMBINABLE = nil,
|
||||
}
|
||||
|
||||
function HgSylbls:create_inverse_tbl()
|
||||
HgSylbls:_create_inverse_tbl_impl("CHARS", "IDX", "INITIAL")
|
||||
HgSylbls:_create_inverse_tbl_impl("CHARS", "IDX", "MEDIAL")
|
||||
HgSylbls:_create_inverse_tbl_impl("CHARS", "IDX", "MEDIAL_COMBINABLE")
|
||||
HgSylbls:_create_inverse_tbl_impl("CHARS", "IDX", "FINAL")
|
||||
HgSylbls:_create_inverse_tbl_impl("CHARS", "IDX", "FINAL_COMBINABLE")
|
||||
end
|
||||
|
||||
function HgSylbls:_create_inverse_tbl_impl(from_prefix, to_prefix, target_tbl)
|
||||
-- ref: https://stackoverflow.com/questions/38282234/returning-the-index-of-a-value-in-a-lua-table
|
||||
HgSylbls[to_prefix .. "_" .. target_tbl] = {}
|
||||
for k, v in pairs(HgSylbls[from_prefix .. "_" .. target_tbl]) do
|
||||
-- NOTE '-1' for making indices start from '0'
|
||||
HgSylbls[to_prefix .. "_" .. target_tbl][v] = k - 1
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function HgSylbls:get_combined_char(initial, medial, final)
|
||||
-- utf8.char()
|
||||
return BaseUtil.unichar(HgSylbls:_get_combined_charcode(initial, medial, final))
|
||||
end
|
||||
function HgSylbls:_get_combined_charcode(initial, medial, final)
|
||||
local len_medial = #HgSylbls.CHARS_MEDIAL
|
||||
local len_final = #HgSylbls.CHARS_FINAL
|
||||
|
||||
local combined_code = HgSylbls.UNI_HG_BASE
|
||||
+ HgSylbls:_initial_idx(initial) * len_medial * len_final
|
||||
+ HgSylbls:_medial_idx(medial) * len_final
|
||||
|
||||
local final_idx = HgSylbls:_final_idx(final)
|
||||
if final_idx then
|
||||
combined_code = combined_code + final_idx
|
||||
end
|
||||
|
||||
return combined_code
|
||||
end
|
||||
|
||||
function HgSylbls:_initial_idx(char)
|
||||
-- double initial can be typed directly from 2-beolsik kbd, hence no table of two chars
|
||||
return HgSylbls.IDX_INITIAL[char]
|
||||
end
|
||||
function HgSylbls:_medial_idx(char)
|
||||
char = HgSylbls:_2elem_tbl_to_str(char)
|
||||
return HgSylbls.IDX_MEDIAL[char]
|
||||
end
|
||||
function HgSylbls:_final_idx(char)
|
||||
char = HgSylbls:_2elem_tbl_to_str(char)
|
||||
return HgSylbls.IDX_FINAL[char]
|
||||
end
|
||||
|
||||
|
||||
function HgSylbls:in_intial(char)
|
||||
-- double initial can be typed directly from 2-beolsik kbd, hence no table of two chars
|
||||
return HgSylbls.IDX_INITIAL[char] ~= nil
|
||||
end
|
||||
function HgSylbls:in_medial(char)
|
||||
char = HgSylbls:_2elem_tbl_to_str(char)
|
||||
return HgSylbls.IDX_MEDIAL[char] ~= nil
|
||||
end
|
||||
function HgSylbls:in_final(char)
|
||||
char = HgSylbls:_2elem_tbl_to_str(char)
|
||||
return HgSylbls.IDX_FINAL[char] ~= nil
|
||||
end
|
||||
function HgSylbls:is_medial_comb(char)
|
||||
return HgSylbls.IDX_MEDIAL_COMBINABLE[char] ~= nil
|
||||
end
|
||||
function HgSylbls:is_final_comb(char)
|
||||
return HgSylbls.IDX_FINAL_COMBINABLE[char] ~= nil
|
||||
end
|
||||
|
||||
function HgSylbls:in_consonnant_char(char)
|
||||
return HgSylbls:_in_target_char_group(char,
|
||||
HgSylbls.UNI_HG_CONSONNANT_BASE, HgSylbls.UNI_HG_CONSONNANT_UPPER,
|
||||
HgSylbls.UNI_HG_COMPAT_CONSONNANT_BASE, HgSylbls.UNI_HG_COMPAT_CONSONNANT_UPPER)
|
||||
end
|
||||
function HgSylbls:in_vowel_char(char)
|
||||
return HgSylbls:_in_target_char_group(char,
|
||||
HgSylbls.UNI_HG_VOWEL_BASE, HgSylbls.UNI_HG_VOWEL_UPPER,
|
||||
HgSylbls.UNI_HG_COMPAT_VOWEL_BASE, HgSylbls.UNI_HG_COMPAT_VOWEL_UPPER)
|
||||
end
|
||||
function HgSylbls:_in_target_char_group(char, base, upper, compat_base, compat_upper)
|
||||
local code = BaseUtil.utf8charcode(char) -- utf8.codepoint()
|
||||
|
||||
if code == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
local result = base <= code and code <= upper
|
||||
|
||||
local result_compat = false
|
||||
if compat_base ~= nil then
|
||||
result_compat = compat_base <= code and code <= compat_upper
|
||||
end
|
||||
|
||||
return result or result_compat
|
||||
end
|
||||
|
||||
function HgSylbls:_2elem_tbl_to_str(str_or_tbl)
|
||||
-- if the type of argument is a 'table',
|
||||
-- then it is a double medial/final character
|
||||
if type(str_or_tbl) == "table" then
|
||||
local tbl = str_or_tbl
|
||||
return tbl[1] .. tbl[2]
|
||||
end
|
||||
-- otherwise, return an argument as-is
|
||||
return str_or_tbl
|
||||
end
|
||||
|
||||
-- initialize HgSylbls inverse index table
|
||||
HgSylbls:create_inverse_tbl()
|
||||
|
||||
|
||||
---------------
|
||||
-- UI interface mock; will be implemented
|
||||
---------------
|
||||
|
||||
local UIHandler = {}
|
||||
|
||||
function UIHandler:put_char(char)
|
||||
logger.dbg("UI:put_char()", char)
|
||||
end
|
||||
function UIHandler:del_char()
|
||||
logger.dbg("UI:del_char()")
|
||||
end
|
||||
function UIHandler:del_put_char(char)
|
||||
UIHandler:del_char()
|
||||
UIHandler:put_char(char)
|
||||
end
|
||||
|
||||
----------------------
|
||||
-- Hangul Automata --
|
||||
----------------------
|
||||
|
||||
local HgFSM = {
|
||||
STATE = {
|
||||
IDLE = 0,
|
||||
GOT_INITIAL = 1,
|
||||
GOT_MEDIAL = 2,
|
||||
GOT_FINAL = 3,
|
||||
GOT_DOUBLE_MEDIAL = 4,
|
||||
GOT_DOUBLE_FINAL = 5,
|
||||
},
|
||||
|
||||
initial = nil,
|
||||
medial = nil,
|
||||
final = nil,
|
||||
|
||||
fsm_state = nil,
|
||||
fsm_prev_states = {},
|
||||
|
||||
do_not_del_in_medial = false,
|
||||
|
||||
ui_handler = nil,
|
||||
}
|
||||
|
||||
function HgFSM:init(ui_handler)
|
||||
HgFSM:clean_state()
|
||||
|
||||
HgFSM.ui_handler = ui_handler
|
||||
end
|
||||
|
||||
function HgFSM:clean_state()
|
||||
HgFSM.initial = nil
|
||||
HgFSM.medial = nil
|
||||
HgFSM.final = nil
|
||||
|
||||
HgFSM.fsm_prev_states = {HgFSM.STATE.IDLE}
|
||||
HgFSM.fsm_state = HgFSM.STATE.IDLE
|
||||
|
||||
HgFSM.do_not_del_in_medial = false
|
||||
end
|
||||
|
||||
function HgFSM:_push_state(state)
|
||||
HgFSM.fsm_prev_states[#HgFSM.fsm_prev_states+1] = state -- append a state
|
||||
HgFSM.fsm_state = state
|
||||
end
|
||||
function HgFSM:_pop_state()
|
||||
local prev_state = HgFSM.fsm_prev_states[#HgFSM.fsm_prev_states]
|
||||
|
||||
table.remove(HgFSM.fsm_prev_states) -- pop last item
|
||||
HgFSM.fsm_state = HgFSM.fsm_prev_states[#HgFSM.fsm_prev_states]
|
||||
|
||||
return prev_state
|
||||
end
|
||||
|
||||
function HgFSM:process_char(char)
|
||||
if HgFSM:_should_handle_as_target_char(char) then
|
||||
HgFSM:_process_hg_char(char)
|
||||
else
|
||||
HgFSM:_process_generic_char(char)
|
||||
end
|
||||
end
|
||||
|
||||
function HgFSM:process_bsp(char)
|
||||
if HgFSM.fsm_state == HgFSM.STATE.IDLE or HgFSM.fsm_state == HgFSM.STATE.GOT_INITIAL then
|
||||
HgFSM:_process_generic_bsp()
|
||||
else
|
||||
HgFSM:_process_hg_bsp_except_initial()
|
||||
HgFSM:_process_hg_char_update_ui(true) -- true: always remove the current character in edit
|
||||
end
|
||||
end
|
||||
|
||||
function HgFSM:_should_handle_as_target_char(char)
|
||||
if HgSylbls:in_consonnant_char(char) then
|
||||
return true
|
||||
elseif HgSylbls:in_vowel_char(char) and HgFSM.fsm_state ~= HgFSM.STATE.IDLE then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function HgFSM:_process_generic_char(char)
|
||||
HgFSM:clean_state()
|
||||
HgFSM.ui_handler:put_char(char)
|
||||
end
|
||||
function HgFSM:_process_generic_bsp(char)
|
||||
HgFSM:clean_state()
|
||||
HgFSM.ui_handler:del_char()
|
||||
end
|
||||
|
||||
function HgFSM:_process_hg_char(char)
|
||||
local result = HgFSM:_process_hg_char_impl(char)
|
||||
|
||||
if result then
|
||||
HgFSM:_process_hg_char_update_ui()
|
||||
else -- e.g. single vowel character
|
||||
HgFSM:_process_generic_char(char)
|
||||
end
|
||||
end
|
||||
|
||||
function HgFSM:_process_hg_bsp_except_initial()
|
||||
local prev_state = HgFSM:_pop_state()
|
||||
|
||||
if prev_state == HgFSM.STATE.GOT_MEDIAL then
|
||||
HgFSM.medial = nil
|
||||
|
||||
elseif prev_state == HgFSM.STATE.GOT_DOUBLE_MEDIAL then
|
||||
HgFSM.medial = HgFSM.medial[1]
|
||||
|
||||
elseif prev_state == HgFSM.STATE.GOT_FINAL then
|
||||
HgFSM.final = nil
|
||||
|
||||
elseif prev_state == HgFSM.STATE.GOT_DOUBLE_FINAL then
|
||||
HgFSM.final = HgFSM.final[1]
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function HgFSM:_process_hg_char_impl(char)
|
||||
if HgFSM.fsm_state == HgFSM.STATE.IDLE then
|
||||
HgFSM:_process_hg_char_new_hg(char)
|
||||
|
||||
elseif HgFSM.fsm_state == HgFSM.STATE.GOT_INITIAL then
|
||||
if HgSylbls:in_consonnant_char(char) then
|
||||
HgFSM:_process_hg_char_new_hg(char)
|
||||
else
|
||||
HgFSM:_process_hg_char_push_medial(char)
|
||||
end
|
||||
|
||||
elseif HgFSM.fsm_state == HgFSM.STATE.GOT_MEDIAL then
|
||||
if HgSylbls:in_vowel_char(char) then
|
||||
local dbl_medial_cand = {HgFSM.medial, char}
|
||||
if HgSylbls:is_medial_comb(HgFSM.medial) and HgSylbls:in_medial(dbl_medial_cand) then
|
||||
HgFSM:_process_hg_char_push_medial(dbl_medial_cand, true)
|
||||
else
|
||||
return false
|
||||
end
|
||||
else
|
||||
HgFSM:_process_hg_char_push_final(char)
|
||||
end
|
||||
|
||||
elseif HgFSM.fsm_state == HgFSM.STATE.GOT_DOUBLE_MEDIAL then
|
||||
if HgSylbls:in_vowel_char(char) then
|
||||
return false
|
||||
else
|
||||
HgFSM:_process_hg_char_push_final(char)
|
||||
end
|
||||
|
||||
elseif HgFSM.fsm_state == HgFSM.STATE.GOT_FINAL then
|
||||
if HgSylbls:in_vowel_char(char) then
|
||||
HgFSM:_process_hg_char_borrow_initial_push_next_medial(
|
||||
nil, HgFSM.final, char)
|
||||
else
|
||||
local dbl_final_cand = {HgFSM.final, char}
|
||||
if HgSylbls:is_final_comb(HgFSM.final) and HgSylbls:in_final(dbl_final_cand) then
|
||||
HgFSM:_process_hg_char_push_final(dbl_final_cand, true)
|
||||
else
|
||||
HgFSM:_process_hg_char_new_hg(char)
|
||||
end
|
||||
end
|
||||
|
||||
elseif HgFSM.fsm_state == HgFSM.STATE.GOT_DOUBLE_FINAL then
|
||||
if HgSylbls:in_vowel_char(char) then
|
||||
HgFSM:_process_hg_char_borrow_initial_push_next_medial(
|
||||
HgFSM.final[1], HgFSM.final[2], char)
|
||||
else
|
||||
HgFSM:_process_hg_char_new_hg(char)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function HgFSM:_process_hg_char_new_hg(char)
|
||||
HgFSM:clean_state()
|
||||
|
||||
HgFSM:_push_state(HgFSM.STATE.GOT_INITIAL)
|
||||
HgFSM.initial = char
|
||||
end
|
||||
|
||||
function HgFSM:_process_hg_char_push_medial(char, is_double)
|
||||
if is_double then
|
||||
HgFSM:_push_state(HgFSM.STATE.GOT_DOUBLE_MEDIAL)
|
||||
else
|
||||
HgFSM:_push_state(HgFSM.STATE.GOT_MEDIAL)
|
||||
end
|
||||
HgFSM.medial = char
|
||||
end
|
||||
|
||||
function HgFSM:_process_hg_char_push_final(char, is_double)
|
||||
if is_double then
|
||||
HgFSM:_push_state(HgFSM.STATE.GOT_DOUBLE_FINAL)
|
||||
else
|
||||
HgFSM:_push_state(HgFSM.STATE.GOT_FINAL)
|
||||
end
|
||||
HgFSM.final = char
|
||||
end
|
||||
|
||||
function HgFSM:_process_hg_char_borrow_initial_push_next_medial(curr_final, next_init, next_medial)
|
||||
local next_init_cand = next_init
|
||||
HgFSM.final = curr_final
|
||||
HgFSM:_pop_state() -- go to previous state
|
||||
HgFSM:_process_hg_char_update_ui() -- apply UI the borrow of final character
|
||||
|
||||
HgFSM:_process_hg_char_new_hg(next_init_cand)
|
||||
|
||||
HgFSM:_push_state(HgFSM.STATE.GOT_MEDIAL)
|
||||
HgFSM.medial = next_medial
|
||||
HgFSM.do_not_del_in_medial = true -- previous character in edit has to be maintained
|
||||
end
|
||||
|
||||
|
||||
function HgFSM:_process_hg_char_update_ui(should_undo_in_initial)
|
||||
should_undo_in_initial = should_undo_in_initial or false
|
||||
|
||||
if HgFSM.fsm_state == HgFSM.STATE.GOT_INITIAL then
|
||||
if should_undo_in_initial then
|
||||
HgFSM.ui_handler:del_char()
|
||||
end
|
||||
HgFSM.ui_handler:put_char(HgFSM.initial)
|
||||
|
||||
elseif HgFSM.fsm_state == HgFSM.STATE.GOT_MEDIAL or HgFSM.fsm_state == HgFSM.STATE.GOT_DOUBLE_MEDIAL then
|
||||
local combined_char = HgSylbls:get_combined_char(HgFSM.initial, HgFSM.medial, nil)
|
||||
if HgFSM.do_not_del_in_medial then
|
||||
HgFSM.do_not_del_in_medial = false
|
||||
HgFSM.ui_handler:put_char(combined_char)
|
||||
else
|
||||
HgFSM.ui_handler:del_put_char(combined_char)
|
||||
end
|
||||
|
||||
elseif HgFSM.fsm_state == HgFSM.STATE.GOT_FINAL or HgFSM.fsm_state == HgFSM.STATE.GOT_DOUBLE_FINAL then
|
||||
local combined_char = HgSylbls:get_combined_char(HgFSM.initial, HgFSM.medial, HgFSM.final)
|
||||
HgFSM.ui_handler:del_put_char(combined_char)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return {
|
||||
UIHandler = UIHandler,
|
||||
HgFSM = HgFSM,
|
||||
}
|
||||
226
frontend/ui/data/keyboardlayouts/ko_KR_keyboard.lua
Normal file
226
frontend/ui/data/keyboardlayouts/ko_KR_keyboard.lua
Normal file
@@ -0,0 +1,226 @@
|
||||
local logger = require("logger")
|
||||
|
||||
--------
|
||||
-- # Korean 2-beolsik Keyboard layout
|
||||
--------
|
||||
|
||||
local HgHelper = require("ui/data/keyboardlayouts/ko_KR_helper")
|
||||
|
||||
--------
|
||||
-- UI handler implementation for communicating with text input box widget
|
||||
--------
|
||||
function HgHelper.UIHandler:put_char(char)
|
||||
HgHelper.UIHandler.inputbox:_addChars(char)
|
||||
end
|
||||
function HgHelper.UIHandler:del_char(char)
|
||||
HgHelper.UIHandler.inputbox:_delChar()
|
||||
end
|
||||
HgHelper.HgFSM:init(HgHelper.UIHandler)
|
||||
|
||||
--------
|
||||
-- Custom key event handlers with Hangul support
|
||||
--------
|
||||
local wrapInputBox = function(inputbox)
|
||||
HgHelper.HgFSM.clean_state() -- reset helper
|
||||
|
||||
if inputbox._wrapped == nil then
|
||||
inputbox._wrapped = true
|
||||
|
||||
-- helper function
|
||||
local function copy_func_reference(obj, name)
|
||||
obj["_" .. name] = obj[name]
|
||||
end
|
||||
|
||||
-- override original implementations with helper object
|
||||
copy_func_reference(inputbox, "addChars")
|
||||
copy_func_reference(inputbox, "delChar")
|
||||
|
||||
function inputbox:addChars(key)
|
||||
logger.dbg("ko_KR_kbd:addChar(", key, ")")
|
||||
HgHelper.UIHandler.inputbox = self
|
||||
HgHelper.HgFSM:process_char(key)
|
||||
end
|
||||
function inputbox:delChar()
|
||||
logger.dbg("ko_KR_kbd:delChar()")
|
||||
HgHelper.UIHandler.inputbox = self
|
||||
HgHelper.HgFSM:process_bsp()
|
||||
end
|
||||
|
||||
-- override implementations: reset helper if we have to stop combining current syllable
|
||||
---- helper function
|
||||
local function wrap_func_with_hghelper_reset(obj, name)
|
||||
copy_func_reference(obj, name)
|
||||
obj[name] = function(self)
|
||||
HgHelper.HgFSM.clean_state()
|
||||
self["_" .. name](self)
|
||||
end
|
||||
end
|
||||
|
||||
---- delete text
|
||||
wrap_func_with_hghelper_reset(inputbox, "delToStartOfLine")
|
||||
wrap_func_with_hghelper_reset(inputbox, "clear")
|
||||
|
||||
---- move cursor
|
||||
wrap_func_with_hghelper_reset(inputbox, "leftChar")
|
||||
wrap_func_with_hghelper_reset(inputbox, "rightChar")
|
||||
wrap_func_with_hghelper_reset(inputbox, "upLine")
|
||||
wrap_func_with_hghelper_reset(inputbox, "downLine")
|
||||
|
||||
---- unfocus: move to other inputbox
|
||||
wrap_func_with_hghelper_reset(inputbox, "unfocus")
|
||||
|
||||
---- tap/hold/swipe: move cursor
|
||||
------ helper function
|
||||
local function wrap_touch_event_func_with_hghelper_reset(obj, name)
|
||||
copy_func_reference(obj, name)
|
||||
obj[name] = function(self, arg, ges)
|
||||
HgHelper.HgFSM.clean_state()
|
||||
return self["_" .. name](self, arg, ges)
|
||||
end
|
||||
end
|
||||
|
||||
wrap_touch_event_func_with_hghelper_reset(inputbox, "onTapTextBox")
|
||||
wrap_touch_event_func_with_hghelper_reset(inputbox, "onHoldTextBox")
|
||||
wrap_touch_event_func_with_hghelper_reset(inputbox, "onSwipeTextBox")
|
||||
end
|
||||
end
|
||||
|
||||
-- Belows are just same as the English keyboard popup
|
||||
local en_popup = require("ui/data/keyboardlayouts/keypopup/en_popup")
|
||||
local com = en_popup.com -- comma (,)
|
||||
local prd = en_popup.prd -- period (.)
|
||||
local _at = en_popup._at
|
||||
local _eq = en_popup._eq -- equals sign (=)
|
||||
local _A_ = en_popup._A_
|
||||
local _a_ = en_popup._a_
|
||||
local _B_ = en_popup._B_
|
||||
local _b_ = en_popup._b_
|
||||
local _C_ = en_popup._C_
|
||||
local _c_ = en_popup._c_
|
||||
local _D_ = en_popup._D_
|
||||
local _d_ = en_popup._d_
|
||||
local _E_ = en_popup._E_
|
||||
local _e_ = en_popup._e_
|
||||
local _F_ = en_popup._F_
|
||||
local _f_ = en_popup._f_
|
||||
local _G_ = en_popup._G_
|
||||
local _g_ = en_popup._g_
|
||||
local _H_ = en_popup._H_
|
||||
local _h_ = en_popup._h_
|
||||
local _I_ = en_popup._I_
|
||||
local _i_ = en_popup._i_
|
||||
local _J_ = en_popup._J_
|
||||
local _j_ = en_popup._j_
|
||||
local _K_ = en_popup._K_
|
||||
local _k_ = en_popup._k_
|
||||
local _L_ = en_popup._L_
|
||||
local _l_ = en_popup._l_
|
||||
local _M_ = en_popup._M_
|
||||
local _m_ = en_popup._m_
|
||||
local _N_ = en_popup._N_
|
||||
local _n_ = en_popup._n_
|
||||
local _O_ = en_popup._O_
|
||||
local _o_ = en_popup._o_
|
||||
local _P_ = en_popup._P_
|
||||
local _p_ = en_popup._p_
|
||||
local _Q_ = en_popup._Q_
|
||||
local _q_ = en_popup._q_
|
||||
local _R_ = en_popup._R_
|
||||
local _r_ = en_popup._r_
|
||||
local _S_ = en_popup._S_
|
||||
local _s_ = en_popup._s_
|
||||
local _T_ = en_popup._T_
|
||||
local _t_ = en_popup._t_
|
||||
local _U_ = en_popup._U_
|
||||
local _u_ = en_popup._u_
|
||||
local _V_ = en_popup._V_
|
||||
local _v_ = en_popup._v_
|
||||
local _W_ = en_popup._W_
|
||||
local _w_ = en_popup._w_
|
||||
local _X_ = en_popup._X_
|
||||
local _x_ = en_popup._x_
|
||||
local _Y_ = en_popup._Y_
|
||||
local _y_ = en_popup._y_
|
||||
local _Z_ = en_popup._Z_
|
||||
local _z_ = en_popup._z_
|
||||
|
||||
-- Based on English keyboard layout, but modifications are made for Korean layout
|
||||
return {
|
||||
shiftmode_keys = {["Shift"] = true},
|
||||
symbolmode_keys = {["Sym"] = true, ["ABC"] = true},
|
||||
utf8mode_keys = {["IM"] = true},
|
||||
umlautmode_keys = {["Äéß"] = false}, -- Disabled 'umlaut' keys
|
||||
keys = {
|
||||
-- [shift, unshift, symbol-shift, symbol-unshift]
|
||||
-- 1, 2, 3, 4: default
|
||||
-- 5, 6, 7, 8: 'IM' (globe)
|
||||
-- 9, 10, 11, 12: 'umlaut' (UNUSED)
|
||||
--
|
||||
-- first row
|
||||
{ -- 1 2 3 4 5 6 7 8 9 10 11 12
|
||||
{ _Q_, _q_, "„", "0", "ㅃ", "ㅂ", "₩", "0", "Å", "å", "1", "ª", },
|
||||
{ _W_, _w_, "!", "1", "ㅉ", "ㅈ", "!", "1", "Ä", "ä", "2", "º", },
|
||||
{ _E_, _e_, _at, "2", "ㄸ", "ㄷ", _at, "2", "Ö", "ö", "3", "¡", },
|
||||
{ _R_, _r_, "#", "3", "ㄲ", "ㄱ", "#", "3", "ß", "ß", "4", "¿", },
|
||||
{ _T_, _t_, "+", _eq, "ㅆ", "ㅅ", "+", _eq, "À", "à", "5", "¼", },
|
||||
{ _Y_, _y_, "€", "(", "ㅛ", "ㅛ", "☆", "(", "Â", "â", "6", "½", },
|
||||
{ _U_, _u_, "‰", ")", "ㅕ", "ㅕ", "★", ")", "Æ", "æ", "7", "¾", },
|
||||
{ _I_, _i_, "|", "\\", "ㅑ", "ㅑ", "♡", "\\", "Ü", "ü", "8", "©", },
|
||||
{ _O_, _o_, "?", "/", "ㅒ", "ㅐ", "♥", "/", "È", "è", "9", "®", },
|
||||
{ _P_, _p_, "~", "`", "ㅖ", "ㅔ", "※", "`", "É", "é", "0", "™", },
|
||||
},
|
||||
-- second row
|
||||
{ -- 1 2 3 4 5 6 7 8 9 10 11 12
|
||||
{ _A_, _a_, "…", _at, "ㅁ", "ㅁ", "…", "@", "Ê", "ê", "Ş", "ş", },
|
||||
{ _S_, _s_, "$", "4", "ㄴ", "ㄴ", "$", "4", "Ë", "ë", "İ", "ı", },
|
||||
{ _D_, _d_, "%", "5", "ㅇ", "ㅇ", "%", "5", "Î", "î", "Ğ", "ğ", },
|
||||
{ _F_, _f_, "^", "6", "ㄹ", "ㄹ", "^", "6", "Ï", "ï", "Ć", "ć", },
|
||||
{ _G_, _g_, ":", ";", "ㅎ", "ㅎ", ":", "'", "Ô", "ô", "Č", "č", },
|
||||
{ _H_, _h_, '"', "'", "ㅗ", "ㅗ", "♩", "\"", "Œ", "œ", "Đ", "đ", },
|
||||
{ _J_, _j_, "{", "[", "ㅓ", "ㅓ", "♪", "[", "Ù", "ù", "Š", "š", },
|
||||
{ _K_, _k_, "}", "]", "ㅏ", "ㅏ", "♬", "]", "Û", "û", "Ž", "ž", },
|
||||
{ _L_, _l_, "_", "-", "ㅣ", "ㅣ", "™", "-", "Ÿ", "ÿ", "Ő", "ő", },
|
||||
},
|
||||
-- third row
|
||||
{ -- 1 2 3 4 5 6 7 8 9 10 11 12
|
||||
{ label = "Shift",
|
||||
icon = "resources/icons/appbar.arrow.shift.png",
|
||||
width = 1.5
|
||||
},
|
||||
{ _Z_, _z_, "&", "7", "ㅋ", "ㅋ", "「", "7", "Á", "á", "Ű", "ű", },
|
||||
{ _X_, _x_, "*", "8", "ㅌ", "ㅌ", "」", "8", "Ø", "ø", "Ã", "ã", },
|
||||
{ _C_, _c_, "£", "9", "ㅊ", "ㅊ", "*", "9", "Í", "í", "Þ", "þ", },
|
||||
{ _V_, _v_, "<", com, "ㅍ", "ㅍ", "❤", com, "Ñ", "ñ", "Ý", "ý", },
|
||||
{ _B_, _b_, ">", prd, "ㅠ", "ㅠ", "&", prd, "Ó", "ó", "†", "‡", },
|
||||
{ _N_, _n_, "‘", "↑", "ㅜ", "ㅜ", "『", "↑", "Ú", "ú", "–", "—", },
|
||||
{ _M_, _m_, "’", "↓", "ㅡ", "ㅡ", "』", "↓", "Ç", "ç", "…", "¨", },
|
||||
{ label = "Backspace",
|
||||
icon = "resources/icons/appbar.clear.reflect.horizontal.png",
|
||||
width = 1.5
|
||||
},
|
||||
},
|
||||
-- fourth row
|
||||
{
|
||||
{ "Sym", "Sym", "ABC", "ABC", "Sym", "Sym", "ABC", "ABC", "Sym", "Sym", "ABC", "ABC",
|
||||
width = 1.5},
|
||||
{ label = "IM",
|
||||
icon = "resources/icons/appbar.globe.wire.png",
|
||||
width = 2,
|
||||
},
|
||||
-- { "Äéß", "Äéß", "Äéß", "Äéß", "Äéß", "Äéß", "Äéß", "Äéß", "Äéß", "Äéß", "Äéß", "Äéß", },
|
||||
{ label = "간격",
|
||||
" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ",
|
||||
width = 3.0},
|
||||
{ com, com, "“", "←", com, com, com, "←", "Ũ", "ũ", com, com, },
|
||||
{ prd, prd, "”", "→", prd, prd, prd, "→", "Ĩ", "ĩ", prd, prd, },
|
||||
{ label = "Enter",
|
||||
"\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n",
|
||||
icon = "resources/icons/appbar.arrow.enter.png",
|
||||
width = 1.5,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
-- wrap InputBox for hooking events to the helper
|
||||
wrapInputBox = wrapInputBox,
|
||||
}
|
||||
@@ -527,6 +527,7 @@ local lang_to_keyboard_layout = {
|
||||
ja = "ja_keyboard",
|
||||
pl = "pl_keyboard",
|
||||
pt_BR = "pt_keyboard",
|
||||
ko_KR = "ko_KR_keyboard",
|
||||
}
|
||||
|
||||
function VirtualKeyboard:init()
|
||||
@@ -546,6 +547,9 @@ function VirtualKeyboard:init()
|
||||
if Device:hasKeys() then
|
||||
self.key_events.Close = { {"Back"}, doc = "close keyboard" }
|
||||
end
|
||||
if keyboard.wrapInputBox then
|
||||
keyboard.wrapInputBox(self.inputbox)
|
||||
end
|
||||
end
|
||||
|
||||
function VirtualKeyboard:onClose()
|
||||
|
||||
Reference in New Issue
Block a user