diff --git a/.config/ags/modules/.widgetutils/keybind.js b/.config/ags/modules/.widgetutils/keybind.js new file mode 100644 index 000000000..f3d723a93 --- /dev/null +++ b/.config/ags/modules/.widgetutils/keybind.js @@ -0,0 +1,26 @@ +const { Gdk } = imports.gi; + +const MODS = { + 'NoMod': Gdk.ModifierType.NO_MODIFIER_MASK, + 'Shift': Gdk.ModifierType.SHIFT_MASK, + 'Ctrl': Gdk.ModifierType.CONTROL_MASK, + 'Alt': Gdk.ModifierType.ALT_MASK, + 'Hyper': Gdk.ModifierType.HYPER_MASK, + 'Meta': Gdk.ModifierType.META_MASK +} + +export const checkKeybind = (event, keybind) => { + const pressedModMask = event.get_state()[1]; + const pressedKey = event.get_keyval()[1]; + const keys = keybind.split('+'); + for (let i = 0; i < keys.length; i++) { + if (keys[i] in MODS) { + if (!(pressedModMask & MODS[keys[i]])) { + return false; + } + } else if (pressedKey !== Gdk[`KEY_${keys[i]}`]) { + return false; + } + } + return true; +} diff --git a/.config/ags/modules/overview/windowcontent.js b/.config/ags/modules/overview/windowcontent.js index 3486c1fe7..675464d01 100644 --- a/.config/ags/modules/overview/windowcontent.js +++ b/.config/ags/modules/overview/windowcontent.js @@ -10,6 +10,7 @@ import { CalculationResultButton, CustomCommandButton, DirectoryButton, DesktopEntryButton, ExecuteCommandButton, SearchButton } from './searchbuttons.js'; +import { checkKeybind } from '../.widgetutils/keybind.js'; // Add math funcs const { abs, sin, cos, tan, cot, asin, acos, atan, acot } = Math; @@ -237,24 +238,18 @@ export const SearchAndWindows = () => { .on('key-press-event', (widget, event) => { // Typing const keyval = event.get_keyval()[1]; const modstate = event.get_state()[1]; - if (modstate & Gdk.ModifierType.CONTROL_MASK) { // Ctrl held - if (keyval == Gdk.KEY_b) - entry.set_position(Math.max(entry.get_position() - 1, 0)); - else if (keyval == Gdk.KEY_f) - entry.set_position(Math.min(entry.get_position() + 1, entry.get_text().length)); - else if (keyval == Gdk.KEY_n) { // simulate Down arrow - entry.get_root_window().simulate_key_press(Gdk.KEY_Down, Gdk.ModifierType.NONE); - // entry.get_root_window().simulate_key_release(Gdk.KEY_Down, Gdk.ModifierType.NONE); - } - else if (keyval == Gdk.KEY_k) { // Delete to end - const text = entry.get_text(); - const pos = entry.get_position(); - const newText = text.slice(0, pos); - entry.set_text(newText); - entry.set_position(newText.length); - } + if (checkKeybind(event, userOptions.keybinds.overview.altMoveLeft)) + entry.set_position(Math.max(entry.get_position() - 1, 0)); + else if (checkKeybind(event, userOptions.keybinds.overview.altMoveRight)) + entry.set_position(Math.min(entry.get_position() + 1, entry.get_text().length)); + else if (checkKeybind(event, userOptions.keybinds.overview.deleteToEnd)) { + const text = entry.get_text(); + const pos = entry.get_position(); + const newText = text.slice(0, pos); + entry.set_text(newText); + entry.set_position(newText.length); } - else { // Ctrl not held + else if (!(modstate & Gdk.ModifierType.CONTROL_MASK)) { // Ctrl not held if (keyval >= 32 && keyval <= 126 && widget != entry) { Utils.timeout(1, () => entry.grab_focus()); entry.set_text(entry.text + String.fromCharCode(keyval)); diff --git a/.config/ags/modules/sideleft/apiwidgets.js b/.config/ags/modules/sideleft/apiwidgets.js index dfa4ca2c8..b75b9ed9c 100644 --- a/.config/ags/modules/sideleft/apiwidgets.js +++ b/.config/ags/modules/sideleft/apiwidgets.js @@ -12,6 +12,7 @@ import { chatGPTView, chatGPTCommands, sendMessage as chatGPTSendMessage, chatGP import { waifuView, waifuCommands, sendMessage as waifuSendMessage, waifuTabIcon } from './apis/waifu.js'; import { booruView, booruCommands, sendMessage as booruSendMessage, booruTabIcon } from './apis/booru.js'; import { enableClickthrough } from "../.widgetutils/clickthrough.js"; +import { checkKeybind } from '../.widgetutils/keybind.js'; const TextView = Widget.subclass(Gtk.TextView, "AgsTextView"); import { widgetContent } from './sideleft.js'; @@ -83,31 +84,25 @@ export const chatEntry = TextView({ self.placeholderText = (Gemini.key.length > 0 ? 'Message Gemini...' : 'Enter Google AI API Key...'); }, 'hasKey') .on("key-press-event", (widget, event) => { - const keyval = event.get_keyval()[1]; + // Don't send when Shift+Enter if (event.get_keyval()[1] === Gdk.KEY_Return && event.get_state()[1] == Gdk.ModifierType.MOD2_MASK) { apiSendMessage(widget); return true; } // Keybinds - if (!(event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK)) { - if (event.get_keyval()[1] === Gdk.KEY_Page_Down) { - apiWidgets.attribute.nextTab(); - return true; - } - else if (event.get_keyval()[1] === Gdk.KEY_Page_Up) { - apiWidgets.attribute.prevTab(); - return true; - } + if (checkKeybind(event, userOptions.keybinds.sidebar.cycleTab)) + widgetContent.cycleTab(); + else if (checkKeybind(event, userOptions.keybinds.sidebar.nextTab)) + widgetContent.nextTab(); + else if (checkKeybind(event, userOptions.keybinds.sidebar.prevTab)) + widgetContent.prevTab(); + else if (checkKeybind(event, userOptions.keybinds.sidebar.apis.nextTab)) { + apiWidgets.attribute.nextTab(); + return true; } - else if (event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK) { - if (event.get_keyval()[1] === Gdk.KEY_Page_Down) { - widgetContent.nextTab(); - return true; - } - else if (event.get_keyval()[1] === Gdk.KEY_Page_Up) { - widgetContent.prevTab(); - return true; - } + else if (checkKeybind(event, userOptions.keybinds.sidebar.apis.prevTab)) { + apiWidgets.attribute.prevTab(); + return true; } }) , diff --git a/.config/ags/modules/sideleft/sideleft.js b/.config/ags/modules/sideleft/sideleft.js index 5ae293849..377273517 100644 --- a/.config/ags/modules/sideleft/sideleft.js +++ b/.config/ags/modules/sideleft/sideleft.js @@ -10,6 +10,7 @@ import toolBox from './toolbox.js'; import apiWidgets from './apiwidgets.js'; import { chatEntry } from './apiwidgets.js'; import { TabContainer } from '../.commonwidgets/tabcontainer.js'; +import { checkKeybind } from '../.widgetutils/keybind.js'; const contents = [ { @@ -85,18 +86,15 @@ export default () => Box({ ], setup: (self) => self .on('key-press-event', (widget, event) => { // Handle keybinds - if (event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK) { // Ctrl held - // Pin sidebar - if (event.get_keyval()[1] == Gdk.KEY_p) - pinButton.attribute.toggle(pinButton); - // Switch sidebar tab - else if (event.get_keyval()[1] === Gdk.KEY_Tab) - widgetContent.cycleTab(); - else if (event.get_keyval()[1] === Gdk.KEY_Page_Up) - widgetContent.prevTab(); - else if (event.get_keyval()[1] === Gdk.KEY_Page_Down) - widgetContent.nextTab(); - } + if (checkKeybind(event, userOptions.keybinds.sidebar.pin)) + pinButton.attribute.toggle(pinButton); + else if (checkKeybind(event, userOptions.keybinds.sidebar.cycleTab)) + widgetContent.cycleTab(); + else if (checkKeybind(event, userOptions.keybinds.sidebar.nextTab)) + widgetContent.nextTab(); + else if (checkKeybind(event, userOptions.keybinds.sidebar.prevTab)) + widgetContent.prevTab(); + if (widgetContent.attribute.names[widgetContent.attribute.shown.value] == 'APIs') { // If api tab is focused // Focus entry when typing if (( @@ -113,13 +111,11 @@ export default () => Box({ buffer.place_cursor(buffer.get_iter_at_offset(-1)); } // Switch API type - else if (!(event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK) && - event.get_keyval()[1] === Gdk.KEY_Page_Down) { + else if (checkKeybind(event, userOptions.keybinds.sidebar.apis.nextTab)) { const toSwitchTab = widgetContent.attribute.children[widgetContent.attribute.shown.value]; toSwitchTab.attribute.nextTab(); } - else if (!(event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK) && - event.get_keyval()[1] === Gdk.KEY_Page_Up) { + else if (checkKeybind(event, userOptions.keybinds.sidebar.apis.prevTab)) { const toSwitchTab = widgetContent.attribute.children[widgetContent.attribute.shown.value]; toSwitchTab.attribute.prevTab(); } diff --git a/.config/ags/user_options.js b/.config/ags/user_options.js index f88cbb8c3..79a8e7e2e 100644 --- a/.config/ags/user_options.js +++ b/.config/ags/user_options.js @@ -1,5 +1,6 @@ let userConfigOptions = { + // General stuff 'ai': { 'defaultGPTProvider': 'openai', 'defaultTemperature': 0.9, @@ -43,7 +44,8 @@ let userConfigOptions = { 'workspaces': { 'shown': 10, }, - icons: { + // Longer stuff + 'icons': { substitutions: { 'code-url-handler': 'visual-studio-code', 'Code': 'visual-studio-code', @@ -55,7 +57,27 @@ let userConfigOptions = { 'wpsoffice': 'wps-office2019-kprometheus', '': 'image-missing', } - } + }, + 'keybinds': { + // Format: Mod1+Mod2+key. CaSe SeNsItIvE! + // Modifiers: Shift Ctrl Alt Hyper Meta NoMod + // See https://docs.gtk.org/gdk3/index.html#constants for the other keys + 'overview': { + 'altMoveLeft': 'Ctrl+b', + 'altMoveRight': 'Ctrl+f', + 'deleteToEnd': 'Ctrl+k', + }, + 'sidebar': { + 'apis': { + 'nextTab': 'Page_Down', + 'prevTab': 'Page_Up', + }, + 'pin': 'Ctrl+p', + 'cycleTab': 'Ctrl+Tab', + 'nextTab': 'Ctrl+Page_Down', + 'prevTab': 'Ctrl+Page_Up', + }, + }, } globalThis['userOptions'] = userConfigOptions;