Bundles
Shortcuts and keytips
Keyboard chords that run a tool without touching the ribbon, the Alt letters that walk to it, and how users rebind both.
A tool can be reached from the keyboard in three ways. Its AutoCAD command
(PYBATCHPLOT) can always be typed at the command line; that is covered in
Commands, macros and AutoLISP. This page covers the other two: a
chord such as Ctrl+Shift+K that pyACAD
watches for itself, and a keytip, the letters AutoCAD shows over the ribbon
when you press Alt.
Two places a binding comes from#
An author ships a default in the bundle's bundle.yaml:
title: Chord Only
tooltip: Invisible on the ribbon; press Ctrl+Shift+K to run it.
shortcut: Ctrl+Shift+KA user overrides it in %APPDATA%\pyACAD\config.json, normally through the
Shortcuts editor on the pyACAD panel, which writes this section for them:
{
"shortcuts": {
"bindings": {
"pyACAD.tab/Output.panel/Batch_Plot.pushbutton": "Ctrl+Shift+P",
"Smoke.tab/Buttons.panel/Chord_Only.nobutton": null
}
}
}The rule is simple: a user entry replaces the author default entirely.
A chord string rebinds the tool; null disables the author's default; no entry
leaves the default in force. The shipped pyACAD tools declare no shortcut: at
all, so every chord on a fresh install is one you chose.
Which bundles can have a chord#
Every pushbutton-shaped bundle, wherever it sits: *.pushbutton,
*.toggle, *.smartbutton and *.nobutton, at panel level,
inside a stack, inside any of the three pulldown kinds, or inside a slideout. A
*.nobutton exists for exactly this: it has no ribbon presence, so a chord (or its
typed command) is the only way in.
The parser reads shortcut: from a *.dockpane's
bundle.yaml, but nothing binds it: the chord table is built from pushbutton
bundles only. A dock pane cannot be toggled by a chord yet. *.urlbutton and
*.linkbutton do not read shortcut: either.
The chord grammar#
A chord is a list of tokens joined by +. Spaces around tokens are ignored and
case does not matter. Modifiers may come in any order; exactly one key is required.
| Token | Accepted spellings |
|---|---|
| Modifiers | Ctrl, Alt, Shift |
| Letters | A to Z |
| Digits | 0 to 9 (the top row, not the number pad) |
| Function keys | F1 to F24 |
| Navigation | Left, Up, Right,
Down, Home, End, PgUp,
PgDn |
Nothing else parses: not Control, Win, Space,
Esc, Del, Enter, punctuation, or the number pad. A
string that does not parse is reported in the log and the tool gets no chord:
Shortcut: 'My.tab/Tools.panel/Count.pushbutton': 'Ctrl+Shift+Num1': unknown token 'Num1'
Shortcut: 'My.tab/Tools.panel/Count.pushbutton': 'Ctrl+K+L': more than one key
Shortcut: 'My.tab/Tools.panel/Count.pushbutton': 'Ctrl+Shift': no keyA chord is shown in one canonical form, Ctrl+Alt+Shift+Key in that order, so
shift+ctrl+m and Ctrl+Shift+M are the same chord and both display
as Ctrl+Shift+M.
The Ctrl-or-Alt policy#
By default a chord must contain Ctrl or Alt. Shift alone
does not count, so Shift+M and a bare F5 are both refused:
'F5': bindings need Ctrl or Alt (set shortcuts.allowBareKeys to permit bare keys)Setting "shortcuts": { "allowBareKeys": true } in config.json
(the Settings window's Allow shortcuts without Ctrl or Alt box) lifts the rule.
Think hard before doing it. In AutoCAD you type commands while the cursor is over the drawing,
and the drawing area is not a text box, so a bare L binding would swallow the L of
LINE, LAYER and every other command you type there.
How the table is built#
At boot and on every Reload, before the ribbon is drawn, the runtime walks every pushbutton bundle in ribbon order (extension by extension, tab by tab, panel by panel, slideout contents after the panel's own items) and resolves each one:
- If
shortcuts.bindingshas an entry for the bundle key, that entry is the chord text, even when it isnull. Otherwise the author'sshortcut:is. - No text: the tool has no chord. Next tool.
- The text is parsed. A parse failure is logged and the tool has no chord. The author default is not restored behind a bad override.
- If an earlier tool already holds the same chord, this tool loses: first
wins, and the log says
'X' wants Ctrl+Shift+K but 'Y' already has it - first wins.
An override whose key matches no loaded bundle is logged as shortcut override for
unknown tool '...' ignored. Every problem goes to
%APPDATA%\pyACAD\logs\pyACAD.log with a Shortcut: prefix, followed
by Shortcuts: N binding(s) active. None of them raises a toast, so a chord that
silently does nothing is a reason to read the log.
The bundle key#
Overrides are keyed by the bundle key: the bundle folder's path relative to
its *.extension folder, with forward slashes and the folder suffixes kept.
| Bundle | Key |
|---|---|
| A panel button | pyACAD.tab/Output.panel/Batch_Plot.pushbutton |
| A button in a stack | pyACAD.tab/AI_(beta).panel/Setup.stack/AI_Settings.pushbutton |
| A button in a slideout | My.tab/Tools.panel/More.slideout/Purge_All.pushbutton |
A legacy numbered folder 01_Toggle_Demo.toggle |
Smoke.tab/Buttons.panel/Toggle_Demo.toggle |
A leading NN_ (two or more digits and an underscore) is dropped from every
segment, both when the key is made and when config.json is read, so renumbering
folders never orphans an override. Keys compare case-insensitively. The extension's own
folder name is not part of the key.
Rename Batch_Plot.pushbutton to Plot_PDFs.pushbutton and the
override keyed by the old path matches nothing. The only symptom is the unknown
tool line in the log. Set bindings through the Shortcuts editor rather than by hand,
and expect to re-bind after a rename.
When a chord fires#
Bindings are watched by a keyboard hook installed on AutoCAD's UI thread. It is
thread-scoped (WH_KEYBOARD), not global: it sees keys delivered to AutoCAD and
nothing typed in any other application. A matching chord still has to clear three guards.
- Exact modifiers. The state of Ctrl, Alt and Shift (either side of the
keyboard) must match the binding exactly:
Ctrl+Kdoes not fire while Shift is also held. On keyboards with an AltGr key, Windows reports AltGr as Ctrl+Alt, so aCtrl+Alt+Ebinding also fires on AltGr+E. - Fresh key down only. Holding the chord does not repeat the tool.
- AutoCAD's main window must be the foreground window. Docked palettes are part of it; a floating palette, the output window, a pyACAD dialog or another application in front means the chord does nothing.
- Focus must not be a text input. A WPF text box or password box blocks the chord, as does a native control whose window class contains "edit". If focus cannot be read at all, the runtime assumes you are typing and does nothing.
A chord that passes is swallowed (AutoCAD never sees the key) and the tool starts on the next turn of the message loop, exactly as a ribbon click would: its registered command is sent to the active drawing. So a chord runs in document context with the drawing locked and one undo group, and with no drawing open it shows the toast Open a drawing first. The details are in Click actions.
Ctrl+Shift+M runs script.py, never
config.py, even though the chord contains Shift. Chords bypass the modifier
click rules entirely; Shift+Click (or typing the tool's CFG command)
is the only way to reach the secondary action.
Conflicts with AutoCAD's own keys#
The hook sees a key before AutoCAD's own accelerators do, and a dispatched chord is
swallowed. A pyACAD binding on a key AutoCAD already uses therefore wins
silently whenever the guards pass: bind Ctrl+S and AutoCAD stops saving
from the keyboard. Nothing warns about this; the Shortcuts editor only checks for conflicts
between pyACAD tools.
AutoCAD's default keyboard shortcuts live in the CUI editor (CUI, Keyboard
Shortcuts), and that is the list to check. The ones people miss most when shadowed:
- The clipboard and file keys:
Ctrl+C,Ctrl+V,Ctrl+X,Ctrl+Z,Ctrl+Y,Ctrl+S,Ctrl+N,Ctrl+O,Ctrl+P, andCtrl+Shift+S,Ctrl+Shift+C,Ctrl+Shift+V. - Most of the palette toggles on the digit row,
Ctrl+0toCtrl+9(Properties isCtrl+1, the command lineCtrl+9). - The drafting toggles on the function keys,
F1toF12. These are bare keys, so only a binding made withallowBareKeyson can take them.
Prefer Ctrl+Shift+letter or Ctrl+Alt+letter,
check the CUI list first, and avoid Alt+letter on its own: the Alt key
is how AutoCAD walks the ribbon (next section).
Keytips#
Keytips are the letters AutoCAD shows over the ribbon when you press and release
Alt. Every tab pyACAD builds carries the tab keytip PY (an extension that adds a
second tab gets PY on that one too); inside a tab, every
item gets one or two letters, assigned per tab when the ribbon is built.
Assignment covers everything that renders on the tab: panel-level buttons (including
toggles and smartbuttons), each child of a stack, the header of each pulldown,
*.splitbutton and *.splitpushbutton, urlbuttons, linkbuttons and dock
pane toggles, slideout contents included. Pulldown children get none, because a menu
is walked with the arrow keys once open, and nobuttons get none because they are not on the
ribbon.
The rules, from KeyTips.Assign:
- Explicit keytips claim first. A
keytip:inbundle.yamlis trimmed and uppercased. If two items on the same tab ask for the same keytip, the first in ribbon order gets it and the second gets no keytip at all; it does not fall back to an automatic one. - Then every other item, in ribbon order, takes the first free candidate built from the letters of its title (digits and spaces are skipped): the first letter, then the first two letters, then the first letter followed by 2, 3 and so on up to 9.
- An item whose candidates are all taken, or whose title has no letters, gets none.
title: Batch Plot
tooltip: Plots the layouts you pick to PDF, one file per layout.
keytip: OPThe shipped tools set two-letter keytips by panel (OP for Output, Batch Plot;
LM for Layers, Layer Manager) so they stay stable as tools are added. Do the same
in your own extension: automatic keytips shift whenever a tool is added before another with the
same initial.
The assignment avoids duplicates but not prefixes: an automatic C can sit on
the same tab as an explicit CC. How AutoCAD's ribbon resolves a keytip that is
the start of another is its own behaviour, so if a two-letter keytip is hard to reach, give the
one-letter item an explicit two-letter keytip too.
What the user sees on the button#
A resolved chord shows in two places, both updated on every ribbon build:
- The tooltip gets the chord appended in brackets, for example
Plots the layouts you pick to PDF. (Ctrl+Shift+P). It names the resolved chord, so a rebound tool shows the user's key, not the author's. - The caption gets a marker after the name, a dot (
●) by default.ribbon.showShortcutMarkerturns it off andribbon.shortcutMarkerchanges the glyph; a glyph starting with a newline puts the marker on its own line. See Settings.
The Shortcuts editor#
The Shortcuts button on the pyACAD panel (command
PYSHORTCUTS) opens the Shortcuts and Aliases window. It lists every
pushbutton bundle currently loaded, grouped under its panel's title, with a search box that
filters by tool name, panel, command, chord and alias.
- Recording. Click a tool's field and press the chord. Backspace or Delete clears it (which disables an author default), Esc leaves the field as it was, and Tab moves on rather than being recorded. A chord the runtime would refuse shows "needs Ctrl or Alt" or "unsupported key" and is not taken.
- Badges. A row away from its author default says custom or disabled, and shows a reset arrow when the tool has a default to go back to.
- Conflicts. When two tools hold the same chord, the later one in ribbon order is marked conflicts with the earlier one, the same first-wins order the runtime uses, and Save stays disabled until the conflict is resolved.
- Aliases. Each row has an Alias field (
BX, orBX, B2X). It follows the registration rules on Commands: an alias another tool holds, or one of the tools' full command names, is flagged is taken by; one inacad.pgpor already an AutoCAD command is flagged too. On a row you changed, the flag is red and Save stays disabled. On an author's alias it is a muted Alias not active note, since registration skips it anyway. - Restore All Defaults puts every row's chord and aliases back to the author's.
Save writes only the rows that differ from their defaults into
shortcuts.bindings (a chord string, or null to disable a default) and
aliases (the aliases, or null for none), leaves every other key in
config.json alone, then reloads pyACAD and toasts Shortcuts and aliases saved
and applied. If the file cannot be written, or holds invalid JSON
that it refuses to overwrite, it toasts Shortcuts were not saved with the reason.
The editor writes the whole bindings map from the tools it can see. An
override for a tool whose extension is not loaded right now (a removed extension root, an
offline network folder) is not carried over, so saving from the editor deletes it. Aliases do
not have this problem: entries for tools the editor did not show are kept.
Hand edits to config.json take effect on the next Reload.
Checklist#
- The chord has Ctrl or Alt, one key, and only the tokens in the grammar table.
- It is not one of AutoCAD's own keys, unless replacing that key is the point.
- The log shows no
Shortcut:line for your tool after a Reload. - The tooltip shows the chord in brackets: that is proof it resolved.
- Your extension's tools carry explicit
keytip:values, unique on the tab.