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 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")
|
2019-11-18 16:16:06 +00:00
|
|
|
local KeyboardLayoutDialog = require("ui/widget/keyboardlayoutdialog")
|
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")
|
2022-05-05 19:00:22 +00:00
|
|
|
local time = require("ui/time")
|
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
|
|
|
|
2021-08-29 10:29:41 +00:00
|
|
|
local keyboard_state = {
|
|
|
|
force_current_layout = false, -- Set to true to get/set current layout (instead of default layout)
|
|
|
|
}
|
|
|
|
|
2021-11-23 20:17:07 +00:00
|
|
|
local DEFAULT_LABEL_SIZE = 22
|
|
|
|
|
2019-04-09 19:29:36 +00:00
|
|
|
local VirtualKeyPopup
|
|
|
|
|
Clarify our OOP semantics across the codebase (#9586)
Basically:
* Use `extend` for class definitions
* Use `new` for object instantiations
That includes some minor code cleanups along the way:
* Updated `Widget`'s docs to make the semantics clearer.
* Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283)
* Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass).
* Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events.
* Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier.
* Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references.
* ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak).
* Terminal: Make sure the shell is killed on plugin teardown.
* InputText: Fix Home/End/Del physical keys to behave sensibly.
* InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...).
* OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of.
* ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed!
* Kobo: Minor code cleanups.
2022-10-06 00:14:48 +00:00
|
|
|
local VirtualKey = InputContainer:extend{
|
2014-03-13 13:52:43 +00:00
|
|
|
key = nil,
|
|
|
|
icon = nil,
|
|
|
|
label = nil,
|
2019-11-25 22:34:31 +00:00
|
|
|
bold = nil,
|
2014-05-29 08:04:00 +00:00
|
|
|
|
2014-03-13 13:52:43 +00:00
|
|
|
keyboard = nil,
|
|
|
|
callback = nil,
|
2019-11-18 16:16:06 +00:00
|
|
|
-- This is to inhibit the key's own refresh (useful to avoid conflicts on Layer changing keys)
|
2018-07-16 15:24:04 +00:00
|
|
|
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,
|
2021-08-24 21:51:39 +00:00
|
|
|
bordersize = 0,
|
|
|
|
focused_bordersize = Size.border.default,
|
2019-03-12 19:00:06 +00:00
|
|
|
radius = 0,
|
2017-04-29 08:38:09 +00:00
|
|
|
face = Font:getFace("infont"),
|
2013-07-30 15:07:33 +00:00
|
|
|
}
|
|
|
|
|
2022-10-31 14:48:05 +00:00
|
|
|
-- For caps lock, it's necessary because after setLayout, the new shift key is no longer the same virtual key
|
|
|
|
-- thus rendering its preset .ignore_key_release property useless
|
|
|
|
local ignore_key_release
|
|
|
|
|
2013-07-30 15:07:33 +00:00
|
|
|
function VirtualKey:init()
|
2021-11-23 20:17:07 +00:00
|
|
|
local label_font_size = G_reader_settings:readSetting("keyboard_key_font_size", DEFAULT_LABEL_SIZE)
|
2021-08-24 21:51:39 +00:00
|
|
|
self.face = Font:getFace("infont", label_font_size)
|
|
|
|
self.bold = G_reader_settings:isTrue("keyboard_key_bold")
|
2017-06-03 09:14:36 +00:00
|
|
|
if self.keyboard.symbolmode_keys[self.label] ~= nil then
|
2019-11-18 16:16:06 +00:00
|
|
|
self.callback = function () self.keyboard:setLayer("Sym") end
|
2018-07-16 15:24:04 +00:00
|
|
|
self.skiptap = true
|
2022-10-31 14:48:05 +00:00
|
|
|
elseif self.keyboard.shiftmode_keys[self.label] ~= nil or self.keyboard.shiftmode_keys[self.key] ~= nil then
|
|
|
|
-- self.key needed because the shift key's label could be the capslock instead of the shift
|
|
|
|
local key = self.key or self.label
|
|
|
|
local releasable = key == ""
|
|
|
|
self.callback = function()
|
|
|
|
self.keyboard.release_shift = releasable
|
|
|
|
self.keyboard:setLayer("Shift")
|
|
|
|
end
|
|
|
|
self.hold_callback = function()
|
|
|
|
ignore_key_release = true
|
|
|
|
if releasable then self.keyboard.release_shift = false end
|
|
|
|
self.keyboard:setLayer("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
|
2021-09-01 20:55:59 +00:00
|
|
|
self.key_chars = self:genKeyboardLayoutKeyChars()
|
2019-11-18 16:16:06 +00:00
|
|
|
self.callback = function ()
|
2022-10-01 23:58:36 +00:00
|
|
|
self.keyboard:onSwitchingKeyboardLayout()
|
2019-11-18 16:16:06 +00:00
|
|
|
local current = G_reader_settings:readSetting("keyboard_layout")
|
2021-08-29 10:29:41 +00:00
|
|
|
local default = G_reader_settings:readSetting("keyboard_layout_default")
|
2021-11-23 20:17:07 +00:00
|
|
|
local keyboard_layouts = G_reader_settings:readSetting("keyboard_layouts", {})
|
2019-11-18 16:16:06 +00:00
|
|
|
local next_layout = nil
|
2021-09-01 20:55:59 +00:00
|
|
|
local layout_index = util.arrayContains(keyboard_layouts, current)
|
|
|
|
if layout_index then
|
|
|
|
if layout_index == #keyboard_layouts then
|
|
|
|
layout_index = 1
|
|
|
|
else
|
|
|
|
layout_index = layout_index + 1
|
2021-08-29 10:29:41 +00:00
|
|
|
end
|
2021-09-01 20:55:59 +00:00
|
|
|
else
|
|
|
|
if default and current ~= default then
|
|
|
|
next_layout = default
|
|
|
|
else
|
|
|
|
layout_index = 1
|
2019-11-18 16:16:06 +00:00
|
|
|
end
|
|
|
|
end
|
2021-09-01 20:55:59 +00:00
|
|
|
next_layout = next_layout or keyboard_layouts[layout_index] or "en"
|
|
|
|
self.keyboard:setKeyboardLayout(next_layout)
|
2019-11-18 16:16:06 +00:00
|
|
|
end
|
|
|
|
self.hold_callback = function()
|
2022-10-01 23:58:36 +00:00
|
|
|
self.keyboard:onSwitchingKeyboardLayout()
|
2021-08-29 10:29:41 +00:00
|
|
|
if util.tableSize(self.key_chars) > 5 then -- 2 or more layouts enabled
|
2019-11-18 16:16:06 +00:00
|
|
|
self.popup = VirtualKeyPopup:new{
|
|
|
|
parent_key = self,
|
|
|
|
}
|
|
|
|
else
|
|
|
|
self.keyboard_layout_dialog = KeyboardLayoutDialog:new{
|
|
|
|
parent = self,
|
2021-08-29 10:29:41 +00:00
|
|
|
keyboard_state = keyboard_state,
|
2019-11-18 16:16:06 +00:00
|
|
|
}
|
|
|
|
UIManager:show(self.keyboard_layout_dialog)
|
|
|
|
end
|
|
|
|
end
|
2021-08-29 15:04:24 +00:00
|
|
|
self.hold_cb_is_popup = true
|
2019-11-18 16:16:06 +00:00
|
|
|
self.swipe_callback = function(ges)
|
2022-10-01 23:58:36 +00:00
|
|
|
self.keyboard:onSwitchingKeyboardLayout()
|
2019-11-18 16:16:06 +00:00
|
|
|
local key_function = self.key_chars[ges.direction.."_func"]
|
|
|
|
if key_function then
|
|
|
|
key_function()
|
|
|
|
end
|
|
|
|
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
|
2019-11-18 16:16:06 +00:00
|
|
|
self.callback = function () self.keyboard:setLayer("Äéß") end
|
2018-07-16 15:24:04 +00:00
|
|
|
self.skiptap = true
|
2019-11-25 22:34:31 +00:00
|
|
|
elseif self.label == "" then
|
2014-03-13 13:52:43 +00:00
|
|
|
self.callback = function () self.keyboard:delChar() end
|
2019-11-06 20:26:17 +00:00
|
|
|
self.hold_callback = function ()
|
|
|
|
self.ignore_key_release = true -- don't have delChar called on release
|
|
|
|
self.keyboard:delToStartOfLine()
|
|
|
|
end
|
2018-07-16 15:24:04 +00:00
|
|
|
--self.skiphold = true
|
2021-05-31 20:19:24 +00:00
|
|
|
elseif self.label == "←" then
|
2017-10-10 16:04:51 +00:00
|
|
|
self.callback = function() self.keyboard:leftChar() end
|
2021-05-22 21:25:14 +00:00
|
|
|
self.hold_callback = function()
|
|
|
|
self.ignore_key_release = true
|
|
|
|
self.keyboard:goToStartOfLine()
|
|
|
|
end
|
2017-10-10 16:04:51 +00:00
|
|
|
elseif self.label == "→" then
|
|
|
|
self.callback = function() self.keyboard:rightChar() end
|
2021-05-22 21:25:14 +00:00
|
|
|
self.hold_callback = function()
|
|
|
|
self.ignore_key_release = true
|
|
|
|
self.keyboard:goToEndOfLine()
|
|
|
|
end
|
2017-10-10 16:04:51 +00:00
|
|
|
elseif self.label == "↑" then
|
|
|
|
self.callback = function() self.keyboard:upLine() end
|
Terminal emulator: full rewrite, real vt52 emulator (#8636)
New real terminal emulator, replacing the old plugin.
The emulator is basically a vt52 terminal (enriched with
some ANSI-sequences, as ash, vi and mksh don't behave well
on a vt52 term).
So far working: ash, mksh, bash, nano, vi, busybox, watch...
The input supports: tab-completion; cursor movement;
backspace; start of line, end of line (long press);
page up, page down (long press).
User scripts may be placed in the koterm.koplugin/scripts/
folder, aliases can be put in the file aliases and startup
command in the file profile.user in that folder.
2022-01-28 19:33:09 +00:00
|
|
|
self.hold_callback = function()
|
|
|
|
self.ignore_key_release = true
|
|
|
|
self.keyboard:scrollUp()
|
|
|
|
end
|
2017-10-10 16:04:51 +00:00
|
|
|
elseif self.label == "↓" then
|
|
|
|
self.callback = function() self.keyboard:downLine() end
|
Terminal emulator: full rewrite, real vt52 emulator (#8636)
New real terminal emulator, replacing the old plugin.
The emulator is basically a vt52 terminal (enriched with
some ANSI-sequences, as ash, vi and mksh don't behave well
on a vt52 term).
So far working: ash, mksh, bash, nano, vi, busybox, watch...
The input supports: tab-completion; cursor movement;
backspace; start of line, end of line (long press);
page up, page down (long press).
User scripts may be placed in the koterm.koplugin/scripts/
folder, aliases can be put in the file aliases and startup
command in the file profile.user in that folder.
2022-01-28 19:33:09 +00:00
|
|
|
self.hold_callback = function()
|
|
|
|
self.ignore_key_release = true
|
|
|
|
self.keyboard:scrollDown()
|
|
|
|
end
|
2014-03-13 13:52:43 +00:00
|
|
|
else
|
2022-10-31 14:48:05 +00:00
|
|
|
self.callback = function()
|
|
|
|
self.keyboard:addChar(self.key)
|
|
|
|
if self.close_after_callback_widget then
|
|
|
|
UIManager:close(self.close_after_callback_widget)
|
|
|
|
end
|
|
|
|
if self.keyboard.shiftmode and not self.keyboard.symbolmode and self.keyboard.release_shift then
|
|
|
|
self.keyboard:setLayer("Shift")
|
|
|
|
end
|
|
|
|
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
|
2021-08-29 15:04:24 +00:00
|
|
|
self.hold_cb_is_popup = true
|
2019-04-09 08:40:39 +00:00
|
|
|
self.swipe_callback = function(ges)
|
2021-08-24 21:51:39 +00:00
|
|
|
local key_string = self.key_chars[ges.direction] or self.key
|
2019-11-11 22:10:27 +00:00
|
|
|
local key_function = self.key_chars[ges.direction.."_func"]
|
|
|
|
|
|
|
|
if not key_function and key_string then
|
2020-06-08 19:54:26 +00:00
|
|
|
if type(key_string) == "table" and key_string.key then
|
|
|
|
key_string = key_string.key
|
|
|
|
end
|
2019-11-11 22:10:27 +00:00
|
|
|
self.keyboard:addChar(key_string)
|
|
|
|
elseif key_function then
|
|
|
|
key_function()
|
|
|
|
end
|
2019-04-09 08:40:39 +00:00
|
|
|
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,
|
2019-11-25 13:31:54 +00:00
|
|
|
width = self.width - 2*self.bordersize,
|
2014-03-13 13:52:43 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
label_widget = TextWidget:new{
|
|
|
|
text = self.label,
|
|
|
|
face = self.face,
|
2019-11-25 22:34:31 +00:00
|
|
|
bold = self.bold or false,
|
2014-03-13 13:52:43 +00:00
|
|
|
}
|
2021-08-24 21:51:39 +00:00
|
|
|
-- Make long labels fit by decreasing font size
|
|
|
|
local max_width = self.width - 2*self.bordersize - 2*Size.padding.small
|
|
|
|
while label_widget:getWidth() > max_width do
|
|
|
|
local new_size = label_widget.face.orig_size - 1
|
|
|
|
label_widget:free()
|
|
|
|
if new_size < 8 then break end -- don't go too small
|
|
|
|
label_widget = TextWidget:new{
|
|
|
|
text = self.label,
|
|
|
|
face = Font:getFace(self.face.orig_font, new_size),
|
|
|
|
bold = self.bold or false,
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if self.alt_label then
|
|
|
|
local OverlapGroup = require("ui/widget/overlapgroup")
|
|
|
|
local alt_label_widget = TextWidget:new{
|
|
|
|
text = self.alt_label,
|
|
|
|
face = Font:getFace(self.face.orig_font, label_font_size - 4),
|
|
|
|
bold = self.bold or false,
|
|
|
|
fgcolor = Blitbuffer.COLOR_DARK_GRAY,
|
|
|
|
padding = 0, -- no additional padding to font line height
|
|
|
|
}
|
|
|
|
local key_inner_dimen = Geom:new{
|
|
|
|
w = self.width - 2*self.bordersize - 2*Size.padding.default,
|
|
|
|
h = self.height - 2*self.bordersize - 2*Size.padding.small, -- already some padding via line height
|
|
|
|
}
|
|
|
|
label_widget = OverlapGroup:new{
|
|
|
|
CenterContainer:new{
|
|
|
|
dimen = key_inner_dimen,
|
|
|
|
label_widget,
|
|
|
|
},
|
|
|
|
WidgetContainer:new{
|
|
|
|
overlap_align = "right",
|
|
|
|
dimen = Geom:new{
|
|
|
|
w = alt_label_widget:getSize().w,
|
|
|
|
h = key_inner_dimen.h,
|
|
|
|
},
|
|
|
|
alt_label_widget,
|
|
|
|
},
|
|
|
|
}
|
2014-03-13 13:52:43 +00:00
|
|
|
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,
|
2019-12-06 21:55:39 +00:00
|
|
|
allow_mirroring = false,
|
2014-03-13 13:52:43 +00:00
|
|
|
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()
|
2022-03-04 20:20:00 +00:00
|
|
|
self.ges_events = {
|
|
|
|
TapSelect = {
|
|
|
|
GestureRange:new{
|
|
|
|
ges = "tap",
|
|
|
|
range = self.dimen,
|
2014-03-13 13:52:43 +00:00
|
|
|
},
|
2022-03-04 20:20:00 +00:00
|
|
|
},
|
|
|
|
HoldSelect = {
|
|
|
|
GestureRange:new{
|
|
|
|
ges = "hold",
|
|
|
|
range = self.dimen,
|
2014-08-20 06:45:38 +00:00
|
|
|
},
|
2022-03-04 20:20:00 +00:00
|
|
|
},
|
|
|
|
HoldReleaseKey = {
|
|
|
|
GestureRange:new{
|
|
|
|
ges = "hold_release",
|
|
|
|
range = self.dimen,
|
2019-04-09 20:19:56 +00:00
|
|
|
},
|
2022-03-04 20:20:00 +00:00
|
|
|
},
|
|
|
|
PanReleaseKey = {
|
|
|
|
GestureRange:new{
|
|
|
|
ges = "pan_release",
|
|
|
|
range = self.dimen,
|
2019-04-09 20:19:56 +00:00
|
|
|
},
|
2022-03-04 20:20:00 +00:00
|
|
|
},
|
|
|
|
SwipeKey = {
|
|
|
|
GestureRange:new{
|
|
|
|
ges = "swipe",
|
|
|
|
range = self.dimen,
|
2019-04-09 08:40:39 +00:00
|
|
|
},
|
2022-03-04 20:20:00 +00:00
|
|
|
},
|
|
|
|
}
|
2022-10-31 14:48:05 +00:00
|
|
|
if ((self.keyboard.shiftmode_keys[self.label] ~= nil or self.keyboard.shiftmode_keys[self.key]) and self.keyboard.shiftmode) or
|
2021-09-28 12:08:40 +00:00
|
|
|
(self.keyboard.umlautmode_keys[self.label] ~= nil and self.keyboard.umlautmode) or
|
|
|
|
(self.keyboard.symbolmode_keys[self.label] ~= nil and self.keyboard.symbolmode) then
|
2019-11-18 16:16:06 +00:00
|
|
|
self[1].background = Blitbuffer.COLOR_LIGHT_GRAY
|
|
|
|
end
|
2021-03-06 21:44:18 +00:00
|
|
|
self.flash_keyboard = G_reader_settings:nilOrTrue("flash_keyboard")
|
2013-07-30 15:07:33 +00:00
|
|
|
end
|
|
|
|
|
2021-09-01 20:55:59 +00:00
|
|
|
function VirtualKey:genKeyboardLayoutKeyChars()
|
2019-11-18 16:16:06 +00:00
|
|
|
local positions = {
|
|
|
|
"northeast",
|
|
|
|
"north",
|
|
|
|
"northwest",
|
|
|
|
"west",
|
|
|
|
}
|
2021-11-23 20:17:07 +00:00
|
|
|
local keyboard_layouts = G_reader_settings:readSetting("keyboard_layouts", {})
|
2019-11-18 16:16:06 +00:00
|
|
|
local key_chars = {
|
|
|
|
{ label = "🌐",
|
|
|
|
},
|
2021-08-24 21:51:39 +00:00
|
|
|
east = { label = "⋮", },
|
2019-11-18 16:16:06 +00:00
|
|
|
east_func = function ()
|
2021-08-24 21:51:39 +00:00
|
|
|
UIManager:close(self.popup)
|
2019-11-18 16:16:06 +00:00
|
|
|
self.keyboard_layout_dialog = KeyboardLayoutDialog:new{
|
|
|
|
parent = self,
|
2021-08-29 10:29:41 +00:00
|
|
|
keyboard_state = keyboard_state,
|
2019-11-18 16:16:06 +00:00
|
|
|
}
|
|
|
|
UIManager:show(self.keyboard_layout_dialog)
|
|
|
|
end,
|
|
|
|
}
|
2021-09-01 20:55:59 +00:00
|
|
|
for i = 1, #keyboard_layouts do
|
|
|
|
key_chars[positions[i]] = string.sub(keyboard_layouts[i], 1, 2)
|
|
|
|
key_chars[positions[i] .. "_func"] = function()
|
|
|
|
UIManager:close(self.popup)
|
|
|
|
self.keyboard:setKeyboardLayout(keyboard_layouts[i])
|
2019-11-18 16:16:06 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
return key_chars
|
|
|
|
end
|
|
|
|
|
2021-08-29 15:04:24 +00:00
|
|
|
-- NOTE: We currently don't ever set want_flash to true (c.f., our invert method).
|
Assorted bag'o tweaks & fixes (#9569)
* UIManager: Support more specialized update modes for corner-cases:
* A2, which we'll use for the VirtualKeyboards keys (they'd... inadvertently switched to UI with the highlight refactor).
* NO_MERGE variants of ui & partial (for sunxi). Use `[ui]` in ReaderHighlight's popup, because of a Sage kernel bug that could otherwise make it translucent, sometimes completely so (*sigh*).
* UIManager: Assorted code cleanups & simplifications.
* Logger & dbg: Unify logging style, and code cleanups.
* SDL: Unbreak suspend/resume outside of the emulator (fix #9567).
* NetworkMgr: Cache the network status, and allow it to be queried. (Used by AutoSuspend to avoid repeatedly poking the system when computing the standby schedule delay).
* OneTimeMigration: Don't forget about `NETWORK_PROXY` & `STARDICT_DATA_DIR` when migrating `defaults.persistent.lua` (fix #9573)
* WakeupMgr: Workaround an apparent limitation of the RTC found on i.MX5 Kobo devices, where setting a wakealarm further than UINT16_MAX seconds in the future would apparently overflow and wraparound... (fix #8039, many thanks to @yfede for the extensive deep-dive and for actually accurately pinpointing the issue!).
* Kobo: Handle standby transitions at full CPU clock speeds, in order to limit the latency hit.
* UIManager: Properly quit on reboot & exit. This ensures our exit code is preserved, as we exit on our own terms (instead of being killed by the init system). This is important on platforms where exit codes are semantically meaningful (e.g., Kobo).
* UIManager: Speaking of reboot & exit, make sure the Screensaver shows in all circumstances (e.g., autoshutdown, re: #9542)), and that there aren't any extraneous refreshes triggered. (Additionally, fix a minor regression since #9448 about tracking this very transient state on Kobo & Cervantes).
* Kindle: ID the upcoming Scribe.
* Bump base (https://github.com/koreader/koreader-base/pull/1524)
2022-10-02 01:01:49 +00:00
|
|
|
function VirtualKey:update_keyboard(want_flash, want_a2)
|
|
|
|
-- NOTE: We use "a2" for the highlights.
|
|
|
|
-- We flash the *full* keyboard when we release a hold.
|
2018-07-16 15:24:04 +00:00
|
|
|
if want_flash then
|
|
|
|
UIManager:setDirty(self.keyboard, function()
|
2023-02-07 00:01:05 +00:00
|
|
|
return "flashui", self.keyboard[1][1].dimen -- i.e., keyboard_frame
|
2018-07-16 15:24:04 +00:00
|
|
|
end)
|
|
|
|
else
|
|
|
|
local refresh_type = "ui"
|
Assorted bag'o tweaks & fixes (#9569)
* UIManager: Support more specialized update modes for corner-cases:
* A2, which we'll use for the VirtualKeyboards keys (they'd... inadvertently switched to UI with the highlight refactor).
* NO_MERGE variants of ui & partial (for sunxi). Use `[ui]` in ReaderHighlight's popup, because of a Sage kernel bug that could otherwise make it translucent, sometimes completely so (*sigh*).
* UIManager: Assorted code cleanups & simplifications.
* Logger & dbg: Unify logging style, and code cleanups.
* SDL: Unbreak suspend/resume outside of the emulator (fix #9567).
* NetworkMgr: Cache the network status, and allow it to be queried. (Used by AutoSuspend to avoid repeatedly poking the system when computing the standby schedule delay).
* OneTimeMigration: Don't forget about `NETWORK_PROXY` & `STARDICT_DATA_DIR` when migrating `defaults.persistent.lua` (fix #9573)
* WakeupMgr: Workaround an apparent limitation of the RTC found on i.MX5 Kobo devices, where setting a wakealarm further than UINT16_MAX seconds in the future would apparently overflow and wraparound... (fix #8039, many thanks to @yfede for the extensive deep-dive and for actually accurately pinpointing the issue!).
* Kobo: Handle standby transitions at full CPU clock speeds, in order to limit the latency hit.
* UIManager: Properly quit on reboot & exit. This ensures our exit code is preserved, as we exit on our own terms (instead of being killed by the init system). This is important on platforms where exit codes are semantically meaningful (e.g., Kobo).
* UIManager: Speaking of reboot & exit, make sure the Screensaver shows in all circumstances (e.g., autoshutdown, re: #9542)), and that there aren't any extraneous refreshes triggered. (Additionally, fix a minor regression since #9448 about tracking this very transient state on Kobo & Cervantes).
* Kindle: ID the upcoming Scribe.
* Bump base (https://github.com/koreader/koreader-base/pull/1524)
2022-10-02 01:01:49 +00:00
|
|
|
if want_a2 then
|
|
|
|
refresh_type = "a2"
|
2018-07-16 15:24:04 +00:00
|
|
|
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)
|
Assorted bag'o tweaks & fixes (#9569)
* UIManager: Support more specialized update modes for corner-cases:
* A2, which we'll use for the VirtualKeyboards keys (they'd... inadvertently switched to UI with the highlight refactor).
* NO_MERGE variants of ui & partial (for sunxi). Use `[ui]` in ReaderHighlight's popup, because of a Sage kernel bug that could otherwise make it translucent, sometimes completely so (*sigh*).
* UIManager: Assorted code cleanups & simplifications.
* Logger & dbg: Unify logging style, and code cleanups.
* SDL: Unbreak suspend/resume outside of the emulator (fix #9567).
* NetworkMgr: Cache the network status, and allow it to be queried. (Used by AutoSuspend to avoid repeatedly poking the system when computing the standby schedule delay).
* OneTimeMigration: Don't forget about `NETWORK_PROXY` & `STARDICT_DATA_DIR` when migrating `defaults.persistent.lua` (fix #9573)
* WakeupMgr: Workaround an apparent limitation of the RTC found on i.MX5 Kobo devices, where setting a wakealarm further than UINT16_MAX seconds in the future would apparently overflow and wraparound... (fix #8039, many thanks to @yfede for the extensive deep-dive and for actually accurately pinpointing the issue!).
* Kobo: Handle standby transitions at full CPU clock speeds, in order to limit the latency hit.
* UIManager: Properly quit on reboot & exit. This ensures our exit code is preserved, as we exit on our own terms (instead of being killed by the init system). This is important on platforms where exit codes are semantically meaningful (e.g., Kobo).
* UIManager: Speaking of reboot & exit, make sure the Screensaver shows in all circumstances (e.g., autoshutdown, re: #9542)), and that there aren't any extraneous refreshes triggered. (Additionally, fix a minor regression since #9448 about tracking this very transient state on Kobo & Cervantes).
* Kindle: ID the upcoming Scribe.
* Bump base (https://github.com/koreader/koreader-base/pull/1524)
2022-10-02 01:01:49 +00:00
|
|
|
logger.dbg("update key", self.key)
|
|
|
|
UIManager:setDirty(nil, refresh_type, self[1].dimen)
|
|
|
|
|
|
|
|
-- NOTE: On MTK, we'd have to forcibly stall a bit for the highlights to actually show.
|
|
|
|
--[[
|
|
|
|
UIManager:forceRePaint()
|
|
|
|
UIManager:yieldToEPDC(3000)
|
|
|
|
--]]
|
2018-07-16 15:24:04 +00:00
|
|
|
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
|
2021-08-29 15:04:24 +00:00
|
|
|
self:invert(true)
|
|
|
|
UIManager:forceRePaint()
|
|
|
|
UIManager:yieldToEPDC()
|
|
|
|
|
|
|
|
self:invert(false)
|
2017-08-04 12:01:06 +00:00
|
|
|
if self.callback then
|
|
|
|
self.callback()
|
|
|
|
end
|
2021-08-29 15:04:24 +00:00
|
|
|
UIManager:forceRePaint()
|
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")
|
2021-08-29 15:04:24 +00:00
|
|
|
-- No visual feedback necessary if we're going to show a popup on top of the key ;).
|
|
|
|
if self.flash_keyboard and not self.skiphold and not self.hold_cb_is_popup then
|
|
|
|
self:invert(true)
|
|
|
|
UIManager:forceRePaint()
|
|
|
|
UIManager:yieldToEPDC()
|
|
|
|
|
|
|
|
-- NOTE: We do *NOT* set hold to true here,
|
|
|
|
-- because some mxcfb drivers apparently like to merge the flash that it would request
|
|
|
|
-- with the following key redraw, leading to an unsightly double flash :/.
|
|
|
|
self:invert(false)
|
2017-08-04 12:01:06 +00:00
|
|
|
if self.hold_callback then
|
|
|
|
self.hold_callback()
|
|
|
|
end
|
2021-08-29 15:04:24 +00:00
|
|
|
UIManager:forceRePaint()
|
2017-08-04 12:01:06 +00:00
|
|
|
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
|
2021-08-29 15:04:24 +00:00
|
|
|
self:invert(true)
|
|
|
|
UIManager:forceRePaint()
|
|
|
|
UIManager:yieldToEPDC()
|
|
|
|
|
|
|
|
self:invert(false)
|
2019-04-09 08:40:39 +00:00
|
|
|
if self.swipe_callback then
|
|
|
|
self.swipe_callback(ges)
|
|
|
|
end
|
2021-08-29 15:04:24 +00:00
|
|
|
UIManager:forceRePaint()
|
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()
|
2022-10-31 14:48:05 +00:00
|
|
|
if ignore_key_release then
|
|
|
|
ignore_key_release = nil
|
|
|
|
return true
|
|
|
|
end
|
2019-11-06 20:26:17 +00:00
|
|
|
if self.ignore_key_release then
|
|
|
|
self.ignore_key_release = nil
|
|
|
|
return true
|
|
|
|
end
|
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()
|
2019-11-06 20:26:17 +00:00
|
|
|
return true
|
2019-05-08 08:13:44 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function VirtualKey:onPanReleaseKey()
|
2019-11-06 20:26:17 +00:00
|
|
|
if self.ignore_key_release then
|
|
|
|
self.ignore_key_release = nil
|
|
|
|
return true
|
|
|
|
end
|
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()
|
2019-11-06 20:26:17 +00:00
|
|
|
return true
|
2019-05-08 08:13:44 +00:00
|
|
|
end
|
2019-04-09 20:19:56 +00:00
|
|
|
|
2021-08-29 15:04:24 +00:00
|
|
|
-- NOTE: We currently don't ever set hold to true (c.f., our onHoldSelect method)
|
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
|
Assorted bag'o tweaks & fixes (#9569)
* UIManager: Support more specialized update modes for corner-cases:
* A2, which we'll use for the VirtualKeyboards keys (they'd... inadvertently switched to UI with the highlight refactor).
* NO_MERGE variants of ui & partial (for sunxi). Use `[ui]` in ReaderHighlight's popup, because of a Sage kernel bug that could otherwise make it translucent, sometimes completely so (*sigh*).
* UIManager: Assorted code cleanups & simplifications.
* Logger & dbg: Unify logging style, and code cleanups.
* SDL: Unbreak suspend/resume outside of the emulator (fix #9567).
* NetworkMgr: Cache the network status, and allow it to be queried. (Used by AutoSuspend to avoid repeatedly poking the system when computing the standby schedule delay).
* OneTimeMigration: Don't forget about `NETWORK_PROXY` & `STARDICT_DATA_DIR` when migrating `defaults.persistent.lua` (fix #9573)
* WakeupMgr: Workaround an apparent limitation of the RTC found on i.MX5 Kobo devices, where setting a wakealarm further than UINT16_MAX seconds in the future would apparently overflow and wraparound... (fix #8039, many thanks to @yfede for the extensive deep-dive and for actually accurately pinpointing the issue!).
* Kobo: Handle standby transitions at full CPU clock speeds, in order to limit the latency hit.
* UIManager: Properly quit on reboot & exit. This ensures our exit code is preserved, as we exit on our own terms (instead of being killed by the init system). This is important on platforms where exit codes are semantically meaningful (e.g., Kobo).
* UIManager: Speaking of reboot & exit, make sure the Screensaver shows in all circumstances (e.g., autoshutdown, re: #9542)), and that there aren't any extraneous refreshes triggered. (Additionally, fix a minor regression since #9448 about tracking this very transient state on Kobo & Cervantes).
* Kindle: ID the upcoming Scribe.
* Bump base (https://github.com/koreader/koreader-base/pull/1524)
2022-10-02 01:01:49 +00:00
|
|
|
self:update_keyboard(hold, true)
|
2013-07-30 15:07:33 +00:00
|
|
|
end
|
|
|
|
|
Clarify our OOP semantics across the codebase (#9586)
Basically:
* Use `extend` for class definitions
* Use `new` for object instantiations
That includes some minor code cleanups along the way:
* Updated `Widget`'s docs to make the semantics clearer.
* Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283)
* Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass).
* Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events.
* Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier.
* Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references.
* ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak).
* Terminal: Make sure the shell is killed on plugin teardown.
* InputText: Fix Home/End/Del physical keys to behave sensibly.
* InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...).
* OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of.
* ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed!
* Kobo: Minor code cleanups.
2022-10-06 00:14:48 +00:00
|
|
|
VirtualKeyPopup = FocusManager:extend{
|
2019-04-09 19:29:36 +00:00
|
|
|
modal = true,
|
|
|
|
disable_double_tap = true,
|
|
|
|
inputbox = nil,
|
Clarify our OOP semantics across the codebase (#9586)
Basically:
* Use `extend` for class definitions
* Use `new` for object instantiations
That includes some minor code cleanups along the way:
* Updated `Widget`'s docs to make the semantics clearer.
* Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283)
* Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass).
* Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events.
* Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier.
* Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references.
* ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak).
* Terminal: Make sure the shell is killed on plugin teardown.
* InputText: Fix Home/End/Del physical keys to behave sensibly.
* InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...).
* OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of.
* ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed!
* Kobo: Minor code cleanups.
2022-10-06 00:14:48 +00:00
|
|
|
layout = nil, -- array
|
2019-04-09 19:29:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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()
|
2019-11-25 13:31:54 +00:00
|
|
|
self:free()
|
2019-04-11 12:00:59 +00:00
|
|
|
UIManager:setDirty(nil, function()
|
2023-02-07 00:01:05 +00:00
|
|
|
return "ui", self[1][1].dimen -- i.e., keyboard_frame
|
2019-04-11 12:00:59 +00:00
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
2019-04-09 19:29:36 +00:00
|
|
|
function VirtualKeyPopup:init()
|
|
|
|
local parent_key = self.parent_key
|
|
|
|
local key_chars = parent_key.key_chars
|
|
|
|
local key_char_orig = key_chars[1]
|
2019-11-11 22:10:27 +00:00
|
|
|
local key_char_orig_func = parent_key.callback
|
2019-04-09 19:29:36 +00:00
|
|
|
|
Clarify our OOP semantics across the codebase (#9586)
Basically:
* Use `extend` for class definitions
* Use `new` for object instantiations
That includes some minor code cleanups along the way:
* Updated `Widget`'s docs to make the semantics clearer.
* Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283)
* Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass).
* Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events.
* Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier.
* Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references.
* ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak).
* Terminal: Make sure the shell is killed on plugin teardown.
* InputText: Fix Home/End/Del physical keys to behave sensibly.
* InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...).
* OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of.
* ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed!
* Kobo: Minor code cleanups.
2022-10-06 00:14:48 +00:00
|
|
|
self.layout = {}
|
2019-04-11 08:12:29 +00:00
|
|
|
local rows = {
|
|
|
|
extra_key_chars = {
|
|
|
|
key_chars[2],
|
|
|
|
key_chars[3],
|
|
|
|
key_chars[4],
|
2019-11-11 22:10:27 +00:00
|
|
|
-- _func equivalent for unnamed extra keys
|
|
|
|
key_chars[5],
|
|
|
|
key_chars[6],
|
|
|
|
key_chars[7],
|
2019-04-11 08:12:29 +00:00
|
|
|
},
|
|
|
|
top_key_chars = {
|
|
|
|
key_chars.northwest,
|
|
|
|
key_chars.north,
|
|
|
|
key_chars.northeast,
|
2019-11-11 22:10:27 +00:00
|
|
|
key_chars.northwest_func,
|
|
|
|
key_chars.north_func,
|
|
|
|
key_chars.northeast_func,
|
2019-04-11 08:12:29 +00:00
|
|
|
},
|
|
|
|
middle_key_chars = {
|
|
|
|
key_chars.west,
|
|
|
|
key_char_orig,
|
|
|
|
key_chars.east,
|
2019-11-11 22:10:27 +00:00
|
|
|
key_chars.west_func,
|
|
|
|
key_char_orig_func,
|
|
|
|
key_chars.east_func,
|
2019-04-11 08:12:29 +00:00
|
|
|
},
|
|
|
|
bottom_key_chars = {
|
|
|
|
key_chars.southwest,
|
|
|
|
key_chars.south,
|
|
|
|
key_chars.southeast,
|
2019-11-11 22:10:27 +00:00
|
|
|
key_chars.southwest_func,
|
|
|
|
key_chars.south_func,
|
|
|
|
key_chars.southeast_func,
|
2019-04-11 08:12:29 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
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}
|
|
|
|
|
2019-12-06 21:55:39 +00:00
|
|
|
local vertical_group = VerticalGroup:new{ allow_mirroring = false }
|
|
|
|
local horizontal_group_extra = HorizontalGroup:new{ allow_mirroring = false }
|
|
|
|
local horizontal_group_top = HorizontalGroup:new{ allow_mirroring = false }
|
|
|
|
local horizontal_group_middle = HorizontalGroup:new{ allow_mirroring = false }
|
|
|
|
local horizontal_group_bottom = HorizontalGroup:new{ allow_mirroring = false }
|
2019-04-09 19:29:36 +00:00
|
|
|
|
|
|
|
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]
|
2019-11-11 22:10:27 +00:00
|
|
|
local v_func = chars[i+3]
|
2019-04-09 19:29:36 +00:00
|
|
|
|
|
|
|
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-11-18 16:16:06 +00:00
|
|
|
local key = type(v) == "table" and v.key or v
|
|
|
|
local label = type(v) == "table" and v.label or key
|
|
|
|
local icon = type(v) == "table" and v.icon
|
2019-11-25 22:34:31 +00:00
|
|
|
local bold = type(v) == "table" and v.bold
|
2019-04-09 19:29:36 +00:00
|
|
|
local virtual_key = VirtualKey:new{
|
2019-11-18 16:16:06 +00:00
|
|
|
key = key,
|
|
|
|
label = label,
|
|
|
|
icon = icon,
|
2019-11-25 22:34:31 +00:00
|
|
|
bold = bold,
|
2019-04-09 19:29:36 +00:00
|
|
|
keyboard = parent_key.keyboard,
|
|
|
|
key_chars = key_chars,
|
|
|
|
width = parent_key.width,
|
|
|
|
height = parent_key.height,
|
2022-10-31 14:48:05 +00:00
|
|
|
close_after_callback_widget = self,
|
2019-04-09 19:29:36 +00:00
|
|
|
}
|
2019-11-11 22:10:27 +00:00
|
|
|
-- Support any function as a callback.
|
|
|
|
if v_func then
|
|
|
|
virtual_key.callback = v_func
|
|
|
|
end
|
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()
|
2021-05-31 20:19:24 +00:00
|
|
|
-- NOTE: Check our *parent* key!
|
|
|
|
if parent_key.ignore_key_release then
|
|
|
|
parent_key.ignore_key_release = nil
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
Device:performHapticFeedback("LONG_PRESS")
|
|
|
|
if virtual_key.keyboard.ignore_first_hold_release then
|
|
|
|
virtual_key.keyboard.ignore_first_hold_release = false
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
2019-04-10 15:05:02 +00:00
|
|
|
virtual_key:onTapSelect(true)
|
|
|
|
UIManager:close(self)
|
2019-11-06 20:26:17 +00:00
|
|
|
return true
|
2019-04-10 15:05:02 +00:00
|
|
|
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,
|
2021-08-24 21:51:39 +00:00
|
|
|
background = G_reader_settings:nilOrTrue("keyboard_key_border") and Blitbuffer.COLOR_LIGHT_GRAY or Blitbuffer.COLOR_WHITE,
|
2019-04-09 19:29:36 +00:00
|
|
|
radius = 0,
|
|
|
|
padding = parent_key.keyboard.padding,
|
2019-12-06 21:55:39 +00:00
|
|
|
allow_mirroring = false,
|
2019-04-09 19:29:36 +00:00
|
|
|
CenterContainer:new{
|
|
|
|
dimen = Geom:new{
|
2021-08-24 21:51:39 +00:00
|
|
|
w = parent_key.width*num_columns + 2*Size.border.default + (num_columns+1)*parent_key.keyboard.key_padding,
|
|
|
|
h = parent_key.height*num_rows + 2*Size.border.default + (num_rows+1)*parent_key.keyboard.key_padding,
|
2019-04-09 19:29:36 +00:00
|
|
|
},
|
|
|
|
vertical_group,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
keyboard_frame.dimen = keyboard_frame:getSize()
|
|
|
|
|
2022-10-27 00:01:51 +00:00
|
|
|
self.ges_events.TapClose = {
|
|
|
|
GestureRange:new{
|
|
|
|
ges = "tap",
|
|
|
|
}
|
2019-04-09 19:29:36 +00:00
|
|
|
}
|
2022-05-05 19:00:22 +00:00
|
|
|
self.tap_interval_override = time.ms(G_reader_settings:readSetting("ges_tap_interval_on_keyboard_ms", 0))
|
2019-04-09 19:29:36 +00:00
|
|
|
|
|
|
|
if Device:hasKeys() then
|
2022-10-27 00:01:51 +00:00
|
|
|
self.key_events.Close = { { Device.input.group.Back } }
|
2019-04-09 19:29:36 +00:00
|
|
|
end
|
|
|
|
|
2021-08-24 21:51:39 +00:00
|
|
|
local offset_x = 2*keyboard_frame.bordersize + keyboard_frame.padding + parent_key.keyboard.key_padding
|
2019-04-11 08:12:29 +00:00
|
|
|
if columns[1] then
|
2021-08-24 21:51:39 +00:00
|
|
|
offset_x = offset_x + parent_key.width + parent_key.keyboard.key_padding
|
2019-04-11 08:12:29 +00:00
|
|
|
end
|
|
|
|
|
2021-08-24 21:51:39 +00:00
|
|
|
local offset_y = 2*keyboard_frame.bordersize + keyboard_frame.padding + parent_key.keyboard.key_padding
|
2019-04-11 08:12:29 +00:00
|
|
|
if rows.extra_key_chars then
|
2021-08-24 21:51:39 +00:00
|
|
|
offset_y = offset_y + parent_key.height + parent_key.keyboard.key_padding
|
2019-04-11 08:12:29 +00:00
|
|
|
end
|
|
|
|
if rows.top_key_chars then
|
2021-08-24 21:51:39 +00:00
|
|
|
offset_y = offset_y + parent_key.height + parent_key.keyboard.key_padding
|
2019-04-11 08:12:29 +00:00
|
|
|
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
|
2021-05-31 20:19:24 +00:00
|
|
|
-- We effectively move the popup, which means the key underneath our finger may no longer *exactly* be parent_key.
|
|
|
|
-- Make sure we won't close the popup right away, as that would risk being a *different* key, in order to make that less confusing.
|
|
|
|
parent_key.ignore_key_release = true
|
2019-04-09 19:29:36 +00:00
|
|
|
elseif position_container.dimen.x + keyboard_frame.dimen.w > Screen:getWidth() then
|
|
|
|
position_container.dimen.x = Screen:getWidth() - keyboard_frame.dimen.w
|
2021-05-31 20:19:24 +00:00
|
|
|
parent_key.ignore_key_release = true
|
2019-04-09 19:29:36 +00:00
|
|
|
end
|
|
|
|
if position_container.dimen.y < 0 then
|
|
|
|
position_container.dimen.y = 0
|
2021-05-31 20:19:24 +00:00
|
|
|
parent_key.ignore_key_release = true
|
2019-04-09 19:29:36 +00:00
|
|
|
elseif position_container.dimen.y + keyboard_frame.dimen.h > Screen:getHeight() then
|
|
|
|
position_container.dimen.y = Screen:getHeight() - keyboard_frame.dimen.h
|
2021-05-31 20:19:24 +00:00
|
|
|
parent_key.ignore_key_release = true
|
2019-04-09 19:29:36 +00:00
|
|
|
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)
|
2023-02-07 00:01:05 +00:00
|
|
|
-- Ensure the post-paint refresh will be able to grab updated coordinates from keyboard_frame by using a refresh function
|
2019-04-09 19:29:36 +00:00
|
|
|
UIManager:setDirty(self, function()
|
|
|
|
return "ui", keyboard_frame.dimen
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
Clarify our OOP semantics across the codebase (#9586)
Basically:
* Use `extend` for class definitions
* Use `new` for object instantiations
That includes some minor code cleanups along the way:
* Updated `Widget`'s docs to make the semantics clearer.
* Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283)
* Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass).
* Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events.
* Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier.
* Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references.
* ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak).
* Terminal: Make sure the shell is killed on plugin teardown.
* InputText: Fix Home/End/Del physical keys to behave sensibly.
* InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...).
* OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of.
* ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed!
* Kobo: Minor code cleanups.
2022-10-06 00:14:48 +00:00
|
|
|
local VirtualKeyboard = FocusManager:extend{
|
Assorted fixes after #7118 (#7161)
* I'd failed to notice that ButtonTable *also* instantiates seven billion Buttons on each update. Unfortunately, that one is way trickier to fix properly, so, work around its behavior in Button. (This fixes multiple issues with stuff using ButtonTable, which is basically anything with a persistent set of buttons. A good and easy test-case is the dictionary popup, e.g., the Highlight button changes text, and the next/prev dic buttons change state. All that, and more, was broken ;p).
* Handle corner-cases related to VirtualKeyboard (e.g., Terminal & Text Editor), which screwed with both TouchMenu & Button heuristics because it's weird.
* Flag a the dictionary switch buttons as vsync
(They trigger a partial repaint of the dictionary content).
* Flag the ReaderSearch buttons as vsync
They very obviously trigger a partial repaint, much like SkimTo ;p.
2021-01-18 15:51:25 +00:00
|
|
|
name = "VirtualKeyboard",
|
2023-09-01 20:51:41 +00:00
|
|
|
visible = nil,
|
|
|
|
lock_visibility = false,
|
2022-11-20 04:33:44 +00:00
|
|
|
covers_footer = true,
|
2018-03-30 10:46:36 +00:00
|
|
|
modal = true,
|
2014-03-13 13:52:43 +00:00
|
|
|
disable_double_tap = true,
|
|
|
|
inputbox = nil,
|
Clarify our OOP semantics across the codebase (#9586)
Basically:
* Use `extend` for class definitions
* Use `new` for object instantiations
That includes some minor code cleanups along the way:
* Updated `Widget`'s docs to make the semantics clearer.
* Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283)
* Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass).
* Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events.
* Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier.
* Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references.
* ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak).
* Terminal: Make sure the shell is killed on plugin teardown.
* InputText: Fix Home/End/Del physical keys to behave sensibly.
* InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...).
* OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of.
* ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed!
* Kobo: Minor code cleanups.
2022-10-06 00:14:48 +00:00
|
|
|
KEYS = nil, -- table to store layouts
|
|
|
|
shiftmode_keys = nil, -- table
|
|
|
|
symbolmode_keys = nil, -- table
|
|
|
|
utf8mode_keys = nil, -- table
|
|
|
|
umlautmode_keys = nil, -- table
|
2019-11-18 16:16:06 +00:00
|
|
|
keyboard_layer = 2,
|
2014-03-13 13:52:43 +00:00
|
|
|
shiftmode = false,
|
|
|
|
symbolmode = false,
|
2014-08-09 11:59:05 +00:00
|
|
|
umlautmode = false,
|
Clarify our OOP semantics across the codebase (#9586)
Basically:
* Use `extend` for class definitions
* Use `new` for object instantiations
That includes some minor code cleanups along the way:
* Updated `Widget`'s docs to make the semantics clearer.
* Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283)
* Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass).
* Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events.
* Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier.
* Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references.
* ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak).
* Terminal: Make sure the shell is killed on plugin teardown.
* InputText: Fix Home/End/Del physical keys to behave sensibly.
* InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...).
* OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of.
* ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed!
* Kobo: Minor code cleanups.
2022-10-06 00:14:48 +00:00
|
|
|
layout = nil, -- array
|
2014-05-29 08:04:00 +00:00
|
|
|
|
2017-06-03 09:14:36 +00:00
|
|
|
height = nil,
|
2021-11-23 20:17:07 +00:00
|
|
|
default_label_size = DEFAULT_LABEL_SIZE,
|
2017-09-13 14:56:20 +00:00
|
|
|
bordersize = Size.border.default,
|
2021-08-24 21:51:39 +00:00
|
|
|
padding = 0,
|
|
|
|
key_padding = Size.padding.small,
|
2013-07-30 15:07:33 +00:00
|
|
|
|
2019-09-06 15:01:37 +00:00
|
|
|
lang_to_keyboard_layout = {
|
2022-12-02 17:39:47 +00:00
|
|
|
ar = "ar_keyboard",
|
2021-02-28 18:59:02 +00:00
|
|
|
bg_BG = "bg_keyboard",
|
2022-03-15 22:13:13 +00:00
|
|
|
bn = "bn_keyboard",
|
2020-07-16 19:25:02 +00:00
|
|
|
de = "de_keyboard",
|
2019-09-06 15:01:37 +00:00
|
|
|
el = "el_keyboard",
|
|
|
|
en = "en_keyboard",
|
|
|
|
es = "es_keyboard",
|
2021-02-05 20:30:09 +00:00
|
|
|
fa = "fa_keyboard",
|
2019-09-06 15:01:37 +00:00
|
|
|
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",
|
2021-02-01 21:35:15 +00:00
|
|
|
ka = "ka_keyboard",
|
2022-10-25 11:44:19 +00:00
|
|
|
ko_KR = "ko_KR_keyboard",
|
2020-10-07 15:29:47 +00:00
|
|
|
pl = "pl_keyboard",
|
2019-09-06 15:01:37 +00:00
|
|
|
pt_BR = "pt_keyboard",
|
2019-11-30 16:35:39 +00:00
|
|
|
ro = "ro_keyboard",
|
2019-11-18 22:33:22 +00:00
|
|
|
ru = "ru_keyboard",
|
2022-10-25 11:44:19 +00:00
|
|
|
sk = "sk_keyboard",
|
2022-10-12 09:25:43 +00:00
|
|
|
th = "th_keyboard",
|
2020-01-27 23:05:16 +00:00
|
|
|
tr = "tr_keyboard",
|
2023-01-23 15:00:57 +00:00
|
|
|
uk = "uk_keyboard",
|
2022-10-03 07:30:03 +00:00
|
|
|
vi = "vi_keyboard",
|
2022-10-01 23:58:36 +00:00
|
|
|
zh = "zh_keyboard",
|
2022-12-02 15:59:31 +00:00
|
|
|
zh_CN = "zh_CN_keyboard",
|
2019-09-06 15:01:37 +00:00
|
|
|
},
|
2021-11-06 05:09:33 +00:00
|
|
|
|
|
|
|
lang_has_submenu = {
|
|
|
|
ja = true,
|
2022-10-01 23:58:36 +00:00
|
|
|
zh = true,
|
2022-12-02 15:59:31 +00:00
|
|
|
zh_CN = true,
|
2021-11-06 05:09:33 +00:00
|
|
|
},
|
2016-11-06 10:01:28 +00:00
|
|
|
}
|
|
|
|
|
2013-07-30 15:07:33 +00:00
|
|
|
function VirtualKeyboard:init()
|
2019-11-25 13:31:52 +00:00
|
|
|
if self.uwrap_func then
|
|
|
|
self.uwrap_func()
|
|
|
|
self.uwrap_func = nil
|
|
|
|
end
|
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)
|
Clarify our OOP semantics across the codebase (#9586)
Basically:
* Use `extend` for class definitions
* Use `new` for object instantiations
That includes some minor code cleanups along the way:
* Updated `Widget`'s docs to make the semantics clearer.
* Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283)
* Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass).
* Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events.
* Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier.
* Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references.
* ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak).
* Terminal: Make sure the shell is killed on plugin teardown.
* InputText: Fix Home/End/Del physical keys to behave sensibly.
* InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...).
* OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of.
* ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed!
* Kobo: Minor code cleanups.
2022-10-06 00:14:48 +00:00
|
|
|
self.KEYS = keyboard.keys or {}
|
|
|
|
self.shiftmode_keys = keyboard.shiftmode_keys or {}
|
|
|
|
self.symbolmode_keys = keyboard.symbolmode_keys or {}
|
|
|
|
self.utf8mode_keys = keyboard.utf8mode_keys or {}
|
|
|
|
self.umlautmode_keys = keyboard.umlautmode_keys or {}
|
2021-09-25 08:51:58 +00:00
|
|
|
self.width = Screen:getWidth()
|
2021-08-29 10:29:41 +00:00
|
|
|
local keys_height = G_reader_settings:isTrue("keyboard_key_compact") and 48 or 64
|
|
|
|
self.height = Screen:scaleBySize(keys_height * #self.KEYS)
|
2019-11-18 16:16:06 +00:00
|
|
|
self.min_layer = keyboard.min_layer
|
|
|
|
self.max_layer = keyboard.max_layer
|
|
|
|
self:initLayer(self.keyboard_layer)
|
2022-05-05 19:00:22 +00:00
|
|
|
self.tap_interval_override = time.ms(G_reader_settings:readSetting("ges_tap_interval_on_keyboard_ms", 0))
|
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:hasKeys() then
|
2022-10-27 00:01:51 +00:00
|
|
|
self.key_events.Close = { { "Back" } }
|
2018-03-30 10:46:36 +00:00
|
|
|
end
|
2019-06-03 09:03:28 +00:00
|
|
|
if keyboard.wrapInputBox then
|
2019-11-25 13:31:52 +00:00
|
|
|
self.uwrap_func = keyboard.wrapInputBox(self.inputbox) or self.uwrap_func
|
2019-06-03 09:03:28 +00:00
|
|
|
end
|
2022-03-04 20:20:00 +00:00
|
|
|
if Device:hasDPad() then
|
2022-01-23 17:40:35 +00:00
|
|
|
-- hadDPad() would have FocusManager handle arrow keys strokes to navigate
|
|
|
|
-- and activate this VirtualKeyboard's touch keys (needed on non-touch Kindle).
|
|
|
|
-- If we have a keyboard, we'd prefer arrow keys (and Enter, and Del) to be
|
|
|
|
-- handled by InputText to navigate the cursor inside the text box, and to
|
|
|
|
-- add newline and delete chars. And if we are a touch device, we don't
|
|
|
|
-- need focus manager to help us navigate keys and fields.
|
|
|
|
-- So, disable all key_event handled by FocusManager
|
2022-03-04 20:20:00 +00:00
|
|
|
if Device:isTouchDevice() then
|
|
|
|
-- Remove all FocusManager key event handlers.
|
|
|
|
for k, _ in pairs(self.builtin_key_events) do
|
|
|
|
self.key_events[k] = nil
|
|
|
|
end
|
|
|
|
for k, _ in pairs(self.extra_key_events) do
|
|
|
|
self.key_events[k] = nil
|
|
|
|
end
|
|
|
|
elseif Device:hasKeyboard() then
|
|
|
|
-- Use physical keyboard for most characters
|
|
|
|
-- For special characters not available in physical keyboard
|
|
|
|
-- Use arrow and Press keys to select in VirtualKeyboard
|
|
|
|
for k, seq in pairs(self.extra_key_events) do
|
|
|
|
if self:_isTextKeyWithoutModifier(seq) then
|
|
|
|
self.key_events[k] = nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2022-01-23 17:40:35 +00:00
|
|
|
end
|
2018-03-30 10:46:36 +00:00
|
|
|
end
|
|
|
|
|
2022-03-04 20:20:00 +00:00
|
|
|
function VirtualKeyboard:_isTextKeyWithoutModifier(seq)
|
|
|
|
for _, oneseq in ipairs(seq) do
|
|
|
|
if #oneseq ~= 1 then -- has modifier key combination
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
if #oneseq[1] ~= 1 then -- not simple text key, like Home, End
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
2019-09-06 15:01:37 +00:00
|
|
|
function VirtualKeyboard:getKeyboardLayout()
|
2021-08-29 10:29:41 +00:00
|
|
|
if G_reader_settings:isFalse("keyboard_remember_layout") and not keyboard_state.force_current_layout then
|
|
|
|
local lang = G_reader_settings:readSetting("keyboard_layout_default")
|
2021-11-23 20:17:07 +00:00
|
|
|
or G_reader_settings:readSetting("keyboard_layout", "en")
|
2021-08-29 10:29:41 +00:00
|
|
|
G_reader_settings:saveSetting("keyboard_layout", lang)
|
|
|
|
end
|
2019-09-06 15:01:37 +00:00
|
|
|
return G_reader_settings:readSetting("keyboard_layout") or G_reader_settings:readSetting("language")
|
|
|
|
end
|
|
|
|
|
2019-11-18 16:16:06 +00:00
|
|
|
function VirtualKeyboard:setKeyboardLayout(layout)
|
2021-08-29 10:29:41 +00:00
|
|
|
keyboard_state.force_current_layout = true
|
2019-11-25 13:31:54 +00:00
|
|
|
local prev_keyboard_height = self.dimen and self.dimen.h
|
2019-11-18 16:16:06 +00:00
|
|
|
G_reader_settings:saveSetting("keyboard_layout", layout)
|
|
|
|
self:init()
|
2019-11-25 13:31:54 +00:00
|
|
|
if prev_keyboard_height and self.dimen.h ~= prev_keyboard_height then
|
|
|
|
self:_refresh(true, true)
|
|
|
|
-- Keyboard height change: notify parent (InputDialog)
|
|
|
|
if self.inputbox and self.inputbox.parent and self.inputbox.parent.onKeyboardHeightChanged then
|
|
|
|
self.inputbox.parent:onKeyboardHeightChanged()
|
|
|
|
end
|
|
|
|
else
|
|
|
|
self:_refresh(true)
|
|
|
|
end
|
2021-08-29 10:29:41 +00:00
|
|
|
keyboard_state.force_current_layout = false
|
2019-11-18 16:16:06 +00:00
|
|
|
end
|
|
|
|
|
2018-03-30 10:46:36 +00:00
|
|
|
function VirtualKeyboard:onClose()
|
|
|
|
UIManager:close(self)
|
2022-03-04 20:20:00 +00:00
|
|
|
if self.inputbox and Device:hasDPad() then
|
|
|
|
-- let input text handle Back event to unfocus
|
|
|
|
-- otherwise, another extra Back event needed
|
|
|
|
return false
|
2022-01-25 00:32:46 +00:00
|
|
|
end
|
2022-03-04 20:20:00 +00:00
|
|
|
return true
|
2013-07-30 15:07:33 +00:00
|
|
|
end
|
|
|
|
|
2019-11-25 13:31:54 +00:00
|
|
|
function VirtualKeyboard:_refresh(want_flash, fullscreen)
|
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
|
2019-11-25 13:31:54 +00:00
|
|
|
if fullscreen then
|
|
|
|
UIManager:setDirty("all", refresh_type)
|
|
|
|
return
|
|
|
|
end
|
2014-12-01 14:39:41 +00:00
|
|
|
UIManager:setDirty(self, function()
|
2023-02-07 00:01:05 +00:00
|
|
|
return refresh_type, self[1][1].dimen -- i.e., keyboard_frame
|
2014-12-01 14:39:41 +00:00
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
function VirtualKeyboard:onShow()
|
2018-06-02 16:10:55 +00:00
|
|
|
self:_refresh(true)
|
2023-09-01 20:51:41 +00:00
|
|
|
self.visible = true
|
|
|
|
Device:startTextInput()
|
2014-12-01 14:39:41 +00:00
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
|
|
function VirtualKeyboard:onCloseWidget()
|
2023-08-01 21:53:10 +00:00
|
|
|
self:_refresh(true)
|
2023-09-01 20:51:41 +00:00
|
|
|
self.visible = false
|
|
|
|
-- NOTE: This effectively stops SDL text input when a keyboard is hidden (... but navigational stuff still works).
|
|
|
|
-- If you instead wanted it to be enabled as long as an input dialog is displayed, regardless of VK's state,
|
|
|
|
-- this could be moved to InputDialog's onShow/onCloseWidget handlers (but, it would allow input on unfocused fields).
|
|
|
|
-- NOTE: But something more complex, possibly based on an in-class ref count would have to be implemented in order to be able to deal
|
|
|
|
-- with multiple InputDialogs being shown and closed in asymmetric fashion... Ugh.
|
|
|
|
Device:stopTextInput()
|
|
|
|
end
|
|
|
|
|
|
|
|
function VirtualKeyboard:lockVisibility(toggle)
|
|
|
|
self.lock_visibility = toggle
|
|
|
|
end
|
|
|
|
|
|
|
|
function VirtualKeyboard:setVisibility(toggle)
|
|
|
|
if self.lock_visibility then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
if toggle then
|
|
|
|
UIManager:show(self)
|
|
|
|
else
|
|
|
|
self:onClose()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function VirtualKeyboard:isVisible()
|
|
|
|
return self.visible
|
|
|
|
end
|
|
|
|
|
|
|
|
function VirtualKeyboard:showKeyboard(ignore_first_hold_release)
|
|
|
|
if not self:isVisible() then
|
|
|
|
self.ignore_first_hold_release = ignore_first_hold_release
|
|
|
|
self:setVisibility(true)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function VirtualKeyboard:hideKeyboard()
|
|
|
|
if self:isVisible() then
|
|
|
|
self:setVisibility(false)
|
|
|
|
end
|
2014-12-01 14:39:41 +00:00
|
|
|
end
|
|
|
|
|
2019-11-18 16:16:06 +00:00
|
|
|
function VirtualKeyboard:initLayer(layer)
|
|
|
|
local function VKLayer(b1, b2, b3)
|
2014-03-13 13:52:43 +00:00
|
|
|
local function boolnum(bool)
|
|
|
|
return bool and 1 or 0
|
|
|
|
end
|
2019-11-18 16:16:06 +00:00
|
|
|
return 2 - boolnum(b1) + 2 * boolnum(b2) + 4 * boolnum(b3)
|
|
|
|
end
|
|
|
|
|
|
|
|
if layer then
|
|
|
|
-- to be sure layer is selected properly
|
|
|
|
layer = math.max(layer, self.min_layer)
|
|
|
|
layer = math.min(layer, self.max_layer)
|
|
|
|
self.keyboard_layer = layer
|
|
|
|
-- fill the layer modes
|
|
|
|
self.shiftmode = (layer == 1 or layer == 3 or layer == 5 or layer == 7 or layer == 9 or layer == 11)
|
|
|
|
self.symbolmode = (layer == 3 or layer == 4 or layer == 7 or layer == 8 or layer == 11 or layer == 12)
|
|
|
|
self.umlautmode = (layer == 5 or layer == 6 or layer == 7 or layer == 8)
|
|
|
|
else -- or, without input parameter, restore layer from current layer modes
|
|
|
|
self.keyboard_layer = VKLayer(self.shiftmode, self.symbolmode, 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()
|
2019-11-25 13:31:54 +00:00
|
|
|
self:free() -- free previous keys' TextWidgets
|
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}
|
2019-12-06 21:55:39 +00:00
|
|
|
local vertical_group = VerticalGroup:new{ allow_mirroring = false }
|
2014-03-13 13:52:43 +00:00
|
|
|
for i = 1, #self.KEYS do
|
2019-12-06 21:55:39 +00:00
|
|
|
local horizontal_group = HorizontalGroup:new{ allow_mirroring = false }
|
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
|
2019-11-18 16:16:06 +00:00
|
|
|
local key_chars = self.KEYS[i][j][self.keyboard_layer]
|
2020-01-18 21:47:34 +00:00
|
|
|
local label
|
2021-08-24 21:51:39 +00:00
|
|
|
local alt_label
|
|
|
|
local width_factor
|
2019-04-09 08:40:39 +00:00
|
|
|
if type(key_chars) == "table" then
|
|
|
|
key = key_chars[1]
|
2020-01-18 21:47:34 +00:00
|
|
|
label = key_chars.label
|
2021-08-24 21:51:39 +00:00
|
|
|
alt_label = key_chars.alt_label
|
|
|
|
width_factor = key_chars.width
|
2019-04-09 08:40:39 +00:00
|
|
|
else
|
|
|
|
key = key_chars
|
|
|
|
key_chars = nil
|
|
|
|
end
|
2021-08-24 21:51:39 +00:00
|
|
|
width_factor = width_factor or self.KEYS[i][j].width or self.KEYS[i].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
|
2020-01-18 21:47:34 +00:00
|
|
|
label = label or self.KEYS[i][j].label or key
|
2022-10-31 14:48:05 +00:00
|
|
|
if label == "" and self.shiftmode and (not self.release_shift or self.symbolmode) then
|
|
|
|
key = label
|
|
|
|
label = "" -- capslock symbol
|
|
|
|
end
|
2019-04-09 08:40:39 +00:00
|
|
|
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,
|
2021-08-24 21:51:39 +00:00
|
|
|
alt_label = alt_label,
|
2019-11-25 22:34:31 +00:00
|
|
|
bold = self.KEYS[i][j].bold,
|
2014-03-13 13:52:43 +00:00
|
|
|
keyboard = self,
|
|
|
|
width = key_width,
|
|
|
|
height = key_height,
|
|
|
|
}
|
2019-11-18 16:16:06 +00:00
|
|
|
if not virtual_key.key_chars then
|
2019-04-09 08:40:39 +00:00
|
|
|
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,
|
2021-08-24 21:51:39 +00:00
|
|
|
background = G_reader_settings:nilOrTrue("keyboard_key_border") and Blitbuffer.COLOR_LIGHT_GRAY or Blitbuffer.COLOR_WHITE,
|
2014-03-13 13:52:43 +00:00
|
|
|
radius = 0,
|
|
|
|
padding = self.padding,
|
2019-12-06 21:55:39 +00:00
|
|
|
allow_mirroring = false,
|
2014-03-13 13:52:43 +00:00
|
|
|
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,
|
|
|
|
}
|
2023-02-07 00:01:05 +00:00
|
|
|
-- Beware, this won't be updated post-paint, so the coordinates will stay at (0, 0)
|
|
|
|
-- (i.e., only the size is accurate, not the position).
|
2014-03-13 13:52:43 +00:00
|
|
|
self.dimen = keyboard_frame:getSize()
|
2013-07-30 15:07:33 +00:00
|
|
|
end
|
|
|
|
|
2019-11-18 16:16:06 +00:00
|
|
|
function VirtualKeyboard:setLayer(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
|
2014-03-13 13:52:43 +00:00
|
|
|
end
|
2019-11-18 16:16:06 +00:00
|
|
|
self:initLayer()
|
2021-08-24 21:51:39 +00:00
|
|
|
self:_refresh(false)
|
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
|
|
|
|
|
2021-05-22 21:25:14 +00:00
|
|
|
function VirtualKeyboard:goToStartOfLine()
|
|
|
|
self.inputbox:goToStartOfLine()
|
|
|
|
end
|
|
|
|
|
2022-10-01 23:58:36 +00:00
|
|
|
-- Some keyboard with intermediate state (ie. zh) may need to be notified
|
|
|
|
function VirtualKeyboard:onSwitchingKeyboardLayout()
|
|
|
|
if self.inputbox.onSwitchingKeyboardLayout then self.inputbox:onSwitchingKeyboardLayout() end
|
|
|
|
end
|
|
|
|
|
2021-05-22 21:25:14 +00:00
|
|
|
function VirtualKeyboard:goToEndOfLine()
|
|
|
|
self.inputbox:goToEndOfLine()
|
|
|
|
end
|
|
|
|
|
2017-10-10 16:04:51 +00:00
|
|
|
function VirtualKeyboard:upLine()
|
|
|
|
self.inputbox:upLine()
|
|
|
|
end
|
|
|
|
|
Terminal emulator: full rewrite, real vt52 emulator (#8636)
New real terminal emulator, replacing the old plugin.
The emulator is basically a vt52 terminal (enriched with
some ANSI-sequences, as ash, vi and mksh don't behave well
on a vt52 term).
So far working: ash, mksh, bash, nano, vi, busybox, watch...
The input supports: tab-completion; cursor movement;
backspace; start of line, end of line (long press);
page up, page down (long press).
User scripts may be placed in the koterm.koplugin/scripts/
folder, aliases can be put in the file aliases and startup
command in the file profile.user in that folder.
2022-01-28 19:33:09 +00:00
|
|
|
function VirtualKeyboard:scrollUp()
|
|
|
|
self.inputbox:scrollUp()
|
|
|
|
end
|
|
|
|
|
2017-10-10 16:04:51 +00:00
|
|
|
function VirtualKeyboard:downLine()
|
|
|
|
self.inputbox:downLine()
|
|
|
|
end
|
|
|
|
|
Terminal emulator: full rewrite, real vt52 emulator (#8636)
New real terminal emulator, replacing the old plugin.
The emulator is basically a vt52 terminal (enriched with
some ANSI-sequences, as ash, vi and mksh don't behave well
on a vt52 term).
So far working: ash, mksh, bash, nano, vi, busybox, watch...
The input supports: tab-completion; cursor movement;
backspace; start of line, end of line (long press);
page up, page down (long press).
User scripts may be placed in the koterm.koplugin/scripts/
folder, aliases can be put in the file aliases and startup
command in the file profile.user in that folder.
2022-01-28 19:33:09 +00:00
|
|
|
function VirtualKeyboard:scrollDown()
|
|
|
|
self.inputbox:scrollDown()
|
|
|
|
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
|