## Associating a textinput event with the keypressed event that triggered it

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
pgimeno
Party member
Posts: 1905
Joined: Sun Oct 18, 2015 2:58 pm
Location: Valencia, ES

### Associating a textinput event with the keypressed event that triggered it

I am trying to accomplish what the title says, but it seems quite tricky. See this post for background.

The first problem is that textinput doesn't ever seem to come before keypressed (if it preceded the generating key all the time, it would have been pretty trivial). It always comes afterwards, and of course for some keys it may not come at all. Second, in Android it's possible that some keyreleased events precede the textinput event. For example, in my phone, when I press Shift+"+" in a wireless keyboard with an en_US layout and with setTextInput(true), the events registered are: shift pressed, "=" pressed, "=" released, shift released, and "+" textinput, in that order, which is extremely annoying.

Furthermore, I'd like a solution that is somewhat future-proof, i.e. that doesn't need lots of changes to adapt it to incoming LÖVE versions. Traditionally, love.run has suffered lots of changes over the years, with every major version having a different one. The latest change in 11.0 in particular was quite major.

The best place to perform the interception seems to be love.handlers, which is kind of an intermediate layer between love.run and application code, because very few programs intercept it, and it's the lowest possible level before love.run.

This technique does have problems: if a quit event follows a keypressed event, the quit event is re-enqueued, therefore all events that were waiting in the queue after the quit event, if any, will be processed. Hopefully that's not too much disruption.

Any better solution than this?

(As a proof of concept, I'm passing the associated textinput and the textinput expectancy check as upvalues of love.keypressed and love.textinput).

Code: Select all

local txt
local expected_textinput = false

function love.keypressed(key, scan, is_repeat)
if key == 'escape' then return love.event.quit() end -- debug key
print("pressed: ".. key,scan, "text: " .. tostring(txt))
end

function love.keyreleased(key, scan)
print("release: " .. key, scan)
end

function love.textinput(txt)
if not expected_textinput then
print("**** UNEXPECTED TEXTINPUT: ****", txt)
end
end

local krq = {}
local poll_i = love.event.poll()
local old_keypressed_handler = love.handlers.keypressed

function love.handlers.keypressed(key, scan, is_repeat)
-- Poll the event queue, as we can't peek
local name, a, b, c, d, e, f = poll_i()
local qlen = 0
while name == 'keyreleased' do
-- enqueue in order of reception
qlen = qlen + 4
krq[qlen - 3] = a
krq[qlen - 2] = b
krq[qlen - 1] = c
krq[qlen] = d
name, a, b, c, d, e, f = poll_i()
end
if name == 'textinput' then
-- This keypressed event generated a keyreleased event
txt = a
else
-- No textinput event associated with this keypress
txt = nil
end
old_keypressed_handler(key, scan, is_repeat)
for i = 1, qlen, 4 do
love.handlers.keyreleased(krq[i], krq[i + 1], krq[i + 2], krq[i + 3])
end
if name == 'quit' then
love.event.push('quit', a, b, c, d, e, f) -- re-enqueue
elseif name == 'textinput' then
expected_textinput = true
love.handlers.textinput(a, b, c, d, e, f)
expected_textinput = false
elseif name then
love.handlers[name](a, b, c, d, e, f)
end
end

Last edited by pgimeno on Fri Nov 08, 2019 12:09 am, edited 1 time in total.

raidho36
Party member
Posts: 1948
Joined: Mon Jun 17, 2013 12:00 pm

### Re: Associating a textinput event with the keypressed event that triggered it

Textinput exist to handle keyboard-independent text input, stuff like japanese writing. Rigging keyboard-agnostic system to a physical keyboard seems like approaching the core problem at a huge tangent.

Keystrokes would produce key events immediately, whereas text input may or may not be generated by that keystrokes. That's why key events would consistently come before input events. Additionally, text input may be generated not by a keystroke at all. In general there's no connection between particular keystrokes and following textinput events. Most of the time there will be evident connection but don't give it any more weight than to a coincidence, as that's only occurring under specific circumstances.

That said, as far as I could tell, appropriate event order will be maintained. If your object is to handle character deletion without missing mid-frame keystrokes, existing system seems perfectly sufficient. Do try to see if the problem exists in the first place to warrant going to the effort of solving it.

pgimeno
Party member
Posts: 1905
Joined: Sun Oct 18, 2015 2:58 pm
Location: Valencia, ES

### Re: Associating a textinput event with the keypressed event that triggered it

raidho36 wrote:
Thu Nov 07, 2019 12:06 am
Do try to see if the problem exists in the first place to warrant going to the effort of solving it.
Maybe you're right. The need arose in relation to babulous' TimelineEvents library, see this thread: https://love2d.org/forums/viewtopic.php ... 2&start=10

I guess that it can enqueue keypressed and textinput events in the same queue, with a type field that distinguishes between them, and read both types with a single function like somethingKeyActivitysomething, which if I understood correctly, is what babulous suggests. A theoretical edit control would then ignore the keystrokes that generated the text input and process the editing ones like arrows and backspace, and the text input events themselves.

### Who is online

Users browsing this forum: MrFariator and 10 guests