web-dev-qa-db-fra.com

Obtenir les clés de macro d'un Razer BlackWidow pour fonctionner sur Linux

J'ai choisi un Razer BlackWidow Ultimate doté de clés supplémentaires destinées aux macros définies à l'aide d'un outil installé sur Windows . Je suppose que ce ne sont pas des clés joojoo de fantaisie et devraient émettre des scancodes comme n'importe quelle autre clé.

Premièrement, existe-t-il un moyen standard de vérifier ces scancodes sous Linux? Deuxièmement, comment définir ces clés pour effectuer des opérations dans les configurations en ligne de commande et sous Linux? Mon installation Linux actuelle est Xubuntu 10.10, mais je vais passer à Kubuntu une fois que plusieurs choses auront été corrigées. Idéalement, la réponse devrait être générique et s’appliquer à l’ensemble du système.

Ce que j'ai essayé jusqu'à présent:

Choses que j'ai besoin d'essayer

  • snoopy pro + ingénierie inverse (oh mon Dieu)

  • Wireshark - les premiers essais semblent indiquer qu’aucun scancode n’est émis, alors que je pense que le clavier est surveillé et les touches enfoncées. Peut indiquer que les clés supplémentaires constituent un périphérique distinct ou doivent être initialisées d'une manière ou d'une autre.

  • Il est nécessaire de croiser cette référence avec la sortie lsusb de Linux dans trois scénarios: autonome, transmise à un système Windows VM sans les pilotes installés et la même chose avec.

  • LSUSB détecte uniquement un périphérique sur une installation autonome de Linux

  • Il peut être utile de vérifier si les souris utilisent le même pilote Razer Synapse, car cela signifie qu'une variation de razercfg pourrait fonctionner (non détectée, semble uniquement travailler pour les souris)

Ce que j'ai travaillé:

  • Dans un système Windows avec pilote, le clavier est considéré comme un clavier et un périphérique de pointage. Le périphérique de pointage utilise, en plus de vos pilotes de souris standard, un pilote pour quelque chose appelé Razer Synapse.

  • Le pilote de souris vu dans Linux sous evdev et lsusb ainsi

  • Un seul appareil sous OS X apparemment, même si je n’ai pas encore essayé lsusb équivalent sur celui-ci.

  • Le clavier passe en mode rétroéclairage pulsé sous OS X lors de l'initialisation avec le pilote. Cela devrait probablement indiquer qu'une séquence d'initialisation a été envoyée au clavier lors de l'activation.

  • Ce sont en fait des clés de fantaisie joojoo.

Étendons un peu cette question:

J'ai accès à un système Windows, donc si je dois utiliser des outils pour aider à répondre à la question, c'est très bien. Je peux aussi l'essayer sur des systèmes avec et sans l'utilitaire de configuration. Le résultat final attendu reste toutefois de rendre ces clés utilisables sous Linux.

Je réalise également qu'il s'agit d'une famille de matériel très spécifique. Je serais prêt à tester tout ce qui a du sens sur un système Linux si j'ai des instructions détaillées - cela devrait ouvrir la question aux personnes ayant des compétences en Linux, mais n'ayant pas accès à ce clavier.

Le résultat final minimum dont j'ai besoin:

J'ai besoin que ces clés soient détectées et utilisables de manière quelconque sur toutes les variantes graphiques actuelles d'Ubuntu; elles doivent naturellement fonctionner avec mon clavier. Un cookie virtuel et des accessoires fous s’il s’agit de quelque chose de bien emballé et utilisable par l’utilisateur moyen.

J'aurai besoin d'un code compilé qui fonctionnera sur mon système ou d'une source que je peux compiler (avec des instructions plus complexes que ./configure, make, make install) si des logiciels supplémentaires ne se trouvent pas dans les référentiels Ubuntu pour la version LTS actuelle ou standard l'heure de la réponse. J'aurai également besoin d'informations suffisantes pour répliquer et utiliser avec succès les clés de mon propre système.

49
Journeyman Geek

Les touches M1-M5 sont en fait des clés ordinaires - elles doivent simplement être spécifiquement activées avant de les presser pour générer un scancode. Tux_mark_5 a développé un petit programme Haskell qui envoie le message SET_REPORT correct aux claviers Razer pour activer ces clés, et ex-parrot a porté le même code vers Python.

Sur les systèmes Arch Linux, le port Python a été empaqueté et est disponible à partir de https://aur.archlinux.org/packages.php?ID=60518 .

