Files
amethyst/.claude/skills/desktop-expert/references/keyboard-shortcuts.md
T
Claude 60edd473c7 Refreshes .claude/ skill library: fixes stale refs, adds 4 new skills
- Updates CLAUDE.md tech stack to current versions (Compose 1.10.3, Kotlin 2.3.20).
- Reframes kotlin-multiplatform iOS as mature; adds secp256k1-kmp 0.23.0 references.
- Updates desktop-expert Main.kt references (code grew from ~270 to 1341 lines and
  NavigationRail moved to ui/deck/SinglePaneLayout.kt); replaces obsolete
  "hardcoded ctrl = true" anti-pattern note with accurate isMacOS branching.
- Removes compose-desktop.md (superseded by desktop-expert/).
- Adds nostr-expert references: nip19-bech32, event-factory, crypto-and-encryption,
  large-cache. Adds kotlin-expert/common-utilities, compose-expert/rich-text-parsing,
  android-expert/image-loading.
- New skills: account-state (Account + LocalCache), relay-client (subscriptions,
  filter assemblers, preloaders), feed-patterns (FeedFilter + FeedViewModel family),
  auth-signers (NostrSigner across internal / NIP-46 / NIP-55).
2026-04-21 21:00:45 +00:00

401 lines
11 KiB
Markdown

