[Addon] Show Current Shortcuts in a Dialog

Lists all the shortcuts available for the area under your mouse.
With

This addon now is a context sensitive popup that shows most of the currently available keyboard shortcuts
This Post is where I will keep the latest version of the code.
If you have any ideas opinions etc I would love to hear the feed back.

Usage Instructions:
Install the plugin
Have a look in the addon prefs and set it up to suit your screen size and key visualization ideas.
More prefs will be available in the future
You can press the shortcut to show the changes as you make them.
If you want to save the setup you need to Save your user prefs after you find something you like.

The shortcut Command/Super + Shift + F1
This can easily be changed in the user preferences.
Is the only real way to run the code ( the spacebar search works too but as this is context sensitive the shortcut makes more sense. IMHO)

Anyway If it can help you I will be stoked.

Change log:
13 October 2014 7:37:53 AM AWST
PEP 8 compliant. Context issolation is getting better. The addon is actually starting to become useable.
24 September 2014 9:41:53 PM AWST
Change to Command/Super + Shift + F1 as default shortcut.
24 September 2014 5:23:51 PM AWST
Major update UI change. Show by context correctly.
10 September 2014 12:04:03 AM AWST
uploaded popup version as I have had no real feed back this is the way I want it to work so I have put the html code aside.
31 August 2014 3:48:09 PM AWST
uploaded as addon html tables are now in the same order as the keymaps in user prefs
Fri Aug 29 19:23:14 2014:
initial upload

Hi I have written a python key map exporter.
Post #1 will always have the latest version.

The script will write out your personal shortcut keys that are available at the time that you run it.
This will include the currently installed addons.
I am open to suggestions for more inclusions.
I have used simple HTML tables so you can simply cut and paste them either into a document editor or a spreadsheet or any other format you like.
I am new to both Blender and Python and couldn’t find something existing.
Please excuse the code. I am definitely a hacker.
Hope you find this useful
It’s amazing to see how many shortcuts combos there are (1615 last count with the basic settings of the script).
Yardie

TODO list

  • Get all the info possible for each shortcut
  • Sort out the obscure mode types (adopt the same structure as in the C module) Half way there
  • Sort out why you can only click on a shortcut once
  • Make the buttons more visually easy to scan quickly

Hi Yardie,

Name the python file: io_export_shortcuts2html.py like the Blender convention.

You can too add a bl_information for an add-on.

and a popup menu for parameters:
http://wiki.blender.org/index.php/Dev:2.5/Py/Scripts/Cookbook/Code_snippets/Interface

I was going to do that but I can’t really think of where to put it in the interface.
I guess the obvious place is in the Info panel under the help menu.
I sought of like the idea of it having it’s on shortcut key like Shft + Ctrl + Alt + OS Key + F1 for a bit of fun.

Yardie,

For me I put just it in Import-Export category.

Warning: For shortcut, there are a lot of add-ons with errors when we press F8.
You must use algorythm like the Booltool add-on for create shortcuts correctly :


addon_keymaps = []

REGISTER:
# handle the keymap    
    wm = bpy.context.window_manager
    km = wm.keyconfigs.addon.keymaps.new(name='Object Mode', space_type='EMPTY')
    kmi = km.keymap_items.new(BooleanUnion.bl_idname, 'NUMPAD_PLUS', 'PRESS', ctrl=True)
    addon_keymaps.append((km, kmi))
    kmi = km.keymap_items.new(BooleanDiff.bl_idname, 'NUMPAD_MINUS', 'PRESS', ctrl=True)
    addon_keymaps.append((km, kmi))
    kmi = km.keymap_items.new(BooleanInters.bl_idname, 'NUMPAD_ASTERIX', 'PRESS', ctrl=True)
    addon_keymaps.append((km, kmi))

UNREGISTER:
# Keymapping
    # handle the keymap
    for km, kmi in addon_keymaps:
        km.keymap_items.remove(kmi)
    addon_keymaps.clear()
    

This code is ok.

