Skip to content

Instantly share code, notes, and snippets.

@atr000
Created February 8, 2010 06:02
Show Gist options
  • Save atr000/297924 to your computer and use it in GitHub Desktop.
Save atr000/297924 to your computer and use it in GitHub Desktop.
// Map right-side Option to Enter in OS X
// by Henrik Nyh <http://henrik.nyh.se> 2008-03-15.
// Free to modify and redistribute with credit.
//
// The Enter key does not always do the same thing as Return: when editing
// text in Photoshop, Return breaks lines and Enter commits the changes.
// The Adium IM client and and Colloquy IRC client can be set up much the
// same way: Return breaks lines, Enter sends. The TextMate editor
// (http://macromates.com) makes good use of Enter in its commands.
//
// For a while up until recently (2007 or so), Apple keyboards had a
// dedicated Enter key. It has since been replaced with a right-side
// Option key. While this was probably a change for the better to most
// users, some users have gotten used to the Enter key and miss it.
// While you can still produce Enter with Fn+Return, this is not nearly
// as convenient. This app, when running, remaps right-Option to Enter.
//
// Compile like:
// gcc -Wall -o optenter optenter.c -framework ApplicationServices
// then just keep the app running to have right-side Option send Enter.
//
// Based on http://www.osxbook.com/book/bonus/chapter2/alterkeys/.
// http://gemma.apple.com/documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html
// is a good reference.
//
// Half-broken bonus feature:
// Enter is only sent if you press no other key at the same
// time; otherwise it still sends Option. So you can still e.g. use
// right-Option plus "." for ellipsis. Half-broken because you'll get
// a line break too, after you hit Option and before you hit "."
// TODO: Fix this by attaching to keyup instead? But then we'd need to
// make sure we don't send Option+Enter, and keep-pressed-for-multiples
// would become trickier.
//
// TODO: Keep app running in some nice way. Prefpane, launchd, daemon?
// TODO: Respect other modifiers, so eg Ctrl+Enter works.
// TODO: Bit logic instead of just checking integer. Necessary for "other modifiers" TODO.
// TODO: Keeping it pressed should send multiple Enters.
#include <ApplicationServices/ApplicationServices.h>
const CGKeyCode ENTER = (CGKeyCode)76;
const CGKeyCode RIGHT_OPT = (CGKeyCode)61;
const int RIGHT_OPT_DOWN = 524608;
const int MODIFIER_UP = 256;
CGEventRef myCGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
CGKeyCode keycode = (CGKeyCode)CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);
CGEventFlags modifiers = CGEventGetFlags(event);
printf("x: %i y: %i\n", kCGEventFlagMaskNumericPad, kCGEventFlagMaskAlternate);
// Debug
printf("Type: %i Modifiers: %i Keycode: %i\n", type, (int)modifiers, keycode);
// Swap right-Opt for Enter
if (modifiers == RIGHT_OPT_DOWN && keycode == RIGHT_OPT) {
printf("swap!\n");
CGEventRef press, release;
press = CGEventCreateKeyboardEvent(NULL, ENTER, true);
release = CGEventCreateKeyboardEvent(NULL, ENTER, false);
CGEventPost(kCGHIDEventTap, press);
CGEventPost(kCGHIDEventTap, release);
}
// FIXME: Not necessary? We must return the event for it to be useful.
return event;
}
int main(void) {
CFMachPortRef eventTap;
CFRunLoopSourceRef runLoopSource;
// Create an event tap. We are interested in modifier changes.
CGEventFlags oldFlags =
CGEventSourceFlagsState(kCGEventSourceStateCombinedSessionState);
eventTap = CGEventTapCreate(kCGSessionEventTap,
kCGHeadInsertEventTap,
0,
CGEventMaskBit(kCGEventFlagsChanged),
myCGEventCallback,
&oldFlags);
if (!eventTap) {
fprintf(stderr, "failed to create event tap\n");
exit(1);
}
// Create a run loop source,
runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
// add to the current run loop,
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
// enable the event tap
CGEventTapEnable(eventTap, true);
// and set it all running.
CFRunLoopRun();
exit(0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment