Écrire un EventTap. La documentation peut être found here.
Dans Mac OS X chaque événement (par exemple, chaque touche du clavier enfoncée, toutes les touches de la souris mouvement pressé ou la souris) crée un événement qui parcourt le chemin suivant:
Driver (Kernel) -> Window Server (privileged) -> User (Login) Session -> Active Application
Partout où j'ai écrit une flèche (->
) un EventTap peut être placé pour regarder uniquement l'événement (une seule EventTap d'écoute) ou pour modifier ou supprimer l'événement (un EventTap de filtrage d'événements). S'il vous plaît noter que pour attraper un événement entre Driver et WindowServer, votre démon doit fonctionner avec les privilèges root.
Voici quelques exemples de code:
// Compile with:
// gcc -framework ApplicationServices -o MouseWatcher MouseWatcher.c
//
// Start with:
// ./MouseWatcher
//
// Terminate by hitting CTRL+C
#include <ApplicationServices/ApplicationServices.h>
static CGEventRef myEventTapCallback (
CGEventTapProxy proxy,
CGEventType type,
CGEventRef event,
void * refcon
) {
CGPoint mouseLocation;
// If we would get different kind of events, we can distinguish them
// by the variable "type", but we know we only get mouse moved events
mouseLocation = CGEventGetLocation(event);
printf(
"Mouse is at x/y: %ld/%ld\n",
(long)mouseLocation.x,
(long)mouseLocation.y
);
// Pass on the event, we must not modify it anyway, we are a listener
return event;
}
int main (
int argc,
char ** argv
) {
CGEventMask emask;
CFMachPortRef myEventTap;
CFRunLoopSourceRef eventTapRLSrc;
// We only want one kind of event at the moment: The mouse has moved
emask = CGEventMaskBit(kCGEventMouseMoved);
// Create the Tap
myEventTap = CGEventTapCreate (
kCGSessionEventTap, // Catch all events for current user session
kCGTailAppendEventTap, // Append to end of EventTap list
kCGEventTapOptionListenOnly, // We only listen, we don't modify
emask,
&myEventTapCallback,
NULL // We need no extra data in the callback
);
// Create a RunLoop Source for it
eventTapRLSrc = CFMachPortCreateRunLoopSource(
kCFAllocatorDefault,
myEventTap,
0
);
// Add the source to the current RunLoop
CFRunLoopAddSource(
CFRunLoopGetCurrent(),
eventTapRLSrc,
kCFRunLoopDefaultMode
);
// Keep the RunLoop running forever
CFRunLoopRun();
// Not reached (RunLoop above never stops running)
return 0;
}
La réponse de Dave est la plus belle façon de cacao de faire à peu près la même chose; Fondamentalement Cocoa fait la même chose que je fais dans mon exemple ci-dessus dans les coulisses, juste enveloppé dans une méthode statique. Le code de Dave ne fonctionne que sur 10.6, cependant, ce qui précède fonctionne dans 10.4, 10.5 et 10.6.
Mais fonctionne seulement avec 10,6, alors que mon code fonctionne même avec 10,4 et plus :-P – Mecki
@Mecki oui, c'est la seule mise en garde. Si l'affiche peut cibler 10.6 exclusivement, alors un moniteur global est définitivement plus facile. Sinon, il aura besoin d'un robinet d'événement. –
Merci pour l'info. J'ai essayé d'ajouter le code de Dave à mon application, mais j'obtiens une erreur de compilation indiquant que NSEvent peut ne pas répondre à mouseLocation et que NSStringFromPoint reçoit un argument non valide. Quel est le signe avant le (NSEvent * mouseEvent) ?? Est-ce le problème? Je ne suis pas familier avec cette syntaxe ... Étant donné que je ne peux pas essayer cela, laissez-moi demander, cela me donnera-t-il les données brutes de la souris? Fondamentalement, même si la souris est ancrée dans le coin supérieur gauche, j'ai besoin de savoir que l'utilisateur a continué à le déplacer vers le haut et à gauche, que ce soit le cas. Est-ce que cela va accomplir cela? Merci encore! – Raconteur