diff --git a/README.md b/README.md index c7d7d2c..72b6090 100644 --- a/README.md +++ b/README.md @@ -161,14 +161,30 @@ Switch pop out window. ### Customize key map +You can overwrite the following key + +- `translate`: Translate from source to destination window. +- `swap_language`: Swap language. +- `clear`: Clear all text in source of translation window. +- `copy_selected`: Copy selected text. +- `copy_source`: Copy all text in source of translation window. +- `copy_destination`: Copy all text in destination of translation window. +- `tts_source`: Play text to speech on source of translation window. +- `tts_destination`: Play text to speech on destination of translation window. +- `stop_tts`: Stop playing text to speech. +- `toggle_transparent`: Toggle transparent. +- `toggle_below`: Toggle Definition/Example & Part of speech. + +For key to combine with `Ctrl`, the value can be `"C-space"`, `"C-\\"`, `"C-]"`, `"C-^"`, `"C-_"` or `"C-a"` to `"C-z"`. + +⚠️ Note, don't use `"C-c"`, `` is for exit program. + +For key to combine with `Alt`, the value can be `"A-space"` or `"A-"` + the character you want. + +Or you can use function key, the value can be `"F1"` to `"F64"`. + See the example in [keymap.yaml](example/keymap.yaml) file. This file should located at `$XDG_CONFIG_HOME/gtt/keymap.yaml` or `$HOME/.config/gtt/keymap.yaml`. -For key to combine with `Ctrl`, value can be `" "` (Space), `"\\"` or `'\'` (backslash), `"]"`, `"^"`, `"_"`, `"a"` to `"z"` (lower case). - -Or the function key, value can be `"F1"` to `"F64"`. - -⚠️ Note, don't use `"c"`, `` is for exit program. - ## Credit [soimort/translate-shell](https://github.com/soimort/translate-shell), diff --git a/config.go b/config.go index 99bf146..2920723 100644 --- a/config.go +++ b/config.go @@ -6,7 +6,6 @@ import ( "github.com/eeeXun/gtt/internal/style" "github.com/eeeXun/gtt/internal/translate" - "github.com/eeeXun/gtt/internal/ui" config "github.com/spf13/viper" ) @@ -17,17 +16,17 @@ func configInit() { themeConfig = config.New() keyMapConfig = config.New() defaultKeyMaps = map[string]string{ - "translate": "j", - "swap_language": "s", - "clear": "q", - "copy_selected": "y", - "copy_source": "g", - "copy_destination": "r", - "tts_source": "o", - "tts_destination": "p", - "stop_tts": "x", - "toggle_transparent": "t", - "toggle_below": "\\", + "translate": "C-j", + "swap_language": "C-s", + "clear": "C-q", + "copy_selected": "C-y", + "copy_source": "C-g", + "copy_destination": "C-r", + "tts_source": "C-o", + "tts_destination": "C-p", + "stop_tts": "C-x", + "toggle_transparent": "C-t", + "toggle_below": "C-\\", } defaultConfig = map[string]interface{}{ "hide_below": false, @@ -123,14 +122,14 @@ func configInit() { if err := keyMapConfig.ReadInConfig(); err == nil { for action, key := range defaultKeyMaps { if keyMapConfig.Get(action) == nil { - keyMaps[action] = ui.NewKeyData(key) + keyMaps[action] = key } else { - keyMaps[action] = ui.NewKeyData(keyMapConfig.GetString(action)) + keyMaps[action] = keyMapConfig.GetString(action) } } } else { for action, key := range defaultKeyMaps { - keyMaps[action] = ui.NewKeyData(key) + keyMaps[action] = key } } // Setup diff --git a/example/keymap.yaml b/example/keymap.yaml index aadf248..63c6cba 100644 --- a/example/keymap.yaml +++ b/example/keymap.yaml @@ -1,27 +1,34 @@ -# This file should located at $XDG_CONFIG_HOME/gtt/keymap.yaml or $HOME/.config/gtt/keymap.yaml -# For key to combine with Ctrl, value can be " " (Space), "\\" or '\' (backslash), "]", "^", "_", "a" to "z" (lower case) -# ⚠️ Note, don't use "c", is for exit program -# Or the function key, value can be "F1" to "F64" +# This file should located at $XDG_CONFIG_HOME/gtt/keymap.yaml or $HOME/.config/gtt/keymap.yaml. -# Translate, -translate: "j" +# For key to combine with Ctrl, the value can be "C-space", "C-\\", "C-]", "C-^", "C-_" or "C-a" to "C-z". +# ⚠️ Note, don't use "C-c", is for exit program. + +# For key to combine with Alt, the value can be "A-space" or "A-" + the character you want. + +# Or you can use function key, the value can be "F1" to "F64". + + +# The following is the default key map + +# Translate from source to destination window, +translate: "C-j" # Swap language, -swap_language: "s" +swap_language: "C-s" # Clear all text in source of translation window, -clear: "q" +clear: "C-q" # Copy selected text, -copy_selected: "y" +copy_selected: "C-y" # Copy all text in source of translation window, -copy_source: "g" +copy_source: "C-g" # Copy all text in destination of translation window, -copy_destination: "r" +copy_destination: "C-r" # Play text to speech on source of translation window, -tts_source: "o" +tts_source: "C-o" # Play text to speech on destination of translation window, -tts_destination: "p" +tts_destination: "C-p" # Stop playing text to speech, -stop_tts: "x" +stop_tts: "C-x" # Toggle transparent, -toggle_transparent: "t" +toggle_transparent: "C-t" # Toggle Definition/Example & Part of speech, -toggle_below: "\\" +toggle_below: "C-\\" diff --git a/example/theme.yaml b/example/theme.yaml index 154c394..f8eafcf 100644 --- a/example/theme.yaml +++ b/example/theme.yaml @@ -1,6 +1,6 @@ -# This file should located at $XDG_CONFIG_HOME/gtt/theme.yaml or $HOME/.config/gtt/theme.yaml -# You have to provide theme name. e.g. tokyonight -# And colors: bg, fg, gray, red, green, yellow, blue, purple, cyan, orange +# This file should located at $XDG_CONFIG_HOME/gtt/theme.yaml or $HOME/.config/gtt/theme.yaml. +# You have to provide theme name. e.g. tokyonight. +# And colors: bg, fg, gray, red, green, yellow, blue, purple, cyan, orange. # bg is for background color # fg is for foreground color # gray is for selected color diff --git a/internal/ui/key.go b/internal/ui/key.go deleted file mode 100644 index 35f7468..0000000 --- a/internal/ui/key.go +++ /dev/null @@ -1,66 +0,0 @@ -package ui - -import ( - "strconv" - - "github.com/gdamore/tcell/v2" -) - -type keyData struct { - name string - key tcell.Key -} - -type KeyMaps map[string]keyData - -func NewKeyData(keyStr string) keyData { - var ( - name string - key tcell.Key - ) - - if len(keyStr) > 1 && keyStr[0] == 'F' { - // function key, can be F1 to F64 - name = keyStr - fNum, err := strconv.Atoi(keyStr[1:]) - if err != nil { - panic(err) - } - key = tcell.KeyF1 + tcell.Key(fNum-1) - } else { - switch keyStr[0] { - case ' ': - name = "C-Space" - key = tcell.KeyCtrlSpace - case '\\': - name = "C-\\" - key = tcell.KeyCtrlBackslash - case ']': - name = "C-]" - key = tcell.KeyCtrlRightSq - case '^': - name = "C-^" - key = tcell.KeyCtrlCarat - case '_': - name = "C-_" - key = tcell.KeyCtrlUnderscore - default: - // This should be a to z - name = "C-" + keyStr - key = tcell.KeyCtrlA + tcell.Key(keyStr[0]-'a') - } - } - - return keyData{ - name: name, - key: key, - } -} - -func (k keyData) GetName() string { - return k.name -} - -func (k keyData) GetKey() tcell.Key { - return k.key -} diff --git a/key.go b/key.go new file mode 100644 index 0000000..0330faa --- /dev/null +++ b/key.go @@ -0,0 +1,121 @@ +package main + +import ( + "github.com/gdamore/tcell/v2" +) + +var keyNames = map[tcell.Key]string{ + tcell.KeyEsc: "Esc", + tcell.KeyF1: "F1", + tcell.KeyF2: "F2", + tcell.KeyF3: "F3", + tcell.KeyF4: "F4", + tcell.KeyF5: "F5", + tcell.KeyF6: "F6", + tcell.KeyF7: "F7", + tcell.KeyF8: "F8", + tcell.KeyF9: "F9", + tcell.KeyF10: "F10", + tcell.KeyF11: "F11", + tcell.KeyF12: "F12", + tcell.KeyF13: "F13", + tcell.KeyF14: "F14", + tcell.KeyF15: "F15", + tcell.KeyF16: "F16", + tcell.KeyF17: "F17", + tcell.KeyF18: "F18", + tcell.KeyF19: "F19", + tcell.KeyF20: "F20", + tcell.KeyF21: "F21", + tcell.KeyF22: "F22", + tcell.KeyF23: "F23", + tcell.KeyF24: "F24", + tcell.KeyF25: "F25", + tcell.KeyF26: "F26", + tcell.KeyF27: "F27", + tcell.KeyF28: "F28", + tcell.KeyF29: "F29", + tcell.KeyF30: "F30", + tcell.KeyF31: "F31", + tcell.KeyF32: "F32", + tcell.KeyF33: "F33", + tcell.KeyF34: "F34", + tcell.KeyF35: "F35", + tcell.KeyF36: "F36", + tcell.KeyF37: "F37", + tcell.KeyF38: "F38", + tcell.KeyF39: "F39", + tcell.KeyF40: "F40", + tcell.KeyF41: "F41", + tcell.KeyF42: "F42", + tcell.KeyF43: "F43", + tcell.KeyF44: "F44", + tcell.KeyF45: "F45", + tcell.KeyF46: "F46", + tcell.KeyF47: "F47", + tcell.KeyF48: "F48", + tcell.KeyF49: "F49", + tcell.KeyF50: "F50", + tcell.KeyF51: "F51", + tcell.KeyF52: "F52", + tcell.KeyF53: "F53", + tcell.KeyF54: "F54", + tcell.KeyF55: "F55", + tcell.KeyF56: "F56", + tcell.KeyF57: "F57", + tcell.KeyF58: "F58", + tcell.KeyF59: "F59", + tcell.KeyF60: "F60", + tcell.KeyF61: "F61", + tcell.KeyF62: "F62", + tcell.KeyF63: "F63", + tcell.KeyF64: "F64", + tcell.KeyCtrlA: "C-a", + tcell.KeyCtrlB: "C-b", + tcell.KeyCtrlC: "C-c", + tcell.KeyCtrlD: "C-d", + tcell.KeyCtrlE: "C-e", + tcell.KeyCtrlF: "C-f", + tcell.KeyCtrlG: "C-g", + tcell.KeyCtrlJ: "C-j", + tcell.KeyCtrlK: "C-k", + tcell.KeyCtrlL: "C-l", + tcell.KeyCtrlN: "C-n", + tcell.KeyCtrlO: "C-o", + tcell.KeyCtrlP: "C-p", + tcell.KeyCtrlQ: "C-q", + tcell.KeyCtrlR: "C-r", + tcell.KeyCtrlS: "C-s", + tcell.KeyCtrlT: "C-t", + tcell.KeyCtrlU: "C-u", + tcell.KeyCtrlV: "C-v", + tcell.KeyCtrlW: "C-w", + tcell.KeyCtrlX: "C-x", + tcell.KeyCtrlY: "C-y", + tcell.KeyCtrlZ: "C-z", + tcell.KeyCtrlSpace: "C-space", + tcell.KeyCtrlUnderscore: "C-_", + tcell.KeyCtrlRightSq: "C-]", + tcell.KeyCtrlBackslash: "C-\\", + tcell.KeyCtrlCarat: "C-^", +} + +func getKeyName(event *tcell.EventKey) string { + var keyName string + key := event.Key() + + if key == tcell.KeyRune { + if event.Modifiers() == tcell.ModAlt { + switch event.Rune() { + case ' ': + keyName = "A-space" + default: + keyName = "A-" + string(event.Rune()) + } + } + } else { + keyName = keyNames[key] + } + + return keyName +} diff --git a/main.go b/main.go index 9ba98ea..06d96d0 100644 --- a/main.go +++ b/main.go @@ -21,7 +21,7 @@ var ( // UI style uiStyle = style.NewStyle() // keyMaps - keyMaps = make(ui.KeyMaps) + keyMaps = make(map[string]string) // UI app = tview.NewApplication() srcInput = tview.NewTextArea() diff --git a/ui.go b/ui.go index 5b4bfa0..34d90c6 100644 --- a/ui.go +++ b/ui.go @@ -10,6 +10,13 @@ import ( "github.com/rivo/tview" ) +type Item struct { + item tview.Primitive + fixedSize int + proportion int + focus bool +} + const ( popOutWindowHeight int = 20 langStrMaxLength int = 32 @@ -45,13 +52,6 @@ const ( Switch pop out window.` ) -type Item struct { - item tview.Primitive - fixedSize int - proportion int - focus bool -} - func updateTranslateWindow() { if uiStyle.HideBelow { translateWindow.RemoveItem(translateBelowWidget) @@ -165,17 +165,17 @@ func updateNonConfigColor() { keyMapMenu.SetTextColor(uiStyle.ForegroundColor()). SetText(fmt.Sprintf(keyMapText, fmt.Sprintf("%.6x", uiStyle.HighLightColor().TrueColor().Hex()), - keyMaps["translate"].GetName(), - keyMaps["swap_language"].GetName(), - keyMaps["clear"].GetName(), - keyMaps["copy_selected"].GetName(), - keyMaps["copy_src"].GetName(), - keyMaps["copy_dst"].GetName(), - keyMaps["tts_src"].GetName(), - keyMaps["tts_dst"].GetName(), - keyMaps["stop_tts"].GetName(), - keyMaps["toggle_transparent"].GetName(), - keyMaps["toggle_below"].GetName(), + keyMaps["translate"], + keyMaps["swap_language"], + keyMaps["clear"], + keyMaps["copy_selected"], + keyMaps["copy_source"], + keyMaps["copy_destination"], + keyMaps["tts_source"], + keyMaps["tts_destination"], + keyMaps["stop_tts"], + keyMaps["toggle_transparent"], + keyMaps["toggle_below"], )). SetBorderColor(uiStyle.HighLightColor()). SetTitleColor(uiStyle.HighLightColor()) @@ -373,9 +373,14 @@ func uiInit() { // https://github.com/golang/go/discussions/56010 widget := widget widget.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { - key := event.Key() - switch key { - case keyMaps["copy_selected"].GetKey(): + keyName := getKeyName(event) + + if len(keyName) == 0 { + return event + } + + switch keyName { + case keyMaps["copy_selected"]: // copy selected text text, _, _ := widget.GetSelection() @@ -437,10 +442,14 @@ func uiInit() { } func mainPageHandler(event *tcell.EventKey) *tcell.EventKey { - key := event.Key() + keyName := getKeyName(event) - switch key { - case keyMaps["toggle_transparent"].GetKey(): + if len(keyName) == 0 { + return event + } + + switch keyName { + case keyMaps["toggle_transparent"]: // Toggle transparent uiStyle.Transparent = !uiStyle.Transparent // The following will trigger transparentDropDown SetDoneFunc @@ -448,7 +457,7 @@ func mainPageHandler(event *tcell.EventKey) *tcell.EventKey { IndexOf(strconv.FormatBool(uiStyle.Transparent), []string{"true", "false"})) return nil - case keyMaps["toggle_below"].GetKey(): + case keyMaps["toggle_below"]: // Toggle Hide below window uiStyle.HideBelow = !uiStyle.HideBelow // The following will trigger hideBelowDropDown SetDoneFunc @@ -462,14 +471,14 @@ func mainPageHandler(event *tcell.EventKey) *tcell.EventKey { } func translateWindowHandler(event *tcell.EventKey) *tcell.EventKey { - key := event.Key() + keyName := getKeyName(event) - switch key { - case tcell.KeyEsc: + switch keyName { + case "Esc": mainPage.ShowPage("langPopOut") app.SetFocus(langCycle.GetCurrentUI()) return nil - case keyMaps["translate"].GetKey(): + case keyMaps["translate"]: message := srcInput.GetText() // Only translate when message exist if len(message) > 0 { @@ -483,10 +492,10 @@ func translateWindowHandler(event *tcell.EventKey) *tcell.EventKey { } } return nil - case keyMaps["clear"].GetKey(): + case keyMaps["clear"]: srcInput.SetText("", true) return nil - case keyMaps["copy_src"].GetKey(): + case keyMaps["copy_source"]: // copy all text in Input text := srcInput.GetText() @@ -495,7 +504,7 @@ func translateWindowHandler(event *tcell.EventKey) *tcell.EventKey { CopyToClipboard(text) } return nil - case keyMaps["copy_dst"].GetKey(): + case keyMaps["copy_destination"]: // copy all text in Output text := dstOutput.GetText(false) @@ -504,7 +513,7 @@ func translateWindowHandler(event *tcell.EventKey) *tcell.EventKey { CopyToClipboard(text[:len(text)-1]) } return nil - case keyMaps["swap_language"].GetKey(): + case keyMaps["swap_language"]: translator.SwapLang() updateCurrentLang() srcText := srcInput.GetText() @@ -517,7 +526,7 @@ func translateWindowHandler(event *tcell.EventKey) *tcell.EventKey { } dstOutput.SetText(srcText) return nil - case keyMaps["tts_src"].GetKey(): + case keyMaps["tts_source"]: // Play text to speech on source of translation window. if translator.LockAvailable() { message := srcInput.GetText() @@ -535,7 +544,7 @@ func translateWindowHandler(event *tcell.EventKey) *tcell.EventKey { } return nil - case keyMaps["tts_dst"].GetKey(): + case keyMaps["tts_destination"]: // Play text to speech on destination of translation window. if translator.LockAvailable() { message := dstOutput.GetText(false) @@ -552,7 +561,7 @@ func translateWindowHandler(event *tcell.EventKey) *tcell.EventKey { } } return nil - case keyMaps["stop_tts"].GetKey(): + case keyMaps["stop_tts"]: // Stop play sound translator.StopTTS() return nil