Journal Un petit script pour les utilisateurs de manette

Posté par . Licence CC by-sa
Tags :
12
4
août
2013

Bonjour à tous
N'ayant pas grand chose à faire hier après midi, je me suis fait un petit script pour contrôler ma souris à l'aide de mon joypad (tous ceux que j'ai essayé jusqu'ici ne fonctionnent pas chez moi).
Le script utilise pygame pour l'acquisition des signaux de la manette et python-xlib pour le contrôle clavier/souris.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#Description: Permet le contrôle de la souris avec une manette.


import pygame
from pygame.locals import *
import Xlib,time
from Xlib import X, display
sroot=display.Display().screen().root

pygame.init()

nb_joysticks = pygame.joystick.get_count()
disable=0
#Bouton pour limiter la vitesse du pointeur
LIMITER=7


# Association des bouton de la manette a une action
#
# binds= {bouton:(materiel, code), ...}
#   bouton: numero du bouton de la manette
#   materiel: 0=souris, 1=clavier
#   code: keycode de la touche pour un clavier,
#         numero du bouton pour une souris

binds={0:(0, 1),        # souris bouton de gauche
        1:(0, 3),       # souris bouton de droite
        2:(1, 36),      # clavier Echap
        3:(1,9),        # clavier Entrer
        4:(1, 117),     # clavier pg suivante
        5:(1,112),      # clavier pg precedente
        6:(1,37),       # clavier ctrl
        #~ 7:(1,50),        # clavier Shift
        #~ 9:(1,64),        # clavier Alt
        }


if nb_joysticks > 0:

    mon_joystick = pygame.joystick.Joystick(0)

    mon_joystick.init()

    #On compte les boutons
    nb_boutons = mon_joystick.get_numbuttons()


    # Init de la memoire pour les etats des bouton
    membstate=map(mon_joystick.get_button,range(nb_boutons))
    # Init de la memoire pour l' etats de la croix
    memhat=[False,False]
    hat=[False,False]

    continuer = 1

    while continuer:
        time.sleep(0.01)
        #Màj de l'etats de la manette
        ev=pygame.event.get()
        #recuperation de l'état des boutons
        bstate=map(mon_joystick.get_button,range(nb_boutons))
        # Permet de verifier si un changement d'etat a eu lieu entre 2 boucles
        bstate_ev=map(lambda c,m:c-m,bstate,membstate)
        # Conversion de bstate en decimal pour detecter les conbinaion de touches
        bstate_int=sum(map(lambda b:int(mon_joystick.get_button(b))*(2**b),range(nb_boutons)))



        # Activation/Desactivation des associations  avec les boutons 
        # L1,L2,R1,R2 (bouton 4,5,6,7) simultanément appuyés
        if bstate_int==240 and sum(bstate_ev)!=0 and disable==0:
            disable=1
            for bn in binds.keys():
                    act=[Xlib.X.ButtonRelease,Xlib.X.KeyRelease]
                    dev,code=binds[bn]
                    Xlib.ext.xtest.fake_input(d['root'],act[dev],code)
        elif bstate_int==240 and sum(bstate_ev)!=0 and disable==1:
            disable=0
        if disable==0:
            # Gestion des boutons   
            if sum(bstate_ev)!=0:
                for bn,st in enumerate(bstate_ev):
                    if st==1 and bn in binds.keys():
                        act=[Xlib.X.ButtonPress,Xlib.X.KeyPress]
                        dev,code=binds[bn]
                        Xlib.ext.xtest.fake_input(sroot.query_pointer()._data['root'],act[dev],code)
                    if st==-1 and bn in binds.keys():
                        act=[Xlib.X.ButtonRelease,Xlib.X.KeyRelease]
                        dev,code=binds[bn]
                        Xlib.ext.xtest.fake_input(sroot.query_pointer()._data['root'],act[dev],code)

            # Limitation de la vitesse du pointeur avec le bouton 9 de la manette
            K=1+(bstate[LIMITER]*9) 


            # Gestion du pointeur avec les analogiques
            # +00001 pour compenser l'erreur des analogiques qui 
            # renvoient des valeurs de -1,00001 à 0.99999
            axe0= round((mon_joystick.get_axis(0)+0.00001)*10,0)/K 
            axe1= round((mon_joystick.get_axis(1)+0.00001)*10,0)/K

            axe2=0
            axe3=0
            #decommenter si 2 analogiques
            #axe2= round((mon_joystick.get_axis(2)+0.00001)*10,0)/K
            #axe3= round((mon_joystick.get_axis(3)+0.00001)*10,0)/K
            if axe0!=0 or axe2!=0:
                y=sroot.query_pointer()._data["root_y"]
                x=sroot.query_pointer()._data["root_x"]
                sroot.warp_pointer(x+int(axe0+axe2),y)
            if axe1!=0 or axe3!=0:
                y=sroot.query_pointer()._data["root_y"]
                x=sroot.query_pointer()._data["root_x"]
                sroot.warp_pointer(x,y+int(axe1+axe3))




            # Gestion des touche HAUT,BAS,GAUCHE,DROITE du clavier avec
            # la croix de la manette
            nb_hats=mon_joystick.get_numhats()
            if nb_hats>0:   
                hat=mon_joystick.get_hat(0)
                hat_ev=map(lambda hc,hm:hc!=hm,hat,memhat)
                d=sroot.query_pointer()._data
                if True in hat_ev:
                    if hat[1] ==1 :
                        Xlib.ext.xtest.fake_input(d['root'],Xlib.X.KeyPress,111)



                    elif hat[1] ==-1 :
                        Xlib.ext.xtest.fake_input(d['root'],Xlib.X.KeyPress,116)


                    elif hat_ev[1]:
                        Xlib.ext.xtest.fake_input(d['root'],Xlib.X.KeyRelease, 111)
                        Xlib.ext.xtest.fake_input(d['root'],Xlib.X.KeyRelease, 116)
                    if hat[0] ==1 :
                        Xlib.ext.xtest.fake_input(d['root'],Xlib.X.KeyPress,114)



                    elif hat[0] ==-1 :
                        Xlib.ext.xtest.fake_input(d['root'],Xlib.X.KeyPress,113)


                    elif hat_ev[0]:
                        Xlib.ext.xtest.fake_input(d['root'],Xlib.X.KeyRelease, 113)
                        Xlib.ext.xtest.fake_input(d['root'],Xlib.X.KeyRelease, 114)


        membstate=bstate
        memhat=hat



