1/* 2 * tkMacOSXKeyEvent.c -- 3 * 4 * This file implements functions that decode & handle keyboard events on 5 * MacOS X. 6 * 7 * Copyright 2001-2009, Apple Inc. 8 * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net> 9 * 10 * See the file "license.terms" for information on usage and redistribution of 11 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 12 * 13 * RCS: @(#) $Id$ 14 */ 15 16#include "tkMacOSXPrivate.h" 17#include "tkMacOSXEvent.h" 18 19/* 20#ifdef TK_MAC_DEBUG 21#define TK_MAC_DEBUG_KEYBOARD 22#endif 23*/ 24 25static Tk_Window grabWinPtr = NULL; 26 /* Current grab window, NULL if no grab. */ 27static Tk_Window keyboardGrabWinPtr = NULL; 28 /* Current keyboard grab window. */ 29static NSModalSession modalSession = NULL; 30 31#pragma mark TKApplication(TKKeyEvent) 32 33@implementation TKApplication(TKKeyEvent) 34- (NSEvent *)tkProcessKeyEvent:(NSEvent *)theEvent { 35#ifdef TK_MAC_DEBUG_EVENTS 36 TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, theEvent); 37#endif 38 NSWindow* w; 39 NSEventType type = [theEvent type]; 40 NSUInteger modifiers, len; 41 BOOL repeat = NO; 42 unsigned short keyCode; 43 NSString *characters = nil, *charactersIgnoringModifiers = nil; 44 static NSUInteger savedModifiers = 0; 45 46 47 switch (type) { 48 case NSKeyUp: 49 case NSKeyDown: 50 repeat = [theEvent isARepeat]; 51 characters = [theEvent characters]; 52 charactersIgnoringModifiers = [theEvent charactersIgnoringModifiers]; 53 case NSFlagsChanged: 54 modifiers = [theEvent modifierFlags]; 55 keyCode = [theEvent keyCode]; 56 w = [self windowWithWindowNumber:[theEvent windowNumber]]; 57#ifdef TK_MAC_DEBUG_EVENTS 58 TKLog(@"-[%@(%p) %s] %d %u %@ %@ %u %@", [self class], self, _cmd, repeat, modifiers, characters, charactersIgnoringModifiers, keyCode, w); 59#endif 60 break; 61 62 default: 63 return theEvent; 64 break; 65 } 66 67 unsigned int state = 0; 68 69 if (modifiers & NSAlphaShiftKeyMask) { 70 state |= LockMask; 71 } 72 if (modifiers & NSShiftKeyMask) { 73 state |= ShiftMask; 74 } 75 if (modifiers & NSControlKeyMask) { 76 state |= ControlMask; 77 } 78 if (modifiers & NSCommandKeyMask) { 79 state |= Mod1Mask; /* command key */ 80 } 81 if (modifiers & NSAlternateKeyMask) { 82 state |= Mod2Mask; /* option key */ 83 } 84 if (modifiers & NSNumericPadKeyMask) { 85 state |= Mod3Mask; 86 } 87 if (modifiers & NSFunctionKeyMask) { 88 state |= Mod4Mask; 89 } 90 91 /* 92 * The focus must be in the FrontWindow on the Macintosh. We then query Tk 93 * to determine the exact Tk window that owns the focus. 94 */ 95 96 TkWindow *winPtr = TkMacOSXGetTkWindow(w); 97 Tk_Window tkwin = (Tk_Window) winPtr; 98 99 if (!tkwin) { 100 TkMacOSXDbgMsg("tkwin == NULL"); 101 return theEvent; 102 } 103 tkwin = (Tk_Window) winPtr->dispPtr->focusPtr; 104 if (!tkwin) { 105 TkMacOSXDbgMsg("tkwin == NULL"); 106 return theEvent; 107 } 108 109 XEvent xEvent; 110 memset(&xEvent, 0, sizeof(XEvent)); 111 xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin)); 112 xEvent.xany.send_event = false; 113 xEvent.xany.display = Tk_Display(tkwin); 114 xEvent.xany.window = Tk_WindowId(tkwin); 115 116 xEvent.xkey.root = XRootWindow(Tk_Display(tkwin), 0); 117 xEvent.xkey.subwindow = None; 118 xEvent.xkey.time = TkpGetMS(); 119 xEvent.xkey.state = state; 120 xEvent.xkey.same_screen = true; 121 xEvent.xkey.trans_chars[0] = 0; 122 xEvent.xkey.nbytes = 0; 123 124 if (type == NSFlagsChanged) { 125 if (savedModifiers > modifiers) { 126 xEvent.xany.type = KeyRelease; 127 } else { 128 xEvent.xany.type = KeyPress; 129 } 130 131 /* 132 * Use special '-1' to signify a special keycode to our platform 133 * specific code in tkMacOSXKeyboard.c. This is rather like what 134 * happens on Windows. 135 */ 136 137 xEvent.xany.send_event = -1; 138 139 /* 140 * Set keycode (which was zero) to the changed modifier 141 */ 142 143 xEvent.xkey.keycode = (modifiers ^ savedModifiers); 144 } else { 145 if (type == NSKeyUp || repeat) { 146 xEvent.xany.type = KeyRelease; 147 } else { 148 xEvent.xany.type = KeyPress; 149 } 150 xEvent.xkey.keycode = (keyCode << 16) | (UInt16) 151 [characters characterAtIndex:0]; 152 if (![characters getCString:xEvent.xkey.trans_chars 153 maxLength:XMaxTransChars encoding:NSUTF8StringEncoding]) { 154 TkMacOSXDbgMsg("characters too long"); 155 return theEvent; 156 } 157 len = [charactersIgnoringModifiers length]; 158 if (len) { 159 xEvent.xkey.nbytes = [charactersIgnoringModifiers characterAtIndex:0]; 160 if (len > 1) { 161 TkMacOSXDbgMsg("more than one charactersIgnoringModifiers"); 162 } 163 } 164 if (repeat) { 165 Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL); 166 xEvent.xany.type = KeyPress; 167 xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin)); 168 } 169 } 170 Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL); 171 savedModifiers = modifiers; 172 173 return theEvent; 174} 175@end 176 177#pragma mark - 178 179/* 180 *---------------------------------------------------------------------- 181 * 182 * XGrabKeyboard -- 183 * 184 * Simulates a keyboard grab by setting the focus. 185 * 186 * Results: 187 * Always returns GrabSuccess. 188 * 189 * Side effects: 190 * Sets the keyboard focus to the specified window. 191 * 192 *---------------------------------------------------------------------- 193 */ 194 195int 196XGrabKeyboard( 197 Display* display, 198 Window grab_window, 199 Bool owner_events, 200 int pointer_mode, 201 int keyboard_mode, 202 Time time) 203{ 204 keyboardGrabWinPtr = Tk_IdToWindow(display, grab_window); 205 if (keyboardGrabWinPtr && grabWinPtr) { 206 NSWindow *w = TkMacOSXDrawableWindow(grab_window); 207 MacDrawable *macWin = (MacDrawable *) grab_window; 208 209 if (w && macWin->toplevel->winPtr == (TkWindow*) grabWinPtr) { 210 if (modalSession) { 211 Tcl_Panic("XGrabKeyboard: already grabbed"); 212 } 213 modalSession = [NSApp beginModalSessionForWindow:[w retain]]; 214 } 215 } 216 return GrabSuccess; 217} 218 219/* 220 *---------------------------------------------------------------------- 221 * 222 * XUngrabKeyboard -- 223 * 224 * Releases the simulated keyboard grab. 225 * 226 * Results: 227 * None. 228 * 229 * Side effects: 230 * Sets the keyboard focus back to the value before the grab. 231 * 232 *---------------------------------------------------------------------- 233 */ 234 235void 236XUngrabKeyboard( 237 Display* display, 238 Time time) 239{ 240 if (modalSession) { 241 NSWindow *w = keyboardGrabWinPtr ? TkMacOSXDrawableWindow( 242 ((TkWindow *) keyboardGrabWinPtr)->window) : nil; 243 [NSApp endModalSession:modalSession]; 244 [w release]; 245 modalSession = NULL; 246 } 247 keyboardGrabWinPtr = NULL; 248} 249 250/* 251 *---------------------------------------------------------------------- 252 * 253 * TkMacOSXGetCapture -- 254 * 255 * Results: 256 * Returns the current grab window 257 * 258 * Side effects: 259 * None. 260 * 261 *---------------------------------------------------------------------- 262 */ 263 264Tk_Window 265TkMacOSXGetCapture(void) 266{ 267 return grabWinPtr; 268} 269 270/* 271 *---------------------------------------------------------------------- 272 * 273 * TkMacOSXGetModalSession -- 274 * 275 * Results: 276 * Returns the current modal session 277 * 278 * Side effects: 279 * None. 280 * 281 *---------------------------------------------------------------------- 282 */ 283 284MODULE_SCOPE NSModalSession 285TkMacOSXGetModalSession(void) 286{ 287 return modalSession; 288} 289 290/* 291 *---------------------------------------------------------------------- 292 * 293 * TkpSetCapture -- 294 * 295 * This function captures the mouse so that all future events will be 296 * reported to this window, even if the mouse is outside the window. If 297 * the specified window is NULL, then the mouse is released. 298 * 299 * Results: 300 * None. 301 * 302 * Side effects: 303 * Sets the capture flag and captures the mouse. 304 * 305 *---------------------------------------------------------------------- 306 */ 307 308void 309TkpSetCapture( 310 TkWindow *winPtr) /* Capture window, or NULL. */ 311{ 312 while (winPtr && !Tk_IsTopLevel(winPtr)) { 313 winPtr = winPtr->parentPtr; 314 } 315 grabWinPtr = (Tk_Window) winPtr; 316} 317 318/* 319 *---------------------------------------------------------------------- 320 * 321 * Tk_SetCaretPos -- 322 * 323 * This enables correct placement of the XIM caret. This is called by 324 * widgets to indicate their cursor placement, and the caret location is 325 * used by TkpGetString to place the XIM caret. 326 * 327 * Results: 328 * None 329 * 330 * Side effects: 331 * None 332 * 333 *---------------------------------------------------------------------- 334 */ 335 336void 337Tk_SetCaretPos( 338 Tk_Window tkwin, 339 int x, 340 int y, 341 int height) 342{ 343} 344 345/* 346 * Local Variables: 347 * mode: c 348 * c-basic-offset: 4 349 * fill-column: 79 350 * coding: utf-8 351 * End: 352 */ 353