Sur les systèmes Debian ou Ubuntu, configurer le port Python du code est relativement facile. Vous devez installer PyUSB et libusb (en tant que root):

    aptitude install python-usb

Ensuite, récupérez le fichier blackwidow_enable.py à partir de http://finch.am/projects/blackwidow/ et exécutez-le (également en tant que root):

    chmod +x blackwidow_enable.py
    ./blackwidow_enable.py

Cela permettra d'activer les touches jusqu'à ce que le clavier soit débranché ou que la machine soit redémarrée. Pour rendre cette tâche permanente, appelez le script à partir du style de script de démarrage que vous préférez. Pour des instructions sur la manière de configurer cela dans Debian, jetez un œil à la documentation Debian .

Pour utiliser le code Haskell de Tux_mark_5, vous devez installer Haskell et le compiler vous-même. Ces instructions concernent un système de type Debian (y compris Ubuntu).

  1. Installez GHC, libusb-1.0-0-dev et cabal (en tant que root):

    aptitude install ghc libusb-1.0-0-dev cabal-install git pkg-config
    
  2. Récupérer la liste des paquets:

    cabal update
    
  3. Installez les liaisons USB pour Haskell (pas besoin de root):

    cabal install usb
    
  4. Téléchargez l'utilitaire:

    git clone git://github.com/tuxmark5/EnableRazer.git
    
  5. Construisez l'utilitaire:

    cabal configure
    cabal build
    
  6. Exécutez l'utilitaire (également en tant que root):

    ./dist/build/EnableRazer/EnableRazer
    

Ensuite, vous pouvez copier le binaire EnableRazer où vous voulez et l'exécuter au démarrage.

Immédiatement après l'exécution, le serveur X doit afficher M1 comme XF86Tools, M2 comme XF86Launch5, M3 comme XF86Launch6, M4 comme XF86Launch7 et M5 comme XF86Launch8. Les événements pour FN sont également émis.

Ces clés peuvent être liées dans xbindkeys ou les paramètres système de KDE à des actions arbitraires.

Étant donné que votre clavier peut être différent, vous devrez peut-être modifier l'ID du produit dans la ligne 64 de Main.hs:

withDevice 0x1532 0x<HERE GOES YOUR KEYBOARD's PRODUCT ID> $ \dev -> do
43
tux_mark_5

Razer semble forcer son configurateur basé sur le cloud Synapse 2 sur tous les utilisateurs, avec la mise à niveau du micrologiciel correspondante vers la version 2. *. Une fois le micrologiciel mis à niveau, vous ne pouvez plus revenir en arrière (le clavier est complètement branché si vous essayez de le flasher avec un micrologiciel plus ancien).

Les "octets magiques" du programme Haskell dans La réponse de Tux_mark_5 ne fonctionnera pas avec le dernier firmware. Au lieu de cela, le pilote envoie ces octets au cours de la séquence d’initialisation: "0200 0403". Celles-ci activent les touches de macro, mais le clavier entre dans un mode particulier dans lequel, au lieu du protocole HID standard, il envoie des paquets de 16 octets (sans doute pour augmenter le nombre de touches pouvant être enfoncées simultanément). Le système Linux HID ne peut pas tout à fait gérer cela, et alors que la plupart des clés fonctionnent comme prévu, les clés de macro restent non reconnues: le pilote HID ne fournit aucune donnée à la couche d’entrée lorsqu’elles sont pressées.

Pour que votre clavier passe en mode hérité (dans lequel les touches de macro envoient les codes XF86Launch * et la touche FN envoie le code 202), envoyez les octets suivants: 0200 0402.

Le paquet complet sera:

00000000 00020004 02000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 0400

Voici un programme très dur et sale que j'ai écrit en Python 3, moins ésotérique, pour effectuer cette tâche. Notez le code pour générer les paquets de contrôle Razer dans blackwidow.bwcmd () et les commandes du logo du logo Razer en bonus :)

#!/usr/bin/python3

import usb
import sys

VENDOR_ID = 0x1532  # Razer
PRODUCT_ID = 0x010e  # BlackWidow / BlackWidow Ultimate

USB_REQUEST_TYPE = 0x21  # Host To Device | Class | Interface
USB_REQUEST = 0x09  # SET_REPORT

USB_VALUE = 0x0300
USB_INDEX = 0x2
USB_INTERFACE = 2

LOG = sys.stderr.write

