Created
February 8, 2010 06:02
-
-
Save atr000/297924 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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