[i18n] Add Korean keyboard (2-beolsik) (#5053)

pull/5055/head
limerainne 5 years ago committed by Frans de Jonge
parent 8fdb7483a2
commit 53b6e3d018

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

@ -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()

Loading…
Cancel
Save