else:
    print("Vous n'avez pas branché de Joystick...")
  • # bonne idée!

    Posté par (page perso) . Évalué à 5.

    Si tu veux améliorer ton script en ajoutant une configuration des manettes, j'ai commencé une base de données, disponibles en json ou dans un format spécifique à la bibliothèque SDL2, qui recense les index des axes et des boutons des manettes de jeux pour les faire correspondre à une manette "type":

    http://devnewton.bci.im/fr/gamepad_db

    http://devnewton.bci.im

    • [^] # Re: bonne idée!

      Posté par . Évalué à 2.

      J'ai fait quelques essais, pygame me sort le nom de mon pad et j'arrive a le trouver dans ta base. Ça peut être sympa comme truc.

    • [^] # Re: bonne idée!

      Posté par . Évalué à 1.

      Pour l'utilisation de la base de données de DevNewton.

      J'ai copier cette partie vers un fichier joy_bind_cfg.py:

      #Bouton pour limiter la vitesse du pointeur
      LIMITER=7
      
      
      # Association des bouton de la manette a une action
      #
      # binds= {bouton:(materiel, code), ...}
      #   bouton: numero du bouton de la manette
      #   materiel: 0=souris, 1=clavier
      #   code: keycode de la touche pour un clavier,
      #         numero du bouton pour une souris
      
      binds={0:(0, 1),        # souris bouton de gauche
              1:(0, 3),       # souris bouton de droite
              2:(1, 36),      # clavier Echap
              3:(1,9),        # clavier Entrer
              4:(1, 117),     # clavier pg suivante
              5:(1,112),      # clavier pg precedente
              6:(1,37),       # clavier ctrl
              #~ 7:(1,50),        # clavier Shift
              #~ 9:(1,64),        # clavier Alt
              }
      

      et je l'ai remplacé par:

      #import la config des boutons
      from joy_bind_cfg import *
      

      ensuite j'ai créé le script autoconf_joy.py qui permet de créer le nouveau fichier joy_bind_cfg.py en fonction de la manette.

      import urllib
      import pygame,os
      pygame.init()
      
      mon_joystick = pygame.joystick.Joystick(0)
      
      mon_joystick.init()
      jname= mon_joystick.get_name()
      
      joydb=eval(urllib.urlopen('http://dl.bci.im/gamepad_db/gamepad_db.json').read())
      joydsc=[ i for i in joydb if i["name"]==jname]
      if len(joydsc)>0:
          try:
              mapping={}
      
              for k,v in joydsc[0]["mappings"].iteritems():
                  if 'button' in v.keys():
                      mapping[k]=v['button']
      
              cfg="""
      #Bouton pour limiter la vitesse du pointeur
      LIMITER=%(righttrigger)d
      
      
      # Association des bouton de la manette a une action
      #
      # binds= {bouton:(materiel, code), ...}
      #   bouton: numero du bouton de la manette
      #   materiel: 0=souris, 1=clavier
      #   code: keycode de la touche pour un clavier,
      #         numero du bouton pour une souris
      binds={%(a)d :(0, 1),       # souris bouton de gauche
              %(x)d :(0, 3),      # souris bouton de droite
              %(y)d:(1, 36),      # clavier Echap
              %(b)d:(1,9),        # clavier Entrer
              %(leftshoulder)d:(1, 117),      # clavier pg suivante
              %(lefttrigger)d:(1,112),        # clavier pg precedente
              %(rightshoulder)d:(1,37),       # clavier ctrl
              }
              """ %mapping
              open("joy_bind_cfg.py","w").write( cfg)
          except:
              print "configuration auto impossible"
          else:
              print "Configuration auto OK"
      else:
          print "Votre manette n'est pas dans la base, vous pouvez soumettre votre configuration ici:\
           http://devnewton.bci.im/fr/gamepad_db"
      #force la fermeture de pygame
      pid= os.getpid()
      os.kill(pid,6)
      

      Et voilà le travail… C'est bien crade mais ça marche!

  • # xf86-input-joystick

    Posté par . Évalué à 4.

    Ne faisait pas l'affaire ?

    • [^] # Re: xf86-input-joystick

      Posté par . Évalué à 2.

      Il fait partie du "tous ceux que j'ai essayé jusqu'ici ne fonctionnent pas chez moi". Il me semble que je l'avais essayé sous debian squeeze.
      Sinon, je ne le trouve pas pour fedora 18 (mon OS du moment).

  • # Avec coloration syntaxique

    Posté par (page perso) . Évalué à 1.

    J'ai créé un gist, c'est plus simple à lire, à modifier et à récupérer.

    Juste par curiosité, tu as quoi comme manette de jeu ?

    • [^] # Re: Avec coloration syntaxique

      Posté par . Évalué à 1.

      J'ai une "Mega World USB Game Controllers" et une "Mega World Thrustmaster dual analog 3.2" (la même que la première mais avec deux analogiques et deux gachettes en plus)

    • [^] # Re: Avec coloration syntaxique

      Posté par . Évalué à 1.

      J'arrive pas a envoyer mon commit sur le gist, je ne connais pas trop git, je suis plutot habitué svn. Donc pour me confirmer, il faut bien faire:

      git clone https://gist.github.com/6155042.git
      

      ensuite je fais des modifs sur le fichier

      cd 6155042
      git add .
      git commit -m "msg"
      git push 
      

      et là j'ai une erreur

      error: The requested URL returned error: 403 Forbidden while accessing https://gist.github.com/6155042.git/info/refs?service=git-receive-pack
      fatal: HTTP request failed

      Je me plante quelque part?

      • [^] # Re: Avec coloration syntaxique

        Posté par (page perso) . Évalué à 1.

        Je me suis un peu renseigné, on ne peut pas faire de pull request sur les gist …
        Désolé, je savais pas.

        Du coup l'idée serait de créer un fork, ou de directement créer le gist sur ton compte (voir de créer un vrai projet git).

        Mais ton utilisation de git est correcte.

  • # QJoypad?

    Posté par (page perso) . Évalué à 2.

    Tu as essayé qjoypad?
    J'ai toujours utilisé ça pour mapper ma manette sur souris/clavier pour les jeux qui ne supporte pas les manettes.

    http://qjoypad.sourceforge.net/#screenshots

    • [^] # Re: QJoypad?

      Posté par . Évalué à 1.

      J'ai pas essayé. Il aurait pû convenir bien qu'en génerale j'ai plutôt du gtk sur mon système et que j'évite d'installer tous ce qui est en rapport avec Qt (je suis un peut bête des fois …). Sinon dommage ils auraient pû faire une partie qui gère la manette et à coté l'interface de config.

      Enfin maintenant que je suis parti sur mon truc qu'il supporte les combinaisons de touche clavier, les execution de programme, que j'ai crée un petit script qui fait clavier virtuelle (mais où la sélection des caractères ce fait avec les flèches dans une grille) et que mon script va bientot gérer les combinaisons de boutons sur la manette. Je pense que je vais le garder.

      Merci quand même ce sera sûrement utile à quelqu'un.

      Dans la liste des programmes qui font la même chose il y aussi joymouse que j'avais essayé.

      On peut continuer a les lister pour ceux qui chercherai ce genre de choses.

  • # Xorg ça marche bien!

    Posté par . Évalué à 0.

    Même directement via Xorg?

    Essaye de rajouter ça dans ta conf Xorg (pas sûr que ça marche, la machine qui possède cette conf est éteinte):
    `
    Section "InputClass"
    Identifier "evdev joystick catchall"
    MatchIsJoystick "on"
    MatchDevicePath "/dev/input/event*"
    Driver "evdev"
    EndSection
    ̀
    Néanmoins ce script montre comment piloter le pointer en python (et ça c'est cool!).

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.