2
0
mirror of https://github.com/koreader/koreader synced 2024-10-31 21:20:20 +00:00
koreader/frontend/ui/widget/virtualkeyboard.lua

369 lines
11 KiB
Lua
Raw Normal View History

2017-04-29 08:38:09 +00:00
local Blitbuffer = require("ffi/blitbuffer")
2013-10-18 20:38:07 +00:00
local BottomContainer = require("ui/widget/container/bottomcontainer")
2017-04-29 08:38:09 +00:00
local CenterContainer = require("ui/widget/container/centercontainer")
local Device = require("device")
local Event = require("ui/event")
local FocusManager = require("ui/widget/focusmanager")
2013-10-18 20:38:07 +00:00
local Font = require("ui/font")
2017-04-29 08:38:09 +00:00
local FrameContainer = require("ui/widget/container/framecontainer")
2013-10-18 20:38:07 +00:00
local Geom = require("ui/geometry")
local GestureRange = require("ui/gesturerange")
2017-04-29 08:38:09 +00:00
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")
2017-09-13 14:56:20 +00:00
local Size = require("ui/size")
2017-04-29 08:38:09 +00:00
local TextWidget = require("ui/widget/textwidget")
2013-10-18 20:38:07 +00:00
local UIManager = require("ui/uimanager")
2017-04-29 08:38:09 +00:00
local VerticalGroup = require("ui/widget/verticalgroup")
local VerticalSpan = require("ui/widget/verticalspan")
local logger = require("logger")
2017-04-29 08:38:09 +00:00
local Screen = Device.screen
2013-07-30 15:07:33 +00:00
2013-10-18 20:38:07 +00:00
local VirtualKey = InputContainer:new{
2014-03-13 13:52:43 +00:00
key = nil,
icon = nil,
label = nil,
2014-03-13 13:52:43 +00:00
keyboard = nil,
callback = nil,
2014-03-13 13:52:43 +00:00
width = nil,
height = math.max(Screen:getWidth(), Screen:getHeight())*0.33,
2017-09-13 14:56:20 +00:00
bordersize = Size.border.default,
2017-04-29 08:38:09 +00:00
face = Font:getFace("infont"),
2013-07-30 15:07:33 +00:00
}
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
2014-03-13 13:52:43 +00:00
elseif self.label == "Backspace" then
self.callback = function () self.keyboard:delChar() end
self.hold_callback = function () self.keyboard:clear() end
elseif self.label =="" then
self.callback = function() self.keyboard:leftChar() end
elseif self.label == "" then
self.callback = function() self.keyboard:rightChar() end
elseif self.label == "" then
self.callback = function() self.keyboard:upLine() end
elseif self.label == "" then
self.callback = function() self.keyboard:downLine() end
2014-03-13 13:52:43 +00:00
else
self.callback = function () self.keyboard:addChar(self.key) end
end
2015-04-27 00:49:27 +00:00
local label_widget
2014-03-13 13:52:43 +00:00
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,
2017-09-13 14:56:20 +00:00
radius = Size.radius.window,
2014-03-13 13:52:43 +00:00
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,
},
},
2014-03-13 13:52:43 +00:00
}
end
self.flash_keyboard = G_reader_settings:readSetting("flash_keyboard") ~= false
2013-07-30 15:07:33 +00:00
end
function VirtualKey:update_keyboard()
UIManager:setDirty(self.keyboard, function()
logger.dbg("update key region", self[1].dimen)
return "fast", self[1].dimen
end)
end
function VirtualKey:onFocus()
self[1].invert = true
end
function VirtualKey:onUnfocus()
self[1].invert = false
end
2013-07-30 15:07:33 +00:00
function VirtualKey:onTapSelect()
if self.flash_keyboard then
self[1].invert = true
self:update_keyboard()
if self.callback then
self.callback()
end
UIManager:scheduleIn(0.1, function() self:invert(false) end)
else
if self.callback then
self.callback()
end
2014-03-13 13:52:43 +00:00
end
return true
2013-07-30 15:07:33 +00:00
end
function VirtualKey:onHoldSelect()
if self.flash_keyboard then
self[1].invert = true
self:update_keyboard()
if self.hold_callback then
self.hold_callback()
end
UIManager:scheduleIn(0.1, function() self:invert(false) end)
else
if self.hold_callback then
self.hold_callback()
end
end
return true
end
2013-07-30 15:07:33 +00:00
function VirtualKey:invert(invert)
2014-03-13 13:52:43 +00:00
self[1].invert = invert
self:update_keyboard()
2013-07-30 15:07:33 +00:00
end
local VirtualKeyboard = FocusManager:new{
modal = true,
2014-03-13 13:52:43 +00:00
disable_double_tap = true,
inputbox = nil,
KEYS = {}, -- table to store layouts
shiftmode_keys = {},
symbolmode_keys = {},
utf8mode_keys = {},
umlautmode_keys = {},
2014-03-13 13:52:43 +00:00
min_layout = 2,
2014-08-11 08:37:38 +00:00
max_layout = 12,
keyboard_layout = 2,
2014-03-13 13:52:43 +00:00
shiftmode = false,
symbolmode = false,
utf8mode = false,
2014-08-09 11:59:05 +00:00
umlautmode = false,
layout = {},
width = Screen:scaleBySize(600),
height = nil,
2017-09-13 14:56:20 +00:00
bordersize = Size.border.default,
padding = Size.padding.small,
key_padding = Size.padding.default,
2013-07-30 15:07:33 +00:00
}
local lang_to_keyboard_layout = {
el = "el_keyboard",
fr = "fr_keyboard",
ja = "ja_keyboard",
pl = "pl_keyboard",
pt_BR = "pt_keyboard",
}
2013-07-30 15:07:33 +00:00
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.keyboard_layout)
if Device:hasKeys() then
self.key_events.PressKey = { {"Press"}, doc = "select key" }
self.key_events.Close = { {"Back"}, doc = "close keyboard" }
end
end
function VirtualKeyboard:onClose()
UIManager:close(self)
return true
end
function VirtualKeyboard:onPressKey()
self:getFocusItem():handleEvent(Event:new("TapSelect"))
return true
2013-07-30 15:07:33 +00:00
end
function VirtualKeyboard:_refresh()
-- TODO: Ideally, ui onShow & partial onClose
UIManager:setDirty(self, function()
return "ui", self[1][1].dimen
end)
end
function VirtualKeyboard:onShow()
self:_refresh()
return true
end
function VirtualKeyboard:onCloseWidget()
self:_refresh()
return true
end
2013-07-30 15:07:33 +00:00
function VirtualKeyboard:initLayout(layout)
2014-08-09 11:59:05 +00:00
local function VKLayout(b1, b2, b3, b4)
2014-03-13 13:52:43 +00:00
local function boolnum(bool)
return bool and 1 or 0
end
2014-08-09 11:59:05 +00:00
return 2 - boolnum(b1) + 2 * boolnum(b2) + 4 * boolnum(b3) + 8 * boolnum(b4)
2014-03-13 13:52:43 +00:00
end
2014-03-13 13:52:43 +00:00
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.keyboard_layout = layout
2014-03-13 13:52:43 +00:00
-- fill the layout modes
2014-08-09 11:59:05 +00:00
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)
2014-03-13 13:52:43 +00:00
else -- or, without input parameter, restore layout from current layout modes
self.keyboard_layout = VKLayout(self.shiftmode, self.symbolmode, self.utf8mode, self.umlautmode)
2014-03-13 13:52:43 +00:00
end
self:addKeys()
2013-07-30 15:07:33 +00:00
end
function VirtualKeyboard:addKeys()
self.layout = {}
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)
2014-03-13 13:52:43 +00:00
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{}
local layout_horizontal = {}
2014-03-13 13:52:43 +00:00
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)
2014-03-13 13:52:43 +00:00
- self.key_padding
local key_height = base_key_height
local label = self.KEYS[i][j].label or self.KEYS[i][j][self.keyboard_layout]
2014-03-13 13:52:43 +00:00
local key = VirtualKey:new{
key = self.KEYS[i][j][self.keyboard_layout],
2014-03-13 13:52:43 +00:00
icon = self.KEYS[i][j].icon,
label = label,
keyboard = self,
width = key_width,
height = key_height,
}
table.insert(horizontal_group, key)
table.insert(layout_horizontal, key)
if j ~= #self.KEYS[i] then
2014-03-13 13:52:43 +00:00
table.insert(horizontal_group, h_key_padding)
end
end
table.insert(vertical_group, horizontal_group)
table.insert(self.layout, layout_horizontal)
2014-03-13 13:52:43 +00:00
if i ~= #self.KEYS then
table.insert(vertical_group, v_key_padding)
end
end
2014-03-13 13:52:43 +00:00
local keyboard_frame = FrameContainer:new{
margin = 0,
bordersize = self.bordersize,
background = Blitbuffer.COLOR_WHITE,
2014-03-13 13:52:43 +00:00
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()
2013-07-30 15:07:33 +00:00
end
function VirtualKeyboard:setLayout(key)
2014-03-13 13:52:43 +00:00
if key == "Shift" then
self.shiftmode = not self.shiftmode
elseif key == "Sym" or key == "ABC" then
self.symbolmode = not self.symbolmode
2014-08-09 11:59:05 +00:00
elseif key == "Äéß" then
self.umlautmode = not self.umlautmode
if self.umlautmode then self.utf8mode = false end
2014-03-13 13:52:43 +00:00
elseif key == "IM" then
self.utf8mode = not self.utf8mode
2014-08-09 11:59:05 +00:00
if self.utf8mode then self.umlautmode = false end
2014-03-13 13:52:43 +00:00
end
self:initLayout()
self:_refresh()
2013-07-30 15:07:33 +00:00
end
function VirtualKeyboard:addChar(key)
logger.dbg("add char", key)
self.inputbox:addChars(key)
2013-07-30 15:07:33 +00:00
end
function VirtualKeyboard:delChar()
logger.dbg("delete char")
2014-03-13 13:52:43 +00:00
self.inputbox:delChar()
2013-07-30 15:07:33 +00:00
end
2013-10-18 20:38:07 +00:00
function VirtualKeyboard:leftChar()
self.inputbox:leftChar()
end
function VirtualKeyboard:rightChar()
self.inputbox:rightChar()
end
function VirtualKeyboard:upLine()
self.inputbox:upLine()
end
function VirtualKeyboard:downLine()
self.inputbox:downLine()
end
function VirtualKeyboard:clear()
logger.dbg("clear input")
self.inputbox:clear()
end
2013-10-18 20:38:07 +00:00
return VirtualKeyboard