micropython icon indicating copy to clipboard operation
micropython copied to clipboard

Create microbit.button_x.is_long_pressed()?

Open c0d3st0rm opened this issue 9 years ago • 9 comments

The micro:bit Bluetooth profile spec supports three button states - not pressed, pressed and long press (to quote: 3 button states are defined and represented by a simple numeric enumeration: 0 = not pressed, 1 = pressed, 2 = long press). Perhaps the long press state could somehow be implemented into MicroPython?

c0d3st0rm avatar May 04 '16 16:05 c0d3st0rm

We have our own button pressing handler that underlyingly uses the DAL's MICROBIT_BUTTON_EVT_DOWN event and nothing else.

The DAL has the following events: up, down, click, long click, double click, hold. Really we should expose them all if we want to add any more to the current state of affairs. Then we need to make things complicated by returning a list of events (in the order they occured), much like accelerometer gestures.

dpgeorge avatar May 05 '16 11:05 dpgeorge

Are the any plans to allow functions to be executed on button events without having to manually check for the state?

So, I believe currently we would have to:

import microbit

while True:
    if microbit.button_a.is_pressed():
        # do something
        pass
    elif microbit.button_b.is_pressed():
        # do something
        pass

Being able to do something like this would be cool:

import microbit

def my_pressed_a():
    # do something
    pass

def my_long_pressed_b():
    # do something
    pass

microbit.button_a.on_pressed = my_pressed_a
microbit.button_b.on_long_pressed = my_pressed_b

while True:
    # Normal program
    pass

carlosperate avatar May 05 '16 11:05 carlosperate

Are the any plans to allow functions to be executed on button events without having to manually check for the state?

No. It makes things too complicated. When would such an event handler be executed? What if the function doesn't finish before the next event comes along? Of course, it could be implemented, but we decided to keep things simple, see #36.

dpgeorge avatar May 05 '16 11:05 dpgeorge

@dpgeorge:

Then we need to make things complicated by returning a list of events (in the order they occured), much like accelerometer gestures.

What functions, similar to the accelerometer's ones, would be ideal for something like this? And button events are a bit more "haywire", e.g: a double-click event is also accompanied by the up and down events.

c0d3st0rm avatar May 08 '16 16:05 c0d3st0rm

What functions, similar to the accelerometer's ones, would be ideal for something like this?

I don't know how to make it nice and neat.

And button events are a bit more "haywire", e.g: a double-click event is also accompanied by the up and down events.

Yes. In general I'd say there are 2 approaches:

  1. Allow raw access to the button state (pressed or not, no debouncing) and also allow to register a callback when the button state changes. This way you can implement whatever higher-level events you want (eg double click, long click).

  2. Provide only the high-level events in a queue, much like the event system in a GUI windowing framework (eg XNextEvent).

We implement point 2, but there is only 1 event, namely a single click.

dpgeorge avatar May 10 '16 08:05 dpgeorge

What about providing something like the is_long_pressed (and other similar high-level, useful functions, such as was_clicked, was_double_clicked, etc), and an event queue with a get_events function, returning a tuple?

On Tue, 10 May 2016, 09:36 Damien George, [email protected] wrote:

What functions, similar to the accelerometer's ones, would be ideal for something like this?

I don't know how to make it nice and neat.

And button events are a bit more "haywire", e.g: a double-click event is also accompanied by the up and down events.

Yes. In general I'd say there are 2 approaches:

  1. Allow raw access to the button state (pressed or not, no debouncing) and also allow to register a callback when the button state changes. This way you can implement whatever higher-level events you want (eg double click, long click).

  2. Provide only the high-level events in a queue, much like the event system in a GUI windowing framework (eg XNextEvent).

We implement point 2, but there is only 1 event, namely a single click.

— You are receiving this because you authored the thread. Reply to this email directly or view it on GitHub https://github.com/bbcmicrobit/micropython/issues/267#issuecomment-218093232

c0d3st0rm avatar May 10 '16 08:05 c0d3st0rm

I would prefer not to add an event queue, it just complicates the API. Adding is_long_pressed, was_clicked, was_double_clicked, etc might be ok, and useful.

dpgeorge avatar May 10 '16 09:05 dpgeorge

@dpgeorge I did come up with this, but I'm not sure if any of the extra button functions are much use except for is_long_pressed, and possibly was_clicked, so I didn't open a PR.

c0d3st0rm avatar May 11 '16 15:05 c0d3st0rm

@JoeGlancy we need to take careful steps when adding anything to the public API, because once it's added we can't really take it away :)

I think we should have a discussion about what methods to add (if any). Then implementing it is the second hurdle (and kind of easier than deciding upon the API).

We have:

  • is_pressed() to get current debounced pressed state
  • was_pressed() to get past or current press state
  • get_presses() to get number of unique "clicks" since last call

Note that "press" is subtly different to "click" - the latter can only be triggered once the button comes up. There is no sense in an is_clicked() method, rather just was_clicked(), and perhaps get_clicks() also makes sense.

is_long_pressed() is different again: you need to wait a bit of time before you can call it a long press, but then it continues to be a long press until the button is released. was_long_pressed() makes sense, so does get_long_presses().

dpgeorge avatar May 11 '16 21:05 dpgeorge