Ticket #7078: menuItemsShortcutsPatch.diff

File menuItemsShortcutsPatch.diff, 11.4 KB (added by leavengood, 9 years ago)

First revision of patch to allow for shortcuts without the command key

  • headers/os/interface/Window.h

     
    334334                                    bool notifyIputServer = false);
    335335            void                _SetName(const char* title);
    336336
     337            void                _AddShortcut(uint32 key, uint32 modifiers, Shortcut* shortcut);
    337338            Shortcut*           _FindShortcut(uint32 key, uint32 modifiers);
    338339            BView*              _FindView(BView* view, BPoint point) const;
    339340            BView*              _FindView(int32 token);
  • headers/os/interface/MenuItem.h

     
    8585            void                _DrawSubmenuSymbol(rgb_color backgroundColor);
    8686            void                _DrawControlChar(char shortcut, BPoint where);
    8787
     88            bool                _IsValidShortcut(char shortcut, uint32 modifiers);
     89
    8890private:
    8991            char*               fLabel;
    9092            BMenu*              fSubmenu;
  • headers/os/interface/InterfaceDefs.h

     
    151151    B_LEFT_CONTROL_KEY  = 0x00001000,
    152152    B_RIGHT_CONTROL_KEY = 0x00002000,
    153153    B_LEFT_OPTION_KEY   = 0x00004000,
    154     B_RIGHT_OPTION_KEY  = 0x00008000
     154    B_RIGHT_OPTION_KEY  = 0x00008000,
     155    B_NO_MODIFIERS      = 0x00010000
    155156};
    156157
    157158
  • src/kits/interface/Window.cpp

     
    103103    static  uint32          PrepareModifiers(uint32 modifiers);
    104104
    105105private:
     106            uint32          _InitializeModifiers(uint32 modifiers);
     107
    106108            uint32          fKey;
    107109            uint32          fModifiers;
    108110            BMenuItem*      fMenuItem;
     
    237239BWindow::Shortcut::Shortcut(uint32 key, uint32 modifiers, BMenuItem* item)
    238240    :
    239241    fKey(PrepareKey(key)),
    240     fModifiers(PrepareModifiers(modifiers)),
     242    fModifiers(_InitializeModifiers(modifiers)),
    241243    fMenuItem(item),
    242244    fMessage(NULL),
    243245    fTarget(NULL)
     
    249251    BHandler* target)
    250252    :
    251253    fKey(PrepareKey(key)),
    252     fModifiers(PrepareModifiers(modifiers)),
     254    fModifiers(_InitializeModifiers(modifiers)),
    253255    fMenuItem(NULL),
    254256    fMessage(message),
    255257    fTarget(target)
     
    267269bool
    268270BWindow::Shortcut::Matches(uint32 key, uint32 modifiers) const
    269271{
    270     return fKey == key && fModifiers == modifiers;
     272    if (fModifiers == B_NO_MODIFIERS && modifiers == 0)
     273        return fKey == key;
     274    else
     275        return fKey == key && fModifiers == modifiers;
    271276}
    272277
    273278
     279uint32
     280BWindow::Shortcut::_InitializeModifiers(uint32 modifiers)
     281{
     282    if (modifiers == B_NO_MODIFIERS)
     283        return modifiers;
     284    else
     285        return PrepareModifiers(modifiers) | B_COMMAND_KEY;
     286}
     287
     288
    274289/*static*/
    275290uint32
    276291BWindow::Shortcut::AllowedModifiers()
     
    284299uint32
    285300BWindow::Shortcut::PrepareModifiers(uint32 modifiers)
    286301{
    287     return (modifiers & AllowedModifiers()) | B_COMMAND_KEY;
     302    return modifiers & AllowedModifiers();
    288303}
    289304
    290305
     
    17851800BWindow::AddShortcut(uint32 key, uint32 modifiers, BMenuItem* item)
    17861801{
    17871802    Shortcut* shortcut = new(std::nothrow) Shortcut(key, modifiers, item);
    1788     if (shortcut == NULL)
    1789         return;
    1790 
    1791     // removes the shortcut if it already exists!
    1792     RemoveShortcut(key, modifiers);
    1793 
    1794     fShortcuts.AddItem(shortcut);
     1803    _AddShortcut(key, modifiers, shortcut);
    17951804}
    17961805
    17971806
     
    18111820
    18121821    Shortcut* shortcut = new(std::nothrow) Shortcut(key, modifiers, message,
    18131822        target);
    1814     if (shortcut == NULL)
    1815         return;
    1816 
    1817     // removes the shortcut if it already exists!
    1818     RemoveShortcut(key, modifiers);
    1819 
    1820     fShortcuts.AddItem(shortcut);
     1823    _AddShortcut(key, modifiers, shortcut);
    18211824}
    18221825
    18231826
     
    36693672    }
    36703673
    36713674    // Handle shortcuts
    3672     if ((modifiers & B_COMMAND_KEY) != 0) {
    3673         // Command+q has been pressed, so, we will quit
    3674         // the shortcut mechanism doesn't allow handlers outside the window
    3675         if (!fNoQuitShortcut && (key == 'Q' || key == 'q')) {
    3676             BMessage message(B_QUIT_REQUESTED);
    3677             message.AddBool("shortcut", true);
     3675    bool shortcutCalled = false;
     3676    // Command+q has been pressed, so, we will quit
     3677    // the shortcut mechanism doesn't allow handlers outside the window
     3678    if (!fNoQuitShortcut && (key == 'Q' || key == 'q') && (modifiers & B_COMMAND_KEY) != 0) {
     3679        BMessage message(B_QUIT_REQUESTED);
     3680        message.AddBool("shortcut", true);
    36783681
    3679             be_app->PostMessage(&message);
    3680             return true;
    3681         }
     3682        be_app->PostMessage(&message);
     3683        return true;
     3684    }
    36823685
    3683         // Pretend that the user opened a menu, to give the subclass a
    3684         // chance to update it's menus. This may install new shortcuts,
    3685         // which is why we have to call it here, before trying to find
    3686         // a shortcut for the given key.
    3687         MenusBeginning();
     3686    // Pretend that the user opened a menu, to give the subclass a
     3687    // chance to update it's menus. This may install new shortcuts,
     3688    // which is why we have to call it here, before trying to find
     3689    // a shortcut for the given key.
     3690    MenusBeginning();
    36883691
    3689         Shortcut* shortcut = _FindShortcut(key, modifiers);
    3690         if (shortcut != NULL) {
    3691             // TODO: would be nice to move this functionality to
    3692             //  a Shortcut::Invoke() method - but since BMenu::InvokeItem()
    3693             //  (and BMenuItem::Invoke()) are private, I didn't want
    3694             //  to mess with them (BMenuItem::Invoke() is public in
    3695             //  Dano/Zeta, though, maybe we should just follow their
    3696             //  example)
    3697             if (shortcut->MenuItem() != NULL) {
    3698                 BMenu* menu = shortcut->MenuItem()->Menu();
    3699                 if (menu != NULL)
    3700                     MenuPrivate(menu).InvokeItem(shortcut->MenuItem(), true);
    3701             } else {
    3702                 BHandler* target = shortcut->Target();
    3703                 if (target == NULL)
    3704                     target = CurrentFocus();
     3692    Shortcut* shortcut = NULL;
     3693    // Handle function keys
     3694    if (key == B_FUNCTION_KEY && rawKey >= B_F1_KEY && rawKey <= B_F12_KEY)
     3695        shortcut = _FindShortcut(rawKey, modifiers);
     3696    else
     3697        shortcut = _FindShortcut(key, modifiers);
    37053698
    3706                 if (shortcut->Message() != NULL) {
    3707                     BMessage message(*shortcut->Message());
     3699    if (shortcut != NULL) {
     3700        shortcutCalled = true;
     3701        // TODO: would be nice to move this functionality to
     3702        //  a Shortcut::Invoke() method - but since BMenu::InvokeItem()
     3703        //  (and BMenuItem::Invoke()) are private, I didn't want
     3704        //  to mess with them (BMenuItem::Invoke() is public in
     3705        //  Dano/Zeta, though, maybe we should just follow their
     3706        //  example)
     3707        if (shortcut->MenuItem() != NULL) {
     3708            BMenu* menu = shortcut->MenuItem()->Menu();
     3709            if (menu != NULL)
     3710                MenuPrivate(menu).InvokeItem(shortcut->MenuItem(), true);
     3711        } else {
     3712            BHandler* target = shortcut->Target();
     3713            if (target == NULL)
     3714                target = CurrentFocus();
    37083715
    3709                     if (message.ReplaceInt64("when", system_time()) != B_OK)
    3710                         message.AddInt64("when", system_time());
    3711                     if (message.ReplaceBool("shortcut", true) != B_OK)
    3712                         message.AddBool("shortcut", true);
     3716            if (shortcut->Message() != NULL) {
     3717                BMessage message(*shortcut->Message());
    37133718
    3714                     PostMessage(&message, target);
    3715                 }
     3719                if (message.ReplaceInt64("when", system_time()) != B_OK)
     3720                    message.AddInt64("when", system_time());
     3721                if (message.ReplaceBool("shortcut", true) != B_OK)
     3722                    message.AddBool("shortcut", true);
     3723
     3724                PostMessage(&message, target);
    37163725            }
    37173726        }
     3727    }
    37183728
    3719         MenusEnded();
     3729    MenusEnded();
    37203730
    3721         // we always eat the event if the command key was pressed
    3722         return true;
    3723     }
    3724 
    37253731    // TODO: convert keys to the encoding of the target view
    37263732
    3727     return false;
     3733    // we always eat the event if a shortcut handled it
     3734    return shortcutCalled;
    37283735}
    37293736
    37303737
     
    37883795}
    37893796
    37903797
     3798void
     3799BWindow::_AddShortcut(uint32 key, uint32 modifiers, Shortcut* shortcut)
     3800{
     3801    if (shortcut == NULL)
     3802        return;
     3803
     3804    // removes the shortcut if it already exists!
     3805    RemoveShortcut(key, modifiers);
     3806
     3807    fShortcuts.AddItem(shortcut);
     3808}
     3809
     3810
    37913811BWindow::Shortcut*
    37923812BWindow::_FindShortcut(uint32 key, uint32 modifiers)
    37933813{
  • src/kits/interface/MenuItem.cpp

     
    1212//! Display item for BMenu class
    1313
    1414#include <ctype.h>
     15#include <stdio.h>
    1516#include <stdlib.h>
    1617#include <string.h>
    1718
     
    6364        fLabel = strdup(label);
    6465
    6566    SetMessage(message);
    66 
    67     fShortcutChar = shortcut;
    68 
    69     if (shortcut != 0)
    70         fModifiers = modifiers | B_COMMAND_KEY;
    71     else
    72         fModifiers = 0;
     67    SetShortcut(shortcut, modifiers);
    7368}
    7469
    7570
     
    266261
    267262
    268263void
    269 BMenuItem::SetShortcut(char ch, uint32 modifiers)
     264BMenuItem::SetShortcut(char shortcut, uint32 modifiers)
    270265{
    271     if (fShortcutChar != 0 && (fModifiers & B_COMMAND_KEY) && fWindow)
     266    if (_IsValidShortcut(fShortcutChar, fModifiers) && fWindow)
    272267        fWindow->RemoveShortcut(fShortcutChar, fModifiers);
    273268
    274     fShortcutChar = ch;
     269    fShortcutChar = shortcut;
    275270
    276     if (ch != 0)
    277         fModifiers = modifiers | B_COMMAND_KEY;
    278     else
     271    if (shortcut != 0) {
     272        if (modifiers != B_NO_MODIFIERS)
     273            fModifiers = modifiers | B_COMMAND_KEY;
     274        else
     275            fModifiers = B_NO_MODIFIERS;
     276    } else
    279277        fModifiers = 0;
    280278
    281     if (fShortcutChar != 0 && (fModifiers & B_COMMAND_KEY) && fWindow)
     279    if (_IsValidShortcut(fShortcutChar, fModifiers) && fWindow)
    282280        fWindow->AddShortcut(fShortcutChar, fModifiers, this);
    283281
    284282    if (fSuper) {
     
    583581void
    584582BMenuItem::Install(BWindow *window)
    585583{
    586     if (fSubmenu) {
     584    if (fSubmenu)
    587585        MenuPrivate(fSubmenu).Install(window);
    588     }
    589586
    590587    fWindow = window;
    591588
    592     if (fShortcutChar != 0 && (fModifiers & B_COMMAND_KEY) && fWindow)
     589    if (_IsValidShortcut(fShortcutChar, fModifiers) && fWindow)
    593590        window->AddShortcut(fShortcutChar, fModifiers, this);
    594591
    595592    if (!Messenger().IsValid())
     
    646643    if (Target() == fWindow)
    647644        SetTarget(BMessenger());
    648645
    649     if (fShortcutChar != 0 && (fModifiers & B_COMMAND_KEY) != 0
    650         && fWindow != NULL)
     646    if (_IsValidShortcut(fShortcutChar, fModifiers) && fWindow != NULL)
    651647        fWindow->RemoveShortcut(fShortcutChar, fModifiers);
    652648
    653649    fWindow = NULL;
     
    734730        where.x -= fBounds.Height() - 3;
    735731
    736732    const float ascent = MenuPrivate(fSuper).Ascent();
    737     if (fShortcutChar < B_SPACE && kUTF8ControlMap[(int)fShortcutChar])
     733    if (fShortcutChar < B_SPACE)
    738734        _DrawControlChar(fShortcutChar, where + BPoint(0, ascent));
    739735    else
    740736        fSuper->DrawChar(fShortcutChar, where + BPoint(0, ascent));
     
    818814{
    819815    // TODO: If needed, take another font for the control characters
    820816    //  (or have font overlays in the app_server!)
    821     const char* symbol = " ";
    822     if (kUTF8ControlMap[(int)fShortcutChar])
    823         symbol = kUTF8ControlMap[(int)fShortcutChar];
     817    if (kUTF8ControlMap[(int)fShortcutChar]) {
     818        const char* symbol = kUTF8ControlMap[(int)fShortcutChar];
     819        fSuper->DrawString(symbol, where);
     820    } else if (shortcut >= B_F1_KEY && shortcut <= B_F12_KEY) {
     821        int number = 1 + (shortcut - B_F1_KEY);
     822        char shortcutString[10];
     823        snprintf(shortcutString, sizeof(shortcutString), "F%d", number);
     824        // Account for this being longer that one character. Subtracting two
     825        // times the size of space seems to align this nicely.
     826        where.x -= (fSuper->StringWidth(shortcutString) - (2 * fSuper->StringWidth(" ")));
     827        fSuper->DrawString(shortcutString, where);
     828    }
     829}
    824830
    825     fSuper->DrawString(symbol, where);
     831
     832bool
     833BMenuItem::_IsValidShortcut(char shortcut, uint32 modifiers)
     834{
     835    if (shortcut != 0) {
     836        // Either explicitly ask for no modifiers or must have at least
     837        // B_COMMAND_KEY
     838        if (modifiers == B_NO_MODIFIERS)
     839            return true;
     840        else
     841            return (modifiers & B_COMMAND_KEY) != 0;
     842    }
     843    return false;
    826844}
    827845
    828846