Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Instead of Ctrl-C print ⌘C in the Menu #46

Open
probonopd opened this issue Nov 20, 2020 · 130 comments
Open

Instead of Ctrl-C print ⌘C in the Menu #46

probonopd opened this issue Nov 20, 2020 · 130 comments
Labels
help wanted Extra attention is needed qt Qt expertise needed

Comments

@probonopd
Copy link
Member

probonopd commented Nov 20, 2020

We want as proper Command Key in the menu.

Is there a way to globally make Qt shortcuts use ⌘+... instead of Ctrl+...?

image

@probonopd probonopd added good first issue Good for newcomers help wanted Extra attention is needed labels Nov 20, 2020
@vermaden
Copy link

Why one would change CTRL+C/V into ALT+C/V? :)

Just asking.

@probonopd
Copy link
Member Author

It's much easier to type with your thumb on Alt than on Ctrl. Also, it just feels natural for switchers coming from the Mac, where the Apple key is the key on the left to the space bar. (It's also what Haiku uses, and it makes it instantly more Mac-like.)

@panosl
Copy link

panosl commented Nov 21, 2020

It's much easier to type with your thumb on Alt than on Ctrl. Also, it just feels natural for switchers coming from the Mac, where the Apple key is the key on the left to the space bar. (It's also what Haiku uses, and it makes it instantly more Mac-like.)

Just wondering, why not make it super/cmd instead of alt?

@probonopd
Copy link
Member Author

probonopd commented Nov 21, 2020

This is a Mac keyboard:

image

This is a Raspberry Pi keyboard:

image

The objective is to get the button that is left to the space bar to work like on the Mac.

Actually the objective is that the button that is left to the space bar will work like on the Mac for both generic (e.g., Raspberry) and Apple keyboards.

@probonopd
Copy link
Member Author

https://twitter.com/threedeyes/status/1329958188242841603:

@threedeyes says:

I swapped the ALT and CTRL modifier codes in Haiku's QPA. For macosx I think it will be here -
https://github.com/qt/qtbase/blob/dev/src/plugins/platforms/cocoa/qcocoakeymapper.mm#L68

@probonopd
Copy link
Member Author

probonopd commented Nov 21, 2020

So far we have https://github.com/helloSystem/QtPlugin (Qt platform plugin and style), but it seems we would need a patched version of the qxcb QXcbIntegrationPlugin for X Window System (X11) support?

Wow, I was hoping not having to patch Qt itself.

@probonopd
Copy link
Member Author

https://github.com/qt/qtbase/blob/ae2c30942086bd0387c6d5297c0cb85b505f29a0/src/plugins/platforms/cocoa/qcocoakeymapper.mm#L71 is interesting in that it says:

{ NSEventModifierFlagCommand, Qt::MetaModifier },

Looks like the Apple key on the Mac keyboard is actually a Meta key (like the Windows/Raspberry key) but its physical location is different than the Meta key on PC/Raspberry Pi keyboards. Also, there is no Windows/Raspberry key on the right-hand side of the keyboard.

It will be an interesting challenge to get this right both for original Apple keyboards and for generic (e.g., Raspberry Pi) keyboards.

@probonopd
Copy link
Member Author

probonopd commented Nov 21, 2020

The relevant code seems to be in

https://github.com/qt/qtbase/blob/5.14/src/plugins/platforms/xcb/qxcbkeyboard.cpp

Search for rmod_masks.alt, it appears in multiple places in that file.

Is there a way to compile only https://github.com/qt/qtbase/blob/5.14/src/plugins/platforms/xcb without the rest of Qt?

@panosl
Copy link

panosl commented Nov 21, 2020

For generic keyboards, I always had to switch cmd with option (alt)
Screenshot 2020-11-21 at 11 04 43 AM

@panosl
Copy link

panosl commented Nov 21, 2020

So far we have https://github.com/helloSystem/QtPlugin (Qt platform plugin and style), but it seems we would need a patched version of the qxcb QXcbIntegrationPlugin for X Window System (X11) support?

Wow, I was hoping not having to patch Qt itself.

After the patch, you can always request to push it upstream so it makes it available everywhere. I'd love to have that option on KDE settings, not just hello.

@probonopd
Copy link
Member Author

Good idea. Me too!

@probonopd
Copy link
Member Author

probonopd commented Nov 21, 2020

Haiku has this:

image

but I don't know whether/how it interacts with the Qt side of things.

@probonopd probonopd mentioned this issue Nov 23, 2020
@probonopd
Copy link
Member Author

probonopd commented Dec 1, 2020

Is it possible to build just the xcb QPA (Qt Platform Abstraction) platform plugin without having to build all of Qt?

pkg which /usr/local/lib/qt5/plugins/platforms/libqxcb.so
/usr/local/lib/qt5/plugins/platforms/libqxcb.so was installed by package qt5-gui-5.15.0_1