class blackwidow(object):
  kernel_driver_detached = False

  def __init__(self):
    self.device = usb.core.find(idVendor=VENDOR_ID, idProduct=PRODUCT_ID)

    if self.device is None:
      raise ValueError("Device {}:{} not found\n".format(VENDOR_ID, PRODUCT_ID))
    else:
      LOG("Found device {}:{}\n".format(VENDOR_ID, PRODUCT_ID))

    if self.device.is_kernel_driver_active(USB_INTERFACE):
      LOG("Kernel driver active. Detaching it.\n")
      self.device.detach_kernel_driver(USB_INTERFACE)
      self.kernel_driver_detached = True

    LOG("Claiming interface\n")
    usb.util.claim_interface(self.device, USB_INTERFACE)

  def __del__(self):
    LOG("Releasing claimed interface\n")
    usb.util.release_interface(self.device, USB_INTERFACE)

    if self.kernel_driver_detached:
      LOG("Reattaching the kernel driver\n")
      self.device.attach_kernel_driver(USB_INTERFACE)

    LOG("Done.\n")

  def bwcmd(self, c):
    from functools import reduce
    c1 = bytes.fromhex(c)
    c2 = [ reduce(int.__xor__, c1) ]
    b = [0] * 90
    b[5: 5+len(c1)] = c1
    b[-2: -1] = c2
    return bytes(b)

  def send(self, c):
    def _send(msg):
      USB_BUFFER = self.bwcmd(msg)
      result = 0
      try:
        result = self.device.ctrl_transfer(USB_REQUEST_TYPE, USB_REQUEST, wValue=USB_VALUE, wIndex=USB_INDEX, data_or_wLength=USB_BUFFER)
      except:
        sys.stderr.write("Could not send data.\n")

      if result == len(USB_BUFFER):
        LOG("Data sent successfully.\n")

      return result

    if isinstance(c, list):
      #import time
      for i in c:
        print(' >> {}\n'.format(i))
        _send(i)
        #time.sleep(.05)
    Elif isinstance(c, str):
        _send(c)

###############################################################################

def main():
    init_new  = '0200 0403'
    init_old  = '0200 0402'
    pulsate = '0303 0201 0402'
    bright  = '0303 0301 04ff'
    normal  = '0303 0301 04a8'
    dim     = '0303 0301 0454'
    off     = '0303 0301 0400'

    bw = blackwidow()
    bw.send(init_old)

if __== '__main__':
    main()
22
Sergey

Peut-être que ceci pourrait éclairer un peu la question (de la page de manuel de showkey):

Dans les noyaux 2.6, le mode brut, ou mode scancode, n’est pas très brut du tout. Les codes de numérisation sont d'abord traduits en codes de clé, et lorsque des codes à balayage sont souhaités, les codes de clé sont reconvertis. Diverses transformations sont impliquées et rien ne garantit que le résultat final correspond à ce que le matériel du clavier a envoyé. Donc, si vous voulez connaître les codes d'analyse envoyés par différentes clés, il est préférable de démarrer un noyau 2.4. Depuis la version 2.6.9, l’option de démarrage atkbd.softraw = 0 indique également au noyau 2.6 de renvoyer les codes d’analyse réels.

Les codes de balayage bruts ne sont disponibles que sur les claviers AT et PS/2, et même dans ce cas, ils sont désactivés, sauf si le paramètre de noyau atkbd.softraw = 0 est utilisé. Lorsque les codes d'analyse bruts ne sont pas disponibles, le noyau utilise un tableau intégré fixe pour générer des codes d'analyse à partir de codes clés. Ainsi, setkeycodes (8) peut affecter la sortie de showkey en mode de vidage du code de balayage.

Je suis sur le point de voir si showkey dumpera quelque chose avec les touches de macro une fois que cette option de démarrage est définie.

EDIT: Après le redémarrage, aucun succès, mais je cherchais à capturer une entrée brute à partir des périphériques USB eux-mêmes. J'ai noté ce qui suit, intéressant (j'ai un Razer Diamondback ainsi que BlackWidow):

[root@kestrel by-id]# pwd
/dev/input/by-id
[root@kestrel by-id]# ls
usb-Razer_Razer_BlackWidow_Ultimate-event-kbd    usb-Razer_Razer_Diamondback_Optical_Mouse-event-mouse
usb-Razer_Razer_BlackWidow_Ultimate-event-mouse  usb-Razer_Razer_Diamondback_Optical_Mouse-mouse
usb-Razer_Razer_BlackWidow_Ultimate-mouse
[root@kestrel by-id]#

