Catch Capslock press in Cocoa application - macos

I’m working on an application that uses the great MASShortcut repository by Shpakovski. I reference this to ask if there is a way to register a shortcut for Capslock in the same way that Shpakovski does in his repository?
It seems that I can’t register 0xffff (Key Codes shows this as Capslock) as a valid shortcut. Even if I combine it with the modifier keys. I also want to catch the press before it toggles the system’s Capslock functionality.
I’m aware that I could listen to all keystrokes and just catch the Capslock when it occurs but I want to avoid this behaviour since I feel it’s potentially insecure and will also decrease the overall system performance.
Edit: I already took a look at some working C++ / C# libraries for Windows which implement this feature. They seem to override the system’s Capslock flag continuously which I found pretty odd. I’m basically having 2 problems here:
1. How to catch the Capslock press without having a keystroke listener all the time
2. How to do so without triggering the system’s Capslock functionality.

One possibility could be to overwrite sendEvent: in your NSApplication delegate. From Apples documentation:
You rarely invoke sendEvent: directly, although you might want to
override this method to perform some action on every event. sendEvent:
messages are sent from the main event loop (the run method).
sendEvent: is the method that dispatches events to the appropriate
responders—NSApp handles application events, the NSWindow object
indicated in the event record handles window-related events, and mouse
and key events are forwarded to the appropriate NSWindow object for
further dispatching.
You could evaluate if the current event has the modifier key pressed and act upon that.
Edit:
For background processing Quartz event taps can be used. If that leads to a rejection, I don't know.

Related

GTK4 under rust, trying to find which mouse pointer and whether there are modifer keys pressed

I'm writing a gtk4 application in rust, and I'd like to get the mouse key that was clicked and any modifier keys at the time. My GestureClick handler has .buttons(0) to accept input from all buttons, but the event object does not seem to have any way to determine the source of the event. The event just gives the GestureClick object, location, and click count. Does it need to have a separate handler for each button?
In addition, I'd like to use modifier keys like shift and ctrl to modify the action. This does not seem to be available (at least, I haven't been able to find it). Would I need to monitor keypress events to keep track of the state myself? I'm pretty sure X reports the state of the modifier keys on click events, gtk doesn't?
Thanks

Implementing a Custom Cocoa Event Tracking Loop

