It’s time for a new weekly blog post. 🙂
This week was a bit unusual, so I can’t structure this blog post in the way that I did before. I’ve mostly worked on tabbing through the main window. I’ve managed to remove from the tabbing order every subwindow of the main window that doesn’t have yet support for accessibility. These are: MuseScore Connect, Palette, Piano and Inspector. Everything looked good at this point, I was preparing to make my first Pull Request and just when I was thinking about it, I started talking to Marc Sabatella, telling him what I’ve did, what works and what are my concernes. At the end of this conversation, we both understood that the Return key problem was just a piece of the bigger picture. There is the same problem with the arrow keys and some other shortcuts used for editing and selecting text (like Ctrl+A, Shift+RightArrow, etc).
It was clear that I could not treat every shortcut that creates conflicts like a KeyPressEvent for two main reasons:
– first of all this would meant that a lot of shortcuts would have been hardcoded. Shortcuts are now configurable through the preferences dialog, using the shortcuts tab, or using directly the shortcuts.xml file
– secondly, there was no way of knowing what shortcuts would every user add/change. I’ve removed that Enter key from being a shortcut, but that doesn’t stop any user to add it again .
Remainder: The problem with the Return key was that the shortcut was global and other objects did not receive an event when it was pressed, because Qt was sending the event to the QAction object that had the key assigned to instead of seding it to the widget that had focus at that moment.
The bigger picture: All shortcuts are global and any key or key sequence that is assigned as shortcut will be sent to the QAction object, instead of the widget that has focus.
I needed to find a new solution, that was general enough to cover if not all, at least most of the usecases. This is the solution that I was able to come up with:
1. Move every QAction that affects the score in the ScoreTab object and change their shorcutcontext from WindowShortcut to WidgetWithChildrenShortcut, leaving in the MuseScore object (Main window) just those that open subwindows, dialogs,etc.
2. Set the focus policy for all the other subwindows of the main window so that the they don’t receive focus by clicking on their elements (except for the case when text editing is necesary)
3. (optional) Restrict the user from assigning keys like Return, Tab, Arrow keys as shortcuts.
For 1. I will create a global enum that will specify for what window/object is the QAction intended. In this way, if in the future other actions will be added that are supposed to go in other objects, the only thing that will be needed is to add a new value for that enum. Since every action is instantiated in the action.cpp file using a Shortcut object, I will put a variable of that enum type as field in the Shortcut object.
For 2. : Since all actions are in the main window at the moment and their shortcut context is WindowShortcut, the focus *appears* to be always in the scoretab. In order to preserve this behavior where this is desired and avoid the bad examples I’ve given above I need to set the focus policy for all the other objects so that they don’t give away the focus to other elements. It would be nice to set a property for scoretab so that it doesn’t give away the focus, but this is not possible. The only usecase I see when the focus should leave the scoretab is when editing text in another subwindow.
For 3: This step is debatable. With the default shortcuts assigned in the way they are now, everything will work as desired, but this doesn’t mean that a user cannot reassign keys like: Return, Tab, Arrow keys as shortcuts for other actions and create problems. This is a question if we consider that is MuseScore’s responsability to restrict the user from poorly assigning shortcuts, or it is the user’s responsability. In the first case, the above mentioned keys will be handled like KeyPressEvents in the scoretab object and their behavior for the scoretab will be hardcoded.
I’ve sent this proposal to the MuseScore mailing list hoping that it will be aproved by the community, since it is a big change. I also asked the following questions:
Q1: What do you think about step 3?
Q2: Do you know other usecases in which the scoretab should give away the focus, except when editing text?
What I forgot to mention on the mailing list is that this change will only affect the way in which the actions are triggered. The chain of functions and verifications that an action travels through for something to actually happen will remain exactly the same. They will be passed as before to the cmd function from the main window using a signal.
The good part is that the time I’ve spent on what I worked until now was not wasted. I implemented enough of the solution so that I can test it and I’ve done this by applying few changes to the code that I’ve already wrote. For step 2 of the solution I’ve used the knowledge that I’ve gain by trying to remove the subwindows from the tabbing order.
Now, I have to make a list of the actions that will remain in the main window.
As Marc said, things might get even more complicated when I get to the Palettes, but hopefully this solution will be good enough and it will not need (many 🙂 ) changes.
I know I promissed a howto post this week, but as it turns out, it is a good thing that I didn’t publish it, since it would have lacked many usefull informations.
Some good news: Thursday I will have my last exam, so after that I’m going to devote all my time to this project.
Thank you for taking the time to read this! 🙂