summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2022-01-05 08:40:53 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2022-01-05 08:40:53 +0200
commit32cbf877ac137b28eb41a9084717707907c02d94 (patch)
treedb971de78c1869a2c3a713080aa6222003e946c6
parent31312b7a2e51a87a41bf777b6af135329927460d (diff)
Handling keys while navigating via home row
When navigating via home row, ensure that other widgets will not trigger when keys are pressed. The document is given keyboard focus even though it is not flagged as focusable, to make sure it gets to handle all the keys first. On macOS, disable all native menu items that have a home row keyboard shortcut. Also on macOS, disable all native menus when changing bindings. IssueID #419
-rw-r--r--src/macos.h2
-rw-r--r--src/macos.m49
-rw-r--r--src/ui/bindingswidget.c6
-rw-r--r--src/ui/documentwidget.c20
-rw-r--r--src/ui/widget.c10
-rw-r--r--src/ui/widget.h3
6 files changed, 82 insertions, 8 deletions
diff --git a/src/macos.h b/src/macos.h
index 22a6dfff..10cbba81 100644
--- a/src/macos.h
+++ b/src/macos.h
@@ -39,8 +39,10 @@ void hideTitleBar_MacOS (iWindow *window);
39void insertMenuItems_MacOS (const char *menuLabel, int atIndex, const iMenuItem *items, size_t count); 39void insertMenuItems_MacOS (const char *menuLabel, int atIndex, const iMenuItem *items, size_t count);
40void removeMenu_MacOS (int atIndex); 40void removeMenu_MacOS (int atIndex);
41void enableMenu_MacOS (const char *menuLabel, iBool enable); 41void enableMenu_MacOS (const char *menuLabel, iBool enable);
42void enableMenuIndex_MacOS (int index, iBool enable);
42void enableMenuItem_MacOS (const char *menuItemCommand, iBool enable); 43void enableMenuItem_MacOS (const char *menuItemCommand, iBool enable);
43void enableMenuItemsByKey_MacOS (int key, int kmods, iBool enable); 44void enableMenuItemsByKey_MacOS (int key, int kmods, iBool enable);
45void enableMenuItemsOnHomeRow_MacOS(iBool enable);
44void handleCommand_MacOS (const char *cmd); 46void handleCommand_MacOS (const char *cmd);
45 47
46void showPopupMenu_MacOS (iWidget *source, iInt2 windowCoord, const iMenuItem *items, size_t n); 48void showPopupMenu_MacOS (iWidget *source, iInt2 windowCoord, const iMenuItem *items, size_t n);
diff --git a/src/macos.m b/src/macos.m
index cfbca488..28e349ea 100644
--- a/src/macos.m
+++ b/src/macos.m
@@ -31,6 +31,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
31 31
32#include <SDL_timer.h> 32#include <SDL_timer.h>
33#include <SDL_syswm.h> 33#include <SDL_syswm.h>
34#include <the_Foundation/stringset.h>
34 35
35#import <AppKit/AppKit.h> 36#import <AppKit/AppKit.h>
36 37
@@ -439,6 +440,13 @@ void enableMenu_MacOS(const char *menuLabel, iBool enable) {
439 [menuItem setEnabled:enable]; 440 [menuItem setEnabled:enable];
440} 441}
441 442
443void enableMenuIndex_MacOS(int index, iBool enable) {
444 NSApplication *app = [NSApplication sharedApplication];
445 NSMenu *appMenu = [app mainMenu];
446 NSMenuItem *menuItem = [appMenu itemAtIndex:index];
447 [menuItem setEnabled:enable];
448}
449
442void enableMenuItem_MacOS(const char *menuItemCommand, iBool enable) { 450void enableMenuItem_MacOS(const char *menuItemCommand, iBool enable) {
443 NSApplication *app = [NSApplication sharedApplication]; 451 NSApplication *app = [NSApplication sharedApplication];
444 NSMenu *appMenu = [app mainMenu]; 452 NSMenu *appMenu = [app mainMenu];
@@ -513,6 +521,47 @@ void enableMenuItemsByKey_MacOS(int key, int kmods, iBool enable) {
513 delete_String(keyEquiv); 521 delete_String(keyEquiv);
514} 522}
515 523
524void enableMenuItemsOnHomeRow_MacOS(iBool enable) {
525 iStringSet *homeRowKeys = new_StringSet();
526 const char *keys[] = { /* Note: another array in documentwidget.c */
527 "f", "d", "s", "a",
528 "j", "k", "l",
529 "r", "e", "w", "q",
530 "u", "i", "o", "p",
531 "v", "c", "x", "z",
532 "m", "n",
533 "g", "h",
534 "b",
535 "t", "y"
536 };
537 iForIndices(i, keys) {
538 iString str;
539 initCStr_String(&str, keys[i]);
540 insert_StringSet(homeRowKeys, &str);
541 deinit_String(&str);
542 }
543 NSApplication *app = [NSApplication sharedApplication];
544 NSMenu *appMenu = [app mainMenu];
545 for (NSMenuItem *mainMenuItem in appMenu.itemArray) {
546 NSMenu *menu = mainMenuItem.submenu;
547 if (menu) {
548 for (NSMenuItem *menuItem in menu.itemArray) {
549 if (menuItem.keyEquivalentModifierMask == 0) {
550 iString equiv;
551 initCStr_String(&equiv, [menuItem.keyEquivalent
552 cStringUsingEncoding:NSUTF8StringEncoding]);
553 if (contains_StringSet(homeRowKeys, &equiv)) {
554 [menuItem setEnabled:enable];
555 [menu setAutoenablesItems:NO];
556 }
557 deinit_String(&equiv);
558 }
559 }
560 }
561 }
562 iRelease(homeRowKeys);
563}
564
516static void setShortcut_NSMenuItem_(NSMenuItem *item, int key, int kmods) { 565static void setShortcut_NSMenuItem_(NSMenuItem *item, int key, int kmods) {
517 NSEventModifierFlags modMask; 566 NSEventModifierFlags modMask;
518 iString *str = composeKeyEquivalent_(key, kmods, &modMask); 567 iString *str = composeKeyEquivalent_(key, kmods, &modMask);
diff --git a/src/ui/bindingswidget.c b/src/ui/bindingswidget.c
index 4cf8df8e..13f9434e 100644
--- a/src/ui/bindingswidget.c
+++ b/src/ui/bindingswidget.c
@@ -143,12 +143,16 @@ static void setActiveItem_BindingsWidget_(iBindingsWidget *d, size_t pos) {
143 item->isWaitingForEvent = iTrue; 143 item->isWaitingForEvent = iTrue;
144 invalidateItem_ListWidget(d->list, d->activePos); 144 invalidateItem_ListWidget(d->list, d->activePos);
145 } 145 }
146#if defined (iPlatformAppleDesktop) 146#if defined (iPlatformAppleDesktop) && defined (iHaveNativeContextMenus)
147 /* Native menus must be disabled while grabbing keys so the shortcuts don't trigger. */ 147 /* Native menus must be disabled while grabbing keys so the shortcuts don't trigger. */
148 const iBool enableNativeMenus = (d->activePos == iInvalidPos); 148 const iBool enableNativeMenus = (d->activePos == iInvalidPos);
149 enableMenu_MacOS("${menu.title.file}", enableNativeMenus);
149 enableMenu_MacOS("${menu.title.edit}", enableNativeMenus); 150 enableMenu_MacOS("${menu.title.edit}", enableNativeMenus);
150 enableMenu_MacOS("${menu.title.view}", enableNativeMenus); 151 enableMenu_MacOS("${menu.title.view}", enableNativeMenus);
152 enableMenu_MacOS("${menu.title.bookmarks}", enableNativeMenus);
151 enableMenu_MacOS("${menu.title.identity}", enableNativeMenus); 153 enableMenu_MacOS("${menu.title.identity}", enableNativeMenus);
154 enableMenuIndex_MacOS(6, enableNativeMenus);
155 enableMenuIndex_MacOS(7, enableNativeMenus);
152#endif 156#endif
153} 157}
154 158
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 46af5fcd..f83539f7 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -55,6 +55,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
55#include "visbuf.h" 55#include "visbuf.h"
56#include "visited.h" 56#include "visited.h"
57 57
58#if defined (iPlatformAppleDesktop)
59# include "macos.h"
60#endif
58#if defined (iPlatformAppleMobile) 61#if defined (iPlatformAppleMobile)
59# include "ios.h" 62# include "ios.h"
60#endif 63#endif
@@ -469,11 +472,18 @@ static void enableActions_DocumentWidget_(iDocumentWidget *d, iBool enable) {
469} 472}
470 473
471static void setLinkNumberMode_DocumentWidget_(iDocumentWidget *d, iBool set) { 474static void setLinkNumberMode_DocumentWidget_(iDocumentWidget *d, iBool set) {
472 iChangeFlags(d->flags, showLinkNumbers_DocumentWidgetFlag, set); 475 if (((d->flags & showLinkNumbers_DocumentWidgetFlag) != 0) != set) {
473 /* Children have priority when handling events. */ 476 iChangeFlags(d->flags, showLinkNumbers_DocumentWidgetFlag, set);
474 enableActions_DocumentWidget_(d, !set); 477 /* Children have priority when handling events. */
475 if (d->menu) { 478 enableActions_DocumentWidget_(d, !set);
476 setFlags_Widget(d->menu, disabled_WidgetFlag, set); 479#if defined (iPlatformAppleDesktop)
480 enableMenuItemsOnHomeRow_MacOS(!set);
481#endif
482 /* Ensure all keyboard events come here first. */
483 setKeyboardGrab_Widget(set ? as_Widget(d) : NULL);
484 if (d->menu) {
485 setFlags_Widget(d->menu, disabled_WidgetFlag, set);
486 }
477 } 487 }
478} 488}
479 489
diff --git a/src/ui/widget.c b/src/ui/widget.c
index cedda461..28c34ccf 100644
--- a/src/ui/widget.c
+++ b/src/ui/widget.c
@@ -1961,7 +1961,8 @@ iBool isAffectedByVisualOffset_Widget(const iWidget *d) {
1961} 1961}
1962 1962
1963void setFocus_Widget(iWidget *d) { 1963void setFocus_Widget(iWidget *d) {
1964 iWindow *win = get_Window(); 1964 iWindow *win = d ? window_Widget(d) : get_Window();
1965 iAssert(win);
1965 if (win->focus != d) { 1966 if (win->focus != d) {
1966 if (win->focus) { 1967 if (win->focus) {
1967 iAssert(!contains_PtrSet(win->focus->root->pendingDestruction, win->focus)); 1968 iAssert(!contains_PtrSet(win->focus->root->pendingDestruction, win->focus));
@@ -1976,6 +1977,13 @@ void setFocus_Widget(iWidget *d) {
1976 } 1977 }
1977} 1978}
1978 1979
1980void setKeyboardGrab_Widget(iWidget *d) {
1981 iWindow *win = d ? window_Widget(d) : get_Window();
1982 iAssert(win);
1983 win->focus = d;
1984 /* no notifications sent */
1985}
1986
1979iWidget *focus_Widget(void) { 1987iWidget *focus_Widget(void) {
1980 return get_Window()->focus; 1988 return get_Window()->focus;
1981} 1989}
diff --git a/src/ui/widget.h b/src/ui/widget.h
index 4025f5c5..57088c07 100644
--- a/src/ui/widget.h
+++ b/src/ui/widget.h
@@ -302,7 +302,8 @@ void scrollInfo_Widget (const iWidget *, iWidgetScrollInfo *inf
302 302
303int backgroundFadeColor_Widget (void); 303int backgroundFadeColor_Widget (void);
304 304
305void setFocus_Widget (iWidget *); 305void setFocus_Widget (iWidget *); /* widget must be flagged `focusable` */
306void setKeyboardGrab_Widget (iWidget *); /* sets focus on any widget */
306iWidget * focus_Widget (void); 307iWidget * focus_Widget (void);
307void setHover_Widget (iWidget *); 308void setHover_Widget (iWidget *);
308iWidget * hover_Widget (void); 309iWidget * hover_Widget (void);