@threedeyes
Copy link

Is it possible to build just the xcb QPA (Qt Platform Abstraction) platform plugin without having to build all of Qt?

Yes of course.
You can take xcb qpa plugin (https://github.com/qt/qtbase/tree/dev/src/plugins/platforms/xcb) and some fix * .pro files to build separately of Qt.

@probonopd
Copy link
Member Author

cd /tmp
git clone https://github.com/qt/qtbase --branch 5.15 --depth 1 # 60 MB
cd qtbase/src/plugins/platforms/xcb 
qmake

Works! If we use a version matching to the Qt on the system, then it compiles

/tmp/qtbase/lib/libQt5XcbQpa.so
/tmp/qtbase/lib/libQt5XcbQpa.so.5
/tmp/qtbase/plugins/platforms/libqxcb.so
/tmp/qtbase/plugins/xcbglintegrations/libqxcb-egl-integration.so
/tmp/qtbase/plugins/xcbglintegrations/libqxcb-glx-integration.so

Now, where does Haiku speficy to use Alt instead of Ctrl?

qhaikurasterwindow.cpp has

Qt::KeyboardModifiers HaikuViewProxy::keyStateToModifiers(uint32 keyState) const
{
    Qt::KeyboardModifiers modifiers(Qt::NoModifier);

    if (keyState & B_SHIFT_KEY)
        modifiers |= Qt::ShiftModifier;
    if (keyState & B_CONTROL_KEY)
        modifiers |= Qt::AltModifier;
    if (keyState & B_COMMAND_KEY)
        modifiers |= Qt::ControlModifier;

    return modifiers;
}

B_CONTROL_KEY being mentioned alongside Qt::AltModifier looks interesting.

What is that B_COMMAND_KEY that get associated with Qt::ControlModifier?

Where can I do the same for XCB?

qxcbkeyboard.cpp has

Qt::KeyboardModifiers QXcbKeyboard::translateModifiers(int s) const
{
    Qt::KeyboardModifiers ret = Qt::NoModifier;
    if (s & XCB_MOD_MASK_SHIFT)
        ret |= Qt::ShiftModifier;
    if (s & XCB_MOD_MASK_CONTROL)
        ret |= Qt::ControlModifier;
    if (s & rmod_masks.alt)
        ret |= Qt::AltModifier;
    if (s & rmod_masks.meta)
        ret |= Qt::MetaModifier;
    if (s & rmod_masks.altgr)
        ret |= Qt::GroupSwitchModifier;
    return ret;
}

What happens if we change this to

Qt::KeyboardModifiers QXcbKeyboard::translateModifiers(int s) const
{
    Qt::KeyboardModifiers ret = Qt::NoModifier;
    if (s & XCB_MOD_MASK_SHIFT)
        ret |= Qt::ShiftModifier;
    if (s & rmod_masks.alt)
        ret |= Qt::ControlModifier;
    if (s & XCB_MOD_MASK_CONTROL)
        ret |= Qt::AltModifier;
    if (s & rmod_masks.meta)
        ret |= Qt::MetaModifier;
    if (s & rmod_masks.altgr)
        ret |= Qt::GroupSwitchModifier;
    return ret;
}

Install the modified version:

sudo mv /usr/local/lib/qt5/plugins/platforms/libqxcb.so /usr/local/lib/qt5/plugins/platforms/libqxcb.so.original
sudo cp /tmp/qtbase/plugins/platforms/libqxcb.so /usr/local/lib/qt5/plugins/platforms/libqxcb.so
sudo mv /usr/local/lib/qt5/libQt5XcbQpa.so.5.15.0 /usr/local/lib/qt5/libQt5XcbQpa.so.5.15.0.original
sudo cp /tmp/qtbase/lib/libQt5XcbQpa.so.5 /usr/local/lib/qt5/libQt5XcbQpa.so.5.15.0

At this point, we can use Alt+Letter instead of Ctrl+Letter to invoke shortcuts, but the menu still says "Ctrl+..." rather than "Alt+...".

How can we change the text in the menu from "Ctrl+..." to "Alt+..."?

Haiku seems to do it...

out.mp4

@probonopd
Copy link
Member Author

Additional considerations:

  • Could we turn this into our own platform plugin that we could load, with a fallback to the unmodified xcb one, e.g., using export QT_QPA_PLATFORM=hello;xcb? This way applications that are bundling their own Qt might possibly still use our modified platform theme?

  • Does Haiku have a solution for Gtk, too?

@probonopd
Copy link
Member Author

probonopd commented Dec 22, 2020

Maybe the correct way would be to use the Super (Windows/Raspberry Pi) key as the key for invoking menu shortcuts instead. And then, on PC keyboards, switch the Super and the Alt key to that Super is to the left of spacebar like on the Mac. For Apple keyboards, the Super key should be the "Command" or "Apple" key.

https://en.wikipedia.org/wiki/Super_key_(keyboard_button)

If a Windows keyboard is connected to macOS it will use the Windows key as the Command key, therefore Super is still on the Windows key for macOS.

@panosl
Copy link

panosl commented Dec 22, 2020

Maybe the correct way would be to use the Super (Windows/Raspberry Pi) key as the key for invoking menu shortcuts instead. And then, on PC keyboards, switch the Super and the Alt key to that Super is to the left of spacebar like on the Mac. For Apple keyboards, the Super key should be the "Command" or "Apple" key.

https://en.wikipedia.org/wiki/Super_key_(keyboard_button)

If a Windows keyboard is connected to macOS it will use the Windows key as the Command key, therefore Super is still on the Windows key for macOS.

That’s is the correct logic 👍

@probonopd
Copy link
Member Author

https://www.emacswiki.org/emacs/SwapControlAltAndCapsLock

Keyboard shortcuts seem to have been written with old Unix and Sun keyboards in mind, where Control and Alt were reversed. Since resoldering a keyboard isn’t an option for most people, why not just swap Control and Alt programatically to use the keyboard the way it was meant to be used?

@probonopd
Copy link
Member Author

probonopd commented Dec 22, 2020

Yes, wholesale swapping Ctrl and Alt on PC keyboards feels right, given that this is how the keys used to be positioned:

image

Symbolics's Lisp Machine keyboard PN 365407 Rev C. (Photo by Joey Devilla, source: http://xahlee.info/kbd/keyboard_hardware_and_key_choices.html)

Turns out that the Ctrl key used to be exactly where the Apple/Command key is...!

Yes, wholesale swapping Ctrl and Alt on PC keyboards means that it will work in Qt, Gtk, and whatnot. But we still need to find a way to fix what gets written in the menu...

@lproven
Copy link

lproven commented Dec 22, 2020

TBH, I could best describe my initial reaction when I just read this (after seeing your comment on Twitter) would be "horrified revulsion". I think I actually swore out loud.

The use of Alt for keyboard shortcuts is 100% definitely certainly my single most-hated thing about GNUstep and it is what stops me using GNUstep apps.

I strongly dispute your reasoning, and will do so point-by-point below.

But thank you for explaining why; I have never understood this.

It's much easier to type with your thumb on Alt than on Ctrl.

No, not really, it isn't. Secondly, muscle memory is the by far the most important thing here, not learning a new pattern to slightly shorten finger-travel. The cast-iron proof of this is that the world does not type with Dvorak.

Also, it just feels natural for switchers coming from the Mac

Hi. Professional Linux wrangler here. Been using Windows since v2 in 1988 and MacOS since System 6.

No, it does not.

This may be your personal feeling but it is 100% NOT universal.

I have used 30+ different operating systems on 15-20 different makes of computer with different keyboard layouts. How one does this is that one learns the keyboard layout of that machine and mentally switches maps. Many of these did not have the ability to reassign keys so there was no choice.

where the Apple key is the key on the left to the space bar.

This is absolute positioning. What is more important is spatial reasoning and memory, which is relative.

This is perhaps the definitive article on spatial memory: https://arstechnica.com/gadgets/2003/04/finder/

(It's also what Haiku uses, and it makes it instantly more Mac-like.)

Also something I absolutely hate about Haiku and reassign when I first install it.

I use Mac keyboards on Macs and PC keyboards on PCs. I could not tell you which key was where, but when my fingers feel a Mac keyboard (I am typing on a 1989 Apple Extended II mechanical-keyswitch ADB keyboard right now, on MacOS 10.14 on a Retina iMac), then I use Mac shortcuts.

When I type on a PC, I use PC shortcuts, on orignal IBM Model M mechanical keyboards. I don't like Linux WMs that don't use standard PC shortcuts. I dislike KDE, for instance. It doesn't respect the keyboard shortcuts. GNOME 3 is also poor at this. Windows sets the standard; Linux should follow.

On a PC, Alt-F opens the File menu. Alt-space opens the window control menu. Alt-tab is the task switcher. Do not even think of remapping this away! It would be a usability disaster.

PCs use Ctrl for actions; Ctrl is short for Control, the verb meaning to make something behave as desired. Ctrl-C = Copy, Ctrl-S = Save, Ctrl-P = Print, etc. In the DOS command line, Ctrl-C means Cancel, a CP/M keystroke I've been using since 1985, but it's easy to remember that it does different things in command-line mode and in the GUI.

Alt opens menus, switches windows and so on. Alt alters the state of a program. Similarly AltGr alters the graphic you get when you type a key.

I switch between Macs and Linux daily and my only problem is when I run Windows or Linux on a Mac: then my fingers get confused because I have to use the wrong keystrokes for the keyboard I feel.

Some people really like that MacOS uses Cmd for things and so there is no overlap between Cmd-C to Copy and Ctrl-C to Cancel. I don't care myself; I learned which is which 30Y ago and need no conscious thought. Others want the same on Linux, and it is doable -- see:

In other words, there are tools for this already. The Mac Cmd key is the Windows key on a PC. If you want Mac-like keystrokes, which personally I strongly do not, then use Windows=Cmd. Command means much the same as Control: "do this now".

But do not confuse the purpose of function of Alt and Cmd; they are totally different modifiers and all you will create is a hideous evil mismatch which destroys the muscle memory of experienced users and drives people away from your OS.

@probonopd
Copy link
Member Author

probonopd commented Dec 22, 2020

Wow. Looks like we need to somehow make this configurable since people seem to have different preferences?

The way I look at it:

  • Without looking at the keyboard, for me the location of the keys matters. Especially I want the key to the left of the spacebar to invoke shortcuts from the menus. (This is the design goal; the question is how to best implement this.)
  • When helloSystem is running on a Mac (keyboard), then the Apple key should act as the key to invoke shortcuts (I think we can all agree on this?) (Technically the Apple key may be mapped as a Meta key, but it is physically swapped with the Alt keys on Mac keyboards.)
  • When helloSystem is running on a PC keyboard, then I would still like to have the same haptic feel (I guess @lproven wouldn't want that.) Reason being, I want the key to the left of the spacebar to do the same regardless of whether I am using an Apple keyboard or a PC keyboard.

@lproven
Copy link

lproven commented Dec 22, 2020

One of my top tips for people interested in usability and accessibility is to use a desktop PC, and unplug the mouse. Try to operate it with keyboard only. Windows is very good for this, Linux much poorer, and macOS quite poor because Apple don't use keyboard shortcuts for much, so there is a whole new set, disjoint with normal operation, for people with disabilities.

I highly recommend trying this. Not for half an hour, for a day or 2 at least. Time to get used to it and for it to feel somewhat natural. When I worked as a consultant, I often got comments from people who were amazed at how fast I operate a Windows PC. Windows fly open, move, and close again without me touching the mouse or clicking on anything, and most Windows techies don't even know this is possible, let alone that it's faster and more efficient than trying to click on tiny on-screen controls.

The WWW is a pain without a pointing device because you have to step through hundreds of links, but the rest of Windows is highly usable. You can move and resize windows, open/close/save/print documents, switch apps and docs, control menus, all with standard keyboard shortcuts which are near-universal: most Linux desktops understand them too.

My muscle memory knows where Ctrl and Alt and Win/Cmd are on Macs and on PCs, and I use all of them, all the time, appropriately for what they are for. Where they are relative to other keys is irrelevant to this. If you try to redefine what a physical key does then you are forcing people to learn your preferred keymap, and redefining the one that their computer has always used. At least with Dvorak, everything has moved and you have to start over. I did, and learned it, and it was horrible. It felt like I'd had a stroke. I knew what I wanted to do but my fingers were paralysed and would not move -- I knew intellectually where to go but my muscle memory was gone. It was a very unpleasant experience and not worth it; after just under 2 months, I switched back to QWERTY.

It sounds to me like you are not an efficient user of keyboard shortcuts, and as such you don't see the problem with re-defining them. May I ask: do you drive a car?

If you do, imagine that you got into your car and I mentioned to you that I'd redefined the controls in a more efficient way. Brake was now a steering-wheel lever, the right pedal was for changing gear, and the middle pedal was the accelerator. The left pedal was now for flashing the headlights.

Do you think you could drive it?

I don't. In fact I think you'd crash the car in seconds.

This is what you want to do to me, because of some strange feeling that you have that I should use an Apple keymap on an x86 PC.

PCs have a Command key. It's the Windows key. If you want to use Mac-type keystrokes, use Windows, then Apple users will be able to use it.

I mentioned that I use a 31-year-old keyboard on my 5-year-old Mac. Consider: this was not merely an intentional choice, but it meant that I had to keep a preferred around for decades, and I had to source expensive specialised hardware to connect it to a modern computer.

I also mentioned that I use a nearly 29-year-old keyboard on my work PC. It, too, I've had for decades. I write my own keymaps to be able to use a Windows key on a 1980s keyboard that just has a gap between Alt and Ctrl.

I take keyboards very *very seriously. It would be a lot less work to use a cheap modern USB keyboard. I don't. When I emigrated in 2014, in my luggage was an IBM Model M and a PS/2-to-USB convertor so I'd be able to work in my new job efficiently from Day 1.

I put it to you that I take keyboards and keyboard shortcuts a lot more seriously than you do. Remember me explaining to you the origin of the Slash key for opening menus?
https://medium.com/@lproven/as-it-happens-the-slash-key-was-how-you-operated-the-menu-system-in-the-original-lotus-1-2-3-bcb23d95a645

Or that I wrote the Wikipedia article on IBM Common User Access? https://en.wikipedia.org/wiki/IBM_Common_User_Access

I have no clue where Cmd and Alt are relative to Space. I just had to get up and walk into another room to look at my work PC to see where that gap was.

Yet I have been touch-typing for over 4 decades and use a multiplicity of keyboard shortcuts every waking hour.

I implore you, I beg you, do not do this. Do not copy this disastrous, project-destroying mistake. It was a terrible idea when GNUstep did it and they had a reason -- PC keyboards did not have a Windows key until after Windows 95. IBM dropped the Super key from the UNIX keyboard design they copied from DEC for the IBM PC-AT.

It doesn't matter where the physical key is. What matters is what the key does, and you do not have freedom to redefine that. Function is more important than form. Form is mere appearance.

@probonopd
Copy link
Member Author

probonopd commented Dec 23, 2020

One of my top tips for people interested in usability and accessibility is to use a desktop PC, and unplug the mouse.

Have you seen the "search in menu" feature (also known as Action Search) in the global menu of helloSystem? It goes a lot into this direction. Also, I wonder whether we could re-implement the Leap functionality (e.g, putting it on the otherwise largely useless caps lock key).

My muscle memory knows where Ctrl and Alt and Win/Cmd are on Macs and on PCs, and I use all of them, all the time, appropriately for what they are for. Where they are relative to other keys is irrelevant to this.

You are making great points, and

I take keyboards very *very seriously.

this is exactly why I am asking you for your opinion :-)

Keep in mind that helloSystem is designed to be welcoming to switchers from the Mac. Most Linux desktops are appealing to Switchers from Windows, with things like Alt+F4 that a Mac user would never dream of (Command-Q is in our muscle memory).

If my goal is to make something that works like a Mac shortcut-wise on both Apple and non-Apple keyboards (with the Raspberry Pi keyboard being my reference hardware), what is your recommendation then?

I have no clue where Cmd and Alt are relative to Space.

This is a bit surprising for me. Shouldn't it be a noble goal to make the keyboard work without the need to look at the print on the keys at all?

It doesn't matter where the physical key is.

It does matter a lot to me:

I have been using a Raspberry Pi keyboard with swapped Ctrl/Alt keys for a day now, and it feels much more "Mac-like" to me. Being able to do Command-C with your thumb and index finger just feels worlds better than having to use your pinkie finger and index finger. At least to me.

I can put a different label on the key if I am really bothered by the wrong print. But I cannot swap out my thumb and my pinkie finger. See?

What matters is what the key does, and you do not have freedom to redefine that. Function is more important than form. Form is mere appearance.

So given that my objective is not to be welcoming to switchers from Windows but to switchers from the Mac, would your recommend to

  • Use the Ctrl key for the shortcuts (because this is how "PC keyboards" operate), or
  • Use the Meta (Windows/Raspberry Pi) key for the shortcuts (because the Apple key, on a Mac keyboard, is technically a Meta key)?

Would you be less opposed to this if the keys (including their labels) were physically swapped in this way?

@grahamperrin
Copy link
Contributor

The subject line worries me.

#46 (comment) and other references to Meta are somewhat reassuring.

switchers from the Mac,

If that's a strict focus then (strictly) I should expect these macOS people to use Mac keyboards.

Less strictly: given the reality that users will have diverse backgrounds, expect some of these users to have keyboards that suit FreeBSD or Linux or Windows or whatever.

The subject line worries me because if you create a system in which Alt as a supposed norm appears in menus, in integral help, in help elsewhere and in conversation:

  • you'll create a system that's somewhat alien to all audiences, and maintenance e.g. documentation will be a chore.

It might help to think binary about one aspect of this discussion:

  • most users will want either or Control

Recalling my switch away from Apple after twenty-something years of addiction to Mac keyboard shortcuts:

  • I found the switch to using Control strange, ergonomically, but not for too long.

Critically: in retrospect, the Mac had caused me to adopt some weird habits. Like, for bold (emphasis):

  • curling my left thumb into my palm then crossing over with my index finger then thumbing then fingering B then releasing then uncurling.

Thumb-curlingly weird, in retrospect.


Much to think about in this issue :-)

@probonopd
Copy link
Member Author

probonopd commented Dec 27, 2020

Let's see whether we can make https://github.com/rbreaves/kinto work for helloSystem.
Please see #8.

@rbreaves
Copy link

rbreaves commented Dec 27, 2020

If you could guarantee that all apps will respect a global menu then you could really mask the modifiers however you’d want & remap everything to satisfy literally anyone. What will be difficult is the variety of differing menus & documented hotkeys per app may no longer follow.

The benefit of me breaking out Kinto into its own project vs integrating into a transformation pack of some kind or enabled in a distro by default is that people better understand what they’re getting into. Clearly some people are equally passionate about their Windows hotkey placements lol. I’d still love to see Kinto becoming a default in a distro though!

Kinto actually follows the Lisp style layout during normal GUI apps.. terminals though return Ctrl to the physical Ctrl key & the Cmd/Alt location converts to Ctrl+Shift.

A global menu or modified Vala-Appmenu that would swap modifier names or symbols would be very interesting indeed imo. Just because other OS’s haven’t addressed it I don’t think that means we shouldn’t - whether masking keys or making the Alt position a primary modifier is the right approach? Perhaps that’s for users to decide during setup but Alt/Cmd being the primary (Ctrl) might not always be maskable from the user depending on the program imo.

I’m writing something similar to what I’m suggesting for Vala right now but for Windows.

@probonopd
Copy link
Member Author

Yes, Qt 5.15.2 on Debian sid in this case.

@probonopd
Copy link
Member Author

probonopd commented Oct 11, 2021

Apparently as soon as we use QT_QPA_PLATFORMTHEME=panda BaseStyle::drawControl does not get used anymore. Same for ::drawItemText (which we could use to replace the text that gets drawn).

I do not know why.


As a real lame workaround we can replace "Ctrl" with "Alt" in the Menu application that is what displays the global menu at the top of the screen. It's a purely cosmetic workaround until we solve this puzzle.

QKeySequence DBusMenuShortcut::toKeySequence() const
{
    QStringList tmp;
    Q_FOREACH(const QStringList& keyTokens_, *this) {
        QStringList keyTokens = keyTokens_;
        processKeyTokens(&keyTokens, DM_COLUMN, QT_COLUMN);
        keyTokens[0].replace("Alt", "_A_L_T_"); // probono: Really ugly hack. FIXME: Implement in QtPlugin rather than in Menu
        keyTokens[0].replace("Ctrl", "Alt"); // probono: Really ugly hack. FIXME: Implement in QtPlugin rather than in Menu
        keyTokens[0].replace("_A_L_T_", "Ctrl"); // probono: Really ugly hack. FIXME: Implement in QtPlugin rather than in Menu
        tmp << keyTokens.join(QLatin1String("+"));
    }
    QString string = tmp.join(QLatin1String(", "));
    return QKeySequence::fromString(string);
}

image

Result:

We can't get it to use random strings (like "Command") or symbols this way, however. And this method obviously affects only menus drawn in https://github.com/helloSystem/Menu/ but does not fix, e.g., context menus nor menus within application windows. So it's a temporary workaround at best.

So, we still need to find a way to do this properly in QtPlugin.

@probonopd
Copy link
Member Author

After a lot of digging, there is now partial success:

Turns out that the Qt platform theme plugin uses Qt Style Sheets (qss) to style widgets, including QMenu::item like this:

https://github.com/helloSystem/QtPlugin/blob/c973e717c0282b2a92c4c867714b57ba8d1729fc/styleplugin/basestyle.cpp#L4496-L4513

In stylesheet.qss we have:

QMenu, QMenu::item {
        background: #eee;
}

As a result, it looks like the widgets get rendered by something else (what?) than BaseStyle::drawControl.

Which means that if I remove the qss, then the following works (but of course the QMenu items now look unstyled):

            // Draw mnemonic text
            if (t >= 0) {
                QRect mnemonicR =
                    Ph::menuItemMnemonicRect(metrics, option->direction, itemRect, hasSubMenu, menuItem->tabWidth);
                const QStringRef textToDrawRef = s.mid(t + 1);
                QString unsafeTextToDraw = QString::fromRawData(textToDrawRef.constData(), textToDrawRef.size());
                // probono: Change the on-screen representation of the shortcuts in the menu
                qDebug() << "probono: tr(qPrintable(QKeySequence(Qt::CTRL).toString()))" << tr(qPrintable(QKeySequence(Qt::CTRL).toString())); // Result: "Ctrl+"
                unsafeTextToDraw = unsafeTextToDraw.replace("Strg+", "⌘").replace("Umschalt+", "⇧"); // FIXME: How to do this w/o hardcoding German?
                // probono: TODO: Right align is not fancy enough, as it looks pretty "unaligned"
                int shortcut_text_flags = Qt::AlignRight | Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
                painter->drawText(mnemonicR, shortcut_text_flags, unsafeTextToDraw);
                s = s.left(t);
            }
            const QStringRef textToDrawRef = s.left(t);
            const QString unsafeTextToDraw = QString::fromRawData(textToDrawRef.constData(), textToDrawRef.size());
            painter->drawText(textRect, text_flags, unsafeTextToDraw);

menu_example

Note that we get the correct shortcut replacements for the QMenu items for which I have temporarily removed the qss styling. (Interesingly, just removing QMenu, QMenu::item { background: #eee; } from the stylesheet.qss file causes all styling to be gone for those, including margin/boder/padding/content, something I find not logical.)
But for the hovered QMenu item (Downloads) we can see that while we get the correct styling, we lose the shortcut replacements.

https://doc.qt.io/qt-5/qapplication.html#setStyle says

Warning: Qt style sheets are currently not supported for custom QStyle subclasses. We plan to address this in some future release.

Is this the culprit? But then, why does all the other styling we are doing using qss seem to work?

So, questions:

  • How can we do the replacement so that it works with translated strings. (Note that I would like to replace Qt::CTRL with but currently I have to replace Umschalt+ for it to work on a German system.)
  • How can we have both qss and shortcut replacements at the same time. (I think to answer this question we need to understand what actually renders widgets that have a qss style set.)
  • Theory: Elements styled by qss never reach BaseStyle:: and hence cannot be drawn in custom ways. In this case, can we leave just MenuItems unstyled via qss and re-implement the effect of the styling in BaseStyle::drawControl - ideally using the information about how things should look from the qss style sheet? When using qss, then something else than BaseStyle:: seems to be doing the actual drawing. Can't we just do the string replacements in BaseStyle:: and then let whatever draws the qss styled widgets, possibly QCommonStyle::drawControl, do the actual drawing?

Pseudo-code:

    case CE_MenuItem: {
        auto menuItem = qstyleoption_cast<const QStyleOptionMenuItem*>(option);
        if (!menuItem)
            break;
        menuItem->setText(menuItem->text().replace("foo", "bar"));
        menuItem->setStyle("QMenu, QMenu::item { background: #eee; }");
        QCommonStyle::drawControl(menuItem); // Assuming that QCommonStyle::drawControl

Could something like this work?

@louies0623
Copy link

If possible, the "Use Mac control key icon" can be added in the keyboard settings as a keyboard for non-Mac users to retain the original control key display style.

@probonopd
Copy link
Member Author

probonopd commented Oct 13, 2021

Once everything is working, one could add something like shown in
#46 (comment).

In general though, we don't want settings for everything (we are not KDE). We want stuff to "just work" in Mac-like ways. There are already enough desktop environments for users who like stuff to work in Windows-like ways.

@jsm222
Copy link

jsm222 commented Oct 13, 2021

FWIW https://code.woboq.org/qt5/qtbase/src/gui/kernel/qkeysequence.cpp.html#1545
Have you tried changing the above function to add special logic for CTRL. Also see https://code.woboq.org/qt5/qtbase/src/gui/kernel/qkeysequence.cpp.html#1232

@jsm222
Copy link

jsm222 commented Oct 13, 2021

screen1

 grep Ctrl translations/qtbase_da.ts -A 1
        <extracomment>This text is an &quot;unfinished&quot; shortcut, expands like &quot;Ctrl+A, ...&quot;</extracomment>
        <translation>%1, ...</translation>
--
        <source>Ctrl</source>
        <translation>⌘</translation>

in misc/qt5-l10n/work/qttranslations-everywhere-src-5.15.2

@probonopd
Copy link
Member Author

Thanks @jsm222, like this this works:

unsafeTextToDraw = unsafeTextToDraw.replace(QCoreApplication::translate("QShortcut", "Ctrl") + "+", "⌘").replace(QCoreApplication::translate("QShortcut", "Shift") + "+", "⇧");

So the first of my questions is answered. Thank you for the pointers. (Originally I had tried to use tr() rather than QCoreApplication::translate() and had missed to pass in QShortcut.)

@probonopd
Copy link
Member Author

probonopd commented Oct 14, 2021

tl;dr: turns out that when one uses qss, then the widgets don't get drawn by our style at all, but by QStyleSheetStyle. So all attempts at doing string replacements within our style are futile. We need to override the QKeySequence::toString().


Whatever routine is drawing the menu items when qss style sheets are used is getting the translated text for the menu item and its shortcut from somewhere (possibly as one string separated by \t). Can we modify (subclass) that somewhere to return another string, so that we don't have to mess around with the code that does the actual drawing at all?

I imagine things like this could be found out using a debugger, but I don't know how to do this.

Is QKeySequence::toString being involved?

https://github.com/qt can be helpful to search through Qt source code.

Apparently qmenu.cpp calls style()->drawControl(QStyle::CE_MenuItem, &opt, &p, this);

https://github.com/qt/qt/blob/0a2f2382541424726168804be2c90b91381608c6/src/gui/widgets/qmenu.cpp#L2246

What happens then, in case a qss style is set for the menu item?

Possibly src/gui/styles/qstylesheetstyle.cpp gets run?

https://github.com/qt/qt/blob/0a2f2382541424726168804be2c90b91381608c6/src/gui/styles/qstylesheetstyle.cpp#L3533

It takes the text to be drawn from a QStyleOptionMenuItem mi(*m);.

https://github.com/qt/qt/blob/0a2f2382541424726168804be2c90b91381608c6/src/gui/widgets/qmenu.cpp#L1265

sets textAndAccel += QLatin1Char('\t') + QString(seq);

So the question is, how can we change what QString(QKeySequence) returns.

Is QKeySequence::toString the same as QString(QKeySequence)?

Apparently yes:

https://github.com/qt/qt/blob/0a2f2382541424726168804be2c90b91381608c6/src/gui/kernel/qkeysequence.cpp#L1470-L1479

It looks like what we want to modify is

https://github.com/qt/qt/blob/0a2f2382541424726168804be2c90b91381608c6/src/gui/kernel/qkeysequence.cpp#L1626-L1638

which seems to use QString QKeySequence::encodeString

https://github.com/qt/qt/blob/0a2f2382541424726168804be2c90b91381608c6/src/gui/kernel/qkeysequence.cpp#L1317-L1325

which in turn uses QKeySequencePrivate::encodeString

So the question is, can we override that from within QtPlugin, without having to ship a custom patched version of Qt5Gui.so?

Fallback:

If the above is not possible, maybe we can take the implementation from

https://github.com/qt/qt/blob/0a2f2382541424726168804be2c90b91381608c6/src/gui/styles/qstylesheetstyle.cpp#L3533

and put them into our style. In theory it should then draw the menu item in the same way as qstylesheetstyle.cpp which presumably is what draws menu items when they have qss applied to them.

Or maybe easiest:

Ship a modified QtStylesheetStyle? Although that won't fix things for other places in the GUI where shortcuts are printed...

Question: Where is the actual code for

https://github.com/qt/qt/blob/0a2f2382541424726168804be2c90b91381608c6/src/gui/kernel/qkeysequence.cpp#L1621-L1622

    On Mac OS X, the string returned resembles the sequence that is
    shown in the menu bar.

Where does this happen, actually?


How can one override functions? One way is to use LD_PRELOAD.

@probonopd
Copy link
Member Author

Implemented using LD_PRELOAD in https://github.com/helloSystem/QKeySequenceOverride.

@probonopd
Copy link
Member Author

Next question is how we can get these symbols rendered nice and large as in the @jsm222 screenshot while keeping our normal font for the text.

@jsm222
Copy link

jsm222 commented Oct 14, 2021

screen_de

You do not have to call the orignal method, you can replace them fully, see https://gist.github.com/jsm222/6babf9c8660b628a47b5946a5e34627e

@probonopd
Copy link
Member Author

probonopd commented Oct 14, 2021

@jsm222 you are a C++/Qt genius. This knowledge will definitely come in handy. Do you see a significant downside of calling the original method? (It produces less code duplication.)

@jsm222
Copy link

jsm222 commented Oct 14, 2021

No not much of a difference really. The end result is also rendered the same, so to hook into the main lib, is more maintainable.

@probonopd
Copy link
Member Author

Thanks @jsm222, can you think of a way to do this kind of override without needing LD_PRELOAD?

@probonopd
Copy link
Member Author

@threedeyes one advantage of our current approach is that the change will affect not only what gets drawn in the menu, but also all other places in the GUI where shortcuts are shown.

For example, QTerminal has a buit-in shortcut editor:

image

Just wanted to bring this to your attention in case this might be relevant for Haiku as well.

@threedeyes
Copy link

Just wanted to bring this to your attention in case this might be relevant for Haiku as well.

thanks

@probonopd
Copy link
Member Author

probonopd commented Oct 17, 2021

Now this is interesting.
Just updating the system (both FreeBSD and the packages) results in much nicer symbols:

image

Even though the Nimbus font is unchanged (it does not come from a package after all).

Looks like the process of updating has placed those unwanted DejaVu and other fonts into the system again, and possibly another font than Nimbus gets used to draw those symbols?

In any case, this is how it should look.

@probonopd
Copy link
Member Author

probonopd commented Nov 3, 2021

Hopefully this fixes the rendering of the special characters (without unwanted DejaVu and other fonts):

helloSystem/ISO@8847c7e

image

@probonopd
Copy link
Member Author

In 0.7.0 we are printing ⌘C in the Menu instead of Ctrl-C.

@rbreaves
Copy link

I'd like to see this applied more universally with other DE's such as xfce4, mate, budgie, etc and vala-appmenu so I have started a new conversation for this over at gitlab for those interested.

https://gitlab.com/vala-panel-project/vala-panel-appmenu/-/issues/367

@probonopd probonopd reopened this Sep 11, 2023
@probonopd
Copy link
Member Author

Unfortunately I have to reopen this, as using LD_LIBRARY_PRELOAD proves to be problematic as soon as Qt5 and Qt6 applications are on the same machine:

@probonopd probonopd added qt Qt expertise needed and removed good first issue Good for newcomers labels Sep 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed qt Qt expertise needed
Projects
None yet
Development

No branches or pull requests

9 participants