GNOME Bugzilla – Bug 354970
Support customization of key and braille bindings
Last modified: 2008-07-22 19:20:59 UTC
PRIMARY GOALS: 1) Provide infrastructure to more easily allow key and braille bindings to be specified/configured via a GUI. 2) Support the notion of "drop in" key and braille bindings files to allow people to share bindings for different keyboard layouts (e.g., laptops) and locales. BACKGROUND: Each script can have its own set of key and braille bindings. Currently, default.py provides the bulk of them, but sub-scripts such as the one for StarOffice provide new key bindings for things such as getting the formula for a spread sheet cell. The key and braille bindings bind a user action (a keystroke or a braille input device event) to an input event handler. The input handlers are set up in the script's setupInputEventHandlers method, and the bindings are set up in the script's getKeyBindings and getBrailleBindings methods. Examples from default.py include: def setupInputEventHandlers(self): ... self.reviewAboveHandler = input_event.InputEventHandler( Script.reviewAbove, _("Moves flat review to the word above the current word.")) ... def getKeyBindings(self): ... keyBindings = script.Script.getKeyBindings(self) ... keyBindings.add( keybindings.KeyBinding( "KP_4", 1 << settings.MODIFIER_ORCA, 1 << settings.MODIFIER_ORCA, self.reviewAboveHandler)) ... return keyBindings def getBrailleBindings(self): ... brailleBindings = script.Script.getBrailleBindings(self) ... brailleBindings[braille.CMD_LNUP] = self.reviewAboveHandler ... return brailleBindings PROPOSAL PART ONE: To make things nicer on folks providing configuration GUIs, we might want to consider using a dictionary to hold the input event handlers. This will allow for the easy enumeration of all possible input event handlers supported by a script (and also allows for the addition of custom input event handlers, if so desired). For example, instead of the following in setupInputEventHandlers: self.reviewAboveHandler = input_event.InputEventHandler( Script.reviewAbove, _("Moves flat review to the word above the current word.")) We'd have: self.inputHandlers["reviewAboveHandler"] = \ input_event.InputEventHandler( Script.reviewAbove, _("Moves flat review to the word above the current word.")) Then in getKeyBindings and getBrailleBindings, we'd have: keyBindings.add( keybindings.KeyBinding( "KP_4", 1 << settings.MODIFIER_ORCA, 1 << settings.MODIFIER_ORCA, self.inputHandlers["reviewAboveHandler"])) brailleBindings[braille.CMD_LNUP] = \ self.inputHandlers["reviewAboveHandler"] For helping with internationalization, we might want to add a name field to the input event handler. This name field would be a localized human consumable form (e.g., _("Left Click Review Item")). PROPOSAL PART TWO: The next step in the proposal is to allow the default keybindings to be extended/modified/overridden. A possible way to do this would be to have ~/.orca/user-customizations.py set a getKeyBindings method in orca.settings (assume the same for getBrailleBindings in the rest of this document). This method and its use would live in user-customizations.py and would look something like the following: def getKeyBindings(script): keyBindings = orca.keybindings.KeyBindings() keyBindings.add(orca.keybindings.KeyBinding( "Some X_Keysym", modifier_mask, modifiers, script.inputHandlers["inputHandlerName"])) ... return keyBindings orca.settings.getKeyBindings = getKeyBindings This method could also provide some logic to know what script it was dealing with if need be (e.g., to provide different custom bindings for StarOffice). default.py:getKeyBindings would then have some logic along the following lines at the very top: def getKeyBindings(self): # Defer to the settings module to override keybindings if so # desired. # try: return settings.getKeyBindings(self) except: pass (rest of code here) The drawback of this approach is that it requires *all* the keybindings to be set up in the customizations file. It might be more desirable to move the customization stuff to the end, renaming the settings.getKeyBindings method to settings.overrideKeyBindings or something like that: def getKeyBindings(self): ... keyBindings = script.Script.getKeyBindings(self) ... (default bindings set here) try: settings.overrideKeyBindings(self, keyBindings) except: pass return keyBindings To allow the overrideKeyBindings method to be more effective, however, we'd need to provide some mechanism to obtain a keyBinding given an InputEventHandler (or InputEventHandler name). A not-well-though-out-idea of how this could be done is via a brute force search to start with, and could be handled via new methods such as 'getKeyBinding(keyBindings, InputEventHandler)' and 'getBrailleBinding(brailleBindings, InputEventHandler)'. These methods would merely search for the given InputEventHandler in the given bindings and return the one that matched. One could then delete the existing InputEventHandler from the given bindings and replace it with a new one (if so desired).
Created attachment 72472 [details] [review] Patch to apply part one of the proposal This patch applies part one of the proposal. Since this is a rather substantial change, assuming people agree with this patch, I think we may need to do it earlier than later in the GNOME 2.17 cycle.
Patch to refactor the way key and braille bindings are created and managed committed. Still need to work on th second part of the proposal, which is to allow customizations to determine the key and braille bindings given an input event handler.
Created attachment 73039 [details] [review] New method for keybindings.KeyBindings As various KeyBinding can have the same InputEventHandler associated, this new method of KeyBindings returs a KeyBindings object, that contains all the KeyBinding that matches the same handler function than the one in the InputEventHandler passed as argument. This could be needed from the (soon-coming) key redefinition GUI section.
Created attachment 73358 [details] [review] Method for getting BrlTTY command code (in script.py Script) New script.py Script method for getting a BrlTTY command code from a brailleBinding dictionary entry (in a specific app script instance).
Created attachment 73416 [details] [review] Patch to combine the two previous patches This patch combines the two previous patches and keeps the logic for both in script.py. The patch renames things a little bit for consistency and also uses existing bindings (e.g., self.keyBindings) for the script rather than creating new ones (e.g., self.getKeyBindings()). The new methods added are: getKeyBindingsForInputHandler getBrailleCommandsForInputHandler
Comment on attachment 73416 [details] [review] Patch to combine the two previous patches Submitted this patch with one fix suggested by Jorge (thanks Jorge): for binding in self.keyBindings.keyBindings:
Created attachment 73483 [details] [review] Common human-readable i18n names for used BrlTTY commands Dictionary in braille.py to provide a human-readable name (i18n) to used BrlTTY codes in default.py script. To be shown in the GUI for Braille redefinition.
Add accessibility keyword. Apologies for spam.
Created attachment 75721 [details] [review] Patch to show Orca default keybindings in a new tab Preliminary patch to show in a new tab of the GUI all the Orca default keybindings as a list. The handler description with their associated keybindings. ATM it's not possible to modify them. Only Orca default keybindings are shown (as a list), in the future also apps specific keybindings will be shown (as a treeview).
Hi Jorge: Thanks for the patch! What kind of file is this? It's coming through as some sort of binary file whose content Firefox displays in a new window versus asking me if I want to save it.
Created attachment 75825 [details] [review] Patch to show Orca default keybindings in a new tab The previous patch, but uploaded in a plain .tar file, instead of a .tar.bz2 file that messed it up, sorry for that, let's hope this time it's ok :) ------------- Preliminary patch to show in a new tab of the GUI all the Orca default keybindings as a list. The handler description with their associated keybindings. ATM it's not possible to modify them. Only Orca default keybindings are shown (as a list), in the future also apps specific keybindings will be shown (as a treeview). -------------
Jorge: I finally had a chance to take a look at this. With one minor fix (I needed to comment out a line that referred to "editinKey" the patched orca_gui_prefs.py), I got it working. I think this is a good patch: even if it doesn't let you change the key bindings and even if it doesn't show app-specific bindings, it serves a very good purpose. That purpose is to provide a very convenient mechanism for people to discover what the Orca keybindings are. Rich, Mike, Lynn: should we shoot for getting this functionality in for 2.17.3? The things that would need to be addressed are: 1) A code review 2) A little cleanup (i.e., removing empty whitespace here and there) 3) Moving the keybindings tab to the last position?
I think you should continue moving forward with the patch, with the following suggestions: 0) Make the "KeyBindings" tab say something like "Key Bindings" (i.e., add a space) and put it at the end of the tab order. 1) Don't force the the Orca modifier to "Ins+". Instead, in keybindings.py, check for "mods & 256" and then use the first list item from settings.orcaModifiers. If you want to get tricky, you could compose a nerdy style string using all the modifiers in the list, such as "{Insert,KP_Insert}+", but this may be too tricky and actually kind of cumbersome when it comes to speech output. Maybe listing the Orca modifier list separate from the table might be a better thing to do. 2) If it's possible to order the bindings, it would be great to put the Function keys (e.g., F10, etc.) at the bottom and the keypad keys (i.e., KP_*) and arrow keys at the top. 3) When one hits the "Apply" button now after changing the bindings from laptop to desktop and vice versa, the bindings table should be recalculated accordingly. This is actually a very exciting patch to me. I see it helping answer one of our top FAQs, which is "what are the Orca key bindings?"
I agree with Will here. I think we should include this functionality as soon as possible. It is also the beginning to a tool that will be very powerful for creating custom key bindings in the future. Thanks much for the contribution.
I too agree that this should go in as soon as possible to work out any remaining kinks. Thanks for the patch.
Created attachment 76709 [details] [review] Revised keybinding list patch Patch to show Orca default keybindings in a new tab, with Willie suggestions fixed: * Keybindings tab as "Key Bindings", in the last position. * Real Orca modifier key list used. * Keybindings ordered by default. * Apply button updates keybinding list and orca modifier keys list. Also a small fix in magnifier GUI to display it correctly with the new dialog size. Anything else that you want to be changed just tell me :)
Created attachment 76741 [details] [review] Slightly modified patch The previous patch looked great. I modified the patch slightly to format the Python code within 80 character limits, use constants where possible, change "OrcaMod." string to "Orca", and eliminate the extra space prior to the keystring. It's checked in. Thanks!
This is going to be a really useful feature. A couple things I've noticed so far. 1. Do we really need to hear both states of the Keypad ie for Keypad 3 we hear both KP3 and KP end" I think just hearing what the key would be if numlock was off would be enough. 2. It would be nice if the ordering of keys could be a little more logical. For example, it would be good to have the keys that increase or decrease the speech rate grouped together. thanks much
Created attachment 77884 [details] [review] Patch to enable key binding editing by the user (in the GUI) Patch to enable editing of the list of key bindings by the user. * Change the List model to a Treeview. * The changes are persistent (when apply/acept button is clicked, the modified key bindings are saved in the ~/.orca/user-settings.py file) * Include a list of braille bindings (not editable) The patch should be revised before getting it into the CVS... And there are still some things to be improved (to delete an already modified keybinding you have to access the file directly, which is not a good idea for the final user)
Jorge: > Patch to enable editing of the list of key bindings by the user. I finally had a chance to look at this patch. It looks like you're almost there and I'm tempted to check it in with very minor modifications (i.e., removing an 'import sys' that doesn't need to be there). Invoking/cancelling the keystroke recording seems pretty intuitive to me and I think it's cool that you got it working. I'm curious about why you removed the "Meta" and "Caps_Lock" strings from keybindings.py:getModifierNames? > The patch should be revised before getting it into the CVS... What things would you like further review on or to make revisions to? > And there are > still some things to be improved (to delete an already modified keybinding you > have to access the file directly, which is not a good idea for the final user) I'm not sure if it is possible, but would you be able to compare the binding and function to the default one and not write it out to user-settings.py if they are the same? In addition, it might be nice to have a button somewhere that allows the user to revert a binding to the default value. In any case, I think this looks pretty good. If you'd like, I'm happy to check it in. I can also wait a little longer if you'd like to refine it some more. The big deadlines to get this in are Dec 18 and Jan 22. After that, it'll become harder to get them in and we'll probably need to wait until GNOME 2.20.
Created attachment 78201 [details] [review] User Key Bindings Editing Feature Updated patch for the edition of Key Bindings: > I finally had a chance to look at this patch. It looks like you're almost > there and I'm tempted to check it in with very minor modifications (i.e., > removing an 'import sys' that doesn't need to be there). Invoking/cancelling > the keystroke recording seems pretty intuitive to me and I think it's cool that > you got it working. Great! I've moved that "import sys" to the begining of the file (it was a test), and clean few other things. New improvements: * Now it's possible to unmark a key binding modification in the GUI as a check box, now they work! :), so the default Orca key binding can be restored easily from the GUI. > I'm curious about why you removed the "Meta" and "Caps_Lock" strings from > keybindings.py:getModifierNames? Well, in my spanish keyboard layout at least, I always get the META modifier when Num_Lock is enabled, it's strange, I removed that to avoid seeing it in the list in every keybinding, as it's not relevant... I'm not sure why happens that here. Other thing I've notice is that I cannot get 'KP_5' (I get just '5' instead). > What things would you like further review on or to make revisions to? Nothing in particular, if you think it's good/useful enough to be checked in, for me it's great :) > I'm not sure if it is possible, but would you be able to compare the binding > and function to the default one and not write it out to user-settings.py if > they are the same? Yes, that's already done at capturing time, it needs to have a different key or modifiers to be captured. > In addition, it might be nice to have a button somewhere that allows the user > to revert a binding to the default value. That's done now, perhaps it's not the most intuitive way of doing it, but it's simple (almost no extra code) and it works fine, if you have any better idea about how to do that just tell me and I'll try to do it. > The big deadlines to get this in are Dec 18 and Jan 22. After that, it'll > become harder to get them in and we'll probably need to wait until GNOME 2.20. Ok, it's ready I think, and we've got still some days to try it, I'm only worried about the gtk warnings it shows in the console when dealing with the treeview. Anything, just tell me :) Jorge.
Created attachment 78252 [details] [review] Jorge's patch with a few minor edits I made a few 'pythonic' changes (at least as much as I understand what it means to be 'pythonic', which may not be a lot) and fixed a few stack traces here and there. I also modified the code to use debug.printException instead of calling sys directly. It's now in for Orca v2.17.4. Great stuff, Jorge! We now have a few release cycles to let people test this before GNOME 2.18.
There is a little problem with this funcionalitty in Orca preferences GUI. Some keybindings doesn't work. If two keybindings are only diferent in the modifiers that they use, the combination with more modifiers doesn't work (well, it works only if is defined _before_ that the combination with less modifiers) The problem is with the second and third parameters in the keybinding function (now, always filled with the same value). When a new keybindings is defined, not only have to write a new entry for it in the user customization file, but also must check if exists another keybinding with the same letter and different modifiers. In this case, the previous keybinding definition must be changed too. I have reported a new bug (#408174) because default.py also has the same problem. In this bug everything is better explained.
Closing this as FIXED. Specific problems with customization should be opened as new bugs. Thanks for all the hard work on this!