# Keyboard Shortcuts Reference
Standard keyboard shortcuts for desktop applications across macOS, Windows, and Linux.
## Primary Modifier Keys
| Platform | Primary | Secondary | Tertiary |
|----------|---------|-----------|----------|
| **macOS** | Cmd (⌘) / `meta` | Option (⌥) / `alt` | Ctrl (⌃) / `ctrl` |
| **Windows** | Ctrl / `ctrl` | Alt / `alt` | Win / `meta` |
| **Linux** | Ctrl / `ctrl` | Alt / `alt` | Super / `meta` |
**In Compose Desktop:**
```kotlin
// macOS
KeyShortcut(Key.N, meta = true) // Cmd+N
// Windows/Linux
KeyShortcut(Key.N, ctrl = true) // Ctrl+N
```
---
## File Operations
| Action | macOS | Windows | Linux | Notes |
|--------|-------|---------|-------|-------|
| **New** | Cmd+N | Ctrl+N | Ctrl+N | Create new |
| **Open** | Cmd+O | Ctrl+O | Ctrl+O | Open file |
| **Save** | Cmd+S | Ctrl+S | Ctrl+S | Save current |
| **Save As** | Cmd+Shift+S | Ctrl+Shift+S | Ctrl+Shift+S | Save with new name |
| **Close** | Cmd+W | Ctrl+W | Ctrl+W | Close window/tab |
| **Quit** | Cmd+Q | Ctrl+Q | Ctrl+Q | Exit app |
| **Print** | Cmd+P | Ctrl+P | Ctrl+P | Print |
**Compose Implementation:**
```kotlin
val isMacOS = System.getProperty("os.name").lowercase().contains("mac")
MenuBar {
Menu("File") {
Item(
"New Note",
shortcut = if (isMacOS) {
KeyShortcut(Key.N, meta = true)
} else {
KeyShortcut(Key.N, ctrl = true)
},
onClick = { createNewNote() }
)
Item(
"Save",
shortcut = if (isMacOS) {
KeyShortcut(Key.S, meta = true)
} else {
KeyShortcut(Key.S, ctrl = true)
},
onClick = { save() }
)
Separator()
Item(
"Quit",
shortcut = if (isMacOS) {
KeyShortcut(Key.Q, meta = true)
} else {
KeyShortcut(Key.Q, ctrl = true)
},
onClick = ::exitApplication
)
}
}
```
---
## Edit Operations
| Action | macOS | Windows | Linux | Notes |
|--------|-------|---------|-------|-------|
| **Undo** | Cmd+Z | Ctrl+Z | Ctrl+Z | Universal |
| **Redo** | Cmd+Shift+Z | Ctrl+Y | Ctrl+Y | Windows/Linux use Y |
| **Cut** | Cmd+X | Ctrl+X | Ctrl+X | Universal |
| **Copy** | Cmd+C | Ctrl+C | Ctrl+C | Universal |
| **Paste** | Cmd+V | Ctrl+V | Ctrl+V | Universal |
| **Select All** | Cmd+A | Ctrl+A | Ctrl+A | Universal |
| **Find** | Cmd+F | Ctrl+F | Ctrl+F | Search |
| **Find Next** | Cmd+G | F3 | F3 | Next result |
| **Replace** | Cmd+Option+F | Ctrl+H | Ctrl+H | Find & replace |
**Note:** Undo/Redo typically handled by text fields automatically.
---
## Navigation
| Action | macOS | Windows | Linux | Notes |
|--------|-------|---------|-------|-------|
| **Tab 1** | Cmd+1 | Ctrl+1 | Ctrl+1 | First tab/view |
| **Tab 2** | Cmd+2 | Ctrl+2 | Ctrl+2 | Second tab/view |
| **Tab 3** | Cmd+3 | Ctrl+3 | Ctrl+3 | Third tab/view |
| **Next Tab** | Cmd+Option+→ | Ctrl+Tab | Ctrl+Tab | Cycle forward |
| **Prev Tab** | Cmd+Option+← | Ctrl+Shift+Tab | Ctrl+Shift+Tab | Cycle back |
| **Go Back** | Cmd+[ | Alt+← | Alt+← | Browser-style |
| **Go Forward** | Cmd+] | Alt+→ | Alt+→ | Browser-style |
**Compose Implementation:**
```kotlin
Window(
onPreviewKeyEvent = { event ->
if (event.type == KeyEventType.KeyDown) {
when {
event.key == Key.One && event.isPrimaryPressed() -> {
navigateTo(AppScreen.Feed)
true
}
event.key == Key.Two && event.isPrimaryPressed() -> {
navigateTo(AppScreen.Search)
true
}
event.key == Key.Three && event.isPrimaryPressed() -> {
navigateTo(AppScreen.Messages)
true
}
else -> false
}
} else false
}
) {
// Content
}
// Helper extension
fun KeyEvent.isPrimaryPressed() = if (isMacOS) isMetaPressed else isCtrlPressed
```
---
## Window Management
| Action | macOS | Windows | Linux | Notes |
|--------|-------|---------|-------|-------|
| **New Window** | Cmd+N | Ctrl+N | Ctrl+N | New instance |
| **Close Window** | Cmd+W | Alt+F4 | Alt+F4 | Close current |
| **Minimize** | Cmd+M | Win+Down | Super+Down | Minimize to dock/taskbar |
| **Maximize** | Cmd+Ctrl+F | Win+Up | Super+Up | Fullscreen/maximize |
| **Hide App** | Cmd+H | - | - | macOS only |
| **Switch Window** | Cmd+` | Alt+Tab | Alt+Tab | Between app windows |
**Note:** Window management often handled by OS, not app shortcuts.
---
## App-Specific (Amethyst)
### Nostr Actions
| Action | macOS | Windows | Linux | Description |
|--------|-------|---------|-------|-------------|
| **New Note** | Cmd+N | Ctrl+N | Ctrl+N | Compose new post |
| **Refresh Feed** | Cmd+R | Ctrl+R | Ctrl+R | Reload timeline |
| **Search** | Cmd+K | Ctrl+K | Ctrl+K | Quick search |
| **DMs** | Cmd+Shift+M | Ctrl+Shift+M | Ctrl+Shift+M | Open messages |
| **Settings** | Cmd+, | Ctrl+, | Ctrl+, | Open preferences |
| **Notifications** | Cmd+Shift+N | Ctrl+Shift+N | Ctrl+Shift+N | View alerts |
**Implementation:**
```kotlin
MenuBar {
Menu("File") {
Item(
"New Note",
shortcut = DesktopShortcuts.primary(Key.N),
onClick = { showComposeDialog() }
)
Item(
"Settings",
shortcut = DesktopShortcuts.primary(Key.Comma),
onClick = { navigateTo(AppScreen.Settings) }
)
}
Menu("View") {
Item(
"Refresh Feed",
shortcut = DesktopShortcuts.primary(Key.R),
onClick = { refreshFeed() }
)
Item(
"Search",
shortcut = DesktopShortcuts.primary(Key.K),
onClick = { focusSearch() }
)
}
}
```
---
## Accessibility
| Action | macOS | Windows | Linux | Description |
|--------|-------|---------|-------|-------------|
| **Zoom In** | Cmd++ | Ctrl++ | Ctrl++ | Increase size |
| **Zoom Out** | Cmd+- | Ctrl+- | Ctrl+- | Decrease size |
| **Reset Zoom** | Cmd+0 | Ctrl+0 | Ctrl+0 | Default size |
| **Help** | Cmd+? | F1 | F1 | Show help |
---
## Best Practices
### 1. OS-Aware Helper
Create a utility for OS detection:
```kotlin
// commons/src/jvmMain/kotlin/utils/PlatformShortcuts.kt
object DesktopShortcuts {
private val isMacOS = System.getProperty("os.name")
.lowercase()
.contains("mac")
fun primary(key: Key) = if (isMacOS) {
KeyShortcut(key, meta = true)
} else {
KeyShortcut(key, ctrl = true)
}
fun primaryShift(key: Key) = if (isMacOS) {
KeyShortcut(key, meta = true, shift = true)
} else {
KeyShortcut(key, ctrl = true, shift = true)
}
fun primaryAlt(key: Key) = if (isMacOS) {
KeyShortcut(key, meta = true, alt = true)
} else {
KeyShortcut(key, ctrl = true, alt = true)
}
val modifierName = if (isMacOS) "Cmd" else "Ctrl"
val secondaryName = if (isMacOS) "Option" else "Alt"
}
```
**Usage:**
```kotlin
Item(
"Save",
shortcut = DesktopShortcuts.primary(Key.S),
onClick = { save() }
)
```
### 2. Show Shortcuts in Tooltips
```kotlin
IconButton(
onClick = { refresh() },
modifier = Modifier.tooltipArea {
Text("Refresh (${DesktopShortcuts.modifierName}+R)")
}
) {
Icon(Icons.Default.Refresh, "Refresh")
}
```
### 3. Shortcuts Menu
Provide a "Keyboard Shortcuts" help menu:
```kotlin
Menu("Help") {
Item("Keyboard Shortcuts", onClick = { showShortcutsDialog() })
}
// Dialog content
@Composable
fun ShortcutsDialog() {
Dialog(onDismissRequest = { /* close */ }) {
Surface {
Column(Modifier.padding(16.dp)) {
Text("Keyboard Shortcuts", style = MaterialTheme.typography.headlineMedium)
Spacer(Modifier.height(16.dp))
ShortcutRow("New Note", "${DesktopShortcuts.modifierName}+N")
ShortcutRow("Save", "${DesktopShortcuts.modifierName}+S")
ShortcutRow("Search", "${DesktopShortcuts.modifierName}+K")
ShortcutRow("Settings", "${DesktopShortcuts.modifierName}+,")
// ...
}
}
}
}
@Composable
fun ShortcutRow(action: String, shortcut: String) {
Row(
Modifier.fillMaxWidth().padding(vertical = 4.dp),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(action, style = MaterialTheme.typography.bodyMedium)
Text(
shortcut,
style = MaterialTheme.typography.bodySmall,
fontFamily = FontFamily.Monospace,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
```
### 4. Avoid Conflicts
**Check for OS-level shortcuts:**
| macOS Reserved | Description |
|----------------|-------------|
| Cmd+Tab | Switch apps |
| Cmd+Space | Spotlight |
| Cmd+H | Hide window |
| Cmd+M | Minimize |
| Cmd+Q | Quit |
| Cmd+W | Close window |
**Windows Reserved:**
| Windows Reserved | Description |
|-----------------|-------------|
| Win+D | Show desktop |
| Win+E | File Explorer |
| Win+L | Lock screen |
| Alt+Tab | Switch apps |
| Alt+F4 | Close window |
**Don't override these unless critical.**
---
## Testing Shortcuts
```kotlin
// Test OS detection
@Test
fun testOsDetection() {
val osName = System.getProperty("os.name")
println("OS: $osName")
val isMacOS = osName.lowercase().contains("mac")
println("Is macOS: $isMacOS")
val shortcut = if (isMacOS) {
KeyShortcut(Key.N, meta = true)
} else {
KeyShortcut(Key.N, ctrl = true)
}
println("Primary modifier for New: $shortcut")
}
```
---
## Current Pattern in Amethyst
`Main.kt` (MenuBar starting at L234) already branches on `isMacOS` (L120) for every shortcut. When adding a new menu item, follow the same pattern — **do not** hardcode `ctrl = true`:
```kotlin
// ❌ WRONG: Hardcoded Ctrl (doesn't work on macOS)
Item(
"New Note",
shortcut = KeyShortcut(Key.N, ctrl = true), // Should be Cmd on macOS
onClick = { /* ... */ }
)
```
**Current pattern (what Main.kt does):**
```kotlin
// ✅ CORRECT: OS-aware
Item(
"New Note",
shortcut = DesktopShortcuts.primary(Key.N),
onClick = { /* ... */ }
)
```
---
## References
- [macOS Keyboard Shortcuts](https://support.apple.com/en-us/102650)
- [Windows Keyboard Shortcuts](https://support.microsoft.com/en-us/windows/keyboard-shortcuts-in-windows-dcc61a57-8ff0-cffe-9796-cb9706c75eec)
- [GNOME Keyboard Shortcuts](https://help.gnome.org/users/gnome-help/stable/shell-keyboard-shortcuts.html)
- [Material Design: Keyboard Shortcuts](https://m3.material.io/foundations/interaction/keyboard)
- [Compose Desktop: Keyboard Events](https://www.jetbrains.com/help/kotlin-multiplatform-dev/compose-desktop-keyboard.html)