2016-12-01 1 views
4

Je souhaite limiter le mouvement de la souris à une zone rectangulaire spécifique de l'écran sous OS X 10.11. J'ai modifié un code de MouseTools (ci-dessous) pour le faire, mais il est nerveux quand vous touchez le bord de l'écran. Comment puis-je me débarrasser de cette gigue?Contraindre le mouvement de la souris à la région sous OS X sans gigue

// gcc -Wall constrain.cpp -framework ApplicationServices -o constrain 

#include <ApplicationServices/ApplicationServices.h> 

int main (int argc, const char * argv[]) { 
    if(argc != 5) { 
     printf("Usage: constrain left top right bottom\n"); 
     return 0; 
    } 
    int leftBound = strtol(argv[1], NULL, 10); 
    int topBound = strtol(argv[2], NULL, 10); 
    int rightBound = strtol(argv[3], NULL, 10); 
    int bottomBound = strtol(argv[4], NULL, 10); 
    CGEventTapLocation tapLocation = kCGHIDEventTap; 
    CGEventSourceRef sourceRef = CGEventSourceCreate(kCGEventSourceStatePrivate); 
    while(true) { 
     CGEventRef mouseEvent = CGEventCreate(NULL); 
     CGPoint mouseLoc = CGEventGetLocation(mouseEvent); 
     int x = mouseLoc.x, y = mouseLoc.y; 
     if(x < leftBound || x > rightBound || y < topBound || y > bottomBound) { 
      if(x < leftBound) x = leftBound; 
      if(x > rightBound) x = rightBound; 
      if(y < topBound) y = topBound; 
      if(y > bottomBound) y = bottomBound; 
      CGEventRef moveMouse = CGEventCreateMouseEvent(sourceRef, kCGEventMouseMoved, CGPointMake(x, y), 0); 
      CGEventPost(tapLocation, moveMouse); 
      CFRelease(moveMouse); 
     } 
     CFRelease(mouseEvent); 
     usleep(8*1000); // 8ms, ~120fps 
    } 
    CFRelease(sourceRef); 
    return 0; 
} 

Voici quelques autres choses que j'essayées: Receiving, Filtering, and Modifying Mouse Events montre comment créer un rappel pour les mouvements de souris en utilisant CGEventTapCreate. Dans le code, il est dit "Nous pouvons changer certains aspects de l'événement souris, par exemple, nous pouvons utiliser CGEventSetLocation(event, newLocation)." Malheureusement, cela ne change pas réellement l'emplacement de la souris (compléter l'exemple here). Les seules façons dont j'ai été en mesure de changer l'emplacement de la souris sont en faisant un CGEventPost ou CGWarpMouseCursorPosition. J'ai également essayé d'utiliser kCGHIDEventTap au lieu de kCGSessionEventTap, et j'ai vérifié que j'avais des autorisations super utilisateur et l'accessibilité activée pour l'application. Il semble que cela devrait fonctionner car il existe un autre exemple de modifying key presses qui fonctionne correctement. Au lieu d'utiliser CGEventSetLocation j'ai également essayé d'utiliser CGEventSetIntegerValueField (comme dans l'exemple du clavier) pour définir les deltas x et y à 0, mais cela n'a rien changé.

Enfin, j'ai également essayé d'utiliser CGEventPost et CGWarpMouseCursorPosition à l'intérieur du CGEventCallback, la "bordure invisible" est encore plus nerveux que le code ci-dessus.

+0

La description de votre problème est détaillée. Personne ne se soucie de ce que vous avez fait avec un programme AppleScript sauf si vous avez un problème avec celui-ci. –

+1

@ElTomato J'ai rendu le problème moins bavard en supprimant les deux phrases expliquant ma première tentative avec AppleScript et le problème que j'avais avec lui. En supposant que vous savez quelque chose sur ce sujet, j'aimerais avoir vos commentaires sur la question mise à jour. Merci! –

+0

À qui le mouvement de la souris va-t-il être contraint? Toute personne utilisant votre ordinateur ou l'utilisateur de votre application? –

Répondre

3

J'ai implémenté ceci pour Wine dans le pilote Mac. Ça devient un peu compliqué.

L'approche consiste à désactiver fondamentalement le mouvement du curseur de la souris en appelant CGAssociateMouseAndMouseCursorPosition(false). Ce droit atteint ici ce que vous voulez si le rectangle contraignant est le rectangle 1x1 à l'emplacement actuel du curseur. En plus de cela, j'utilise un événement tap pour observer les événements de déplacement de la souris. Ceux-ci ne changent pas de position mais ont les deltas de ce que l'utilisateur a tenté de faire. J'utilise ensuite CGWarpMouseCursorPosition() pour déplacer le curseur en fonction de ces deltas et ajuster les événements avant de les transmettre.

Notez que les informations d'emplacement dans les événements de la souris ne sont pas significatives. Ce sera vicié. Certains événements auront été placés en file d'attente avant votre dernière distorsion et auront donc un ancien emplacement. Vous devez suivre où se trouve le curseur. Il commence où que ce soit lorsque vous l'avez dissocié de la souris et change à chaque fois que vous le déformez. Vous ajoutez les deltas à cela (pas à l'emplacement de l'événement), coupez le dans le rectangle de contrainte et utilisez-le comme nouvelle position pour l'événement et pour le warp. Pour le prochain événement, vous commencerez à partir de cette nouvelle position. Etc

Il y a une autre ride malheureuse. CGWarpMouseCursorPosition() affecte les valeurs delta des événements de déplacement de souris suivants. Fondamentalement, la distance que vous avez déformé le curseur est ajoutée au premier événement de déplacement de la souris qui est mis en file d'attente après la distorsion. Si elle n'est pas cochée, les mouvements de la souris de l'utilisateur seront doublés avec chaque événement pour une boucle de retour et le curseur se déclenchera à l'extrême ou à l'extrême. Donc, vous devez garder une trace des déformations que vous effectuez, quand vous les avez exécutées, et à quel point elles ont changé la position. Puis, à mesure que les événements passent par le robinet, vous comparez leur temps aux temps de distorsion. Pour toutes les déformations antérieures à l'événement en cours, soustrayez leur changement de position des deltas de l'événement et supprimez-les de la liste.

+0

Merci Ken. Ce que vous décrivez semble être la meilleure solution possible. Et merci pour votre travail sur Wine pour Mac! –