This question is a follow up from a very old post:
CGEventPost - hold a key (shift)
I am building a SwiftUI virtual keyboard. Like a real keyboard, I have UIButtons that resemble the hardware buttons ( key a, s, d, etc ) which the user can click with their mouse. The user can also toggle to keep a button pressed.
I can send keyDown events using a function below, but an unable to keep a keyboard key held down. Inferring that my users want to hold every button until released, how would I send a CGEvent that would tell the macOS that the key with keyCode == a is being held by the user?
private func pressButton(_ keyCode: UInt16) {
// create a key down event
let eventDown = CGEvent(keyboardEventSource: nil, virtualKey: keyCode, keyDown: true)
// post the key down event
eventDown?.post(tap: .cghidEventTap)
}
I tried intentionally only setting the keyDown event without the keyUp event ( as seen in the above function ), but I get an equivalent of a button press as opposed to hold. I also tried to use timers to fire the pressButton method periodically to keep sending button down events, but ran into the issue of "the events are being sent too fast or too slow", in comparison what would happen if i were to hold that specific button on my keyboard.
A useful thread: Simulate keypress using Swift
Related
I have an NSView with several NSButton and one NSSlider in it.
I am watching keyCode Events with [NSEvent addLocalMonitorForEventsMatchingMask:...handler:^{}] and change the buttons appearance with .highlighted=YES && NO.
I chose this handler method because I have to act on quite unusual event.keyCode combinations that can not be expressed via [NSButton setKeyEquivalent:(NSString * _Nonnull)] and/or [NSButton setKeyEquivalentModifierMask:(NSEventModifierFlags)].
All works quite well and smooth (all keys can be pressed at once, singular or in any combination) unless NSSlider comes into play for which i use traditional event handling with a predefined Action on a Target.
Symptom: The Slider slides nice until I hit any Key and slides again when lifting Keys.
Or the other way around, when I hit a Key and want to slide, the Slider just does not slide at all.
I hope i just ran into some edge case of NSResponder and NSEvent handling in general and can learn something. My goal is to be able to press any key while dragging freely with the slider at the same time.
So how can i achieve congruent Event Handling/Executing between Keycodes and MouseEvents of KeyEquivalent NSButtons and native modifierFlag changing behaviour of NSSliders in one and the same NSView?
There are two problems that clash.
NSSlider have special behaviour when ⌥ key is down.
And [NSEvent addLocalMonitorForEventsMatchingMask:...handler:^{ }] with a mask set to catch NSEventMaskFlagsChanged will cancel each others functionality out when the flag returns nil into the Responder chain.
The modifierFlags to step NSSlider up and down with its altIncrementValue or other special behaviour in combination with other modifierFlags can not work properly when it never reaches the NSView's action method.
Releasing the key lets the Slider slide again, Keys where useless then.
Pressing a key (specially a flag) sets the NSSlider in stepwise increment mode but its mouse events are dumped as they where not catched from LocalMonitor which was focused on KeyCode events only.
So the solution is to explicit check for event.type == NSEventTypeLeftMouseDown and for sure subclassing NSSlider to change this interferences with flags or to implement a different NSControl imposing as slider.
I handle pressing of letter keys on keyboard with the following code.
NSEvent.addGlobalMonitorForEvents(matching: NSEvent.EventTypeMask.keyDown) { event in
// code
}
How do I then mark the NSEvent as handled, not allowing it to be handled again by system and another apps? For example do not allow the input of a pressed letter in the opened text editor?
You can't do that with NSEvent. As the docs note:
Events are delivered asynchronously to your app and you can only observe the event; you cannot modify or otherwise prevent the event from being delivered to its original target application.
You're not part of the event-generation system; you're just getting notifications as part of your runloop.
If you want to become part of the event system, below the app layer, you need to use CGEvent. See tapCreate(tap:place:options:eventsOfInterest:callback:userInfo:). The callback can return NULL to indicate it's consumed the event.
I'm writing a game in Swift 3 for Mac OS. I'd like to be able to do "as long as the A key is down, move to the left". In other environments I'm used to a function like KeyIsDown('A'), but I can't find it here.
Does it exist, or do I need to watch every keydown and keyup event and keep track of the state myself? I will be wanting to do this for arrow keys as well as alphabetic keys.
Kudos to BallpointPen, for a clear answer. So I'll just keep a table of key state for every keycode, and switch bits on an off as keyDown and keyUp events come in.
Depending on you use UITextview or UITextfield. So, conforming UITextviewDegelate or UITextfieldDegalate there are some degelate methods that can change keyboard state.
I'm not sure if this is the right place to ask this question. It's not an application specific question nor it is about any concrete problem. However, to make it more application specific, I'll take the example of Photoshop.
The shortcut to reduce the brush size is [. When I keep it pressed, the brush size reduces quickly with some inertia. I wanted to know how this is implemented. Does it send the keypress event multiple times or does it send the keypress event along with the key down duration, to which the application responds according to the duration?
I suppose this also depends on the OS? I want to know more specifically OSX.
I don't know what's the behavior on OS X, but this article shows some ways how you can find it out by yourself (without reading the developer manuals):
Super User: Mouse button and keypress counter for Mac OS X
On Windows and .NET and "Windows Forms" as the development platform, the behavior would be
MSDN: System.Windows.Forms → KeyPressEventArgs Class
...A KeyPress event occurs when the user presses a key. Two events that are closely related to the KeyPress event are KeyUp and KeyDown. The KeyDown event precedes each KeyPress event when the user presses a key, and a KeyUp event occurs when the user releases a key. When the user holds down a key, duplicate KeyDown and KeyPress events occur each time the character repeats. One KeyUp event is generated upon release...
See also:
MSDN: System.Windows.Input → Keyboard Attached Events
Application code typically handles all three events, while the KeyPress is actually computed from the down/up signals. Because it mimics the signals received from hardware (see http://wiki.osdev.org/Keyboard for more details) which is OS-neutral I'd expect the OS-APIs to be conceptually very similar
How would we know if "Delete" button on key board is pressed in GWT?
i tried keydown handler ,key press but i cant find methods like "isDeleteKeyDown()".
Thanks
If the keydown event is firing properly for you on press of delete then you can compare the keycode to figure out if the delete key has been pressed. Basically,
if(event.getNativeKeyCode() == KeyCodes.KEY_DELETE)
{ // Delete key pressed, do you stuff }