mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
Show/Hide Virtual keyboard and more keyboard shortcuts (#12162)
This commit is contained in:
@@ -377,6 +377,8 @@ function FileManager:registerKeyEvents()
|
||||
self.file_chooser.key_events.Back = { { Device.input.group.Back } }
|
||||
if Device:hasScreenKB() then
|
||||
self.key_events.ToggleWifi = { { "ScreenKB", "Home" } }
|
||||
elseif Device:hasKeyboard() then
|
||||
self.key_events.ToggleWifi = { { "Shift", "Home" } }
|
||||
end
|
||||
if not Device:hasFewKeys() then
|
||||
-- Also remove the handler assigned to the "Back" key by menu.lua
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
local ButtonDialog = require("ui/widget/buttondialog")
|
||||
local CheckButton = require("ui/widget/checkbutton")
|
||||
local ConfirmBox = require("ui/widget/confirmbox")
|
||||
local Device = require("device")
|
||||
local DocSettings = require("docsettings")
|
||||
local DocumentRegistry = require("document/documentregistry")
|
||||
local FileChooser = require("ui/widget/filechooser")
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local InputDialog = require("ui/widget/inputdialog")
|
||||
local Menu = require("ui/widget/menu")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
||||
local Utf8Proc = require("ffi/utf8proc")
|
||||
local filemanagerutil = require("apps/filemanager/filemanagerutil")
|
||||
local lfs = require("libs/libkoreader-lfs")
|
||||
@@ -17,12 +18,23 @@ local _ = require("gettext")
|
||||
local N_ = _.ngettext
|
||||
local T = require("ffi/util").template
|
||||
|
||||
local FileSearcher = WidgetContainer:extend{
|
||||
local FileSearcher = InputContainer:extend{
|
||||
case_sensitive = false,
|
||||
include_subfolders = true,
|
||||
include_metadata = false,
|
||||
}
|
||||
|
||||
function FileSearcher:init()
|
||||
self:registerKeyEvents()
|
||||
end
|
||||
|
||||
function FileSearcher:registerKeyEvents()
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events.ShowFileSearch = { { "Alt", "F" } }
|
||||
self.key_events.ShowFileSearchBlank = { { "Alt", "Shift", "F" }, event = "ShowFileSearch", args = "" }
|
||||
end
|
||||
end
|
||||
|
||||
function FileSearcher:onShowFileSearch(search_string)
|
||||
local search_dialog
|
||||
local check_button_case, check_button_subfolders, check_button_metadata
|
||||
@@ -94,6 +106,7 @@ function FileSearcher:onShowFileSearch(search_string)
|
||||
end
|
||||
UIManager:show(search_dialog)
|
||||
search_dialog:onShowKeyboard()
|
||||
return true
|
||||
end
|
||||
|
||||
function FileSearcher:doSearch()
|
||||
|
||||
@@ -6,6 +6,7 @@ local DictQuickLookup = require("ui/widget/dictquicklookup")
|
||||
local Event = require("ui/event")
|
||||
local Geom = require("ui/geometry")
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local InputDialog = require("ui/widget/inputdialog")
|
||||
local JSON = require("json")
|
||||
local KeyValuePage = require("ui/widget/keyvaluepage")
|
||||
@@ -15,7 +16,6 @@ local NetworkMgr = require("ui/network/manager")
|
||||
local SortWidget = require("ui/widget/sortwidget")
|
||||
local Trapper = require("ui/trapper")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
||||
local ffi = require("ffi")
|
||||
local C = ffi.C
|
||||
local ffiUtil = require("ffi/util")
|
||||
@@ -60,7 +60,7 @@ local function getIfosInDir(path)
|
||||
return ifos
|
||||
end
|
||||
|
||||
local ReaderDictionary = WidgetContainer:extend{
|
||||
local ReaderDictionary = InputContainer:extend{
|
||||
data_dir = nil,
|
||||
lookup_msg = _("Searching dictionary for:\n%1"),
|
||||
}
|
||||
@@ -99,6 +99,8 @@ local function getDictionaryFixHtmlFunc(path)
|
||||
end
|
||||
|
||||
function ReaderDictionary:init()
|
||||
self:registerKeyEvents()
|
||||
|
||||
self.disable_lookup_history = G_reader_settings:isTrue("disable_lookup_history")
|
||||
self.dicts_order = G_reader_settings:readSetting("dicts_order", {})
|
||||
self.dicts_disabled = G_reader_settings:readSetting("dicts_disabled", {})
|
||||
@@ -162,6 +164,12 @@ function ReaderDictionary:init()
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderDictionary:registerKeyEvents()
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events.ShowDictionaryLookup = { { "Alt", "D" } }
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderDictionary:sortAvailableIfos()
|
||||
table.sort(available_ifos, function(lifo, rifo)
|
||||
local lord = self.dicts_order[lifo.file]
|
||||
|
||||
@@ -3,6 +3,7 @@ local ButtonDialog = require("ui/widget/buttondialog")
|
||||
local CheckButton = require("ui/widget/checkbutton")
|
||||
local Device = require("device")
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local InputDialog = require("ui/widget/inputdialog")
|
||||
local Menu = require("ui/widget/menu")
|
||||
local Notification = require("ui/widget/notification")
|
||||
@@ -10,7 +11,6 @@ local SpinWidget = require("ui/widget/spinwidget")
|
||||
local TextBoxWidget = require("ui/widget/textboxwidget")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local Utf8Proc = require("ffi/utf8proc")
|
||||
local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
||||
local logger = require("logger")
|
||||
local _ = require("gettext")
|
||||
local C_ = _.pgettext
|
||||
@@ -19,7 +19,7 @@ local T = require("ffi/util").template
|
||||
|
||||
local DGENERIC_ICON_SIZE = G_defaults:readSetting("DGENERIC_ICON_SIZE")
|
||||
|
||||
local ReaderSearch = WidgetContainer:extend{
|
||||
local ReaderSearch = InputContainer:extend{
|
||||
direction = 0, -- 0 for search forward, 1 for search backward
|
||||
case_insensitive = true, -- default to case insensitive
|
||||
|
||||
@@ -41,6 +41,8 @@ local ReaderSearch = WidgetContainer:extend{
|
||||
}
|
||||
|
||||
function ReaderSearch:init()
|
||||
self:registerKeyEvents()
|
||||
|
||||
-- number of words before and after the search string in All search results
|
||||
self.findall_nb_context_words = G_reader_settings:readSetting("fulltext_search_nb_context_words") or 5
|
||||
self.findall_results_per_page = G_reader_settings:readSetting("fulltext_search_results_per_page") or 10
|
||||
@@ -81,6 +83,13 @@ SRELL_ERROR_CODES[110] = _("No preceding expression in repetition.")
|
||||
SRELL_ERROR_CODES[111] = _("Expression too complex, some hits will not be shown.")
|
||||
SRELL_ERROR_CODES[666] = _("Expression may lead to an extremely long search time.")
|
||||
|
||||
function ReaderSearch:registerKeyEvents()
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events.ShowFulltextSearchInputBlank = { { "Alt", "Shift", "S" }, event = "ShowFulltextSearchInput", args = "" }
|
||||
self.key_events.ShowFulltextSearchInputRecent = { { "Alt", "S" }, event = "ShowFulltextSearchInput" }
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderSearch:addToMainMenu(menu_items)
|
||||
menu_items.fulltext_search_settings = {
|
||||
text = _("Fulltext search settings"),
|
||||
@@ -244,7 +253,7 @@ function ReaderSearch:searchCallback(reverse, text)
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderSearch:onShowFulltextSearchInput()
|
||||
function ReaderSearch:onShowFulltextSearchInput(search_string)
|
||||
local backward_text = "◁"
|
||||
local forward_text = "▷"
|
||||
if BD.mirroredUILayout() then
|
||||
@@ -253,7 +262,7 @@ function ReaderSearch:onShowFulltextSearchInput()
|
||||
self.input_dialog = InputDialog:new{
|
||||
title = _("Enter text to search for"),
|
||||
width = math.floor(math.min(Screen:getWidth(), Screen:getHeight()) * 0.9),
|
||||
input = self.last_search_text or self.ui.doc_settings:readSetting("fulltext_search_last_search_text"),
|
||||
input = search_string or self.last_search_text or self.ui.doc_settings:readSetting("fulltext_search_last_search_text"),
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
@@ -310,6 +319,7 @@ function ReaderSearch:onShowFulltextSearchInput()
|
||||
|
||||
UIManager:show(self.input_dialog)
|
||||
self.input_dialog:onShowKeyboard()
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderSearch:onShowSearchDialog(text, direction, regex, case_insensitive)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
local ConfirmBox = require("ui/widget/confirmbox")
|
||||
local DataStorage = require("datastorage")
|
||||
local Device = require("device")
|
||||
local DictQuickLookup = require("ui/widget/dictquicklookup")
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local InputDialog = require("ui/widget/inputdialog")
|
||||
@@ -28,6 +29,7 @@ local ReaderWikipedia = ReaderDictionary:extend{
|
||||
}
|
||||
|
||||
function ReaderWikipedia:init()
|
||||
self:registerKeyEvents()
|
||||
self.wiki_languages = {}
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
if not wikipedia_history then
|
||||
@@ -35,6 +37,12 @@ function ReaderWikipedia:init()
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderWikipedia:registerKeyEvents()
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events.ShowWikipediaLookup = { { "Alt", "W" } }
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderWikipedia:lookupInput()
|
||||
self.input_dialog = InputDialog:new{
|
||||
title = _("Enter a word or phrase to look up"),
|
||||
|
||||
@@ -463,7 +463,8 @@ common_settings.back_in_reader = {
|
||||
genGenericMenuEntry(_("Go to previous read page"), "back_in_reader", "previous_read_page"),
|
||||
},
|
||||
}
|
||||
if Device:hasKeyboard() then
|
||||
-- Kindle keyboard does not have a 'Backspace' key
|
||||
if Device:hasKeyboard() and not Device:hasSymKey() then
|
||||
common_settings.backspace_as_back = {
|
||||
text = _("Backspace works as back button"),
|
||||
checked_func = function()
|
||||
|
||||
@@ -3,6 +3,7 @@ local CheckMark = require("ui/widget/checkmark")
|
||||
local Device = require("device")
|
||||
local FFIUtil = require("ffi/util")
|
||||
local Font = require("ui/font")
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local Language = require("ui/language")
|
||||
local Size = require("ui/size")
|
||||
local TextWidget = require("ui/widget/textwidget")
|
||||
@@ -68,7 +69,6 @@ local function genKeyboardLayoutsSubmenu()
|
||||
if #keyboard_layouts < 4 then
|
||||
table.insert(keyboard_layouts, lang)
|
||||
else -- no more space in the 'globe' popup
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Up to four layouts can be enabled."),
|
||||
timeout = 2,
|
||||
@@ -163,6 +163,9 @@ local sub_item_table = {
|
||||
{
|
||||
text = _("Keyboard appearance settings"),
|
||||
keep_menu_open = true,
|
||||
enabled_func = function()
|
||||
return G_reader_settings:nilOrTrue("virtual_keyboard_enabled")
|
||||
end,
|
||||
callback = function(touchmenu_instance)
|
||||
local InputDialog = require("ui/widget/inputdialog")
|
||||
input_dialog = InputDialog:new{
|
||||
@@ -224,7 +227,26 @@ local sub_item_table = {
|
||||
end,
|
||||
},
|
||||
}
|
||||
if Device:hasKeyboard() or Device:hasScreenKB() then
|
||||
-- we use same pos. 4 as below so we are always above "keyboard apperance settings"
|
||||
table.insert(sub_item_table, 4, {
|
||||
text = _("Show virtual keyboard"),
|
||||
help_text = _("Enable this setting to always display the virtual keyboard within a text input field. When a field is selected (in focus), you can temporarily toggle the keyboard on/off by pressing 'Shift' + 'Home'."),
|
||||
checked_func = function()
|
||||
return G_reader_settings:nilOrTrue("virtual_keyboard_enabled")
|
||||
end,
|
||||
callback = function()
|
||||
G_reader_settings:flipNilOrTrue("virtual_keyboard_enabled")
|
||||
if G_reader_settings:isFalse("virtual_keyboard_enabled") then
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("When a text field is selected (in focus), you can temporarily bring up the virtual keyboard by pressing 'Shift' + 'Home'.")
|
||||
})
|
||||
end
|
||||
end,
|
||||
})
|
||||
end
|
||||
if Device:isTouchDevice() then
|
||||
-- same pos. 4 as above so if both conditions are met we are above "Show virtual keyboard"
|
||||
table.insert(sub_item_table, 4, {
|
||||
text = _("Swipe to input additional characters"),
|
||||
checked_func = function()
|
||||
|
||||
@@ -29,6 +29,7 @@ local VerticalGroup = require("ui/widget/verticalgroup")
|
||||
local VerticalSpan = require("ui/widget/verticalspan")
|
||||
local logger = require("logger")
|
||||
local serpent = require("ffi/serpent")
|
||||
local util = require("util")
|
||||
local _ = require("gettext")
|
||||
local Screen = Device.screen
|
||||
local T = require("ffi/util").template
|
||||
@@ -894,8 +895,15 @@ function ConfigDialog:init()
|
||||
}
|
||||
if Device:hasKeys() then
|
||||
-- set up keyboard events
|
||||
local close_keys = Device:hasFewKeys() and { "Back", "Left" } or Device.input.group.Back
|
||||
self.key_events.Close = { { close_keys } }
|
||||
local back_group = util.tableDeepCopy(Device.input.group.Back)
|
||||
if Device:hasFewKeys() then
|
||||
table.insert(back_group, "Left")
|
||||
self.key_events.Close = { { back_group } }
|
||||
else
|
||||
table.insert(back_group, "Menu")
|
||||
table.insert(back_group, "AA")
|
||||
self.key_events.Close = { { back_group } }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -222,6 +222,10 @@ function InputDialog:init()
|
||||
if self.fullscreen or self.add_nav_bar then
|
||||
self.deny_keyboard_hiding = true
|
||||
end
|
||||
if (Device:hasKeyboard() or Device:hasScreenKB()) and G_reader_settings:isFalse("virtual_keyboard_enabled") then
|
||||
self.keyboard_visible = false
|
||||
self.skip_first_show_keyboard = true
|
||||
end
|
||||
|
||||
-- Title & description
|
||||
self.title_bar = TitleBar:new{
|
||||
@@ -450,7 +454,7 @@ function InputDialog:init()
|
||||
end
|
||||
end
|
||||
|
||||
-- If we're fullscreen without a keyboard, make sure only the toggle button can show the keyboard...
|
||||
-- If we're fullscreen without the virtual keyboard, make sure only the toggle button can bring back the keyboard...
|
||||
if self.fullscreen and not self.keyboard_visible then
|
||||
self:lockKeyboard(true)
|
||||
end
|
||||
@@ -561,6 +565,11 @@ function InputDialog:onCloseWidget()
|
||||
end
|
||||
|
||||
function InputDialog:onShowKeyboard(ignore_first_hold_release)
|
||||
-- Don't initiate virtual keyboard when user has a physical keyboard and G_setting(vk_enabled) unchecked.
|
||||
if self.skip_first_show_keyboard then
|
||||
self.skip_first_show_keyboard = nil
|
||||
return
|
||||
end
|
||||
-- NOTE: There's no VirtualKeyboard widget instantiated at all when readonly,
|
||||
-- and our input widget handles that itself, so we don't need any guards here.
|
||||
-- (In which case, isKeyboardVisible will return `nil`, same as if we had a VK instantiated but *never* shown).
|
||||
@@ -580,6 +589,10 @@ function InputDialog:isKeyboardVisible()
|
||||
end
|
||||
|
||||
function InputDialog:lockKeyboard(toggle)
|
||||
if (Device:hasKeyboard() or Device:hasScreenKB()) and G_reader_settings:isFalse("virtual_keyboard_enabled") then
|
||||
-- do not lock the virtual keyboard when user is hiding it, we still *might* want to activate it via shortcuts ("Shift" + "Home") when in need of special characters or symbols
|
||||
return
|
||||
end
|
||||
return self._input_widget:lockKeyboard(toggle)
|
||||
end
|
||||
|
||||
|
||||
@@ -300,6 +300,8 @@ local function initDPadEvents()
|
||||
-- Event called by the focusmanager
|
||||
if self.parent.onSwitchFocus then
|
||||
self.parent:onSwitchFocus(self)
|
||||
elseif (Device:hasKeyboard() or Device:hasScreenKB()) and G_reader_settings:isFalse("virtual_keyboard_enabled") then
|
||||
do end -- luacheck: ignore 541
|
||||
else
|
||||
self:onShowKeyboard()
|
||||
end
|
||||
@@ -584,6 +586,17 @@ function InputText:focus()
|
||||
self._frame_textwidget.color = Blitbuffer.COLOR_BLACK
|
||||
end
|
||||
|
||||
-- NOTE: This key_map can be used for keyboards without numeric keys, such as on Kindles with keyboards. It is loosely 'inspired' by the symbol layer on the virtual keyboard but,
|
||||
-- we have taken the liberty of making some adjustments since:
|
||||
-- * K3 does not have numeric keys (top row) and,
|
||||
-- * we want to prioritise the most-likely-used characters for "style tweaks" and note taking
|
||||
-- (in English, sorry everybody else, there are just not enough keys)
|
||||
local sym_key_map = {
|
||||
["Q"] = "!", ["W"] = "?", ["E"] = "-", ["R"] = "_", ["T"] = "%", ["Y"] = "=", ["U"] = "7", ["I"] = "8", ["O"] = "9", ["P"] = "0",
|
||||
["A"] = "<", ["S"] = ">", ["D"] = "(", ["F"] = ")", ["G"] = "#", ["H"] = "'", ["J"] = "4", ["K"] = "5", ["L"] = "6",
|
||||
["Z"] = "{", ["X"] = "}", ["C"] = "[", ["V"] = "]", ["B"] = "1", ["N"] = "2", ["M"] = "3", ["."] = ":", ["AA"] = ";",
|
||||
}
|
||||
|
||||
-- Handle real keypresses from a physical keyboard, even if the virtual keyboard
|
||||
-- is shown. Mostly likely to be in the emulator, but could be Android + BT
|
||||
-- keyboard, or a "coder's keyboard" Android input method.
|
||||
@@ -609,9 +622,11 @@ function InputText:onKeyPress(key)
|
||||
self:leftChar()
|
||||
elseif key["Right"] then
|
||||
self:rightChar()
|
||||
elseif key["Up"] then
|
||||
-- NOTE: When we are not showing the virtual keyboard, let focusmanger handle up/down keys, as they are used to directly move around the widget
|
||||
-- seemlessly in and out of text fields and onto virtual buttons like `[cancel] [search dict]`, no need to unfocus first.
|
||||
elseif key["Up"] and G_reader_settings:nilOrTrue("virtual_keyboard_enabled") then
|
||||
self:upLine()
|
||||
elseif key["Down"] then
|
||||
elseif key["Down"] and G_reader_settings:nilOrTrue("virtual_keyboard_enabled") then
|
||||
self:downLine()
|
||||
elseif key["End"] then
|
||||
self:goToEnd()
|
||||
@@ -621,7 +636,8 @@ function InputText:onKeyPress(key)
|
||||
self:addChars("\n")
|
||||
elseif key["Tab"] then
|
||||
self:addChars(" ")
|
||||
elseif key["Back"] then
|
||||
-- as stated before, we also don't need to unfocus when there is no keyboard, one less key press to exit widgets, yay!
|
||||
elseif key["Back"] and G_reader_settings:nilOrTrue("virtual_keyboard_enabled") then
|
||||
if self.focused then
|
||||
self:unfocus()
|
||||
end
|
||||
@@ -641,8 +657,12 @@ function InputText:onKeyPress(key)
|
||||
end
|
||||
if not handled and (key["ScreenKB"] or key["Shift"]) then
|
||||
handled = true
|
||||
if key["Back"] then
|
||||
if key["Back"] and Device:hasScreenKB() then
|
||||
self:delChar()
|
||||
elseif key["Back"] and Device:hasSymKey() then
|
||||
self:delToStartOfLine()
|
||||
elseif key["Del"] and Device:hasSymKey() then
|
||||
self:delWord()
|
||||
elseif key["Left"] then
|
||||
self:leftChar()
|
||||
elseif key["Right"] then
|
||||
@@ -664,6 +684,15 @@ function InputText:onKeyPress(key)
|
||||
handled = false
|
||||
end
|
||||
end
|
||||
if not handled and Device:hasSymKey() then
|
||||
local symkey = sym_key_map[key.key]
|
||||
-- Do not match Shift + Sym + 'Alphabet keys'
|
||||
if symkey and key.modifiers["Sym"] and not key.modifiers["Shift"] then
|
||||
self:addChars(symkey)
|
||||
else
|
||||
handled = false
|
||||
end
|
||||
end
|
||||
if not handled and Device:hasDPad() then
|
||||
-- FocusManager may turn on alternative key maps.
|
||||
-- These key map maybe single text keys.
|
||||
@@ -680,6 +709,10 @@ function InputText:onKeyPress(key)
|
||||
-- if it is single text char, insert it
|
||||
local key_code = key.key -- is in upper case
|
||||
if not Device.isSDL() and #key_code == 1 then
|
||||
if key["Shift"] and key["Alt"] and key["G"] then
|
||||
-- Allow the screenshot keyboard-shortcut to work when focus is on InputText
|
||||
return false
|
||||
end
|
||||
if not key["Shift"] then
|
||||
key_code = string.lower(key_code)
|
||||
end
|
||||
|
||||
@@ -237,7 +237,11 @@ function MultiInputDialog:onSwitchFocus(inputbox)
|
||||
self._input_widget:focus()
|
||||
self.focused_field_idx = inputbox.idx
|
||||
|
||||
-- Make sure we have a (new) visible keyboard
|
||||
if (Device:hasKeyboard() or Device:hasScreenKB()) and G_reader_settings:isFalse("virtual_keyboard_enabled") then
|
||||
-- do not load virtual keyboard when user is hiding it.
|
||||
return
|
||||
end
|
||||
-- Otherwise make sure we have a (new) visible keyboard
|
||||
self:onShowKeyboard()
|
||||
end
|
||||
|
||||
|
||||
@@ -1886,7 +1886,7 @@ function TextBoxWidget:moveCursorDown()
|
||||
end
|
||||
|
||||
function TextBoxWidget:moveCursorHome()
|
||||
self:moveCursorToCharPos(self.vertical_string_list[self.current_line_num].offset)
|
||||
self:moveCursorToCharPos(self.vertical_string_list[self.current_line_num] and self.vertical_string_list[self.current_line_num].offset or #self.charlist)
|
||||
end
|
||||
|
||||
function TextBoxWidget:moveCursorEnd()
|
||||
|
||||
Reference in New Issue
Block a user