53 votes

Faire fonctionner les touches macro d'un Razer BlackWidow sous Linux

J'ai pris un Razer BlackWidow Ultimate qui possède des touches supplémentaires destinées aux macros qui sont définies à l'aide d'un qui est installé sur Windows . Je suppose qu'il ne s'agit pas de touches joojoo fantaisistes et qu'elles devraient émettre des scancodes comme n'importe quelles autres touches.

Tout d'abord, existe-t-il un moyen standard de vérifier ces scancodes sous Linux ? Deuxièmement, comment puis-je configurer ces touches pour faire des choses en ligne de commande et dans les configurations Linux basées sur X ? Mon installation Linux actuelle est Xubuntu 10.10, mais je vais passer à Kubuntu une fois que j'aurai réglé quelques problèmes. Idéalement, la réponse devrait être générique et s'appliquer à l'ensemble du système.

Les choses que j'ai essayées jusqu'à présent :

Choses à essayer

  • snoopy pro + rétro-ingénierie (oh là là)

  • Wireshark - des essais préliminaires semblent indiquer qu'aucun scancode n'est émis lorsque ce que je pense être le clavier est surveillé et que des touches sont pressées. Cela pourrait indiquer que les touches supplémentaires sont un périphérique séparé ou qu'elles doivent être initialisées d'une manière ou d'une autre.

  • Il faut croiser ces données avec la sortie lsusb de Linux, dans trois scénarios : autonome, transmis à une VM Windows sans les pilotes installés, et la même chose avec.

  • LSUSB ne détecte qu'un seul périphérique sur une installation Linux autonome

  • 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é, ne semble fonctionner que pour les souris)

Les choses que j'ai résolues :

  • Dans un système Windows équipé du pilote, le clavier est considéré comme un clavier a un dispositif de pointage. Le dispositif de pointage utilise - en plus des pilotes de souris standard - un pilote pour un dispositif appelé Razer Synapse.

  • Pilote de souris sous Linux sous evdev y lsusb ainsi que

  • Un seul appareil sous OS X apparemment, mais je n'ai pas encore essayé. lsusb équivalent sur ce point

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

  • Il s'agit en fait de clés joojoo de fantaisie.

Je prolonge un peu cette question :

J'ai accès à un système Windows, donc si j'ai besoin d'utiliser des outils sur ce système pour répondre à la question, c'est parfait. Je peux également l'essayer sur des systèmes avec et sans l'utilitaire de configuration. Le résultat final attendu est toujours de rendre ces clés utilisables sous Linux.

Je suis également conscient 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 qui ont des compétences en matière de Linux, mais qui n'ont 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 en tous La mode sur n'importe laquelle des variantes graphiques actuelles d'Ubuntu, et je dois naturellement travailler avec mon clavier. Le cookie virtuel et les encouragements 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 si c'est plus complexe que ./configure , make , make install ) si un logiciel supplémentaire ne se trouve pas dans les dépôts Ubuntu pour la version LTS actuelle ou la version standard du bureau au moment de la réponse. J'aurai également besoin d'informations suffisantes pour reproduire et utiliser avec succès les clés sur mon propre système.

45voto

Akash Points 41

M1-M5 sont en fait des touches normales - elles ont juste besoin d'être activées spécifiquement pour qu'une pression sur elles génère 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 touches, et ex-parrot a porté le même code en Python.

Sur les systèmes Arch Linux, le portage Python a été empaqueté et est disponible à l'adresse suivante https://aur.archlinux.org/packages.php?ID=60518 .

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

    aptitude install python-usb

Saisissez ensuite le blackwidow_enable.py à partir de http://finch.am/projects/blackwidow/ et l'exécuter (également en tant que root) :

    chmod +x blackwidow_enable.py
    ./blackwidow_enable.py

Cela activera les touches jusqu'à ce que le clavier soit débranché ou que la machine soit redémarrée. Pour rendre cela permanent, appelez le script à partir du style de script de démarrage que vous préférez. Pour des instructions sur la manière de mettre en place ceci dans Debian, jetez un coup d'oeil à la page Documentation Debian .

Pour utiliser le code Haskell de tux_mark_5, vous devrez installer Haskell et compiler le code vous-même. Ces instructions sont valables pour un système de type Debian (y compris Ubuntu).

  1. Installer 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. Installer les bindings USB pour Haskell (pas besoin d'être root) :

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

    git clone git://github.com/tuxmark5/EnableRazer.git
  5. Construire le service public :

    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 le lancer au démarrage.

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

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

Comme votre clavier peut être différent, il se peut que vous deviez modifier l'ID du produit dans Main.hs ligne 64 :

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

24voto

Sergey Points 341

Razer semble imposer son configurateur Synapse 2 basé sur le cloud à tous les utilisateurs, avec la mise à jour du firmware vers la version 2.* qui l'accompagne. Une fois que vous avez mis à jour le firmware, vous ne pouvez plus revenir en arrière (le clavier est complètement brické si vous essayez de le flasher avec l'ancien firmware).

