1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
19 # this script creates Keyboard layout images of the current keyboard configuration.
20 # first implementation done by jbakker
21 # version 0.2 - file manager directory on export, modified the SVG layout (lijenstina)
24 "name": "Keyboard Layout (SVG)",
27 "blender": (2, 80, 0),
28 "location": "Help Menu > Save Shortcuts as SVG files",
29 "description": "Save the hotkeys as .svg files (search: Keyboard)",
30 "warning": "Needs Updating. Basic functions work",
31 "doc_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/"
32 "Scripts/System/keymaps_to_svg",
33 "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
40 from bpy
.props
import StringProperty
43 ('`', 'ONE', 'TWO', 'THREE', 'FOUR', 'FIVE', 'SIX', 'SEVEN', 'EIGHT', 'NINE',
44 'ZERO', 'MINUS', 'EQUAL', 'BACKSPACE'),
45 ('TAB', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '(', ')', '\\'),
46 ('CAPSLOCK', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', "'", 'ENTER'),
47 ('SHIFT', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', ',', '.', '/', 'SHIFT'),
48 ('CONTROL', 'OSKEY', 'ALT', 'SPACE', 'ALT', 'OSKEY', 'MENUKEY', 'CONTROL')
51 # default dimension of a single key [width, height]
53 DEFAULT_KEY_DIMENSION
= 170, HEIGHT_KEY
54 # alternative dimensions of specific keys [keyname,[width, height]]
55 ALTERNATIVE_KEY_DIMENSIONS
= {
56 'BACKSPACE': (270, HEIGHT_KEY
),
57 'TAB': (220, HEIGHT_KEY
),
58 '\\': (220, HEIGHT_KEY
),
59 'CAPSLOCK': (285, HEIGHT_KEY
),
60 'ENTER': (345, HEIGHT_KEY
),
61 'SHIFT': (410, HEIGHT_KEY
),
62 'CONTROL': (230, HEIGHT_KEY
),
63 'ALT': DEFAULT_KEY_DIMENSION
,
64 'OSKEY': DEFAULT_KEY_DIMENSION
,
65 'MENUKEY': DEFAULT_KEY_DIMENSION
,
66 'SPACE': (1290, HEIGHT_KEY
),
68 INFO_STRING
= "Modifier keys Info: [C] = Ctrl, [A] = Alt, [S] = Shift"
71 def createKeyboard(viewtype
, filepaths
):
73 Creates a keyboard layout (.svg) file of the current configuration for a specific viewtype.
74 example of a viewtype is "VIEW_3D".
77 for keyconfig
in bpy
.data
.window_managers
[0].keyconfigs
:
79 for keymap
in keyconfig
.keymaps
:
80 if keymap
.space_type
== viewtype
:
81 for key
in keymap
.keymap_items
:
82 if key
.map_type
== 'KEYBOARD':
98 cont
= "[" + cont
+ "] "
100 if ktype
not in kc_map
:
102 kc_map
[ktype
].append((test
, cont
+ key
.name
))
104 filename
= "keyboard_%s.svg" % viewtype
105 export_path
= os
.path
.join(os
.path
.normpath(filepaths
), filename
)
106 with
open(export_path
, mode
="w") as svgfile
:
107 svgfile
.write("""<?xml version="1.0" standalone="no"?>
108 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
110 svgfile
.write("""<svg width="2800" height="1000" version="1.1" xmlns="http://www.w3.org/2000/svg">
112 svgfile
.write("""<style>
114 fill:rgb(223,235,238);
125 stroke:rgb(0,65,100);
156 fill:rgb(0, 128, 128)
160 fill:rgb(128,128,128)
164 fill:rgb(128,128,128)
168 fill:rgb(255,128,128)
172 fill:rgb(128,255,128)
176 fill:rgb(255,255,128)
180 fill:rgb(128,128,255)
184 fill:rgb(255,128,255)
188 fill:rgb(128,255,255)
192 fill:rgb(255,255,128)
196 svgfile
.write("""<text class="header" x="30" y="32">Keyboard Layout for """ + viewtype
+ """</text>
206 width
, height
= ALTERNATIVE_KEY_DIMENSIONS
.get(key
, DEFAULT_KEY_DIMENSION
)
207 tx
= ceil(width
* 0.2)
209 svgfile
.write("""<rect x=\"""" + str(x) +
210 """\" y
=\"""
" + str(y) +
211 """\" width=\"""" + str(width
) +
212 """\" height=\"""" + str(height) +
213 """\" rx
="20" ry
="20" />
215 svgfile.write("""<text
class="key" x
=\"""
" + str(x + tx) +
216 """\" y=\"""" + str(y
+ ty
) +
217 """\" width=\"""" + str(width) +
218 """\" height
=\"""
" + str(height) + """\">
221 svgfile.write("</text
>")
225 for a in kc_map[key]:
226 svgfile.write("""<text class="add
""" + str(a[0]) +
227 """" x=\"""" + str(x
+ tx
) +
228 """\" y=\"""" + str(y + ty) +
229 """\" width
=\"""
" + str(width) +
230 """\" height=\"""" + str(height
) + """\">
233 svgfile
.write("</text>")
236 y
= y
+ HEIGHT_KEY
+ ygap
238 svgfile
.write("""<text class="header" x="30" y="975" >""")
239 svgfile
.write(INFO_STRING
)
240 svgfile
.write("</text>")
242 svgfile
.write("""</svg>""")
245 class WM_OT_keyboardlayout(bpy
.types
.Operator
):
246 bl_idname
= "wm.keyboardlayout"
247 bl_label
= "Save Shortcuts as SVG files"
248 bl_description
= ("Export the keyboard layouts in SVG format\n"
249 "for each Editor in a separate file")
251 directory
: StringProperty(
253 options
={'SKIP_SAVE'},
256 def invoke(self
, context
, event
):
257 if not self
.directory
:
260 wm
= context
.window_manager
261 wm
.fileselect_add(self
)
262 return {'RUNNING_MODAL'}
264 def execute(self
, context
):
265 if not (os
.path
.isdir(self
.directory
) and os
.path
.exists(self
.directory
)):
266 self
.report({'WARNING'},
267 "Chosen path is not a directory or it doesn't exist. Operation Cancelled")
270 # Iterate over all viewtypes to export the keyboard layout
271 for vt
in ('VIEW_3D',
284 createKeyboard(vt
, self
.directory
)
289 def menu_func_help(self
, context
):
290 self
.layout
.separator()
291 self
.layout
.operator(WM_OT_keyboardlayout
.bl_idname
, icon
="IMGDISPLAY")
295 bpy
.utils
.register_class(WM_OT_keyboardlayout
)
297 bpy
.types
.TOPBAR_MT_help
.append(menu_func_help
)
301 bpy
.types
.TOPBAR_MT_help
.remove(menu_func_help
)
303 bpy
.utils
.unregister_class(WM_OT_keyboardlayout
)
306 if __name__
== "__main__":