bbcmicrobit / micropython

Port of MicroPython for the BBC micro:bit
https://microbit-micropython.readthedocs.io
Other
600 stars 284 forks source link

Create microbit.button_x.is_long_pressed()? #267

Open c0d3st0rm opened 8 years ago

c0d3st0rm commented 8 years ago

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?

dpgeorge commented 8 years ago

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.

carlosperate commented 8 years ago

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
dpgeorge commented 8 years ago

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.

c0d3st0rm commented 8 years ago

@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.

dpgeorge commented 8 years ago

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.

c0d3st0rm commented 8 years ago

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, notifications@github.com 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

dpgeorge commented 8 years ago

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.

c0d3st0rm commented 8 years ago

@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.

dpgeorge commented 8 years ago

@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:

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().