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

Selector and Joystick #422

Closed
AdamCyffka opened this issue Nov 8, 2022 · 10 comments
Closed

Selector and Joystick #422

AdamCyffka opened this issue Nov 8, 2022 · 10 comments
Labels

Comments

@AdamCyffka
Copy link

Hey, me again, sorry for the delay, we had taken a break on our project.

To come back to our problem, here is a video that will be more telling of the problem with our joystick. When we go left and then return to the center, it goes to the left and then to the right and not left and nothing. Do you have any idea?

https://streamable.com/l75kqh

@AdamCyffka AdamCyffka added the bug label Nov 8, 2022
@ppizarror
Copy link
Owner

I think this is related to the calibration of the menu events. Check out the following lines:

if self._current._joy_event:
sel = self._current._handle_joy_event(True)
if self._current._joy_event == prev:
pygame.time.set_timer(self._current._joy_event_repeat, self._ctrl.joy_repeat)
else:
pygame.time.set_timer(self._current._joy_event_repeat, self._ctrl.joy_delay)
if sel:
self._current._last_update_mode.append(_events.MENU_LAST_JOY_REPEAT)
updated = True
break
else:
pygame.time.set_timer(self._current._joy_event_repeat, 0)

When you move the joystick to left or right it generates a lot of events that have to be "delayed" because if not one single movement of the axis would trigger 300 "move left" events. How many repeats and delay is configured in JOY_DELAY and JOY_REPEAT.

# Joy pad
JOY_AXIS_X = 0
JOY_AXIS_Y = 1
JOY_BUTTON_BACK = 1
JOY_BUTTON_SELECT = 0
JOY_DEADZONE = 0.5
JOY_DELAY = 300 # ms
JOY_DOWN = (0, -1)
JOY_LEFT = (-1, 0)
JOY_REPEAT = 100 # ms
JOY_RIGHT = (1, 0)
JOY_UP = (0, 1)

Maybe tuning these parameters will solve your issue. You can change these values by modifying the Controller:

new_ctrl = ctrl.Controller()
new_ctrl.joy_delay = 200 # ms
menu.set_controller(new_ctrl)

@ppizarror
Copy link
Owner

Today I updated the library to v4.3.0 which introduces this new Controller object. https://pygame-menu.readthedocs.io/en/4.3.0/_source/advanced_controller.html

@AdamCyffka
Copy link
Author

Thanks it's working!

Another tricky thing, I want to change the confirm key of a game selector and set a button (not keyboard).
I know how to change i: ctrl.KEY_APPLY = pygame.K_SPACE with the space bar, but can't find a enum for buttons.

In the program, I have the event var so I can check if event.button == 8 and do something. But how can I found the equivalent of K_SPACE but for buttons.

@ppizarror
Copy link
Owner

Sure, as explained in the documentation, you can create a custom controller object which now has all the instructions regarding how a widget responds to apply:

def apply(self, event: EventType, widget: WidgetType) -> bool:
"""
Accepts apply key. Requires ``pygame.KEYDOWN``.
:param event: Event
:param widget: Widget that accepts the event
:return: True if event matches
"""
return event.key == KEY_APPLY

As you can see, the controller receives the event and widget, thus, any kind of new event can be created. In your case, you must create a new controller (or retrieve the one from the widget, as each instance of the widget has its own object) and apply it to the widget:

import pygame_menu.controls as ctrl
new_ctrl = ctrl.Controller()

def custom_widget_apply(event, widget) -> bool:
    return event.key == pygame.K_SPACE or event.button == 8

new_ctrl.apply = custom_widget_apply
mywidget.set_controller(new_ctrl)

Since v4.3.1 (to be released today) you can get the controller from a widget widget.get_controller(), and you can apply a controller to all widgets within the menu menu.set_controller(new_ctrl, apply_to_widgets=True).

Let me know if this solves your issue.

@ppizarror
Copy link
Owner

v4.3.1 uploaded to pip!

@AdamCyffka
Copy link
Author

Nice to ear, better to update everything this way ^^
Little issue here, Event can't be found in custom_widget_apply, got this error.
AttributeError: 'Event' object has no attribute 'button'

Also before that, the function custom_widget_apply said one arg is missing, I tried to add self as first arg, I don't have the bellow error with this, but still first error.

TypeError: Launcher.custom_widget_apply() takes 2 positional arguments but 3 were given

@ppizarror
Copy link
Owner

ppizarror commented Dec 7, 2022

I think you should use ctrl.joy_select instead:

def custom_widget_apply(event, _) -> bool:
    return event.key == pygame.K_SPACE
def custom_joy_apply(event, _) -> bool:
    return event.button == 8

new_ctrl_sel = ctrl.Controller()
new_ctrl_sel.apply = custom_widget_apply
new_ctrl_sel.joy_select = custom_joy_apply

selector = menu.add.selector('select', ['a', 'b', 'c'])
selector.set_controller(new_ctrl_sel)

I can confirm this works. See updated tests:

# Test selector apply
sel_apply = [False]
joy_apply = [False]
def custom_widget_apply(event, _) -> bool:
"""
Custom widget apply event.
"""
condition = event.key == pygame.K_SPACE
sel_apply[0] = condition
return condition
def custom_joy_apply(event, _) -> bool:
"""
Custom widget apply event.
"""
condition = event.button == 8
joy_apply[0] = condition
return condition
new_ctrl_sel = ctrl.Controller()
new_ctrl_sel.apply = custom_widget_apply
new_ctrl_sel.joy_select = custom_joy_apply
selector = menu.add.selector('select', ['a', 'b', 'c'])
selector.set_controller(new_ctrl_sel)
selector.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True))
self.assertFalse(sel_apply[0])
selector.update(PygameEventUtils.key(pygame.K_SPACE, keydown=True))
self.assertTrue(sel_apply[0])
selector.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True)) # Rollback
self.assertFalse(sel_apply[0])
# Now tests joy buttons
self.assertFalse(joy_apply[0])
selector.update(PygameEventUtils.joy_button(8))
self.assertTrue(joy_apply[0])

Regarding TypeError: Launcher.custom_widget_apply() takes 2 positional arguments but 3 were given I cannot reproduce your issue. Tests from python 3.7-3.10 works https://github.com/ppizarror/pygame-menu/actions/runs/3640023933

@AdamCyffka
Copy link
Author

For me, your apply function still take 3 args

image

@ppizarror
Copy link
Owner

Weird, as old tests had the same format, see https://github.com/ppizarror/pygame-menu/tree/e75441d5ab425404406ef6c9bd473fad3973868f and https://github.com/ppizarror/pygame-menu/actions/runs/3630490971. The test was the same. Which python version are you using?.

Today I changed that class using @staticmethod. Also, to overcome that issue you can create a custom Controller using inheritance:

class MyCustomController(Controller):
   ...

That approach should solve that issue.

@AdamCyffka
Copy link
Author

python was not up to date, everything is working fine. thanks a lot

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

2 participants