Audacity 3.2.0
Public Member Functions | Private Member Functions | Private Attributes | List of all members
EventMonitor Class Referencefinal
Inheritance diagram for EventMonitor:
[legend]
Collaboration diagram for EventMonitor:
[legend]

Public Member Functions

 EventMonitor ()
 
 ~EventMonitor () override
 
int FilterEvent (wxEvent &event) override
 

Private Member Functions

bool HandleCapture (wxWindow *target, const wxKeyEvent &event)
 
wxString GetUnicodeString (const wxKeyEvent &event)
 

Private Attributes

id mHandler
 
NSEvent * mEvent {}
 
UInt32 mDeadKeyState
 

Detailed Description

Definition at line 86 of file KeyboardCapture.cpp.

Constructor & Destructor Documentation

◆ EventMonitor()

EventMonitor::EventMonitor ( )
inline

Definition at line 89 of file KeyboardCapture.cpp.

90 : wxEventFilter()
91 {
92#if defined(__WXMAC__)
93 // In wx3, the menu accelerators take precedence over key event processing
94 // so we won't get wxEVT_CHAR_HOOK events for combinations assigned to menus.
95 // Since we only support OS X 10.6 or greater, we can use an event monitor
96 // to capture the key event before it gets to the normal wx3 processing.
97
98 // The documentation for addLocalMonitorForEventsMatchingMask implies that
99 // NSKeyUpMask can't be used in 10.6, but testing shows that it can.
100 NSEventMask mask = NSKeyDownMask | NSKeyUpMask;
101
102 mHandler =
103 [
104 NSEvent addLocalMonitorForEventsMatchingMask:mask handler:^NSEvent *(NSEvent *event)
105 {
106 WXWidget widget = (WXWidget) [ [event window] firstResponder];
107 if (widget)
108 {
109 wxWidgetCocoaImpl *impl = (wxWidgetCocoaImpl *)
110 wxWidgetImpl::FindFromWXWidget(widget);
111 if (impl)
112 {
113 mEvent = event;
114
115 wxKeyEvent wxevent([event type] == NSKeyDown ? wxEVT_KEY_DOWN : wxEVT_KEY_UP);
116 impl->SetupKeyEvent(wxevent, event);
117
118 NSEvent *result;
119 if ([event type] == NSKeyDown)
120 {
121 wxKeyEvent eventHook(wxEVT_CHAR_HOOK, wxevent);
122 result = FilterEvent(eventHook) == Event_Processed ? nil : event;
123 }
124 else
125 {
126 result = FilterEvent(wxevent) == Event_Processed ? nil : event;
127 }
128
129 mEvent = nullptr;
130 return result;
131 }
132 }
133
134 return event;
135 }
136 ];
137
138 // Bug1252: must also install this filter with wxWidgets, else
139 // we don't intercept command keys when focus is in a combo box.
140 wxEvtHandler::AddFilter(this);
141#else
142
143 wxEvtHandler::AddFilter(this);
144
145#endif
146 }
int FilterEvent(wxEvent &event) override

References FilterEvent(), audacity::cloud::audiocom::anonymous_namespace{AuthorizationHandler.cpp}::handler, mEvent, and mHandler.

Here is the call graph for this function:

◆ ~EventMonitor()

EventMonitor::~EventMonitor ( )
inlineoverride

Definition at line 148 of file KeyboardCapture.cpp.

149 {
150#if defined(__WXMAC__)
151 wxEvtHandler::RemoveFilter(this);
152 [NSEvent removeMonitor:mHandler];
153#else
154 wxEvtHandler::RemoveFilter(this);
155#endif
156 }

References mHandler.

Member Function Documentation

◆ FilterEvent()

int EventMonitor::FilterEvent ( wxEvent &  event)
inlineoverride

Definition at line 158 of file KeyboardCapture.cpp.

