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")
|
2018-03-30 10:46:36 +00:00
|
|
|
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")
|
2019-04-09 19:29:36 +00:00
|
|
|
local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
2016-12-29 08:10:38 +00:00
|
|
|
local logger = require("logger")
|
2019-04-11 08:12:29 +00:00
|
|
|
local util = require("util")
|
2017-04-29 08:38:09 +00:00
|
|
|
local Screen = Device.screen
|
2013-07-30 15:07:33 +00:00
|
|
|
|
2019-04-09 19:29:36 +00:00
|
|
|
local VirtualKeyPopup
|
|
|
|
|
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-05-29 08:04:00 +00:00
|
|
|
|
2014-03-13 13:52:43 +00:00
|
|
|
keyboard = nil,
|
|
|
|
callback = nil,
|
2018-07-16 15:24:04 +00:00
|
|
|
-- This is to inhibit the key's own refresh (useful to avoid conflicts on Layout changing keys)
|
|
|
|
skiptap = nil,
|
|
|
|
skiphold = nil,
|
2014-05-29 08:04:00 +00:00
|
|
|
|
2014-03-13 13:52:43 +00:00
|
|
|
width = nil,
|
2016-01-31 22:56:05 +00:00
|
|
|
height = math.max(Screen:getWidth(), Screen:getHeight())*0.33,
|
2019-03-12 19:00:06 +00:00
|
|
|
bordersize = Size.border.thin,
|
|
|
|
focused_bordersize = Size.border.default * 5,
|
|
|
|
radius = 0,
|
2017-04-29 08:38:09 +00:00
|
|
|
face = Font:getFace("infont"),
|
2013-07-30 15:07:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function VirtualKey:init()
|
2017-06-03 09:14:36 +00:00
|
|
|
if self.keyboard.symbolmode_keys[self.label] ~= nil then
|
|
|
|
self.callback = function () self.keyboard:setLayout("Sym") end
|
2018-07-16 15:24:04 +00:00
|
|
|
self.skiptap = true
|
2017-06-03 09:14:36 +00:00
|
|
|
elseif self.keyboard.shiftmode_keys[self.label] ~= nil then
|
|
|
|
self.callback = function () self.keyboard:setLayout("Shift") end
|
2018-07-16 15:24:04 +00:00
|
|
|
self.skiptap = true
|
2017-06-03 09:14:36 +00:00
|
|
|
elseif self.keyboard.utf8mode_keys[self.label] ~= nil then
|
|
|
|
self.callback = function () self.keyboard:setLayout("IM") end
|
2018-07-16 15:24:04 +00:00
|
|
|
self.skiptap = true
|
2017-06-03 09:14:36 +00:00
|
|
|
elseif self.keyboard.umlautmode_keys[self.label] ~= nil then
|
|
|
|
self.callback = function () self.keyboard:setLayout("Äéß") end
|
2018-07-16 15:24:04 +00:00
|
|
|
self.skiptap = true
|
2014-03-13 13:52:43 +00:00
|
|
|
elseif self.label == "Backspace" then
|
|
|
|
self.callback = function () self.keyboard:delChar() end
|
2018-08-01 16:33:52 +00:00
|
|
|
self.hold_callback = function () self.keyboard:delToStartOfLine() end
|
2018-07-16 15:24:04 +00:00
|
|
|
--self.skiphold = true
|
2017-10-10 16:04:51 +00:00
|
|
|
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
|
2019-04-09 19:29:36 +00:00
|
|
|
self.hold_callback = function()
|
|
|
|
if not self.key_chars then return end
|
|
|
|
|
|
|
|
VirtualKeyPopup:new{
|
|
|
|
parent_key = self,
|
|
|
|
}
|
|
|
|
end
|
2019-04-09 08:40:39 +00:00
|
|
|
self.swipe_callback = function(ges)
|
|
|
|
self.keyboard:addChar(self.key_chars[ges.direction])
|
|
|
|
end
|
2014-03-13 13:52:43 +00:00
|
|
|
end
|
2014-05-29 08:04:00 +00:00
|
|
|
|
2015-04-27 00:49:27 +00:00
|
|
|
local label_widget
|
2014-03-13 13:52:43 +00:00
|
|
|
if self.icon then
|
2018-07-11 15:24:37 +00:00
|
|
|
-- Scale icon to fit other characters height
|
|
|
|
-- (use *1.5 as our icons have a bit of white padding)
|
|
|
|
local icon_height = math.ceil(self.face.size * 1.5)
|
2014-03-13 13:52:43 +00:00
|
|
|
label_widget = ImageWidget:new{
|
|
|
|
file = self.icon,
|
2018-07-11 15:24:37 +00:00
|
|
|
scale_factor = 0, -- keep icon aspect ratio
|
|
|
|
height = icon_height,
|
|
|
|
width = icon_height * 100, -- to fit height when ensuring a/r
|
2014-03-13 13:52:43 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
label_widget = TextWidget:new{
|
|
|
|
text = self.label,
|
|
|
|
face = self.face,
|
|
|
|
}
|
|
|
|
end
|
|
|
|
self[1] = FrameContainer:new{
|
|
|
|
margin = 0,
|
|
|
|
bordersize = self.bordersize,
|
2014-10-22 13:34:11 +00:00
|
|
|
background = Blitbuffer.COLOR_WHITE,
|
2019-03-12 19:00:06 +00:00
|
|
|
radius = 0,
|
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,
|
|
|
|
},
|
|
|
|
},
|
2014-08-20 06:45:38 +00:00
|
|
|
HoldSelect = {
|
|
|
|
GestureRange:new{
|
|
|
|
ges = "hold",
|
|
|
|
range = self.dimen,
|
|
|
|
},
|
|
|
|
},
|
2019-04-09 20:19:56 +00:00
|
|
|
HoldReleaseKey = {
|
|
|
|
GestureRange:new{
|
|
|
|
ges = "hold_release",
|
|
|
|
range = self.dimen,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
PanReleaseKey = {
|
|
|
|
GestureRange:new{
|
|
|
|
ges = "pan_release",
|
|
|
|
range = self.dimen,
|
|
|
|
},
|
|
|
|
},
|
2019-04-09 08:40:39 +00:00
|
|
|
SwipeKey = {
|
|
|
|
GestureRange:new{
|
|
|
|
ges = "swipe",
|
|
|
|
range = self.dimen,
|
|
|
|
},
|
|
|
|
},
|
2014-03-13 13:52:43 +00:00
|
|
|
}
|
|
|
|
end
|
2017-08-04 12:01:06 +00:00
|
|
|
self.flash_keyboard = G_reader_settings:readSetting("flash_keyboard") ~= false
|
2013-07-30 15:07:33 +00:00
|
|
|
end
|
|
|
|
|
2018-07-16 15:24:04 +00:00
|
|
|
function VirtualKey:update_keyboard(want_flash, want_fast)
|
|
|
|
-- NOTE: We mainly use "fast" when inverted & "ui" when not, with a cherry on top:
|
|
|
|
-- we flash the *full* keyboard instead when we release a hold.
|
|
|
|
if want_flash then
|
|
|
|
UIManager:setDirty(self.keyboard, function()
|
|
|
|
return "flashui", self.keyboard[1][1].dimen
|
|
|
|
end)
|
|
|
|
else
|
|
|
|
local refresh_type = "ui"
|
|
|
|
if want_fast then
|
|
|
|
refresh_type = "fast"
|
|
|
|
end
|
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
2019-02-07 00:14:37 +00:00
|
|
|
-- Only repaint the key itself, not the full board...
|
|
|
|
UIManager:widgetRepaint(self[1], self[1].dimen.x, self[1].dimen.y)
|
|
|
|
UIManager:setDirty(nil, function()
|
2018-07-16 15:24:04 +00:00
|
|
|
logger.dbg("update key region", self[1].dimen)
|
|
|
|
return refresh_type, self[1].dimen
|
|
|
|
end)
|
|
|
|
end
|
2014-11-03 03:25:16 +00:00
|
|
|
end
|
|
|
|
|
2018-03-30 10:46:36 +00:00
|
|
|
function VirtualKey:onFocus()
|
2019-03-12 19:00:06 +00:00
|
|
|
self[1].inner_bordersize = self.focused_bordersize
|
2018-03-30 10:46:36 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function VirtualKey:onUnfocus()
|
2019-03-12 19:00:06 +00:00
|
|
|
self[1].inner_bordersize = 0
|
2018-03-30 10:46:36 +00:00
|
|
|
end
|
|
|
|
|
2019-04-10 15:05:02 +00:00
|
|
|
function VirtualKey:onTapSelect(skip_flash)
|
2019-09-29 13:42:05 +00:00
|
|
|
Device:performHapticFeedback("KEYBOARD_TAP")
|
2019-05-08 08:13:44 +00:00
|
|
|
-- just in case it's not flipped to false on hold release where it's supposed to
|
|
|
|
self.keyboard.ignore_first_hold_release = false
|
2019-04-10 15:05:02 +00:00
|
|
|
if self.flash_keyboard and not skip_flash and not self.skiptap then
|
2019-03-12 19:00:06 +00:00
|
|
|
self[1].inner_bordersize = self.focused_bordersize
|
2018-07-16 15:24:04 +00:00
|
|
|
self:update_keyboard(false, true)
|
2017-08-04 12:01:06 +00:00
|
|
|
if self.callback then
|
|
|
|
self.callback()
|
|
|
|
end
|
2018-06-02 16:10:55 +00:00
|
|
|
UIManager:tickAfterNext(function() self:invert(false) end)
|
2017-08-04 12:01:06 +00:00
|
|
|
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
|
|
|
|
|
2014-08-20 06:45:38 +00:00
|
|
|
function VirtualKey:onHoldSelect()
|
2019-09-29 13:42:05 +00:00
|
|
|
Device:performHapticFeedback("LONG_PRESS")
|
2018-07-16 15:24:04 +00:00
|
|
|
if self.flash_keyboard and not self.skiphold then
|
2019-03-12 19:00:06 +00:00
|
|
|
self[1].inner_bordersize = self.focused_bordersize
|
2018-07-16 15:24:04 +00:00
|
|
|
self:update_keyboard(false, true)
|
2019-05-01 00:09:01 +00:00
|
|
|
-- Don't refresh the key region if we're going to show a popup on top of it ;).
|
2017-08-04 12:01:06 +00:00
|
|
|
if self.hold_callback then
|
2019-05-01 00:09:01 +00:00
|
|
|
self[1].inner_bordersize = 0
|
2017-08-04 12:01:06 +00:00
|
|
|
self.hold_callback()
|
2019-05-01 00:09:01 +00:00
|
|
|
else
|
|
|
|
UIManager:tickAfterNext(function() self:invert(false, true) end)
|
2017-08-04 12:01:06 +00:00
|
|
|
end
|
|
|
|
else
|
|
|
|
if self.hold_callback then
|
|
|
|
self.hold_callback()
|
|
|
|
end
|
2014-08-20 06:45:38 +00:00
|
|
|
end
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
2019-04-09 08:40:39 +00:00
|
|
|
function VirtualKey:onSwipeKey(arg, ges)
|
2019-09-29 13:42:05 +00:00
|
|
|
Device:performHapticFeedback("KEYBOARD_TAP")
|
2019-04-09 08:40:39 +00:00
|
|
|
if self.flash_keyboard and not self.skipswipe then
|
|
|
|
self[1].inner_bordersize = self.focused_bordersize
|
|
|
|
self:update_keyboard(false, true)
|
|
|
|
if self.swipe_callback then
|
|
|
|
self.swipe_callback(ges)
|
|
|
|
end
|
2019-05-01 00:09:01 +00:00
|
|
|
UIManager:tickAfterNext(function() self:invert(false, false) end)
|
2019-04-09 08:40:39 +00:00
|
|
|
else
|
|
|
|
if self.swipe_callback then
|
|
|
|
self.swipe_callback(ges)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
2019-05-08 08:13:44 +00:00
|
|
|
function VirtualKey:onHoldReleaseKey()
|
2019-09-29 13:42:05 +00:00
|
|
|
Device:performHapticFeedback("LONG_PRESS")
|
2019-05-08 08:13:44 +00:00
|
|
|
if self.keyboard.ignore_first_hold_release then
|
|
|
|
self.keyboard.ignore_first_hold_release = false
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
self:onTapSelect()
|
|
|
|
end
|
|
|
|
|
|
|
|
function VirtualKey:onPanReleaseKey()
|
2019-09-29 13:42:05 +00:00
|
|
|
Device:performHapticFeedback("LONG_PRESS")
|
2019-05-08 08:13:44 +00:00
|
|
|
if self.keyboard.ignore_first_hold_release then
|
|
|
|
self.keyboard.ignore_first_hold_release = false
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
self:onTapSelect()
|
|
|
|
end
|
2019-04-09 20:19:56 +00:00
|
|
|
|
2018-07-16 15:24:04 +00:00
|
|
|
function VirtualKey:invert(invert, hold)
|
2019-03-12 19:00:06 +00:00
|
|
|
if invert then
|
|
|
|
self[1].inner_bordersize = self.focused_bordersize
|
|
|
|
else
|
|
|
|
self[1].inner_bordersize = 0
|
|
|
|
end
|
2018-07-16 15:24:04 +00:00
|
|
|
self:update_keyboard(hold, false)
|
2013-07-30 15:07:33 +00:00
|
|
|
end
|
|
|
|
|
2019-04-09 19:29:36 +00:00
|
|
|
VirtualKeyPopup = FocusManager:new{
|
|
|
|
modal = true,
|
|
|
|
disable_double_tap = true,
|
|
|
|
inputbox = nil,
|
|
|
|
layout = {},
|
|
|
|
}
|
|
|
|
|
|
|
|
function VirtualKeyPopup:onTapClose(arg, ges)
|
|
|
|
if ges.pos:notIntersectWith(self[1][1].dimen) then
|
|
|
|
UIManager:close(self)
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
function VirtualKeyPopup:onClose()
|
|
|
|
UIManager:close(self)
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
2019-04-11 12:00:59 +00:00
|
|
|
function VirtualKeyPopup:onCloseWidget()
|
|
|
|
UIManager:setDirty(nil, function()
|
2019-05-01 00:09:01 +00:00
|
|
|
return "ui", self[1][1].dimen
|
2019-04-11 12:00:59 +00:00
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
2019-04-09 19:29:36 +00:00
|
|
|
function VirtualKeyPopup:onPressKey()
|
|
|
|
self:getFocusItem():handleEvent(Event:new("TapSelect"))
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
|
|
function VirtualKeyPopup:init()
|
|
|
|
local parent_key = self.parent_key
|
|
|
|
local key_chars = parent_key.key_chars
|
|
|
|
local key_char_orig = key_chars[1]
|
|
|
|
|
2019-04-11 08:12:29 +00:00
|
|
|
local rows = {
|
|
|
|
extra_key_chars = {
|
|
|
|
key_chars[2],
|
|
|
|
key_chars[3],
|
|
|
|
key_chars[4],
|
|
|
|
},
|
|
|
|
top_key_chars = {
|
|
|
|
key_chars.northwest,
|
|
|
|
key_chars.north,
|
|
|
|
key_chars.northeast,
|
|
|
|
},
|
|
|
|
middle_key_chars = {
|
|
|
|
key_chars.west,
|
|
|
|
key_char_orig,
|
|
|
|
key_chars.east,
|
|
|
|
},
|
|
|
|
bottom_key_chars = {
|
|
|
|
key_chars.southwest,
|
|
|
|
key_chars.south,
|
|
|
|
key_chars.southeast,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
if util.tableSize(rows.extra_key_chars) == 0 then rows.extra_key_chars = nil end
|
|
|
|
if util.tableSize(rows.top_key_chars) == 0 then rows.top_key_chars = nil end
|
|
|
|
-- we should always have a middle
|
|
|
|
if util.tableSize(rows.bottom_key_chars) == 0 then rows.bottom_key_chars = nil end
|
|
|
|
|
|
|
|
-- to store if a column exists
|
|
|
|
local columns = {}
|
|
|
|
local blank = {
|
|
|
|
HorizontalSpan:new{width = 0},
|
|
|
|
HorizontalSpan:new{width = parent_key.width},
|
|
|
|
HorizontalSpan:new{width = 0},
|
|
|
|
}
|
|
|
|
local h_key_padding = {
|
|
|
|
HorizontalSpan:new{width = 0},
|
|
|
|
HorizontalSpan:new{width = parent_key.keyboard.key_padding},
|
|
|
|
HorizontalSpan:new{width = 0},
|
|
|
|
}
|
2019-04-09 19:29:36 +00:00
|
|
|
local v_key_padding = VerticalSpan:new{width = parent_key.keyboard.key_padding}
|
|
|
|
|
|
|
|
local vertical_group = VerticalGroup:new{}
|
|
|
|
local horizontal_group_extra = HorizontalGroup:new{}
|
|
|
|
local horizontal_group_top = HorizontalGroup:new{}
|
|
|
|
local horizontal_group_middle = HorizontalGroup:new{}
|
|
|
|
local horizontal_group_bottom = HorizontalGroup:new{}
|
|
|
|
|
|
|
|
local function horizontalRow(chars, group)
|
|
|
|
local layout_horizontal = {}
|
2019-04-11 08:12:29 +00:00
|
|
|
|
2019-04-09 19:29:36 +00:00
|
|
|
for i = 1,3 do
|
|
|
|
local v = chars[i]
|
|
|
|
|
|
|
|
if v then
|
2019-04-11 08:12:29 +00:00
|
|
|
columns[i] = true
|
|
|
|
blank[i].width = blank[2].width
|
|
|
|
if i == 1 then
|
|
|
|
h_key_padding[i].width = h_key_padding[2].width
|
|
|
|
end
|
|
|
|
|
2019-04-09 19:29:36 +00:00
|
|
|
local virtual_key = VirtualKey:new{
|
|
|
|
key = v,
|
|
|
|
label = v,
|
|
|
|
keyboard = parent_key.keyboard,
|
|
|
|
key_chars = key_chars,
|
|
|
|
width = parent_key.width,
|
|
|
|
height = parent_key.height,
|
|
|
|
}
|
2019-04-10 15:05:02 +00:00
|
|
|
-- don't open another popup on hold
|
2019-04-09 20:19:56 +00:00
|
|
|
virtual_key.hold_callback = nil
|
2019-04-10 15:05:02 +00:00
|
|
|
-- close popup on hold release
|
|
|
|
virtual_key.onHoldReleaseKey = function()
|
|
|
|
virtual_key:onTapSelect(true)
|
|
|
|
UIManager:close(self)
|
|
|
|
end
|
|
|
|
virtual_key.onPanReleaseKey = virtual_key.onHoldReleaseKey
|
2019-04-09 19:29:36 +00:00
|
|
|
|
|
|
|
if v == key_char_orig then
|
|
|
|
virtual_key[1].background = Blitbuffer.COLOR_LIGHT_GRAY
|
2019-04-09 20:19:56 +00:00
|
|
|
|
|
|
|
-- restore ability to hold/pan release on central key after opening popup
|
|
|
|
virtual_key._keyOrigHoldPanHandler = function()
|
|
|
|
virtual_key.onHoldReleaseKey = virtual_key._onHoldReleaseKey
|
|
|
|
virtual_key.onPanReleaseKey = virtual_key._onPanReleaseKey
|
|
|
|
end
|
|
|
|
virtual_key._onHoldReleaseKey = virtual_key.onHoldReleaseKey
|
|
|
|
virtual_key.onHoldReleaseKey = virtual_key._keyOrigHoldPanHandler
|
|
|
|
virtual_key._onPanReleaseKey = virtual_key.onPanReleaseKey
|
|
|
|
virtual_key.onPanReleaseKey = virtual_key._keyOrigHoldPanHandler
|
2019-04-09 19:29:36 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
table.insert(group, virtual_key)
|
|
|
|
table.insert(layout_horizontal, virtual_key)
|
|
|
|
else
|
2019-04-11 08:12:29 +00:00
|
|
|
table.insert(group, blank[i])
|
2019-04-09 19:29:36 +00:00
|
|
|
end
|
2019-04-11 08:12:29 +00:00
|
|
|
table.insert(group, h_key_padding[i])
|
2019-04-09 19:29:36 +00:00
|
|
|
end
|
|
|
|
table.insert(vertical_group, group)
|
2019-04-10 15:05:02 +00:00
|
|
|
table.insert(self.layout, layout_horizontal)
|
2019-04-09 19:29:36 +00:00
|
|
|
end
|
2019-04-11 08:12:29 +00:00
|
|
|
if rows.extra_key_chars then
|
|
|
|
horizontalRow(rows.extra_key_chars, horizontal_group_extra)
|
|
|
|
table.insert(vertical_group, v_key_padding)
|
|
|
|
end
|
|
|
|
if rows.top_key_chars then
|
|
|
|
horizontalRow(rows.top_key_chars, horizontal_group_top)
|
|
|
|
table.insert(vertical_group, v_key_padding)
|
|
|
|
end
|
|
|
|
-- always middle row
|
|
|
|
horizontalRow(rows.middle_key_chars, horizontal_group_middle)
|
|
|
|
if rows.bottom_key_chars then
|
|
|
|
table.insert(vertical_group, v_key_padding)
|
|
|
|
horizontalRow(rows.bottom_key_chars, horizontal_group_bottom)
|
|
|
|
end
|
|
|
|
|
|
|
|
if not columns[3] then
|
|
|
|
h_key_padding[2].width = 0
|
|
|
|
end
|
|
|
|
|
|
|
|
local num_rows = util.tableSize(rows)
|
|
|
|
local num_columns = util.tableSize(columns)
|
2019-04-09 19:29:36 +00:00
|
|
|
|
|
|
|
local keyboard_frame = FrameContainer:new{
|
|
|
|
margin = 0,
|
|
|
|
bordersize = Size.border.default,
|
|
|
|
background = Blitbuffer.COLOR_WHITE,
|
|
|
|
radius = 0,
|
|
|
|
padding = parent_key.keyboard.padding,
|
|
|
|
CenterContainer:new{
|
|
|
|
dimen = Geom:new{
|
2019-04-11 08:12:29 +00:00
|
|
|
w = parent_key.width*num_columns + 2*Size.border.default + (num_columns)*parent_key.keyboard.key_padding,
|
|
|
|
h = parent_key.height*num_rows + 2*Size.border.default + num_rows*parent_key.keyboard.key_padding,
|
2019-04-09 19:29:36 +00:00
|
|
|
},
|
|
|
|
vertical_group,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
keyboard_frame.dimen = keyboard_frame:getSize()
|
|
|
|
|
2019-04-10 15:05:02 +00:00
|
|
|
self.ges_events = {
|
2019-04-09 19:29:36 +00:00
|
|
|
TapClose = {
|
|
|
|
GestureRange:new{
|
|
|
|
ges = "tap",
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
if Device:hasDPad() then
|
2019-04-10 15:05:02 +00:00
|
|
|
self.key_events.PressKey = { {"Press"}, doc = "select key" }
|
2019-04-09 19:29:36 +00:00
|
|
|
end
|
|
|
|
if Device:hasKeys() then
|
2019-04-10 15:05:02 +00:00
|
|
|
self.key_events.Close = { {"Back"}, doc = "close keyboard" }
|
2019-04-09 19:29:36 +00:00
|
|
|
end
|
|
|
|
|
2019-04-11 08:12:29 +00:00
|
|
|
local offset_x = 2*parent_key.keyboard.padding + 2*parent_key.keyboard.bordersize
|
|
|
|
if columns[1] then
|
|
|
|
offset_x = offset_x + parent_key.width + parent_key.keyboard.padding + 2*parent_key.keyboard.bordersize
|
|
|
|
end
|
|
|
|
|
|
|
|
local offset_y = parent_key.keyboard.padding + parent_key.keyboard.padding + 2*parent_key.keyboard.bordersize
|
|
|
|
if rows.extra_key_chars then
|
|
|
|
offset_y = offset_y + parent_key.height + parent_key.keyboard.padding + 2*parent_key.keyboard.bordersize
|
|
|
|
end
|
|
|
|
if rows.top_key_chars then
|
|
|
|
offset_y = offset_y + parent_key.height + parent_key.keyboard.padding + 2*parent_key.keyboard.bordersize
|
|
|
|
end
|
|
|
|
|
2019-04-09 19:29:36 +00:00
|
|
|
local position_container = WidgetContainer:new{
|
|
|
|
dimen = {
|
2019-04-11 08:12:29 +00:00
|
|
|
x = parent_key.dimen.x - offset_x,
|
|
|
|
y = parent_key.dimen.y - offset_y,
|
2019-04-09 19:29:36 +00:00
|
|
|
h = Screen:getSize().h,
|
|
|
|
w = Screen:getSize().w,
|
|
|
|
},
|
|
|
|
keyboard_frame,
|
|
|
|
}
|
|
|
|
if position_container.dimen.x < 0 then
|
|
|
|
position_container.dimen.x = 0
|
|
|
|
elseif position_container.dimen.x + keyboard_frame.dimen.w > Screen:getWidth() then
|
|
|
|
position_container.dimen.x = Screen:getWidth() - keyboard_frame.dimen.w
|
|
|
|
end
|
|
|
|
if position_container.dimen.y < 0 then
|
|
|
|
position_container.dimen.y = 0
|
|
|
|
elseif position_container.dimen.y + keyboard_frame.dimen.h > Screen:getHeight() then
|
|
|
|
position_container.dimen.y = Screen:getHeight() - keyboard_frame.dimen.h
|
|
|
|
end
|
|
|
|
|
2019-04-10 15:05:02 +00:00
|
|
|
self[1] = position_container
|
2019-04-09 19:29:36 +00:00
|
|
|
|
2019-04-10 15:05:02 +00:00
|
|
|
UIManager:show(self)
|
2019-04-09 19:29:36 +00:00
|
|
|
|
|
|
|
UIManager:setDirty(self, function()
|
|
|
|
return "ui", keyboard_frame.dimen
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
2018-03-30 10:46:36 +00:00
|
|
|
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
|
2017-06-03 09:14:36 +00:00
|
|
|
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,
|
2018-03-30 10:46:36 +00:00
|
|
|
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,
|
2018-03-30 10:46:36 +00:00
|
|
|
layout = {},
|
2014-05-29 08:04:00 +00:00
|
|
|
|
2016-04-12 06:33:37 +00:00
|
|
|
width = Screen:scaleBySize(600),
|
2017-06-03 09:14:36 +00:00
|
|
|
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
|
|
|
|
2019-09-06 15:01:37 +00:00
|
|
|
lang_to_keyboard_layout = {
|
|
|
|
el = "el_keyboard",
|
|
|
|
en = "en_keyboard",
|
|
|
|
es = "es_keyboard",
|
|
|
|
fr = "fr_keyboard",
|
2019-09-22 20:21:00 +00:00
|
|
|
he = "he_keyboard",
|
2019-09-06 15:01:37 +00:00
|
|
|
ja = "ja_keyboard",
|
|
|
|
pt_BR = "pt_keyboard",
|
|
|
|
ko_KR = "ko_KR_keyboard",
|
|
|
|
},
|
2016-11-06 10:01:28 +00:00
|
|
|
}
|
|
|
|
|
2013-07-30 15:07:33 +00:00
|
|
|
function VirtualKeyboard:init()
|
2019-09-06 15:01:37 +00:00
|
|
|
local lang = self:getKeyboardLayout()
|
|
|
|
local keyboard_layout = self.lang_to_keyboard_layout[lang] or self.lang_to_keyboard_layout["en"]
|
2017-06-03 09:14:36 +00:00
|
|
|
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)
|
2018-03-30 10:46:36 +00:00
|
|
|
self:initLayout(self.keyboard_layout)
|
A few graphics fixes after #4541 (#4554)
* Various FocusManager related tweaks to limit its usage to devices with a DPad, and prevent initial button highlights in Dialogs on devices where it makes no sense (i.e., those without a DPad. And even on DPad devices, I'm not even sure how we'd go about making one of those pop up anyway, because no Touch ;)!).
* One mysterious fix to text-only Buttons so that the flash_ui highlight always works, and always honors `FrameContainer`'s pill shape. (Before that, an unhighlight on a text button with a callback that didn't repaint anything [say, the find first/find last buttons in the Reader's search bar when you're already on the first/last match] would do a square black highlight, and a white pill-shaped unhighlight (leaving the black corners visible)).
The workaround makes *absolutely* no sense to me (as `self[1] -> self.frame`, AFAICT), but it works, and ensures all highlights/unhighlights are pill-shaped, so at least we're not doing maths for rounded corners for nothing ;).
2019-02-07 23:56:32 +00:00
|
|
|
if Device:hasDPad() then
|
2018-03-30 10:46:36 +00:00
|
|
|
self.key_events.PressKey = { {"Press"}, doc = "select key" }
|
A few graphics fixes after #4541 (#4554)
* Various FocusManager related tweaks to limit its usage to devices with a DPad, and prevent initial button highlights in Dialogs on devices where it makes no sense (i.e., those without a DPad. And even on DPad devices, I'm not even sure how we'd go about making one of those pop up anyway, because no Touch ;)!).
* One mysterious fix to text-only Buttons so that the flash_ui highlight always works, and always honors `FrameContainer`'s pill shape. (Before that, an unhighlight on a text button with a callback that didn't repaint anything [say, the find first/find last buttons in the Reader's search bar when you're already on the first/last match] would do a square black highlight, and a white pill-shaped unhighlight (leaving the black corners visible)).
The workaround makes *absolutely* no sense to me (as `self[1] -> self.frame`, AFAICT), but it works, and ensures all highlights/unhighlights are pill-shaped, so at least we're not doing maths for rounded corners for nothing ;).
2019-02-07 23:56:32 +00:00
|
|
|
end
|
|
|
|
if Device:hasKeys() then
|
2018-03-30 10:46:36 +00:00
|
|
|
self.key_events.Close = { {"Back"}, doc = "close keyboard" }
|
|
|
|
end
|
2019-06-03 09:03:28 +00:00
|
|
|
if keyboard.wrapInputBox then
|
|
|
|
keyboard.wrapInputBox(self.inputbox)
|
|
|
|
end
|
2018-03-30 10:46:36 +00:00
|
|
|
end
|
|
|
|
|
2019-09-06 15:01:37 +00:00
|
|
|
function VirtualKeyboard:getKeyboardLayout()
|
|
|
|
return G_reader_settings:readSetting("keyboard_layout") or G_reader_settings:readSetting("language")
|
|
|
|
end
|
|
|
|
|
2018-03-30 10:46:36 +00:00
|
|
|
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
|
|
|
|
|
2018-06-02 16:10:55 +00:00
|
|
|
function VirtualKeyboard:_refresh(want_flash)
|
2019-05-01 00:09:01 +00:00
|
|
|
local refresh_type = "ui"
|
2018-06-02 16:10:55 +00:00
|
|
|
if want_flash then
|
|
|
|
refresh_type = "flashui"
|
|
|
|
end
|
2014-12-01 14:39:41 +00:00
|
|
|
UIManager:setDirty(self, function()
|
2018-06-02 16:10:55 +00:00
|
|
|
return refresh_type, self[1][1].dimen
|
2014-12-01 14:39:41 +00:00
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
function VirtualKeyboard:onShow()
|
2018-06-02 16:10:55 +00:00
|
|
|
self:_refresh(true)
|
2014-12-01 14:39:41 +00:00
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
|
|
function VirtualKeyboard:onCloseWidget()
|
2018-06-02 16:10:55 +00:00
|
|
|
self:_refresh(false)
|
2014-12-01 14:39:41 +00:00
|
|
|
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-05-29 08:04:00 +00:00
|
|
|
|
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)
|
2018-03-30 10:46:36 +00:00
|
|
|
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
|
2018-03-30 10:46:36 +00:00
|
|
|
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()
|
2018-03-30 10:46:36 +00:00
|
|
|
self.layout = {}
|
2017-06-03 09:14:36 +00:00
|
|
|
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{}
|
2018-03-30 10:46:36 +00:00
|
|
|
local layout_horizontal = {}
|
2014-03-13 13:52:43 +00:00
|
|
|
for j = 1, #self.KEYS[i] do
|
2019-04-09 08:40:39 +00:00
|
|
|
local key
|
|
|
|
local key_chars = self.KEYS[i][j][self.keyboard_layout]
|
|
|
|
if type(key_chars) == "table" then
|
|
|
|
key = key_chars[1]
|
|
|
|
else
|
|
|
|
key = key_chars
|
|
|
|
key_chars = nil
|
|
|
|
end
|
2014-03-13 13:52:43 +00:00
|
|
|
local width_factor = self.KEYS[i][j].width or 1.0
|
2014-05-29 08:04:00 +00:00
|
|
|
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
|
2019-04-09 08:40:39 +00:00
|
|
|
local label = self.KEYS[i][j].label or key
|
|
|
|
local virtual_key = VirtualKey:new{
|
|
|
|
key = key,
|
|
|
|
key_chars = key_chars,
|
2014-03-13 13:52:43 +00:00
|
|
|
icon = self.KEYS[i][j].icon,
|
|
|
|
label = label,
|
|
|
|
keyboard = self,
|
|
|
|
width = key_width,
|
|
|
|
height = key_height,
|
|
|
|
}
|
2019-04-09 08:40:39 +00:00
|
|
|
if not key_chars then
|
|
|
|
virtual_key.swipe_callback = nil
|
|
|
|
end
|
|
|
|
table.insert(horizontal_group, virtual_key)
|
|
|
|
table.insert(layout_horizontal, virtual_key)
|
2014-05-29 08:04:00 +00:00
|
|
|
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)
|
2018-03-30 10:46:36 +00:00
|
|
|
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-05-29 08:04:00 +00:00
|
|
|
|
2014-03-13 13:52:43 +00:00
|
|
|
local keyboard_frame = FrameContainer:new{
|
|
|
|
margin = 0,
|
2019-03-12 19:00:06 +00:00
|
|
|
bordersize = Size.border.default,
|
2014-10-22 13:34:11 +00:00
|
|
|
background = Blitbuffer.COLOR_WHITE,
|
2014-03-13 13:52:43 +00:00
|
|
|
radius = 0,
|
|
|
|
padding = self.padding,
|
|
|
|
CenterContainer:new{
|
|
|
|
dimen = Geom:new{
|
2019-03-12 19:00:06 +00:00
|
|
|
w = self.width - 2*Size.border.default - 2*self.padding,
|
|
|
|
h = self.height - 2*Size.border.default - 2*self.padding,
|
2014-03-13 13:52:43 +00:00
|
|
|
},
|
|
|
|
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()
|
2018-06-02 16:10:55 +00:00
|
|
|
self:_refresh(true)
|
2013-07-30 15:07:33 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function VirtualKeyboard:addChar(key)
|
2016-12-29 08:10:38 +00:00
|
|
|
logger.dbg("add char", key)
|
2018-03-07 09:22:49 +00:00
|
|
|
self.inputbox:addChars(key)
|
2013-07-30 15:07:33 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function VirtualKeyboard:delChar()
|
2016-12-29 08:10:38 +00:00
|
|
|
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
|
|
|
|
2018-08-01 16:33:52 +00:00
|
|
|
function VirtualKeyboard:delToStartOfLine()
|
|
|
|
logger.dbg("delete to start of line")
|
|
|
|
self.inputbox:delToStartOfLine()
|
|
|
|
end
|
|
|
|
|
2017-10-10 16:04:51 +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
|
|
|
|
|
2014-08-20 06:45:38 +00:00
|
|
|
function VirtualKeyboard:clear()
|
2016-12-29 08:10:38 +00:00
|
|
|
logger.dbg("clear input")
|
2014-08-20 06:45:38 +00:00
|
|
|
self.inputbox:clear()
|
|
|
|
end
|
|
|
|
|
2013-10-18 20:38:07 +00:00
|
|
|
return VirtualKeyboard
|