I'm working on a custom cross platform UI library that needs a synchronous "ShowPopup" method that shows a popup, runs an event loop until it's finished and automatically cancels when clicking outside the popup or pressing escape. Keyboard, mouse and scroll wheel events need to be dispatched to the popup but other events (paint, draw, timers etc...) need to be dispatched to their regular targets while the loop runs.
Edit: for clarification, by popup, I mean this kind of menu style popup window, not an alert/dialog etc...
On Windows I've implemented this fairly simply by calling GetMessage/DispatchMessage and filtering and dispatching messages as appropriate. Works fine.
I've much less experience with Cocoa/OS X however and finding the whole event loop/dispatch paradigm a bit confusing. I've seen the following article which explains how to implement a mouse tracking loop which is very similar to what I need:
http://stpeterandpaul.ca/tiger/documentation/Cocoa/Conceptual/EventOverview/HandlingMouseEvents/chapter_5_section_4.html
but... there's some things about this that concern me.
The linked article states: "the application’s main thread is unable to process any other requests during an event-tracking loop and timers might not fire". Might not? Why not, when not, how to make sure they do?
The docs for nextEventMatchingMask:untilDate:inMode:dequeue: states "events that do not match one of the specified event types are left in the queue.". That seems a little odd. Does this mean that if an event loop only asks for mouse events then any pressed keys will be processed once the loop finishes? That'd be weird.
Is it possible to peek at a message in the event queue without removing it. eg: the Windows version of my library uses this to close the popup when it's clicked outside, but leaves the click event in the queue so that clicking outside the popup on a another button doesn't require a second click.
I've read and re-read about run loop modes but still don't really get it. A good explanation of what these are for would be great.
Are there any other good examples of implementing an event loop for a popup. Even better would be pseudo-code for what the built in NSApplication run loop does.
Another way of putting all this... what's the Cocoa equivalent of Windows' PeekMessage(..., PM_REMOVE), PeekMessage(..., PM_NOREMOVE) and DispatchMessage().
Any help greatly appreciated.
What exactly is a "popup" as you're using the term? That term means different things in different GUI APIs. Is it just a modal dialog window?
Update for edits to question:
It seems you just want to implement a custom menu. Apple provides a sample project, CustomMenus, which illustrates that technique. It's a companion to one of the WWDC 2010 session videos, Session 145, "Key Event Handling in Cocoa Applications".
Depending on exactly what you need to achieve, you might want to use an NSAlert. Alternatively, you can use a custom window and just run it modally using the -runModalForWindow: method of NSApplication.
To meet your requirement of ending the modal session when the user clicks outside of the window, you could use a local event monitor. There's even an example of just such functionality in the (modern, current) Cocoa Event Handling Guide: Monitoring Events.
All of that said, here are (hopefully no longer relevant) answers to your specific questions:
The linked article states: "the application’s main thread is unable to process any other requests during an event-tracking loop and
timers might not fire". Might not? Why not, when not, how to make
sure they do?
Because timers are scheduled in a particular run loop mode or set of modes. See the answer to question 4, below. You would typically use the event-tracking mode when running an event-tracking loop, so timers which are not scheduled in that mode will not run.
You could use the default mode for your event-tracking loop, but it really isn't a good idea. It might cause unexpected re-entrancy.
Assuming your pop-up is similar to a modal window, you should probably use NSModalPanelRunLoopMode.
The docs for nextEventMatchingMask:untilDate:inMode:dequeue:
states "events that do not match one of the specified event types are
left in the queue.". That seems a little odd. Does this mean that if
an event loop only asks for mouse events then any pressed keys will be
processed once the loop finishes? That'd be weird.
Yes, that's what it means. It's up to you to prevent that weird outcome. If you were to read a version of the Cocoa Event Handling Guide from this decade, you'd find there's a section on how to deal with this. ;-P
Is it possible to peek at a message in the event queue without removing it. eg: the Windows version of my library uses this to close
the popup when it's clicked outside, but leaves the click event in the
queue so that clicking outside the popup on a another button doesn't
require a second click.
Yes. Did you notice the "dequeue:" parameter of nextEventMatchingMask:untilDate:inMode:dequeue:? If you pass NO for that, then the event is left in the queue.
I've read and re-read about run loop modes but still don't really get it. A good explanation of what these are for would be great.
It's hard to know what to tell you without knowing what you're confused about and how the Apple guide failed you.
Are you familiar with handling multiple asynchronous communication channels using a loop around select(), poll(), epoll(), or kevent()? It's kind of like that, but a bit more automated. Not only do you build a data structure which lists the input sources you want to monitor and what specific events on those input sources you're interested in, but each input source also has a callback associated with it. Running the run loop is like calling one of the above functions to wait for input but also, when input arrives, calling the callback associated with the source to handle that input. You can run a single turn of that loop, run it until a specific time, or even run it indefinitely.
With run loops, the input sources can be organized into sets. The sets are called "modes" and identified by name (i.e. a string). When you run a run loop, you specify which set of input sources it should monitor by specifying which mode it should run in. The other input sources are still known to the run loop, but just ignored temporarily.
The -nextEventMatchingMask:untilDate:inMode:dequeue: method is, more or less, running the thread's run loop internally. In addition to whatever input sources were already present in the run loop, it temporarily adds an input source to monitor events from the windowing system, including mouse and key events.
Are there any other good examples of implementing an event loop for a popup. Even better would be pseudo-code for what the built in
NSApplication run loop does.
There's old Apple sample code, which is actually their implementation of GLUT. It provides a subclass of NSApplication and overrides the -run method. When you strip away some stuff that's only relevant for application start-up or GLUT, it's pretty simple. It's just a loop around -nextEventMatchingMask:... and -sendEvent:.

Respond immediately to textarea changes in Dart