Cependant, l'utilisation de dd pour capturer une entrée brute fonctionne sur les deux souris Diamondback, sur le périphérique event-kbd, mais pas sur les souris BlackWidow.

J'imagine qu'ils ne génèrent peut-être aucune sortie tant qu'ils ne sont pas activés par les pilotes installés. Cependant, je ne connais pas grand chose à propos de Linux USB, alors je ne sais même pas si cela a du sens. Peut-être ont-ils besoin d'être liés en premier?

Eh bien, les trois périphériques Black Widow sont notés dans /proc/bus/input/devices, mais ils ne semblent pas être énumérés dans lsusb ou /proc/bus/usb/devices. Je ne sais pas comment accéder à ces périphériques pour tenter de les lier ou de communiquer avec eux de quelque manière que ce soit.

event4 semble correspondre au clavier actuel, event6 avec les touches de macro, mais je ne peux toujours pas capturer leurs entrées. J'espère que tout a aidé.

   [root@kestrel input]# ls
devices  handlers
[root@kestrel input]# cat handlers
N: Number=0 Name=kbd
N: Number=1 Name=mousedev Minor=32
N: Number=2 Name=evdev Minor=64
N: Number=3 Name=rfkill
[root@kestrel input]# pwd
/proc/bus/input
[root@kestrel input]# cat devices
I: Bus=0019 Vendor=0000 Product=0001 Version=0000
N: Name="Power Button"
P: Phys=PNP0C0C/button/input0
S: Sysfs=/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0C0C:00/input/input0
U: Uniq=
H: Handlers=kbd event0 
B: EV=3
B: KEY=10000000000000 0

I: Bus=0019 Vendor=0000 Product=0001 Version=0000
N: Name="Power Button"
P: Phys=LNXPWRBN/button/input0
S: Sysfs=/devices/LNXSYSTM:00/LNXPWRBN:00/input/input1
U: Uniq=
H: Handlers=kbd event1 
B: EV=3
B: KEY=10000000000000 0

I: Bus=0017 Vendor=0001 Product=0001 Version=0100
N: Name="Macintosh mouse button emulation"
P: Phys=
S: Sysfs=/devices/virtual/input/input2
U: Uniq=
H: Handlers=mouse0 event2 
B: EV=7
B: KEY=70000 0 0 0 0
B: REL=3

I: Bus=0003 Vendor=1532 Product=010d Version=0111
N: Name="Razer Razer BlackWidow Ultimate"
P: Phys=usb-0000:00:12.1-3/input0
S: Sysfs=/devices/pci0000:00/0000:00:12.1/usb4/4-3/4-3:1.0/input/input4
U: Uniq=
H: Handlers=kbd event4 
B: EV=120013
B: KEY=1000000000007 ff9f207ac14057ff febeffdfffefffff fffffffffffffffe
B: MSC=10
B: LED=7

I: Bus=0003 Vendor=1532 Product=010d Version=0111
N: Name="Razer Razer BlackWidow Ultimate"
P: Phys=usb-0000:00:12.1-3/input1
S: Sysfs=/devices/pci0000:00/0000:00:12.1/usb4/4-3/4-3:1.1/input/input5
U: Uniq=
H: Handlers=kbd event5 
B: EV=1f
B: KEY=837fff002c3027 bf00444400000000 1 c040a27c000 267bfad941dfed 9e000000000000 0
B: REL=40
B: ABS=100000000
B: MSC=10

I: Bus=0003 Vendor=1532 Product=010d Version=0111
N: Name="Razer Razer BlackWidow Ultimate"
P: Phys=usb-0000:00:12.1-3/input2
S: Sysfs=/devices/pci0000:00/0000:00:12.1/usb4/4-3/4-3:1.2/input/input6
U: Uniq=
H: Handlers=mouse2 event6 
B: EV=17
B: KEY=70000 0 0 0 0
B: REL=103
B: MSC=10

I: Bus=0003 Vendor=1532 Product=0002 Version=0110
N: Name="Razer Razer Diamondback Optical Mouse"
P: Phys=usb-0000:00:12.1-2/input0
S: Sysfs=/devices/pci0000:00/0000:00:12.1/usb4/4-2/4-2:1.0/input/input9
U: Uniq=
H: Handlers=mouse1 event3 
B: EV=17
B: KEY=7f0000 0 0 0 0
B: REL=103
B: MSC=10

