2010-05-13 3 views
4

EDIT - ne pas avoir beaucoup d'entrées sur ceci, voici donc le skinny. Je poste des événements de clavier sur un PSN. Je passe ensuite à une autre fenêtre, j'envoie d'autres événements (cette fois-ci au niveau de la session tat) et je retourne à la première fenêtre. Quand je commence à poster sur le PSN, rien ne se passe. Jusqu'à ce que je bouge la souris ou la molette de défilement. Pourquoi cela serait-il le cas et comment puis-je contourner le problème (si ce n'est pas le cas)?Comportement étrange lors de la publication de CGEvent sur PSN

ORIGINAL - Si je configure une boucle qui enregistre certains événements de clavier sur un PSN, je trouve que cela fonctionne correctement, sauf lors du premier lancement. L'événement semble seulement afficher quand je fais quelque chose avec la souris manuellement - même juste en le déplaçant légèrement. Voici les détails, s'ils aident.

Une application externe possède une zone de liste de lignes de texte, que je suis en train de lire en affichant des commandes de copie (et en vérifiant la table de montage). Malheureusement, c'est mon seul moyen d'obtenir ce texte. Parfois, l'application retire le focus de la liste, que je peux détecter. Lorsque cela se produit, la manière la plus fiable de renvoyer le focus est d'envoyer un événement souris pour cliquer sur un champ de texte directement au-dessus de la liste, puis d'envoyer un événement clavier 'tabulation' pour déplacer le focus sur la liste. Donc, au lancement, la boucle tourne bien, en faisant défiler la liste et en copiant le texte. Lorsque la mise au point est décalée, elle est détectée correctement et les événements sont envoyés pour revenir à la liste. Mais rien ne semble arriver. La boucle continue de détecter que le focus a changé, mais les événements ne fonctionnent que lorsque je déplace la souris. Ou même simplement utiliser la molette de défilement. Étrange.

Une fois que cela s'est produit la première fois, cela fonctionne bien - chaque fois que le focus se déplace, les événements PSN le renvoient sans que je doive faire quoi que ce soit.

Voici le code qui fonctionne dans la boucle - vérifiée comme travail:

//copy to pasteboard - CMD-V 
e3 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)8, true); 
CGEventSetFlags(e3, kCGEventFlagMaskCommand); 
CGEventPostToPSN(&psn, e3); 
CFRelease(e3); 
e4 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)8, false); 
CGEventPostToPSN(&psn, e4); 
CFRelease(e4); 

//move cursor down 
e1 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)125, true); 
CGEventPostToPSN(&psn, e1); 
CFRelease(e1); 
e2 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)125, false); 
CGEventPostToPSN(&psn, e2); 
CFRelease(e2); 

Et voici où je passe le focus, de travail (sauf lors nécessaire) aussi:

//click in text input box - point is derived earlier 
e6 = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, point, 0); 
CGEventPostToPSN(&psn, e6); 
CFRelease(e6); 
e7 = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseUp, point, 0); 
CGEventPostToPSN(&psn, e7); 
CFRelease(e7); 

//press tab key to move to chat log table 
CGEventRef e = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)48, true); 
//CGEventPost(kCGSessionEventTap, e); 
CGEventPostToPSN(&psn, e); 
CFRelease(e); 
CGEventRef e11 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)48, false); 
CGEventPostToPSN(&psn, e11); 
CFRelease(e11); 
+0

Comment basculez-vous entre les fenêtres, et les deux fenêtres sont-elles dans la même application? – drawnonward

+0

Les deux fenêtres sont dans la même application. J'utilise AXUIElementSetAttributeValue (myWindow, kAXMainAttribute, kCFBooleanTrue); –

Répondre

2

Hey, i sais que ce n'est pas ce que vous voulez entendre mais applescript fonctionne beaucoup mieux pour ce genre de choses - lire des champs de texte en postant des commandes de copie, mettre au point en envoyant des événements de clic aux objets proches puis en envoyant des événements de tabulation - ce n'est pas la meilleure façon de faire il. Le problème avec la simulation d'événements est que leur génération n'est pas l'histoire entière. Ils ne deviennent "Evénements" que si l'application cible les interprète correctement. Savez-vous si l'application cible est même une application de cacao? Par exemple, dans votre deuxième bit de code, vous créez 4 événements. L'application cible doit exécuter sa boucle de traitement des événements, sur laquelle vous n'avez pas beaucoup de contrôle, et vérifier les événements mis en file d'attente. Si c'était le cas, il trouverait une souris simultanée vers le bas, la souris vers le haut, la touche vers le bas, la touche vers le haut. Vous voulez qu'il interprète ces événements simultanés comme un clic de souris et ALORS une touche ... mais qui va le dire?

Vous pourrez peut-être obtenir ce travail en ajoutant dans le mélange une combinaison de files d'attente d'événements de rinçage, obtenir l'application cible à terme, il est runloop, jeter quelques pauses entre les événements simulés, et tripoter timestamps événement - mais il ne sera probablement pas fiable.

En AppleScript, vous pouvez obtenir le texte de la ligne 3 d'une table dans une autre application par

tell application "System Events" 
    tell process targetAppName 
    set frontmost to true 
    tell window named windowTitle 
     tell table 1 
     set value of attribute "AXFocused" to true 
     set txtField to first text field of row 3 
     return value of txtField 
     end tell 
    end tell 
    end tell 
end tell 

D'un cacao App vous pouvez exécuter une chaîne comme AppleScript, vous pouvez appeler des fonctions dans différents scripts, passe les variables, les valeurs de retour, etc.

+0

Je ne peux pas utiliser applescript pour ça. Comme je l'ai mentionné, il n'y a pas d'autre moyen - je peux expliquer pourquoi si vous êtes dérangé. Merci néanmoins pour l'info. –

+1

Ouais, je suis intéressé, je fais des choses similaires. Juste pour clarifier .. Quand je dis utiliser Applescript - je veux dire (ou aurait pu facilement signifier) ​​à partir d'une application Cocoa. – hooleyhoop

+0

AppleScript n'a aucun privilège ici, System Events.app utilise CGPostKeyboardEvent. –

1

au lieu de créer l'événement avec un CGEventSourceRef null essayez de créer une source d'entrée de cette façon:

CGEventSourceRef eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); 

sur la base de cette mailing list message, cela semble être le secret du succès de la publication d'événements avec CGEventCreateXXXEvent. Une recherche Google montre que beaucoup de développeurs ont des problèmes avec cela, mais c'est le seul succès que j'ai trouvé, et un CGEventSourceRef (au lieu de NULL) semble être la seule différence dans cet exemple par rapport à tous les autres. J'ai trouvé. Il a résolu mes problèmes avec l'affichage des événements de clavier.