I've got this in my html file:
<textarea id="inputbox" placeholder="type here"></textarea>
What's the correct way to wire up a handler that will fire immediately whenever the content of the textarea changes? (whether by keyboard, mouse/clipboard, speech input, brainwave reader, etc)
I tried:
query("#inputbox").on.change.add(handler)
but (at least on Dartium) it only fires after you tab out of the field.
The purpose is to update a "live preview" window, similar to the way Stackoverflow renders Markdown output while you type.
This is the best I came up with so far. I'd be happy to hear if anyone knows of a more compact or preferable alternative.
Edit: Code snippet updated to the new pattern for event registration.
import 'dart:html';
void main() {
query("#inputbox")
..onChange.listen(handler)
..onKeyDown.listen(handler)
..onKeyUp.listen(handler)
..onCut.listen(handler)
..onPaste.listen(handler);
}
void handler(Event event) {
print((query("#inputbox") as TextAreaElement).value);
}
The precise behavior will vary between browsers and operating systems.
You could skip keyDown, but be aware keyDown and keyUp behavior is influenced by the OS and isn't guaranteed to be symmetric. You might conceivably miss a change, at least until the next keyUp or change event gets fired. Indeed I proved this out by creating a little app on Windows 7 to send an orphan WM_KEYDOWN message to Dartium and IE9.
keyPress could be used instead of keyUp and keyDown, but won't generate events for certain keys like backspace and delete.
cut and paste react immediately to a cut or paste performed with the mouse. If you don't use them, the change event will capture the change, but not until after the field loses focus, or sometimes even later.
The input event could replace all listeners above and seems to work great in Dartium, but under IE9 it only captures character additions, not removals.
Note keyUp and keyDown may generate additional unwanted events for cursor keys, home, end, shift, etc. (e.g. In IE9). It will fire in addition to the cut/paste listeners when the user uses shortcut keys for those actions.
While the question is specific to Dart, a lot of the discussion above applies to any code listening to the DOM. Even keyCode values aren't standardized across browsers (more detail).
It may also be worthwhile checking out the KeyboardEventController class, though by and large when I tested it the edge case behavior was similar to that noted above. That may or may not be by design. The Dart developers do make some effort to insulate you from cross-browser inconsistencies, but it's still a work in progress.
Also while we're talking about textarea, remember to use its value property, not its text property. Finally, be sure your handler throttles its reactions to "bursts" of keyboard activity (e.g. some sort of timer that briefly defers the guts of your handler and rolls up any additional events which occur in the meantime).
Related questions and links:
Handle events in DART
Handling Keyboard events in Dart Language
How do you listen for a keyUp event in Dart?
Cross browser key event handler in Dart
jQuery example that skips keyboard events and binds to propertychange
Its not clear if you are using polymer or not, but if you are, you can subscribe to a change to a variable annotated with #observable by creating a function in the polymer element in the form as [variable name]Changed(oldvalue). I originally found this here: How to subscribe to change of an observable field

block ALL keyboard access, mouse access and keyboard shortcut events

In order to block ALL keyboard access, mouse access and keyboard shortcut events in one of my projects, I:
Created a full screen transparent borderless window, in front of other windows, but invisible.
Handle all keyboard and mouse events with simple return; the window itself.
Make the window modal [NSApp runModalForWindow:myWindow] in order to block keyboard shortcuts.
Release window from touchpad's gesture events only.
But this guy made it look simple in a tiny app -MACIFIER:
How did he do it?
not really sure if this would be usable, but you could use the program hotkeynet (generally used for gaming, but I have had success using other methods) and map every single key/mouse action to do nothing. I did something similar by blocking access to a specific program with it in about 20-30 minutes.
not sure if it will help; but it might be the solution you need?
I believe you can use Quartz Event Services. In particular, have a look at CGEventTapCreate, and note the 4th parameter, which allows you to specify what kinds of events you'd like to intercept. The available kinds of events are listed in the CGEventType enum.
If you set your tap to be an active filter, returning NULL from the callback will delete the event.

What is the difference between the Control.Enter and Control.GotFocus events?

This may be a basic question, but I have to admit I've never truly understood what the difference between the Control.Enter and Control.GotFocus events is.
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.enter.aspx
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.gotfocus.aspx
Is it a differentiation between capturing keyboard or mouse input or something else?
The GotFocus/LostFocus events are generated by Windows messages, WM_SETFOCUS and WM_KILLFOCUS respectively. They are a bit troublesome, especially WM_KILLFOCUS which is prone to deadlock. The logic inside Windows Forms that handles the validation logic (Validating event for example) can override focus changes. In other words, the focus actually changed but then the validation code moved it back. The logical state of your UI is that it never moved and you shouldn't be aware that it did.
The Enter/Leave events avoid the kind of trouble these low-level focus change notification events can cause, they are generated when Winforms has established the true focus. You almost always want to use these.
Control.Enter event happens when a control gets focus for the first time. While Control.GotFocus happens EVERY time a control gets focus. For example, you have 'textBox1' that already has focus and you call textBox1.Focus(), the GotFocus event will always fire in this instance, unlike for the Enter event that will only fire if a control doesn't already have the focus and receives it for the first time.

Resources