2010-05-29 14 views
4

J'utilise Quartz CGEventTap pour tenter d'intercepter globalement les appuis sur les majuscules et les bloquer (pour les faire faire quelque chose d'utile à la place). Je détecte avec succès les presses de capslock, mais j'ai été jusqu'à présent incapable de les bloquer. Mon code (provenant de this stackoverflow réponse) est quelque chose comme ceci:Impossible de bloquer le verrouillage des majuscules avec CGEventTap

eventTap = CGEventTapCreate(kCGHIDEventTap, 
          kCGTailAppendEventTap, 
          kCGEventTapOptionDefault, 
          eventMask, 
          myCGEventCallback, 
          &oldFlags); 

runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0); 

CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes); 
CGEventTapEnable(eventTap, true); 

CGEventRef myCGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef theEvent, void *refcon) 
{ 
    CGEventFlags *oldFlags = (CGEventFlags *)refcon; 

    switch (type) 
    { 
     case kCGEventFlagsChanged: 
     { 
      CGEventFlags newFlags = CGEventGetFlags(theEvent); 
      CGEventFlags changedFlags = *oldFlags^newFlags; 
      *oldFlags = newFlags; 

      if (changedFlags == 65536) 
      { 
       NSLog(@"Capslock pressed. Let's not return the event"); 
       return NULL; 
      } 
      break; 
     } 
     default: 
      break; 
    } 

    NSLog(@"Different modifier than capslock. Returning the event"); 
    return theEvent; 
} 

Si je comprends correctement le retour NULL devrait bloquer efficacement la propagation de keypress. En effet, il le fait également pour les événements "normal" de keyup et de downdown. Cependant, le verrouillage des majuscules change indépendamment. Des idées pourquoi c'est? Est-ce que je fais des hypothèses incorrectes? Et/ou comment puis-je faire les choses différemment pour atteindre mon objectif?

Merci,

Thor

Répondre

8

Vous ne pouvez pas bloquer capslock comme ça. Capslock est une condition, qui est gérée par le pilote du clavier, et non par le serveur Windows ou les applications individuelles. Un événement keypress se propage dans OS X comme ça:

Clavier Pilote -> Windows Server -> Session utilisateur -> Active Application

A chaque propagation de niveau (indiqué par "->") vous pouvez placer un événement robinet et bloquer et/ou modifier les événements clés. Keyboard Driver et Window Server sont deux composants privilégiés, les deux autres sont des composants de niveau utilisateur normal.

Le plus tôt vous pouvez attraper un événement de clavier est lorsque l'événement se propage du pilote (espace de noyau) au serveur de fenêtre (espace utilisateur, mais toujours privilégié). Cependant, comme indiqué ci-dessus, l'état de verrouillage est géré de manière interne dans le pilote, attrapant ainsi un événement qui est déjà trop tard. Le pilote aura déjà activé le voyant de verrouillage sur le clavier (si nécessaire et ne sera pas exécuté par le matériel lui-même) et se souviendra que l'état du verrouillage est activé, ce qui aura un effet sur toutes les futures frappes de touches.

Vous pouvez désactiver la lumière de verrouillage par programme pour les périphériques HID (Apple a même sample code for that), mais cela ne désactivera pas la fonction de verrouillage, il éteindra simplement la lumière. La seule façon d'implémenter cette fonction en utilisant les taps d'événement est de réécrire manuellement chaque touche avec une fonction de verrouillage à une touche sans caplock (celle où l'indicateur de verrouillage n'est pas défini et la lettre attachée, le cas échéant, minuscule). De plus, pour ne pas perturber l'utilisateur, vous devez éteindre la lumière de verrouillage comme indiqué par l'exemple de code d'Apple. D'autres alternatives sont: Écrivez votre propre pilote de clavier, qui prend le contrôle du clavier au lieu du pilote standard d'Apple (pas aussi difficile que vous le pensez, mais toujours assez dur) ou de vous frayer un chemin dans le pilote (mal, mais travaux). Par exemple. certains raccourcis clavier ne remplacent que des méthodes simples du pilote (les pilotes sont C++ dans OS X, donc ils sont OO-objets et vous pouvez remplacer dynamiquement les méthodes C++ à l'exécution, pas vraiment les surcharger, mais manipuler les tables de méthodes). Les problèmes avec ces deux solutions sont: Le premier signifie qu'à moins que votre pilote soit aussi bon que celui d'Apple, certains claviers USB peuvent ne pas fonctionner avec votre pilote, tandis que d'autres le font, le second signifie que si vous faites une erreur, le Le système punit cette erreur avec une panique du noyau. Je cherche moi-même un moyen de basculer par programme le verrouillage de caps sur Mac, sans succès jusqu'à présent. Mais je peux vous assurer, les robinets d'événement ne sont pas la voie à suivre.

+0

Merci pour votre réponse complète. –

+0

Je sais que je suis un peu en retard, mais avez-vous réussi à basculer le verrouillage des majuscules? – sidyll

+1

@sidyll: Il semble que vous ne pouvez pas faire cela. Pas même via une API privée.Vous pouvez utiliser une API privée pour que le système remappe le verrouillage des majuscules à une autre clé du pilote, mais aucune touche n'est possible (Apple en expose certaines dans les touches de modification du clavier prefs->, mais d'autres mappages sont possibles). . Si vous avez vraiment besoin d'un contrôle total de cette clé, vous devez écrire une propre extension de noyau; Vous pouvez utiliser ce projet open source comme une bonne référence comment en démarrer un: http://tinyurl.com/ykywauk – Mecki