Thanks heaps Spirou4D
Your previous post sent me looking and I have been looking for current relevant examples
Learning Blender/Python at the moment seams to be a bit like jumping onto a fast moving train.
Many refs are out of date. Only yesterday found out about % and format
I have now found template_py in the 2.71 source and am working from that.
Also in http://www.blender.org/documentation/blender_python_api_2_71_release/info_tutorial_addon.html
(I wish someone would symlink/map the blender_python_api_2_71_release to something like blender_python_api_current_release then you wouldn’t need to hunt for the latest docs all the time)

Anyway my question is
the code suggests defining
addon_keymaps = []
above the register line
is this required / would it break other addons
I don’t really understand scope inside blender
is my script sandboxed

Thanks heaps for your help

the code suggests defining
addon_keymaps = []
above the register line
YES like in the Booltool add-on.

is this required / would it break other addons
? no your km kmi are unique with their names!

I don’t really understand scope inside blender
LIKE IN OFFICIAL PYTHON

is my script sandboxed
NO. ? it’s python not C++

For easy study, read a lot of official Blender add-on files only.

Sorry I do have a lot of C type history and so Python is like French to me :slight_smile:
Thanks I’ll check out booltool
and
“For easy study, read a lot of official Blender add-on files only.”
This is a very good idea and appears obvious now that you suggest it.
Thanks again.

Glad to help you and I apreciate your script…
Good luck and good night.
bye bye
Spirou4D

Warning:

Traceback (most recent call last):  File "C:\Users\Patrick\AppData\Roaming\Blender Foundation\Blender\2.71\scripts\addons\io_export_shortcuts2html.py", line 141, in execute
    raw_data = get_shortcuts()
  File "C:\Users\Patrick\AppData\Roaming\Blender Foundation\Blender\2.71\scripts\addons\io_export_shortcuts2html.py", line 82, in get_shortcuts
    desc = idtype.bl_rna.properties[prop].enum_items[attr].description
KeyError: 'bpy_prop_collection[key]: key "GLOBAL" not found'

It’s the error line:
desc = idtype.bl_rna.properties[prop].enum_items[attr].description

# ##### BEGIN GPL LICENSE BLOCK ######
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.     See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####




bl_info = {
    "name": "Export Shortcuts to HTML",
    "author": "Yardie",
    "version": (0, 1),
    "blender": (2, 70, 0),
    "location": "File menu",
    "description": "Get and Write Shortcuts to HTML file",
    "warning": "",
    "wiki_url": "",
    "category": "Import-Export"}


import bpy
import string
from datetime import datetime, date


#------------------- FUNCTIONS------------------------------