Les "octets magiques" du programme Haskell en Réponse de tux_mark_5 ne fonctionne pas avec le dernier firmware. Au lieu de cela, le pilote envoie ces octets pendant la séquence d'initialisation : '0200 0403'. Ceux-ci activent les touches macro, mais le clavier entre dans un mode particulier dans lequel, au lieu du protocole HID standard, il envoie des paquets de 16 octets (probablement pour augmenter le nombre de touches pouvant être pressées simultanément). Le système HID de Linux ne peut pas vraiment gérer cela, et bien que la plupart des touches fonctionnent comme prévu, les touches macro ne sont pas reconnues : le pilote HID ne transmet aucune donnée à la couche d'entrée lorsqu'elles sont pressées.

Pour que votre clavier entre dans le mode legacy (dans lequel les touches macro envoient les keycodes XF86Launch*, et la touche FN envoie le keycode 202), envoyez ces octets : 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 rudimentaire que j'ai écrit en Python 3, moins ésotérique, pour réaliser cette tâche. Notez le code pour générer les paquets de contrôle Razer dans blackwidow.bwcmd() et les commandes LED 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 __name__ == '__main__':
    main()

8voto

srmaddox Points 81

Ceci pourrait peut-être éclairer le problème (tiré de la page de manuel showkey) :

Dans les noyaux 2.6, le mode brut, ou mode scancode, n'est pas du tout brut. Les codes de balayage sont d'abord traduits en codes clés, et lorsque des scancodes sont souhaités, les codes clés sont retraduits. Diverses transformations sont nécessaires, et il n'y a aucune garantie que le résultat final corresponde à ce que le matériel du clavier a envoyé. Par conséquent, si vous souhaitez connaître les codes de balayage envoyés par les différentes touches, il est préférable de démarrer un noyau 2.4. Depuis la version 2.6.9, il existe également l'option de démarrage atkbd.softraw=0 qui indique au noyau 2.6 de renvoyer les codes de balayage 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 à moins que le paramètre de noyau atkbd.softraw=0 ne soit utilisé. Lorsque les codes de balayage bruts ne sont pas disponibles, le noyau utilise une table fixe intégrée pour produire des codes de balayage à partir des codes de touches. Ainsi, setkeycodes(8) peut affecter la sortie de showkey en mode scan code dump.

Je suis sur le point de voir si le showkey va faire sortir quelque chose avec les touches macro après que cette option de démarrage soit activée.

EDIT : Après le redémarrage, pas de succès, mais j'ai cherché à capturer l'entrée brute des périphériques USB eux-mêmes. J'ai noté ce qui suit, de manière intéressante (j'ai un Razer Diamondback ainsi que le 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 l'entrée brute fonctionne sur les deux souris diamondback, sur le périphérique event-kbd, mais pas sur les souris BlackWidow.

Je suppose qu'ils ne génèrent aucune sortie tant qu'ils ne sont pas activés d'une manière ou d'une autre par les pilotes installés. Je ne connais pas grand-chose à l'USB Linux, donc je ne sais pas si cela a un sens. Peut-être faut-il d'abord les lier ?

Les trois dispositifs de la veuve noire sont mentionnés dans le document /proc/bus/input/devices Cependant, ils ne semblent pas être énumérés dans la base de données de l lsusb o /proc/bus/usb/devices . Je ne sais pas comment accéder à ces dispositifs pour tenter de les lier ou de les interfacer d'une manière ou d'une autre.

event4 semble correspondre au clavier réel, event6 aux touches macro, mais je ne peux toujours pas capturer d'entrée à partir de celles-ci. J'espère que cela vous 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]#

7voto

Gu1234 Points 101

Ma solution consiste à Razer BlackWidow 2013 Mechanical Gaming Keyboard (Numéro de modèle : RZ03-0039) et a été testé sur openSUSE 12.3.

J'ai utilisé Google Translate sur 本リンク .

Il utilise essentiellement la version modifiée de Réponse de @Sergey pour cette question, mais avec des modifications simples :

  1. Mi 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 l'élément bwcmd et a défini la méthode USB_BUFFER = ... comme dans le lien de Réponse de @tux_mark_5 .


Par souci 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 __name__ == '__main__':
    main()

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

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

2voto

Christopher Points 446

Ce document vous aidera peut-être :

Le clavier et la console Linux HOWTO , Programmes utiles

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X