2012-07-05 3 views
2

Il m'a donc été demandé de porter certaines applications d'aide interne vers Mac OS X 10.7. Fonctionne très bien car le code dépendant de la plate-forme est minime de toute façon, mais une application a besoin d'un raccourci pour fonctionner (RegisterHotkey fonctionnalité) et je ne trouve aucune documentation sur la façon dont je ferais cela sur un Mac .raccourci système pour Mac OS X

Le programme utilise un outil PyQt avec Python 3.2. et le code correspondant pour Windows est essentiellement:

def register_hotkey(self): 
    hwnd = int(self.winId()) 
    modifiers, key = self._get_hotkey() 
    user32.RegisterHotKey(hwnd, self._MESSAGE_ID, modifiers, key) 

puis de recevoir les événements Hotkey:

def winEvent(self, msg): 
    if msg.message == w32.WM_HOTKEY: 
     self.handle_hotkey() 
     return True, id(msg) 
    return False, id(msg) 

Notez que je ne suis pas besoin d'une variante de python, je peux facilement écrire une simple extension de c - Les solutions C/Objective-C sont donc les bienvenues.

Répondre

8

J'ai récemment codé un extension à quodlibet capturant des clés multimédia (depuis absorbé dans quodlibet lui-même); pour votre configuration, le même processus s'applique.

J'ai utilisé la boucle CGEventTapCreate hook de Quartz et la structure Cocoa AppKit pour déchiffrer les codes clés pour y parvenir.

Le code suivant enregistre un rappel de python qui est passé touches globales, et lance la boucle d'événement:

import Quartz 
from AppKit import NSKeyUp, NSSystemDefined, NSEvent 

# Set up a tap, with type of tap, location, options and event mask 
tap = Quartz.CGEventTapCreate(
    Quartz.kCGSessionEventTap, # Session level is enough for our needs 
    Quartz.kCGHeadInsertEventTap, # Insert wherever, we do not filter 
    Quartz.kCGEventTapOptionListenOnly, # Listening is enough 
    Quartz.CGEventMaskBit(NSSystemDefined), # NSSystemDefined for media keys 
    keyboardTapCallback, 
    None 
) 

runLoopSource = Quartz.CFMachPortCreateRunLoopSource(None, tap, 0) 
Quartz.CFRunLoopAddSource(
    Quartz.CFRunLoopGetCurrent(), 
    runLoopSource, 
    Quartz.kCFRunLoopDefaultMode 
) 
# Enable the tap 
Quartz.CGEventTapEnable(tap, True) 
# and run! This won't return until we exit or are terminated. 
Quartz.CFRunLoopRun() 

je définissais un robinet pour les clés définis par le système uniquement (touches multimédias); vous devrez spécifier un masque d'événement différent (CGEventMaskBit avec un ou plusieurs Event Types); par exemple. Quartz.CGEventMaskBit(Quartz.kCGEventKeyUp) pour les événements key up.

Le rappel doit avoir la signature suivante (il implémente le CGEventTapCallBack method from the Quartz API:

def keyboardTapCallback(proxy, type_, event, refcon): 
    # Convert the Quartz CGEvent into something more useful 
    keyEvent = NSEvent.eventWithCGEvent_(event) 

I converti l'événement à quartz dans un NSEvent, parce que toutes les informations que je pouvais trouver sur les touches multimédias Mac faisait référence à cette classe. En principe, vous pouvez obtenir la même chose avec les API AppKit, mais votre application Python est traitée comme une application Mac (visible dans le Dock avec une icône et tout), alors que je voulais que cela reste dans le fond complètement

+0

Merci, ressemble exactement à ce dont j'ai besoin. J'ai compilé pyobjc pour Python3 (légèrement plus encombrant que prévu), mais lors de l'exécution du code, il m'indique que l'attribut 'AttributeError:' module 'n'a pas d'attribut' CGEventTapCreate''. pyobjc devrait fonctionner avec python3, alors je manque quelque chose ou l'API n'est-elle pas complètement portée? – Voo

+0

@Voo: Désolé, aucune idée; J'ai seulement travaillé avec python 2.7 et pyobjc. –

+2

Débogué le problème un peu le matin et l'a réparé. Le plat à emporter est: python3 et pyobjc n'est vraiment pas recommandé, mais on peut le faire fonctionner. Et c'était certainement moins de travail que d'apprendre le framework cacao ou de rétroporter l'application sur python2. Merci encore pour l'aide. – Voo

1

En utilisant la puissance de Google, je trouve this snippet of code, qui permet l'enregistrement des raccourcis clavier globaux pour Mac OS X

Vous aurez besoin d'ajouter le cadre Carbon, et probablement un casting pour ARC comblé lors du passage de l'objectif -C pointeur auto vers la fonction C.

Au minimum, vous aurez également besoin de:

#import <Carbon/Carbon.h> 

Les keycodes peuvent être vus on this page explaining the virtual key codes.