问题描述
我想在不实际单击鼠标的情况下模拟对Cocoa应用程序的鼠标单击,并且*在给定当前鼠标位置的情况下,不必弄清楚应该对单击做出响应的视图.
I would like to simulate a mouse click on a Cocoa application without actually clicking the mouse, and* not have to figure out which view should respond to the click, given the current mouse location.
我希望Cocoa框架能够弄清楚哪个视图应该响应,所以我不认为我要找的是对NSView对象的方法调用.也就是说,我认为我需要一个方法调用,最终将调用此方法.
I would like the Cocoa framework to handle figuring out which view should respond, so I don't think that a method call on an NSView object is what I'm looking for. That is, I think I need a method call that will end up calling this method.
我目前正在通过使用CGEventCreateMouseEvent和CGEventPost在特定的全局位置单击鼠标来完成此工作.但是,此技术实际上是单击鼠标的.所以这行得通,但是我对这种行为并不完全满意.例如,如果在调用CGEventPost时按住键盘上的某个键,则该键将包装到事件中.另外,如果我将另一个进程的窗口移到要模拟单击的窗口上,则CGEventPost方法将在该窗口中单击鼠标.也就是说,它在跨流程的全球范围内发挥作用.我想要一种可以在单个窗口上运行的技术.可能是NSWindow对象上的东西?
I currently have this working by clicking the mouse at a particular global location, using CGEventCreateMouseEvent and CGEventPost. However, this technique actually clicks the mouse. So this works, but I'm not completely happy with the behavior. For example, if I hold down a key on the keyboard while the CGEventPost is called, that key is wrapped into the event. Also, if I move another process's window over the window that I'd like to simulate the click, then the CGEventPost method will click the mouse in that window. That is, it's acting globally, across processes. I'd like a technique that works on a single window. Something on the NSWindow object maybe?
我在Cocoa文档中读到鼠标事件由NSWindow对象调度到发生该事件的NSView对象".
I read that "Mouse events are dispatched by an NSWindow object to the NSView object over which the event occurred" in the Cocoa documentation.
好.因此,我想知道执行调度的方法.在窗口上调用此方法,然后在给定当前鼠标位置的情况下,让框架找出要调用的NSView.
OK. So I'd like to know the method that is called to do the dispatching. Call this method on the window, and then let the framework figure out which NSView to call, given the current mouse location.
任何帮助将不胜感激.我刚刚开始学习Cocoa框架,因此,如果这里的任何术语/措辞都不正确,我深表歉意.
Any help would be greatly appreciated. I'm just starting to learn the Cocoa framework, so I apologize if any of the terminology/verbage here isn't quite right.
推荐答案
很难确切地知道您要寻找多少保真度以及实际点击所发生的情况.例如,您是否希望单击激活应用程序?您是否希望通过单击将窗口带到顶部?要使其成为关键还是主要?如果该位置在标题栏中,您是否希望它可能关闭,最小化,缩放或移动窗口?
It's hard to know exactly how much fidelity you're looking for with what happens for an actual click. For example, do you want the click to activate the app? Do you want the click to bring a window to the top? To make it key or main? If the location is in the title bar, do you want it to potentially close, minimize, zoom, or move the window?
正如John Caswell所指出的,如果将适当构造的NSEvent
传递给-[NSApplication sendEvent:]
,则它将紧密模拟真实事件的处理.在大多数情况下,NSApplication
会将事件转发到事件的窗口及其-[NSWindow sendEvent:]
方法.如果您想避免NSApplication
做其他事情的任何机会,则可以直接分派到窗口的-sendEvent:
方法.但这可能会挫败某些理想的行为,具体取决于您的需求.
As John Caswell noted, if you pass an appropriately-constructed NSEvent
to -[NSApplication sendEvent:]
that will closely simulate the processing of a real event. In most cases, NSApplication
will forward the event to the event's window and its -[NSWindow sendEvent:]
method. If you want to avoid any chance of NSApplication
doing something else, you could dispatch directly to the window's -sendEvent:
method. But that may defeat some desirable behavior, depending on exactly what you desire.
如果单击的窗口或视图的响应是运行内部事件跟踪循环,会发生什么?这将是同步的;也就是说,调用-sendEvent:
的代码要在该循环完成之后才能重新获得控制权,并且如果您无法传递后续事件,则可能无法完成控制.实际上,这样的循环将通过-[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:]
查找后续事件,因此,如果您的综合事件不在队列中,则不会看到它们.因此,要更好地模拟真实事件,可能需要使用-[NSApplication postEvent:atStart:]
将事件(鼠标向下移动,鼠标拖动,鼠标向上移动)发布到队列中.
What happens if the clicked window's or view's response is to run an internal event-tracking loop? It's going to be synchronous; that is, the code that calls -sendEvent:
is not going to get control back until after that loop has completed and it might not complete if you aren't able to deliver subsequent events. In fact, such a loop is going to look for subsequent events via -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:]
, so if your synthetic events are not in the queue, they won't be seen. Therefore, an even better simulation of the handling of real events would probably require that you post events (mouse-down, mouse drags, mouse-up) to the queue using -[NSApplication postEvent:atStart:]
.
我认为您的首要任务是真正地深入思考您要完成的任务,所有潜在的陷阱和极端情况,并决定如何处理这些问题.
I think your first task is to really think deeply about what you're trying to accomplish, all the potential pitfalls and corner cases, and decide how you want to handle those.
关于CGEvent...
内容,您可以使用CGEventPostToPSN()
将事件发布到特定进程,并且该事件不会单击其他应用程序的窗口,即使它们位于目标窗口的前面.但是,它仍可能在目标应用程序内单击其他窗口.
With respect to the CGEvent...
stuff, you can post an event to a specific process using CGEventPostToPSN()
and that won't click on other app's windows, even if they are in front of the target window. However, it may still click on a different window within the target app.
这篇关于模拟在NSWindow中的鼠标单击的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!