1 /* vi:set ts=8 sts=4 sw=4 ft=objc:
3 * VIM - Vi IMproved by Bram Moolenaar
4 * MacVim GUI port by Bjorn Winckler
6 * Do ":help uganda" in Vim to read copying and usage conditions.
7 * Do ":help credits" in Vim to see a list of people who contributed.
8 * See README.txt for an overview of the Vim source code.
13 * Some default NSApplication key input behavior is overridden here.
16 #import "MMApplication.h"
17 #import "Miscellaneous.h"
19 // Ctrl-Tab is broken on pre 10.5, so we add a hack to make it work.
20 #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
21 # import "MMTextView.h"
22 # define MM_CTRL_TAB_HACK 1
28 @implementation MMApplication
32 [self fakeEscModifierKeyChanged:nil];
35 - (void)sendEvent:(NSEvent *)event
37 NSEventType type = [event type];
38 unsigned flags = [event modifierFlags];
40 // The following hack allows the user to set one modifier key of choice
41 // (Ctrl, Alt, or Cmd) to generate an Esc key press event. In order for
42 // the key to still be used as a modifier we only send the "faked" Esc
43 // event if the modifier was pressed and released without any other keys
44 // being pressed in between. The user may elect to have the chosen
45 // modifier sending Esc on key down, since sending it on key up makes it
46 // appear a bit sluggish. However, this effectively disables the modifier
47 // key (but only the left key and not the right one, in case there are two
50 // This hack is particularly useful in conjunction with Mac OS X's ability
51 // to turn Caps-Lock into a modifier key of choice because it enables us to
52 // turn Caps-Lock into a quasi-Esc key! (This remapping be done inside
53 // "System Preferences -> Keyboard & Mouse -> Modifier Keys...".)
55 if (fakeEscKeyCode != 0) {
56 if (NSFlagsChanged == type && [event keyCode] == fakeEscKeyCode) {
58 CFAbsoluteTime timeNow = CFAbsoluteTimeGetCurrent();
60 if ((flags & fakeEscModifierMask) == 0) {
61 // The chosen modifier was released. If the modifier was
62 // recently pressed then convert this event to a "fake" Esc key
64 if (!blockFakeEscEvent && !fakeEscOnKeyDown &&
65 timeNow - fakeEscTimeDown < fakeEscTimeout)
68 blockFakeEscEvent = YES;
71 // The chosen modifier was pressed.
72 blockFakeEscEvent = NO;
73 fakeEscTimeDown = timeNow;
75 if (fakeEscOnKeyDown) {
78 // Block key down while the fake Esc modifier key is held,
79 // otherwise "marked text" may pop up if a key is pressed
80 // while the fake Esc modifier is held (which looks ugly,
87 NSEvent *e = [NSEvent keyEventWithType:NSKeyDown
88 location:[event locationInWindow]
89 modifierFlags:flags & 0x0000ffffU
90 timestamp:[event timestamp]
91 windowNumber:[event windowNumber]
92 context:[event context]
93 characters:@"\x1b" // Esc
94 charactersIgnoringModifiers:@"\x1b"
98 [self postEvent:e atStart:YES];
101 } else if (type != NSKeyUp) {
102 // Another event occurred, so don't send any fake Esc events now
103 // (else the modifier would not function as a modifier key any
105 blockFakeEscEvent = YES;
108 if (blockKeyDown && type == NSKeyDown)
112 #ifdef MM_CTRL_TAB_HACK
113 NSResponder *firstResponder = [[self keyWindow] firstResponder];
115 if (NSKeyDown == type && NSControlKeyMask & flags && 48 == [event keyCode]
116 && [firstResponder isKindOfClass:[MMTextView class]]) {
117 // HACK! This is a Ctrl-Tab key down event and the first responder is
118 // an MMTextView; send the event directly to the text view, else it
119 // will never receive it on pre 10.5 systems.
120 [firstResponder keyDown:event];
125 // HACK! Intercept 'help' key presses and clear the 'help key flag', else
126 // Cocoa turns the mouse cursor into a question mark and goes into 'context
127 // help mode' (the keyDown: event itself never reaches the text view). By
128 // clearing the 'help key flag' this event will be treated like a normal
130 if ((NSKeyDown == type || NSKeyUp == type) && (flags & NSHelpKeyMask)) {
131 flags &= ~NSHelpKeyMask;
132 NSEvent *e = [NSEvent keyEventWithType:[event type]
133 location:[event locationInWindow]
135 timestamp:[event timestamp]
136 windowNumber:[event windowNumber]
137 context:[event context]
138 characters:[event characters]
139 charactersIgnoringModifiers:[event charactersIgnoringModifiers]
140 isARepeat:[event isARepeat]
141 keyCode:[event keyCode]];
143 [self postEvent:e atStart:YES];
147 [super sendEvent:event];
151 - (void)orderFrontStandardAboutPanel:(id)sender
153 NSString *version = [[NSBundle mainBundle] objectForInfoDictionaryKey:
155 NSString *marketingVersion = [[NSBundle mainBundle]
156 objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
157 NSString *title = [NSString stringWithFormat:
158 @"Custom Version %@ (%@)", marketingVersion, version];
160 [self orderFrontStandardAboutPanelWithOptions:
161 [NSDictionary dictionaryWithObjectsAndKeys:
163 title, @"ApplicationVersion",
167 - (IBAction)fakeEscModifierKeyChanged:(id)sender
169 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
170 switch ([ud integerForKey:MMFakeEscModifierKey]) {
173 fakeEscModifierMask = NSControlKeyMask;
177 fakeEscModifierMask = NSAlternateKeyMask;
181 fakeEscModifierMask = NSCommandKeyMask;
184 fakeEscKeyCode = fakeEscModifierMask = 0;
187 fakeEscTimeout = [ud floatForKey:MMFakeEscTimeoutKey];
188 fakeEscOnKeyDown = [ud boolForKey:MMFakeEscOnKeyDownKey];