KiCad PCB EDA Suite
Loading...
Searching...
No Matches
tool_dispatcher.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2013 CERN
5 * Copyright The KiCad Developers, see CHANGELOG.txt for contributors.
6 * @author Tomasz Wlostowski <[email protected]>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
27
28#include <bit>
29#include <optional>
30
31#include <wx/log.h>
32#include <wx/stc/stc.h>
33#include <wx/settings.h>
34
35#include <core/ignore.h>
36#include <macros.h>
37#include <trace_helpers.h>
38#include <tool/tool_manager.h>
39#include <tool/actions.h>
40#include <tool/action_manager.h>
41#include <tool/action_menu.h>
42#include <view/view.h>
44#include <eda_draw_frame.h>
45#include <core/kicad_algo.h>
46
47#include <kiplatform/app.h>
48#include <kiplatform/ui.h>
49
50
53{
54 BUTTON_STATE( TOOL_MOUSE_BUTTONS aButton, const wxEventType& aDownEvent,
55 const wxEventType& aUpEvent, const wxEventType& aDblClickEvent ) :
56 dragging( false ),
57 pressed( false ),
58 button( aButton ),
59 downEvent( aDownEvent ),
60 upEvent( aUpEvent ),
61 dblClickEvent( aDblClickEvent )
62 {};
63
66
68 bool pressed;
69
72
75
78
81
83 wxEventType downEvent;
84
86 wxEventType upEvent;
87
89 wxEventType dblClickEvent;
90
92 wxLongLong downTimestamp;
93
95 void Reset()
96 {
97 dragging = false;
98 pressed = false;
99 }
100
102 bool GetState() const
103 {
104 wxMouseState mouseState = wxGetMouseState();
105
106 switch( button )
107 {
108 case BUT_LEFT:
109 return mouseState.LeftIsDown();
110
111 case BUT_MIDDLE:
112 return mouseState.MiddleIsDown();
113
114 case BUT_RIGHT:
115 return mouseState.RightIsDown();
116
117 case BUT_AUX1:
118 return mouseState.Aux1IsDown();
119
120 case BUT_AUX2:
121 return mouseState.Aux2IsDown();
122
123 default:
124 wxFAIL_MSG( wxT( "unknown button" ) );
125 return false;
126 }
127 }
128};
129
130
132 m_toolMgr( aToolMgr )
133{
134 m_sysDragMinX = wxSystemSettings::GetMetric( wxSYS_DRAG_X );
135 m_sysDragMinY = wxSystemSettings::GetMetric( wxSYS_DRAG_Y );
136
139
140 m_buttons.push_back( new BUTTON_STATE( BUT_LEFT, wxEVT_LEFT_DOWN,
141 wxEVT_LEFT_UP, wxEVT_LEFT_DCLICK ) );
142 m_buttons.push_back( new BUTTON_STATE( BUT_RIGHT, wxEVT_RIGHT_DOWN,
143 wxEVT_RIGHT_UP, wxEVT_RIGHT_DCLICK ) );
144 m_buttons.push_back( new BUTTON_STATE( BUT_MIDDLE, wxEVT_MIDDLE_DOWN,
145 wxEVT_MIDDLE_UP, wxEVT_MIDDLE_DCLICK ) );
146 m_buttons.push_back( new BUTTON_STATE( BUT_AUX1, wxEVT_AUX1_DOWN,
147 wxEVT_AUX1_UP, wxEVT_AUX1_DCLICK ) );
148 m_buttons.push_back( new BUTTON_STATE( BUT_AUX2, wxEVT_AUX2_DOWN,
149 wxEVT_AUX2_UP, wxEVT_AUX2_DCLICK ) );
150
151 ResetState();
152}
153
154
156{
157 for( BUTTON_STATE* st : m_buttons )
158 delete st;
159}
160
161int TOOL_DISPATCHER::decodeModifiers( const wxKeyboardState* aState )
162{
163 int mods = 0;
164 int wxmods = aState->GetModifiers();
165
166 // Returns the state of key modifiers (Alt, Ctrl and so on). Be carefull:
167 // the flag wxMOD_ALTGR is defined in wxWidgets as wxMOD_CONTROL|wxMOD_ALT
168 // So AltGr key cannot used as modifier key because it is the same as Alt key + Ctrl key.
169#if CAN_USE_ALTGR_KEY
170 if( wxmods & wxMOD_ALTGR )
171 mods |= MD_ALTGR;
172 else
173#endif
174 {
175 if( wxmods & wxMOD_CONTROL )
176 mods |= MD_CTRL;
177
178 if( wxmods & wxMOD_ALT )
179 mods |= MD_ALT;
180 }
181
182 if( wxmods & wxMOD_SHIFT )
183 mods |= MD_SHIFT;
184
185#ifdef wxMOD_META
186 if( wxmods & wxMOD_META )
187 mods |= MD_META;
188#endif
189
190#ifdef wxMOD_WIN
191 if( wxmods & wxMOD_WIN )
192 mods |= MD_SUPER;
193#endif
194
195 return mods;
196}
197
198
200{
201 for( BUTTON_STATE* st : m_buttons )
202 st->Reset();
203}
204
205
207{
208 return m_toolMgr->GetView();
209}
210
211
212bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMotion )
213{
214 BUTTON_STATE* st = m_buttons[aIndex];
215 wxEventType type = aEvent.GetEventType();
216 std::optional<TOOL_EVENT> evt;
217 bool isClick = false;
218
219// bool up = type == st->upEvent;
220// bool down = type == st->downEvent;
221 bool up = false, down = false;
222 bool dblClick = type == st->dblClickEvent;
223 bool state = st->GetState();
224
225 if( !dblClick )
226 {
227 // Sometimes the dispatcher does not receive mouse button up event, so it stays
228 // in the dragging mode even if the mouse button is not held anymore
229 if( st->pressed && !state )
230 up = true;
231 // Don't apply same logic to down events as it kills touchpad tapping
232 else if( !st->pressed && type == st->downEvent )
233 down = true;
234 }
235
236 int mods = decodeModifiers( static_cast<wxMouseEvent*>( &aEvent ) );
237 int args = st->button | mods;
238
239 if( down ) // Handle mouse button press
240 {
241 st->downTimestamp = wxGetLocalTimeMillis();
242
243 if( !st->pressed ) // save the drag origin on the first click only
244 {
247 }
248
250 st->pressed = true;
251 evt = TOOL_EVENT( TC_MOUSE, TA_MOUSE_DOWN, args );
252 }
253 else if( up ) // Handle mouse button release
254 {
255 st->pressed = false;
256
257 if( st->dragging )
258 evt = TOOL_EVENT( TC_MOUSE, TA_MOUSE_UP, args );
259 else
260 isClick = true;
261
262 if( isClick )
263 evt = TOOL_EVENT( TC_MOUSE, TA_MOUSE_CLICK, args );
264
265 st->dragging = false;
266 }
267 else if( dblClick )
268 {
269 evt = TOOL_EVENT( TC_MOUSE, TA_MOUSE_DBLCLICK, args );
270 }
271
272 if( st->pressed && aMotion )
273 {
274 if( !st->dragging )
275 {
276#ifdef __WXMAC__
277 if( wxGetLocalTimeMillis() - st->downTimestamp > DragTimeThreshold )
278 st->dragging = true;
279#endif
281
282 if( abs( offset.x ) > m_sysDragMinX || abs( offset.y ) > m_sysDragMinY )
283 st->dragging = true;
284
285 }
286
287 if( st->dragging )
288 {
289 evt = TOOL_EVENT( TC_MOUSE, TA_MOUSE_DRAG, args );
290 evt->setMouseDragOrigin( st->dragOrigin );
291 evt->setMouseDelta( m_lastMousePos - st->dragOrigin );
292 }
293 }
294
295 if( evt )
296 {
297 evt->SetMousePosition( isClick ? st->downPosition : m_lastMousePos );
298 m_toolMgr->ProcessEvent( *evt );
299
300 return true;
301 }
302
303 return false;
304}
305
306
315bool isKeySpecialCode( int aKeyCode )
316{
317 // These keys have predefined actions (like move thumbtrack cursor),
318 // and we do not want these actions executed
319 const std::vector<enum wxKeyCode> special_keys =
320 {
321 WXK_PAGEUP, WXK_PAGEDOWN,
322 WXK_NUMPAD_PAGEUP, WXK_NUMPAD_PAGEDOWN
323 };
324
325 return alg::contains( special_keys, aKeyCode );
326}
327
328
333static bool isKeyModifierOnly( int aKeyCode )
334{
335 static std::vector<enum wxKeyCode> special_keys =
336 {
337 WXK_CONTROL, WXK_RAW_CONTROL, WXK_SHIFT, WXK_ALT,
338#ifdef WXK_WINDOWS_LEFT
339 WXK_WINDOWS_LEFT, WXK_WINDOWS_RIGHT,
340#endif
341#ifdef WXK_MENU
342 WXK_MENU,
343#endif
344#ifdef WXK_COMMAND
345 WXK_COMMAND,
346#endif
347#ifdef WXK_META
348 WXK_META,
349#endif
350 };
351
352 return alg::contains( special_keys, aKeyCode );
353}
354
355
356static bool isMouseClick( wxEventType type )
357{
358 return type == wxEVT_LEFT_DOWN || type == wxEVT_LEFT_UP || type == wxEVT_LEFT_DCLICK
359 || type == wxEVT_MIDDLE_DOWN || type == wxEVT_MIDDLE_UP || type == wxEVT_MIDDLE_DCLICK
360 || type == wxEVT_RIGHT_DOWN || type == wxEVT_RIGHT_UP || type == wxEVT_RIGHT_DCLICK
361 || type == wxEVT_AUX1_DOWN || type == wxEVT_AUX1_UP || type == wxEVT_AUX1_DCLICK
362 || type == wxEVT_AUX2_DOWN || type == wxEVT_AUX2_UP || type == wxEVT_AUX2_DCLICK;
363}
364
365
380int translateSpecialCode( int aKeyCode )
381{
382 switch( aKeyCode )
383 {
384 case WXK_NUMPAD_UP: return WXK_UP;
385 case WXK_NUMPAD_DOWN: return WXK_DOWN;
386 case WXK_NUMPAD_LEFT: return WXK_LEFT;
387 case WXK_NUMPAD_RIGHT: return WXK_RIGHT;
388 case WXK_NUMPAD_PAGEUP: return WXK_PAGEUP;
389 case WXK_NUMPAD_PAGEDOWN: return WXK_PAGEDOWN;
390 default: break;
391 };
392
393 return aKeyCode;
394}
395
396
397std::optional<TOOL_EVENT> TOOL_DISPATCHER::GetToolEvent( wxKeyEvent* aKeyEvent, bool* keyIsSpecial )
398{
399 std::optional<TOOL_EVENT> evt;
400 int key = aKeyEvent->GetKeyCode();
401 int unicode_key = aKeyEvent->GetUnicodeKey();
402
403 // This wxEVT_CHAR_HOOK event can be ignored: not useful in KiCad
404 if( isKeyModifierOnly( key ) )
405 {
406 aKeyEvent->Skip();
407 return evt;
408 }
409
410 wxLogTrace( kicadTraceKeyEvent, wxS( "TOOL_DISPATCHER::GetToolEvent %s" ), dump( *aKeyEvent ) );
411
412 // if the key event must be skipped, skip it here if the event is a wxEVT_CHAR_HOOK
413 // and do nothing.
414 *keyIsSpecial = isKeySpecialCode( key );
415
416 if( aKeyEvent->GetEventType() == wxEVT_CHAR_HOOK )
417 key = translateSpecialCode( key );
418
419 int mods = decodeModifiers( aKeyEvent );
420
421 if( mods & MD_CTRL )
422 {
423 // wxWidgets maps key codes related to Ctrl+letter handled by CHAR_EVT
424 // (http://docs.wxwidgets.org/trunk/classwx_key_event.html):
425 // char events for ASCII letters in this case carry codes corresponding to the ASCII
426 // value of Ctrl-Latter, i.e. 1 for Ctrl-A, 2 for Ctrl-B and so on until 26 for Ctrl-Z.
427 // They are remapped here to be more easy to handle in code
428 // Note also on OSX wxWidgets has a different behavior and the mapping is made
429 // only for ctrl+'A' to ctlr+'Z' (unicode code return 'A' to 'Z').
430 // Others OS return WXK_CONTROL_A to WXK_CONTROL_Z, and Ctrl+'M' returns the same code as
431 // the return key, so the remapping does not use the unicode key value.
432#ifdef __APPLE__
433 if( unicode_key >= 'A' && unicode_key <= 'Z' && key >= WXK_CONTROL_A && key <= WXK_CONTROL_Z )
434#else
435 ignore_unused( unicode_key );
436
437 if( key >= WXK_CONTROL_A && key <= WXK_CONTROL_Z )
438#endif
439 key += 'A' - 1;
440 }
441
442#ifdef __APPLE__
443 if( mods & MD_ALT )
444 {
445 // OSX maps a bunch of commonly used extended-ASCII characters onto the keyboard
446 // using the ALT key. Since we use ALT for some of our hotkeys, we need to map back
447 // to the underlying keys. The kVK_ANSI_* values come from Apple and are said to be
448 // hardware independent.
449 switch( aKeyEvent->GetRawKeyCode() )
450 {
451 case /* kVK_ANSI_1 */ 0x12: key = '1'; break;
452 case /* kVK_ANSI_2 */ 0x13: key = '2'; break;
453 case /* kVK_ANSI_3 */ 0x14: key = '3'; break;
454 case /* kVK_ANSI_4 */ 0x15: key = '4'; break;
455 case /* kVK_ANSI_6 */ 0x16: key = '6'; break;
456 case /* kVK_ANSI_5 */ 0x17: key = '5'; break;
457 case /* kVK_ANSI_Equal */ 0x18: key = '='; break;
458 case /* kVK_ANSI_9 */ 0x19: key = '9'; break;
459 case /* kVK_ANSI_7 */ 0x1A: key = '7'; break;
460 case /* kVK_ANSI_Minus */ 0x1B: key = '-'; break;
461 case /* kVK_ANSI_8 */ 0x1C: key = '8'; break;
462 case /* kVK_ANSI_0 */ 0x1D: key = '0'; break;
463 default: ;
464 }
465 }
466#endif
467
468 if( key == WXK_ESCAPE ) // ESC is the special key for canceling tools
469 evt = TOOL_EVENT( TC_COMMAND, TA_CANCEL_TOOL, WXK_ESCAPE );
470 else
471 evt = TOOL_EVENT( TC_KEYBOARD, TA_KEY_PRESSED, key | mods );
472
473 return evt;
474}
475
476
478{
479 // When an escape key event arrives, keyboard events can be processed before mouse button
480 // events due to wxWidgets event queue ordering. If a mouse button was pressed and has since
481 // been released (detected via polling), we need to process that click before handling the
482 // escape to maintain proper event ordering.
483 for( BUTTON_STATE* st : m_buttons )
484 {
485 if( st->pressed && !st->GetState() )
486 {
487 st->pressed = false;
488
489 TOOL_EVENT clickEvt( TC_MOUSE, TA_MOUSE_CLICK, st->button );
490 clickEvt.SetMousePosition( st->downPosition );
491 m_toolMgr->ProcessEvent( clickEvt );
492
493 st->dragging = false;
494 }
495 }
496}
497
498
499void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
500{
501 bool motion = false;
502 bool buttonEvents = false;
503 VECTOR2D pos;
504 std::optional<TOOL_EVENT> evt;
505 bool keyIsEscape = false; // True if the keypress was the escape key
506 bool keyIsSpecial = false; // True if the key is a special key code
507 wxWindow* focus = wxWindow::FindFocus();
508
509 // Required in win32 to ensure wxTimer events get scheduled in between other events
510 // Or else we may stall them out entirely and never get them during actions like rapid
511 // mouse moves.
513
514 wxEventType type = aEvent.GetEventType();
515
516 // Sometimes there is no window that has the focus (it happens when another PCB_BASE_FRAME
517 // is opened and is iconized on Windows).
518 // In this case, give the focus to the parent frame (GAL canvas itself does not accept the
519 // focus when iconized for some obscure reason)
520 if( focus == nullptr )
521 {
522 wxWindow* holderWindow = dynamic_cast<wxWindow*>( m_toolMgr->GetToolHolder() );
523
524#if defined( _WIN32 ) || defined( __WXGTK__ )
525 // Mouse events may trigger regardless of window status (windows feature)
526 // However we need to avoid focus fighting (especially modals)
527 if( holderWindow && KIPLATFORM::UI::IsWindowActive( holderWindow ) )
528#else
529 if( holderWindow )
530#endif
531 {
532 holderWindow->SetFocus();
533 }
534 }
535
536 if( isMouseClick( type ) )
537 {
538 if( m_toolMgr->GetToolHolder() && m_toolMgr->GetToolHolder()->GetToolCanvas() &&
539 !m_toolMgr->GetToolHolder()->GetToolCanvas()->HasFocus() )
540 {
541 m_toolMgr->GetToolHolder()->GetToolCanvas()->SetFocus();
542 }
543 }
544
545 // Mouse handling
546 // Note: wxEVT_LEFT_DOWN event must always be skipped.
547 if( type == wxEVT_MOTION || type == wxEVT_MOUSEWHEEL ||
548 type == wxEVT_MAGNIFY ||
549 isMouseClick( type ) ||
550 // Event issued when mouse retains position in screen coordinates,
551 // but changes in world coordinates (e.g. autopanning)
553 {
554 wxMouseEvent* me = static_cast<wxMouseEvent*>( &aEvent );
555 int mods = decodeModifiers( me );
556
557 if( m_toolMgr->GetViewControls() )
558 {
559 pos = m_toolMgr->GetViewControls()->GetMousePosition();
560 m_lastMousePosScreen = m_toolMgr->GetViewControls()->GetMousePosition( false );
561
562 if( pos != m_lastMousePos )
563 {
564 motion = true;
565 m_lastMousePos = pos;
566 }
567 }
568
569 for( unsigned int i = 0; i < m_buttons.size(); i++ )
570 buttonEvents |= handleMouseButton( aEvent, i, motion );
571
572 if( m_toolMgr->GetViewControls() )
573 {
574 if( !buttonEvents && motion )
575 {
576 evt = TOOL_EVENT( TC_MOUSE, TA_MOUSE_MOTION, mods );
577 evt->SetMousePosition( pos );
578 }
579 }
580
581 // We only handle wheel events that aren't for the view control.
582 // Events with zero or one modifier are reserved for view control.
583 // When using WX_VIEW_CONTROLS, these will already be handled, but
584 // we still shouldn't consume such events if we get them (e.g. for
585 // when WX_VIEW_CONTROLS is not in use, like in the 3D viewer)
586 if( !evt && me->GetWheelRotation() != 0 )
587 {
588 const unsigned modBits =
589 static_cast<unsigned>( mods ) & MD_MODIFIER_MASK;
590 const bool shouldHandle = std::popcount( modBits ) > 1;
591
592 if( shouldHandle )
593 {
594 evt = TOOL_EVENT( TC_MOUSE, TA_MOUSE_WHEEL, mods );
595 evt->SetParameter<int>( me->GetWheelRotation() );
596 }
597 }
598 }
599 else if( type == wxEVT_CHAR_HOOK || type == wxEVT_CHAR )
600 {
601 wxKeyEvent* ke = static_cast<wxKeyEvent*>( &aEvent );
602
603 wxLogTrace( kicadTraceKeyEvent, wxS( "TOOL_DISPATCHER::DispatchWxEvent %s" ), dump( *ke ) );
604
605 // Do not process wxEVT_CHAR_HOOK for a shift-modified key, as ACTION_MANAGER::RunHotKey
606 // will run the un-shifted key and that's not what we want. Wait to get the translated
607 // key from wxEVT_CHAR.
608 // See https://gitlab.com/kicad/code/kicad/-/issues/1809
609 if( type == wxEVT_CHAR_HOOK && ke->GetModifiers() == wxMOD_SHIFT )
610 {
611 aEvent.Skip();
612 return;
613 }
614
615 keyIsEscape = ( ke->GetKeyCode() == WXK_ESCAPE );
616
617 // When escape is pressed shortly after a mouse click, the keyboard event can be
618 // processed before the mouse button release event. Flush any pending clicks first
619 // to ensure proper event ordering.
620 if( keyIsEscape )
622
623 if( KIUI::IsInputControlFocused( focus ) )
624 {
625 bool enabled = KIUI::IsInputControlEditable( focus );
626
627 // Never process key events for tools when a text entry has focus
628 if( enabled )
629 {
630 aEvent.Skip();
631 return;
632 }
633 // Even if not enabled, allow a copy out
634 else if( ke->GetModifiers() == wxMOD_CONTROL && ke->GetKeyCode() == 'C' )
635 {
636 aEvent.Skip();
637 return;
638 }
639 }
640
641 evt = GetToolEvent( ke, &keyIsSpecial );
642 }
643 else if( type == wxEVT_MENU_OPEN || type == wxEVT_MENU_CLOSE || type == wxEVT_MENU_HIGHLIGHT )
644 {
645 wxMenuEvent* tmp = dynamic_cast<wxMenuEvent*>( &aEvent );
646
647 // Something is amiss if the event has these types and isn't a menu event, so bail out on
648 // its processing
649 if( !tmp )
650 {
651 aEvent.Skip();
652 return;
653 }
654
655 wxMenuEvent& menuEvent = *tmp;
656
657#if wxCHECK_VERSION( 3, 2, 0 )
658 // Forward the event to the menu for processing
659 if( ACTION_MENU* currentMenu = dynamic_cast<ACTION_MENU*>( menuEvent.GetMenu() ) )
660 currentMenu->OnMenuEvent( menuEvent );
661#else
662 //
663 // wxWidgets has several issues that we have to work around:
664 //
665 // 1) wxWidgets 3.0.x Windows has a bug where wxEVT_MENU_OPEN and wxEVT_MENU_HIGHLIGHT
666 // events are not captured by the ACTON_MENU menus. So we forward them here.
667 // (FWIW, this one is fixed in wxWidgets 3.1.x.)
668 //
669 // 2) wxWidgets doesn't pass the menu pointer for wxEVT_MENU_HIGHLIGHT events. So we
670 // store the menu pointer from the wxEVT_MENU_OPEN call.
671 //
672 // 3) wxWidgets has no way to tell whether a command is from a menu selection or a
673 // hotkey. So we keep track of menu highlighting so we can differentiate.
674 //
675
676 static ACTION_MENU* currentMenu;
677
678 if( type == wxEVT_MENU_OPEN )
679 {
680 currentMenu = dynamic_cast<ACTION_MENU*>( menuEvent.GetMenu() );
681
682 if( currentMenu )
683 currentMenu->OnMenuEvent( menuEvent );
684 }
685 else if( type == wxEVT_MENU_HIGHLIGHT )
686 {
687 if( currentMenu )
688 currentMenu->OnMenuEvent( menuEvent );
689 }
690 else if( type == wxEVT_MENU_CLOSE )
691 {
692 if( currentMenu )
693 currentMenu->OnMenuEvent( menuEvent );
694
695 currentMenu = nullptr;
696 }
697#endif
698
699 aEvent.Skip();
700 }
701
702 bool handled = false;
703
704 if( evt )
705 {
706 wxLogTrace( kicadTraceToolStack, wxS( "TOOL_DISPATCHER::DispatchWxEvent %s" ),
707 evt->Format() );
708
709 handled = m_toolMgr->ProcessEvent( *evt );
710
711 wxLogTrace( kicadTraceToolStack,
712 wxS( "TOOL_DISPATCHER::DispatchWxEvent - Handled: %s %s" ),
713 ( handled ? wxS( "true" ) : wxS( "false" ) ), evt->Format() );
714 }
715
716 // pass the event to the GUI, it might still be interested in it
717 // Note wxEVT_CHAR_HOOK event is already skipped for special keys not used by KiCad
718 // and wxEVT_LEFT_DOWN must be always Skipped.
719 //
720 // On OS X, key events are always meant to be caught. An uncaught key event is assumed
721 // to be a user input error by OS X (as they are pressing keys in a context where nothing
722 // is there to catch the event). This annoyingly makes OS X beep and/or flash the screen
723 // in Pcbnew and the footprint editor any time a hotkey is used. The correct procedure is
724 // to NOT pass wxEVT_CHAR events to the GUI under OS X.
725 //
726 // On Windows, avoid to call wxEvent::Skip for special keys because some keys
727 // (PAGE_UP, PAGE_DOWN) have predefined actions (like move thumbtrack cursor), and we do
728 // not want these actions executed (most are handled by KiCad)
729
730 if( !evt || type == wxEVT_LEFT_DOWN )
731 aEvent.Skip();
732
733 // Not handled wxEVT_CHAR must be Skipped (sent to GUI).
734 // Otherwise accelerators and shortcuts in main menu or toolbars are not seen.
735 // Escape key presses are never skipped by the handler since they correspond to tool cancel
736 // events, and if they aren't skipped then they are propagated to other frames (which we
737 // don't want).
738 if( ( type == wxEVT_CHAR || type == wxEVT_CHAR_HOOK )
739 && !keyIsSpecial
740 && !handled
741 && !keyIsEscape )
742 {
743 aEvent.Skip();
744 }
745
746 wxLogTrace( kicadTraceToolStack, "TOOL_DISPATCHER::DispatchWxEvent - Wx event skipped: %s",
747 ( aEvent.GetSkipped() ? "true" : "false" ) );
748}
749
750// LocalWords: EDA CERN CHANGELOG txt Tomasz Wlostowski wxEvent WXK
751// LocalWords: MERCHANTABILITY bool upEvent downEvent touchpad Ctrl
752// LocalWords: wxEVENT isKeySpecialCode thumbtrack DispatchWxEvent
753// LocalWords: NUMPAD PAGEUP PAGEDOWN wxEVT EVT OSX ctrl ctlr kVK
754// LocalWords: unicode ESC keypress wxTimer iconized autopanning WX
755// LocalWords: un Wx
Define the structure of a menu based on ACTIONs.
Definition action_menu.h:47
void OnMenuEvent(wxMenuEvent &aEvent)
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:66
static const wxEventType EVT_REFRESH_MOUSE
Event that forces mouse move event in the dispatcher (eg.
static const int DragDistanceThreshold
The distance threshold for mouse cursor that distinguishes between a single mouse click and a beginni...
static const int DragTimeThreshold
The time threshold for a mouse button press that distinguishes between a single mouse click and a beg...
virtual void ResetState()
Bring the dispatcher to its initial state.
virtual void DispatchWxEvent(wxEvent &aEvent)
Process wxEvents (mostly UI events), translate them to TOOL_EVENTs, and make tools handle those.
KIGFX::VIEW * getView()
Returns the instance of VIEW, used by the application.
int m_sysDragMinX
Minimum distance before drag is activated in the X axis.
bool handleMouseButton(wxEvent &aEvent, int aIndex, bool aMotion)
Handles mouse related events (click, motion, dragging).
int m_sysDragMinY
Maximum distance before drag is activated in the Y axis.
static int decodeModifiers(const wxKeyboardState *aState)
Returns the state of key modifiers (Alt, Ctrl and so on) as OR'ed list of bits (MD_CTRL,...
void flushPendingClicks()
Processes any pending mouse clicks that have been physically completed but not yet dispatched.
VECTOR2D m_lastMousePosScreen
The last mouse cursor position (in screen coordinates).
TOOL_MANAGER * m_toolMgr
Instance of tool manager that cooperates with the dispatcher.
TOOL_DISPATCHER(TOOL_MANAGER *aToolMgr)
std::vector< BUTTON_STATE * > m_buttons
VECTOR2D m_lastMousePos
The last mouse cursor position (in world coordinates).
std::optional< TOOL_EVENT > GetToolEvent(wxKeyEvent *aKeyEvent, bool *aSpecialKeyFlag)
Map a wxWidgets key event to a TOOL_EVENT.
Generic, UI-independent tool event.
Definition tool_event.h:171
void SetMousePosition(const VECTOR2D &aP)
Definition tool_event.h:538
Master controller class:
const wxChar *const kicadTraceKeyEvent
Flag to enable wxKeyEvent debug tracing.
const wxChar *const kicadTraceToolStack
Flag to enable tracing of the tool handling stack.
void ignore_unused(const T &)
Definition ignore.h:24
This file contains miscellaneous commonly used macros and functions.
void ForceTimerMessagesToBeCreatedIfNecessary()
Forces wxTimers to fire more promptly on Win32.
Definition unix/app.cpp:95
bool IsWindowActive(wxWindow *aWindow)
Check to see if the given window is the currently active window (e.g.
Definition wxgtk/ui.cpp:147
KICOMMON_API bool IsInputControlFocused(wxWindow *aFocus=nullptr)
Check if a input control has focus.
KICOMMON_API bool IsInputControlEditable(wxWindow *aControl)
Check if a input control has focus.
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:100
Store information about a mouse button state.
VECTOR2D dragOrigin
Point where dragging has started (in world coordinates).
wxEventType dblClickEvent
The type of wxEvent that determines mouse button double click.
wxEventType upEvent
The type of wxEvent that determines mouse button release.
VECTOR2D downPosition
Point where click event has occurred.
bool dragging
Flag indicating that dragging is active for the given button.
bool GetState() const
Checks the current state of the button.
bool pressed
Flag indicating that the given button is pressed.
BUTTON_STATE(TOOL_MOUSE_BUTTONS aButton, const wxEventType &aDownEvent, const wxEventType &aUpEvent, const wxEventType &aDblClickEvent)
wxLongLong downTimestamp
Time stamp for the last mouse button press event.
TOOL_MOUSE_BUTTONS button
Determines the mouse button for which information are stored.
void Reset()
Restores initial state.
wxEventType downEvent
The type of wxEvent that determines mouse button press.
VECTOR2D dragOriginScreen
Point where dragging has started (in screen coordinates).
static bool isMouseClick(wxEventType type)
bool isKeySpecialCode(int aKeyCode)
Helper to know if a special key ( see key list ) should be captured.
int translateSpecialCode(int aKeyCode)
Convert some special key codes to an equivalent.
static bool isKeyModifierOnly(int aKeyCode)
Helper to know if a key should be managed by DispatchWxEvent() or if the event can be ignored and ski...
@ TA_MOUSE_CLICK
Definition tool_event.h:67
@ TA_MOUSE_MOTION
Definition tool_event.h:72
@ TA_MOUSE_UP
Definition tool_event.h:69
@ TA_MOUSE_DRAG
Definition tool_event.h:71
@ TA_MOUSE_DOWN
Definition tool_event.h:70
@ TA_KEY_PRESSED
Definition tool_event.h:76
@ TA_MOUSE_DBLCLICK
Definition tool_event.h:68
@ TA_MOUSE_WHEEL
Definition tool_event.h:73
@ TA_CANCEL_TOOL
Tool cancel event.
Definition tool_event.h:90
@ MD_MODIFIER_MASK
Definition tool_event.h:149
@ MD_META
Definition tool_event.h:147
@ MD_ALT
Definition tool_event.h:145
@ MD_CTRL
Definition tool_event.h:144
@ MD_SUPER
Definition tool_event.h:146
@ MD_ALTGR
Definition tool_event.h:148
@ MD_SHIFT
Definition tool_event.h:143
@ TC_COMMAND
Definition tool_event.h:57
@ TC_MOUSE
Definition tool_event.h:55
@ TC_KEYBOARD
Definition tool_event.h:56
TOOL_MOUSE_BUTTONS
Definition tool_event.h:130
@ BUT_AUX1
Definition tool_event.h:135
@ BUT_MIDDLE
Definition tool_event.h:134
@ BUT_LEFT
Definition tool_event.h:132
@ BUT_RIGHT
Definition tool_event.h:133
@ BUT_AUX2
Definition tool_event.h:136
wxString dump(const wxArrayString &aArray)
Debug helper for printing wxArrayString contents.
wxLogTrace helper definitions.
VECTOR2< double > VECTOR2D
Definition vector2d.h:694
WX_VIEW_CONTROLS class definition.