Fix: universal hotkeys using Ctrl+combinations
- All hotkeys now use Ctrl+letter (Ctrl+A, Ctrl+E, Ctrl+D, Ctrl+T, Ctrl+F, Ctrl+Q) - Works on ANY keyboard layout (EN, FR, DE, RU, etc.) - Ctrl+letter generates same control character regardless of layout - Updated help text and README Rationale: Ctrl+A always produces byte 0x01 (SOH) regardless of whether the physical key is QWERTY 'a', AZERTY 'a', or ЙЦУКЕН 'ф'. This is the standard approach used by vim, tmux, ranger, etc.
This commit is contained in:
parent
3b509d5d2e
commit
d1bb216d82
14
README.md
14
README.md
|
|
@ -82,17 +82,17 @@ sshkeeper ssh-config install-include
|
|||
sshkeeper
|
||||
```
|
||||
|
||||
Клавиши (раскладка не важна, работает и на русской):
|
||||
Клавиши (работают на любой раскладке — используются Ctrl+комбинации):
|
||||
|
||||
| Клавиша | Действие |
|
||||
|---------|----------|
|
||||
| Enter | Подключиться к серверу |
|
||||
| q / й | Выход |
|
||||
| a / ф | Добавить сервер |
|
||||
| e / у | Редактировать сервер |
|
||||
| d / в | Удалить сервер |
|
||||
| t / е | Проверить подключение |
|
||||
| / | Поиск |
|
||||
| Ctrl+A | Добавить сервер |
|
||||
| Ctrl+E | Редактировать сервер |
|
||||
| Ctrl+D | Удалить сервер |
|
||||
| Ctrl+T | Проверить подключение |
|
||||
| Ctrl+F | Поиск |
|
||||
| Ctrl+Q / Ctrl+C | Выход |
|
||||
|
||||
В форме добавления/редактирования:
|
||||
|
||||
|
|
|
|||
|
|
@ -222,35 +222,35 @@ func (m *tuiModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
return m, nil
|
||||
}
|
||||
|
||||
func matchKeys(msg tea.KeyMsg, en, ru string) bool {
|
||||
if len(msg.Runes) != 1 {
|
||||
return false
|
||||
}
|
||||
r := msg.Runes[0]
|
||||
return r == []rune(en)[0] || r == []rune(ru)[0]
|
||||
}
|
||||
|
||||
func (m *tuiModel) updateList(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
// Check key by runes (layout-independent)
|
||||
if msg.Type == tea.KeyRunes {
|
||||
switch {
|
||||
case matchKeys(msg, "q", "й"):
|
||||
switch msg.Type {
|
||||
case tea.KeyEnter:
|
||||
// Connect to selected server
|
||||
if item, ok := m.list.SelectedItem().(serverItem); ok {
|
||||
return m, func() tea.Msg {
|
||||
return connectRequestMsg{server: item.server}
|
||||
}
|
||||
}
|
||||
|
||||
case tea.KeyCtrlC, tea.KeyCtrlQ:
|
||||
return m, tea.Quit
|
||||
case matchKeys(msg, "/", "?"):
|
||||
m.screen = screenSearch
|
||||
m.searchInput.Focus()
|
||||
return m, nil
|
||||
case matchKeys(msg, "a", "ф"):
|
||||
|
||||
case tea.KeyCtrlA:
|
||||
// Add server
|
||||
m.form = newFormModel(m.width, m.height)
|
||||
m.screen = screenForm
|
||||
return m, nil
|
||||
case matchKeys(msg, "e", "у"):
|
||||
|
||||
case tea.KeyCtrlE:
|
||||
// Edit selected server
|
||||
if item, ok := m.list.SelectedItem().(serverItem); ok {
|
||||
m.form = newEditFormModel(item.server, m.width, m.height)
|
||||
m.screen = screenForm
|
||||
}
|
||||
return m, nil
|
||||
case matchKeys(msg, "d", "в"):
|
||||
|
||||
case tea.KeyCtrlD:
|
||||
// Delete selected server
|
||||
if item, ok := m.list.SelectedItem().(serverItem); ok {
|
||||
return m, func() tea.Msg {
|
||||
err := DeleteServer(item.server.Alias)
|
||||
|
|
@ -261,25 +261,22 @@ func (m *tuiModel) updateList(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
|||
return serversLoadedMsg{servers: servers, err: err}
|
||||
}
|
||||
}
|
||||
case matchKeys(msg, "t", "е"):
|
||||
|
||||
case tea.KeyCtrlT:
|
||||
// Test connection
|
||||
if item, ok := m.list.SelectedItem().(serverItem); ok {
|
||||
return m, func() tea.Msg {
|
||||
ok, testErr := TestConnection(item.server)
|
||||
return testDoneMsg{ok: ok, err: testErr}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch msg.Type {
|
||||
case tea.KeyEnter:
|
||||
if item, ok := m.list.SelectedItem().(serverItem); ok {
|
||||
return m, func() tea.Msg {
|
||||
return connectRequestMsg{server: item.server}
|
||||
}
|
||||
}
|
||||
case tea.KeyCtrlC:
|
||||
return m, tea.Quit
|
||||
case tea.KeyCtrlF, tea.KeyCtrlS:
|
||||
// Search
|
||||
m.screen = screenSearch
|
||||
m.searchInput.Focus()
|
||||
return m, nil
|
||||
|
||||
default:
|
||||
var cmd tea.Cmd
|
||||
m.list, cmd = m.list.Update(msg)
|
||||
|
|
@ -342,11 +339,11 @@ func (m *tuiModel) View() string {
|
|||
case screenList:
|
||||
b.WriteString(m.list.View())
|
||||
b.WriteString("\n")
|
||||
b.WriteString(helpStyle.Render("Enter connect | a add | e edit | d delete | t test | / search | q quit"))
|
||||
b.WriteString(helpStyle.Render("Enter connect | Ctrl+A add | Ctrl+E edit | Ctrl+D del | Ctrl+T test | Ctrl+F search | Ctrl+Q quit"))
|
||||
|
||||
case screenSearch:
|
||||
b.WriteString("Search: " + m.searchInput.View() + "\n")
|
||||
b.WriteString(helpStyle.Render("Enter search | Esc cancel"))
|
||||
b.WriteString(helpStyle.Render("Type to search | Enter confirm | Esc cancel"))
|
||||
|
||||
case screenForm:
|
||||
b.WriteString(m.form.View())
|
||||
|
|
|
|||
Loading…
Reference in New Issue