[root@kestrel input]# 
8
srmaddox

Ma solution est pour le clavier de jeu mécanique Razer BlackWidow 2013 (numéro de modèle: RZ03-0039) et a été testé sur openSUSE 12.3.

J'ai utilisé Google Traduction sur ce lien .

Fondamentalement, il utilise la version modifiée de @ La réponse de Sergey pour cette question, mais avec de simples modifications:

  1. Mon PRODUCT_ID = 0x011b

  2. Sur mon openSUSE 12.3, python-usb n’est pas disponible pour Python 3, j’ai donc converti ce script pour qu’il fonctionne avec Python 2 en supprimant la méthode bwcmd et en définissant le USB_BUFFER = ... comme dans le lien de @ réponse de Tux_mark_5 .


Pour plus de commodité, voici le contenu de mon /usr/local/sbin/init_blackwidow.py:

#!/usr/bin/python

"""This is a patched version of Sergey's code form
https://superuser.com/a/474595/8647

It worked for my Razer BlackWidow 2013 Mechanical Gaming Keyboard
(Model Number: RZ03-0039).

"""
import usb
import sys

VENDOR_ID = 0x1532       # Razer
PRODUCT_ID = 0x011b      # BlackWidow 2013 Mechanical Gaming Keyboard

USB_REQUEST_TYPE = 0x21  # Host To Device | Class | Interface
USB_REQUEST = 0x09       # SET_REPORT

USB_VALUE = 0x0300
USB_INDEX = 0x2
USB_INTERFACE = 2

USB_BUFFER = b"\x00\x00\x00\x00\x00\x02\x00\x04\x02\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00"

LOG = sys.stderr.write


class blackwidow(object):
    kernel_driver_detached = False

    def __init__(self):
        self.device = usb.core.find(idVendor=VENDOR_ID, idProduct=PRODUCT_ID)

        if self.device is None:
            raise ValueError("Device {}:{} not found\n".format(VENDOR_ID, PRODUCT_ID))
        else:
            LOG("Found device {}:{}\n".format(VENDOR_ID, PRODUCT_ID))

        if self.device.is_kernel_driver_active(USB_INTERFACE):
            LOG("Kernel driver active. Detaching it.\n")
            self.device.detach_kernel_driver(USB_INTERFACE)
            self.kernel_driver_detached = True

        LOG("Claiming interface\n")
        usb.util.claim_interface(self.device, USB_INTERFACE)

    def __del__(self):
        LOG("Releasing claimed interface\n")
        usb.util.release_interface(self.device, USB_INTERFACE)

        if self.kernel_driver_detached:
            LOG("Reattaching the kernel driver\n")
            self.device.attach_kernel_driver(USB_INTERFACE)

        LOG("Done.\n")

    def send(self, c):
        def _send(msg):
            result = 0
            try:
                result = self.device.ctrl_transfer(USB_REQUEST_TYPE, USB_REQUEST, wValue=USB_VALUE, wIndex=USB_INDEX, data_or_wLength=USB_BUFFER)
            except:
                sys.stderr.write("Could not send data.\n")

            if result == len(USB_BUFFER):
                LOG("Data sent successfully.\n")

            return result

        if isinstance(c, list):
            for i in c:
                print(' >> {}\n'.format(i))
                _send(i)
        Elif isinstance(c, str):
            _send(c)


def main():
    init_new = '0200 0403'
    init_old = '0200 0402'
    pulsate  = '0303 0201 0402'
    bright   = '0303 0301 04ff'
    normal   = '0303 0301 04a8'
    dim      = '0303 0301 0454'
    off      = '0303 0301 0400'

    bw = blackwidow()
    bw.send(init_old)


if __== '__main__':
    main()

... et mon /etc/udev/rules.d/99-razer-balckwidow.rules est:

SUBSYSTEM=="usb", ACTION=="add", ATTR{idVendor}=="1532", ATTR{idProduct}=="011b", RUN+="/usr/local/sbin/init_blackwidow.py"
7
Chen Levy

Peut-être que ce document vous aidera:

Le HOWTO clavier et console Linux, Programmes utiles

2
ascobol

Voir Razer Key Mapper pour Linux.

Cela fonctionne avec les macros de tous les périphériques Razer, moyennant certaines modifications du code. Si vous n'avez toujours pas de solution et que votre appareil ne figure pas dans la liste, je serais ravi de vous aider à configurer votre appareil et à l'ajouter à ma liste prise en charge.

1
Camille Guay