diff --git a/src/mred/mredmac.cxx b/src/mred/mredmac.cxx index 48c2db8423..da087d599f 100644 --- a/src/mred/mredmac.cxx +++ b/src/mred/mredmac.cxx @@ -41,6 +41,9 @@ static void MrDequeue(MrQueueElem *q); WindowPtr MrEdMouseWindow(Point where); WindowPtr MrEdKeyWindow(); +extern int wxTranslateRawKey(int key); +extern short wxMacDisableMods; + typedef MrQueueElem *MrQueueRef; typedef int (*Checker_Func)(EventRecord *evt, MrQueueRef q, int check_only, @@ -276,9 +279,15 @@ static int pending_self_ae; static void EnsureWNEReturn() { - /* Generate an event that WaitNextEvent will return, but - that we can recognize and ignore. An AppleEvent is a - heavyweight but reliable way to do that. */ + /* Generate an event that WaitNextEvent() will return, but that we can + recognize and ignore. (Note that window handlers can run nested + event handlers, such as the resize handler for the little + OS-provided window to implement Chinese text via pinyin. We need + something that doesn't break those loops.) An AppleEvent is a + heavyweight(?) but apparently reliable way to get WaitNextEvent() to + return. Of course, don't install the standard handlers that are put + in place by RunApplicationEventLoop(), because they'll dispatch the + dummy AppleEvent and defeat the purpose. */ if (!pending_self_ae) { ProcessSerialNumber psn; AEAddressDesc target; @@ -332,20 +341,34 @@ void wxSmuggleOutEvent(EventRef ref) && (GetEventKind(ref) == kEventTextInputUnicodeForKeyEvent)) { UniChar *text; UInt32 actualSize; + EventRef kref; - GetEventParameter(ref, kEventParamTextInputSendText, - typeUnicodeText, NULL, 0, &actualSize, NULL); - if (actualSize) { - text = (UniChar*)scheme_malloc_atomic(actualSize); - GetEventParameter(ref, kEventParamTextInputSendText, - typeUnicodeText, NULL, actualSize, NULL, text); - - e.what = unicodeEvt; - e.message = text[0]; + GetEventParameter(ref, kEventParamTextInputSendKeyboardEvent, + typeEventRef, NULL, sizeof(EventRef), NULL, &kref); + if (ConvertEventRefToEventRecord(kref, &e)) { + ok = TRUE; + } else { e.modifiers = 0; + e.message = 0; e.where.h = 0; e.where.v = 0; - ok = TRUE; + } + + if ((e.modifiers & (wxMacDisableMods | cmdKey)) + || wxTranslateRawKey((e.message & keyCodeMask) >> 8)) { + /* keep the raw event */ + } else { + GetEventParameter(ref, kEventParamTextInputSendText, + typeUnicodeText, NULL, 0, &actualSize, NULL); + if (actualSize) { + text = (UniChar*)scheme_malloc_atomic(actualSize); + GetEventParameter(ref, kEventParamTextInputSendText, + typeUnicodeText, NULL, actualSize, NULL, text); + + e.what = unicodeEvt; + e.message = text[0]; + ok = TRUE; + } } } else { ok = ConvertEventRefToEventRecord(ref, &e); @@ -379,7 +402,7 @@ static pascal OSErr HandleSmug(const AppleEvent *evt, AppleEvent *rae, long k) return 0; } -/* WNE: a small wrapper for WaitNextEvent, mostly to manage +/* WNE: a small wrapper for WaitNextEvent(), mostly to manage wake-up activities. It's tempting to try to use ReceiveNextEvent() to filter the raw events. Don't do that, because WaitNextEvent() is @@ -424,7 +447,7 @@ int WNE(EventRecord *e, double sleep_secs) ::InstallEventHandler(GetEventDispatcherTarget(), smuggle_handler, - 2, + 3, evts, NULL, NULL); @@ -465,7 +488,7 @@ static int TransferQueue(int all) int sleep_time = 0; int delay_time = 0; - /* Don't call WaitNextEvent too often. */ + /* Don't call WaitNextEvent() too often. */ static unsigned long lastTime; if (TickCount() <= lastTime + delay_time) return 0; @@ -726,6 +749,7 @@ static int CheckForMouseOrKey(EventRecord *e, MrQueueRef osq, int check_only, } break; case wheelEvt: + case unicodeEvt: case keyDown: case autoKey: case keyUp: @@ -754,10 +778,6 @@ static int CheckForActivate(EventRecord *evt, MrQueueRef q, int check_only, WindowPtr window; switch (evt->what) { -#ifndef OS_X - // OS X does not support the diskEvt event. - case diskEvt: -#endif case kHighLevelEvent: { MrEdContext *fc; @@ -904,6 +924,7 @@ int MrEdGetNextEvent(int check_only, int current_only, case mouseMenuDown: case mouseDown: case wheelEvt: + case unicodeEvt: case keyDown: case keyUp: case autoKey: @@ -1071,14 +1092,12 @@ int MrEdCheckForBreak(void) /* sleep */ /***************************************************************************/ -#ifdef OS_X #include static volatile int thread_running; static volatile int need_post; /* 0=>1 transition has a benign race condition, an optimization */ static SLEEP_PROC_PTR mzsleep; static pthread_t watcher; static volatile float sleep_secs; -static ProcessSerialNumber psn; /* These file descriptors act as semaphores: */ static int watch_read_fd, watch_write_fd; @@ -1103,7 +1122,6 @@ static void *do_watch(void *fds) mzsleep(sleep_secs, fds); if (need_post) { need_post = 0; - WakeUpProcess(&psn); if (cb_socket_ready) { /* Sometimes WakeUpProcess() doesn't work. Try a notification socket as a backup. @@ -1145,7 +1163,6 @@ static int StartFDWatcher(void (*mzs)(float secs, void *fds), float secs, void * } if (!watcher) { - GetCurrentProcess(&psn); if (pthread_create(&watcher, NULL, do_watch, fds)) { return 0; } @@ -1175,32 +1192,26 @@ static void EndFDWatcher(void) } } -/* See ARGH below. */ void socket_callback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) { - WakeUpProcess(&psn); + EnsureWNEReturn(); } -/* See ARGH below. */ static const void *sock_retain(const void *info) { return NULL; } -/* See ARGH below. */ static void sock_release(const void *info) { /* do nothing */ } -/* See ARGH below. */ static CFStringRef sock_copy_desc(const void *info) { return CFSTR("sock"); } -#endif - static int going, reported_recursive_sleep; void MrEdMacSleep(float secs, void *fds, SLEEP_PROC_PTR mzsleep) @@ -1215,24 +1226,24 @@ void MrEdMacSleep(float secs, void *fds, SLEEP_PROC_PTR mzsleep) } /* If we're asked to sleep less than 1/60 of a second, then don't - bother with WaitNextEvent. */ + bother with WaitNextEvent(). */ if ((secs > 0) && (secs < 1.0/60)) { mzsleep(secs, fds); } else { EventRecord e; if (!cb_socket_ready) { - /* ARGH: We set up a pipe for the purpose of breaking the Carbon + /* We set up a pipe for the purpose of breaking the Carbon event manager out of its loop. When the watcher thread sees that an fd is ready, it writes to write_sock_ready, which means that sock_ready is ready to read, which means that - socket_callback is invoked, and it calls WakeUpProcess(). + socket_callback is invoked, and it calls EnsureWNEReturn(). - None of this would be necessary if WakeUpProcess() worked - correctly, because the watcher thread also calls - WakeUpProcess(). It seems to have become broken in OS X 10.2, - where WakeUpprocess() doesn't work when called before the WNE - starts (reminiscent of OS 7.1.2 or so). */ + With the current implementation of EnsureWNEReturn(), this is + probably overkill. I think the watcher thread could call + EnsureWNEReturn() directly. Doing it this way moves the call + into this thread, though, which seems more robust in the long + run (i.e., if EnsureWNEReturn() changes). */ int fds[2]; if (!pipe(fds)) { CFRunLoopRef rl; diff --git a/src/wxmac/src/mac/wx_app.cc b/src/wxmac/src/mac/wx_app.cc index aaf0fc7ef3..595d4767d0 100644 --- a/src/wxmac/src/mac/wx_app.cc +++ b/src/wxmac/src/mac/wx_app.cc @@ -46,6 +46,8 @@ extern WindowPtr MrEdKeyWindow(); extern void wxCheckRootFrame(WindowPtr w); +int wxTranslateRawKey(int key); + int wxMenuBarHeight; extern wxApp *wxTheApp; @@ -649,232 +651,141 @@ void wxApp::doMacKeyUpDown(Bool down) } else if (cCurrentEvent.what == unicodeEvt) { key = cCurrentEvent.message; } else { + int newkey; + key = (cCurrentEvent.message & keyCodeMask) >> 8; - /* Better way than to use hard-wired key codes? */ - switch (key) { -# define wxFKEY(code, wxk) case code: key = wxk; break - wxFKEY(122, WXK_F1); - wxFKEY(120, WXK_F2); - wxFKEY(99, WXK_F3); - wxFKEY(118, WXK_F4); - wxFKEY(96, WXK_F5); - wxFKEY(97, WXK_F6); - wxFKEY(98, WXK_F7); - wxFKEY(100, WXK_F8); - wxFKEY(101, WXK_F9); - wxFKEY(109, WXK_F10); - wxFKEY(103, WXK_F11); - wxFKEY(111, WXK_F12); - wxFKEY(105, WXK_F13); - wxFKEY(107, WXK_F14); - wxFKEY(113, WXK_F15); - case 0x7e: - case 0x3e: - key = WXK_UP; - break; - case 0x7d: - case 0x3d: - key = WXK_DOWN; - break; - case 0x7b: - case 0x3b: - key = WXK_LEFT; - break; - case 0x7c: - case 0x3c: - key = WXK_RIGHT; - break; - case 0x24: - key = WXK_RETURN; - break; - case 0x30: - key = WXK_TAB; - break; - case 0x33: - key = WXK_BACK; - break; - case 0x75: - key = WXK_DELETE; - break; - case 0x73: - key = WXK_HOME; - break; - case 0x77: - key = WXK_END; - break; - case 0x74: - key = WXK_PRIOR; - break; - case 0x79: - key = WXK_NEXT; - break; - case 0x45: - key = WXK_ADD; - break; - case 78: - key = WXK_SUBTRACT; - break; - case 0x43: - key = WXK_MULTIPLY; - break; - case 0x4B: - key = WXK_DIVIDE; - break; - case 71: - key = WXK_SEPARATOR; - break; - case 65: - key = WXK_DECIMAL; - break; - case 76: - key = 3; /* numpad enter */ - break; - case 82: - case 83: - case 84: - case 85: - case 86: - case 87: - case 88: - case 89: - key = WXK_NUMPAD0 + (key - 82); - break; - case 91: - key = WXK_NUMPAD8; - break; - case 92: - key = WXK_NUMPAD9; - break; - default: - { - int iter, akey, orig_key = key; + newkey = wxTranslateRawKey(key); - key = 0; /* let compiler know that key is assigned */ - for (iter = 0; iter < ((cCurrentEvent.modifiers & cmdKey) ? 2 : 1); iter++) { - char cstr[3]; - int from_str = 0; + if (newkey) { + key = newkey; + } else { + int iter, akey, orig_key = key; - akey = orig_key; + key = 0; /* let compiler know that key is assigned */ + for (iter = 0; iter < ((cCurrentEvent.modifiers & cmdKey) ? 2 : 1); iter++) { + char cstr[3]; + int from_str = 0; - if (cCurrentEvent.modifiers & (wxMacDisableMods | cmdKey)) { - /* The following code manually translates the virtual key event - into a character. We'd use this code all the time, except - that dead keys have already been filtered before we get here, - which means that option-e-e doesn't produce an accented e. - So, instead, we only use this code to find out what would - happen if the control/option key wasn't pressed. */ - int mods; - OSStatus status; - UniCharCount len; - UniChar keys[1]; - SInt16 currentKeyLayoutID; - static UCKeyboardLayout *key_layout; + akey = orig_key; - mods = cCurrentEvent.modifiers; - if (mods & cmdKey) { - /* Strip control and option modifiers when command is pressed: */ - mods -= (mods & (optionKey | controlKey | cmdKey | shiftKey)); - /* On second iteration, set the shift key: */ - if (iter) - mods |= shiftKey; - } else { - /* Remove effect of anything in wxMacDisableMods: */ - mods -= (mods & wxMacDisableMods); - } + if (cCurrentEvent.modifiers & (wxMacDisableMods | cmdKey)) { + /* The following code manually translates the virtual key event + into a character. We'd use this code all the time, except + that dead keys have already been filtered before we get here, + which means that option-e-e doesn't produce an accented e. + So, instead, we only use this code to find out what would + happen if the control/option key wasn't pressed. */ + int mods; + OSStatus status; + UniCharCount len; + UniChar keys[1]; + SInt16 currentKeyLayoutID; + static UCKeyboardLayout *key_layout; - currentKeyLayoutID = GetScriptVariable(GetScriptManagerVariable(smKeyScript), smScriptKeys); - if (!keyLayoutSet || (currentKeyLayoutID != lastKeyLayoutID)) { - KeyboardLayoutRef kl; - key_state = 0; - if (KLGetCurrentKeyboardLayout(&kl) == noErr) { - void *p; - if (KLGetKeyboardLayoutProperty(kl, kKLKCHRData, (const void **)&p) == noErr) { - KCHRPtr = p; - } else - KCHRPtr = NULL; - if (KLGetKeyboardLayoutProperty(kl, kKLuchrData, (const void **)&p) == noErr) - uchrPtr = p; - else - uchrPtr = NULL; - } - lastKeyLayoutID = currentKeyLayoutID; - keyLayoutSet = 1; - } + mods = cCurrentEvent.modifiers; + if (mods & cmdKey) { + /* Strip control and option modifiers when command is pressed: */ + mods -= (mods & (optionKey | controlKey | cmdKey | shiftKey)); + /* On second iteration, set the shift key: */ + if (iter) + mods |= shiftKey; + } else { + /* Remove effect of anything in wxMacDisableMods: */ + mods -= (mods & wxMacDisableMods); + } - if (!uchrPtr) { - if (!KCHRPtr) { - akey = '?'; - } else { - int trans; - trans = KeyTranslate(KCHRPtr, akey | mods, &key_state); - if (trans & 0xFF0000) { - /* 2-byte result */ - cstr[0] = (trans & 0xFF0000) >> 16; - cstr[1] = trans & 0xFF; - cstr[2] = 0; - } else { - /* 1-byte result */ - cstr[0] = trans & 0xFF; - cstr[1] = 0; - } + currentKeyLayoutID = GetScriptVariable(GetScriptManagerVariable(smKeyScript), smScriptKeys); + if (!keyLayoutSet || (currentKeyLayoutID != lastKeyLayoutID)) { + KeyboardLayoutRef kl; + key_state = 0; + if (KLGetCurrentKeyboardLayout(&kl) == noErr) { + void *p; + if (KLGetKeyboardLayoutProperty(kl, kKLKCHRData, (const void **)&p) == noErr) { + KCHRPtr = p; + } else + KCHRPtr = NULL; + if (KLGetKeyboardLayoutProperty(kl, kKLuchrData, (const void **)&p) == noErr) + uchrPtr = p; + else + uchrPtr = NULL; + } + lastKeyLayoutID = currentKeyLayoutID; + keyLayoutSet = 1; + } - akey = '?'; /* temporary */ - from_str = 1; - } - } else { - key_layout = (UCKeyboardLayout *)uchrPtr; + if (!uchrPtr) { + if (!KCHRPtr) { + akey = '?'; + } else { + int trans; + trans = KeyTranslate(KCHRPtr, akey | mods, &key_state); + if (trans & 0xFF0000) { + /* 2-byte result */ + cstr[0] = (trans & 0xFF0000) >> 16; + cstr[1] = trans & 0xFF; + cstr[2] = 0; + } else { + /* 1-byte result */ + cstr[0] = trans & 0xFF; + cstr[1] = 0; + } - status = UCKeyTranslate(key_layout, - akey, - cCurrentEvent.what - keyDown, - mods >> 8, - LMGetKbdType(), - 0 /* options */, - &key_state, - 1, - &len, - keys); + akey = '?'; /* temporary */ + from_str = 1; + } + } else { + key_layout = (UCKeyboardLayout *)uchrPtr; - if (status == noErr) - akey = keys[0]; - else - akey = '?'; - } - } else { - akey = '?'; /* temporary */ - cstr[0] = cCurrentEvent.message & charCodeMask; - cstr[1] = 0; - from_str = 1; - } + status = UCKeyTranslate(key_layout, + akey, + cCurrentEvent.what - keyDown, + mods >> 8, + LMGetKbdType(), + 0 /* options */, + &key_state, + 1, + &len, + keys); - if (from_str) { - CFStringRef str; - UniChar keys[1]; + if (status == noErr) + akey = keys[0]; + else + akey = '?'; + } + } else { + akey = '?'; /* temporary */ + cstr[0] = cCurrentEvent.message & charCodeMask; + cstr[1] = 0; + from_str = 1; + } + + if (from_str) { + CFStringRef str; + UniChar keys[1]; - str = CFStringCreateWithCStringNoCopy(NULL, cstr, - GetScriptManagerVariable(smKeyScript), - kCFAllocatorNull); - if (str) { - if (CFStringGetLength(str) > 0) { - GC_CAN_IGNORE CFRange rng; - rng = CFRangeMake(0, 1); - CFStringGetCharacters(str, rng, keys); - } else - keys[0] = '?'; - CFRelease(str); - } else - keys[0] = '?'; + str = CFStringCreateWithCStringNoCopy(NULL, cstr, + GetScriptManagerVariable(smKeyScript), + kCFAllocatorNull); + if (str) { + if (CFStringGetLength(str) > 0) { + GC_CAN_IGNORE CFRange rng; + rng = CFRangeMake(0, 1); + CFStringGetCharacters(str, rng, keys); + } else + keys[0] = '?'; + CFRelease(str); + } else + keys[0] = '?'; - akey = keys[0]; - } + akey = keys[0]; + } - if (!iter) - key = akey; - else - otherKey = akey; - } + if (!iter) + key = akey; + else + otherKey = akey; } - } // end switch + } } if (down) { @@ -915,6 +826,111 @@ void wxApp::doMacAutoKey(void) doMacKeyUpDown(true); } +int wxTranslateRawKey(int key) +{ + /* Better way than to use hard-wired key codes? */ + switch (key) { +# define wxFKEY(code, wxk) case code: key = wxk; break + wxFKEY(122, WXK_F1); + wxFKEY(120, WXK_F2); + wxFKEY(99, WXK_F3); + wxFKEY(118, WXK_F4); + wxFKEY(96, WXK_F5); + wxFKEY(97, WXK_F6); + wxFKEY(98, WXK_F7); + wxFKEY(100, WXK_F8); + wxFKEY(101, WXK_F9); + wxFKEY(109, WXK_F10); + wxFKEY(103, WXK_F11); + wxFKEY(111, WXK_F12); + wxFKEY(105, WXK_F13); + wxFKEY(107, WXK_F14); + wxFKEY(113, WXK_F15); + case 0x7e: + case 0x3e: + key = WXK_UP; + break; + case 0x7d: + case 0x3d: + key = WXK_DOWN; + break; + case 0x7b: + case 0x3b: + key = WXK_LEFT; + break; + case 0x7c: + case 0x3c: + key = WXK_RIGHT; + break; + case 0x24: + key = WXK_RETURN; + break; + case 0x30: + key = WXK_TAB; + break; + case 0x33: + key = WXK_BACK; + break; + case 0x75: + key = WXK_DELETE; + break; + case 0x73: + key = WXK_HOME; + break; + case 0x77: + key = WXK_END; + break; + case 0x74: + key = WXK_PRIOR; + break; + case 0x79: + key = WXK_NEXT; + break; + case 0x45: + key = WXK_ADD; + break; + case 78: + key = WXK_SUBTRACT; + break; + case 0x43: + key = WXK_MULTIPLY; + break; + case 0x4B: + key = WXK_DIVIDE; + break; + case 71: + key = WXK_SEPARATOR; + break; + case 65: + key = WXK_DECIMAL; + break; + case 76: + key = 3; /* numpad enter */ + break; + case 82: + case 83: + case 84: + case 85: + case 86: + case 87: + case 88: + case 89: + key = WXK_NUMPAD0 + (key - 82); + break; + case 91: + key = WXK_NUMPAD8; + break; + case 92: + key = WXK_NUMPAD9; + break; + default: + key = 0; + break; + } + + return key; +} + //----------------------------------------------------------------------------- void wxApp::doMacActivateEvt(void) { diff --git a/src/wxmac/src/mac/wx_frame.cc b/src/wxmac/src/mac/wx_frame.cc index 2613f50560..446b3057b4 100644 --- a/src/wxmac/src/mac/wx_frame.cc +++ b/src/wxmac/src/mac/wx_frame.cc @@ -263,6 +263,12 @@ wxFrame::wxFrame // Constructor (for frame window) spec[2].eventKind = kEventWindowBoundsChanging; InstallEventHandler(GetWindowEventTarget(theMacWindow), window_evt_handler, 3, spec, refcon, NULL); } + + { + /* In case we need to recognize MrEd windows: */ + UInt32 val = 1; + SetWindowProperty (theMacWindow, 'mReD', 'Ello', sizeof(UInt32), &val); + } } static void userPaneDrawFunction(ControlRef controlRef, SInt16 thePart)