Keyboard Shortcuts
Wails provides a powerful key binding system that allows you to register global keyboard shortcuts that work across all windows in your application. This enables users to quickly access functionality without navigating through menus.
Accessing the Key Binding Manager
The key binding manager is accessed through the KeyBindings property on your application instance:
app := application.New(application.Options{
Name: "Keyboard Shortcuts Demo",
})
// Access the key binding manager
keyBindings := app.KeyBindingAdding Key Bindings
Basic Key Binding
Register a simple keyboard shortcut:
app.KeyBinding.Add("Ctrl+S", func(window application.Window) {
// Handle save action
app.Logger.Info("Save shortcut triggered")
// Perform save operation...
})Multiple Key Bindings
Register multiple shortcuts for common operations:
// File operations
app.KeyBinding.Add("Ctrl+N", func(window application.Window) {
// New file
window.EmitEvent("file:new", nil)
})
app.KeyBinding.Add("Ctrl+O", func(window application.Window) {
// Open file
dialog := app.Dialog.OpenFile()
if file, err := dialog.PromptForSingleSelection(); err == nil {
window.EmitEvent("file:open", file)
}
})
app.KeyBinding.Add("Ctrl+S", func(window application.Window) {
// Save file
window.EmitEvent("file:save", nil)
})
// Edit operations
app.KeyBinding.Add("Ctrl+Z", func(window application.Window) {
// Undo
window.EmitEvent("edit:undo", nil)
})
app.KeyBinding.Add("Ctrl+Y", func(window application.Window) {
// Redo (Windows/Linux)
window.EmitEvent("edit:redo", nil)
})
app.KeyBinding.Add("Cmd+Shift+Z", func(window application.Window) {
// Redo (macOS)
window.EmitEvent("edit:redo", nil)
})Key Binding Accelerators
Accelerator Format
Key bindings use a standard accelerator format with modifiers and keys:
// Modifier keys
"Ctrl+S" // Control + S
"Cmd+S" // Command + S (macOS)
"Alt+F4" // Alt + F4
"Shift+Ctrl+Z" // Shift + Control + Z
// Function keys
"F1" // F1 key
"Ctrl+F5" // Control + F5
// Special keys
"Escape" // Escape key
"Enter" // Enter key
"Space" // Spacebar
"Tab" // Tab key
"Backspace" // Backspace key
"Delete" // Delete key
// Arrow keys
"Up" // Up arrow
"Down" // Down arrow
"Left" // Left arrow
"Right" // Right arrowPlatform-Specific Accelerators
Handle platform differences for common shortcuts:
import "runtime"
// Cross-platform save shortcut
if runtime.GOOS == "darwin" {
app.KeyBinding.Add("Cmd+S", saveHandler)
} else {
app.KeyBinding.Add("Ctrl+S", saveHandler)
}
// Or register both
app.KeyBinding.Add("Ctrl+S", saveHandler)
app.KeyBinding.Add("Cmd+S", saveHandler)Managing Key Bindings
Removing Key Bindings
Remove key bindings when they’re no longer needed:
// Remove a specific key binding
app.KeyBinding.Remove("Ctrl+S")
// Example: Temporary key binding for a modal
app.KeyBinding.Add("Escape", func(window application.Window) {
// Close modal
window.EmitEvent("modal:close", nil)
// Remove this temporary binding
app.KeyBinding.Remove("Escape")
})Getting All Key Bindings
Retrieve all registered key bindings:
allBindings := app.KeyBinding.GetAll()
for _, binding := range allBindings {
app.Logger.Info("Key binding", "accelerator", binding.Accelerator)
}Advanced Usage
Context-Aware Key Bindings
Make key bindings context-aware by checking application state:
app.KeyBinding.Add("Ctrl+S", func(window application.Window) {
// Check current application state
if isEditMode() {
// Save document
saveDocument()
} else if isInSettings() {
// Save settings
saveSettings()
} else {
app.Logger.Info("Save not available in current context")
}
})Window-Specific Actions
Key bindings receive the active window, allowing window-specific behavior:
app.KeyBinding.Add("F11", func(window application.Window) {
// Toggle fullscreen for the active window
window.ToggleFullscreen()
})
app.KeyBinding.Add("Ctrl+W", func(window application.Window) {
// Close the active window
window.Close()
})Dynamic Key Binding Management
Dynamically add and remove key bindings based on application state:
func enableEditMode() {
// Add edit-specific key bindings
app.KeyBinding.Add("Ctrl+B", func(window application.Window) {
window.EmitEvent("format:bold", nil)
})
app.KeyBinding.Add("Ctrl+I", func(window application.Window) {
window.EmitEvent("format:italic", nil)
})
app.KeyBinding.Add("Ctrl+U", func(window application.Window) {
window.EmitEvent("format:underline", nil)
})
}
func disableEditMode() {
// Remove edit-specific key bindings
app.KeyBinding.Remove("Ctrl+B")
app.KeyBinding.Remove("Ctrl+I")
app.KeyBinding.Remove("Ctrl+U")
}Platform Considerations
On macOS:
- Use
Cmdinstead ofCtrlfor standard shortcuts Cmd+Qis typically reserved for quitting the applicationCmd+Hhides the applicationCmd+Mminimizes windows- Consider standard macOS keyboard shortcuts
Common macOS patterns:
app.KeyBinding.Add("Cmd+N", newFileHandler) // New
app.KeyBinding.Add("Cmd+O", openFileHandler) // Open
app.KeyBinding.Add("Cmd+S", saveFileHandler) // Save
app.KeyBinding.Add("Cmd+Z", undoHandler) // Undo
app.KeyBinding.Add("Cmd+Shift+Z", redoHandler) // Redo
app.KeyBinding.Add("Cmd+C", copyHandler) // Copy
app.KeyBinding.Add("Cmd+V", pasteHandler) // PasteOn Windows:
- Use
Ctrlfor standard shortcuts Alt+F4closes applicationsF1typically opens help- Consider Windows keyboard conventions
Common Windows patterns:
app.KeyBinding.Add("Ctrl+N", newFileHandler) // New
app.KeyBinding.Add("Ctrl+O", openFileHandler) // Open
app.KeyBinding.Add("Ctrl+S", saveFileHandler) // Save
app.KeyBinding.Add("Ctrl+Z", undoHandler) // Undo
app.KeyBinding.Add("Ctrl+Y", redoHandler) // Redo
app.KeyBinding.Add("Ctrl+C", copyHandler) // Copy
app.KeyBinding.Add("Ctrl+V", pasteHandler) // Paste
app.KeyBinding.Add("F1", helpHandler) // HelpOn Linux:
- Generally follows Windows conventions with
Ctrl - May vary by desktop environment
- Consider GNOME/KDE standard shortcuts
- Some desktop environments reserve certain shortcuts
Common Linux patterns:
app.KeyBinding.Add("Ctrl+N", newFileHandler) // New
app.KeyBinding.Add("Ctrl+O", openFileHandler) // Open
app.KeyBinding.Add("Ctrl+S", saveFileHandler) // Save
app.KeyBinding.Add("Ctrl+Z", undoHandler) // Undo
app.KeyBinding.Add("Ctrl+Shift+Z", redoHandler) // Redo
app.KeyBinding.Add("Ctrl+C", copyHandler) // Copy
app.KeyBinding.Add("Ctrl+V", pasteHandler) // PasteBest Practices
- Use Standard Shortcuts: Follow platform conventions for common operations:
// Cross-platform save
if runtime.GOOS == "darwin" {
app.KeyBinding.Add("Cmd+S", saveHandler)
} else {
app.KeyBinding.Add("Ctrl+S", saveHandler)
}- Provide Visual Feedback: Let users know when shortcuts are triggered:
app.KeyBinding.Add("Ctrl+S", func(window application.Window) {
saveDocument()
// Show brief notification
window.EmitEvent("notification:show", "Document saved")
})- Handle Conflicts: Be careful not to override important system shortcuts:
// Avoid overriding system shortcuts like:
// Ctrl+Alt+Del (Windows)
// Cmd+Space (macOS Spotlight)
// Alt+Tab (Window switching)- Document Shortcuts: Provide help or documentation for available shortcuts:
app.KeyBinding.Add("F1", func(window application.Window) {
// Show help dialog with available shortcuts
showKeyboardShortcutsHelp()
})- Clean Up: Remove temporary key bindings when they’re no longer needed:
func enterEditMode() {
app.KeyBinding.Add("Escape", exitEditModeHandler)
}
func exitEditModeHandler(window application.Window) {
exitEditMode()
app.KeyBinding.Remove("Escape") // Clean up temporary binding
}Complete Example
Here’s a complete example of a text editor with keyboard shortcuts:
package main
import (
"runtime"
"github.com/wailsapp/wails/v3/pkg/application"
)
func main() {
app := application.New(application.Options{
Name: "Text Editor with Shortcuts",
})
// File operations
if runtime.GOOS == "darwin" {
app.KeyBinding.Add("Cmd+N", func(window application.Window) {
window.EmitEvent("file:new", nil)
})
app.KeyBinding.Add("Cmd+O", func(window application.Window) {
openFile(app, window)
})
app.KeyBinding.Add("Cmd+S", func(window application.Window) {
window.EmitEvent("file:save", nil)
})
} else {
app.KeyBinding.Add("Ctrl+N", func(window application.Window) {
window.EmitEvent("file:new", nil)
})
app.KeyBinding.Add("Ctrl+O", func(window application.Window) {
openFile(app, window)
})
app.KeyBinding.Add("Ctrl+S", func(window application.Window) {
window.EmitEvent("file:save", nil)
})
}
// View operations
app.KeyBinding.Add("F11", func(window application.Window) {
window.ToggleFullscreen()
})
app.KeyBinding.Add("F1", func(window application.Window) {
showKeyboardShortcuts(window)
})
// Create main window
window := app.Window.New()
window.SetTitle("Text Editor")
err := app.Run()
if err != nil {
panic(err)
}
}
func openFile(app *application.App, window application.Window) {
dialog := app.Dialog.OpenFile()
dialog.AddFilter("Text Files", "*.txt;*.md")
if file, err := dialog.PromptForSingleSelection(); err == nil {
window.EmitEvent("file:open", file)
}
}
func showKeyboardShortcuts(window application.Window) {
shortcuts := `
Keyboard Shortcuts:
- Ctrl/Cmd+N: New file
- Ctrl/Cmd+O: Open file
- Ctrl/Cmd+S: Save file
- F11: Toggle fullscreen
- F1: Show this help
`
window.EmitEvent("help:show", shortcuts)
}