better input field keyboard handling

This commit is contained in:
Michael Freno
2025-11-09 12:00:42 -05:00
parent 3690202f48
commit 694a2d0a2e
8 changed files with 1846 additions and 20 deletions

View File

@@ -2595,6 +2595,7 @@ function Element:draw(backdropCanvas)
-- For editable elements, use _textBuffer; for non-editable, use text
local displayText = self.editable and self._textBuffer or self.text
local isPlaceholder = false
local isPasswordMasked = false
-- Show placeholder if editable, empty, and not focused
if self.editable and (not displayText or displayText == "") and self.placeholder and not self._focused then
@@ -2602,6 +2603,13 @@ function Element:draw(backdropCanvas)
isPlaceholder = true
end
-- Apply password masking if enabled
if self.passwordMode and displayText and displayText ~= "" and not isPlaceholder then
local maskedText = string.rep("", utf8.len(displayText))
displayText = maskedText
isPasswordMasked = true
end
if displayText and displayText ~= "" then
local textColor = isPlaceholder and Color.new(self.textColor.r * 0.5, self.textColor.g * 0.5, self.textColor.b * 0.5, self.textColor.a * 0.5)
or self.textColor
@@ -4661,13 +4669,19 @@ function Element:_getCursorScreenPosition()
local text = self._textBuffer or ""
local cursorPos = self._cursorPosition or 0
-- Apply password masking for cursor position calculation
local textForMeasurement = text
if self.passwordMode and text ~= "" then
textForMeasurement = string.rep("", utf8.len(text))
end
-- For single-line text, calculate simple X position
if not self.multiline then
local cursorText = ""
if text ~= "" and cursorPos > 0 then
local byteOffset = utf8.offset(text, cursorPos + 1)
if textForMeasurement ~= "" and cursorPos > 0 then
local byteOffset = utf8.offset(textForMeasurement, cursorPos + 1)
if byteOffset then
cursorText = text:sub(1, byteOffset - 1)
cursorText = textForMeasurement:sub(1, byteOffset - 1)
end
end
return font:getWidth(cursorText), 0
@@ -4775,14 +4789,20 @@ function Element:_getSelectionRects(selStart, selEnd)
local text = self._textBuffer or ""
local rects = {}
-- Apply password masking for selection rectangle calculation
local textForMeasurement = text
if self.passwordMode and text ~= "" then
textForMeasurement = string.rep("", utf8.len(text))
end
-- For single-line text, calculate simple rectangle
if not self.multiline then
local startByte = utf8.offset(text, selStart + 1)
local endByte = utf8.offset(text, selEnd + 1)
local startByte = utf8.offset(textForMeasurement, selStart + 1)
local endByte = utf8.offset(textForMeasurement, selEnd + 1)
if startByte and endByte then
local beforeSelection = text:sub(1, startByte - 1)
local selectedText = text:sub(startByte, endByte - 1)
local beforeSelection = textForMeasurement:sub(1, startByte - 1)
local selectedText = textForMeasurement:sub(startByte, endByte - 1)
local selX = font:getWidth(beforeSelection)
local selWidth = font:getWidth(selectedText)
local selY = 0
@@ -5278,32 +5298,44 @@ function Element:keypressed(key, scancode, isrepeat)
-- Move cursor based on key
if key == "left" then
if self:hasSelection() and not modifiers.shift then
if modifiers.super then
-- Cmd/Super+Left: Move to start
self:moveCursorToStart()
if not modifiers.shift then
self:clearSelection()
end
elseif modifiers.alt then
-- Alt+Left: Move to previous word
self:moveCursorToPreviousWord()
elseif self:hasSelection() and not modifiers.shift then
-- Move to start of selection
local startPos, _ = self:getSelection()
self._cursorPosition = startPos
self:clearSelection()
elseif ctrl then
-- Ctrl+Left: Move to previous word
self:moveCursorToPreviousWord()
else
self:moveCursorBy(-1)
end
elseif key == "right" then
if self:hasSelection() and not modifiers.shift then
if modifiers.super then
-- Cmd/Super+Right: Move to end
self:moveCursorToEnd()
if not modifiers.shift then
self:clearSelection()
end
elseif modifiers.alt then
-- Alt+Right: Move to next word
self:moveCursorToNextWord()
elseif self:hasSelection() and not modifiers.shift then
-- Move to end of selection
local _, endPos = self:getSelection()
self._cursorPosition = endPos
self:clearSelection()
elseif ctrl then
-- Ctrl+Right: Move to next word
self:moveCursorToNextWord()
else
self:moveCursorBy(1)
end
elseif key == "home" then
-- Move to line start (or document start for single-line)
if ctrl or not self.multiline then
-- Home: Move to start (or line start for multiline)
if not self.multiline then
self:moveCursorToStart()
else
self:moveCursorToLineStart()
@@ -5312,8 +5344,8 @@ function Element:keypressed(key, scancode, isrepeat)
self:clearSelection()
end
elseif key == "end" then
-- Move to line end (or document end for single-line)
if ctrl or not self.multiline then
-- End: Move to end (or line end for multiline)
if not self.multiline then
self:moveCursorToEnd()
else
self:moveCursorToLineEnd()