Double Press issues

Started by Jip-Hop, July 11, 2019, 05:25:34 PM

Previous topic - Next topic

0 Members and 2 Guests are viewing this topic.

Jip-Hop

This script should disable all keys, and log if there was a single or double keypress within 3 seconds.
When you run this script, I'd expect you'd be unable to navigate out of the menu.
Single presses are ignored.
But when you double press, it responds as a single press...
How's that possible with return false on all key events?

-- Double Press
-- Not working

key_counter = 0
function check_double_press()
    sleep(3)
    if(key_counter == 2) then
        -- Double press
        display.notify_box(tostring(key_counter))
    elseif(key_counter == 1) then
        -- Single press
        display.notify_box(tostring(key_counter))
    end
    key_counter = 0
    return false
end

event.keypress = function(k)

    key_counter = key_counter + 1
    if(key_counter == 1) then
        task.create(function()
            check_double_press()
        end)
    end   

    -- Don't respond to any keys
    return false

end

garry23

Do you have other scripts running?


Jip-Hop

Quote from: garry23 on July 11, 2019, 06:18:41 PM
Do you have other scripts running?
Good question! Just tried on a fresh install of the newest build from Danne. Only Lua module loaded and this test script. But the issue remains.

Quote from: a1ex on July 11, 2019, 08:55:20 PM
Multitasking limitations, see https://builds.magiclantern.fm/lua_api/modules/task.html and https://www.magiclantern.fm/forum/index.php?topic=14828.msg179227#msg179227 .

No easy fix for this one :(

That's a bummer :(
Will need to use creative workarounds then.

As a side-note, how can I set priority when calling task.create()? I thought it would just be an integer but I can't seem to get the syntax right.

Danne

Quote from: Jip-Hop on July 11, 2019, 09:35:38 PM
Good question! Just tried on a fresh install of the newest build from Danne. Only Lua module loaded and this test script. But the issue remains.
I could merge fixes here but that's blind merging on my part. Interested what a1ex has to say about the issue and the fix first.

Jip-Hop

What I understand is that there's no easy fix for the Lua multitasking limitations.
But the config.lua issue I ran into is a separate matter and there's already a fix and pull request for those.

Danne

Yep. Those pull requests. Maybe a reason why they are not merged...

Jip-Hop


Jip-Hop

I think I now have a working example, which uses event.shoot_task instead of task.create().
Honestly I don't know what event.shoot_task actually is, how often it refreshes etc.
And I'm still curious about the priority syntax for task.create().

This test blocks all keys, and no keys slip through.
Seems to reliably detect single and double press, which is what I wanted.

Doesn't this run into the multitasking limitations because it's all in one task?

-- Double Press
-- Working

first_press_time = nil
second_press_time = nil

event.shoot_task = function()

    if(first_press_time == nil) then
        return true
    end

    -- If after 500ms no second key is pressed
    -- Don't wait and handle first key press
    if(dryos.ms_clock - first_press_time) > 500 then
        display.notify_box("Single")
        first_press_time = nil
        return true
    end

    if(second_press_time ~= nil) then
        -- This is a double press
        first_press_time = nil
        second_press_time = nil
        display.notify_box("Double")
    end

    return true
end

event.keypress = function(k)

    if(first_press_time == nil) then
        first_press_time = dryos.ms_clock
    else
        second_press_time = dryos.ms_clock
    end

    -- Don't respond to any keys
    return false
end

garry23

@Jip-Hop

I think I hinted in a previous post that you need to exploit the two event handlers, ie key and shoot.

From my experience shoot handler is cycled fast enough.

Jip-Hop

Thanks garry23, that was great advice  :)
Though also this technique I'm not quite out of the woods yet.
With below example I get funky results when I keep basing the PLAY for a while.
E.g. if I press it quickly, maybe 40 times, the camera locks up for some time.
When it responds again it often shows me, in the playback mode, a photo I've taken.
Clearly the intention of the script is to not allow default action of the keys.
Yet still a key event slipped through.

While this may be extreme usage it shows it's not robust.

With my more complex script the issues and lockups are worse, also with less key pressing.

-- Double Press
-- Working kind of

