Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve the button api #108

Open
ensonic opened this issue Oct 9, 2015 · 17 comments
Open

improve the button api #108

ensonic opened this issue Oct 9, 2015 · 17 comments
Labels

Comments

@ensonic
Copy link
Contributor

ensonic commented Oct 9, 2015

I am missing two feature from the button api.

  1. if I want to check if a key is pressed, where key is a variable I have to do:
getattr(ev3dev.buttons, key).pressed

This is not very discoverable.

2.) how would I check for any key pressed?
If there would be an enum of available keys, I could check if any of them are pressed. We could also just have some convenience api for this.

@ddemidov
Copy link
Member

ddemidov commented Oct 9, 2015

How about this?

ev3_keys = [
        'back'  : ev3dev.button.back,
        'left'  : ev3dev.button.left,
        'right' : ev3dev.button.right,
        'up'    : ev3dev.button.up,
        'down'  : ev3dev.button.down,
        'enter' : ev3dev.button.enter
        ]

def key_pressed(k):
    return ev3_keys[k].pressed()

def keys_pressed()
    return [k for k in ev3_keys if ev3_keys[k].pressed()]

@ensonic
Copy link
Contributor Author

ensonic commented Oct 9, 2015

+1 for button.ev3_keys, or maybe just button.keys

button.key_pressed(k) is good.

maybe instead of button.keys_pressed -> button.any_key_pressed() (which would just check for keys_pressed() not returning an empty list)

@ddemidov
Copy link
Member

ddemidov commented Oct 9, 2015

button.key_pressed(k) is good.

May be button.key[k].pressed() is even better (where key is a dict equal to ev3_keys above).

maybe instead of button.keys_pressed -> button.any_key_pressed() (which would just check for keys_pressed() not returning an empty list)

Would not you miss an opportunity to do something like

if 'left' in buttons.keys_pressed(): do_something_great()

or even

if set(['left', 'up']).issubset(buttons.keys_pressed()): do_something_even_greater()

?

@ddemidov ddemidov added the Python label Oct 9, 2015
@ensonic
Copy link
Contributor Author

ensonic commented Oct 14, 2015

I don't think I'd miss them. For those I would probably rather write:

if buttons.left.isPressed(): go_left()

Given that there are just 6 keys, changes that two will be used for the same thing are probably quite low. We can also add both :)

@ddemidov
Copy link
Member

Well, you could do

if set(['left', 'up']).issubset(buttons.keys_pressed()): go_north_west()

:)

@ddemidov
Copy link
Member

Ok, I'll try to add this into python bindings.

ddemidov added a commit to ddemidov/ev3dev-lang-python that referenced this issue Oct 14, 2015
@ddemidov
Copy link
Member

@ensonic
Copy link
Contributor Author

ensonic commented Oct 15, 2015

Thanks!

@ensonic ensonic closed this as completed Oct 15, 2015
@rhempel rhempel reopened this Oct 25, 2015
@rhempel
Copy link
Member

rhempel commented Oct 25, 2015

@ensonic / @ddemidov - I am about to merge in the helper functions for the Button API, but @ddemidov's changes are specific to the EV3. I have 2 questions:

  1. Will the helpers still work as implemented [here][https://github.com/ddemidov/ev3dev-lang-python/commit/f535ed6c5201f4af035d0adc4e4b2fb3011c20db] without instantiating a Button now that we have a cache for the file descriptor?
  2. Should the any_pressed() function return None or an iterable list of pressed keys?

@ensonic - can you send along some sample code where you are using the Button API today, and where the helpers are used? The Button properties as lower case, like this:

if b.up:
    ....
if b.backspace:
    ....

@ddemidov
Copy link
Member

  1. Will the helpers still work as implemented [here][ddemidov/ev3dev-lang-python@f535ed6] without instantiating a Button now that we have a cache for the file descriptor?

Probably not. The properties (up, down, etc) used to be instances of Button class, so there was no need instantiating the main class (it was used simply as namespace). But it should be easy to reimplement the helper functions with getattr().

  1. Should the any_pressed() function return None or an iterable list of pressed keys?

I think @ensonic and I agreed that any_pressed() should return boolean value.

can you send along some sample code where you are using the Button API today?

I am not @ensonic, but this looks like what you are looking for: https://mp-devel.iais.fraunhofer.de/code/projects/ORA/repos/robertalab/browse/EV3MenuEv3dev/roberta/ev3.py#187

@rhempel
Copy link
Member

rhempel commented Oct 25, 2015

If any_pressed() returns True what you typically end up doing is enumerating the buttons to find out which one is pressed :-) I'd still like a helper to return a list of pressed buttons - maybe list_pressed()?

Looking at @ensonic's code, the important bits for the Button API seem to be:

self.key = ev3dev.button
...
    # key
    def isKeyPressed(self, key):
        if key in ['any', '*']:
            # TODO: https://github.com/ev3dev/ev3dev-lang/issues/108
            for key in ['up', 'down', 'left', 'right', 'enter', 'back']:
                if getattr(self.key, key).pressed:
                  return True
            else:
                return False
        else:
            # remap some keys
            keys = {
              'escape':  'back',
              'backspace': 'back',
            }
            if key in keys:
                key = keys[key]
            # throws attribute error on wrong keys
            return getattr(self.key, key).pressed

    def isKeyPressedAndReleased(self, key):
        return False

And it's pretty clear that he's looking for an "any" operation with Boolean result. I'm going to add the helpers to the autogen template for the button properties because that way the platform specific list can be generated easily.

@ddemidov
Copy link
Member

If any_pressed() returns True what you typically end up doing is enumerating the buttons to find out which one is pressed :-) I'd still like a helper to return a list of pressed buttons - maybe list_pressed()?

I agree that could be helpful.

@ensonic
Copy link
Contributor Author

ensonic commented Oct 28, 2015

Just confirming, I was indeed looking for something that returns true if any key is pressed. That is useful when e.g. showing an error.

@rhempel
Copy link
Member

rhempel commented Oct 28, 2015

That's b.any - if you want the list of buttons that are pressed, b.buttons_pressed and if you want to check if a particular set of buttons is pressed, then b.check_buttons([...])
But I realize there's a bug - if there are more buttons pressed than specified. I'll fix that...basically we want all the buttons pressed to match all the buttons specified. and passing an empty list will return True if no buttons are pressed.

@BookBytes
Copy link

I've read through the updates here but I'm unsure about how the current Button class works. What is the current notation for checking for a button press? I read the documentation on readthedocs but am not sure if that is updated. So if I want to check for whether the left button is pressed or not, should I write
b.left, ev3.Button.left (if I have ev3dev imported as 'ev3'), or getattr(ev3dev.buttons, 'left').pressed? Thank you!

@ddemidov
Copy link
Member

ddemidov commented Aug 9, 2016

Currently you have to create an instance of the Button class and use it to query button states:

btn = ev3.Button()
# Is 'Left' button pressed?
print('yes' if btn.left else 'no')

# Check if any buttons are pressed:
print('yes' if btn.any() else 'no')

# Do something when state of 'Left' button changes:
def report(state):
    print('pressed' if state else 'not pressed')
btn.on_left = report

while True:  # This loop checks buttons state continuously, calls appropriate event handlers
  btn.process()

@BookBytes
Copy link

BookBytes commented Aug 9, 2016

@ddemidov - Thank you. This is exactly what I was looking for. The button class makes much more sense now.
Edit: And my code is now up and running correctly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants