Page 1 of 2

InputField - proper text input handling library

Posted: Fri Jan 14, 2022 9:22 pm
by ReFreezed
InputField enables simple handling of user text input into your program. The library is a single file with no external dependencies.

Features:
  • Different field types: Single-line, multi-line (with or without wrapping), password (obscured characters).
  • Text cursor and navigation (by keyboard and mouse).
  • Text selection.
  • Scrolling, both vertical and horizontal.
  • Text alignment.
  • Shortcuts for common operations, like copying selected text and deleting the next word.
  • Undo and redo (history).
  • Helper functions for rendering.
The library does not do any rendering itself, but provides helper functions for rendering text, cursors and selections.

InputField on GitHub Image
Direct link to library file
Releases
Example programs

Basic usage:

Code: Select all

local InputField = require("InputField")
local field      = InputField("Initial text.")

local fieldX = 80
local fieldY = 50

love.keyboard.setKeyRepeat(true)

function love.keypressed(key, scancode, isRepeat)
	field:keypressed(key, isRepeat)
end
function love.textinput(text)
	field:textinput(text)
end

function love.mousepressed(mx, my, mbutton, pressCount)
	field:mousepressed(mx-fieldX, my-fieldY, mbutton, pressCount)
end
function love.mousemoved(mx, my)
	field:mousemoved(mx-fieldX, my-fieldY)
end
function love.mousereleased(mx, my, mbutton)
	field:mousereleased(mx-fieldX, my-fieldY, mbutton)
end
function love.wheelmoved(dx, dy)
	field:wheelmoved(dx, dy)
end

function love.draw()
	love.graphics.setColor(0, 0, 1)
	for _, x, y, w, h in field:eachSelection() do
		love.graphics.rectangle("fill", fieldX+x, fieldY+y, w, h)
	end

	love.graphics.setColor(1, 1, 1)
	for _, text, x, y in field:eachVisibleLine() do
		love.graphics.print(text, fieldX+x, fieldY+y)
	end

	local x, y, h = field:getCursorLayout()
	love.graphics.rectangle("fill", fieldX+x, fieldY+y, 1, h)
end
See the library file for documentation. Also look at the example programs.

Re: InputField - text input handling library

Posted: Sat Jan 15, 2022 1:19 am
by pgimeno
Not providing rendering is a quite radical approach. I like it :)

Nice work. It's not often that you see so much love placed in an edit control. Almost all fall short of standard features. Slab and Thranduil were the closest to full features editors I've seen before this one, and both missed on some.

I've found a problem. Double-click to select word does not work well in presence of multibyte characters, and it appears that it doesn't work well when using Ctrl+Arrow either, so maybe it's about the word splitter. As for features, it's pretty complete, congrats! In my tests I only missed the double-click-and-drag feature to select multiple words, and the Shift+Del key combination as equivalent to Ctrl+X.

Re: InputField - text input handling library

Posted: Sat Jan 15, 2022 2:39 am
by ReFreezed
Thanks for the feedback, pgimeno!

Because rendering tend to be different in every game/GUI system I thought having a lower-level library like this would be good for handling text input as it's more portable. (I've actually used a version of the library for several years in multiple different projects and it's been working nicely.)

Yeah, word navigation was broken (fixed in repo). I noticed utf8.codes() generates garbage after I did most testing so I hastily implemented my own version (very incorrectly). Also, the library doesn't support non-ASCII punctuation and whitespace yet - it sees all non-ASCII characters as letters. It'll be fixed soon.

I'll add double-click-and-drag and the missing shortcut to the todo list.

Re: InputField - text input handling library

Posted: Sat Jan 15, 2022 7:44 pm
by ReFreezed
Update 3.1

Changes since 3.0:
  • Added double-click-and-drag to select words.
  • Added shortcut Shift+Delete to cut text.
  • Pressing Escape while dragging stops the dragging.
  • Fixed word navigation/selection not working.
  • Better Unicode support for word navigation/selection.
  • Fixed freezing issue when calling some methods on fields that never had any text.

Re: InputField - text input handling library

Posted: Wed Mar 09, 2022 12:54 am
by togFox
Incorporating 3.1 into my project. Works v well. :)

Is there a way for the inputfield to not have focus all the time? I see the 'cursor' is always on and when I use arrows to move through the text, those same arrows are scrolling the map I have in the game.

I want my arrows to either: a) scroll the map when the input box does not have focus or b) manipulate the cursor in the input box when it does have focus. Do I need to capture mouse clicks and track focus myself and then govern different actions in love.keypressed? I assume so - and that's okay. Just trying to nut this out.

I get this is a 'low level' library that requires extra work and I'm happy to do that extra work. Also, how does the cursor respond if you have multiple inputfields? Must try ...

Re: InputField - text input handling library

Posted: Wed Mar 09, 2022 11:15 am
by ReFreezed
Yeah, focus is something you'll have to implement yourself. Example for key handling:

Code: Select all

local fieldHasFocus = false

function love.keypressed(key, scancode, isRepeat)
	-- First handle keys that override InputField's behavior.
	if key == "tab" then
		fieldHasFocus = not fieldHasFocus
		field:resetBlinking()

	-- Then handle InputField, if it has focus.
	elseif fieldHasFocus and field:keypressed(key, isRepeat) then
		-- Event was handled.

	-- Lastly handle keys for when InputField doesn't have focus or the key
	-- wasn't handled by the library.
	elseif key == "escape" then
		love.event.quit()
	end
end

function love.textinput(text)
	if fieldHasFocus then
		field:textinput(text)
	end
end
Every InputField instance have their own cursor and everything - i.e. instances are independent from each other.

Re: InputField - text input handling library

Posted: Wed Mar 09, 2022 9:08 pm
by togFox
Okay. Thanks. I might have multiple input fields so I'll try moving that focus thing inside the field to keep that tidy.

field:hasFocus(boolean)


and then set that value in mouse press events.

I haven't checked the code but that should be straight forward.

Re: InputField - text input handling library

Posted: Wed Mar 09, 2022 10:23 pm
by ReFreezed
If only one field has focus at a time it might be preferred to, instead of having a boolean 'fieldHasFocus', have a global 'focusedField' that determines what field has focus (nil could mean nothing has focus). That way you don't have to update the internal state of several instances when focus changes.

Code: Select all

function love.keypressed(key, scancode, isRepeat)
	-- ...
	elseif focusedField and focusedField:keypressed(key, isRepeat) then
	-- ...
end

Code: Select all

if someField == focusedField then
	-- someField has focus!
end

Re: InputField - text input handling library

Posted: Wed Mar 09, 2022 10:24 pm
by togFox
Yeah - I thought about that after posting. And set it to nil if no field has focus. Thx.

Re: InputField - text input handling library

Posted: Thu Mar 10, 2022 6:15 pm
by ReFreezed
Update 3.2

Changes since 3.1:
  • Added text alignment (left/right/center).
  • Added methods: canScroll, canScrollHorizontally, canScrollVertically.
  • Added methods: getScrollHandles, getScrollHandleHorizontal, getScrollHandleVertical.
  • PageUp and PageDown work in multi-line fields.
  • Keyboard interactions are now disabled while dragging.
I've also added another example program to the repository. (See the new examples folder.)