159 {
160 // Unguarded exception propagation may crash the program, at least
161 // on Mac while in the objective-C closure above
162 return GuardedCall< int > ( [&] {
163 // Quickly bail if this isn't something we want.
164 wxEventType type = event.GetEventType();
165 if (type != wxEVT_CHAR_HOOK && type != wxEVT_KEY_UP)
166 {
167 return Event_Skip;
168 }
169
170 wxKeyEvent key = static_cast<wxKeyEvent &>( event );
171
173 return Event_Skip;
174
175#ifdef __WXMAC__
176 // Bugs 1329 and 2107 (Mac only)
177 // wxButton::SetDefault() alone doesn't cause correct event routing
178 // of key-down to the button when a text entry or combo has focus,
179 // but we can intercept wxEVT_CHAR_HOOK here and do it
180 if ( type == wxEVT_CHAR_HOOK &&
181 key.GetKeyCode() == WXK_RETURN ) {
182 const auto focus = wxWindow::FindFocus();
183 // Bug 2267 (Mac only): don't apply fix for 2107 when a text entry
184 // needs to allow multiple line input
185 const auto text = dynamic_cast<wxTextCtrl*>(focus);
186 if ( !(text && text->IsMultiLine()) ) {
187 if (auto top =
188 dynamic_cast< wxTopLevelWindow* >(
189 wxGetTopLevelParent( focus ) ) ) {
190 if ( auto button =
191 dynamic_cast<wxButton*>( top->GetDefaultItem() ) ) {
192 wxCommandEvent newEvent{ wxEVT_BUTTON, button->GetId() };
193 newEvent.SetEventObject( button );
194 button->GetEventHandler()->AddPendingEvent( newEvent );
195 return Event_Processed;
196 }
197 }
198 }
199 }
200#endif
201
202 // Make a copy of the event and (possibly) make it look like a key down
203 // event.
204 if (type == wxEVT_CHAR_HOOK)
205 {
206 key.SetEventType(wxEVT_KEY_DOWN);
207 }
208
209 // Give the capture handler first dibs at the event.
212 {
213 return Event_Processed;
214 }
215
217 return Event_Processed;
218
219 // Give it back to WX for normal processing.
220 return Event_Skip;
221 },
222 // Immediate handler invokes the same high level catch-all as for
223 // unhandled exceptions, which will also do its own delayed handling
224 [](AudacityException *pEx){
225 if (pEx)
226 wxTheApp->OnExceptionInMainLoop();
227 else
228 throw;
229 return Event_Processed;
230 },
231 // So don't duplicate delayed handling:
232 [](auto){}
233 );
234 }
static const AudacityProject::AttachedObjects::RegisteredFactory key
Base class for exceptions specially processed by the application.
bool HandleCapture(wxWindow *target, const wxKeyEvent &event)
static result_type Call(Arguments &&...arguments)
Null check of the installed function is done for you.
std::unique_ptr< WindowPlacement > FindFocus()
Find the window that is accepting keyboard input, if any.
Definition: BasicUI.h:383
wxWindow * GetHandler()

References GlobalHook< PreFilter, bool(wxKeyEvent &) >::Call(), GlobalHook< PostFilter, bool(wxKeyEvent &) >::Call(), BasicUI::FindFocus(), KeyboardCapture::GetHandler(), HandleCapture(), audacity::cloud::audiocom::anonymous_namespace{AuthorizationHandler.cpp}::handler, and key.

Referenced by EventMonitor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetUnicodeString()

wxString EventMonitor::GetUnicodeString ( const wxKeyEvent &  event)
inlineprivate

Definition at line 309 of file KeyboardCapture.cpp.

310 {
311 wxString chars;
312
313#if defined(__WXMSW__)
314
315 BYTE ks[256];
316 GetKeyboardState(ks);
317 WCHAR ucode[256];
318 int res = ToUnicode(event.GetRawKeyCode(), 0, ks, ucode, 256, 0);
319 if (res >= 1)
320 {
321 chars.Append(ucode, res);
322 }
323
324#elif defined(__WXGTK__)
325
326 chars.Append((wxChar) gdk_keyval_to_unicode(event.GetRawKeyCode()));
327
328#elif defined(__WXMAC__)
329
330 if (!mEvent) {
331 // TODO: we got here without getting the NSEvent pointer,
332 // as in the combo box case of bug 1252. We can't compute it!
333 // This makes a difference only when there is a capture handler.
334 // It's never the case yet that there is one.
335
336 // Return just a one-character string.
337 return event.GetUnicodeKey();
338 }
339
340 NSString *c = [mEvent charactersIgnoringModifiers];
341 if ([c length] == 1)
342 {
343 unichar codepoint = [c characterAtIndex:0];
344 if ((codepoint >= 0xF700 && codepoint <= 0xF8FF) || codepoint == 0x7F)
345 {
346 return chars;
347 }
348 }
349
350 c = [mEvent characters];
351 chars = [c UTF8String];
352
353 auto uchr = static_cast<CFDataRef>(TISGetInputSourceProperty(
354 CF_ptr<TISInputSourceRef>{ TISCopyCurrentKeyboardInputSource() }
355 .get(),
356 kTISPropertyUnicodeKeyLayoutData));
357 if (!uchr)
358 return chars;
359
360 const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr);
361 if (keyboardLayout == NULL)
362 {
363 return chars;
364 }
365
366 const UniCharCount maxStringLength = 255;
367 UniCharCount actualStringLength = 0;
368 UniChar unicodeString[maxStringLength];
369 UInt32 nsflags = [mEvent modifierFlags];
370 UInt16 modifiers = (nsflags & NSAlphaShiftKeyMask ? alphaLock : 0) |
371 (nsflags & NSShiftKeyMask ? shiftKey : 0) |
372 (nsflags & NSControlKeyMask ? controlKey : 0) |
373 (nsflags & NSAlternateKeyMask ? optionKey : 0) |
374 (nsflags & NSCommandKeyMask ? cmdKey : 0);
375
376 OSStatus status = UCKeyTranslate(keyboardLayout,
377 [mEvent keyCode],
378 kUCKeyActionDown,
379 (modifiers >> 8) & 0xff,
380 LMGetKbdType(),
381 0,
383 maxStringLength,
384 &actualStringLength,
385 unicodeString);
386
387 if (status != noErr)
388 {
389 return chars;
390 }
391
392 chars = [ [NSString stringWithCharacters:unicodeString
393 length:(NSInteger)actualStringLength] UTF8String];
394
395#endif
396
397 return chars;
398 }

