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

USB joystick in kivy fails on process_as_mouse_or_keyboard #5891

Open
joshuacox opened this issue Aug 7, 2018 · 4 comments
Open

USB joystick in kivy fails on process_as_mouse_or_keyboard #5891

joshuacox opened this issue Aug 7, 2018 · 4 comments

Comments

@joshuacox
Copy link

joshuacox commented Aug 7, 2018

Versions

Description

I was attempting to use a DragonRise USB controller to add many buttons and a joystick to an embedded raspberrypi project.

Code and Logs

# Joystick / Gamepad example
# STOP_FIRE from https://wiki.libsdl.org/SDL_JoyAxisEvent

from kivy.app import App
from kivy.clock import Clock
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.properties import ObjectProperty, ListProperty


class Listener(Widget):
    # fire / trigger axis
    FIRE = (2, 5)
    STOP_FIRE = -32767

    # min value for user to actually trigger axis
    OFFSET = 15000

    # current values + event instance
    VALUES = ListProperty([])
    HOLD = ObjectProperty(None)

    def __init__(self, **kwargs):
        super(Listener, self).__init__(**kwargs)

        # get joystick events first
        Window.bind(on_joy_hat=self.on_joy_hat)
        Window.bind(on_joy_ball=self.on_joy_ball)
        Window.bind(on_joy_axis=self.on_joy_axis)
        Window.bind(on_joy_button_up=self.on_joy_button_up)
        Window.bind(on_joy_button_down=self.on_joy_button_down)

    # show values in console
    def print_values(self, *args):
        print(self.VALUES)

    def joy_motion(self, event, id, axis, value):
        # HAT first, returns max values
        if isinstance(value, tuple):
            if not value[0] and not value[1]:
                Clock.unschedule(self.HOLD)
            else:
                self.VALUES = [event, id, axis, value]
                self.HOLD = Clock.schedule_interval(self.print_values, 0)
            return

        # unschedule if at zero or at minimum (FIRE)
        if axis in self.FIRE and value < self.STOP_FIRE:
            Clock.unschedule(self.HOLD)
            return
        elif abs(value) < self.OFFSET or self.HOLD:
            Clock.unschedule(self.HOLD)

        # schedule if over OFFSET (to prevent accidental event with low value)
        if (axis in self.FIRE and value > self.STOP_FIRE or
                axis not in self.FIRE and abs(value) >= self.OFFSET):
            self.VALUES = [event, id, axis, value]
            self.HOLD = Clock.schedule_interval(self.print_values, 0)

    # replace window instance with identifier
    def on_joy_axis(self, win, stickid, axisid, value):
        pass
        #self.joy_motion('axis', stickid, axisid, value)

    def on_joy_ball(self, win, stickid, ballid, xvalue, yvalue):
        pass
        #self.joy_motion('ball', stickid, ballid, (xvalue, yvalue))

    def on_joy_hat(self, win, stickid, hatid, value):
        pass
        #self.joy_motion('hat', stickid, hatid, value)

    def on_joy_button_down(self, win, stickid, buttonid):
        print('button_down', stickid, buttonid)

    def on_joy_button_up(self, win, stickid, buttonid):
        print('button_up', stickid, buttonid)


class JoystickApp(App):
    def build(self):
        return Listener()


if __name__ == '__main__':
    JoystickApp().run()

output:

[INFO   ] [HIDMotionEvent] using <E-Signal/A-One USB Gaming Mouse>
[INFO   ] [HIDMotionEvent] using <SONiX USB DEVICE>
[INFO   ] [HIDMotionEvent] using <DragonRise Inc.   Generic   USB  Joystick  >
[INFO   ] [HIDMotionEvent] <DragonRise Inc.   Generic   USB  Joystick  > range ABS X position is 0 - 255
[INFO   ] [HIDMotionEvent] <DragonRise Inc.   Generic   USB  Joystick  > range ABS Y position is 0 - 255
[INFO   ] [HIDMotionEvent] using <E-Signal/A-One USB Gaming Mouse>
[INFO   ] [HIDMotionEvent] <SONiX USB DEVICE> range position X is 0 - 255
[INFO   ] [HIDMotionEvent] <SONiX USB DEVICE> range position Y is 0 - 255
[INFO   ] [HIDMotionEvent] <SONiX USB DEVICE> range pressure is 0 - 255
[INFO   ] [HIDMotionEvent] using <SONiX USB DEVICE>
 Exception in thread Thread-3:
 Traceback (most recent call last):
   File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner
     self.run()
   File "/usr/lib/python2.7/threading.py", line 754, in run
     self.__target(*self.__args, **self.__kwargs)
   File "/home/pi/kivy/kivy/input/providers/hidinput.py", line 700, in _thread_run
     process_as_mouse_or_keyboard(*infos)
   File "/home/pi/kivy/kivy/input/providers/hidinput.py", line 551, in process_as_mouse_or_keyboard
     z = keyboard_keys[ev_code][-1
 KeyError: 290

I have tried this on kivey 1.9, 1.10, and 1.11 on ubuntu, raspbian and arch linux, and on both x86_64 and armhf architectures with the dragonrise controller as well as some generic game controllers as well (all work under jstest)

stackoverflow where I asked about this bug first

@joshuacox joshuacox changed the title joystick issues USB joystick in kivy fails on process_as_mouse_or_keyboard Ask Question Aug 7, 2018
@joshuacox joshuacox changed the title USB joystick in kivy fails on process_as_mouse_or_keyboard Ask Question USB joystick in kivy fails on process_as_mouse_or_keyboard Aug 7, 2018
@KeyWeeUsr
Copy link
Contributor

I'm not quite sure why a joystick is detected as mouse/keyboard. Perhaps try to disable hidinput and see if SDL detects the device? The joystick is handled in SDL window anyway.

@joshuacox
Copy link
Author

What's the best method to disable hidinput?

I see the provider code here:
https://kivy.org/docs/_modules/kivy/input/providers/hidinput.html

and in the config there is this section:


[input]
mouse = mouse
%(name)s = probesysfs,provider=hidinput

should I perhaps just change the provider there? I tried removing the line entirely but now I get no output at all (joystick does not seem to respond). Is there a way for me to specify which device? like /dev/input/js0?

@tshirtman
Copy link
Member

you might be interested in this documentation:
https://kivy.org/docs/api-kivy.input.providers.probesysfs.html

@joshuacox
Copy link
Author

@tshirtman that is indeed interesting, yet I can't help feeling that I'm hacking on a problem that is probably already solved, in pygame this is indeed pretty easy to test:
https://gist.github.com/joshuacox/fa079f4e91102c8349aef0f544903dae

and while running the default code I do get lot's of spam from the joystick axis:
https://github.com/kivy/kivy/blob/master/examples/miscellaneous/joystick.py

but commenting out that code and trying to listen to the buttons I get nothing.

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

No branches or pull requests

3 participants