mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
* Add a basic Japanese keyboard layout Allow for entring Japanese text into text boxes. Only supports kana and latin letters due to limitations of current VirtualKeyboard implementation (complex text input with conversion is not possible). * Allow keyboard layouts to declare custom modifiers Refactor modifier key setup code and existing keyboard layouts so that each layout can declare custom modifier key labels. This allows for greater extensibility and for future keyboard layouts.
301 lines
9.5 KiB
Lua
301 lines
9.5 KiB
Lua
local Blitbuffer = require("ffi/blitbuffer")
|
|
local BottomContainer = require("ui/widget/container/bottomcontainer")
|
|
local CenterContainer = require("ui/widget/container/centercontainer")
|
|
local Device = require("device")
|
|
local Font = require("ui/font")
|
|
local FrameContainer = require("ui/widget/container/framecontainer")
|
|
local Geom = require("ui/geometry")
|
|
local GestureRange = require("ui/gesturerange")
|
|
local HorizontalGroup = require("ui/widget/horizontalgroup")
|
|
local HorizontalSpan = require("ui/widget/horizontalspan")
|
|
local ImageWidget = require("ui/widget/imagewidget")
|
|
local InputContainer = require("ui/widget/container/inputcontainer")
|
|
local TextWidget = require("ui/widget/textwidget")
|
|
local UIManager = require("ui/uimanager")
|
|
local VerticalGroup = require("ui/widget/verticalgroup")
|
|
local VerticalSpan = require("ui/widget/verticalspan")
|
|
local logger = require("logger")
|
|
local Screen = Device.screen
|
|
|
|
local VirtualKey = InputContainer:new{
|
|
key = nil,
|
|
icon = nil,
|
|
label = nil,
|
|
|
|
keyboard = nil,
|
|
callback = nil,
|
|
|
|
width = nil,
|
|
height = math.max(Screen:getWidth(), Screen:getHeight())*0.33,
|
|
bordersize = 2,
|
|
face = Font:getFace("infont"),
|
|
}
|
|
|
|
function VirtualKey:init()
|
|
if self.keyboard.symbolmode_keys[self.label] ~= nil then
|
|
self.callback = function () self.keyboard:setLayout("Sym") end
|
|
elseif self.keyboard.shiftmode_keys[self.label] ~= nil then
|
|
self.callback = function () self.keyboard:setLayout("Shift") end
|
|
elseif self.keyboard.utf8mode_keys[self.label] ~= nil then
|
|
self.callback = function () self.keyboard:setLayout("IM") end
|
|
elseif self.keyboard.umlautmode_keys[self.label] ~= nil then
|
|
self.callback = function () self.keyboard:setLayout("Äéß") end
|
|
elseif self.label == "Backspace" then
|
|
self.callback = function () self.keyboard:delChar() end
|
|
self.hold_callback = function () self.keyboard:clear() end
|
|
else
|
|
self.callback = function () self.keyboard:addChar(self.key) end
|
|
end
|
|
|
|
local label_widget
|
|
if self.icon then
|
|
label_widget = ImageWidget:new{
|
|
file = self.icon,
|
|
}
|
|
else
|
|
label_widget = TextWidget:new{
|
|
text = self.label,
|
|
face = self.face,
|
|
}
|
|
end
|
|
self[1] = FrameContainer:new{
|
|
margin = 0,
|
|
bordersize = self.bordersize,
|
|
background = Blitbuffer.COLOR_WHITE,
|
|
radius = 5,
|
|
padding = 0,
|
|
CenterContainer:new{
|
|
dimen = Geom:new{
|
|
w = self.width - 2*self.bordersize,
|
|
h = self.height - 2*self.bordersize,
|
|
},
|
|
label_widget,
|
|
},
|
|
}
|
|
self.dimen = Geom:new{
|
|
w = self.width,
|
|
h = self.height,
|
|
}
|
|
--self.dimen = self[1]:getSize()
|
|
if Device:isTouchDevice() then
|
|
self.ges_events = {
|
|
TapSelect = {
|
|
GestureRange:new{
|
|
ges = "tap",
|
|
range = self.dimen,
|
|
},
|
|
},
|
|
HoldSelect = {
|
|
GestureRange:new{
|
|
ges = "hold",
|
|
range = self.dimen,
|
|
},
|
|
},
|
|
}
|
|
end
|
|
end
|
|
|
|
function VirtualKey:update_keyboard()
|
|
UIManager:setDirty(self.keyboard, function()
|
|
logger.dbg("update key region", self[1].dimen)
|
|
return "ui", self[1].dimen
|
|
end)
|
|
end
|
|
|
|
function VirtualKey:onTapSelect()
|
|
self[1].invert = true
|
|
self:update_keyboard()
|
|
if self.callback then
|
|
self.callback()
|
|
end
|
|
UIManager:scheduleIn(0.2, function() self:invert(false) end)
|
|
return true
|
|
end
|
|
|
|
function VirtualKey:onHoldSelect()
|
|
self[1].invert = true
|
|
self:update_keyboard()
|
|
if self.hold_callback then
|
|
self.hold_callback()
|
|
end
|
|
UIManager:scheduleIn(0.2, function() self:invert(false) end)
|
|
return true
|
|
end
|
|
|
|
function VirtualKey:invert(invert)
|
|
self[1].invert = invert
|
|
self:update_keyboard()
|
|
end
|
|
|
|
local VirtualKeyboard = InputContainer:new{
|
|
is_always_active = true,
|
|
disable_double_tap = true,
|
|
inputbox = nil,
|
|
KEYS = {}, -- table to store layouts
|
|
shiftmode_keys = {},
|
|
symbolmode_keys = {},
|
|
utf8mode_keys = {},
|
|
umlautmode_keys = {},
|
|
min_layout = 2,
|
|
max_layout = 12,
|
|
layout = 2,
|
|
shiftmode = false,
|
|
symbolmode = false,
|
|
utf8mode = false,
|
|
umlautmode = false,
|
|
|
|
width = Screen:scaleBySize(600),
|
|
height = nil,
|
|
bordersize = Screen:scaleBySize(2),
|
|
padding = Screen:scaleBySize(2),
|
|
key_padding = Screen:scaleBySize(6),
|
|
}
|
|
|
|
local lang_to_keyboard_layout = {
|
|
el = "el_keyboard",
|
|
ja = "ja_keyboard",
|
|
pl = "pl_keyboard",
|
|
pt_BR = "pt_keyboard",
|
|
}
|
|
|
|
function VirtualKeyboard:init()
|
|
local lang = G_reader_settings:readSetting("language")
|
|
local keyboard_layout = lang_to_keyboard_layout[lang] or "std"
|
|
local keyboard = require("ui/data/keyboardlayouts/" .. keyboard_layout)
|
|
self.KEYS = keyboard.keys
|
|
self.shiftmode_keys = keyboard.shiftmode_keys
|
|
self.symbolmode_keys = keyboard.symbolmode_keys
|
|
self.utf8mode_keys = keyboard.utf8mode_keys
|
|
self.umlautmode_keys = keyboard.umlautmode_keys
|
|
self.height = Screen:scaleBySize(64 * #self.KEYS)
|
|
self:initLayout(self.layout)
|
|
end
|
|
|
|
function VirtualKeyboard:_refresh()
|
|
-- TODO: Ideally, ui onShow & partial onClose
|
|
UIManager:setDirty(self, function()
|
|
return "partial", self[1][1].dimen
|
|
end)
|
|
end
|
|
|
|
function VirtualKeyboard:onShow()
|
|
self:_refresh()
|
|
return true
|
|
end
|
|
|
|
function VirtualKeyboard:onCloseWidget()
|
|
self:_refresh()
|
|
return true
|
|
end
|
|
|
|
function VirtualKeyboard:initLayout(layout)
|
|
local function VKLayout(b1, b2, b3, b4)
|
|
local function boolnum(bool)
|
|
return bool and 1 or 0
|
|
end
|
|
return 2 - boolnum(b1) + 2 * boolnum(b2) + 4 * boolnum(b3) + 8 * boolnum(b4)
|
|
end
|
|
|
|
if layout then
|
|
-- to be sure layout is selected properly
|
|
layout = math.max(layout, self.min_layout)
|
|
layout = math.min(layout, self.max_layout)
|
|
self.layout = layout
|
|
-- fill the layout modes
|
|
self.shiftmode = (layout == 1 or layout == 3 or layout == 5 or layout == 7 or layout == 9 or layout == 11)
|
|
self.symbolmode = (layout == 3 or layout == 4 or layout == 7 or layout == 8 or layout == 11 or layout == 12)
|
|
self.utf8mode = (layout == 5 or layout == 6 or layout == 7 or layout == 8)
|
|
self.umlautmode = (layout == 9 or layout == 10 or layout == 11 or layout == 12)
|
|
else -- or, without input parameter, restore layout from current layout modes
|
|
self.layout = VKLayout(self.shiftmode, self.symbolmode, self.utf8mode, self.umlautmode)
|
|
end
|
|
self:addKeys()
|
|
end
|
|
|
|
function VirtualKeyboard:addKeys()
|
|
local base_key_width = math.floor((self.width - (#self.KEYS[1] + 1)*self.key_padding - 2*self.padding)/#self.KEYS[1])
|
|
local base_key_height = math.floor((self.height - (#self.KEYS + 1)*self.key_padding - 2*self.padding)/#self.KEYS)
|
|
local h_key_padding = HorizontalSpan:new{width = self.key_padding}
|
|
local v_key_padding = VerticalSpan:new{width = self.key_padding}
|
|
local vertical_group = VerticalGroup:new{}
|
|
for i = 1, #self.KEYS do
|
|
local horizontal_group = HorizontalGroup:new{}
|
|
for j = 1, #self.KEYS[i] do
|
|
local width_factor = self.KEYS[i][j].width or 1.0
|
|
local key_width = math.floor((base_key_width + self.key_padding) * width_factor)
|
|
- self.key_padding
|
|
local key_height = base_key_height
|
|
local label = self.KEYS[i][j].label or self.KEYS[i][j][self.layout]
|
|
local key = VirtualKey:new{
|
|
key = self.KEYS[i][j][self.layout],
|
|
icon = self.KEYS[i][j].icon,
|
|
label = label,
|
|
keyboard = self,
|
|
width = key_width,
|
|
height = key_height,
|
|
}
|
|
table.insert(horizontal_group, key)
|
|
if j ~= #self.KEYS[i] then
|
|
table.insert(horizontal_group, h_key_padding)
|
|
end
|
|
end
|
|
table.insert(vertical_group, horizontal_group)
|
|
if i ~= #self.KEYS then
|
|
table.insert(vertical_group, v_key_padding)
|
|
end
|
|
end
|
|
|
|
local keyboard_frame = FrameContainer:new{
|
|
margin = 0,
|
|
bordersize = self.bordersize,
|
|
background = Blitbuffer.COLOR_WHITE,
|
|
radius = 0,
|
|
padding = self.padding,
|
|
CenterContainer:new{
|
|
dimen = Geom:new{
|
|
w = self.width - 2*self.bordersize -2*self.padding,
|
|
h = self.height - 2*self.bordersize -2*self.padding,
|
|
},
|
|
vertical_group,
|
|
}
|
|
}
|
|
self[1] = BottomContainer:new{
|
|
dimen = Screen:getSize(),
|
|
keyboard_frame,
|
|
}
|
|
self.dimen = keyboard_frame:getSize()
|
|
end
|
|
|
|
function VirtualKeyboard:setLayout(key)
|
|
if key == "Shift" then
|
|
self.shiftmode = not self.shiftmode
|
|
elseif key == "Sym" or key == "ABC" then
|
|
self.symbolmode = not self.symbolmode
|
|
elseif key == "Äéß" then
|
|
self.umlautmode = not self.umlautmode
|
|
if self.umlautmode then self.utf8mode = false end
|
|
elseif key == "IM" then
|
|
self.utf8mode = not self.utf8mode
|
|
if self.utf8mode then self.umlautmode = false end
|
|
end
|
|
self:initLayout()
|
|
self:_refresh()
|
|
end
|
|
|
|
function VirtualKeyboard:addChar(key)
|
|
logger.dbg("add char", key)
|
|
self.inputbox:addChar(key)
|
|
end
|
|
|
|
function VirtualKeyboard:delChar()
|
|
logger.dbg("delete char")
|
|
self.inputbox:delChar()
|
|
end
|
|
|
|
function VirtualKeyboard:clear()
|
|
logger.dbg("clear input")
|
|
self.inputbox:clear()
|
|
end
|
|
|
|
return VirtualKeyboard
|