References mDeadKeyState, and mEvent.

Referenced by HandleCapture().

Here is the caller graph for this function:

◆ HandleCapture()

bool EventMonitor::HandleCapture ( wxWindow *  target,
const wxKeyEvent &  event 
)
inlineprivate

Definition at line 239 of file KeyboardCapture.cpp.

240 {
241 if (wxGetTopLevelParent(target) != wxGetTopLevelParent(wxWindow::FindFocus()))
242 {
243 return false;
244 }
245 wxEvtHandler *handler = target->GetEventHandler();
246
247 // We make a copy of the event because the capture handler may modify it.
248 wxKeyEvent temp = event;
249
250#if defined(__WXGTK__)
251 // wxGTK uses the control and alt modifiers to represent ALTGR,
252 // so remove it as it might confuse the capture handlers.
253 if (temp.GetModifiers() == (wxMOD_CONTROL | wxMOD_ALT))
254 {
255 temp.SetControlDown(false);
256 temp.SetAltDown(false);
257 }
258#endif
259
260 // Ask the capture handler if the key down/up event is something it
261 // might be interested in handling.
262 wxCommandEvent e(EVT_CAPTURE_KEY);
263 e.SetEventObject(&temp);
264 e.StopPropagation();
265 if (!handler->ProcessEvent(e))
266 {
267 return false;
268 }
269
270 // Now, let the handler process the normal key event.
271 bool keyDown = temp.GetEventType() == wxEVT_KEY_DOWN;
272 temp.WasProcessed();
273 temp.StopPropagation();
274 wxEventProcessInHandlerOnly onlyDown(temp, handler);
275 bool processed = handler->ProcessEvent(temp);
276
277 // Don't go any further if the capture handler didn't process
278 // the key down event.
279 if (!processed && keyDown)
280 {
281 return false;
282 }
283
284 // At this point the capture handler has either processed a key down event
285 // or we're dealing with a key up event.
286 //
287 // So, only generate the char events for key down events.
288 if (keyDown)
289 {
290 wxString chars = GetUnicodeString(temp);
291 for (size_t i = 0, cnt = chars.length(); i < cnt; i++)
292 {
293 temp = event;
294 temp.SetEventType(wxEVT_CHAR);
295 temp.WasProcessed();
296 temp.StopPropagation();
297 temp.m_uniChar = chars[i];
298 wxEventProcessInHandlerOnly onlyChar(temp, handler);
299 handler->ProcessEvent(temp);
300 }
301 }
302
303 // We get here for processed key down events or for key up events, whether
304 // processed or not.
305 return true;
306 }
wxString GetUnicodeString(const wxKeyEvent &event)

References BasicUI::FindFocus(), GetUnicodeString(), and audacity::cloud::audiocom::anonymous_namespace{AuthorizationHandler.cpp}::handler.

Referenced by FilterEvent().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ mDeadKeyState

UInt32 EventMonitor::mDeadKeyState
private

Definition at line 405 of file KeyboardCapture.cpp.

Referenced by GetUnicodeString().

◆ mEvent

NSEvent* EventMonitor::mEvent {}
private

Definition at line 404 of file KeyboardCapture.cpp.

Referenced by EventMonitor(), and GetUnicodeString().

◆ mHandler

id EventMonitor::mHandler
private

Definition at line 403 of file KeyboardCapture.cpp.

Referenced by EventMonitor(), and ~EventMonitor().


The documentation for this class was generated from the following file: