I'm using Quartz CGEventTap in an attempt to globally intercept capslock presses and block them (to have them do something useful instead). I succesfully detect capslock presses but have so far been unable to block them. My code (originating from this stackoverflow answer) is something like this:
eventTap = CGEventTapCreate(kCGHIDEventTap,
kCGTailAppendEventTap,
kCGEventTapOptionDefault,
eventMask,
myCGEventCallback,
&oldFlags);
runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
CGEventTapEnable(eventTap, true);
CGEventRef myCGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef theEvent, void *refcon)
{
CGEventFlags *oldFlags = (CGEventFlags *)refcon;
switch (type)
{
case kCGEventFlagsChanged:
{
CGEventFlags newFlags = CGEventGetFlags(theEvent);
CGEventFlags changedFlags = *oldFlags ^ newFlags;
*oldFlags = newFlags;
if (changedFlags == 65536)
{
NSLog(#"Capslock pressed. Let's not return the event");
return NULL;
}
break;
}
default:
break;
}
NSLog(#"Different modifier than capslock. Returning the event");
return theEvent;
}
If I understand correctly returning NULL should effectively block the keypress from propagating. Indeed it also does for "normal" keyup and -down events. However capslock toggles regardless. Any ideas why that is? Am I making incorrect assumptions? And/or how can I do things differently to achieve my goal?
Thanks,
Thor
You cannot block capslock like that. Capslock is a condition, that is handled by the keyboard driver, not by the Window Server or the individual applications. A keypress event propagates in OS X like that:
Keyboard Driver -> Window Server -> User Session -> Active Application
At each level propagation (indicated by "->") you can place an event tap and block and/or modify key events. Keyboard Driver and Window Server are both privileged components, the other two are normal user level components.
The earliest you can catch a keyboard event is when the event propagates from the Driver (kernel space) to the Window Server (user space, but still privileged). However, as noted above, the capslock state is handled internally in the driver, thus catching an event there is already too late. The driver will already have enabled the capslock light on the keyboard (if necessary at all and not performed by the hardware on its own) and remembered the capslock state being on, which has an effect on all future key presses.
You can turn off the capslock light programmatically for HID devices (Apple has even sample code for that), but this will not turn-off capslock, it just turns off the light.
The only way I see to implement that using event taps is to manually re-write every key press with capslock to a key press without capslock (one where the capslock flag is not set and the attached letter, if any, is lower case). Further, to not confuse the user, you'd turn off the capslock light as shown by Apple's sample code.
Other alternatives are: Write your own keyboard driver, that takes control over the keyboard instead of Apple's standard driver (not as hard as you think, but still hard hard enough) or hacking your way into the driver (evil, but works). E.g. some keyboard remappers override only single methods of the driver (drivers are C++ in OS X, thus they are OO-objects and you can dynamically override C++ methods at runtime; not really override them, but rather manipulate method tables). The problems with those two solutions are: The first one means that unless your driver is as good as the one from Apple, some USB keyboards may not work with your driver, while others do, the second one means if you make any mistake, the system punishes this mistake with a kernel panic.
I'm looking myself for a way to programmatically toggle capslock on Mac, without success so far. But I can assure you, event taps are not the way to go.
Related
In Linux (most distros?) there is a Keyboard Shortcuts settings app that lets you set keyboard shortcuts like the key combination that minimizes a window or switches to the next workspace/desktop or moves to the next media track. I want to connect to the event that is fired when the defined shortcut is pressed rather than the key combination as the key combination can change but the event is always the event. Specifically I want to capture the next/previous workspace/desktop events, not the workspace/desktop changing, but the keyboard request to make the change.
However, I cannot figure out where these events are surfaced. Does anyone know where I might connect to these events? I would think GTK+ has some way to surface it, but even if I have to go down to X11/XLib, I'm ok with that.
Ultimately I will code this in python, but for now I'm just looking for a way to capture these events.
So I have a keyboard, and it has a mode where it lights up every key you press.
I was wondering if you could physically simulate a keypress, AHK just sends it directly to the system.
However I need a way to make the keyboard light up, because AHK doesn't do that. The keyboard is not programmable.
Solutions in mostly any language are welcome.
This is not possible, you want to send a simulate keypress to your fysical keyboard. (this is i think a mechanical switch insite the keyboard self, that does do light up if you press a key) and it is only possible if the company did make a keyboard driver that allows you to change the settings (disable - light up) in the Windows Registry. (you did not give me the name of your keyboard but you can then try to searching into the registry for example software/Logitech/settings)
I am currently working on a project for mapping every possible keyboard and mouse interrupt.
The mapping is done in linux environment and with ncurses library.
The question is how to catch the following keyboard keys :
Home
End
page up / down
when pressing those keys the terminal itself is catching them and the program itself cant see them (spent a few hours of configuration and found no solution yet)
pause/break (above page up in standard keyboard)
PrtScreen
Num Locked keys (0 to 9 and < . >).
Windows button
the following just not getting any response at all, neither from the terminal or the program.
short: you cannot catch all keys with ncurses
long: the usual problems lie in a failure to initialize things properly:
you probably forgot to call keypad(stdscr,TRUE) (or whatever window you might be using with wgetch). That will allow an application to read any of the keys defined in the terminal description as an integer.
If it is not in the terminal description, (n)curses will return the sequence of bytes which make up the key as sent from the keyboard.
That's two likely problems. There are other keys (or combinations of keys) which the terminal will not send (in a way which makes distinct keyboard sequences). For instance, using the Control key with other keys may change the sequence sent by the keyboard, or it may not. To see this, use experiment with the control key with comma, period or the other punctuation keys in that area of the keyboard.
I understand that new keyboards can be ordered online, but now that this problem has proven to be hard I am completely fascinated by it.
Many old laptop keyboards as they wear develop consistent shorts which cause multiple keys to react when a single key is pressed. For example, on my little sister's computer if you press "r" the system outputs "vr", "i" outputs ",i" and so-on.
Assuming the user is not a vim/emacs power user, the keyboard still seems salvageable. It seems that if the keyboard driver was changed so that pressing the "r" key resulted in the computer accepting "backspace r" the "v" would disappear and not be such a hassle anymore.
Xmodmap XKB and other systems seem to assume that each single key depression will result in a single command. Does anybody understand the missing link where more than one character can come from a single keypress? There seem to be many places in the stack where this can be pulled off, but none of them are particularly clearly documented. Another fun fact is that you can't force this in the ubuntu keyboard shortcuts editor, ubuntu will stop you from entering the changes there under the premise that "this will make it impossible to type."
Hacking around in xev shows that the computer believes that when you hit and release 'r' that it gets a keypress event for 'v' then a keypress event for 'r' then a keyrelease event for 'v' then one for 'r'. If you could change the configuration to ignore a first keypress if there is no corresponding key release before the next key is pressed, that would work too.
I am currently implementing a program in X11 using C. I got the program to handle right- and left-click events, however middle-clicking poses a problem. It seems my window manager (Gnome on Ubuntu 9.10) thinks it's better if, instead of having a single middle-click, I should have a series of other clicks instead. I assume it's got something to do with the middle-click being used for copying-pasting. I really don't want this, though, as I'm making a full-screen application with OpenGL, and such things aren't appropriate. Is there any way to have the middle mouse button just working like any other button?
My current code goes something like this:
switch(currentXEvent.type) {
case ButtonPress:
switch(currentXEvent.xbutton.button) {
case 1:
leftMouseButton(currentXEvent.xbutton.x, currentXEvent.xbutton.y);
break;
case 2:
middleMouseButton(currentXEvent.xbutton.x, currentXEvent.xbutton.y);
break;
}
}
My difficulty is that it behaves like leftMouseButton() has been pressed. Any ideas?
To do this, you have to grab controls from the server. Then the window manager is left out of the processing chain. The most comfortable way is to use libSDL. It creates the appropriate context for a fullscreen OpenGL application and is easier to handle than Xlib+GLX.