def get_shortcuts():
    """Get the data from the user prefs"""
    output = {}
    """populate output with keymaps"""
    for prefs in bpy.context.window_manager.keyconfigs.user.keymaps:
        #loop through each context
        context = prefs.name
        print (context)
        key_info = {}
        for prefs_item in prefs.keymap_items:
            # enum in ['KEYBOARD', 'TWEAK', 'MOUSE', 'NDOF', 'TEXTINPUT', 'TIMER'], default 'KEYBOARD'
            # From this list add which devices you want to get shortcuts on 
            # ie I don't have a NDOF device so I didn't include it
            if prefs_item.map_type in {'KEYBOARD', 'TWEAK', 'MOUSE', 'TEXTINPUT', 'TIMER'} and prefs_item.active:
                # loop through each key combo
                modifiers = ""
                if prefs_item.any:
                    modifiers = "Any modifier key"
                else:
                    modifier_key = []
                    if prefs_item.shift: modifier_key.append("Shift")
                    if prefs_item.oskey: modifier_key.append("OS Key")
                    if prefs_item.ctrl: modifier_key.append("Ctrl")
                    if prefs_item.alt: modifier_key.append("Alt")
                    modifiers = " + ".join(modifier_key)
                #sortable key for dict
                sort_key = prefs_item.type + " " + modifiers
                if modifiers != "":
                    modifiers += " + "
                base_key = string.capwords(prefs_item.type.replace("MOUSE","_MOUSE").replace("TRACKPAD","TRACKPAD_"),"_").replace("_"," ").replace("Ndof","NDOF ")
                #base_key = key_map_item.type #string.capwords(key_map_item.type.replace("MOUSE","_MOUSE").replace("TRACKPAD","TRACKPAD_"),"_").replace("_"," ").replace("Ndof","NDOF ")
                if hasattr(prefs_item, "properties") and prefs_item.idname:
                    idname = prefs_item.idname
                    mod, opname = idname.split(".")
                    idname_c = "{!s}_OT_{!s}".format(mod.upper(), opname)
                    idtype = getattr(bpy.types, idname_c)
                    description = idtype.bl_rna.description
                    #args = []
                    for prop in dir(prefs_item.properties):
                        if prop in idtype.bl_rna.properties and not prop.startswith("_") and prop not in {"bl_rna", "rna_type"}:
                            attr = getattr(prefs_item.properties, prop)
                            #args.append("{!s} = {!r}".format(prop, attr))
                            if idtype.bl_rna.properties[prop].type == "ENUM": # needs to handle attr = "" ie default of enum?
                            #needs to handle empty description -> print selected enum  "With prop as attr
                                if attr:
                                    desc = idtype.bl_rna.properties[prop].enum_items[attr].description
                                    if desc == "":
                                        desc = "Where {0} equals {1}".format(prop,string.capwords(attr))
                                    description += " " + desc
                            elif idtype.bl_rna.properties[prop].type == "BOOLEAN":
                                if attr:
                                    description += " " + (idtype.bl_rna.properties[prop].description)
                            #elif idtype.bl_rna.properties[prop].type not in {"INT","FLOAT"}:
                            #     print("	{0} ({1}) = {2} ".format(prop,idtype.bl_rna.properties[prop].type,attr))
                    if description == "":
                         description = prefs_item.name
                    #if idtype.bl_rna.properties[prop].type == "INT":
                            #     description += " " + (idtype.bl_rna.properties[prop].description)
                    #cmd = ">>>>> bpy.ops.{0}({1})".format(prefs_item.idname, ", ".join(args))
                    key_info[sort_key] = {"base key": base_key , "modifiers": modifiers, "description": description}
                    #print ("====> In {0}    [{1}{2}] Name {3}
	{4}".format(context, modifiers, base_key, prefs_item.name,description))
                    #if description == "":
                    #     print (cmd)
                    #print (description)
        #for key in sorted(key_info):
        #     out = key_info[key]
        #     print("{1}{0} 	{2}".format(out['base key'],out['modifiers'],out['description']))
        output[context]=key_info
    return output


def format_html(shortcuts):
    """format the data into html with tables"""
    output = "<html><head></head><body><h2>Blender Shortcut Keys</h2>