first_press_time = nil
second_press_time = nil

event.shoot_task = function()

    if(first_press_time == nil) then
        return true
    end

    -- If after 500ms no second key is pressed
    -- Don't wait and handle first key press
    if(dryos.ms_clock - first_press_time) > 500 then
        display.notify_box("Single")
        first_press_time = nil
        return true
    end

    if(second_press_time ~= nil) then
        -- This is a double press
        first_press_time = nil
        second_press_time = nil
        display.notify_box("Double")
        lv.pause()
        lv.start()
    end

    return true
end

event.keypress = function(k)

    if(first_press_time == nil) then
        first_press_time = dryos.ms_clock
    else
        second_press_time = dryos.ms_clock
    end

    -- Don't respond to any keys
    return false
end

Jip-Hop

I've now tried the approach from the calc.lua example.
Now I only have one event handler for the key presses and another infinite loop with task.yield(100).
Seems to work a lot better already, especially for opening the ML menu.
I've added a cooldown period too, but I can still get the camera to lock up by pressing keys quickly.

The camera no longer responds to any buttons on the back, the screen is either black or a frozen still.
But it still responds to switching to photo mode with the mode dial and back to video mode.
Then it works as normal again.
Also I can shutdown the camera with ON/OFF button still.

-- Double Press
-- Double Press works fine, but combined with the rest it may still cause issues

-- Simple test, doesn't lock up camera
first_press_time = nil
second_press_time = nil
cooldown_start_time = nil

event.keypress = function(k)

    -- Temporarily ignore PLAY keys during cooldown period
    if cooldown_start_time ~= nil and (dryos.ms_clock - cooldown_start_time) < 1000 then
        return false
    end

    if(first_press_time == nil) then
        first_press_time = dryos.ms_clock
    else
        second_press_time = dryos.ms_clock
    end

    -- Don't respond to any keys
    return false
end

function main_loop()

    while true do

        if lv.paused == true then
            lv.start()
        end

        if(first_press_time ~= nil) then
            -- If after 500ms no second key is pressed
            -- Don't wait and handle first key press
            if(dryos.ms_clock - first_press_time) > 500 then
                display.notify_box("Single")
                cooldown_start_time = dryos.ms_clock
                first_press_time = nil
                if menu.visible == false then
                    menu.open()
                end
            elseif (second_press_time ~= nil) then
                -- This is a double press
                cooldown_start_time = dryos.ms_clock
                first_press_time = nil
                second_press_time = nil
                display.notify_box("Double")
                lv.pause()
                -- lv.start()
            end           
        end

        task.yield(100)
    end
end

console.hide()
main_loop()

garry23

@Jip-Hop

Only time for a quick look.

Your keypress event function only returns false  ;)

You need to handle all keys, ie only your hyjacked key gets the special treatment, all other key presses need to return true.

Try using the keypress event to set flags for the shoot event to handle.

Jip-Hop

Hi garry23,

I'm using flags already and I'm aware I shouldn't return false always, but for this simple example I return false for all keys just to be clear that no keys should be handled as normal (they should all be blocked). Makes it all the more obvious when a key slips through.

From Lua api docs: "Event handlers will not run if there's already a script or another event handler actively executing at the same time."

This is a big problem for what I'm trying to do. If I double press the play key, I call a function to switch raw video preset and refresh live view. This apparently keeps the camera busy (it's actively executing a script). Therefore the key press event handler won't run the third time I press play, and the default action isn't prevented. Now the camera tries to go into play mode while still switching raw video presets and refreshing live view. This causes conflicts and partially locks up the camera.

So with a double press and a few seconds of patience it works fine, but if I accidentally triple press I lock up the camera and need to reboot or switch modes.

Conclusion: Until there's a reliable way to prevent the default action of a key I can't make this work.

Still curious if using task.create with a high priority would make a difference. But I still haven't figured out how to specify the priority...

garry23

@Jip-Hop

One thought I had, that I have tried before and that worked, is to have one script that handles all key events and maintains info in that scripts menus.

Thus other scripts, that do stuff, can read the key handler menu info.

This way you can also try and deconflict between the scripts.

Just a thought.