"
    output += "As at {:%c}".format(datetime.now())
    
    for context_key in sorted(shortcuts):
        output += "<h3 style=\"color: #FF0000;\">{0}</h3>".format(context_key)
        output += """<table border=1>
        <thead>
        <tr>
            <th style=\"color: #0000FF;\">Modifier/s</th>
            <th style=\"color: #0000FF;\">Keys</th>
            <th>Description</th>
        </tr></thead>
"""
        key_info = shortcuts[context_key]
        
        #Write the rows
        for key_info_key in sorted(key_info):
            out = key_info[key_info_key]
            output += ("<tr><td style=\"color: #0000FF;\"><b>{0}</b></td>
<td style=\"color: #0000FF;\"><b>{1}</b></td>
<td>{2}</td></tr>
".format(out['modifiers'],out['base key'],out['description']))
        output += "</table>

"
    output += "</body></html>
"
    return output


#------------------- OPERATOR CLASSES ------------------------------  
class ShortCuts(bpy.types.Operator):
    """Get and Write Shortcuts to HTML file"""
    bl_idname = "objects.shortcuts_export"
    bl_label = "Write shortcuts to html"
    
    filepath = bpy.props.StringProperty(subtype="FILE_PATH")
    filename = bpy.props.StringProperty(name="File name", default="shortcut_keys.html")
    
    def execute(self, context):
        raw_data = get_shortcuts()
        html_data = format_html(raw_data)
        self.filename="shortcut_keys.html"
        file = open(self.filepath, 'w')
        file.write(html_data)
        file.close()
        return {'FINISHED'}
        
    def invoke(self, context, event):
        context.window_manager.fileselect_add(self)
        return {'RUNNING_MODAL'}




    
def menu_func(self, context):
    self.layout.operator(ShortCuts.bl_idname, text="Shortcuts to HTML")
    
ShortCuts_addon_keymaps = []
# Register and add to the file selector
def register():
    bpy.utils.register_module(__name__)
    bpy.types.INFO_MT_file_export.append(menu_func)
    
    # handle the keymap       
    wm = bpy.context.window_manager
    km = wm.keyconfigs.addon.keymaps.new(name='Object Mode', space_type='EMPTY')
    kmi = km.keymap_items.new(ShortCuts.bl_idname, 'F1', 'PRESS', ctrl=True, shift=True, alt=True, oskey=True)
    ShortCuts_addon_keymaps.append((km, kmi))


def unregister():
    bpy.utils.unregister_module(__name__)
    bpy.types.INFO_MT_file_export.remove(menu_func)
    
    # Keymapping
    # handle the keymap
    for km, kmi in ShortCuts_addon_keymaps:
        km.keymap_items.remove(kmi)
    ShortCuts_addon_keymaps.clear()


if __name__ == "__main__":
    register()

You must find the error yourself now…but you can see I have made the shortcuts of this add-on.

Thanks for the heads up mate I’ll look into it.
It’s always hard to break your own code. So I’m very grateful for your input.
May take a day or two.

Does this happen when you paste it in the console as well.
It shouldn’t really change anything tho.

Maybe I’ll put it in a try block for now so it doesn’t hose the whole process when a key breaks

Thanks again.
Knowing that one person can find this useful is enough to make it worth while.

>>>Knowing that one person can find this useful is enough to make it worth while.
yes but you can use the export file of shortcut of Blender and extract&read with an extern python script to produce a page html with a bat file if you want, no? it’s the same. Not in Blender but the same…

Good luck!

Actually I don’t think you can as the export file only exports any that are different from the defaults.
This is what I first tried. Unless I did something wrong before I started this.
Anyway I have done the basics.
It’s now a proper Addon as you suggested.
I will implement the other parts to follow the idea to it’s completion.
If someone then finds it useful then that’s ok if not that’s ok too.
I know a lot more about blender than I did when I started.
And maybe I am that one person :slight_smile:

Anyway I will update post #1 with the latest code

May be I follow this code with one eye…may be…

NO! Export is the good way but you must study some export like “Export mesh as raw” add-on…etc…

A little patience, please.
Bye bye
Spirou4D

New release this one actually works in a usable way.
It is visibly scanable.
Context is generally correct.
The multiple buttons are there 'cause there are different versions of each command
I will combine these next
There is a button to activate the shortcut next to each item.
Hopefully this will help people learn all the 1600 or so shortcuts for Blender.
And if you don’t want to learn them just learn Command + F1


Latest Code is here

Luckily you say you’re a newbie:

“I am new to both Blender and Python and couldn’t find something existing.
…/…
Sorry I do have a lot of C type history and so Python is like French to me”

because you have attempted a difficult add-on! Congratulations: very useful add-on!

On Vista, you don’t use the Command button + F1 without ctrl or shift with, otherwise Vista displays an alert!

Thanks for the feedback
Maybe I’ll change the default to Shift + F1
I think F1 is good as it is traditionally a Help shortcut so new users will recall it.
Also Shift + F1 should be generic no OS affected keyboard combo.

This is now the default in the release version.

I will also add a link in the header of the 3D View and others not sure which ones (mostly to follow Blender UI guidelines
It’s tricky for me to know with so little Blender experience.
So the more feedback I can get here the better I can make it.

Also it is difficult to break/critic your own code so ‘Bring it on guys’ and I’ll do what I can.

If you can’t find a shortcut in the list that you know is available jot down what window it is in and what op it is calling. maybe see if you can find it in the user prefs under input. When I know where it is I will be able to track it down. Context is a tricky thing in Blender.