toshy_config.py (322763B)
1 # -*- coding: utf-8 -*- 2 __version__ = '20260101' 3 ############################################################################### 4 ############################ Welcome to Toshy! ############################ 5 ### 6 ### This is a highly customized fork of the config file that powers 7 ### Kinto.sh, by Ben Reaves 8 ### (https://kinto.sh) 9 ### 10 ### All credit for the basis of this config goes to Ben Reaves. 11 ### (https://github.com/rbreaves/kinto/) 12 ### 13 ### Much assistance was provided by Josh Goebel, the developer of the 14 ### `xkeysnail` fork `keyszer`, which is now forked into `xwaykeyz` to 15 ### provide support for some (most?) Wayland environments. 16 ### (http://github.com/joshgoebel/keyszer) 17 ### 18 ############################################################################### 19 20 import re 21 import os 22 import sys 23 import time 24 import shutil 25 import asyncio 26 import inspect 27 import subprocess 28 29 from subprocess import DEVNULL 30 from typing import Any, Callable, Optional, Union, List, Dict, Tuple 31 32 from xwaykeyz.config_api import * 33 from xwaykeyz.lib.key_context import KeyContext 34 from xwaykeyz.lib.logger import debug, error 35 from xwaykeyz.models.modifier import Modifier 36 37 38 ################################################################################################### 39 ### SLICE_MARK_START: keymapper_api ### EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE 40 41 # Keymapper-specific config settings - REMOVE OR SET TO DEFAULTS FOR DISTRIBUTION 42 dump_diagnostics_key(Key.F15) # default key: F15 43 emergency_eject_key(Key.F16) # default key: F16 44 45 timeouts( 46 multipurpose = 1, # default: 1 sec 47 suspend = 1, # default: 1 sec, try 0.1 sec for touchpads/trackpads 48 ) 49 50 # Delays often needed for Wayland and/or virtual machines or slow systems 51 throttle_delays( 52 key_pre_delay_ms = 8, # default: 0 ms, range: 0-150 ms, suggested: 1-50 ms 53 key_post_delay_ms = 12, # default: 0 ms, range: 0-150 ms, suggested: 1-100 ms 54 ) 55 56 devices_api( 57 # Only the specified devices will be "grabbed" and watched for during 58 # device connections/disconnections. 59 only_devices = [ 60 # 'Example Disconnected Keyboard', 61 # 'Example Connected Keyboard', 62 ] 63 ) 64 65 ########################################################### 66 # Use this ONLY if you want near zero CPU usage for held, 67 # repeating keys. This will bypass the new repeating keys 68 # cache mechanism that reduces CPU usage for repeats to 69 # very low levels (but not zero), in xwaykeyz>=1.11.0. 70 # 71 # This override will BREAK shortcuts like Emacs-style 72 # cursor movement, which will not be able to repeat. 73 # 74 # A warning will appear in verbose debug logging. 75 ########################################################### 76 # ignore_repeating_keys(True) 77 78 79 ### SLICE_MARK_END: keymapper_api ### EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE 80 ################################################################################################### 81 82 83 84 ################################################################################################### 85 # How to add an alias to an existing modifier definition (VERY EXPERIMENTAL!!!) 86 # Some of these are disabled because I'm not sure they would apply correctly 87 # to all of the different keyboard types. But virtualized Command and Left Ctrl, 88 # Left Option aliases should make sense for all keyboard types. 89 # WARNING: It is not advisable to start using these in actual input 90 # combos in keymaps. These aliases may be removed in the future. 91 try: 92 ########################################################################### 93 # # Virtualized (left) Control key (in Terminals) 94 95 LC_aliases: List[str] = Modifier.L_CONTROL.aliases 96 LC_keys: List[Key] = Modifier.L_CONTROL.keys 97 # use slice assignment instead of insert() 98 LC_aliases[:0] = ['VLCtrl', 'VirtLCtrl'] 99 # debug(f"{LC_aliases = }") 100 # debug(f"{LC_keys = }") 101 102 ########################################################################### 103 # # Virtualized (left/right) Control keys (in GUI apps) 104 105 # L_META_aliases: List[str] = Modifier.L_META.aliases 106 # L_META_keys: List[Key] = Modifier.L_META.keys 107 # # use slice assignment instead of insert() 108 # L_META_aliases[:0] = ['VLCtrl', 'Virt_LCtrl'] 109 # debug(f"{L_META_aliases = }") 110 # debug(f"{L_META_keys = }") 111 112 # R_META_aliases: List[str] = Modifier.R_META.aliases 113 # R_META_keys: List[Key] = Modifier.R_META.keys 114 # # use slice assignment instead of insert() 115 # R_META_aliases[:0] = ['VRCtrl', 'Virt_RCtrl'] 116 # debug(f"{R_META_aliases = }") 117 # debug(f"{R_META_keys = }") 118 119 ########################################################################### 120 # Virtualized Option/Alt keys (left/right) 121 122 LA_aliases: List[str] = Modifier.L_ALT.aliases 123 LA_keys: List[Key] = Modifier.L_ALT.keys 124 # use slice assignment instead of insert() 125 LA_aliases[:0] = ['VLOpt', 'VirtLOpt'] 126 # debug(f"{LA_aliases = }") 127 # debug(f"{LA_keys = }") 128 129 # RA_aliases: List[str] = Modifier.R_ALT.aliases 130 # RA_keys: List[Key] = Modifier.R_ALT.keys 131 # # use slice assignment instead of insert() 132 # RA_aliases[:0] = ['VROpt', 'VirtROpt'] 133 # debug(f"{RA_aliases = }") 134 # debug(f"{RA_keys = }") 135 136 ########################################################################### 137 # Virtualized Command key (all keyboard types) 138 139 R_CONTROL_aliases: List[str] = Modifier.R_CONTROL.aliases 140 R_CONTROL_keys: List[Key] = Modifier.R_CONTROL.keys 141 # use slice assignment instead of insert() 142 R_CONTROL_aliases[:0] = ['VCmd', 'VirtCmd'] 143 # debug(f"{R_CONTROL_aliases = }") 144 # debug(f"{R_CONTROL_keys = }") 145 146 except AttributeError as e: 147 error(f"Problem adding alias to modifier:\n\t{e}") 148 ################################################################################################### 149 150 151 152 ################################################################################################### 153 # Some important setup work necessary to make custom preferences, 154 # notifications and Synergy log monitoring work. 155 home_dir = os.path.expanduser('~') 156 icons_dir = os.path.join(home_dir, '.local', 'share', 'icons') 157 158 # get the path of this file (not the main module loading it) 159 config_globals = inspect.stack()[1][0].f_globals 160 current_folder_path = os.path.dirname(os.path.abspath(config_globals["__config__"])) 161 sys.path.insert(0, current_folder_path) 162 163 # Local imports after path has been set 164 from toshy_common.env_context import EnvironmentInfo 165 from toshy_common.machine_context import get_machine_id_hash 166 from toshy_common.notification_manager import NotificationManager 167 from toshy_common.settings_class import Settings 168 169 assets_path = os.path.join(current_folder_path, 'assets') 170 icon_file_active = os.path.join(assets_path, "toshy_app_icon_rainbow.svg") 171 icon_file_grayscale = os.path.join(assets_path, "toshy_app_icon_rainbow_inverse_grayscale.svg") 172 icon_file_inverse = os.path.join(assets_path, "toshy_app_icon_rainbow_inverse.svg") 173 174 # Toshy config file 175 TOSHY_PART = 'config' # CUSTOMIZE TO SPECIFIC TOSHY COMPONENT! (gui, tray, config) 176 TOSHY_PART_NAME = 'Toshy Config file' 177 APP_VERSION = __version__ 178 179 # Settings object used to tweak preferences "live" between gui, tray and config. 180 cnfg = Settings(current_folder_path) 181 cnfg.watch_database() # activate watchdog observer on the sqlite3 db file 182 cnfg.watch_shared_devices() # Look for network KVM apps and watch logs (on server only) 183 # debug("") 184 debug(cnfg, ctx="CG") 185 186 187 188 ############################# ENVIRONMENT ############################## 189 ### ### 190 ### ### 191 ### ███████ ███ ██ ██ ██ ██ ██████ ██████ ███ ██ ### 192 ### ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ### 193 ### █████ ██ ██ ██ ██ ██ ██ ██████ ██ ██ ██ ██ ██ ### 194 ### ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 195 ### ███████ ██ ████ ████ ██ ██ ██ ██████ ██ ████ ### 196 ### ### 197 ### ### 198 ########################################################################## 199 # Set up some useful environment variables 200 201 ################################################################################################### 202 ### SLICE_MARK_START: env_overrides ### EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE 203 204 # MANUALLY set any environment information if the auto-identification isn't working: 205 OVERRIDE_DISTRO_ID = None 206 OVERRIDE_DISTRO_VER = None 207 OVERRIDE_VARIANT_ID = None 208 OVERRIDE_SESSION_TYPE = None 209 OVERRIDE_DESKTOP_ENV = None 210 OVERRIDE_DE_MAJ_VER = None 211 OVERRIDE_WINDOW_MGR = None 212 213 wlroots_compositors = [ 214 # Comma-separated list of Wayland desktop environments or window managers 215 # that should try to use the 'wlroots' window context provider. Use the 216 # 'WINDOW_MGR' name that appears when running `toshy-env`, or 'DESKTOP_ENV' 217 # if the window manager name is not identified. 218 # 'obscurewm', 219 # 'unknown-wm', 220 221 ] 222 223 ### SLICE_MARK_END: env_overrides ### EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE 224 ################################################################################################### 225 226 # Leave all of this alone! Don't try to override values here. 227 DISTRO_ID = None 228 DISTRO_VER = None 229 VARIANT_ID = None 230 SESSION_TYPE = None 231 DESKTOP_ENV = None 232 DE_MAJ_VER = None 233 WINDOW_MGR = None 234 235 env_ctxt_getter = EnvironmentInfo() 236 env_ctxt: Dict[str, str] = env_ctxt_getter.get_env_info() 237 238 DISTRO_ID = locals().get('OVERRIDE_DISTRO_ID') or env_ctxt.get('DISTRO_ID', 'keymissing') 239 DISTRO_VER = locals().get('OVERRIDE_DISTRO_VER') or env_ctxt.get('DISTRO_VER', 'keymissing') 240 VARIANT_ID = locals().get('OVERRIDE_VARIANT_ID') or env_ctxt.get('VARIANT_ID', 'keymissing') 241 SESSION_TYPE = locals().get('OVERRIDE_SESSION_TYPE') or env_ctxt.get('SESSION_TYPE', 'keymissing') 242 DESKTOP_ENV = locals().get('OVERRIDE_DESKTOP_ENV') or env_ctxt.get('DESKTOP_ENV', 'keymissing') 243 DE_MAJ_VER = locals().get('OVERRIDE_DE_MAJ_VER') or env_ctxt.get('DE_MAJ_VER', 'keymissing') 244 WINDOW_MGR = locals().get('OVERRIDE_WINDOW_MGR') or env_ctxt.get('WINDOW_MGR', 'keymissing') 245 246 # debug("") 247 debug( f'Toshy config sees this environment:' 248 f'\n\t{DISTRO_ID = }' 249 f'\n\t{DISTRO_VER = }' 250 f'\n\t{VARIANT_ID = }' 251 f'\n\t{SESSION_TYPE = }' 252 f'\n\t{DESKTOP_ENV = }' 253 f'\n\t{DE_MAJ_VER = }' 254 f'\n\t{WINDOW_MGR = }', ctx="CG") 255 256 257 # NOTE: List kind of stabilized, so moved all into keymapper wlroots window context method 258 # during the transition from using "desktop environment" to using "window manager". 259 known_wlroots_compositors = [ 260 # 'hyprland', 261 # 'labwc', 262 # 'miracle-wm', 263 # 'miriway', 264 # 'miriway-shell', # actual process name for 'miriway' compositor? 265 # 'niri', 266 # 'qtile', 267 # 'river', 268 # 'sway', 269 # 'wayfire', 270 ] 271 272 # Make sure the 'wlroots_compositors' list variable exists before checking it. 273 # Older config files won't have it in the 'env_overrides' slice. 274 wlroots_compositors = locals().get('wlroots_compositors', []) 275 276 all_wlroots_compositors = known_wlroots_compositors + wlroots_compositors 277 278 # Direct the keymapper to try to use `wlroots` window context for 279 # all DEs/WMs in user list, if list is not empty. 280 if wlroots_compositors and WINDOW_MGR in wlroots_compositors: 281 debug(f"Will use 'wlroots' context provider for '{WINDOW_MGR}' WM", ctx="CG") 282 debug("File an issue on GitHub repo if this works for your WM.", ctx="CG") 283 _wl_compositor = 'wlroots' 284 elif wlroots_compositors and DESKTOP_ENV in wlroots_compositors: 285 debug(f"Will use 'wlroots' context provider for '{DESKTOP_ENV}' DE", ctx="CG") 286 debug("File an issue on GitHub repo if this works for your DE.", ctx="CG") 287 _wl_compositor = 'wlroots' 288 elif WINDOW_MGR in known_wlroots_compositors: 289 debug(f"WM '{WINDOW_MGR}' is in known 'wlroots' compositor list.", ctx="CG") 290 _wl_compositor = 'wlroots' 291 elif DESKTOP_ENV in known_wlroots_compositors: 292 debug(f"DE '{DESKTOP_ENV}' is in known 'wlroots' compositor list.", ctx="CG") 293 _wl_compositor = 'wlroots' 294 # elif (SESSION_TYPE, DESKTOP_ENV) == ('wayland', 'lxqt') and WINDOW_MGR == 'kwin_wayland': 295 # # The Toshy KWin script must be installed in the LXQt/KWin environment for this to work! 296 # debug(f"DE is LXQt, WM is '{WINDOW_MGR}', using 'kwin_wayland' window context method.", ctx="CG") 297 # _desktop_env = 'kde' 298 # elif (SESSION_TYPE, DESKTOP_ENV) == ('wayland', 'lxqt') and WINDOW_MGR in all_wlroots_compositors: 299 # debug(f"DE is LXQt, WM is '{WINDOW_MGR}', using 'wlroots' window context method.", ctx="CG") 300 # _desktop_env = 'wlroots' 301 else: 302 _wl_compositor = WINDOW_MGR 303 304 try: 305 # Help the keymapper select the correct window context provider object 306 environ_api(session_type = SESSION_TYPE, wl_compositor = _wl_compositor) # type: ignore 307 except NameError: 308 error(f"The API function 'environ_api' is not defined yet. Wrong keymapper branch?") 309 pass 310 311 312 # Global variable to store the local machine ID at runtime, for machine-specific keymaps. 313 # Allows syncing a single config file between different machines without overlapping the 314 # hardware/media key overrides, or any other machine-specific customization. 315 # Get the ID for each machine with the `toshy-machine-id` command, for use in `if` conditions. 316 MACHINE_ID = get_machine_id_hash() 317 318 319 320 ################# VARIABLES #################### 321 ### ### 322 ### ### 323 ### ██ ██ █████ ██████ ███████ ### 324 ### ██ ██ ██ ██ ██ ██ ██ ### 325 ### ██ ██ ███████ ██████ ███████ ### 326 ### ██ ██ ██ ██ ██ ██ ██ ### 327 ### ████ ██ ██ ██ ██ ███████ ### 328 ### ### 329 ### ### 330 ################################################## 331 # Establish important global variables here 332 333 334 STARTUP_TIMESTAMP = time.time() # only gets evaluated once for each run of keymapper 335 336 # Variable to hold the keyboard type 337 KBTYPE = None 338 339 # Short names for the `xwaykeyz/keyszer` string and Unicode processing helper functions 340 ST = to_US_keystrokes # was 'to_keystrokes' originally 341 UC = unicode_keystrokes 342 ignore_combo = ComboHint.IGNORE 343 344 ############################################################################### 345 # This is a "trick" to negate the need to put quotes around all the key labels 346 # inside the "lists of dicts" to be given to the matchProps() function. 347 # Makes the variables evaluate to equivalent strings inside the dicts. 348 # Provides for nice syntax highlighting and visual separation of key:value. 349 clas = 'clas' # key label for matchProps() arg to match: wm_class 350 name = 'name' # key label for matchProps() arg to match: wm_name 351 devn = 'devn' # key label for matchProps() arg to match: device_name 352 not_clas = 'not_clas' # key label for matchProps() arg to NEGATIVE match: wm_class 353 not_name = 'not_name' # key label for matchProps() arg to NEGATIVE match: wm_name 354 not_devn = 'not_devn' # key label for matchProps() arg to NEGATIVE match: device_name 355 numlk = 'numlk' # key label for matchProps() arg to match: numlock_on 356 capslk = 'capslk' # key label for matchProps() arg to match: capslock_on 357 cse = 'cse' # key label for matchProps() arg to enable: case sensitivity 358 lst = 'lst' # key label for matchProps() arg to pass in a [list] of {dicts} 359 dbg = 'dbg' # key label for matchProps() arg to set debugging info string 360 361 # global variables for the isDoubleTap() function 362 tapTime1 = time.time() 363 tapInterval = 0.24 364 tapCount = 0 365 last_dt_combo = None 366 367 # Set this variable to False to disable the alert that appears 368 # when using Apple logo shortcut (Shift+Option+K) 369 applelogoalert_enabled = True # Default: True 370 371 372 373 374 ###################### LISTS ####################### 375 ### ### 376 ### ### 377 ### ██ ██ ███████ ████████ ███████ ### 378 ### ██ ██ ██ ██ ██ ### 379 ### ██ ██ ███████ ██ ███████ ### 380 ### ██ ██ ██ ██ ██ ### 381 ### ███████ ██ ███████ ██ ███████ ### 382 ### ### 383 ### ### 384 ###################################################### 385 386 387 def toRgxStr(lst_of_str) -> str: 388 """ 389 Convert a list of strings into single casefolded regex pattern string. 390 """ 391 def raise_TypeError(): raise TypeError(f"\n\n### toRgxStr wants a list of strings ###\n") 392 if not isinstance(lst_of_str, list): raise_TypeError() 393 if any([not isinstance(x, str) for x in lst_of_str]): raise_TypeError() 394 lst_of_str_clean = [str(x).replace('^','').replace('$','') for x in lst_of_str] 395 return "|".join('^'+x.casefold()+'$' for x in lst_of_str_clean) 396 397 398 def negRgx(rgx_str): 399 """ 400 Convert positive match regex pattern into negative lookahead regex pattern. 401 """ 402 # remove any ^$ 403 rgx_str_strip = str(rgx_str).replace('^','').replace('$','') 404 # add back ^$, but only around ENTIRE STRING (ignore any vertical bars/pipes) 405 rgx_str_add = str('^'+rgx_str_strip+'$') 406 # convert ^$ to complicated negative lookahead pattern that actually works 407 neg_rgx_str = str(rgx_str_add).replace('^','^(?:(?!^').replace('$','$).)*$') 408 return neg_rgx_str 409 410 411 def create_list_of_dicts(lst: List[str]): 412 """ 413 Convert a simple list of class names into a list of dictionaries, 414 each dictionary containing a single key 'clas' with the regex pattern 415 for exact match. Strips any leading '^' or trailing '$' from each item 416 in the list to ensure clean, standardized entries. 417 """ 418 cleaned_list = [name.strip('^$') for name in lst] # Remove any leading '^' or trailing '$' 419 return [{'clas': f"^{item}$"} for item in cleaned_list] 420 421 422 terminals = [ 423 "alacritty", 424 # "com.mitchellh.ghostty", # Replaced with double-wildcard ghostty pattern 425 "com.raggesilver.BlackBox", 426 "com.system76.CosmicTerm", 427 "contour", 428 "cutefish-terminal", 429 "deepin-terminal", 430 "dev.warp.Warp", 431 "eterm", 432 ".*ghostty.*", 433 # "ghostty", # Replaced with double-wildcard ghostty pattern 434 # "ghostty-debug", # Replaced with double-wildcard ghostty pattern 435 "gnome-terminal", 436 "gnome-terminal-server", 437 "guake", 438 "hyper", 439 "io.elementary.terminal", 440 "kinto-gui.py", 441 "kitty", 442 "Kgx", 443 "konsole", 444 "lxterminal", 445 "mate-terminal", 446 "MateTerminal", 447 "org.codeberg.dnkl.foot.desktop", 448 "org.gnome.Console", 449 # "org.gnome.Ptyxis.*", # Replaced by double-wildcard Ptyxis pattern 450 "org.gnome.Terminal", 451 "org.kde.konsole", 452 "org.kde.yakuake", 453 "org.wezfurlong.wezterm", 454 ".*Ptyxis.*", 455 "roxterm", 456 "qterminal", 457 "st", 458 "sakura", 459 "station", 460 "tabby", 461 "terminator", 462 "terminology", 463 "termite", 464 "Termius", 465 "tilda", 466 "tilix", 467 "urxvt", 468 "Wave", 469 "wezterm", 470 "wezterm-gui", 471 "xfce4-terminal", 472 "xterm", 473 "yakuake", 474 ] 475 terminals = [x.casefold() for x in terminals] 476 termStr = toRgxStr(terminals) 477 478 # DEPRECATED 479 # This is only for use with 'remotes_lod', otherwise regex pattern string is used. 480 terminals_lod = create_list_of_dicts(terminals) 481 482 vscodes = [ 483 "code", 484 "code - oss", 485 "code-oss", 486 "cursor", # New VSCode variant with A.I. 487 "vscodium", 488 ] 489 vscodes = [x.casefold() for x in vscodes] 490 vscodeStr = toRgxStr(vscodes) 491 492 # DEPRECATED: Converted back to simple list 493 # This is only for use with 'vscodes_and_remotes_lod', otherwise regex pattern string is used. 494 vscodes_lod = create_list_of_dicts(vscodes) 495 496 sublimes = [ 497 "sublime_text", 498 "subl", 499 ] 500 sublimes = [x.casefold() for x in sublimes] 501 sublimeStr = toRgxStr(sublimes) 502 503 JDownloader_lod = [ 504 {clas: "^.*jdownloader.*$"}, 505 {clas: "^java-lang-Thread$", name: "^JDownloader.*$"} # Happens after auto-update of app 506 ] 507 508 # Transmission app can have several different app class strings 509 transmissions = [ 510 'Transmission-gtk', 511 'Transmission-qt', 512 'com.transmissionbt.Transmission.*', # Flatpak has a stupid random app class suffix 513 ] 514 transmissions = [x.casefold() for x in transmissions] 515 transmissionStr = toRgxStr(transmissions) 516 517 518 # Add remote desktop clients & VM software here 519 # Ideally we'd only exclude the client window, 520 # but that may not be easily done. 521 # (Can be done now with `keyszer`, as long as main window has a 522 # different WM_NAME than client windows. See `remotes_lod` below.) 523 remotes = [ 524 "Anydesk", 525 "cs2", 526 "csgo", 527 "Gnome-boxes", 528 "gnome-connections", 529 "org.gnome.Boxes", 530 "org.remmina.Remmina", 531 "Nxplayer.bin", 532 "remmina", 533 "qemu-system-.*", 534 "qemu", 535 "Spicy", 536 "Virt-manager", 537 "VirtualBox", 538 "VirtualBox Machine", 539 "xfreerdp", 540 "Wfica", 541 ] 542 remotes = [x.casefold() for x in remotes] 543 remoteStr = toRgxStr(remotes) 544 545 # DEPRECATED: Converted back to simple list format 546 # Add remote desktop clients & VM software here 547 remotes_lod = [ 548 {clas: "^Anydesk$" }, 549 {clas: "^Gnome-boxes$" }, 550 {clas: "^gnome-connections$" }, 551 {clas: "^org.remmina.Remmina$", 552 not_name: "^Remmina Remote Desktop Client$|^Remote Connection Profile$"}, 553 {clas: "^Nxplayer.bin$" }, 554 {clas: "^remmina$" }, 555 {clas: "^qemu-system-.*$" }, 556 {clas: "^qemu$" }, 557 {clas: "^Spicy$" }, 558 {clas: "^Virt-manager$" }, 559 {clas: "^VirtualBox$" }, 560 {clas: "^VirtualBox Machine$" }, 561 {clas: "^xfreerdp$" }, 562 {clas: "^Wfica$" }, 563 ] 564 565 terms_and_remotes_lst = terminals + remotes 566 terms_and_remotes_Str = toRgxStr(terms_and_remotes_lst) 567 568 # DEPRECATED: Converted back to simple list 569 terminals_and_remotes_lod = [ 570 {lst: terminals_lod }, 571 {lst: remotes_lod }, 572 ] 573 574 # DEPRECATED by 'vscodes_and_remotes_lod' "list of dicts" below 575 # vscodes.extend(remotes) 576 # vscodeStr_ext = toRgxStr(vscodes) 577 578 vscodes_and_remotes_lst = vscodes + remotes 579 vscodes_and_remotes_Str = toRgxStr(vscodes_and_remotes_lst) 580 581 # DEPRECATED: Converted back to simple list 582 vscodes_and_remotes_lod = [ 583 {lst: vscodes_lod }, 584 {lst: remotes_lod }, 585 ] 586 587 browsers_chrome = [ 588 "Brave-browser", 589 "Chromium", 590 "Chromium-browser", 591 "Falkon", 592 "Google-chrome", 593 "Io.github.ungoogled_software.ungoogled_chromium", 594 "microsoft-edge", 595 "microsoft-edge-dev", 596 "org.deepin.browser", 597 "org.kde.falkon", 598 ".*ungoogled_chromium", 599 "Vivaldi.*", 600 ] 601 browsers_chrome = [x.casefold() for x in browsers_chrome] 602 browsers_chromeStr = "|".join('^'+x+'$' for x in browsers_chrome) 603 604 browsers_firefox = [ 605 "firedragon", # Garuda Firefox fork 606 "Firefox", 607 "firefox_.*", # Catch "firefox_firefox" (WTF?), seen on Ubuntu Cinnamon 25.10 in X11 session 608 "firefox-esr", 609 "Firefox Developer Edition", 610 "firefoxdeveloperedition", 611 "firefox-nightly.*", 612 "floorp", 613 "LibreWolf", 614 "Mullvad Browser", 615 "Navigator", 616 "org.mozilla.firefox", 617 "Waterfox", 618 "zen-browser", 619 "zen", 620 "zen-alpha", 621 "zen-beta", 622 "zen-bin", 623 "zen-twilight", 624 ] 625 browsers_firefox = [x.casefold() for x in browsers_firefox] 626 browsers_firefoxStr = "|".join('^'+x+'$' for x in browsers_firefox) 627 628 browsers_all = [ 629 # unpack Chrome and Firefox lists into this general browser list 630 *browsers_chrome, 631 *browsers_firefox, 632 "Discord", 633 "Epiphany", 634 "org.gnome.Epiphany", 635 ] 636 browsers_all = [x.casefold() for x in browsers_all] 637 browsers_allStr = "|".join('^'+x+'$' for x in browsers_all) 638 639 640 # NOTE: Do not be tempted to convert simple app class lists into a "list of dicts" 641 # If the list contains only app classes, the regex pattern string is much faster. 642 filemanagers = [ 643 "caja", 644 "com.system76.CosmicFiles", 645 "dde-file-manager", 646 "dolphin", 647 "io.elementary.files", 648 "krusader", 649 "nautilus", 650 "nemo", 651 "org.gnome.nautilus", 652 "org.kde.dolphin", 653 "org.kde.krusader", 654 "pcmanfm", 655 "pcmanfm-qt", 656 "peony-qt", 657 "spacefm", 658 "thunar", 659 ] 660 filemanagers = [x.casefold() for x in filemanagers] 661 filemanagerStr = "|".join('^'+x+'$' for x in filemanagers) 662 663 664 ### dialogs_Escape_lod = send these windows the Escape key for Cmd+W 665 dialogs_Escape_lod = [ 666 {clas: "^Angry.*IP.*Scanner$", 667 name: "^IP.*address.*details.*$|^Preferences.*$|^Scan.*Statistics.*$|^Edit.*openers.*$"}, 668 # TODO: add or change Atoms class to "pm.mirko.Atoms" if the app gets updated 669 # TODO: remove "atoms" from "name: " entry patterns if "Shortcuts" dialog gets updated 670 # Reference: https://github.com/AtomsDevs/Atoms/issues/61 671 {clas: "^atoms$", name: "^Preferences$|^Shortcuts$|^About$|^atoms$"}, 672 {clas: "^com.github.rafostar.Clapper$", name: "^Preferences$"}, 673 {clas: "^epiphany$|^org.gnome.Epiphany$", name: "^Preferences$"}, 674 {clas: "^gnome-text-editor$|^org.gnome.TextEditor$", name: "^Preferences$"}, 675 {clas: "^io.github.celluloid_player.Celluloid$", name: "^Preferences$"}, 676 {clas: "^konsole$|^org.kde.konsole$", name: "^Configure.*Konsole$|^Edit Profile.*Konsole$"}, 677 {clas: "^krusader$|^org.kde.krusader$", name: "^Properties.*Krusader$"}, 678 {clas: "^.*nautilus$", name: "^.*Properties$|^Preferences$|^Create Archive$|^Rename.*Files$"}, 679 # {clas: "^org.gnome.Ptyxis.*$", name: "^Preferences$"}, 680 {clas: "^.*Ptyxis.*$", name: "^Preferences$"}, 681 {clas: "^org.gnome.Shell.Extensions$"}, 682 {clas: "^org.kde.Dolphin$", name: "^Configure.*Dolphin$|^Properties.*Dolphin$"}, 683 {clas: "^org.kde.falkon$|^Falkon$", name: "^Preferences.*Falkon$"}, 684 {clas: "^org.kde.kdialog$"}, 685 {clas: "^org.kde.KWrite$", name: "^Configure.*KWrite$"}, 686 {clas: "^org.gnome.Software$", not_name: "^Software$"}, 687 {clas: transmissionStr, not_name: "^Transmission$"}, 688 {clas: "^xfce4-terminal$", name: "^Terminal Preferences$"}, 689 {clas: "^zenity$|^qarma$"} 690 ] 691 692 ### dialogs_CloseWin_lod = send these windows the "Close window" combo for Cmd+W 693 dialogs_CloseWin_lod = [ 694 {clas: "^Angry.*IP.*Scanner$", name: "^Fetchers.*$|^Edit.*favorites.*$"}, 695 {clas: "^com.mattjakeman.ExtensionManager$|^extension-manager$", not_name: "^Extension Manager$"}, 696 {clas: "^fr.handbrake.ghb$", not_name: "^HandBrake$"}, 697 {clas: "^Gnome-control-center$", not_name: "^Settings$"}, 698 {clas: "^gnome-terminal.*$", name: "^Preferences.*$"}, 699 {clas: "^gnome-terminal-pref.*$", name: "^Preferences.*$"}, 700 {clas: "^org.kde.kate$", name: "^Configure.*Kate$"}, 701 {clas: "^pcloud$"}, 702 {clas: "^systemsettings$", name: "^Download New.*System Settings$"}, 703 {clas: "^Totem$", not_name: "^Videos$"}, 704 ] 705 706 707 ################################################################################################### 708 ### SLICE_MARK_START: kbtype_override ### EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE 709 710 keyboards_UserCustom_dct = { 711 # Add your keyboard device here if its type is misidentified. 712 # Valid types to map device to: Apple, Windows, IBM, Chromebook (case sensitive) 713 # Example: 714 'My Keyboard Device Name': 'Apple', 715 } 716 717 ### SLICE_MARK_END: kbtype_override ### EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE 718 ################################################################################################### 719 720 # Create a "UserCustom" keyboard dictionary with casefolded keys 721 kbds_UserCustom_dct_cf = {k.casefold(): v for k, v in keyboards_UserCustom_dct.items()} 722 723 724 # Lists of keyboard device names, to match keyboard type 725 keyboards_IBM = [ 726 # Add specific IBM-style keyboard device names to this list 727 'IBM Enhanced (101/102-key) Keyboard', 728 'IBM Rapid Access Keyboard', 729 'IBM Space Saver II', 730 'IBM Model M', 731 'IBM Model F', 732 ] 733 keyboards_Chromebook = [ 734 # Add specific Chromebook keyboard device names to this list 735 'Google.*Keyboard', 736 ] 737 keyboards_Windows = [ 738 # Add specific Windows/PC keyboard device names to this list 739 'AT Translated Set 2 keyboard', 740 ] 741 keyboards_Apple = [ 742 # Add specific Apple/Mac keyboard device names to this list 743 'HP TouchPad Wireless Keyboard', # Missing some keys, but Apple type probably best default 744 'Magic Keyboard with Numeric Keypad', 745 'Magic Keyboard', 746 'Mitsumi Electric Apple Extended USB Keyboard', 747 'MX Keys Mac Keyboard', 748 'Griffin Technology, Inc. iMate, USB To ADB Adaptor', 749 '.*USB to ADB Adapt.*' # ADB device is pretty much guaranteed to be an Apple (or NeXT) keyboard 750 ] 751 752 kbtype_lists = { 753 'IBM': keyboards_IBM, 754 'Chromebook': keyboards_Chromebook, 755 'Windows': keyboards_Windows, 756 'Apple': keyboards_Apple 757 } 758 759 # List of all known keyboard devices from all lists 760 all_keyboards = [kb for kbtype in kbtype_lists.values() for kb in kbtype] 761 762 # keyboard lists compiled to regex objects (replacing spaces with wildcards) 763 kbds_IBM_rgx = [re.compile(kb.replace(" ", ".*"), re.I) for kb in keyboards_IBM] 764 kbds_Chromebook_rgx = [re.compile(kb.replace(" ", ".*"), re.I) for kb in keyboards_Chromebook] 765 kbds_Windows_rgx = [re.compile(kb.replace(" ", ".*"), re.I) for kb in keyboards_Windows] 766 kbds_Apple_rgx = [re.compile(kb.replace(" ", ".*"), re.I) for kb in keyboards_Apple] 767 768 # Dict mapping keyboard type keywords onto 769 kbtype_lists_rgx = { 770 'IBM': kbds_IBM_rgx, 771 'Chromebook': kbds_Chromebook_rgx, 772 'Windows': kbds_Windows_rgx, 773 'Apple': kbds_Apple_rgx 774 } 775 776 # List of all known keyboard devices from all lists 777 all_kbds_rgx = re.compile(toRgxStr(all_keyboards), re.I) 778 779 not_win_type_rgx = re.compile("IBM|Chromebook|Apple", re.I) 780 781 782 # Suggested location for customizing lists and variables for use with the "when" conditions. 783 ################################################################################################### 784 ### SLICE_MARK_START: user_custom_lists ### EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE 785 786 787 788 ### SLICE_MARK_END: user_custom_lists ### EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE 789 ################################################################################################### 790 791 792 793 ################################### CUSTOM FUNCTIONS #################################### 794 ### ### 795 ### ### 796 ### ███████ ██ ██ ███ ██ ██████ ████████ ██ ██████ ███ ██ ███████ ### 797 ### ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ████ ██ ██ ### 798 ### █████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███████ ### 799 ### ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 800 ### ██ ██████ ██ ████ ██████ ██ ██ ██████ ██ ████ ███████ ### 801 ### ### 802 ### ### 803 ########################################################################################### 804 805 806 # Instantiate a useful notification object class instance, to make notifications easier 807 ntfy = NotificationManager(icon_file_active, title='Toshy Alert (Config)') 808 809 810 def isKBtype(kbtype: str, map=None): 811 # guard against failure to give valid type arg (we don't need to casefold anything with this) 812 if kbtype not in ['IBM', 'Chromebook', 'Windows', 'Apple']: 813 raise ValueError(f"Invalid type given to isKBtype() function: '{kbtype}'" 814 f'\n\t Valid keyboard types (case sensitive): IBM | Chromebook | Windows | Apple') 815 def _isKBtype(ctx: KeyContext): 816 # debug(f"KBTYPE: '{KBTYPE}' | isKBtype check from map: '{map}'") 817 return kbtype == KBTYPE 818 return _isKBtype 819 820 821 kbtype_cache_dct = {} 822 823 824 def getKBtype(): 825 """ 826 ### Get the keyboard type string for the current device 827 828 #### Valid Types 829 830 - IBM | Chromebook | Windows | Apple 831 832 #### Hierarchy of validations: 833 834 - Check if a forced override of keyboard type is applied by user preference. 835 - Check cache dictionary for device name stored from previous run of function. 836 - Check if the device name is in the keyboards_UserCustom_dct dictionary. 837 - Check if the device name matches any keyboard type list. 838 - Check if any keyboard type string is found in the device name string. 839 - Check if the device name indicates a "Windows" keyboard by excluding other types. 840 """ 841 842 valid_kbtypes = ['IBM', 'Chromebook', 'Windows', 'Apple'] 843 844 def _getKBtype(ctx: KeyContext): 845 # debug(f"Entering getKBtype with override value: '{cnfg.override_kbtype}'") 846 global KBTYPE 847 kbd_dev_name = ctx.device_name 848 849 def log_kbtype(msg, cache_dev): 850 debug(f"KBTYPE: '{KBTYPE}' | {msg}: '{kbd_dev_name}'") 851 if cache_dev: 852 kbtype_cache_dct[kbd_dev_name] = (KBTYPE, msg) 853 854 # If user wants to override, apply override and return. 855 # Breaks per-device adaptatation capability while engaged! 856 if cnfg.override_kbtype in valid_kbtypes: 857 KBTYPE = cnfg.override_kbtype 858 log_kbtype(f"WARNING: Override applied! Dev", cache_dev=False) 859 return 860 861 # Check in the kbtype cache dict for the device 862 if kbd_dev_name in kbtype_cache_dct: 863 KBTYPE, cached_msg = kbtype_cache_dct[kbd_dev_name] 864 log_kbtype(f'(CACHED) {cached_msg}', cache_dev=False) 865 return 866 867 kbd_dev_name_cf = ctx.device_name.casefold() 868 869 # Check if there is a custom type for the device 870 custom_kbtype = kbds_UserCustom_dct_cf.get(kbd_dev_name_cf, '') 871 if custom_kbtype and custom_kbtype in valid_kbtypes: 872 KBTYPE = custom_kbtype 873 log_kbtype('Custom type for dev', cache_dev=True) 874 return 875 876 # Check against the keyboard type lists 877 for kbtype, regex_lst in kbtype_lists_rgx.items(): 878 for rgx in regex_lst: 879 if rgx.search(kbd_dev_name_cf): 880 KBTYPE = kbtype 881 log_kbtype('Rgx matched on dev', cache_dev=True) 882 return 883 884 # Check if any keyboard type string is found in the device name 885 for kbtype in ['IBM', 'Chromebook', 'Windows', 'Apple']: 886 if kbtype.casefold() in kbd_dev_name_cf: 887 KBTYPE = kbtype 888 log_kbtype('Type in dev name', cache_dev=True) 889 return 890 891 # Check if the device name indicates a "Windows" keyboard 892 if ('windows' not in kbd_dev_name_cf 893 and not not_win_type_rgx.search(kbd_dev_name_cf) 894 and not all_kbds_rgx.search(kbd_dev_name_cf) ): 895 KBTYPE = 'Windows' 896 log_kbtype('Default type for dev', cache_dev=True) 897 return 898 899 # Default to None if no matching keyboard type is found 900 KBTYPE = 'unidentified' 901 error(f"KBTYPE: '{KBTYPE}' | Dev fell through all checks: '{kbd_dev_name}'") 902 903 return _getKBtype # Return the inner function 904 905 906 def isDoubleTap(dt_combo): 907 """ 908 VERY EXPERIMENTAL!!! 909 910 Simplistic detection of double-tap of a key or combo. 911 912 BLOCKS single-tap function, if used with a single key as the input, but the 913 'normal' (non-modifier) key of a combo will still be usable when used by 914 itself as a non-double-tapped key press. 915 916 Example: 'RC-CapsLock' will respond when "Cmd" key (under Toshy remapping) 917 is held and CapsLock key is double-tapped. Nothing will happen if 918 Cmd+CapsLock is pressed without double-tapping CapsLock key within the 919 configured time interval. But the CapsLock key will still work by itself. 920 921 If double-tap input "combo" is just 'CapsLock', the functioning of a single-tap 922 CapsLock key press will be BLOCKED. Nothing will happen unless the key is 923 double-tapped within the configured time interval. 924 925 Only cares about the 'real' key in a combo of Mods+key, like in the example 926 above with 'RC-CapsLock'. 927 928 The proper way to do this would be inside the keymapper, in the async event loop 929 that deals with input/output functions. 930 """ 931 def _isDoubleTap(): 932 global tapTime1 933 global tapInterval 934 global tapCount 935 global last_dt_combo 936 _tapTime = time.time() 937 # This first "if" block has a logic defect, if a different key in the 938 # same keymap is also set up to send the same "dt_combo" value. 939 if tapCount == 1 and last_dt_combo != dt_combo: 940 debug(f'## isDoubleTap: \n\tDifferent combo: \n\t{last_dt_combo, dt_combo=}') 941 last_dt_combo = None 942 tapCount = 0 943 # 2nd tap beyond time interval? Treat as new double-tap cycle. 944 if tapCount == 1 and _tapTime - tapTime1 >= tapInterval: 945 debug(f'## isDoubleTap: \n\tTime diff (too long): \n\t{_tapTime - tapTime1=}') 946 tapCount = 0 947 # Try to keep held key from producing repeats of dt_combo. 948 # If repeat rate very slow or delay very short, this won't work well. 949 if tapCount == 1 and _tapTime - tapTime1 < 0.07: 950 debug(f'## isDoubleTap: \n\tTime diff (too short): \n\t{_tapTime - tapTime1=}') 951 tapCount = 0 952 return None 953 # 2nd tap within interval window? Reset cycle & send dt_combo. 954 if tapCount == 1 and _tapTime - tapTime1 < tapInterval: 955 debug(f'## isDoubleTap: \n\tTime diff (just right): \n\t{_tapTime - tapTime1=}') 956 tapCount = 0 957 tapTime1 = 0.0 958 return dt_combo 959 # New cycle? Set count = 1, tapTime1 = now. Send nothing. 960 if tapCount == 0: 961 debug(f'## isDoubleTap: \n\tTime diff (1st cycle): \n\t{_tapTime - tapTime1=}') 962 last_dt_combo = dt_combo 963 tapCount = 1 964 tapTime1 = _tapTime 965 return None 966 return _isDoubleTap 967 968 969 total_matchProps_iterations = 0 970 MAX_MATCHPROPS_ITERATIONS = 1000 971 MAX_MATCHPROPS_ITERATIONS_REACHED = False 972 MATCHPROPS_FULL_DEBUG = False # Set True to disable short-circuits and enable full debug logging 973 974 975 # Correct syntax to reject all positional parameters: put `*,` at beginning 976 def matchProps(*, 977 # string parameters (positive matching) 978 clas: str = None, name: str = None, devn: str = None, 979 # string parameters (negative matching) 980 not_clas: str = None, not_name: str = None, not_devn: str = None, 981 # bool parameters 982 numlk: bool = None, capslk: bool = None, cse: bool = None, 983 # list of dicts of parameters (positive) 984 lst: List[Dict[str, Union[str, bool]]] = None, 985 # list of dicts of parameters (negative) 986 not_lst: List[Dict[str, Union[str, bool]]] = None, 987 dbg: str = None, # debugging info (such as: which modmap/keymap?) 988 ) -> Callable[[KeyContext], bool]: 989 """ 990 ### Match all given properties to current window context. \n 991 - Parameters must be _named_, no positional arguments. \n 992 - All parameters optional, but at least one must be given. \n 993 - Defaults to case insensitive matching of: \n 994 - WM_CLASS, WM_NAME, device_name \n 995 - To negate/invert regex pattern match use: \n 996 - `not_clas` `not_name` `not_devn` params or... \n 997 - "^(?:(?!^pattern$).)*$" \n 998 - To force case insensitive pattern match use: \n 999 - "^(?i:pattern)$" or... \n 1000 - "^(?i)pattern$" \n 1001 1002 ### Accepted Parameters: \n 1003 `clas` = WM_CLASS (regex/string) [xprop WM_CLASS] \n 1004 `name` = WM_NAME (regex/string) [xprop _NET_WM_NAME] \n 1005 `devn` = Device Name (regex/string) [xwaykeyz --list-devices] \n 1006 `not_clas` = `clas` but inverted, matches when "not" \n 1007 `not_name` = `name` but inverted, matches when "not" \n 1008 `not_devn` = `devn` but inverted, matches when "not" \n 1009 `numlk` = Num Lock LED state (bool) \n 1010 `capslk` = Caps Lock LED state (bool) \n 1011 `cse` = Case Sensitive matching (bool) \n 1012 `lst` = List of dicts of the above arguments \n 1013 `not_lst` = `lst` but inverted, matches when "not" \n 1014 `dbg` = Debugging info (string) \n 1015 1016 ### Negative match parameters: 1017 - `not_clas`|`not_name`|`not_devn` \n 1018 Parameters take same regex patterns as `clas`|`name`|`devn` \n 1019 but result in a True condition only if pattern is NOT found. \n 1020 Negative parameters cannot be used together with the normal \n 1021 positive matching equivalent parameter in same instance. \n 1022 1023 ### List of Dicts parameter: `lst`|`not_lst` 1024 A [list] of {dicts} with each dict containing 1 to 6 of the \n 1025 named parameters above, to be processed recursively as args. \n 1026 A dict can also contain a single `lst` or `not_lst` argument. \n 1027 1028 ### Debugging info parameter: `dbg` 1029 A string that will print as part of logging output. Use to \n 1030 help identify origin of logging output. \n 1031 - \n 1032 """ 1033 # Reference for successful negative lookahead pattern, and 1034 # explanation of why it works: 1035 # https://stackoverflow.com/questions/406230/\ 1036 # regular-expression-to-match-a-line-that-doesnt-contain-a-word 1037 1038 global MAX_MATCHPROPS_ITERATIONS_REACHED 1039 global total_matchProps_iterations 1040 1041 # Return `False` immediately if screen does not have focus (e.g. Synergy), 1042 # but only after the guard clauses have had a chance to evaluate on 1043 # all possible uses of the function that may exist in the config. 1044 if MAX_MATCHPROPS_ITERATIONS_REACHED and not cnfg.screen_has_focus: 1045 # return False # Returning a boolean here causes as exception. Must return a callable! 1046 return lambda _: False 1047 1048 if total_matchProps_iterations >= MAX_MATCHPROPS_ITERATIONS: 1049 MAX_MATCHPROPS_ITERATIONS_REACHED = True 1050 bypass_guard_clauses = True 1051 else: 1052 total_matchProps_iterations += 1 1053 current_timestamp = time.time() 1054 1055 # 'STARTUP_TIMESTAMP' is a global variable, set when config is executed 1056 time_elapsed = current_timestamp - STARTUP_TIMESTAMP 1057 1058 # Bypass all guard clauses if more than a few seconds have passed since keymapper 1059 # started and loaded the config file. Inputs never change until keymapper 1060 # restarts and reloads the config file, so we don't need to keep checking. 1061 bypass_guard_clauses = time_elapsed > 6 1062 1063 logging_enabled = False 1064 1065 allowed_params = (clas, name, devn, not_clas, not_name, not_devn, 1066 numlk, capslk, cse, lst, not_lst, dbg) 1067 lst_dct_params = (clas, name, devn, not_clas, not_name, not_devn, 1068 numlk, capslk, cse) 1069 string_params = (clas, name, devn, not_clas, not_name, not_devn, dbg) 1070 1071 # This was using up a lot of CPU time, actually. Bad idea. 1072 # dct_param_strs = list(inspect.signature(matchProps).parameters.keys()) 1073 1074 # Static list of parameter names. Using this instead of `inspect` cuts CPU 1075 # usage considerably, for reasons I don't yet understand. Apparently the 1076 # keymapper is actually running the entire function again on each key 1077 # press and release, rather than just re-evaluating the inner closure. 1078 dct_param_strs = [ 1079 'clas', 'name', 'devn', 'not_clas', 'not_name', 'not_devn', 1080 'numlk', 'capslk', 'cse', 'lst', 'not_lst', 'dbg' 1081 ] 1082 1083 if not MAX_MATCHPROPS_ITERATIONS_REACHED or not bypass_guard_clauses: 1084 if all([x is None for x in allowed_params]): 1085 raise ValueError(f"\n\n(EE) matchProps(): Received no valid argument\n") 1086 if any([x not in (True, False, None) for x in (numlk, capslk, cse)]): 1087 raise TypeError(f"\n\n(EE) matchProps(): Params 'numlk|capslk|cse' are bools\n") 1088 if any([x is not None and not isinstance(x, str) for x in string_params]): 1089 raise TypeError( f"\n\n(EE) matchProps(): These parameters must be strings:" 1090 f"\n\t'clas|name|devn|not_clas|not_name|not_devn|dbg'\n") 1091 if clas and not_clas or name and not_name or devn and not_devn or lst and not_lst: 1092 raise ValueError( f"\n\n(EE) matchProps(): Do not mix positive and " 1093 f"negative match params for same property\n") 1094 1095 # consolidate positive and negative matching params into new vars 1096 # only one should be in use at a time (checked above) 1097 _lst = not_lst if lst is None else lst 1098 _clas = not_clas if clas is None else clas 1099 _name = not_name if name is None else name 1100 _devn = not_devn if devn is None else devn 1101 1102 # process lists of conditions 1103 if _lst is not None: 1104 1105 if not MAX_MATCHPROPS_ITERATIONS_REACHED or not bypass_guard_clauses: 1106 if any([x is not None for x in lst_dct_params]): 1107 raise TypeError(f"\n\n(EE) matchProps(): Param 'lst|not_lst' must be used alone\n") 1108 if not isinstance(_lst, list) or not all(isinstance(item, dict) for item in _lst): 1109 raise TypeError( 1110 f"\n\n(EE) matchProps(): Param 'lst|not_lst' wants a [list] of {{dicts}}\n") 1111 # verify that every {dict} in [list of dicts] only contains valid parameter names 1112 for dct in _lst: 1113 for param in list(dct.keys()): 1114 if param not in dct_param_strs: 1115 error(f"matchProps(): Invalid parameter: '{param}'") 1116 error(f"Invalid parameter is in this dict: \n\t{dct}") 1117 error(f"Dict is in this list:") 1118 for item in _lst: 1119 print(f"\t{item}") 1120 raise ValueError( 1121 f"\n(EE) matchProps(): Invalid parameter found in dict in list. " 1122 f"See log output before traceback.\n") 1123 1124 def _matchProps_Lst(ctx: KeyContext): 1125 if not cnfg.screen_has_focus: 1126 return False 1127 if not_lst is not None: 1128 if logging_enabled: print(f"## _matchProps_Lst()[not_lst] ## {dbg=}") 1129 return not any(matchProps(**dct)(ctx) for dct in not_lst) 1130 else: 1131 if logging_enabled: print(f"## _matchProps_Lst()[lst] ## {dbg=}") 1132 return any(matchProps(**dct)(ctx) for dct in lst) 1133 1134 return _matchProps_Lst # outer function returning inner function 1135 1136 # compile case insensitive regex object for given params, unless cse=True 1137 if _clas is not None: clas_rgx = re.compile(_clas, 0 if cse else re.I) 1138 if _name is not None: name_rgx = re.compile(_name, 0 if cse else re.I) 1139 if _devn is not None: devn_rgx = re.compile(_devn, 0 if cse else re.I) 1140 1141 def _matchProps(ctx: KeyContext): 1142 if not cnfg.screen_has_focus: 1143 return False 1144 1145 nt_err = 'ERR: matchProps: NoneType in ctx.' 1146 1147 # Full debug mode: use original cond_list approach for complete visibility 1148 if MATCHPROPS_FULL_DEBUG: 1149 cond_list = [] 1150 if numlk is not None: 1151 cond_list.append(numlk is ctx.numlock_on) 1152 if capslk is not None: 1153 cond_list.append(capslk is ctx.capslock_on) 1154 if _devn is not None: 1155 devn_match = re.search(devn_rgx, ctx.device_name or nt_err + 'device_name') 1156 cond_list.append(not devn_match if not_devn is not None else devn_match) 1157 if _clas is not None: 1158 clas_match = re.search(clas_rgx, ctx.wm_class or nt_err + 'wm_class') 1159 cond_list.append(not clas_match if not_clas is not None else clas_match) 1160 if _name is not None: 1161 name_match = re.search(name_rgx, ctx.wm_name or nt_err + 'wm_name') 1162 cond_list.append(not name_match if not_name is not None else name_match) 1163 print(f'#### CND_LST ({all(cond_list)}) #### {dbg=}') 1164 for elem in cond_list: 1165 print('##', re.sub(r'^.*span=.*\), ', '', str(elem)).replace('>','')) 1166 print('-------------------------------------------------------------------') 1167 return all(cond_list) 1168 1169 # Optimized path: short-circuit on first failure 1170 # Order: cheapest checks first, then most selective (devn), then clas, then name 1171 1172 # Bool checks - nearly free (identity comparison) 1173 if numlk is not None and numlk is not ctx.numlock_on: 1174 return False 1175 if capslk is not None and capslk is not ctx.capslock_on: 1176 return False 1177 1178 # Device check - most selective, eliminates most keystrokes from other devices 1179 if _devn is not None: 1180 devn_match = re.search(devn_rgx, ctx.device_name or nt_err + 'device_name') 1181 # XOR: fail if (negative match requested) == (match found) 1182 if (not_devn is not None) == bool(devn_match): 1183 return False 1184 1185 # Class check - moderately selective, often complex regex patterns 1186 if _clas is not None: 1187 clas_match = re.search(clas_rgx, ctx.wm_class or nt_err + 'wm_class') 1188 if (not_clas is not None) == bool(clas_match): 1189 return False 1190 1191 # Name check - least commonly used 1192 if _name is not None: 1193 name_match = re.search(name_rgx, ctx.wm_name or nt_err + 'wm_name') 1194 if (not_name is not None) == bool(name_match): 1195 return False 1196 1197 return True 1198 1199 return _matchProps # outer function returning inner function 1200 1201 1202 # Boolean variable to toggle Enter key state between F2 and Enter 1203 # True = Enter key sends F2, False = Enter key sends Enter 1204 _enter_is_F2 = True # DON'T CHANGE THIS! Must be set to True here. 1205 _enter_F2_last_app_class = None # Track which app set the state to be False 1206 1207 1208 def iEF2(combo_if_true, latch_or_combo_if_false, 1209 keep_value_if_true=False, keep_value_if_false=False): 1210 """ 1211 Formerly 'is_Enter_F2' 1212 Send a different combo for the Enter key based on the state of the `_enter_is_F2` variable, 1213 or latch the variable to True or False to control the Enter key output on the next use. 1214 1215 Store the app class of the file manager that sets the state variable to be False, and 1216 reset the state variable to True if the current app class does not match. 1217 1218 Args: 1219 combo_if_true: The combo to send if _enter_is_F2 is True. 1220 latch_or_combo_if_false: The combo to send if _enter_is_F2 is False, or 1221 a Boolean to latch _enter_is_F2 to a specific value. 1222 keep_value_if_true (opt.): If True, _enter_is_F2 will be kept True if it is currently True. 1223 If False, _enter_is_F2 will be set to False if it is currently True. 1224 keep_value_if_false (opt.): If True, _enter_is_F2 will be kept False if it is currently False. 1225 If False, _enter_is_F2 will be set to True if it is currently False. 1226 1227 Returns: 1228 A function that, when called, returns the appropriate combo based on the current 1229 state of _enter_is_F2 and the provided parameters, and updates _enter_is_F2 1230 based on the provided parameters. The current app class is obtained by checking 1231 the context object. 1232 1233 This enables a simulation of the macOS Finder's "Enter to rename" capability, allowing 1234 for complex control over the Enter key's behavior in various scenarios. 1235 """ 1236 def _is_Enter_F2(ctx: KeyContext): 1237 global _enter_is_F2, _enter_F2_last_app_class 1238 1239 # If last app class that set state to False is not None, and does not match current 1240 # app, reset the state var to True for initial behavior in new file manager windows. 1241 if _enter_F2_last_app_class and _enter_F2_last_app_class != ctx.wm_class: 1242 _enter_is_F2 = True 1243 _enter_F2_last_app_class = None 1244 1245 combo_list = [combo_if_true] 1246 if latch_or_combo_if_false in (True, False): # Latch variable to the provided bool value 1247 _enter_is_F2 = latch_or_combo_if_false 1248 elif _enter_is_F2: # If Enter is F2 now, set to be Enter next 1249 if keep_value_if_true is False: 1250 _enter_is_F2 = False 1251 else: # If Enter is Enter now, set to be F2 next 1252 combo_list = [latch_or_combo_if_false] 1253 if keep_value_if_false is False: 1254 _enter_is_F2 = True 1255 1256 # At this point we know whether the state var was set to True or False 1257 if not _enter_is_F2: 1258 # Record which app set state var to False 1259 _enter_F2_last_app_class = ctx.wm_class 1260 1261 # If state var is currently True, clear last app. 1262 elif _enter_is_F2: 1263 _enter_F2_last_app_class = None 1264 1265 debug(f"_is_Enter_F2: {combo_list = }") 1266 debug(f"_is_Enter_F2: {_enter_is_F2 = }") 1267 debug(f"_enter_F2_last_app_class: {_enter_F2_last_app_class = }") 1268 1269 return combo_list 1270 return _is_Enter_F2 1271 1272 1273 def iEF2NT(): 1274 """Feed `is_Enter_F2` function `None` and `True` as arguments, with short name""" 1275 return iEF2(None, True) 1276 1277 1278 def macro_tester(): 1279 """Type out a macro with useful info and a Unicode test. 1280 WARNING: Safe only for use in apps that accept text blocks/typing of many characters.""" 1281 def _macro_tester(ctx: KeyContext): 1282 return [ 1283 C("Enter"), 1284 ST(f"Class: '{ctx.wm_class}'"), C("Enter"), 1285 ST(f"Title: '{ctx.wm_name}'"), C("Enter"), 1286 ST(f"Keybd: '{ctx.device_name}'"), C("Enter"), 1287 ST(f"Keyboard type: '{KBTYPE}'"), C("Enter"), 1288 ST("Next test should come out on ONE LINE!"), C("Enter"), 1289 ST("Unicode and Shift Test: 🌹—€—\u2021—ÿ—\U00002021 12345 !@#$% |\\ !!!!!!"), 1290 C("Enter"), C("Enter"), 1291 ] 1292 return _macro_tester 1293 1294 1295 def is_valid_command(command): 1296 """Check if the command path is valid and executable""" 1297 return command and os.path.isfile(command) and os.access(command, os.X_OK) 1298 1299 1300 # Result will be None if DE is not in list OR if 'kdialog' not available. 1301 # kdialog_cmd = shutil.which('kdialog') if DESKTOP_ENV.casefold() in ['kde', 'lxqt'] else None 1302 # DISABLING KDIALOG BECAUSE IT KIND OF SUCKS QUITE A BIT COMPARED TO ZENITY/QARMA 1303 kdialog_cmd = shutil.which('kdialog') if DESKTOP_ENV.casefold() in ['kdialog_is_lame'] else None 1304 1305 1306 zenity_is_qarma = False 1307 1308 zenity_cmd = shutil.which('zenity-gtk') 1309 if not zenity_cmd: 1310 zenity_cmd = shutil.which('qarma') 1311 if zenity_cmd: 1312 zenity_is_qarma = True 1313 if not zenity_cmd: 1314 zenity_cmd = shutil.which('zenity') 1315 1316 debug(f"Zenity command path: '{zenity_cmd}'") 1317 1318 zenity_icon_option = None 1319 1320 if zenity_cmd: 1321 try: 1322 zenity_help_output = subprocess.check_output([zenity_cmd, '--help-info']) 1323 help_text = str(zenity_help_output) 1324 if '--icon=' in help_text: 1325 zenity_icon_option = '--icon=toshy_app_icon_rainbow' 1326 elif '--icon-name=' in help_text: 1327 zenity_icon_option = '--icon-name=toshy_app_icon_rainbow' 1328 except subprocess.CalledProcessError: 1329 pass # zenity --help-info failed, assume icon is not supported 1330 else: 1331 error('ERR: Zenity command is missing! Diagnostic dialog not available!') 1332 1333 1334 def notify_context(): 1335 """pop up a dialog with context info""" 1336 def _notify_context(ctx: KeyContext): 1337 1338 dialog_cmd = None 1339 nwln_str = '\n' 1340 1341 if kdialog_cmd: 1342 dialog_cmd = kdialog_cmd 1343 nwln_str = '<br>' 1344 elif zenity_cmd: 1345 dialog_cmd = zenity_cmd 1346 nwln_str = '<br>' if zenity_is_qarma else '\n' 1347 elif not zenity_cmd and not kdialog_cmd: 1348 error('ERR: Diagnostic dialog not available. Necessary commands missing.') 1349 return 1350 1351 if not is_valid_command(dialog_cmd): 1352 error(f"ERR: Dialog command not valid: '{dialog_cmd}'") 1353 return 1354 1355 # fix a problem with zenity and <tags> in text 1356 def escape_markup(text: str): 1357 return text.replace('&', '&').replace('<', '<').replace('>', '>') 1358 1359 ctx_clas = ctx.wm_class 1360 ctx_name = ctx.wm_name 1361 ctx_devn = ctx.device_name 1362 1363 # ------ following are all True/False 1364 ctx_term = matchProps(clas=termStr )(ctx) 1365 ctx_rmte = matchProps(clas=remoteStr )(ctx) 1366 ctx_fmgr = matchProps(clas=filemanagerStr )(ctx) 1367 ctx_brws = matchProps(clas=browsers_allStr )(ctx) 1368 ctx_vscd = matchProps(clas=vscodeStr )(ctx) 1369 1370 if matchProps(lst=dialogs_CloseWin_lod)(ctx) or matchProps(lst=dialogs_Escape_lod)(ctx): 1371 ctx_dlgs = True 1372 else: 1373 ctx_dlgs = False 1374 1375 message = ( 1376 f"<tt>" 1377 f"<b>Class:</b> '{escape_markup(ctx_clas)}' {nwln_str}" 1378 f"<b>Title:</b> '{escape_markup(ctx_name)}' {nwln_str}" 1379 f"{nwln_str}" 1380 f"<b>Input keyboard name:</b> '{ctx_devn}' {nwln_str}" 1381 f"<b>Device seen as type:</b> '{KBTYPE}' {nwln_str}" 1382 f"{nwln_str}" 1383 f"<b>Toshy config file sees this environment:</b> {nwln_str}" 1384 f"<b> • DISTRO_ID ____________</b> '{DISTRO_ID }' {nwln_str}" 1385 f"<b> • DISTRO_VER ___________</b> '{DISTRO_VER }' {nwln_str}" 1386 f"<b> • VARIANT_ID ___________</b> '{VARIANT_ID }' {nwln_str}" 1387 f"<b> • SESSION_TYPE _________</b> '{SESSION_TYPE }' {nwln_str}" 1388 f"<b> • DESKTOP_ENV __________</b> '{DESKTOP_ENV }' {nwln_str}" 1389 f"<b> • DE_MAJ_VER ___________</b> '{DE_MAJ_VER }' {nwln_str}" 1390 f"<b> • WINDOW_MGR ___________</b> '{WINDOW_MGR }' {nwln_str}" 1391 f"{nwln_str}" 1392 f"<b>Do any app class groups match on this window?:</b> {nwln_str}" 1393 f"<b> • Terminals ____________</b> '{ctx_term}' {nwln_str}" 1394 f"<b> • Remotes/VMs __________</b> '{ctx_rmte}' {nwln_str}" 1395 f"<b> • File Managers ________</b> '{ctx_fmgr}' {nwln_str}" 1396 f"<b> • Web Browsers _________</b> '{ctx_brws}' {nwln_str}" 1397 f"<b> • VSCode(s) ____________</b> '{ctx_vscd}' {nwln_str}" 1398 f"<b> • Dialogs ______________</b> '{ctx_dlgs}' {nwln_str}" 1399 f"{nwln_str}" 1400 f"<b> __________________________________________________ </b>{nwln_str}" 1401 f"<i>Keyboard shortcuts (Ctrl+C/Cmd+C) may not work here.</i>{nwln_str}" 1402 f"<i>Select text with mouse. Triple-click to select all. </i>{nwln_str}" 1403 f"<i>Right-click with mouse and choose 'Copy' from menu. </i>{nwln_str}" 1404 f"</tt>" 1405 ) 1406 1407 zenity_cmd_lst = [ zenity_cmd, '--info', '--no-wrap', 1408 '--title=Toshy Context Info', 1409 '--text=' + message ] 1410 1411 # insert the icon argument if it's supported 1412 if zenity_icon_option is not None: 1413 zenity_cmd_lst.insert(3, zenity_icon_option) 1414 1415 kdialog_cmd_lst = [kdialog_cmd, '--msgbox', message, '--title', 'Toshy Context Info'] 1416 # Add icon if needed: kdialog_cmd_lst += ['--icon', '/path/to/icon'] 1417 # Figure out why icon argument doesn't work. Need a proper icon theme folder? 1418 # DONE: Figured out that Kdialog does not support custom icons at all! 1419 kdialog_cmd_lst += ['--icon', 'toshy_app_icon_rainbow'] 1420 1421 if dialog_cmd == kdialog_cmd: 1422 subprocess.Popen(kdialog_cmd_lst, cwd=icons_dir, stderr=DEVNULL, stdout=DEVNULL) 1423 elif dialog_cmd == zenity_cmd: 1424 subprocess.Popen(zenity_cmd_lst, cwd=icons_dir, stderr=DEVNULL, stdout=DEVNULL) 1425 1426 # Optionally, also send a system notification: 1427 # ntfy.send_notification(message) 1428 return _notify_context 1429 1430 1431 def is_pre_GNOME_45(de_ver): 1432 """Utility function to check if GNOME version is older than GNOME 45""" 1433 if DESKTOP_ENV != 'gnome': 1434 # No need to go further if we aren't even in GNOME 1435 return False 1436 pre_G45_ver_lst = [44, 43, 42, 41, 40, 3] 1437 return str(de_ver).isdigit() and int(de_ver) in pre_G45_ver_lst 1438 1439 1440 def toggle_and_show_capslock_state(ctx: KeyContext): 1441 """ 1442 Show the (coming) state of CapsLock LED in a notification pop-up dialog. 1443 Then return the CapsLock key combo to toggle the CapsLock LED state. 1444 1445 No need to return inner closure because not used in conditionals. 1446 Do not use () to 'call' the function from output macro. Not needed. 1447 1448 Example usage: 1449 C("CapsLock"): toggle_and_show_capslock_state, # Toggle CapsLock, show notification 1450 """ 1451 1452 # Logic reversed because notification is constructed before combo is returned. 1453 message = 'CapsLock is ON' if not ctx.capslock_on else 'CapsLock is OFF' 1454 icon = 'input-caps-on-symbolic' if not ctx.capslock_on else 'window-close' 1455 ntfy.send_notification(message, icon, 'low', False) 1456 return C("CapsLock") 1457 1458 1459 def toggle_and_show_numlock_state(ctx: KeyContext): 1460 """ 1461 Show the (coming) state of NumLock LED in a notification pop-up dialog. 1462 Then return the NumLock key combo to toggle the NumLock LED state. 1463 1464 Only shows notification and toggles if 'Forced Numpad' pref is disabled. 1465 Like the isNumlockClearKey() function, returns Escape combo if 'Forced 1466 Numpad' feature is enabled. 'Forced Numpad' must be disabled to use 1467 NumLock key normally and see the notifications. 1468 1469 No need to return inner closure because not used in conditionals. 1470 Do not use () to 'call' the function from output macro. Not needed. 1471 1472 Example usage: 1473 C("NumLock"): toggle_and_show_numlock_state, # Toggle NumLock, show notification 1474 """ 1475 1476 if cnfg.forced_numpad: 1477 debug(f'Force Numpad is ON: NumLock key is "Clear" (sends Escape)') 1478 return C("Esc") 1479 else: 1480 # Logic reversed because notification is constructed before combo is returned. 1481 message = 'NumLock is ON' if not ctx.numlock_on else 'NumLock is OFF' 1482 icon = 'input-num-on' if not ctx.numlock_on else 'window-close' 1483 ntfy.send_notification(message, icon, 'low', False) 1484 return C("NumLock") 1485 1486 1487 1488 # Suggested location for adding custom functions for personal use. 1489 ################################################################################################### 1490 ### SLICE_MARK_START: user_custom_functions ### EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE 1491 1492 def open_launcher(ctx): 1493 subprocess.Popen(['vicinae', 'toggle'], stdout=DEVNULL, stderr=DEVNULL) 1494 return None 1495 1496 ### SLICE_MARK_END: user_custom_functions ### EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE 1497 ################################################################################################### 1498 1499 1500 1501 ################################### MULTI-TAP #################################### 1502 ### ### 1503 ### ### 1504 ### ███ ███ ██ ██ ██ ████████ ██ ████████ █████ ██████ ### 1505 ### ████ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 1506 ### ██ ████ ██ ██ ██ ██ ██ ██ █████ ██ ███████ ██████ ### 1507 ### ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 1508 ### ██ ██ ██████ ███████ ██ ██ ██ ██ ██ ██ ### 1509 ### ### 1510 ### ### 1511 #################################################################################### 1512 # Functions to support proper asyncio time-based multi-tap actions, without 1513 # blocking the single-tap usage of the same combo (unless desired). 1514 # 1515 # Until this EXPERIMENTAL feature moves into the keymapper, the API function 1516 # `multitap_config()` will need to be called from a section lower down, like 1517 # the "user_apps" editable slice, if user wants custom multi-tap timings. 1518 1519 1520 # Multi-tap configuration storage 1521 _MULTITAP_CONFIG = { 1522 'tap_interval': 0.25, # Default: 250ms between taps 1523 'min_tap_delay': 0.07, # Default: 70ms repeat protection 1524 } 1525 1526 1527 def get_output(): 1528 """Get the main keymapper's output instance""" 1529 try: 1530 # Access the transform module's _output at runtime 1531 if 'xwaykeyz.transform' in sys.modules: 1532 transform_module = sys.modules['xwaykeyz.transform'] 1533 if hasattr(transform_module, '_output'): 1534 debug("## multitap: Using main keymapper's _output instance") 1535 return transform_module._output 1536 except Exception as e: 1537 debug(f"## multitap: Error accessing output: {e}") 1538 return None 1539 1540 1541 def process_multitap_command(command, ctx): 1542 """Simplified recursive command processor based on handle_commands logic""" 1543 debug(f"## multitap: Processing command: {type(command)}") 1544 1545 if callable(command): 1546 # Handle functions like ST(), notify_context, etc. 1547 cmd_param_cnt = len(inspect.signature(command).parameters) 1548 debug(f"## multitap: Callable with {cmd_param_cnt} parameters") 1549 1550 if cmd_param_cnt == 0: 1551 result = command() 1552 else: 1553 result = command(ctx) 1554 1555 debug(f"## multitap: Callable returned: {type(result)}") 1556 1557 # Recursively process the result 1558 if result is not None: 1559 process_multitap_command(result, ctx) 1560 1561 elif isinstance(command, list): 1562 # Recursively process each item in the list 1563 debug(f"## multitap: Processing list with {len(command)} items") 1564 for i, item in enumerate(command): 1565 debug(f"## multitap: Processing list item {i+1}: {type(item)}") 1566 process_multitap_command(item, ctx) 1567 1568 else: 1569 # Handle direct objects (Combo, Key, etc.) 1570 output = get_output() 1571 if output and hasattr(command, '__class__'): 1572 class_name = command.__class__.__name__ 1573 debug(f"## multitap: Direct object class: {class_name}") 1574 1575 if 'Combo' in class_name: 1576 output.send_combo(command) 1577 debug(f"## multitap: Sent Combo object") 1578 elif 'Key' in class_name: 1579 output.send_key(command) 1580 debug(f"## multitap: Sent Key object") 1581 elif command is not None: 1582 debug(f"## multitap: Unknown command type: {class_name}") 1583 elif not output: 1584 debug(f"## multitap: No output available for command: {type(command)}") 1585 else: 1586 debug(f"## multitap: Command has no __class__: {command}") 1587 1588 1589 # Per-combo state tracking using action tuple as key 1590 tap_states: Dict[tuple, Dict[str, Any]] = {} 1591 1592 event_loop: Optional[asyncio.AbstractEventLoop] = None 1593 1594 1595 def get_loop() -> Optional[asyncio.AbstractEventLoop]: 1596 global event_loop 1597 if event_loop is None or event_loop.is_closed(): 1598 try: 1599 event_loop = asyncio.get_running_loop() 1600 except RuntimeError: 1601 event_loop = None 1602 return event_loop 1603 1604 1605 def multitap_config(tap_interval=None, min_tap_delay=None): 1606 """ 1607 Configure global multi-tap timing settings. 1608 1609 Args: 1610 tap_interval: Maximum time between taps in seconds (0.15 to 1.5) 1611 min_tap_delay: Minimum time between taps to avoid repeats (0.05 to 0.5) 1612 1613 Example: 1614 multitap_config( 1615 tap_interval=0.3, # 300ms between taps 1616 min_tap_delay=0.10 # 100ms repeat protection 1617 ) 1618 """ 1619 global _MULTITAP_CONFIG 1620 1621 if tap_interval is not None: 1622 if isinstance(tap_interval, (int, float)) and 0.15 <= tap_interval <= 1.5: 1623 _MULTITAP_CONFIG['tap_interval'] = float(tap_interval) 1624 debug(f"## multitap_config: Set tap_interval to {tap_interval}s") 1625 else: 1626 debug(f"## multitap_config: Invalid tap_interval {tap_interval}, must be 0.15-1.5 sec") 1627 1628 if min_tap_delay is not None: 1629 if isinstance(min_tap_delay, (int, float)) and 0.05 <= min_tap_delay <= 0.5: 1630 _MULTITAP_CONFIG['min_tap_delay'] = float(min_tap_delay) 1631 debug(f"## multitap_config: Set min_tap_delay to {min_tap_delay}s") 1632 else: 1633 debug(f"## multitap_config: Invalid min_tap_delay {min_tap_delay}, must be 0.05-0.5 sec") 1634 1635 # Ensure ignore time is less than interval time 1636 if _MULTITAP_CONFIG['min_tap_delay'] >= _MULTITAP_CONFIG['tap_interval']: 1637 original_delay = _MULTITAP_CONFIG['min_tap_delay'] 1638 _MULTITAP_CONFIG['min_tap_delay'] = _MULTITAP_CONFIG['tap_interval'] * 0.25 1639 debug(f"## multitap_config: min_tap_delay ({original_delay}s) >= tap_interval, " 1640 f"adjusted to {_MULTITAP_CONFIG['min_tap_delay']:.3f}s") 1641 1642 1643 def isMultiTap( tap_1_action: Optional[Callable] = None, 1644 tap_2_action: Optional[Callable] = None, 1645 tap_3_action: Optional[Callable] = None, 1646 tap_4_action: Optional[Callable] = None, 1647 tap_5_action: Optional[Callable] = None, 1648 tap_interval: float = None, 1649 min_tap_delay: float = None) -> Callable: 1650 """ 1651 Multi-tap handler that supports 1-5 taps with asyncio. 1652 1653 Args: 1654 tap_1_action: Function to call on single tap (can be None to block single-tap) 1655 tap_2_action: Function to call on double tap 1656 tap_3_action: Function to call on triple tap 1657 tap_4_action: Function to call on quadruple tap 1658 tap_5_action: Function to call on quintuple tap 1659 tap_interval: Max time between taps (None = use global config) 1660 min_tap_delay: Min time between taps to avoid key repeat (None = use global config) 1661 1662 Returns: 1663 Function that handles the tap detection 1664 """ 1665 1666 # Use global config values if not explicitly provided 1667 if tap_interval is None: 1668 tap_interval = _MULTITAP_CONFIG['tap_interval'] 1669 if min_tap_delay is None: 1670 min_tap_delay = _MULTITAP_CONFIG['min_tap_delay'] 1671 1672 # Use action tuple as unique identifier, converting lists to tuples for hashability 1673 def make_hashable(action): 1674 if isinstance(action, list): 1675 return tuple(make_hashable(item) for item in action) 1676 return action 1677 1678 action_key = ( 1679 make_hashable(tap_1_action), 1680 make_hashable(tap_2_action), 1681 make_hashable(tap_3_action), 1682 make_hashable(tap_4_action), 1683 make_hashable(tap_5_action) 1684 ) 1685 1686 def execute_action_for_tap_count( tap_count: int, 1687 captured_ctx, 1688 tap_1_action, 1689 tap_2_action, 1690 tap_3_action, 1691 tap_4_action, 1692 tap_5_action): 1693 """Execute the appropriate action based on tap count.""" 1694 actions = { 1695 1: tap_1_action, 1696 2: tap_2_action, 1697 3: tap_3_action, 1698 4: tap_4_action, 1699 5: tap_5_action 1700 } 1701 1702 action = actions.get(tap_count) 1703 if action is not None: 1704 try: 1705 debug(f"## isMultiTap: Executing {tap_count}-tap action for {action_key}") 1706 process_multitap_command(action, captured_ctx) 1707 debug(f"## isMultiTap: Completed {tap_count}-tap action for {action_key}") 1708 except Exception as e: 1709 debug(f"## isMultiTap: Error executing {tap_count}-tap action: {e}") 1710 else: 1711 debug(f"## isMultiTap: No action defined for {tap_count} taps on {action_key}") 1712 1713 def finalize_taps(action_key: tuple, captured_ctx): 1714 """Called when tap sequence is finalized.""" 1715 if action_key in tap_states: 1716 state = tap_states[action_key] 1717 tap_count = state['count'] 1718 debug(f"## isMultiTap: Finalizing {tap_count} taps for {action_key}") 1719 1720 # Get the actions before cleaning up state 1721 stored_tap_1_action = state['tap_1_action'] 1722 stored_tap_2_action = state['tap_2_action'] 1723 stored_tap_3_action = state['tap_3_action'] 1724 stored_tap_4_action = state['tap_4_action'] 1725 stored_tap_5_action = state['tap_5_action'] 1726 1727 # Clean up state 1728 del tap_states[action_key] 1729 1730 # Execute appropriate action with captured context 1731 execute_action_for_tap_count( tap_count, 1732 captured_ctx, 1733 stored_tap_1_action, 1734 stored_tap_2_action, 1735 stored_tap_3_action, 1736 stored_tap_4_action, 1737 stored_tap_5_action) 1738 1739 def _isMultiTap(ctx) -> None: 1740 loop = get_loop() 1741 if loop is None: 1742 debug(f"## isMultiTap: No event loop available for {action_key}") 1743 return None 1744 1745 current_time = time.time() 1746 1747 # Initialize or get existing state 1748 if action_key not in tap_states: 1749 tap_states[action_key] = { 1750 'count': 0, 1751 'last_tap_time': 0.0, 1752 'finalize_handle': None, 1753 'captured_ctx': ctx, 1754 # Store the individual actions in the state 1755 'tap_1_action': tap_1_action, 1756 'tap_2_action': tap_2_action, 1757 'tap_3_action': tap_3_action, 1758 'tap_4_action': tap_4_action, 1759 'tap_5_action': tap_5_action, 1760 } 1761 1762 state = tap_states[action_key] 1763 time_since_last = current_time - state['last_tap_time'] 1764 1765 # Check if this tap is too soon (key repeat protection) 1766 if state['count'] > 0 and time_since_last < min_tap_delay: 1767 debug( f"## isMultiTap: Ignoring repeat for {action_key} " 1768 f"(too soon: {time_since_last:.3f}s)") 1769 return None 1770 1771 # Check if this tap is too late (start new sequence) 1772 if state['count'] > 0 and time_since_last >= tap_interval: 1773 debug( f"## isMultiTap: Too late for {action_key} " 1774 f"(gap: {time_since_last:.3f}s), finalizing previous") 1775 # Finalize the previous sequence with its captured context 1776 finalize_taps(action_key, state['captured_ctx']) 1777 # Start new sequence with current context 1778 tap_states[action_key] = { 1779 'count': 0, 1780 'last_tap_time': 0.0, 1781 'finalize_handle': None, 1782 'captured_ctx': ctx, 1783 # Store the individual actions in the state 1784 'tap_1_action': tap_1_action, 1785 'tap_2_action': tap_2_action, 1786 'tap_3_action': tap_3_action, 1787 'tap_4_action': tap_4_action, 1788 'tap_5_action': tap_5_action, 1789 } 1790 state = tap_states[action_key] 1791 1792 # Cancel any pending finalization 1793 finalize_handle: Optional[asyncio.Handle] = state['finalize_handle'] 1794 if finalize_handle is not None: 1795 finalize_handle.cancel() 1796 state['finalize_handle'] = None 1797 1798 # Increment tap count 1799 state['count'] += 1 1800 state['last_tap_time'] = current_time 1801 1802 debug(f"## isMultiTap: Tap #{state['count']} for {action_key}") 1803 1804 # If we've exceeded max taps (5), ignore subsequent taps 1805 if state['count'] > 5: 1806 debug(f"## isMultiTap: Ignoring tap beyond maximum (tap #{state['count']})") 1807 return None 1808 1809 # Schedule finalization after the interval for all tap counts 1810 if state['tap_1_action'] or state['count'] > 1: 1811 captured_ctx = state['captured_ctx'] 1812 handle: asyncio.Handle = loop.call_later( 1813 tap_interval, 1814 lambda: finalize_taps(action_key, captured_ctx) # Pass captured context 1815 ) 1816 state['finalize_handle'] = handle 1817 debug(f"## isMultiTap: Scheduled finalization for {action_key} in {tap_interval}s") 1818 1819 # Return None since we're handling actions asynchronously 1820 return None 1821 1822 return _isMultiTap 1823 1824 1825 1826 ################################# MODMAPS #################################### 1827 ### ### 1828 ### ### 1829 ### ███ ███ ██████ ██████ ███ ███ █████ ██████ ███████ ### 1830 ### ████ ████ ██ ██ ██ ██ ████ ████ ██ ██ ██ ██ ██ ### 1831 ### ██ ████ ██ ██ ██ ██ ██ ██ ████ ██ ███████ ██████ ███████ ### 1832 ### ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 1833 ### ██ ██ ██████ ██████ ██ ██ ██ ██ ██ ███████ ### 1834 ### ### 1835 ### ### 1836 ################################################################################ 1837 ### Modmaps turn a key into a different key as long as the modmap is active 1838 ### The modified key can be used in shortcut combos as the new key 1839 1840 1841 # DO NOT REMOVE THIS MODMAP AND KEYMAP! 1842 # Special modmap to trigger the evaluation of the keyboard type when 1843 # any modifier key is pressed 1844 modmap("Trigger Modmap: Keyboard Type", { 1845 # This modmap must have all modifier keys inside it, so they will 1846 # all trigger the re-evaluation of the keyboard type. 1847 # The accompanying keymap can be empty and still accomplish 1848 # the same purpose of triggering a re-evaluation of the 1849 # keyboard type when any non-modifier key is pressed. 1850 Key.LEFT_META: Key.LEFT_META, 1851 Key.RIGHT_META: Key.RIGHT_META, 1852 Key.LEFT_ALT: Key.LEFT_ALT, 1853 Key.RIGHT_ALT: Key.RIGHT_ALT, 1854 Key.LEFT_CTRL: Key.LEFT_CTRL, 1855 Key.RIGHT_CTRL: Key.RIGHT_CTRL, 1856 Key.LEFT_SHIFT: Key.LEFT_SHIFT, 1857 Key.RIGHT_SHIFT: Key.RIGHT_SHIFT, 1858 }, when = lambda ctx: getKBtype()(ctx) ) # THIS CONDITIONAL MUST NEVER EVALUATE TO TRUE! 1859 # Special keymap to trigger the evaluation of the keyboard type when 1860 # any non-modifier key is pressed 1861 keymap("Trigger Keymap: Keyboard Type", { 1862 # Nothing needed here. 1863 }, when = lambda ctx: getKBtype()(ctx) ) 1864 1865 1866 def get_iEF2_context(): 1867 """Reset Enter-to-rename state variable to True, if the current 1868 application does not match on the file manager app class string""" 1869 def _get_iEF2_context(ctx: KeyContext): 1870 global _enter_is_F2, _enter_F2_last_app_class 1871 if not _enter_is_F2 and not matchProps(clas=filemanagerStr)(ctx): 1872 debug("Resetting Enter-to-rename state variable to True.") 1873 _enter_is_F2 = True 1874 _enter_F2_last_app_class = None 1875 1876 return False 1877 1878 return _get_iEF2_context 1879 1880 1881 # DO NOT REMOVE THIS MODMAP AND KEYMAP! 1882 # Special modmap to trigger the evaluation of the window context when 1883 # any modifier key is pressed 1884 modmap("Trigger Modmap: Enter-to-Rename Context", { 1885 # This modmap must have all modifier keys inside it, so they will 1886 # all trigger the re-evaluation of the window context. 1887 # The accompanying keymap can be empty and still accomplish 1888 # the same purpose of triggering a re-evaluation of the 1889 # window context when any non-modifier key is pressed. 1890 Key.LEFT_META: Key.LEFT_META, 1891 Key.RIGHT_META: Key.RIGHT_META, 1892 Key.LEFT_ALT: Key.LEFT_ALT, 1893 Key.RIGHT_ALT: Key.RIGHT_ALT, 1894 Key.LEFT_CTRL: Key.LEFT_CTRL, 1895 Key.RIGHT_CTRL: Key.RIGHT_CTRL, 1896 Key.LEFT_SHIFT: Key.LEFT_SHIFT, 1897 Key.RIGHT_SHIFT: Key.RIGHT_SHIFT, 1898 }, when = lambda ctx: get_iEF2_context()(ctx) ) # THIS CONDITIONAL MUST NEVER EVALUATE TO TRUE! 1899 # Special keymap to trigger the evaluation of the window context when 1900 # any non-modifier key is pressed 1901 keymap("Trigger Keymap: Enter-to-Rename Context", { 1902 # Nothing needed here. 1903 }, when = lambda ctx: get_iEF2_context()(ctx) ) 1904 1905 1906 modmap("Cond modmap - Media Arrows Fix",{ 1907 # Fix arrow keys with media functions instead of PgUp/PgDn/Home/End 1908 Key.PLAYPAUSE: Key.PAGE_UP, 1909 Key.STOPCD: Key.PAGE_DOWN, 1910 Key.PREVIOUSSONG: Key.HOME, 1911 Key.NEXTSONG: Key.END, 1912 }, when = lambda ctx: 1913 cnfg.media_arrows_fix and 1914 cnfg.screen_has_focus and 1915 matchProps(not_clas=remoteStr)(ctx) 1916 ) 1917 1918 1919 ################################################################################################### 1920 ### SLICE_MARK_START: exclude_kpad_devs ### EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE 1921 1922 # List of devices to add to the device exclusion list below this slice 1923 1924 exclude_kpad_devs_UserCustom_lst = [ 1925 # Example syntax: 1926 # 'My Keyboard Device', 1927 1928 ] 1929 1930 ### SLICE_MARK_END: exclude_kpad_devs ### EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE 1931 ################################################################################################### 1932 1933 1934 # DEPRECATED in favor of simple list: 1935 # # List of devices with keypads to exclude from Forced Numpad and GTK3 fix modmaps 1936 # exclude_kpad_devs_lod = [ 1937 # {devn: 'Razer Razer Naga X'}, 1938 # *exclude_kpad_devs_UserCustom_lod, 1939 # ] 1940 1941 # Ensure the DEPRECATED variable exists and is a list before attempting to access it 1942 # (New users WILL NOT have it in the marked slice above) 1943 exclude_kpad_devs_UserCustom_lod = locals().get('exclude_kpad_devs_UserCustom_lod', []) 1944 1945 # Ensure the NEW variable exists and is a list before attempting to access it 1946 # (Existing users MIGHT NOT have it in the marked slice above) 1947 exclude_kpad_devs_UserCustom_lst = locals().get('exclude_kpad_devs_UserCustom_lod', []) 1948 1949 DEPRECATED_exclude_kpad_devs_UserCustom_lst = [ 1950 device['devn'] for device in exclude_kpad_devs_UserCustom_lod 1951 if isinstance(exclude_kpad_devs_UserCustom_lod, list) 1952 ] 1953 1954 # List of devices with keypads to exclude from Forced Numpad and GTK3 fix modmaps 1955 exclude_kpad_devs_lst = [ 1956 'Razer Razer Naga X', 1957 *DEPRECATED_exclude_kpad_devs_UserCustom_lst, 1958 *exclude_kpad_devs_UserCustom_lst, 1959 ] 1960 exclude_kpad_devs_Str = toRgxStr(exclude_kpad_devs_lst) 1961 1962 modmap("Cond modmap - Forced Numpad feature",{ 1963 # Make numpad be a numpad regardless of Numlock state (like an Apple keyboard in macOS) 1964 Key.KP1: Key.KEY_1, 1965 Key.KP2: Key.KEY_2, 1966 Key.KP3: Key.KEY_3, 1967 Key.KP4: Key.KEY_4, 1968 Key.KP5: Key.KEY_5, 1969 Key.KP6: Key.KEY_6, 1970 Key.KP7: Key.KEY_7, 1971 Key.KP8: Key.KEY_8, 1972 Key.KP9: Key.KEY_9, 1973 Key.KP0: Key.KEY_0, 1974 Key.KPDOT: Key.DOT, 1975 Key.KPENTER: Key.ENTER, 1976 }, when = lambda ctx: 1977 cnfg.forced_numpad and 1978 cnfg.screen_has_focus and 1979 matchProps(not_devn=exclude_kpad_devs_Str)(ctx) and 1980 matchProps(not_clas=remoteStr)(ctx) 1981 ) 1982 1983 1984 modmap("Cond modmap - GTK3 numpad nav keys fix", { 1985 # Make numpad nav keys work correctly in GTK3 apps 1986 # Key.KP5: Key.X, # GTK3 numpad fix - TEST TO SEE IF WORKING 1987 # Numpad PgUp/PgDn/Home/End keys 1988 Key.KP9: Key.PAGE_UP, 1989 Key.KP3: Key.PAGE_DOWN, 1990 Key.KP7: Key.HOME, 1991 Key.KP1: Key.END, 1992 # Numpad arrow keys 1993 Key.KP8: Key.UP, 1994 Key.KP2: Key.DOWN, 1995 Key.KP4: Key.LEFT, 1996 Key.KP6: Key.RIGHT, 1997 # Numpad Insert/Delete/Enter keys 1998 Key.KP0: Key.INSERT, 1999 Key.KPDOT: Key.DELETE, 2000 Key.KPENTER: Key.ENTER, 2001 }, when = lambda ctx: 2002 not cnfg.forced_numpad and 2003 cnfg.screen_has_focus and 2004 matchProps(numlk=False)(ctx) and 2005 matchProps(not_devn=exclude_kpad_devs_Str)(ctx) and 2006 matchProps(not_clas=remoteStr)(ctx) 2007 ) 2008 2009 2010 # multipurpose_modmap("Optional Tweaks", 2011 # # {Key.ENTER: [Key.ENTER, Key.RIGHT_CTRL] # Enter2Cmd 2012 # # {Key.CAPSLOCK: [Key.ESC, Key.RIGHT_CTRL] # Caps2Esc 2013 # # {Key.LEFT_META: [Key.ESC, Key.RIGHT_CTRL] # Caps2Esc - Chromebook 2014 # { # Placeholder 2015 # }) 2016 2017 multipurpose_modmap("Enter2Cmd", { 2018 Key.ENTER: [Key.ENTER, Key.RIGHT_CTRL] # Enter2Cmd 2019 }, when = lambda ctx: 2020 cnfg.Enter2Ent_Cmd and 2021 cnfg.screen_has_focus and 2022 matchProps(not_clas=remoteStr)(ctx) 2023 ) 2024 2025 multipurpose_modmap("Caps2Esc - not Chromebook kbd", { 2026 Key.CAPSLOCK: [Key.ESC, Key.RIGHT_CTRL] # Caps2Esc - not Chromebook 2027 }, when = lambda ctx: 2028 cnfg.Caps2Esc_Cmd and 2029 cnfg.screen_has_focus and 2030 not isKBtype('Chromebook')(ctx) and 2031 matchProps(not_clas=remoteStr)(ctx) 2032 ) 2033 2034 multipurpose_modmap("Caps2Esc - Chromebook kbd", { 2035 Key.LEFT_META: [Key.ESC, Key.RIGHT_CTRL] # Caps2Esc - Chromebook 2036 }, when = lambda ctx: 2037 cnfg.Caps2Esc_Cmd and 2038 cnfg.screen_has_focus and 2039 isKBtype('Chromebook')(ctx) and 2040 matchProps(not_clas=remoteStr)(ctx) 2041 ) 2042 2043 2044 # THIS IS ALL SUPERCEDED BY THE NEW SOLUTION OF MONITORING THE SYNERGY LOG FILE! 2045 # Fix for avoiding modmapping when using Synergy keyboard/mouse sharing. 2046 # Synergy doesn't set a wm_class, so this may cause issues with other 2047 # applications that also don't set the wm_class. 2048 # Enable only if you use Synergy. (This is only for use with xkeysnail.) 2049 # define_conditional_modmap(lambda wm_class: wm_class == '', {}) 2050 ########################### 2051 # Suggestion (untested): 2052 # For use with keyszer, to avoid catching GNOME Shell task switcher (which has 2053 # an empty WM_CLASS but sets a WM_NAME): 2054 # modmap("Synergy fix", {}, when = lambda ctx: ctx.wm_class == '' and ctx.wm_name == '') 2055 # If Synergy actually sets a WM_NAME like GNOME Shell does, you'd need to use 2056 # one of these alternatives: 2057 # modmap("Synergy fix", {}, when = lambda ctx: ctx.wm_class == '' and ctx.wm_name == 'SYNERGY_WM_NAME') 2058 # Or: 2059 # modmap("Synergy fix", {}, when = lambda ctx: ctx.wm_class == '' and not ctx.wm_name == 'gnome-shell') 2060 # PROBLEM: When GNOME desktop has focus, it sets no window info at all (no class, no name/title) 2061 2062 2063 # [Global GUI conditional modmaps] Change modifier keys as in xmodmap 2064 modmap("Cond modmap - GUI - Caps2Cmd - not Cbk kdb", { 2065 Key.CAPSLOCK: Key.RIGHT_CTRL, # Caps2Cmd 2066 }, when = lambda ctx: 2067 cnfg.Caps2Cmd and 2068 cnfg.screen_has_focus and 2069 not isKBtype('Chromebook')(ctx) and 2070 matchProps(not_clas=terms_and_remotes_Str)(ctx) 2071 ) 2072 modmap("Cond modmap - GUI - Caps2Cmd - Cbk kdb", { 2073 Key.LEFT_META: Key.RIGHT_CTRL, # Caps2Cmd - Chromebook 2074 }, when = lambda ctx: 2075 cnfg.Caps2Cmd and 2076 cnfg.screen_has_focus and 2077 isKBtype('Chromebook')(ctx) and 2078 matchProps(not_clas=terms_and_remotes_Str)(ctx) 2079 ) 2080 modmap("Cond modmap - GUI - IBM kbd - multi_lang OFF", { 2081 # - IBM 2082 Key.RIGHT_ALT: Key.RIGHT_CTRL, # IBM - Multi-language (Remove) 2083 Key.RIGHT_CTRL: Key.RIGHT_ALT, # IBM - Multi-language (Remove) 2084 }, when = lambda ctx: 2085 not cnfg.multi_lang and 2086 cnfg.screen_has_focus and 2087 isKBtype('IBM', map='mmap GUI IBM ML-OFF')(ctx) and 2088 matchProps(not_clas=terms_and_remotes_Str)(ctx) 2089 ) 2090 modmap("Cond modmap - GUI - IBM kbd", { 2091 # - IBM 2092 Key.CAPSLOCK: Key.LEFT_META, # IBM 2093 Key.LEFT_CTRL: Key.LEFT_ALT, # IBM 2094 Key.LEFT_ALT: Key.RIGHT_CTRL, # IBM 2095 }, when = lambda ctx: 2096 cnfg.screen_has_focus and 2097 isKBtype('IBM', map='mmap GUI IBM')(ctx) and 2098 matchProps(not_clas=terms_and_remotes_Str)(ctx) 2099 ) 2100 modmap("Cond modmap - GUI - Cbk kbd - multi_lang OFF", { 2101 # - Chromebook 2102 Key.RIGHT_ALT: Key.RIGHT_CTRL, # Chromebook - Multi-language (Remove) 2103 Key.RIGHT_CTRL: Key.RIGHT_ALT, # Chromebook - Multi-language (Remove) 2104 }, when = lambda ctx: 2105 not cnfg.multi_lang and 2106 cnfg.screen_has_focus and 2107 isKBtype('Chromebook', map='mmap GUI Cbk ML-OFF')(ctx) and 2108 matchProps(not_clas=terms_and_remotes_Str)(ctx) 2109 ) 2110 modmap("Cond modmap - GUI - Cbk kbd", { 2111 # - Chromebook 2112 Key.LEFT_CTRL: Key.LEFT_ALT, # Chromebook 2113 Key.LEFT_ALT: Key.RIGHT_CTRL, # Chromebook 2114 }, when = lambda ctx: 2115 cnfg.screen_has_focus and 2116 isKBtype('Chromebook', map='mmap GUI Cbk')(ctx) and 2117 matchProps(not_clas=terms_and_remotes_Str)(ctx) 2118 ) 2119 modmap("Cond modmap - GUI - Win kbd - multi_lang OFF", { 2120 # - Default Mac/Win 2121 # - Default Win 2122 Key.RIGHT_ALT: Key.RIGHT_CTRL, # WinMac - Multi-language (Remove) 2123 Key.RIGHT_META: Key.RIGHT_ALT, # WinMac - Multi-language (Remove) 2124 Key.RIGHT_CTRL: Key.RIGHT_META, # WinMac - Multi-language (Remove) 2125 }, when = lambda ctx: 2126 not cnfg.multi_lang and 2127 cnfg.screen_has_focus and 2128 isKBtype('Windows', map='mmap GUI Win ML-OFF')(ctx) and 2129 matchProps(not_clas=terms_and_remotes_Str)(ctx) 2130 ) 2131 modmap("Cond modmap - GUI - Win kbd", { 2132 # - Default Mac/Win 2133 # - Default Win 2134 Key.LEFT_CTRL: Key.LEFT_META, # WinMac 2135 Key.LEFT_META: Key.LEFT_ALT, # WinMac 2136 Key.LEFT_ALT: Key.RIGHT_CTRL, # WinMac 2137 }, when = lambda ctx: 2138 cnfg.screen_has_focus and 2139 isKBtype('Windows', map='mmap GUI Win')(ctx) and 2140 matchProps(not_clas=terms_and_remotes_Str)(ctx) 2141 ) 2142 modmap("Cond modmap - GUI - Mac kbd - multi_lang OFF", { 2143 # - Mac Only 2144 Key.RIGHT_META: Key.RIGHT_CTRL, # Mac - Multi-language (Remove) 2145 Key.RIGHT_CTRL: Key.RIGHT_META, # Mac - Multi-language (Remove) 2146 }, when = lambda ctx: 2147 not cnfg.multi_lang and 2148 cnfg.screen_has_focus and 2149 isKBtype('Apple', map='mmap GUI Apple ML-OFF')(ctx) and 2150 matchProps(not_clas=terms_and_remotes_Str)(ctx) 2151 ) 2152 modmap("Cond modmap - GUI - Mac kbd", { 2153 # - Mac Only 2154 Key.LEFT_CTRL: Key.LEFT_META, # Mac 2155 Key.LEFT_META: Key.RIGHT_CTRL, # Mac 2156 }, when = lambda ctx: 2157 cnfg.screen_has_focus and 2158 isKBtype('Apple', map='mmap GUI Apple')(ctx) and 2159 matchProps(not_clas=terms_and_remotes_Str)(ctx) 2160 ) 2161 2162 2163 # [Global Terminals conditional modmaps] Change modifier keys in certain applications 2164 modmap("Cond modmap - Terms - IBM kbd - multi_lang OFF", { 2165 # - IBM - Multi-language 2166 Key.RIGHT_ALT: Key.RIGHT_CTRL, # IBM - Multi-language (Remove) 2167 }, when = lambda ctx: 2168 not cnfg.multi_lang and 2169 cnfg.screen_has_focus and 2170 isKBtype('IBM', map='mmap terms IBM ML-OFF')(ctx) and 2171 matchProps(clas=termStr)(ctx) 2172 ) 2173 modmap("Cond modmap - Terms - IBM kbd", { 2174 # - IBM 2175 Key.CAPSLOCK: Key.LEFT_ALT, # IBM 2176 # Left Ctrl stays Left Ctrl 2177 Key.LEFT_ALT: Key.RIGHT_CTRL, # IBM 2178 # Right Meta does not exist on IBM keyboards 2179 Key.RIGHT_CTRL: Key.RIGHT_ALT, # IBM 2180 }, when = lambda ctx: 2181 cnfg.screen_has_focus and 2182 isKBtype('IBM', map='mmap terms IBM')(ctx) and 2183 matchProps(clas=termStr)(ctx) 2184 ) 2185 modmap("Cond modmap - Terms - Cbk kbd - multi_lang OFF", { 2186 # - Chromebook 2187 Key.RIGHT_ALT: Key.RIGHT_CTRL, # Chromebook - Multi-language (Remove) 2188 }, when = lambda ctx: 2189 not cnfg.multi_lang and 2190 cnfg.screen_has_focus and 2191 isKBtype('Chromebook', map='mmap terms Cbk ML-OFF')(ctx) and 2192 matchProps(clas=termStr)(ctx) 2193 ) 2194 modmap("Cond modmap - Terms - Cbk kbd", { 2195 # - Chromebook 2196 # Left Ctrl Stays Left Ctrl 2197 Key.LEFT_META: Key.LEFT_ALT, # Chromebook 2198 Key.LEFT_ALT: Key.RIGHT_CTRL, # Chromebook 2199 # Right Meta does not exist on chromebooks 2200 Key.RIGHT_CTRL: Key.RIGHT_ALT, # Chromebook 2201 }, when = lambda ctx: 2202 cnfg.screen_has_focus and 2203 isKBtype('Chromebook', map='mmap terms Cbk')(ctx) and 2204 matchProps(clas=termStr)(ctx) 2205 ) 2206 modmap("Cond modmap - Terms - Win kbd - multi_lang OFF", { 2207 # - Default Mac/Win 2208 # - Default Win 2209 Key.RIGHT_ALT: Key.RIGHT_CTRL, # WinMac - Multi-language (Remove) 2210 Key.RIGHT_META: Key.RIGHT_ALT, # WinMac - Multi-language (Remove) 2211 Key.RIGHT_CTRL: Key.LEFT_CTRL, # WinMac - Multi-language (Remove) 2212 }, when = lambda ctx: 2213 not cnfg.multi_lang and 2214 cnfg.screen_has_focus and 2215 isKBtype('Windows', map='mmap terms Win ML-OFF')(ctx) and 2216 matchProps(clas=termStr)(ctx) 2217 ) 2218 modmap("Cond modmap - Terms - Win kbd", { 2219 # - Default Mac/Win 2220 # - Default Win 2221 Key.LEFT_CTRL: Key.LEFT_CTRL, # WinMac 2222 Key.LEFT_META: Key.LEFT_ALT, # WinMac 2223 Key.LEFT_ALT: Key.RIGHT_CTRL, # WinMac 2224 }, when = lambda ctx: 2225 cnfg.screen_has_focus and 2226 isKBtype('Windows', map='mmap terms Win')(ctx) and 2227 matchProps(clas=termStr)(ctx) 2228 ) 2229 modmap("Cond modmap - Terms - Mac kbd - multi_lang OFF", { 2230 # - Mac Only 2231 # Left Ctrl Stays Left Ctrl 2232 Key.RIGHT_META: Key.RIGHT_CTRL, # Mac - Multi-language (Remove) 2233 Key.RIGHT_CTRL: Key.LEFT_CTRL, # Mac - Multi-language (Remove) 2234 }, when = lambda ctx: 2235 not cnfg.multi_lang and 2236 cnfg.screen_has_focus and 2237 isKBtype('Apple', map='mmap terms Apple ML-OFF')(ctx) and 2238 matchProps(clas=termStr)(ctx) 2239 ) 2240 modmap("Cond modmap - Terms - Mac kbd", { 2241 # - Mac Only 2242 # Left Ctrl Stays Left Ctrl 2243 Key.LEFT_CTRL: Key.LEFT_CTRL, # Mac (self-modmap) 2244 Key.LEFT_ALT: Key.LEFT_ALT, # Mac (self-modmap) 2245 Key.LEFT_META: Key.RIGHT_CTRL, # Mac 2246 Key.RIGHT_ALT: Key.RIGHT_ALT, # Mac (self-modmap) 2247 }, when = lambda ctx: 2248 cnfg.screen_has_focus and 2249 isKBtype('Apple', map='mmap terms Apple')(ctx) and 2250 matchProps(clas=termStr)(ctx) 2251 ) 2252 2253 2254 2255 # Suggested location for adding custom modmaps for personal use. 2256 ################################################################################################### 2257 ### SLICE_MARK_START: user_custom_modmaps ### EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE 2258 2259 2260 2261 ### SLICE_MARK_END: user_custom_modmaps ### EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE 2262 ################################################################################################### 2263 2264 2265 2266 ########################## FORCED NUMPAD ############################ 2267 ### ### 2268 ### ### 2269 ### ███ ██ ██ ██ ███ ███ ██████ █████ ██████ ### 2270 ### ████ ██ ██ ██ ████ ████ ██ ██ ██ ██ ██ ██ ### 2271 ### ██ ██ ██ ██ ██ ██ ████ ██ ██████ ███████ ██ ██ ### 2272 ### ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 2273 ### ██ ████ ██████ ██ ██ ██ ██ ██ ██████ ### 2274 ### ### 2275 ### ### 2276 ####################################################################### 2277 2278 # Force the numpad to always be a numpad, like a Mac keyboard on macOS 2279 # Numlock key becomes "Clear" key for use with calculator (sends Escape) 2280 # Toggle feature on/off with Option+Numlock (Fn+Numlock might work on 2281 # Apple keyboards that have Fn key) 2282 2283 2284 def toggle_forced_numpad(): 2285 """Toggle the Forced Numpad feature on or off.""" 2286 cnfg.forced_numpad = not cnfg.forced_numpad 2287 cnfg.save_settings() 2288 ntfy.forced_numpad(cnfg.forced_numpad) 2289 2290 2291 def isNumlockClearKey(): 2292 """NumLock key is Clear (Esc) if Forced Numpad feature is enabled.""" 2293 return C("Esc") if cnfg.forced_numpad else C("Numlock") 2294 2295 2296 2297 ########################### OPTSPECIALCHARS ############################## 2298 ### ### 2299 ### ### 2300 ### ██████ ██████ ████████ ███████ ██████ ███████ ██████ ### 2301 ### ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 2302 ### ██ ██ ██████ ██ ███████ ██████ █████ ██ ### 2303 ### ██ ██ ██ ██ ██ ██ ██ ██ ### 2304 ### ██████ ██ ██ ███████ ██ ███████ ██████ ### 2305 ### ### 2306 ### ### 2307 ############################################################################ 2308 2309 ########### START OF OPTION KEY SPECIAL CHARACTER ENTRY SCHEME ############# 2310 ################################################################################# 2311 ### Full list of special characters on Apple US and ABC Extended keyboard layouts: 2312 ### https://github.org/RedBearAK/optspecialchars 2313 2314 2315 def apple_logo_alert(): 2316 """Show a notification about needing Baskerville Old Face font for displaying Apple logo""" 2317 if applelogoalert_enabled: 2318 ntfy.apple_logo() 2319 2320 2321 2322 ###################################################################################### 2323 ### ### 2324 ### ### 2325 ### ██████ ███████ █████ ██████ ██ ██ ███████ ██ ██ ███████ ### 2326 ### ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 2327 ### ██ ██ █████ ███████ ██ ██ █████ █████ ████ ███████ ### 2328 ### ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 2329 ### ██████ ███████ ██ ██ ██████ ██ ██ ███████ ██ ███████ ### 2330 ### ### 2331 ### ### 2332 ###################################################################################### 2333 2334 # variables to store dead keys diacritic accent character Unicode address 2335 ac_Chr_main = None 2336 _ac_Chr_copy = None 2337 2338 2339 def set_dead_key_char(hex_unicode_addr): 2340 """ 2341 Set the value of the dead keys accent character 2342 variable, and its alternate. Does not clear the 2343 value of the alternate variable if input is 2344 falsy (such as None or 0x0000 or 0). This allows 2345 the value to be used after the tripwire keymap 2346 clears the main variable value. 2347 """ 2348 def _set_dead_key_char(): 2349 global ac_Chr_main 2350 global _ac_Chr_copy 2351 # if hex_unicode_addr is None or hex_unicode_addr == 0x0000: 2352 # pass 2353 # else: 2354 if hex_unicode_addr: 2355 _ac_Chr_copy = hex_unicode_addr 2356 ac_Chr_main = hex_unicode_addr 2357 # 2358 return _set_dead_key_char 2359 2360 2361 def get_dead_key_char(): 2362 """Get the value of the alternate dead key accent character 2363 variable, and print/type the resulting Unicode character.""" 2364 def _get_dead_key_char(): 2365 global _ac_Chr_copy 2366 return UC(_ac_Chr_copy) 2367 # 2368 return _get_dead_key_char 2369 2370 2371 def setDK(*args, **kwargs): 2372 """wrapper for `set_dead_key_char` function, to provide shorter name""" 2373 return set_dead_key_char(*args, **kwargs) 2374 2375 2376 def getDK(): 2377 """wrapper for `get_dead_key_char` function, to provide shorter name""" 2378 return get_dead_key_char() 2379 2380 2381 # setDK = set_dead_key_char 2382 # getDK = get_dead_key_char 2383 2384 deadkeys_ABC = [ 2385 # Dead keys on ABC Extended keyboard layout (25, plus substitutes for problematic chars) 2386 0x0060, # Dead Keys Accent: Grave 2387 0x02C6, # Dead Keys Accent: Circumflex 2388 0x02D9, # Dead Keys Accent: Dot Above 2389 0x00B4, # Dead Keys Accent: Acute 2390 2391 ### Combining Double Grave has issues (spacing behavior) - substituting {U+02F5} 2392 0x030F, # Dead Keys Accent: Combining Double Grave 2393 ### Substitute for Double Grave: Modifier Letter Middle Double Grave Accent 2394 0x02F5, # Dead Keys Accent: Double Grave - substitute for {U+030F} 2395 2396 0x00A8, # Dead Keys Accent: Umlaut/Diaeresis 2397 0x02BC, # Dead Keys Accent: Apostrophe/Horn 2398 0x002C, # Dead Keys Accent: Comma Below 2399 0x00AF, # Dead Keys Accent: Macron/Line Above 2400 2401 ### Combining Inverted Breve has issues (spacing behavior) - substituting {U+1D16} 2402 0x0311, # Dead Keys Accent: Combining Inverted Breve 2403 ### Substitute for Inverted Breve: Latin Small Letter Top Half O 2404 0x1D16, # Dead Keys Accent: Inverted Breve - substitute for {U+0311} 2405 2406 ### Combining Tilde Below has issues (spacing behavior) - substituting {U+02F7} 2407 0x0330, # Dead Keys Accent: Combining Tilde Below 2408 ### Substitute for Tilde Below: Modifier Letter Low Tilde 2409 2410 0x02F7, # Dead Keys Accent: Tilde Below 2411 0x2038, # Dead Keys Accent: Caret/Circumflex Below 2412 0x02CD, # Dead Keys Accent: Low Macron/Line Below 2413 0x02DD, # Dead Keys Accent: Double Acute 2414 0x02DA, # Dead Keys Accent: Ring Above 2415 0x002D, # Dead Keys Accent: Stroke/Hyphen-Minus 2416 0x2116, # Dead Keys Accent: Numero Sign 2417 0x02C0, # Dead Keys Accent: Hook Above/Glottal Stop 2418 0x002E, # Dead Keys Accent: Dot Below 2419 0x00B8, # Dead Keys Accent: Cedilla/Cedille 2420 0x02C7, # Dead Keys Accent: Caron/hacek 2421 0x02D8, # Dead Keys Accent: Breve 2422 0x02DC, # Dead Keys Accent: Tilde 2423 0x02DB, # Dead Keys Accent: Ogonek 2424 0x0294, # Dead Keys Accent: Hook 2425 ] 2426 2427 deadkeys_US = [ 2428 # Dead keys on standard US keyboard layout (5) 2429 0x0060, # Dead Keys Accent: Grave 2430 0x00B4, # Dead Keys Accent: Acute 2431 0x00A8, # Dead Keys Accent: Umlaut/Diaeresis 2432 0x02C6, # Dead Keys Accent: Circumflex 2433 0x02DC, # Dead Keys Accent: Tilde 2434 ] 2435 2436 # Join the two dead keys lists together 2437 deadkeys_list = [] 2438 deadkeys_list.extend(deadkeys_ABC) 2439 deadkeys_list.extend(deadkeys_US) 2440 2441 2442 ##################################### 2443 ### DEAD KEYS KEYMAPS - START ### 2444 ##################################### 2445 # Dead Keys conditional keymaps 2446 # only active when the dead key variable matches 2447 # and the layout variable matches (US or ABC) 2448 2449 ################################################# 2450 ### DEAD KEYS KEYMAPS - ABC EXTENDED LAYOUT ### 2451 ################################################# 2452 2453 keymap("DK-ABC - Grave", { 2454 # Option+Grave {U+0060} 2455 # Valid keys: 2456 # a e i n o u v w y 2457 # A E I N O U V W Y 2458 C("A"): UC(0x00E0), # à Latin Small Letter A with Grave 2459 C("E"): UC(0x00E8), # è Latin Small Letter E with Grave 2460 C("I"): UC(0x00EC), # ì Latin Small Letter I with Grave 2461 C("N"): UC(0x01F9), # ǹ Latin Small Letter N with Grave 2462 C("O"): UC(0x00F2), # ò Latin Small Letter O with Grave 2463 C("U"): UC(0x00F9), # ù Latin Small Letter U with Grave 2464 C("V"): UC(0x01DC), # ǜ Latin Small Letter U w/Diaeresis and Grave 2465 C("W"): UC(0x1E81), # ẁ Latin Small Letter W with Grave 2466 C("Y"): UC(0x1EF3), # ỳ Latin Small Letter Y with Grave 2467 C("Shift-A"): UC(0x00C0), # À Latin Capital Letter A with Grave 2468 C("Shift-E"): UC(0x00C8), # È Latin Capital Letter E with Grave 2469 C("Shift-I"): UC(0x00CC), # Ì Latin Capital Letter I with Grave 2470 C("Shift-N"): UC(0x01F8), # Ǹ Latin Capital Letter N with Grave 2471 C("Shift-O"): UC(0x00D2), # Ò Latin Capital Letter O with Grave 2472 C("Shift-U"): UC(0x00D9), # Ù Latin Capital Letter U with Grave 2473 C("Shift-V"): UC(0x01DB), # Ǜ Latin Capital Letter U w/Diaeresis and Grave 2474 C("Shift-W"): UC(0x1E80), # Ẁ Latin Capital Letter W with Grave 2475 C("Shift-Y"): UC(0x1EF2), # Ỳ Latin Capital Letter Y with Grave 2476 }, when = lambda _: ac_Chr_main == 0x0060 and cnfg.optspec_layout == 'ABC') 2477 2478 keymap("DK-ABC - Circumflex", { 2479 # Option+6 {U+02C6} 2480 # Valid keys: 2481 # a c e g h i j m n o s u w y z 2482 # A C E G H I J M N O S U W Y Z 2483 C("A"): UC(0x00E2), # â Latin Small Letter A with Circumflex 2484 C("C"): UC(0x0109), # ĉ Latin Small Letter C with Circumflex 2485 C("E"): UC(0x00EA), # ê Latin Small Letter E with Circumflex 2486 C("G"): UC(0x011D), # ĝ Latin Small Letter G with Circumflex 2487 C("H"): UC(0x0125), # ĥ Latin Small Letter H with Circumflex 2488 C("I"): UC(0x00EE), # î Latin Small Letter I with Circumflex 2489 C("J"): UC(0x0135), # ĵ Latin Small Letter J with Circumflex 2490 C("M"): [UC(0x006D),UC(0x0302)], # m̂ Latin Small Letter M with Circumflex 2491 C("N"): [UC(0x006E),UC(0x0302)], # n̂ Latin Small Letter N with Circumflex 2492 C("O"): UC(0x00F4), # ô Latin Small Letter O with Circumflex 2493 C("S"): UC(0x015D), # ŝ Latin Small Letter S with Circumflex 2494 C("U"): UC(0x00FB), # û Latin Small Letter U with Circumflex 2495 C("W"): UC(0x0175), # ŵ Latin Small Letter W with Circumflex 2496 C("Y"): UC(0x0177), # ŷ Latin Small Letter Y with Circumflex 2497 C("Z"): UC(0x1E91), # ẑ Latin Small Letter Z with Circumflex 2498 C("Shift-A"): UC(0x00C2), #  Latin Capital Letter A with Circumflex 2499 C("Shift-C"): UC(0x0108), # Ĉ Latin Capital Letter C with Circumflex 2500 C("Shift-E"): UC(0x00CA), # Ê Latin Capital Letter E with Circumflex 2501 C("Shift-G"): UC(0x011C), # Ĝ Latin Capital Letter G with Circumflex 2502 C("Shift-H"): UC(0x0124), # Ĥ Latin Capital Letter H with Circumflex 2503 C("Shift-I"): UC(0x00CE), # Î Latin Capital Letter I with Circumflex 2504 C("Shift-J"): UC(0x0134), # Ĵ Latin Capital Letter J with Circumflex 2505 C("Shift-M"): [UC(0x004D),UC(0x0302)], # M̂ Latin Capital Letter M with Circumflex 2506 C("Shift-N"): [UC(0x004E),UC(0x0302)], # N̂ Latin Capital Letter N with Circumflex 2507 C("Shift-O"): UC(0x00D4), # Ô Latin Capital Letter O with Circumflex 2508 C("Shift-S"): UC(0x015C), # Ŝ Latin Capital Letter S with Circumflex 2509 C("Shift-U"): UC(0x00DB), # Û Latin Capital Letter U with Circumflex 2510 C("Shift-W"): UC(0x0174), # Ŵ Latin Capital Letter W with Circumflex 2511 C("Shift-Y"): UC(0x0176), # Ŷ Latin Capital Letter Y with Circumflex 2512 C("Shift-Z"): UC(0x1E90), # Ẑ Latin Capital Letter Z with Circumflex 2513 }, when = lambda _: ac_Chr_main == 0x02C6 and cnfg.optspec_layout == 'ABC') 2514 2515 keymap("DK-ABC - Dot Above", { 2516 # Option+W {U+02D9} 2517 # Valid keys: 2518 # a b c d e f g h i m n o p r s t w x y z 2519 # A B C D E F G H I M N O P R S T W X Y Z 2520 C("A"): UC(0x0227), # ȧ Latin Small Letter A with Dot Above 2521 C("B"): UC(0x1E03), # ḃ Latin Small Letter B with Dot Above 2522 C("C"): UC(0x010B), # ċ Latin Small Letter C with Dot Above 2523 C("D"): UC(0x1E0B), # ḋ Latin Small Letter D with Dot Above 2524 C("E"): UC(0x0117), # ė Latin Small Letter E with Dot Above 2525 C("F"): UC(0x1E1F), # ḟ Latin Small Letter F with Dot Above 2526 C("G"): UC(0x0121), # ġ Latin Small Letter G with Dot Above 2527 C("H"): UC(0x1E23), # ḣ Latin Small Letter H with Dot Above 2528 C("I"): UC(0x0131), # ı Latin Small Letter Dotless I 2529 C("M"): UC(0x1E41), # ṁ Latin Small Letter M with Dot Above 2530 C("N"): UC(0x1E45), # ṅ Latin Small Letter N with Dot Above 2531 C("O"): UC(0x022F), # ȯ Latin Small Letter O with Dot Above 2532 C("P"): UC(0x1E57), # ṗ Latin Small Letter P with Dot Above 2533 C("R"): UC(0x1E59), # ṙ Latin Small Letter R with Dot Above 2534 C("S"): UC(0x1E61), # ṡ Latin Small Letter S with Dot Above 2535 C("T"): UC(0x1E6B), # ṫ Latin Small Letter T with Dot Above 2536 C("W"): UC(0x1E87), # ẇ Latin Small Letter W with Dot Above 2537 C("X"): UC(0x1E8B), # ẋ Latin Small Letter X with Dot Above 2538 C("Y"): UC(0x1E8F), # ẏ Latin Small Letter Y with Dot Above 2539 C("Z"): UC(0x017C), # ż Latin Small Letter Z with Dot Above 2540 C("Shift-A"): UC(0x0226), # Ȧ Latin Capital Letter A with Dot Above 2541 C("Shift-B"): UC(0x1E02), # Ḃ Latin Capital Letter B with Dot Above 2542 C("Shift-C"): UC(0x010A), # Ċ Latin Capital Letter C with Dot Above 2543 C("Shift-D"): UC(0x1E0A), # Ḋ Latin Capital Letter D with Dot Above 2544 C("Shift-E"): UC(0x0116), # Ė Latin Capital Letter E with Dot Above 2545 C("Shift-F"): UC(0x1E1E), # Ḟ Latin Capital Letter F with Dot Above 2546 C("Shift-G"): UC(0x0120), # Ġ Latin Capital Letter G with Dot Above 2547 C("Shift-H"): UC(0x1E22), # Ḣ Latin Capital Letter H with Dot Above 2548 C("Shift-I"): UC(0x0130), # İ Latin Capital Letter I with Dot Above 2549 C("Shift-M"): UC(0x1E40), # Ṁ Latin Capital Letter M with Dot Above 2550 C("Shift-N"): UC(0x1E44), # Ṅ Latin Capital Letter N with Dot Above 2551 C("Shift-O"): UC(0x022E), # Ȯ Latin Capital Letter O with Dot Above 2552 C("Shift-P"): UC(0x1E56), # Ṗ Latin Capital Letter P with Dot Above 2553 C("Shift-R"): UC(0x1E58), # Ṙ Latin Capital Letter R with Dot Above 2554 C("Shift-S"): UC(0x1E60), # Ṡ Latin Capital Letter S with Dot Above 2555 C("Shift-T"): UC(0x1E6A), # Ṫ Latin Capital Letter T with Dot Above 2556 C("Shift-W"): UC(0x1E86), # Ẇ Latin Capital Letter W with Dot Above 2557 C("Shift-X"): UC(0x1E8A), # Ẋ Latin Capital Letter X with Dot Above 2558 C("Shift-Y"): UC(0x1E8E), # Ẏ Latin Capital Letter Y with Dot Above 2559 C("Shift-Z"): UC(0x017B), # Ż Latin Capital Letter Z with Dot Above 2560 }, when = lambda _: ac_Chr_main == 0x02D9 and cnfg.optspec_layout == 'ABC') 2561 2562 keymap("DK-ABC - Acute", { 2563 # Option+E {U+00B4} 2564 # Valid keys: 2565 # a c e g i m n o p r s w y z 2566 # A C E G I M N O P R S W Y Z 2567 C("A"): UC(0x00E1), # á Latin Small Letter A with Acute 2568 C("C"): UC(0x0107), # ć Latin Small Letter C with Acute 2569 C("E"): UC(0x00E9), # é Latin Small Letter E with Acute 2570 C("G"): UC(0x01F5), # ǵ Latin Small Letter G with Acute 2571 C("I"): UC(0x00ED), # í Latin Small Letter I with Acute 2572 C("M"): UC(0x1E3F), # ḿ Latin Small Letter M with Acute 2573 C("N"): UC(0x0144), # ń Latin Small Letter N with Acute 2574 C("O"): UC(0x00F3), # ó Latin Small Letter O with Acute 2575 C("P"): UC(0x1E55), # ṕ Latin Small Letter P with Acute 2576 C("R"): UC(0x0155), # ŕ Latin Small Letter R with Acute 2577 C("S"): UC(0x015B), # ś Latin Small Letter S with Acute 2578 C("W"): UC(0x1E83), # ẃ Latin Small Letter W with Acute 2579 C("Y"): UC(0x00FD), # ý Latin Small Letter Y with Acute 2580 C("Z"): UC(0x017A), # ź Latin Small Letter Z with Acute 2581 C("Shift-A"): UC(0x00C1), # Á Latin Capital Letter A with Acute 2582 C("Shift-C"): UC(0x0106), # Ć Latin Capital Letter C with Acute 2583 C("Shift-E"): UC(0x00C9), # É Latin Capital Letter E with Acute 2584 C("Shift-G"): UC(0x01F4), # Ǵ Latin Capital Letter G with Acute 2585 C("Shift-I"): UC(0x00CD), # Í Latin Capital Letter I with Acute 2586 C("Shift-M"): UC(0x1E3E), # Ḿ Latin Capital Letter M with Acute 2587 C("Shift-N"): UC(0x0143), # Ń Latin Capital Letter N with Acute 2588 C("Shift-O"): UC(0x00D3), # Ó Latin Capital Letter O with Acute 2589 C("Shift-P"): UC(0x1E54), # Ṕ Latin Capital Letter P with Acute 2590 C("Shift-R"): UC(0x0154), # Ŕ Latin Capital Letter R with Acute 2591 C("Shift-S"): UC(0x015A), # Ś Latin Capital Letter S with Acute 2592 C("Shift-W"): UC(0x1E82), # Ẃ Latin Capital Letter W with Acute 2593 C("Shift-Y"): UC(0x00DD), # Ý Latin Capital Letter Y with Acute 2594 C("Shift-Z"): UC(0x0179), # Ź Latin Capital Letter Z with Acute 2595 }, when = lambda _: ac_Chr_main == 0x00B4 and cnfg.optspec_layout == 'ABC') 2596 2597 keymap("DK-ABC - Double Grave", { 2598 # Shift+Option+Y {U+030F} [uses {U+02F5} Modifier Letter Middle Double Grave Accent] 2599 # Valid keys: 2600 # a e i o r u 2601 # A E I O R U 2602 C("A"): UC(0x0201), # ȁ Latin Small Letter A with Double Grave 2603 C("E"): UC(0x0205), # ȅ Latin Small Letter E with Double Grave 2604 C("I"): UC(0x0209), # ȉ Latin Small Letter I with Double Grave 2605 C("O"): UC(0x020D), # ȍ Latin Small Letter O with Double Grave 2606 C("R"): UC(0x0211), # ȑ Latin Small Letter R with Double Grave 2607 C("U"): UC(0x0215), # ȕ Latin Small Letter U with Double Grave 2608 C("Shift-A"): UC(0x0200), # Ȁ Latin Capital Letter A with Double Grave 2609 C("Shift-E"): UC(0x0204), # Ȅ Latin Capital Letter E with Double Grave 2610 C("Shift-I"): UC(0x0208), # Ȉ Latin Capital Letter I with Double Grave 2611 C("Shift-O"): UC(0x020C), # Ȍ Latin Capital Letter O with Double Grave 2612 C("Shift-R"): UC(0x0210), # Ȑ Latin Capital Letter R with Double Grave 2613 C("Shift-U"): UC(0x0214), # Ȕ Latin Capital Letter U with Double Grave 2614 }, when=lambda _: ac_Chr_main in [0x030F, 0x02F5] and cnfg.optspec_layout == 'ABC') 2615 2616 keymap("DK-ABC - Umlaut/Diaeresis", { 2617 # Option+U {U+00A8} 2618 # Valid keys: 2619 # a e h i o t u w x y 2620 # A E H I O T U W X Y 2621 C("A"): UC(0x00E4), # ä Latin Small Letter A with Diaeresis 2622 C("E"): UC(0x00EB), # ë Latin Small Letter E with Diaeresis 2623 C("H"): UC(0x1E27), # ḧ Latin Small Letter H with Diaeresis 2624 C("I"): UC(0x00EF), # ï Latin Small Letter I with Diaeresis 2625 C("O"): UC(0x00F6), # ö Latin Small Letter O with Diaeresis 2626 C("T"): UC(0x1E97), # ẗ Latin Small Letter T with Diaeresis 2627 C("U"): UC(0x00FC), # ü Latin Small Letter U with Diaeresis 2628 C("W"): UC(0x1E85), # ẅ Latin Small Letter W with Diaeresis 2629 C("X"): UC(0x1E8D), # ẍ Latin Small Letter X with Diaeresis 2630 C("Y"): UC(0x00FF), # ÿ Latin Small Letter Y with Diaeresis 2631 C("Shift-A"): UC(0x00C4), # Ä Latin Capital Letter A with Diaeresis 2632 C("Shift-E"): UC(0x00CB), # Ë Latin Capital Letter E with Diaeresis 2633 C("Shift-H"): UC(0x1E26), # Ḧ Latin Capital Letter H with Diaeresis 2634 C("Shift-I"): UC(0x00CF), # Ï Latin Capital Letter I with Diaeresis 2635 C("Shift-O"): UC(0x00D6), # Ö Latin Capital Letter O with Diaeresis 2636 C("Shift-T"): [UC(0x0054),UC(0x0308)], # T̈ Latin Capital Letter T with Diaeresis 2637 C("Shift-U"): UC(0x00DC), # Ü Latin Capital Letter U with Diaeresis 2638 C("Shift-W"): UC(0x1E84), # Ẅ Latin Capital Letter W with Diaeresis 2639 C("Shift-X"): UC(0x1E8C), # Ẍ Latin Capital Letter X with Diaeresis 2640 C("Shift-Y"): UC(0x0178), # Ÿ Latin Capital Letter Y with Diaeresis 2641 }, when = lambda _: ac_Chr_main == 0x00A8 and cnfg.optspec_layout == 'ABC') 2642 2643 keymap("DK-ABC - Apostrophe/Horn", { 2644 # Option+I {U+02BC} 2645 # Valid keys: 2646 # o u 2647 # O U 2648 C("O"): UC(0x01A1), # ơ Latin Small Letter O with Horn 2649 C("U"): UC(0x01B0), # ư Latin Small Letter U with Horn 2650 C("Shift-O"): UC(0x01A0), # Ơ Latin Capital Letter O with Horn 2651 C("Shift-U"): UC(0x01AF), # Ư Latin Capital Letter U with Horn 2652 }, when = lambda _: ac_Chr_main == 0x02BC and cnfg.optspec_layout == 'ABC') 2653 2654 keymap("DK-ABC - Comma Below", { 2655 # Option+P {U+002C} 2656 # Valid keys: 2657 # s t 2658 # S T 2659 C("S"): UC(0x0219), # ș Latin Small Letter S with Comma Below 2660 C("T"): UC(0x021B), # ț Latin Small Letter T with Comma Below 2661 C("Shift-S"): UC(0x0218), # Ș Latin Capital Letter S with Comma Below 2662 C("Shift-T"): UC(0x021A), # Ț Latin Capital Letter T with Comma Below 2663 }, when = lambda _: ac_Chr_main == 0x002C and cnfg.optspec_layout == 'ABC') 2664 2665 keymap("DK-ABC - Macron/Line Above", { 2666 # Option+A {U+00AF} 2667 # Valid keys: 2668 # a e g i l o r s v y z 2669 # A E G I L O R S V Y Z 2670 C("A"): UC(0x0101), # ā Latin Small Letter A with Macron 2671 C("E"): UC(0x0113), # ē Latin Small Letter E with Macron 2672 C("G"): UC(0x1E21), # ḡ Latin Small Letter G with Macron 2673 C("I"): UC(0x012B), # ī Latin Small Letter I with Macron 2674 C("L"): [UC(0x006C),UC(0x0304),UC(0x0323)], # ḹ Latin Small Letter L w/Macron and Dot Below 2675 C("O"): UC(0x014D), # ō Latin Small Letter O with Macron 2676 C("R"): [UC(0x0072),UC(0x0304),UC(0x0323)], # ṝ Latin Small Letter R w/Macron and Dot Below 2677 C("S"): [UC(0x0073),UC(0x0304)], # s̄ Latin Small Letter S with Macron 2678 C("V"): UC(0x01D6), # ǖ Latin Small Letter U with Diaeresis and Macron 2679 C("Y"): UC(0x0233), # ȳ Latin Small Letter Y with Macron 2680 C("Z"): [UC(0x007A),UC(0x0304)], # z̄ Latin Small Letter Z with Macron 2681 C("Shift-A"): UC(0x0100), # Ā Latin Capital Letter A with Macron 2682 C("Shift-E"): UC(0x0112), # Ē Latin Capital Letter E with Macron 2683 C("Shift-G"): UC(0x1E20), # Ḡ Latin Capital Letter G with Macron 2684 C("Shift-I"): UC(0x012A), # Ī Latin Capital Letter I with Macron 2685 C("Shift-L"): [UC(0x004C),UC(0x0304),UC(0x0323)], # Ḹ Latin Capital Letter L w/Macron and Dot Below 2686 C("Shift-O"): UC(0x014C), # Ō Latin Capital Letter O with Macron 2687 C("Shift-R"): [UC(0x0052),UC(0x0304),UC(0x0323)], # Ṝ Latin Capital Letter R w/Macron and Dot Below 2688 C("Shift-S"): [UC(0x0053),UC(0x0304)], # S̄ Latin Capital Letter S with Macron 2689 C("Shift-V"): UC(0x01D5), # Ǖ Latin Capital Letter U with Diaeresis and Macron 2690 C("Shift-Y"): UC(0x0232), # Ȳ Latin Capital Letter Y with Macron 2691 C("Shift-Z"): [UC(0x005A),UC(0x0304)], # Z̄ Latin Capital Letter Z with Macron 2692 }, when = lambda _: ac_Chr_main == 0x00AF and cnfg.optspec_layout == 'ABC') 2693 2694 keymap("DK-ABC - Inverted Breve", { 2695 # Shift+Option+S {U+0311} [uses {U+1D16} as a substitute] 2696 # Valid keys: 2697 # a e i o r u 2698 # A E I O R U 2699 C("A"): UC(0x0203), # ȃ Latin Small Letter A with Inverted Breve 2700 C("E"): UC(0x0207), # ȇ Latin Small Letter E with Inverted Breve 2701 C("I"): UC(0x020B), # ȋ Latin Small Letter I with Inverted Breve 2702 C("O"): UC(0x020F), # ȏ Latin Small Letter O with Inverted Breve 2703 C("R"): UC(0x0213), # ȓ Latin Small Letter R with Inverted Breve 2704 C("U"): UC(0x0217), # ȗ Latin Small Letter U with Inverted Breve 2705 C("Shift-A"): UC(0x0202), # Ȃ Latin Capital Letter A with Inverted Breve 2706 C("Shift-E"): UC(0x0206), # Ȇ Latin Capital Letter E with Inverted Breve 2707 C("Shift-I"): UC(0x020A), # Ȋ Latin Capital Letter I with Inverted Breve 2708 C("Shift-O"): UC(0x020E), # Ȏ Latin Capital Letter O with Inverted Breve 2709 C("Shift-R"): UC(0x0212), # Ȓ Latin Capital Letter R with Inverted Breve 2710 C("Shift-U"): UC(0x0216), # Ȗ Latin Capital Letter U with Inverted Breve 2711 }, when = lambda _: ac_Chr_main in [0x0311, 0x1D16] and cnfg.optspec_layout == 'ABC') 2712 2713 keymap("DK-ABC - Tilde Below", { 2714 # Shift+Option+F {U+0330} [uses {U+02F7} as a substitute] 2715 # Valid keys: 2716 # e i u 2717 # E I U 2718 C("E"): UC(0x1E1B), # ḛ Latin Small Letter E with Tilde Below 2719 C("I"): UC(0x1E2D), # ḭ Latin Small Letter I with Tilde Below 2720 C("U"): UC(0x1E75), # ṵ Latin Small Letter U with Tilde Below 2721 C("Shift-E"): UC(0x1E1A), # Ḛ Latin Capital Letter E with Tilde Below 2722 C("Shift-I"): UC(0x1E2C), # Ḭ Latin Capital Letter I with Tilde Below 2723 C("Shift-U"): UC(0x1E74), # Ṵ Latin Capital Letter U with Tilde Below 2724 }, when = lambda _: ac_Chr_main in [0x0330, 0x02F7] and cnfg.optspec_layout == 'ABC') 2725 2726 keymap("DK-ABC - Caret/Circumflex Below", { 2727 # Shift+Option+G {U+2038} 2728 # Valid keys: 2729 # d e l n t u 2730 # D E L N T U 2731 C("D"): UC(0x1E13), # ḓ Latin Small Letter D with Circumflex Below 2732 C("E"): UC(0x1E19), # ḙ Latin Small Letter E with Circumflex Below 2733 C("L"): UC(0x1E3D), # ḽ Latin Small Letter L with Circumflex Below 2734 C("N"): UC(0x1E4B), # ṋ Latin Small Letter N with Circumflex Below 2735 C("T"): UC(0x1E71), # ṱ Latin Small Letter T with Circumflex Below 2736 C("U"): UC(0x1E77), # ṷ Latin Small Letter U with Circumflex Below 2737 C("Shift-D"): UC(0x1E12), # Ḓ Latin Capital Letter D with Circumflex Below 2738 C("Shift-E"): UC(0x1E18), # Ḙ Latin Capital Letter E with Circumflex Below 2739 C("Shift-L"): UC(0x1E3C), # Ḽ Latin Capital Letter L with Circumflex Below 2740 C("Shift-N"): UC(0x1E4A), # Ṋ Latin Capital Letter N with Circumflex Below 2741 C("Shift-T"): UC(0x1E70), # Ṱ Latin Capital Letter T with Circumflex Below 2742 C("Shift-U"): UC(0x1E76), # Ṷ Latin Capital Letter U with Circumflex Below 2743 }, when = lambda _: ac_Chr_main == 0x2038 and cnfg.optspec_layout == 'ABC') 2744 2745 keymap("DK-ABC - Low Macron/Line Below", { 2746 # Option+H {U+02CD} 2747 # Valid keys: 2748 # b d h k l n r t z 2749 # B D H K L N R T Z 2750 C("B"): UC(0x1E07), # ḇ Latin Small Letter B with Line Below 2751 C("D"): UC(0x1E0F), # ḏ Latin Small Letter D with Line Below 2752 C("H"): UC(0x1E96), # ẖ Latin Small Letter H with Line Below 2753 C("K"): UC(0x1E35), # ḵ Latin Small Letter K with Line Below 2754 C("L"): UC(0x1E3B), # ḻ Latin Small Letter L with Line Below 2755 C("N"): UC(0x1E49), # ṉ Latin Small Letter N with Line Below 2756 C("R"): UC(0x1E5F), # ṟ Latin Small Letter R with Line Below 2757 C("T"): UC(0x1E6F), # ṯ Latin Small Letter T with Line Below 2758 C("Z"): UC(0x1E95), # ẕ Latin Small Letter Z with Line Below 2759 C("Shift-B"): UC(0x1E06), # Ḇ Latin Capital Letter B with Line Below 2760 C("Shift-D"): UC(0x1E0E), # Ḏ Latin Capital Letter D with Line Below 2761 C("Shift-H"): [UC(0x0048),UC(0x0331)], # H̱ Latin Capital Letter H with Line Below 2762 C("Shift-K"): UC(0x1E34), # Ḵ Latin Capital Letter K with Line Below 2763 C("Shift-L"): UC(0x1E3A), # Ḻ Latin Capital Letter L with Line Below 2764 C("Shift-N"): UC(0x1E48), # Ṉ Latin Capital Letter N with Line Below 2765 C("Shift-R"): UC(0x1E5E), # Ṟ Latin Capital Letter R with Line Below 2766 C("Shift-T"): UC(0x1E6E), # Ṯ Latin Capital Letter T with Line Below 2767 C("Shift-Z"): UC(0x1E94), # Ẕ Latin Capital Letter Z with Line Below 2768 }, when = lambda _: ac_Chr_main == 0x02CD and cnfg.optspec_layout == 'ABC') 2769 2770 keymap("DK-ABC - Double Acute", { 2771 # Option+J {U+02DD} 2772 # Valid keys: 2773 # o u 2774 # O U 2775 C("O"): UC(0x0151), # ő Latin Small Letter O with Double Acute 2776 C("U"): UC(0x0171), # ű Latin Small Letter U with Double Acute 2777 C("Shift-O"): UC(0x0150), # Ő Latin Capital Letter O with Double Acute 2778 C("Shift-U"): UC(0x0170), # Ű Latin Capital Letter U with Double Acute 2779 }, when = lambda _: ac_Chr_main == 0x02DD and cnfg.optspec_layout == 'ABC') 2780 2781 keymap("DK-ABC - Ring Above", { 2782 # Option+K {U+02DA} 2783 # Valid keys: 2784 # a e o u w y 2785 # A E O U W Y 2786 C("A"): UC(0x00E5), # å Latin Small Letter A with Ring Above 2787 C("E"): [UC(0x0065),UC(0x030A)], # e̊ Latin Small Letter E with Ring Above 2788 C("O"): [UC(0x006F),UC(0x030A)], # o̊ Latin Small Letter O with Ring Above 2789 C("U"): UC(0x016F), # ů Latin Small Letter U with Ring Above 2790 C("W"): UC(0x1E98), # ẘ Latin Small Letter W with Ring Above 2791 C("Y"): UC(0x1E99), # ẙ Latin Small Letter Y with Ring Above 2792 C("Shift-A"): UC(0x00C5), # Å Latin Capital Letter A with Ring Above 2793 C("Shift-E"): [UC(0x0045),UC(0x030A)], # E̊ Latin Capital Letter E with Ring Above 2794 C("Shift-O"): [UC(0x004F),UC(0x030A)], # O̊ Latin Capital Letter O with Ring Above 2795 C("Shift-U"): UC(0x016E), # Ů Latin Capital Letter U with Ring Above 2796 C("Shift-W"): [UC(0x0057),UC(0x030A)], # W̊ Latin Capital Letter W with Ring Above 2797 C("Shift-Y"): [UC(0x0059),UC(0x030A)], # Y̊ Latin Capital Letter Y with Ring Above 2798 }, when = lambda _: ac_Chr_main == 0x02DA and cnfg.optspec_layout == 'ABC') 2799 2800 keymap("DK-ABC - Stroke/Hyphen-Minus", { 2801 # Option+L {U+002D} 2802 # Valid keys: 2803 # b d g h i l o t u z 2804 # D G H I L O T Z 2805 C("B"): UC(0x0180), # ƀ Latin Small Letter B with Stroke 2806 C("D"): UC(0x0111), # đ Latin Small Letter D with Stroke 2807 C("G"): UC(0x01E5), # ǥ Latin Small Letter G with Stroke 2808 C("H"): UC(0x0127), # ħ Latin Small Letter H with Stroke 2809 C("I"): UC(0x0268), # ɨ Latin Small Letter I with Stroke 2810 C("L"): UC(0x0142), # ł Latin Small Letter L with Stroke 2811 C("O"): UC(0x0275), # ɵ Latin Small Letter Barred O 2812 C("T"): UC(0x0167), # ŧ Latin Small Letter T with Stroke 2813 C("U"): UC(0x0289), # ʉ Latin Small Letter U Bar 2814 C("Z"): UC(0x01B6), # ƶ Latin Small Letter Z with Stroke 2815 C("Shift-D"): UC(0x0110), # Đ Latin Capital Letter D with Stroke 2816 C("Shift-G"): UC(0x01E4), # Ǥ Latin Capital Letter G with Stroke 2817 C("Shift-H"): UC(0x0126), # Ħ Latin Capital Letter H with Stroke 2818 C("Shift-I"): UC(0x0197), # Ɨ Latin Capital Letter I with Stroke 2819 C("Shift-L"): UC(0x0141), # Ł Latin Capital Letter L with Stroke 2820 C("Shift-O"): UC(0x019F), # Ɵ Latin Capital Letter O with Middle Tilde 2821 C("Shift-T"): UC(0x0166), # Ŧ Latin Capital Letter T with Stroke 2822 C("Shift-Z"): UC(0x01B5), # Ƶ Latin Capital Letter Z with Stroke 2823 }, when = lambda _: ac_Chr_main == 0x002D and cnfg.optspec_layout == 'ABC') 2824 2825 keymap("DK-ABC - Numero Sign", { 2826 # Shift+Option+Semicolon {U+2116} 2827 # Valid keys: 2828 # 2 3 5 6 7 8 (digits with Option) 2829 # 2 3 5 6 8 (digits with Shift+Option) 2830 # a c e g h j k m n q r s u v w y z (letters with Option) 2831 # A C E G H J K M N Q R U W Y Z (letters with Shift+Option) 2832 C("3"): UC(0x025B), # ɛ Latin Small Letter Open E 2833 C("5"): UC(0x01BD), # ƽ Latin Small Letter Tone Five 2834 C("2"): UC(0x01A8), # ƨ Latin Small Letter Tone Two 2835 C("6"): UC(0x0185), # ƅ Latin Small Letter Tone Six 2836 C("7"): UC(0x204A), # ⁊ Tironian Sign Et 2837 C("8"): UC(0x0223), # ȣ Latin Small Letter Ou 2838 C("Shift-2"): UC(0x01A7), # Ƨ Latin Capital Letter Tone Two 2839 C("Shift-3"): UC(0x0190), # Ɛ Latin Capital Letter Open E 2840 C("Shift-5"): UC(0x01BC), # Ƽ Latin Capital Letter Tone Five 2841 C("Shift-6"): UC(0x0184), # Ƅ Latin Capital Letter Tone Six 2842 C("Shift-8"): UC(0x0222), # Ȣ Latin Capital Letter Ou 2843 C("a"): UC(0x0259), # ə Latin Small Letter Schwa 2844 C("c"): UC(0x0254), # ɔ Latin Small Letter Open O 2845 C("e"): UC(0x01DD), # ǝ Latin Small Letter Turned E 2846 C("g"): UC(0x0263), # ɣ Latin Small Letter Gamma 2847 C("h"): UC(0x0195), # ƕ Latin Small Letter Hv 2848 C("j"): UC(0x019E), # ƞ Latin Small Letter N with Long Right Leg 2849 C("k"): UC(0x0138), # ĸ Latin Small Letter Kra 2850 C("m"): UC(0x026F), # ɯ Latin Small Letter Turned M 2851 C("n"): UC(0x014B), # ŋ Latin Small Letter Eng 2852 C("q"): UC(0x01A3), # ƣ Latin Small Letter Oi 2853 C("r"): UC(0x0280), # ʀ Latin Letter Small Capital R 2854 C("s"): UC(0x017F), # ſ Latin Small Letter Long S 2855 C("u"): UC(0x028A), # ʊ Latin Small Letter Upsilon 2856 C("v"): UC(0x028C), # ʌ Latin Small Letter Turned V 2857 C("w"): UC(0x01BF), # ƿ Latin Letter Wynn 2858 C("y"): UC(0x021D), # ȝ Latin Small Letter Yogh 2859 C("z"): UC(0x0292), # ʒ Latin Small Letter Ezh 2860 C("Shift-A"): UC(0x018F), # Ə Latin Capital Letter Schwa 2861 C("Shift-C"): UC(0x0186), # Ɔ Latin Capital Letter Open O 2862 C("Shift-E"): UC(0x018E), # Ǝ Latin Capital Letter Reversed E 2863 C("Shift-G"): UC(0x0194), # Ɣ Latin Capital Letter Gamma 2864 C("Shift-H"): UC(0x01F6), # Ƕ Latin Capital Letter Hwair 2865 C("Shift-J"): UC(0x0220), # Ƞ Latin Capital Letter N with Long Right Leg 2866 C("Shift-K"): [UC(0x004B),UC(0x2019)], # K’ Latin Capital Letter K with Apostrophe 2867 C("Shift-M"): UC(0x019C), # Ɯ Latin Capital Letter Turned M 2868 C("Shift-N"): UC(0x014A), # Ŋ Latin Capital Letter Eng 2869 C("Shift-Q"): UC(0x01A2), # Ƣ Latin Capital Letter Oi 2870 C("Shift-R"): UC(0x01A6), # Ʀ Latin Letter Yr 2871 C("Shift-U"): UC(0x01B1), # Ʊ Latin Capital Letter Upsilon 2872 C("Shift-W"): UC(0x01F7), # Ƿ Latin Capital Letter Wynn 2873 C("Shift-Y"): UC(0x021C), # Ȝ Latin Capital Letter Yogh 2874 C("Shift-Z"): UC(0x01B7), # Ʒ Latin Capital Letter Ezh 2875 }, when = lambda _: ac_Chr_main == 0x2116 and cnfg.optspec_layout == 'ABC') 2876 2877 keymap("DK-ABC - Hook Above/Glottal Stop", { 2878 # Option+Z {U+02C0} 2879 # Valid keys: 2880 # a e i o u y 2881 # A E I O U Y 2882 C("A"): UC(0x1EA3), # ả Latin Small Letter A with Hook Above 2883 C("E"): UC(0x1EBB), # ẻ Latin Small Letter E with Hook Above 2884 C("I"): UC(0x1EC9), # ỉ Latin Small Letter I with Hook Above 2885 C("O"): UC(0x1ECF), # ỏ Latin Small Letter O with Hook Above 2886 C("U"): UC(0x1EE7), # ủ Latin Small Letter U with Hook Above 2887 C("Y"): UC(0x1EF7), # ỷ Latin Small Letter Y with Hook Above 2888 C("Shift-A"): UC(0x1EA2), # Ả Latin Small Letter A with Hook Above 2889 C("Shift-E"): UC(0x1EBA), # Ẻ Latin Small Letter E with Hook Above 2890 C("Shift-I"): UC(0x1EC8), # Ỉ Latin Small Letter I with Hook Above 2891 C("Shift-O"): UC(0x1ECE), # Ỏ Latin Small Letter O with Hook Above 2892 C("Shift-U"): UC(0x1EE6), # Ủ Latin Small Letter U with Hook Above 2893 C("Shift-Y"): UC(0x1EF6), # Ỷ Latin Small Letter Y with Hook Above 2894 }, when = lambda _: ac_Chr_main == 0x02C0 and cnfg.optspec_layout == 'ABC') 2895 2896 keymap("DK-ABC - Dot Below", { 2897 # Option+X {U+002E} 2898 # Valid keys: 2899 # a b d e h i k l m n o r s t u v w y z 2900 # A B D E H I K L M N O R S T U V W Y Z 2901 C("A"): UC(0x1EA1), # ạ Latin Small Letter A with Dot Below 2902 C("B"): UC(0x1E05), # ḅ Latin Small Letter B with Dot Below 2903 C("D"): UC(0x1E0D), # ḍ Latin Small Letter D with Dot Below 2904 C("E"): UC(0x1EB9), # ẹ Latin Small Letter E with Dot Below 2905 C("H"): UC(0x1E25), # ḥ Latin Small Letter H with Dot Below 2906 C("I"): UC(0x1ECB), # ị Latin Small Letter I with Dot Below 2907 C("K"): UC(0x1E33), # ḳ Latin Small Letter K with Dot Below 2908 C("L"): UC(0x1E37), # ḷ Latin Small Letter L with Dot Below 2909 C("M"): UC(0x1E43), # ṃ Latin Small Letter M with Dot Below 2910 C("N"): UC(0x1E47), # ṇ Latin Small Letter N with Dot Below 2911 C("O"): UC(0x1ECD), # ọ Latin Small Letter O with Dot Below 2912 C("R"): UC(0x1E5B), # ṛ Latin Small Letter R with Dot Below 2913 C("S"): UC(0x1E63), # ṣ Latin Small Letter S with Dot Below 2914 C("T"): UC(0x1E6D), # ṭ Latin Small Letter T with Dot Below 2915 C("U"): UC(0x1EE5), # ụ Latin Small Letter U with Dot Below 2916 C("V"): UC(0x1E7F), # ṿ Latin Small Letter V with Dot Below 2917 C("W"): UC(0x1E89), # ẉ Latin Small Letter W with Dot Below 2918 C("Y"): UC(0x1EF5), # ỵ Latin Small Letter Y with Dot Below 2919 C("Z"): UC(0x1E93), # ẓ Latin Small Letter Z with Dot Below 2920 C("Shift-A"): UC(0x1EA0), # Ạ Latin Capital Letter A with Dot Below 2921 C("Shift-B"): UC(0x1E04), # Ḅ Latin Capital Letter B with Dot Below 2922 C("Shift-D"): UC(0x1E0C), # Ḍ Latin Capital Letter D with Dot Below 2923 C("Shift-E"): UC(0x1EB8), # Ẹ Latin Capital Letter E with Dot Below 2924 C("Shift-H"): UC(0x1E24), # Ḥ Latin Capital Letter H with Dot Below 2925 C("Shift-I"): UC(0x1ECA), # Ị Latin Capital Letter I with Dot Below 2926 C("Shift-K"): UC(0x1E32), # Ḳ Latin Capital Letter K with Dot Below 2927 C("Shift-L"): UC(0x1E36), # Ḷ Latin Capital Letter L with Dot Below 2928 C("Shift-M"): UC(0x1E42), # Ṃ Latin Capital Letter M with Dot Below 2929 C("Shift-N"): UC(0x1E46), # Ṇ Latin Capital Letter N with Dot Below 2930 C("Shift-O"): UC(0x1ECC), # Ọ Latin Capital Letter O with Dot Below 2931 C("Shift-R"): UC(0x1E5A), # Ṛ Latin Capital Letter R with Dot Below 2932 C("Shift-S"): UC(0x1E62), # Ṣ Latin Capital Letter S with Dot Below 2933 C("Shift-T"): UC(0x1E6C), # Ṭ Latin Capital Letter T with Dot Below 2934 C("Shift-U"): UC(0x1EE4), # Ụ Latin Capital Letter U with Dot Below 2935 C("Shift-V"): UC(0x1E7E), # Ṿ Latin Capital Letter V with Dot Below 2936 C("Shift-W"): UC(0x1E88), # Ẉ Latin Capital Letter W with Dot Below 2937 C("Shift-Y"): UC(0x1EF4), # Ỵ Latin Capital Letter Y with Dot Below 2938 C("Shift-Z"): UC(0x1E92), # Ẓ Latin Capital Letter Z with Dot Below 2939 }, when = lambda _: ac_Chr_main == 0x002E and cnfg.optspec_layout == 'ABC') 2940 2941 keymap("DK-ABC - Cedilla/Cedille", { 2942 # Option+C {U+00B8} 2943 # Valid keys: 2944 # c d e g h k l n r s t z 2945 # C D E G H K L N R S T Z 2946 C("C"): UC(0x00E7), # ç Latin Small Letter C with Cedilla 2947 C("D"): UC(0x1E11), # ḑ Latin Small Letter D with Cedilla 2948 C("E"): UC(0x0229), # ȩ Latin Small Letter E with Cedilla 2949 C("G"): UC(0x0123), # ģ Latin Small Letter G with Cedilla 2950 C("H"): UC(0x1E29), # ḩ Latin Small Letter H with Cedilla 2951 C("K"): UC(0x0137), # ķ Latin Small Letter K with Cedilla 2952 C("L"): UC(0x013C), # ļ Latin Small Letter L with Cedilla 2953 C("N"): UC(0x0146), # ņ Latin Small Letter N with Cedilla 2954 C("R"): UC(0x0157), # ŗ Latin Small Letter R with Cedilla 2955 C("S"): UC(0x015F), # ş Latin Small Letter S with Cedilla 2956 C("T"): UC(0x0163), # ţ Latin Small Letter T with Cedilla 2957 C("Z"): [UC(0x007A),UC(0x0327)], # z̧ Latin Small Letter Z with Cedilla 2958 C("Shift-C"): UC(0x00C7), # Ç Latin Capital Letter C with Cedilla 2959 C("Shift-D"): UC(0x1E10), # Ḑ Latin Capital Letter D with Cedilla 2960 C("Shift-E"): UC(0x0228), # Ȩ Latin Capital Letter E with Cedilla 2961 C("Shift-G"): UC(0x0122), # Ģ Latin Capital Letter G with Cedilla 2962 C("Shift-H"): UC(0x1E28), # Ḩ Latin Capital Letter H with Cedilla 2963 C("Shift-K"): UC(0x0136), # Ķ Latin Capital Letter K with Cedilla 2964 C("Shift-L"): UC(0x013B), # Ļ Latin Capital Letter L with Cedilla 2965 C("Shift-N"): UC(0x0145), # Ņ Latin Capital Letter N with Cedilla 2966 C("Shift-R"): UC(0x0156), # Ŗ Latin Capital Letter R with Cedilla 2967 C("Shift-S"): UC(0x015E), # Ş Latin Capital Letter S with Cedilla 2968 C("Shift-T"): UC(0x0162), # Ţ Latin Capital Letter T with Cedilla 2969 C("Shift-Z"): [UC(0x005A),UC(0x0327)], # Z̧ Latin Capital Letter Z with Cedilla 2970 }, when = lambda _: ac_Chr_main == 0x00B8 and cnfg.optspec_layout == 'ABC') 2971 2972 keymap("DK-ABC - Caron/hacek", { 2973 # Option+V {U+02C7} 2974 # Valid keys: 2975 # a c d e g h i j k l n o r s t u v x z 2976 # A C D E G H I J K L N O R S T U V X Z 2977 C("A"): UC(0x01CE), # ǎ Latin Small Letter A with Caron 2978 C("C"): UC(0x010D), # č Latin Small Letter C with Caron 2979 C("D"): UC(0x010F), # ď Latin Small Letter D with Caron 2980 C("E"): UC(0x011B), # ě Latin Small Letter E with Caron 2981 C("G"): UC(0x01E7), # ǧ Latin Small Letter G with Caron 2982 C("H"): UC(0x021F), # ȟ Latin Small Letter H with Caron 2983 C("I"): UC(0x01D0), # ǐ Latin Small Letter I with Caron 2984 C("J"): UC(0x01F0), # ǰ Latin Small Letter J with Caron 2985 C("K"): UC(0x01E9), # ǩ Latin Small Letter K with Caron 2986 C("L"): UC(0x013E), # ľ Latin Small Letter L with Caron 2987 C("N"): UC(0x0148), # ň Latin Small Letter N with Caron 2988 C("O"): UC(0x01D2), # ǒ Latin Small Letter O with Caron 2989 C("R"): UC(0x0159), # ř Latin Small Letter R with Caron 2990 C("S"): UC(0x0161), # š Latin Small Letter S with Caron 2991 C("T"): UC(0x0165), # ť Latin Small Letter T with Caron 2992 C("U"): UC(0x01D4), # ǔ Latin Small Letter U with Caron 2993 C("V"): UC(0x01DA), # ǚ Latin Small Letter U w/Diaeresis and Caron 2994 C("X"): [UC(0x0292),UC(0x030C)], # ǯ Latin Small Letter Ezh with Caron 2995 C("Z"): UC(0x017E), # ž Latin Small Letter Z with Caron 2996 C("Shift-A"): UC(0x01CD), # Ǎ Latin Capital Letter A with Caron 2997 C("Shift-C"): UC(0x010C), # Č Latin Capital Letter C with Caron 2998 C("Shift-D"): UC(0x010E), # Ď Latin Capital Letter D with Caron 2999 C("Shift-E"): UC(0x011A), # Ě Latin Capital Letter E with Caron 3000 C("Shift-G"): UC(0x01E6), # Ǧ Latin Capital Letter G with Caron 3001 C("Shift-H"): UC(0x021E), # Ȟ Latin Capital Letter H with Caron 3002 C("Shift-I"): UC(0x01CF), # Ǐ Latin Capital Letter I with Caron 3003 C("Shift-J"): [UC(0x004A),UC(0x030C)], # J̌ Latin Capital Letter J with Caron 3004 C("Shift-K"): UC(0x01E8), # Ǩ Latin Capital Letter K with Caron 3005 C("Shift-L"): UC(0x013D), # Ľ Latin Capital Letter L with Caron 3006 C("Shift-N"): UC(0x0147), # Ň Latin Capital Letter N with Caron 3007 C("Shift-O"): UC(0x01D1), # Ǒ Latin Capital Letter O with Caron 3008 C("Shift-R"): UC(0x0158), # Ř Latin Capital Letter R with Caron 3009 C("Shift-S"): UC(0x0160), # Š Latin Capital Letter S with Caron 3010 C("Shift-T"): UC(0x0164), # Ť Latin Capital Letter T with Caron 3011 C("Shift-U"): UC(0x01D3), # Ǔ Latin Capital Letter U with Caron 3012 C("Shift-V"): UC(0x01D9), # Ǚ Latin Capital Letter U w/Diaeresis and Caron 3013 C("Shift-X"): [UC(0x01B7),UC(0x030C)], # Ǯ Latin Capital Letter Ezh with Caron 3014 C("Shift-Z"): UC(0x017D), # Ž Latin Capital Letter Z with Caron 3015 }, when = lambda _: ac_Chr_main == 0x02C7 and cnfg.optspec_layout == 'ABC') 3016 3017 keymap("DK-ABC - Breve", { 3018 # Option+B {U+02D8} 3019 # Valid keys: 3020 # a e g h i o u 3021 # A E G H I O U 3022 C("A"): UC(0x0103), # ă Latin Small Letter A with Breve 3023 C("E"): UC(0x0115), # ĕ Latin Small Letter E with Breve 3024 C("G"): UC(0x011F), # ğ Latin Small Letter G with Breve 3025 C("H"): UC(0x1E2B), # ḫ Latin Small Letter H with Breve Below 3026 C("I"): UC(0x012D), # ĭ Latin Small Letter I with Breve 3027 C("O"): UC(0x014F), # ŏ Latin Small Letter O with Breve 3028 C("U"): UC(0x016D), # ŭ Latin Small Letter U with Breve 3029 C("Shift-A"): UC(0x0102), # Ă Latin Capital Letter A with Breve 3030 C("Shift-E"): UC(0x0114), # Ĕ Latin Capital Letter E with Breve 3031 C("Shift-G"): UC(0x011E), # Ğ Latin Capital Letter G with Breve 3032 C("Shift-H"): UC(0x1E2A), # Ḫ Latin Capital Letter H with Breve Below 3033 C("Shift-I"): UC(0x012C), # Ĭ Latin Capital Letter I with Breve 3034 C("Shift-O"): UC(0x014E), # Ŏ Latin Capital Letter O with Breve 3035 C("Shift-U"): UC(0x016C), # Ŭ Latin Capital Letter U with Breve 3036 }, when = lambda _: ac_Chr_main == 0x02D8 and cnfg.optspec_layout == 'ABC') 3037 3038 keymap("DK-ABC - Tilde", { 3039 # Option+N {U+02DC} 3040 # Valid keys: 3041 # a e i n o u v y 3042 # A E I N O U V Y 3043 C("A"): UC(0x00E3), # ã Latin Small Letter A with Tilde 3044 C("E"): UC(0x1EBD), # ẽ Latin Small Letter E with Tilde 3045 C("I"): UC(0x0129), # ĩ Latin Small Letter I with Tilde 3046 C("N"): UC(0x00F1), # ñ Latin Small Letter N with Tilde 3047 C("O"): UC(0x00F5), # õ Latin Small Letter O with Tilde 3048 C("U"): UC(0x0169), # ũ Latin Small Letter U with Tilde 3049 C("V"): UC(0x1E7D), # ṽ Latin Small Letter V with Tilde 3050 C("Y"): UC(0x1EF9), # ỹ Latin Small Letter Y with Tilde 3051 C("Shift-A"): UC(0x00C3), # à Latin Capital Letter A with Tilde 3052 C("Shift-E"): UC(0x1EBC), # Ẽ Latin Capital Letter E with Tilde 3053 C("Shift-I"): UC(0x0128), # Ĩ Latin Capital Letter I with Tilde 3054 C("Shift-N"): UC(0x00D1), # Ñ Latin Capital Letter N with Tilde 3055 C("Shift-O"): UC(0x00D5), # Õ Latin Capital Letter O with Tilde 3056 C("Shift-U"): UC(0x0168), # Ũ Latin Capital Letter U with Tilde 3057 C("Shift-V"): UC(0x1E7C), # Ṽ Latin Capital Letter V with Tilde 3058 C("Shift-Y"): UC(0x1EF8), # Ỹ Latin Capital Letter Y with Tilde 3059 }, when = lambda _: ac_Chr_main == 0x02DC and cnfg.optspec_layout == 'ABC') 3060 3061 keymap("DK-ABC - Ogonek", { 3062 # Option+M {U+02DB} 3063 # Valid keys: 3064 # a e i o u 3065 # A E I O U 3066 C("A"): UC(0x0105), # ą Latin Small Letter A with Ogonek 3067 C("E"): UC(0x0119), # ę Latin Small Letter E with Ogonek 3068 C("I"): UC(0x012F), # į Latin Small Letter I with Ogonek 3069 C("O"): UC(0x01EB), # ǫ Latin Small Letter O with Ogonek 3070 C("U"): UC(0x0173), # ų Latin Small Letter U with Ogonek 3071 C("Shift-A"): UC(0x0104), # Ą Latin Capital Letter A with Ogonek 3072 C("Shift-E"): UC(0x0118), # Ę Latin Capital Letter E with Ogonek 3073 C("Shift-I"): UC(0x012E), # Į Latin Capital Letter I with Ogonek 3074 C("Shift-O"): UC(0x01EA), # Ǫ Latin Capital Letter O with Ogonek 3075 C("Shift-U"): UC(0x0172), # Ų Latin Capital Letter U with Ogonek 3076 }, when = lambda _: ac_Chr_main == 0x02DB and cnfg.optspec_layout == 'ABC') 3077 3078 keymap("DK-ABC - Hook", { 3079 # Shift+Option+Dot {U+0294} 3080 # Valid keys: 3081 # b c d f g h i k n p q r s t u x y z 3082 # B C D F G I K N P R S T U X Y Z 3083 C("B"): UC(0x0253), # ɓ Latin Small Letter B with Hook 3084 C("C"): UC(0x0188), # ƈ Latin Small Letter C with Hook 3085 C("D"): UC(0x0257), # ɗ Latin Small Letter D with Hook 3086 C("F"): UC(0x0192), # ƒ Latin Small Letter F with Hook (function symbol) 3087 C("G"): UC(0x0260), # ɠ Latin Small Letter G with Hook 3088 C("H"): UC(0x0266), # ɦ Latin Small Letter H with Hook 3089 C("I"): UC(0x0269), # ɩ Latin Small Letter Iota 3090 C("K"): UC(0x0199), # ƙ Latin Small Letter K with Hook 3091 C("N"): UC(0x0272), # ɲ Latin Small Letter N with Left Hook 3092 C("P"): UC(0x01A5), # ƥ Latin Small Letter P with Hook 3093 C("Q"): UC(0x02A0), # ʠ Latin Small Letter Q with Hook 3094 C("R"): UC(0x0288), # ʈ Latin Small Letter T with Retroflex Hook 3095 C("S"): UC(0x0283), # ʃ Latin Small Letter Esh 3096 C("T"): UC(0x01AD), # ƭ Latin Small Letter T with Hook 3097 C("U"): UC(0x028B), # ʋ Latin Small Letter V with Hook 3098 C("X"): UC(0x0256), # ɖ Latin Small Letter D with Tail 3099 C("Y"): UC(0x01B4), # ƴ Latin Small Letter Y with Hook 3100 C("Z"): UC(0x0225), # ȥ Latin Small Letter Z with Hook 3101 C("Shift-B"): UC(0x0181), # Ɓ Latin Capital Letter B with Hook 3102 C("Shift-C"): UC(0x0187), # Ƈ Latin Capital Letter C with Hook 3103 C("Shift-D"): UC(0x018A), # Ɗ Latin Capital Letter D with Hook 3104 C("Shift-F"): UC(0x0191), # Ƒ Latin Capital Letter F with Hook 3105 C("Shift-G"): UC(0x0193), # Ɠ Latin Capital Letter G with Hook 3106 C("Shift-I"): UC(0x0196), # Ɩ Latin Capital Letter Iota 3107 C("Shift-K"): UC(0x0198), # Ƙ Latin Capital Letter K with Hook 3108 C("Shift-N"): UC(0x019D), # Ɲ Latin Capital Letter N with Left Hook 3109 C("Shift-P"): UC(0x01A4), # Ƥ Latin Capital Letter P with Hook 3110 C("Shift-R"): UC(0x01AE), # Ʈ Latin Capital Letter T with Retroflex Hook 3111 C("Shift-S"): UC(0x01A9), # Ʃ Latin Capital Letter Esh 3112 C("Shift-T"): UC(0x01AC), # Ƭ Latin Capital Letter T with Hook 3113 C("Shift-U"): UC(0x01B2), # Ʋ Latin Capital Letter V with Hook 3114 C("Shift-X"): UC(0x0189), # Ɖ Latin Capital Letter African D 3115 C("Shift-Y"): UC(0x01B3), # Ƴ Latin Capital Letter Y with Hook 3116 C("Shift-Z"): UC(0x0224), # Ȥ Latin Capital Letter Z with Hook 3117 }, when = lambda _: ac_Chr_main == 0x0294 and cnfg.optspec_layout == 'ABC') 3118 3119 3120 ####################################### 3121 ### DEAD KEYS KEYMAPS - US LAYOUT ### 3122 ####################################### 3123 keymap("DK-US - Grave", { 3124 # Valid keys: 3125 # a e i o u 3126 # A E I O U 3127 C("A"): UC(0x00E0), # à Latin Small a with Grave 3128 C("E"): UC(0x00E8), # è Latin Small e with Grave 3129 C("I"): UC(0x00EC), # ì Latin Small i with Grave 3130 C("O"): UC(0x00F2), # ò Latin Small o with Grave 3131 C("U"): UC(0x00F9), # ù Latin Small u with Grave 3132 C("Shift-A"): UC(0x00C0), # À Latin Capital A with Grave 3133 C("Shift-E"): UC(0x00C8), # È Latin Capital E with Grave 3134 C("Shift-I"): UC(0x00CC), # Ì Latin Capital I with Grave 3135 C("Shift-O"): UC(0x00D2), # Ò Latin Capital O with Grave 3136 C("Shift-U"): UC(0x00D9), # Ù Latin Capital U with Grave 3137 }, when = lambda _: ac_Chr_main == 0x0060 and cnfg.optspec_layout == 'US') 3138 3139 keymap("DK-US - Acute", { 3140 # Valid keys: 3141 # a e i o u 3142 # A E I O U 3143 C("A"): UC(0x00E1), # á Latin Small a with Acute 3144 C("E"): UC(0x00E9), # é Latin Small e with Acute 3145 C("I"): UC(0x00ED), # í Latin Small i with Acute 3146 C("O"): UC(0x00F3), # ó Latin Small o with Acute 3147 C("U"): UC(0x00FA), # ú Latin Small u with Acute 3148 C("Shift-A"): UC(0x00C1), # Á Latin Capital A with Acute 3149 C("Shift-E"): UC(0x00C9), # É Latin Capital E with Acute 3150 C("Shift-I"): UC(0x00CD), # Í Latin Capital I with Acute 3151 C("Shift-O"): UC(0x00D3), # Ó Latin Capital O with Acute 3152 C("Shift-U"): UC(0x00DA), # Ú Latin Capital U with Acute 3153 }, when = lambda _: ac_Chr_main == 0x00B4 and cnfg.optspec_layout == 'US') 3154 3155 keymap("DK-US - Umlaut", { 3156 # Valid keys: 3157 # a e i o u y 3158 # A E I O U Y 3159 C("A"): UC(0x00E4), # ä Latin Small a with Umlaut 3160 C("E"): UC(0x00EB), # ë Latin Small e with Umlaut 3161 C("I"): UC(0x00EF), # ï Latin Small i with Umlaut 3162 C("O"): UC(0x00F6), # ö Latin Small o with Umlaut 3163 C("U"): UC(0x00FC), # ü Latin Small u with Umlaut 3164 C("Y"): UC(0x00FF), # ÿ Latin Small y with Umlaut 3165 C("Shift-A"): UC(0x00C4), # Ä Latin Capital A with Umlaut 3166 C("Shift-E"): UC(0x00CB), # Ë Latin Capital E with Umlaut 3167 C("Shift-I"): UC(0x00CF), # Ï Latin Capital I with Umlaut 3168 C("Shift-O"): UC(0x00D6), # Ö Latin Capital O with Umlaut 3169 C("Shift-U"): UC(0x00DC), # Ü Latin Capital U with Umlaut 3170 C("Shift-Y"): UC(0x0178), # Ÿ Latin Capital Y with Umlaut 3171 }, when = lambda _: ac_Chr_main == 0x00A8 and cnfg.optspec_layout == 'US') 3172 3173 keymap("DK-US - Circumflex", { 3174 # Valid keys: 3175 # a e i o u 3176 # A E I O U 3177 C("A"): UC(0x00E2), # â Latin Small a with Circumflex 3178 C("E"): UC(0x00EA), # ê Latin Small e with Circumflex 3179 C("I"): UC(0x00EE), # î Latin Small i with Circumflex 3180 C("O"): UC(0x00F4), # ô Latin Small o with Circumflex 3181 C("U"): UC(0x00FB), # û Latin Small u with Circumflex 3182 C("Shift-A"): UC(0x00C2), #  Latin Capital A with Circumflex 3183 C("Shift-E"): UC(0x00CA), # Ê Latin Capital E with Circumflex 3184 C("Shift-I"): UC(0x00CE), # Î Latin Capital I with Circumflex 3185 C("Shift-O"): UC(0x00D4), # Ô Latin Capital O with Circumflex 3186 C("Shift-U"): UC(0x00DB), # Û Latin Capital U with Circumflex 3187 }, when = lambda _: ac_Chr_main == 0x02C6 and cnfg.optspec_layout == 'US') 3188 3189 keymap("DK-US - Tilde", { 3190 # Valid keys: 3191 # a n o 3192 # A N O 3193 C("A"): UC(0x00E3), # ã Latin Small a with Tilde 3194 C("N"): UC(0x00F1), # ñ Latin Small n with Tilde 3195 C("O"): UC(0x00F5), # õ Latin Small o with Tilde 3196 C("Shift-A"): UC(0x00C3), # à Latin Capital A with Tilde 3197 C("Shift-N"): UC(0x00D1), # Ñ Latin Capital N with Tilde 3198 C("Shift-O"): UC(0x00D5), # Õ Latin Capital O with Tilde 3199 }, when = lambda _: ac_Chr_main == 0x02DC and cnfg.optspec_layout == 'US') 3200 3201 3202 3203 ################################################################# 3204 ### ### 3205 ### ### 3206 ### ███████ ███████ ██████ █████ ██████ ███████ ### 3207 ### ██ ██ ██ ██ ██ ██ ██ ██ ### 3208 ### █████ ███████ ██ ███████ ██████ █████ ### 3209 ### ██ ██ ██ ██ ██ ██ ██ ### 3210 ### ███████ ███████ ██████ ██ ██ ██ ███████ ### 3211 ### ### 3212 ### ### 3213 ################################################################# 3214 keymap("Escape actions for dead keys - Overrides for ABC Extended", { 3215 3216 ### activate other dead keys correctly while one is active 3217 3218 # US layout dead keys (not here, see keymap below) 3219 3220 # ABC Extended layout dead keys 3221 C("Alt-Grave"): [getDK(),UC(0x0060),C("Shift-Left"),setDK(0x0060)], # Dead Key Accent: Grave 3222 C("Alt-6"): [getDK(),UC(0x02C6),C("Shift-Left"),setDK(0x02C6)], # Dead Key Accent: Circumflex 3223 C("Alt-W"): [getDK(),UC(0x02D9),C("Shift-Left"),setDK(0x02D9)], # Dead Key Accent: Dot Above 3224 C("Alt-E"): [getDK(),UC(0x00B4),C("Shift-Left"),setDK(0x00B4)], # Dead Key Accent: Acute 3225 3226 # C("Shift-Alt-Y"): [getDK(),UC(0x030F),C("Shift-Left"),setDK(0x030F)], # Dead Key Accent: Combining Double Grave 3227 # Double Grave accent acts odd when using the Combining Double Grave {U+030F} 3228 # Substituting {U+02F5}: ˵ Modifier Letter Middle Double Grave Accent 3229 C("Shift-Alt-Y"): [getDK(),UC(0x02F5),C("Shift-Left"),setDK(0x02F5)], # Dead Key Accent: Double Grave (substitute) 3230 3231 C("Alt-U"): [getDK(),UC(0x00A8),C("Shift-Left"),setDK(0x00A8)], # Dead Key Accent: Umlaut/Diaeresis 3232 C("Alt-I"): [getDK(),UC(0x02BC),C("Shift-Left"),setDK(0x02BC)], # Dead Key Accent: Apostrophe/Horn 3233 C("Alt-P"): [getDK(),UC(0x002C),C("Shift-Left"),setDK(0x002C)], # Dead Key Accent: Comma Below 3234 C("Alt-A"): [getDK(),UC(0x00AF),C("Shift-Left"),setDK(0x00AF)], # Dead Key Accent: Macron/Line Above 3235 3236 # C("Shift-Alt-S"): [getDK(),UC(0x0311),C("Shift-Left"),setDK(0x0311)], # Dead Key Accent: Combining Inverted Breve 3237 C("Shift-Alt-S"): [getDK(),UC(0x1D16),C("Shift-Left"),setDK(0x1D16)], # Dead Key Accent: Combining Inverted Breve 3238 3239 # C("Shift-Alt-F"): [getDK(),UC(0x0330),C("Shift-Left"),setDK(0x0330)], # Dead Key Accent: Combining Tilde Below 3240 # Tilde Below accent acts odd when using the Combining Tilde Below {U+0330} 3241 # Substituting {U+02F7}: ˷ Modifier Letter Low Tilde 3242 C("Shift-Alt-F"): [getDK(),UC(0x02F7),C("Shift-Left"),setDK(0x02F7)], # Dead Key Accent: Tilde Below 3243 C("Shift-Alt-G"): [getDK(),UC(0x2038),C("Shift-Left"),setDK(0x2038)], # Dead Key Accent: Caret/Circumflex Below 3244 3245 C("Alt-H"): [getDK(),UC(0x02CD),C("Shift-Left"),setDK(0x02CD)], # Dead Key Accent: Low Macron/Line Below 3246 C("Alt-J"): [getDK(),UC(0x02DD),C("Shift-Left"),setDK(0x02DD)], # Dead Key Accent: Double Acute 3247 C("Alt-K"): [getDK(),UC(0x02DA),C("Shift-Left"),setDK(0x02DA)], # Dead Key Accent: Ring Above 3248 C("Alt-L"): [getDK(),UC(0x002D),C("Shift-Left"),setDK(0x002D)], # Dead Key Accent: Stroke/Hyphen-Minus 3249 3250 C("Shift-Alt-Semicolon"): [getDK(),UC(0x2116),C("Shift-Left"),setDK(0x2116)], # Dead Key Accent: Numero Sign 3251 3252 C("Alt-Z"): [getDK(),UC(0x02C0),C("Shift-Left"),setDK(0x02C0)], # Dead Key Accent: Hook Above/Glottal Stop 3253 C("Alt-X"): [getDK(),UC(0x002E),C("Shift-Left"),setDK(0x002E)], # Dead Key Accent: Dot Below 3254 C("Alt-C"): [getDK(),UC(0x00B8),C("Shift-Left"),setDK(0x00B8)], # Dead Key Accent: Cedilla/Cedille 3255 C("Alt-V"): [getDK(),UC(0x02C7),C("Shift-Left"),setDK(0x02C7)], # Dead Key Accent: Caron/hacek 3256 C("Alt-B"): [getDK(),UC(0x02D8),C("Shift-Left"),setDK(0x02D8)], # Dead Key Accent: Breve 3257 C("Alt-N"): [getDK(),UC(0x02DC),C("Shift-Left"),setDK(0x02DC)], # Dead Key Accent: Tilde 3258 C("Alt-M"): [getDK(),UC(0x02DB),C("Shift-Left"),setDK(0x02DB)], # Dead Key Accent: Ogonek 3259 3260 C("Shift-Alt-Dot"): [getDK(),UC(0x0294),C("Shift-Left"),setDK(0x0294)], # Dead Key Accent: Hook 3261 3262 }, when = lambda _: ac_Chr_main in deadkeys_list and cnfg.optspec_layout == 'ABC') 3263 3264 keymap("Escape actions for dead keys", { 3265 # special case shortcuts that should cancel dead keys 3266 C("Esc"): [getDK(),setDK(None)], # Leave accent char if dead keys Escaped 3267 C("Space"): [getDK(),setDK(None)], # Leave accent char if user hits Space 3268 C("Delete"): [getDK(),setDK(None)], # Leave accent char if user hits Delete 3269 C("Backspace"): [getDK(),C("Backspace"),setDK(None)], # Delete character if user hits Backspace 3270 C("Tab"): [getDK(),C("Tab"),setDK(None)], # Leave accent char, insert Tab 3271 C("Enter"): [getDK(),C("Enter"),setDK(None)], # Leave accent char, Enter key 3272 C("Up"): [getDK(),C("Up"),setDK(None)], # Leave accent char, up arrow 3273 C("Down"): [getDK(),C("Down"),setDK(None)], # Leave accent char, down arrow 3274 C("Left"): [getDK(),C("Left"),setDK(None)], # Leave accent char, left arrow 3275 C("Right"): [getDK(),C("Right"),setDK(None)], # Leave accent char, right arrow 3276 C("RC-Tab"): [getDK(),bind,C("Alt-Tab"),setDK(None)], # Leave accent char, task switch 3277 C("Shift-RC-Tab"): [getDK(),bind,C("Shift-Alt-Tab"),setDK(None)], # Leave accent char, task switch (reverse) 3278 C("RC-Grave"): [getDK(),bind,C("Alt-Grave"),setDK(None)], # Leave accent char, in-app window switch 3279 C("Shift-RC-Tab"): [getDK(),bind,C("Shift-Alt-Grave"),setDK(None)], # Leave accent char, in-app window switch (reverse) 3280 3281 # common shortcuts that should also cancel dead keys 3282 C("RC-a"): [getDK(),C("C-a"),setDK(None)], # Leave accent char, select all 3283 C("RC-z"): [getDK(),C("C-z"),setDK(None)], # Leave accent char, undo 3284 C("RC-x"): [getDK(),C("C-x"),setDK(None)], # Leave accent char, cut 3285 C("RC-c"): [getDK(),C("C-c"),setDK(None)], # Leave accent char, copy 3286 C("RC-v"): [getDK(),C("C-v"),setDK(None)], # Leave accent char, paste 3287 3288 ### activate other dead keys correctly while one is active 3289 3290 # US layout dead keys 3291 C("Alt-Grave"): [getDK(),UC(0x0060),C("Shift-Left"),setDK(0x0060)], # Dead Key Accent: Grave 3292 C("Alt-E"): [getDK(),UC(0x00B4),C("Shift-Left"),setDK(0x00B4)], # Dead Key Accent: Acute 3293 C("Alt-U"): [getDK(),UC(0x00A8),C("Shift-Left"),setDK(0x00A8)], # Dead Key Accent: Umlaut/Diaeresis 3294 C("Alt-I"): [getDK(),UC(0x02C6),C("Shift-Left"),setDK(0x02C6)], # Dead Key Accent: Circumflex 3295 C("Alt-N"): [getDK(),UC(0x02DC),C("Shift-Left"),setDK(0x02DC)], # Dead Key Accent: Tilde 3296 3297 # ABC Extended layout dead keys (not here, see keymap above) 3298 3299 3300 # cancel dead keys with number keys row 3301 C("Grave"): [getDK(),C("Grave"),setDK(None)], 3302 C("Key_1"): [getDK(),C("Key_1"),setDK(None)], 3303 C("Key_2"): [getDK(),C("Key_2"),setDK(None)], 3304 C("Key_3"): [getDK(),C("Key_3"),setDK(None)], 3305 C("Key_4"): [getDK(),C("Key_4"),setDK(None)], 3306 C("Key_5"): [getDK(),C("Key_5"),setDK(None)], 3307 C("Key_6"): [getDK(),C("Key_6"),setDK(None)], 3308 C("Key_7"): [getDK(),C("Key_7"),setDK(None)], 3309 C("Key_8"): [getDK(),C("Key_8"),setDK(None)], 3310 C("Key_9"): [getDK(),C("Key_9"),setDK(None)], 3311 C("Key_0"): [getDK(),C("Key_0"),setDK(None)], 3312 C("Minus"): [getDK(),C("Minus"),setDK(None)], 3313 C("Equal"): [getDK(),C("Equal"),setDK(None)], 3314 C("Shift-Grave"): [getDK(),C("Shift-Grave"),setDK(None)], 3315 C("Shift-Key_1"): [getDK(),C("Shift-Key_1"),setDK(None)], 3316 C("Shift-Key_2"): [getDK(),C("Shift-Key_2"),setDK(None)], 3317 C("Shift-Key_3"): [getDK(),C("Shift-Key_3"),setDK(None)], 3318 C("Shift-Key_4"): [getDK(),C("Shift-Key_4"),setDK(None)], 3319 C("Shift-Key_5"): [getDK(),C("Shift-Key_5"),setDK(None)], 3320 C("Shift-Key_6"): [getDK(),C("Shift-Key_6"),setDK(None)], 3321 C("Shift-Key_7"): [getDK(),C("Shift-Key_7"),setDK(None)], 3322 C("Shift-Key_8"): [getDK(),C("Shift-Key_8"),setDK(None)], 3323 C("Shift-Key_9"): [getDK(),C("Shift-Key_9"),setDK(None)], 3324 C("Shift-Key_0"): [getDK(),C("Shift-Key_0"),setDK(None)], 3325 C("Shift-Minus"): [getDK(),C("Shift-Minus"),setDK(None)], 3326 C("Shift-Equal"): [getDK(),C("Shift-Equal"),setDK(None)], 3327 3328 # cancel dead keys with any letter on the keyboard that isn't supported by the dead key 3329 C("A"): [getDK(),C("A"),setDK(None)], 3330 C("B"): [getDK(),C("B"),setDK(None)], 3331 C("C"): [getDK(),C("C"),setDK(None)], 3332 C("D"): [getDK(),C("D"),setDK(None)], 3333 C("E"): [getDK(),C("E"),setDK(None)], 3334 C("F"): [getDK(),C("F"),setDK(None)], 3335 C("G"): [getDK(),C("G"),setDK(None)], 3336 C("H"): [getDK(),C("H"),setDK(None)], 3337 C("I"): [getDK(),C("I"),setDK(None)], 3338 C("J"): [getDK(),C("J"),setDK(None)], 3339 C("K"): [getDK(),C("K"),setDK(None)], 3340 C("L"): [getDK(),C("L"),setDK(None)], 3341 C("M"): [getDK(),C("M"),setDK(None)], 3342 C("N"): [getDK(),C("N"),setDK(None)], 3343 C("O"): [getDK(),C("O"),setDK(None)], 3344 C("P"): [getDK(),C("P"),setDK(None)], 3345 C("Q"): [getDK(),C("Q"),setDK(None)], 3346 C("R"): [getDK(),C("R"),setDK(None)], 3347 C("S"): [getDK(),C("S"),setDK(None)], 3348 C("T"): [getDK(),C("T"),setDK(None)], 3349 C("U"): [getDK(),C("U"),setDK(None)], 3350 C("V"): [getDK(),C("V"),setDK(None)], 3351 C("W"): [getDK(),C("W"),setDK(None)], 3352 C("X"): [getDK(),C("X"),setDK(None)], 3353 C("Y"): [getDK(),C("Y"),setDK(None)], 3354 C("Z"): [getDK(),C("Z"),setDK(None)], 3355 C("Shift-A"): [getDK(),C("Shift-A"),setDK(None)], 3356 C("Shift-B"): [getDK(),C("Shift-B"),setDK(None)], 3357 C("Shift-C"): [getDK(),C("Shift-C"),setDK(None)], 3358 C("Shift-D"): [getDK(),C("Shift-D"),setDK(None)], 3359 C("Shift-E"): [getDK(),C("Shift-E"),setDK(None)], 3360 C("Shift-F"): [getDK(),C("Shift-F"),setDK(None)], 3361 C("Shift-G"): [getDK(),C("Shift-G"),setDK(None)], 3362 C("Shift-H"): [getDK(),C("Shift-H"),setDK(None)], 3363 C("Shift-I"): [getDK(),C("Shift-I"),setDK(None)], 3364 C("Shift-J"): [getDK(),C("Shift-J"),setDK(None)], 3365 C("Shift-K"): [getDK(),C("Shift-K"),setDK(None)], 3366 C("Shift-L"): [getDK(),C("Shift-L"),setDK(None)], 3367 C("Shift-M"): [getDK(),C("Shift-M"),setDK(None)], 3368 C("Shift-N"): [getDK(),C("Shift-N"),setDK(None)], 3369 C("Shift-O"): [getDK(),C("Shift-O"),setDK(None)], 3370 C("Shift-P"): [getDK(),C("Shift-P"),setDK(None)], 3371 C("Shift-Q"): [getDK(),C("Shift-Q"),setDK(None)], 3372 C("Shift-R"): [getDK(),C("Shift-R"),setDK(None)], 3373 C("Shift-S"): [getDK(),C("Shift-S"),setDK(None)], 3374 C("Shift-T"): [getDK(),C("Shift-T"),setDK(None)], 3375 C("Shift-U"): [getDK(),C("Shift-U"),setDK(None)], 3376 C("Shift-V"): [getDK(),C("Shift-V"),setDK(None)], 3377 C("Shift-W"): [getDK(),C("Shift-W"),setDK(None)], 3378 C("Shift-X"): [getDK(),C("Shift-X"),setDK(None)], 3379 C("Shift-Y"): [getDK(),C("Shift-Y"),setDK(None)], 3380 C("Shift-Z"): [getDK(),C("Shift-Z"),setDK(None)], 3381 3382 # cancel dead keys with other punctuation keys 3383 C("Left_Brace"): [getDK(),C("Left_Brace"),setDK(None)], 3384 C("Right_Brace"): [getDK(),C("Right_Brace"),setDK(None)], 3385 C("Backslash"): [getDK(),C("Backslash"),setDK(None)], 3386 C("Semicolon"): [getDK(),C("Semicolon"),setDK(None)], 3387 C("Apostrophe"): [getDK(),C("Apostrophe"),setDK(None)], 3388 C("Comma"): [getDK(),C("Comma"),setDK(None)], 3389 C("Dot"): [getDK(),C("Dot"),setDK(None)], 3390 C("Slash"): [getDK(),C("Slash"),setDK(None)], 3391 C("Shift-Left_Brace"): [getDK(),C("Shift-Left_Brace"),setDK(None)], 3392 C("Shift-Right_Brace"): [getDK(),C("Shift-Right_Brace"),setDK(None)], 3393 C("Shift-Backslash"): [getDK(),C("Shift-Backslash"),setDK(None)], 3394 C("Shift-Semicolon"): [getDK(),C("Shift-Semicolon"),setDK(None)], 3395 C("Shift-Apostrophe"): [getDK(),C("Shift-Apostrophe"),setDK(None)], 3396 C("Shift-Comma"): [getDK(),C("Shift-Comma"),setDK(None)], 3397 C("Shift-Dot"): [getDK(),C("Shift-Dot"),setDK(None)], 3398 C("Shift-Slash"): [getDK(),C("Shift-Slash"),setDK(None)], 3399 3400 }, when = lambda _: ac_Chr_main in deadkeys_list) 3401 3402 keymap("Disable Dead Keys Tripwire",{ 3403 # Nothing needs to be here. Tripwire keymap to disable active dead keys keymap(s) 3404 }, when = lambda _: setDK(None)()) 3405 3406 3407 3408 ############################################################################## 3409 ### ### 3410 ### ### 3411 ### █████ ██████ ██████ ███ ███ █████ ██ ███ ██ ### 3412 ### ██ ██ ██ ██ ██ ████ ████ ██ ██ ██ ████ ██ ### 3413 ### ███████ ██████ ██ ██ ████ ██ ███████ ██ ██ ██ ██ ### 3414 ### ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 3415 ### ██ ██ ██████ ██████ ██ ██ ██ ██ ██ ██ ████ ### 3416 ### ### 3417 ### ### 3418 ############################################################################## 3419 # Main keymap for special characters on the ABC Extended layout 3420 keymap("OptSpecialChars - ABC", { 3421 3422 # Number keys row with Option 3423 ###################################################### 3424 C("Alt-Grave"): [UC(0x0060),C("Shift-Left"),setDK(0x0060)], # Dead Key Accent: Grave 3425 3426 C("Alt-1"): UC(0x00A1), # ¡ Inverted Exclamation Mark 3427 C("Alt-2"): UC(0x2122), # ™ Trade Mark Sign Emoji 3428 C("Alt-3"): UC(0x00A3), # £ British Pound currency symbol 3429 C("Alt-4"): UC(0x00A2), # ¢ Cent currency symbol 3430 C("Alt-5"): UC(0x00A7), # § Section symbol 3431 3432 C("Alt-6"): [UC(0x02C6),C("Shift-Left"),setDK(0x02C6)], # Dead Key Accent: Circumflex 3433 3434 C("Alt-7"): UC(0x00B6), # ¶ Paragraph mark (Pilcrow) symbol 3435 C("Alt-8"): UC(0x2022), # • Bullet Point symbol (solid) 3436 C("Alt-9"): UC(0x00AA), # ª Feminine Ordinal Indicator 3437 C("Alt-0"): UC(0x00BA), # º Masculine Ordinal Indicator 3438 C("Alt-Minus"): UC(0x2013), # – En Dash punctuation mark 3439 C("Alt-Equal"): UC(0x2260), # ≠ Not Equal To symbol 3440 3441 # Number keys row with Shift+Option 3442 ###################################################### 3443 C("Shift-Alt-Grave"): UC(0x0300), # ` Combining Grave Accent 3444 C("Shift-Alt-1"): UC(0x2044), # ⁄ Fraction Slash 3445 C("Shift-Alt-2"): UC(0x20AC), # € Euro currency symbol 3446 C("Shift-Alt-3"): UC(0x2039), # ‹ Single Left-Pointing Angle Quotation mark 3447 C("Shift-Alt-4"): UC(0x203A), # › Single Right-Pointing Angle Quotation mark 3448 C("Shift-Alt-5"): UC(0x2020), # † Simple dagger (cross) symbol 3449 C("Shift-Alt-6"): UC(0x0302), # ̂ Combining Circumflex Accent 3450 C("Shift-Alt-7"): UC(0x2021), # ‡ Double dagger (cross) symbol 3451 C("Shift-Alt-8"): UC(0x00B0), # ° Degree Sign 3452 C("Shift-Alt-9"): UC(0x00B7), # · Middle Dot (interpunct/middot) 3453 C("Shift-Alt-0"): UC(0x201A), # ‚ Single low-9 quotation mark 3454 C("Shift-Alt-Minus"): UC(0x2014), # — Em Dash punctuation mark 3455 C("Shift-Alt-Equal"): UC(0x00B1), # ± Plus Minus mathematical symbol 3456 3457 # Tab key row with Option 3458 ###################################################### 3459 C("Alt-Q"): UC(0x0153), # œ Small oe (oethel) ligature 3460 3461 C("Alt-W"): [UC(0x02D9),C("Shift-Left"),setDK(0x02D9)], # Dead Key Accent: Dot Above 3462 C("Alt-E"): [UC(0x00B4),C("Shift-Left"),setDK(0x00B4)], # Dead Key Accent: Acute 3463 3464 C("Alt-R"): UC(0x00AE), # ® Registered Trade Mark Sign 3465 C("Alt-T"): UC(0x00FE), # þ Latin Small Letter Thorn 3466 C("Alt-Y"): UC(0x00A5), # ¥ Japanese Yen currency symbol 3467 3468 C("Alt-U"): [UC(0x00A8),C("Shift-Left"),setDK(0x00A8)], # Dead Key Accent: Umlaut/Diaeresis 3469 C("Alt-I"): [UC(0x02BC),C("Shift-Left"),setDK(0x02BC)], # Dead Key Accent: Apostrophe/Horn 3470 3471 C("Alt-O"): UC(0x00F8), # ø Latin Small Letter o with Stroke 3472 3473 C("Alt-P"): [UC(0x002C),C("Shift-Left"),setDK(0x002C)], # Dead Key Accent: Comma Below 3474 3475 C("Alt-Left_Brace"): UC(0x201C), # “ Left Double Quotation Mark 3476 C("Alt-Right_Brace"): UC(0x2018), # ‘ Left Single Quotation Mark 3477 C("Alt-Backslash"): UC(0x00AB), # « Left-Pointing Double Angle Quotation Mark 3478 3479 # Tab key row with Shift+Option 3480 ###################################################### 3481 C("Shift-Alt-Q"): UC(0x0152), # Œ Capital OE (Oethel) ligature 3482 C("Shift-Alt-W"): UC(0x0307), # ˙ Combining Dot Above 3483 C("Shift-Alt-E"): UC(0x0301), # ́ Combining Acute Accent 3484 C("Shift-Alt-R"): UC(0x2030), # ‰ Per mille symbol (zero over zero-zero) 3485 C("Shift-Alt-T"): UC(0x00DE), # Þ Latin Capital Letter Thorn 3486 3487 # C("Shift-Alt-Y"): UC(0x02F5), # UC(0x030F), # ̏ Combining Double Grave Accent 3488 # Spacing issues when using Combining Double Grave {U+030F} 3489 # Substituting {U+02F5}: ˵ Modifier Letter Middle Double Grave Accent for initial presentation 3490 C("Shift-Alt-Y"): [UC(0x02F5),C("Shift-Left"),setDK(0x02F5)], # Dead Key Accent: Double Grave 3491 3492 C("Shift-Alt-U"): UC(0x0308), # ̈ Combining Diaeresis/Umlaut 3493 C("Shift-Alt-I"): UC(0x031B), # ̛ Combining Horn (Apostrophe) 3494 C("Shift-Alt-O"): UC(0x00D8), # Ø Latin Capital Letter O with Stroke 3495 C("Shift-Alt-P"): UC(0x0326), # ̦ Combining Comma Below 3496 C("Shift-Alt-Left_Brace"): UC(0x201D), # ” Right Double Quotation Mark 3497 C("Shift-Alt-Right_Brace"): UC(0x2019), # ’ Right Single Quotation Mark 3498 C("Shift-Alt-Backslash"): UC(0x00BB), # » Right-Pointing Double Angle Quotation Mark 3499 3500 # CapsLock key row with Option 3501 ###################################################### 3502 3503 C("Alt-A"): [UC(0x00AF),C("Shift-Left"),setDK(0x00AF)], # Dead Key Accent: Macron/Line Above 3504 3505 C("Alt-S"): UC(0x00DF), # ß German Eszett/beta (Sharfes/Sharp S) 3506 C("Alt-D"): UC(0x00F0), # ð Latin Small Letter Eth 3507 C("Alt-F"): UC(0x0192), # ƒ Function/florin currency symbol 3508 C("Alt-G"): UC(0x00A9), # © Copyright Sign 3509 3510 C("Alt-H"): [UC(0x02CD),C("Shift-Left"),setDK(0x02CD)], # Dead Key Accent: Low Macron/Line Below 3511 C("Alt-J"): [UC(0x02DD),C("Shift-Left"),setDK(0x02DD)], # Dead Key Accent: Double Acute 3512 C("Alt-K"): [UC(0x02DA),C("Shift-Left"),setDK(0x02DA)], # Dead Key Accent: Ring Above 3513 C("Alt-L"): [UC(0x002D),C("Shift-Left"),setDK(0x002D)], # Dead Key Accent: Stroke/Hyphen-Minus 3514 3515 C("Alt-Semicolon"): UC(0x2026), # … Horizontal ellipsis 3516 C("Alt-Apostrophe"): UC(0x00E6), # æ Small ae ligature 3517 3518 # CapsLock key row with Shift+Option 3519 ###################################################### 3520 C("Shift-Alt-A"): UC(0x0304), # ̄ Combining Macron/Line Below 3521 3522 # C("Shift-Alt-S"): [UC(0x0311),C("Shift-Left"),setDK(0x0311)], # Dead Key Accent: Combining Inverted Breve 3523 # Combining Inverted Breve has spacing problems 3524 # Substituting {U+1D16}: ᴖ Latin Small Letter Top Half O 3525 C("Shift-Alt-S"): [UC(0x1D16),C("Shift-Left"),setDK(0x1D16)], # Dead Key Accent: Inverted Breve 3526 3527 C("Shift-Alt-D"): UC(0x00D0), # Ð Latin Capital Letter Eth 3528 3529 # C("Shift-Alt-F"): [UC(0x0330),C("Shift-Left"),setDK(0x0330)], # Dead Key Accent: Tilde Below 3530 # Combining Tilde Below has spacing problems 3531 # Substituting {U+02F7}: ˷ Modifier Letter Low Tilde 3532 C("Shift-Alt-F"): [UC(0x02F7),C("Shift-Left"),setDK(0x02F7)], # Dead Key Accent: Tilde Below 3533 C("Shift-Alt-G"): [UC(0x2038),C("Shift-Left"),setDK(0x2038)], # Dead Key Accent: Caret/Circumflex Below 3534 3535 C("Shift-Alt-H"): UC(0x0331), # ̱ Combining Macron/Line Below 3536 C("Shift-Alt-J"): UC(0x030B), # ̋ Combining Double Acute Accent 3537 C("Shift-Alt-K"): UC(0x030A), # ̊ Combining Ring Above 3538 C("Shift-Alt-L"): UC(0x0335), # ̵ Combining Short Stroke Overlay 3539 3540 C("Shift-Alt-Semicolon"): [UC(0x2116),C("Shift-Left"),setDK(0x2116)], # Dead Key Accent: Numero Sign 3541 3542 C("Shift-Alt-Apostrophe"): UC(0x00C6), # Æ Capital AE ligature 3543 3544 # Shift keys row with Option 3545 ###################################################### 3546 3547 C("Alt-Z"): [UC(0x02C0),C("Shift-Left"),setDK(0x02C0)], # Dead Key Accent: Hook Above/Glottal Stop 3548 C("Alt-X"): [UC(0x002E),C("Shift-Left"),setDK(0x002E)], # Dead Key Accent: Dot Below 3549 C("Alt-C"): [UC(0x00B8),C("Shift-Left"),setDK(0x00B8)], # Dead Key Accent: Cedilla/Cedille 3550 C("Alt-V"): [UC(0x02C7),C("Shift-Left"),setDK(0x02C7)], # Dead Key Accent: Caron/hacek 3551 C("Alt-B"): [UC(0x02D8),C("Shift-Left"),setDK(0x02D8)], # Dead Key Accent: Breve 3552 C("Alt-N"): [UC(0x02DC),C("Shift-Left"),setDK(0x02DC)], # Dead Key Accent: Tilde 3553 C("Alt-M"): [UC(0x02DB),C("Shift-Left"),setDK(0x02DB)], # Dead Key Accent: Ogonek 3554 3555 C("Alt-Comma"): UC(0x2264), # ≤ Less Than or Equal To symbol 3556 C("Alt-Dot"): UC(0x2265), # ≥ Greater Than or Equal To symbol 3557 C("Alt-Slash"): UC(0x00F7), # ÷ Obelus/Division symbol 3558 3559 # Shift keys row with Shift+Option 3560 ###################################################### 3561 C("Shift-Alt-Z"): UC(0x0309), # ̉ Combining Hook Above (hoi) 3562 C("Shift-Alt-X"): UC(0x0323), # ̣ Combining Dot Below (nang) 3563 C("Shift-Alt-C"): UC(0x0327), # ̧ Combining Cedilla 3564 C("Shift-Alt-V"): UC(0x030C), # ̌ Combining Caron/hacek 3565 C("Shift-Alt-B"): UC(0x0306), # ̆ Combining Breve 3566 C("Shift-Alt-N"): UC(0x0303), # ̃ Combining Tilde 3567 C("Shift-Alt-M"): UC(0x0328), # ̨ Combining Ogonek (nasal hook) 3568 C("Shift-Alt-Comma"): UC(0x201E), # „ Double Low-9 Quotation Mark 3569 3570 C("Shift-Alt-Dot"): [UC(0x0294),C("Shift-Left"),setDK(0x0294)], # Dead Key Accent: Hook 3571 3572 C("Shift-Alt-Slash"): UC(0x00BF), # ¿ Inverted Question mark 3573 3574 }, when = lambda ctx: 3575 cnfg.screen_has_focus and 3576 cnfg.optspec_layout == 'ABC' and 3577 matchProps(not_clas=terms_and_remotes_Str)(ctx) 3578 ) 3579 3580 3581 3582 ###################################################################### 3583 ### ### 3584 ### ### 3585 ### ██ ██ ███████ ███ ███ █████ ██ ███ ██ ### 3586 ### ██ ██ ██ ████ ████ ██ ██ ██ ████ ██ ### 3587 ### ██ ██ ███████ ██ ████ ██ ███████ ██ ██ ██ ██ ### 3588 ### ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 3589 ### ██████ ███████ ██ ██ ██ ██ ██ ██ ████ ### 3590 ### ### 3591 ### ### 3592 ###################################################################### 3593 # Main keymap for special characters on the standard US layout 3594 keymap("OptSpecialChars - US", { 3595 3596 # Number keys row with Option 3597 ###################################################### 3598 C("Alt-Grave"): [UC(0x0060), C("Shift-Left"), setDK(0x0060)], # Dead Key Accent: Grave 3599 3600 C("Alt-1"): UC(0x00A1), # ¡ Inverted Exclamation Mark 3601 C("Alt-2"): UC(0x2122), # ™ Trade Mark Sign Emoji 3602 C("Alt-3"): UC(0x00A3), # £ British Pound currency symbol 3603 C("Alt-4"): UC(0x00A2), # ¢ Cent currency symbol 3604 C("Alt-5"): UC(0x221E), # ∞ Infinity mathematical symbol 3605 C("Alt-6"): UC(0x00A7), # § Section symbol 3606 C("Alt-7"): UC(0x00B6), # ¶ Paragraph mark (Pilcrow) symbol 3607 C("Alt-8"): UC(0x2022), # • Bullet Point symbol (solid) 3608 C("Alt-9"): UC(0x00AA), # ª Feminine Ordinal Indicator 3609 C("Alt-0"): UC(0x00BA), # º Masculine Ordinal Indicator 3610 C("Alt-Minus"): UC(0x2013), # – En Dash punctuation mark 3611 C("Alt-Equal"): UC(0x2260), # ≠ Not Equal To symbol 3612 3613 # Number keys row with Shift+Option 3614 ###################################################### 3615 C("Shift-Alt-Grave"): UC(0x0060), # ` Grave Accent (non-combining) 3616 C("Shift-Alt-1"): UC(0x2044), # ⁄ Fraction Slash 3617 C("Shift-Alt-2"): UC(0x20AC), # € Euro currency symbol 3618 C("Shift-Alt-3"): UC(0x2039), # ‹ Single Left-Pointing Angle Quotation mark 3619 C("Shift-Alt-4"): UC(0x203A), # › Single Right-Pointing Angle Quotation mark 3620 C("Shift-Alt-5"): UC(0xFB01), # fi Latin Small Ligature Fi 3621 C("Shift-Alt-6"): UC(0xFB02), # fl Latin Small Ligature Fl 3622 C("Shift-Alt-7"): UC(0x2021), # ‡ Double dagger (cross) symbol 3623 C("Shift-Alt-8"): UC(0x00B0), # ° Degree Sign 3624 C("Shift-Alt-9"): UC(0x00B7), # · Middle Dot (interpunct/middot) 3625 C("Shift-Alt-0"): UC(0x201A), # ‚ Single low-9 quotation mark 3626 C("Shift-Alt-Minus"): UC(0x2014), # — Em Dash punctuation mark 3627 C("Shift-Alt-Equal"): UC(0x00B1), # ± Plus Minus mathematical symbol 3628 3629 # Tab key row with Option 3630 ###################################################### 3631 C("Alt-Q"): UC(0x0153), # œ Small oe (oethel) ligature 3632 C("Alt-W"): UC(0x2211), # ∑ N-Ary Summation (sigma) notation 3633 3634 C("Alt-E"): [UC(0x00B4), C("Shift-Left"), setDK(0x00B4)], # Dead Key Accent: Acute 3635 3636 C("Alt-R"): UC(0x00AE), # ® Registered Trade Mark Sign 3637 C("Alt-T"): UC(0x2020), # † Simple dagger (cross) symbol 3638 C("Alt-Y"): UC(0x00A5), # ¥ Japanese Yen currency symbol 3639 3640 C("Alt-U"): [UC(0x00A8), C("Shift-Left"), setDK(0x00A8)], # Dead Key Accent: Umlaut/Diaeresis 3641 3642 C("Alt-I"): [UC(0x02C6), C("Shift-Left"), setDK(0x02C6)], # Dead Key Accent: Circumflex 3643 3644 C("Alt-O"): UC(0x00F8), # ø Latin Small Letter o with Stroke 3645 C("Alt-P"): UC(0x03C0), # π Greek Small Letter Pi 3646 C("Alt-Left_Brace"): UC(0x201C), # “ Left Double Quotation Mark 3647 C("Alt-Right_Brace"): UC(0x2018), # ‘ Left Single Quotation Mark 3648 C("Alt-Backslash"): UC(0x00AB), # « Left-Pointing Double Angle Quotation Mark 3649 3650 # Tab key row with Shift+Option 3651 ###################################################### 3652 C("Shift-Alt-Q"): UC(0x0152), # Œ Capital OE (Oethel) ligature 3653 C("Shift-Alt-W"): UC(0x201E), # „ Double Low-9 Quotation mark 3654 C("Shift-Alt-E"): UC(0x00B4), # ´ Acute Accent diacritic (non-combining) 3655 C("Shift-Alt-R"): UC(0x2030), # ‰ Per mille symbol (zero over zero-zero) 3656 C("Shift-Alt-T"): UC(0x02C7), # ˇ Caron/hacek diacritic (non-combining) 3657 C("Shift-Alt-Y"): UC(0x00C1), # Á Latin Capital Letter A with Acute 3658 C("Shift-Alt-U"): UC(0x00A8), # ¨ Diaeresis/Umlaut (non-combining) 3659 C("Shift-Alt-I"): UC(0x02C6), # ˆ Circumflex Accent (non-combining) 3660 C("Shift-Alt-O"): UC(0x00D8), # Ø Latin Capital Letter O with Stroke 3661 C("Shift-Alt-P"): UC(0x220F), # ∏ N-Ary Product mathematical symbol 3662 C("Shift-Alt-Left_Brace"): UC(0x201D), # ” Right Double Quotation Mark 3663 C("Shift-Alt-Right_Brace"): UC(0x2019), # ’ Right Single Quotation Mark 3664 C("Shift-Alt-Backslash"): UC(0x00BB), # » Right-Pointing Double Angle Quotation Mark 3665 3666 # CapsLock key row with Option 3667 ###################################################### 3668 C("Alt-A"): UC(0x00E5), # å Small Letter a with Ring Above 3669 C("Alt-S"): UC(0x00DF), # ß German Eszett/beta (Sharfes/Sharp S) 3670 C("Alt-D"): UC(0x2202), # ∂ Partial Differential 3671 C("Alt-F"): UC(0x0192), # ƒ Function/florin currency symbol 3672 C("Alt-G"): UC(0x00A9), # © Copyright Sign 3673 C("Alt-H"): UC(0x02D9), # ˙ Dot Above diacritic (non-combining) 3674 C("Alt-J"): UC(0x2206), # ∆ Increment, laplace operator symbol 3675 C("Alt-K"): UC(0x02DA), # ˚ Ring Above diacritic (non-combining) 3676 C("Alt-L"): UC(0x00AC), # ¬ Not Sign angled dash symbol 3677 C("Alt-Semicolon"): UC(0x2026), # … Horizontal ellipsis 3678 C("Alt-Apostrophe"): UC(0x00E6), # æ Small ae ligature 3679 3680 # CapsLock key row with Shift+Option 3681 ###################################################### 3682 C("Shift-Alt-A"): UC(0x00C5), # Å Capital Letter A with Ring Above 3683 C("Shift-Alt-S"): UC(0x00CD), # Í Latin Capital Letter I with Acute 3684 C("Shift-Alt-D"): UC(0x00CE), # Î Latin Capital Letter I with Circumflex 3685 C("Shift-Alt-F"): UC(0x00CF), # Ï Latin Capital Letter I with Diaeresis 3686 C("Shift-Alt-G"): UC(0x02DD), # ˝ Double Acute Accent (non-combining) 3687 C("Shift-Alt-H"): UC(0x00D3), # Ó Latin Capital Letter O with Acute 3688 C("Shift-Alt-J"): UC(0x00D4), # Ô Latin Capital Letter O with Circumflex 3689 ######################################################################################################### 3690 # The Apple logo is at {U+F8FF} in a Unicode Private Use Area. Only at that location in Mac fonts. 3691 # Symbol exists at {U+F000} in Baskerville Old Face font. 3692 C("Shift-Alt-K"): [apple_logo_alert,UC(0xF000)], # Apple logo [req's Baskerville Old Face font] 3693 C("Shift-Alt-L"): UC(0x00D2), # Ò Latin Capital Letter O with Grave 3694 C("Shift-Alt-Semicolon"): UC(0x00DA), # Ú Latin Capital Letter U with Acute 3695 C("Shift-Alt-Apostrophe"): UC(0x00C6), # Æ Capital AE ligature 3696 3697 # Shift keys row with Option 3698 ###################################################### 3699 C("Alt-Z"): UC(0x03A9), # Ω Greek Capital Letter Omega 3700 C("Alt-X"): UC(0x2248), # ≈ Almost Equal To symbol 3701 C("Alt-C"): UC(0x00E7), # ç Small Letter c with Cedilla 3702 C("Alt-V"): UC(0x221A), # √ Square Root radical sign 3703 C("Alt-B"): UC(0x222B), # ∫ Integral mathematical symbol 3704 3705 C("Alt-N"): [UC(0x02DC), C("Shift-Left"), setDK(0x02DC)], # Dead Key Accent: Tilde 3706 3707 C("Alt-M"): UC(0x00B5), # µ Micro (mu) symbol 3708 C("Alt-Comma"): UC(0x2264), # ≤ Less Than or Equal To symbol 3709 C("Alt-Dot"): UC(0x2265), # ≥ Greater Than or Equal To symbol 3710 C("Alt-Slash"): UC(0x00F7), # ÷ Obelus/Division symbol 3711 3712 # Shift keys row with Shift+Option 3713 ###################################################### 3714 C("Shift-Alt-Z"): UC(0x00B8), # ¸ Spacing Cedilla diacritic (non-combining) 3715 C("Shift-Alt-X"): UC(0x02DB), # ˛ Ogonek diacritic (non-combining) 3716 C("Shift-Alt-C"): UC(0x00C7), # Ç Capital Letter C with Cedilla 3717 C("Shift-Alt-V"): UC(0x25CA), # ◊ Lozenge (diamond) shape symbol 3718 C("Shift-Alt-B"): UC(0x0131), # ı Latin Small Letter Dotless i 3719 C("Shift-Alt-N"): UC(0x02DC), # ˜ Small Tilde character 3720 C("Shift-Alt-M"): UC(0x00C2), #  Latin Capital Letter A with Circumflex 3721 C("Shift-Alt-Comma"): UC(0x00AF), # ¯ Macron/overline/overbar (non-combining) 3722 C("Shift-Alt-Dot"): UC(0x02D8), # ˘ Breve diacritic (non-combining) 3723 C("Shift-Alt-Slash"): UC(0x00BF), # ¿ Inverted Question mark 3724 3725 }, when = lambda ctx: 3726 cnfg.screen_has_focus and 3727 cnfg.optspec_layout == 'US' and 3728 matchProps(not_clas=terms_and_remotes_Str)(ctx) 3729 ) 3730 3731 3732 3733 #################################### USER APPS ##################################### 3734 ### ### 3735 ### ### 3736 ### ██ ██ ███████ ███████ ██████ █████ ██████ ██████ ███████ ### 3737 ### ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 3738 ### ██ ██ ███████ █████ ██████ ███████ ██████ ██████ ███████ ### 3739 ### ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 3740 ### ██████ ███████ ███████ ██ ██ ██ ██ ██ ██ ███████ ### 3741 ### ### 3742 ### ### 3743 ###################################################################################### 3744 ### This is a good location in the config file for adding new custom keymaps for 3745 ### user applications and custom function keys. Watch out that you don't override 3746 ### any "general" shortcuts like Cmd+Z/X/C/V that may be defined below this section. 3747 ### Changes made between the "slice" marks will be retained by the Toshy installer 3748 ### if you reinstall and it finds matching start/end markers for each section. 3749 3750 ################################################################################################### 3751 ### SLICE_MARK_START: user_apps ### EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE 3752 3753 3754 keymap("User hardware keys", { 3755 # PUT UNIVERSAL REMAPS FOR HARDWARE KEYS HERE 3756 # KEYMAP WILL BE ACTIVE IN ALL DESKTOP ENVIRONMENTS/DISTROS 3757 3758 C("RC-Space"): open_launcher, # Command+Space to open Albert launcher 3759 3760 }, when = lambda ctx: 3761 cnfg.screen_has_focus and 3762 matchProps(not_clas=remoteStr)(ctx) 3763 ) 3764 3765 ### SLICE_MARK_END: user_apps ### EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE 3766 ################################################################################################### 3767 3768 3769 # HOW TO SWAP CMD+SPACE AND CTRL+SPACE (SPOTLIGHT EQUIVALENT VS INPUT SWITCHING) 3770 # Copy this entire block into the "user_apps" editable slice markers, and 3771 # uncomment everything below this text. Fix the output shortcuts to work on your 3772 # chosen desktop environment. 3773 # 3774 # keymap("User overrides terminals", { 3775 # C("LC-Space"): [iEF2NT(),C("THE-REAL-COMBO-FOR-SOME-LAUNCHER")], # Spotlight equivalent 3776 # C("Shift-LC-Space"): None, # block the default general terminals shortcut for input switching 3777 # }, when = lambda ctx: 3778 # cnfg.screen_has_focus and 3779 # matchProps(clas=termStr)(ctx) 3780 # ) 3781 # keymap("User overrides general", { 3782 # C("Super-Space"): [iEF2NT(),C("THE-REAL-COMBO-FOR-SOME-LAUNCHER")], # Spotlight equivalent 3783 # C("Shift-Super-Space"): None, # block the default general GUI shortcut for reverse input switching 3784 # ### Keyboard input source (language/layout) switching 3785 # C("RC-Space"): [bind,C("THE-REAL-COMBO-FOR-INPUT-SWITCHING")], # input switch forward 3786 # C("Shift-RC-Space"): [bind,C("THE-REAL-COMBO-FOR-REVERSE-INPUT-SWITCHING")], # input switch reverse (OPTIONAL) 3787 # }, when = lambda ctx: 3788 # cnfg.screen_has_focus and 3789 # matchProps(clas=remoteStr)(ctx) 3790 # ) 3791 3792 3793 3794 ################################# MISC APPS ##################################### 3795 ### ### 3796 ### ### 3797 ### ███ ███ ██ ███████ ██████ █████ ██████ ██████ ███████ ### 3798 ### ████ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 3799 ### ██ ████ ██ ██ ███████ ██ ███████ ██████ ██████ ███████ ### 3800 ### ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 3801 ### ██ ██ ██ ███████ ██████ ██ ██ ██ ██ ███████ ### 3802 ### ### 3803 ### ### 3804 ################################################################################### 3805 # Miscellaneous apps that need a few fixes 3806 3807 keymap("Thunderbird email client", { 3808 C("Alt-RC-I"): C("Shift-C-I"), # Dev tools 3809 # Enable Cmd+Option+Left/Right for tab navigation 3810 C("RC-Alt-Left"): [bind,C("C-Page_Up")], # Go to prior tab (macOS Thunderbird tab nav shortcut) 3811 C("RC-Alt-Right"): [bind,C("C-Page_Down")], # Go to next tab (macOS Thunderbird tab nav shortcut) 3812 }, when = lambda ctx: 3813 cnfg.screen_has_focus and 3814 matchProps(clas="^thunderbird.*$|^org.mozilla.thunderbird$")(ctx) ) 3815 3816 keymap("Angry IP Scanner", { 3817 C("RC-comma"): C("Shift-C-P"), # Open preferences 3818 C("RC-i"): C("Alt-Enter"), # Get info (details) 3819 C("RC-h"): C("C-h"), # Go to next live host (override hide window) 3820 C("Shift-RC-i"): C("C-i"), # Invert selection 3821 }, when = lambda ctx: 3822 cnfg.screen_has_focus and 3823 matchProps(clas="^Angry.*IP.*Scanner$")(ctx) ) 3824 3825 keymap("Transmission bittorrent client", { 3826 C("RC-i"): C("Alt-Enter"), # Open properties (Get Info) dialog 3827 C("RC-comma"): [C("Alt-e"),C("p")], # Open preferences (settings) dialog 3828 }, when = lambda ctx: 3829 cnfg.screen_has_focus and 3830 matchProps(clas=transmissionStr)(ctx) ) 3831 3832 keymap("JDownloader", { 3833 # Fixes for tab navigation done here instead of in the main tab nav fix keymaps, 3834 # because we have to use a "list of dicts" to match some JDownloader windows. 3835 C("Shift-RC-Left_Brace"): [bind,C("C-Shift-Tab")], # Tab nav: Go to prior tab (left) 3836 C("Shift-RC-Right_Brace"): [bind,C("C-Tab")], # Tab nav: Go to next tab (right) 3837 C("Shift-RC-Left"): [bind,C("C-Shift-Tab")], # Tab nav: Go to prior tab (left) 3838 C("Shift-RC-Right"): [bind,C("C-Tab")], # Tab nav: Go to next tab (right) 3839 3840 C("RC-i"): C("Alt-Enter"), # Open properties 3841 C("RC-Backspace"): C("Delete"), # Remove download from list 3842 C("RC-Comma"): C("C-P"), # Open preferences (settings) 3843 }, when = lambda ctx: 3844 cnfg.screen_has_focus and 3845 matchProps(lst=JDownloader_lod)(ctx) ) 3846 3847 keymap("Totem video player", { 3848 C("RC-dot"): C("C-q"), # Stop (quit player, there is no "Stop" function) 3849 }, when = lambda ctx: 3850 cnfg.screen_has_focus and 3851 matchProps(clas="^totem$")(ctx) ) 3852 3853 keymap("GNOME image viewer", { 3854 C("RC-i"): C("Alt-Enter"), # Image properties 3855 }, when = lambda ctx: 3856 cnfg.screen_has_focus and 3857 matchProps(clas="^eog$")(ctx) ) 3858 3859 keymap("LibreOffice Writer", { 3860 C("RC-comma"): C("Alt-F12"), # Tools > Options (preferences dialog) 3861 }, when = lambda ctx: 3862 cnfg.screen_has_focus and 3863 matchProps(clas="^libreoffice-writer$")(ctx) ) 3864 3865 3866 3867 ######################################## FINDER MODS ############################################# 3868 ### ### 3869 ### ### 3870 ### ███████ ██ ███ ██ ██████ ███████ ██████ ███ ███ ██████ ██████ ███████ ### 3871 ### ██ ██ ████ ██ ██ ██ ██ ██ ██ ████ ████ ██ ██ ██ ██ ██ ### 3872 ### █████ ██ ██ ██ ██ ██ ██ █████ ██████ ██ ████ ██ ██ ██ ██ ██ ███████ ### 3873 ### ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 3874 ### ██ ██ ██ ████ ██████ ███████ ██ ██ ██ ██ ██████ ██████ ███████ ### 3875 ### ### 3876 ### ### 3877 #################################################################################################### 3878 3879 ### START OF FILE MANAGER GROUP OF KEYMAPS - FINDER MODS ### 3880 3881 # Keybindings overrides for Caja 3882 # (overrides some bindings from general file manager code block below) 3883 keymap("Overrides for Caja - Finder Mods", { 3884 C("RC-Super-o"): C("Shift-C-Enter"), # Open in new tab 3885 # C("RC-Super-o"): C("Shift-C-W"), # Open in new window 3886 }, when = lambda ctx: 3887 cnfg.screen_has_focus and 3888 matchProps(clas="^caja$")(ctx) ) 3889 3890 # Keybindings overrides for COSMIC Files 3891 # (overrides some bindings from general file manager code block below) 3892 keymap("Overrides for COSMIC Files - Finder Mods", { 3893 # No shortcuts yet to change the view modes? 3894 # TODO: Add Grid/List view mode shortcuts when available (if different from general FMs) 3895 # Tab nav uses Ctrl+Tab/Shift+Ctrl+Tab 3896 C("Shift-RC-Left_Brace"): [bind,C("Shift-C-Tab")], # Go to prior tab (left) 3897 C("Shift-RC-Right_Brace"): [bind,C("C-Tab")], # Go to next tab (right) 3898 C("Shift-RC-Left"): [bind,C("Shift-C-Tab")], # Go to prior tab (left) 3899 C("Shift-RC-Right"): [bind,C("C-Tab")], # Go to next tab (right) 3900 # COSMIC uses nonstandard shortcut (Space) for file/folder Properties dialog 3901 C("RC-i"): C("Space"), # Get info (properties) [MacOS shortcut] 3902 C("Alt-Enter"): C("Space"), # Get info (properties) [Linux shortcut] 3903 }, when = lambda ctx: 3904 cnfg.screen_has_focus and 3905 matchProps(clas="^com.system76.CosmicFiles$")(ctx) ) 3906 3907 # Keybindings overrides for DDE (Deepin) File Manager 3908 # (overrides some bindings from general file manager code block below) 3909 keymap("Overrides for DDE File Manager - Finder Mods", { 3910 C("RC-i"): C("C-i"), # File properties dialog (Get Info) 3911 C("RC-comma"): None, # Disable preferences shortcut (no shortcut available) 3912 C("RC-Up"): C("C-Up"), # Go Up dir 3913 C("Shift-RC-Left_Brace"): [bind,C("C-Shift-Tab")], # Go to prior tab 3914 C("Shift-RC-Right_Brace"): [bind,C("C-Tab")], # Go to next tab 3915 C("Shift-RC-Left"): [bind,C("C-Shift-Tab")], # Go to prior tab 3916 C("Shift-RC-Right"): [bind,C("C-Tab")], # Go to next tab 3917 }, when = lambda ctx: 3918 cnfg.screen_has_focus and 3919 matchProps(clas="^dde-file-manager$")(ctx) ) 3920 3921 ########################## DOLPHIN KEYMAPS - BEGIN ########################## 3922 # Keybindings overrides for Dolphin (KDE file manager) 3923 # (overrides some bindings from general file manager code block below) 3924 3925 keymap("Overrides for Dolphin - Finder Mods pre-KF6", { 3926 # KDE Frameworks 6 assigns F10 to "Open Main Manu" so this is only valid for KF5 now 3927 # (Reference https://planet.kde.org/felix-ernst-2023-10-13-f10-for-accessibility-in-kf6/) 3928 C("Shift-RC-n"): iEF2(C("F10"), False), # Create new folder (F10), toggle Enter to be Enter (pre-KF6!) 3929 }, when = lambda ctx: 3930 cnfg.screen_has_focus and 3931 DESKTOP_ENV == 'kde' and DE_MAJ_VER in ['5', '4', '3'] and 3932 matchProps(clas="^dolphin$|^org.kde.dolphin$")(ctx) 3933 ) 3934 3935 # Dolphin dialog names where Enter should always be Enter (not F2/Enter toggle) 3936 dlgs_Dolphin_Enter_is_Enter = [ 3937 "Edit Places Entry.*", 3938 "Create New File.*", 3939 "Folder Already Exists.*", 3940 "File Already Exists.*", 3941 ] 3942 # Convert list to regex pattern string 3943 dlgs_Dolphin_Enter_is_Enter_Str = toRgxStr(dlgs_Dolphin_Enter_is_Enter) 3944 3945 keymap("Overrides for Dolphin dialogs - Finder Mods", { 3946 C("Enter"): C("Enter"), # Override Enter to be Enter (never F2) for dialogs 3947 }, when = lambda ctx: 3948 cnfg.screen_has_focus and 3949 matchProps(clas="^dolphin$|^org.kde.dolphin$", name=dlgs_Dolphin_Enter_is_Enter_Str)(ctx) 3950 ) 3951 3952 keymap("Overrides for Dolphin - Finder Mods", { 3953 C("RC-r"): C("F5"), # Refresh folder view with Cmd+R (like browsers) 3954 C("RC-KEY_2"): C("C-KEY_3"), # View as List (Detailed) 3955 C("RC-KEY_3"): C("C-KEY_2"), # View as List (Compact) 3956 ########################################################################################## 3957 ### "Open in new window" (or new tab) requires manually setting custom shortcut of Ctrl+Shift+o 3958 ### in Dolphin's keyboard shortcuts. There is no default shortcut set for this function. 3959 ########################################################################################## 3960 C("RC-Super-o"): C("Shift-C-o"), # Open in new window (or new tab, user's choice, see above) 3961 C("Shift-RC-n"): iEF2(C("Shift-C-n"), False), # Create new folder, toggle Enter to be Enter (KF6 and later) 3962 C("RC-comma"): C("Shift-C-comma"), # Open preferences dialog 3963 }, when = lambda ctx: 3964 cnfg.screen_has_focus and 3965 matchProps(clas="^dolphin$|^org.kde.dolphin$")(ctx) ) 3966 3967 # 3968 ########################### DOLPHIN KEYMAPS - END ########################### 3969 3970 3971 # Keybindings overrides for elementary OS Files (Pantheon) 3972 # (overrides some bindings from general file manager code block below) 3973 keymap("Overrides for Pantheon - Finder Mods", { 3974 C("RC-Super-o"): C("Shift-Enter"), # Open folder in new tab 3975 C("RC-comma"): None, # Disable preferences shortcut since none available 3976 }, when = lambda ctx: 3977 cnfg.screen_has_focus and 3978 matchProps(clas="^io.elementary.files$")(ctx) ) 3979 3980 # Keybindings overrides for Krusader (alternative/old KDE file manager) 3981 # (overrides some bindings from general file manager code block below) 3982 keymap("Overrides for Krusader - Finder Mods", { 3983 C("Shift-RC-Dot"): C("Alt-Dot"), # Toggle hidden files visibility ("dot" files) 3984 # C("RC-n"): None, # Enable this to block Cmd+N (new window is not possible?) 3985 C("RC-Shift-n"): iEF2(C("F7"), False), # New folder (F7) 3986 C("RC-KEY_1"): None, # View as Icons [Not available, blocked] 3987 C("RC-KEY_2"): C("Alt-Shift-D"), # View as List (Detailed) 3988 C("RC-KEY_3"): C("Alt-Shift-B"), # View as List (Compact) 3989 C("RC-KEY_4"): None, # View as Gallery [Not available, blocked] 3990 C("RC-Backspace"): [C("Delete"), sleep(0.5), C("Tab"), sleep(0.5), C("Enter")], # Delete file/folder (auto-confirm) 3991 # C("RC-Backspace"): C("Delete"), # Delete file/folder (no auto-confirm) 3992 }, when = lambda ctx: 3993 cnfg.screen_has_focus and 3994 matchProps(clas="^org.kde.krusader$|^krusader$")(ctx) ) 3995 3996 # Keybindings overrides for Nautilus 3997 # (overrides some bindings from general file manager code block below) 3998 keymap("Overrides for Nautilus Create Archive dialog - Finder Mods", { 3999 C("Enter"): C("Enter"), # Use Enter as Enter in the Create Archive dialog 4000 }, when = lambda ctx: 4001 cnfg.screen_has_focus and 4002 matchProps(clas="^org.gnome.nautilus$|^nautilus$", name="Create Archive")(ctx) ) 4003 4004 keymap("Overrides for Nautilus - Finder Mods", { 4005 # Optional "new window at home folder" in Nautilus 4006 # C("RC-N"): C("C-Alt-Space"), # macOS Finder search window shortcut Cmd+Option+Space 4007 # For the above shortcut to work, a custom shortcut bound to Ctrl+Alt+Space must be set up in the 4008 # Settings app in GNOME to run command: "nautilus --new-window /home/USER" [ replace "USER" ] 4009 C("RC-KEY_1"): C("C-KEY_2"), # View as Icons 4010 C("RC-KEY_2"): C("C-KEY_1"), # View as List (Detailed) 4011 # C("RC-Super-o"): C("Shift-Enter"), # Open in new window (disable line below) 4012 C("RC-Super-o"): C("C-Enter"), # Open in new tab (disable line above) 4013 C("RC-comma"): C("C-comma"), # Overrides "Open preferences dialog" shortcut below 4014 C("RC-F"): C("C-F"), # Don't toggle Enter key, pass Cmd+F 4015 }, when = lambda ctx: 4016 cnfg.screen_has_focus and 4017 matchProps(clas="^org.gnome.nautilus$|^nautilus$")(ctx) ) 4018 4019 # Keybindings overrides for Nemo 4020 # (overrides some bindings from general file manager code block below) 4021 keymap("Overrides for Nemo - Finder Mods", { 4022 C("RC-Backspace"): iEF2(C("Delete"), False), # Set Enter to Enter for Cmd+Delete confirmation 4023 }, when = lambda ctx: 4024 cnfg.screen_has_focus and 4025 matchProps(clas="^nemo$")(ctx) ) 4026 4027 # Keybindings overrides for PCManFM and PCManFM-Qt 4028 # (overrides some bindings from general file manager code block below) 4029 keymap("Overrides for PCManFM-Qt - Finder Mods - LXQt desktop", { 4030 C("Enter"): C("Enter"), # Use Enter as Enter on the LXQt desktop 4031 }, when = lambda ctx: 4032 cnfg.screen_has_focus and 4033 matchProps(clas="^pcmanfm-qt$", name="^pcmanfm-desktop.*$")(ctx) ) 4034 keymap("Overrides for PCManFM-Qt - Finder Mods", { 4035 C("RC-Backspace"): C("Delete"), # Move to Trash (delete, bypass dialog) 4036 # Change folder view 4037 C("RC-KEY_1"): [C("Alt-V"), sleep(0.1), C("V"), sleep(0.1), C("I")], # View as Icons 4038 C("RC-KEY_2"): [C("Alt-V"), sleep(0.1), C("V"), sleep(0.1), C("D")], # View as List (Detailed) 4039 C("RC-KEY_3"): [C("Alt-V"), sleep(0.1), C("V"), sleep(0.1), C("C")], # View as List (Compact) 4040 C("RC-KEY_4"): [C("Alt-V"), sleep(0.1), C("V"), sleep(0.1), C("T")], # View as Thumbnails 4041 }, when = lambda ctx: 4042 cnfg.screen_has_focus and 4043 matchProps(clas="^pcmanfm-qt$")(ctx) ) 4044 4045 keymap("Overrides for PCManFM - Finder Mods", { 4046 C("RC-KEY_2"): C("C-KEY_4"), # View as List (Detailed) [Not in PCManFM-Qt] 4047 C("RC-Backspace"): [C("Delete"),C("Space")], # Move to Trash (delete, bypass dialog) 4048 C("RC-F"): C("C-F"), # Don't toggle Enter key state, pass Cmd+F (Ctrl+F) 4049 }, when = lambda ctx: 4050 cnfg.screen_has_focus and 4051 matchProps(clas="^pcmanfm$|^pcmanfm-qt$")(ctx) ) 4052 4053 keymap("Overrides for Peony-Qt - Finder Mods", { 4054 C("RC-Comma"): None, # Block Cmd+Comma (doesn't work in Peony) 4055 C("RC-Equal"): C("Shift-C-Equal"), # Enlarge icons 4056 C("Shift-RC-Left_Brace"): [bind,C("C-Shift-Tab")], # Go to prior tab 4057 C("Shift-RC-Right_Brace"): [bind,C("C-Tab")], # Go to next tab 4058 C("Shift-RC-Left"): [bind,C("C-Shift-Tab")], # Go to prior tab 4059 C("Shift-RC-Right"): [bind,C("C-Tab")], # Go to next tab 4060 }, when = lambda ctx: 4061 cnfg.screen_has_focus and 4062 matchProps(clas="^peony-qt$")(ctx) ) 4063 4064 # Keybindings overrides for SpaceFM 4065 # (overrides some bindings from general file manager code block below) 4066 keymap("Overrides for SpaceFM Find Files dialog - Finder Mods", { 4067 C("Enter"): C("Enter"), # Use Enter as Enter in the Find dialog 4068 C("Esc"): C("Alt-F4"), # Close Find Files dialog with Escape 4069 C("RC-W"): C("Alt-F4"), # Close Find Files dialog with Cmd+W 4070 }, when = lambda ctx: 4071 cnfg.screen_has_focus and 4072 matchProps(clas="^SpaceFM$", name="Find Files")(ctx) ) 4073 4074 keymap("Overrides for SpaceFM - Finder Mods", { 4075 C("RC-Page_Up"): [bind,C("C-Shift-Tab")], # Go to prior tab 4076 C("RC-Page_Down"): [bind,C("C-Tab")], # Go to next tab 4077 C("Shift-RC-Left_Brace"): [bind,C("C-Shift-Tab")], # Go to prior tab 4078 C("Shift-RC-Right_Brace"): [bind,C("C-Tab")], # Go to next tab 4079 C("Shift-RC-Left"): [bind,C("C-Shift-Tab")], # Go to prior tab 4080 C("Shift-RC-Right"): [bind,C("C-Tab")], # Go to next tab 4081 C("Shift-RC-N"): iEF2(C("C-F"), False), # Switch Enter to Enter. New folder is Ctrl+F(???) 4082 # Need to catch WM_NAME of "Find Files" and override Enter key state back to being Enter. See above keymap. 4083 C("RC-F"): None, # No direct shortcut available and menu macros don't work in SpaceFM. 4084 C("RC-Backspace"): [C("Delete"),C("Space")], # Move to Trash (delete, bypass dialog) 4085 C("RC-comma"): [C("Alt-V"),C("p")], # Overrides "Open preferences dialog" shortcut below 4086 # This shortcut ^^^^^^^^^^^^^^^ is not fully working in SpaceFM. Opens "View" menu but not Preferences. 4087 # SpaceFM is doing some nasty binding that blocks all shortcuts, including Alt+Tab, while any menu is open. 4088 }, when = lambda ctx: 4089 cnfg.screen_has_focus and 4090 matchProps(clas="^spacefm$")(ctx) ) 4091 4092 # Keybindings overrides for Thunar 4093 # (overrides some bindings from general file manager code block below) 4094 keymap("Overrides for Thunar - Finder Mods", { 4095 C("RC-Super-o"): C("Shift-C-P"), # Open in new tab 4096 C("RC-comma"): [C("Alt-E"),C("E")], # Overrides "Open preferences dialog" shortcut below 4097 C("RC-F"): C("C-F"), # Don't toggle Enter key, pass Cmd+F (Ctrl+F) 4098 }, when = lambda ctx: 4099 cnfg.screen_has_focus and 4100 matchProps(clas="^thunar$")(ctx) ) 4101 4102 # Keybindings overrides for GNOME XDG "Save As" and "Open File" dialogs 4103 file_open_save_dialogs = [ 4104 { 4105 clas: "^xdg-desktop-portal-gnome$|^Firefox.*$|^LibreWolf$|^Waterfox$|^zen.*$", 4106 name: "^Open File$|^Save As$" 4107 }, 4108 ] 4109 keymap("XDG file dialogs", { 4110 C("RC-Left"): C("Alt-Left"), # Go Back 4111 C("RC-Right"): C("Alt-Right"), # Go Forward 4112 C("RC-Up"): C("Alt-Up"), # Go Up dir 4113 C("RC-Down"): C("Enter"), # Go Down dir (open folder/file) [universal] 4114 }, when = lambda ctx: 4115 cnfg.screen_has_focus and 4116 matchProps(lst=file_open_save_dialogs)(ctx) 4117 ) 4118 4119 #################################################################################################### 4120 ## Keybindings for Linux general file managers group: 4121 ## 4122 ## Currently supported Linux file managers (file browsers): 4123 ## 4124 ## Caja File Browser (MATE file manager, fork of Nautilus) 4125 ## COSMIC Files (Pop!_OS COSMIC desktop environment file manager) 4126 ## DDE File Manager (Deepin Linux file manager) 4127 ## Dolphin (KDE file manager) 4128 ## Krusader (Alternative/old KDE file manager) 4129 ## Nautilus (GNOME file manager, may be named "Files") 4130 ## Nemo (Cinnamon file manager, fork of Nautilus, may be named "Files") 4131 ## Pantheon Files (elementary OS file manager, may be named "Files") 4132 ## PCManFM (LXDE file manager) 4133 ## PCManFM-Qt (LXQt file manager) 4134 ## Peony-Qt (UKUI file manager, found in Ubuntu Kylin) 4135 ## SpaceFM (Fork of PCManFM file manager) 4136 ## Thunar File Manager (Xfce file manager) 4137 ## 4138 ## GNOME XDG file dialogs ("Open File" and "Save As" windows in apps like Firefox) 4139 ## 4140 #################################################################################################### 4141 4142 keymap("General File Managers - Finder Mods", { 4143 ########################################################################################################### 4144 ### Show Properties (Get Info) | Open Settings/Preferences | Toggle hidden files visibility ### 4145 ########################################################################################################### 4146 C("RC-i"): C("Alt-Enter"), # File properties dialog (Get Info) 4147 C("RC-comma"): [C("Alt-E"),C("N")], # Open preferences dialog 4148 C("Shift-RC-dot"): C("C-H"), # Toggle hidden files visibility ("dot" files) 4149 ########################################################################################################### 4150 ### Navigation ### 4151 ########################################################################################################### 4152 4153 # C("Shift-RC-Left_Brace"): C("C-Page_Up"), # Go to prior tab 4154 # C("Shift-RC-Right_Brace"): C("C-Page_Down"), # Go to next tab 4155 4156 C("Shift-RC-Left_Brace"): [bind,C("C-Page_Up")], # Go to prior tab 4157 C("Shift-RC-Right_Brace"): [bind,C("C-Page_Down")], # Go to next tab 4158 4159 # C("Shift-RC-Left"): C("C-Page_Up"), # Go to prior tab 4160 # C("Shift-RC-Right"): C("C-Page_Down"), # Go to next tab 4161 4162 C("Shift-RC-Left"): [bind,C("C-Page_Up")], # Go to prior tab 4163 C("Shift-RC-Right"): [bind,C("C-Page_Down")], # Go to next tab 4164 4165 C("RC-Left_Brace"): C("Alt-Left"), # Go Back 4166 C("RC-Right_Brace"): C("Alt-Right"), # Go Forward 4167 4168 # C("RC-Left"): C("Alt-Left"), # Go Back 4169 # C("RC-Right"): C("Alt-Right"), # Go Forward 4170 # C("RC-Up"): C("Alt-Up"), # Go Up dir 4171 # C("RC-Down"): C("Enter"), # Go Down dir (open folder/file) [universal] 4172 # EXPERIMENTAL: Attempt to get wordwise Cmd+Left/Right to work while renaming, but otherwise be navigation 4173 C("RC-Left"): iEF2(C("Alt-Left"), C("Home"), True, True), # Go Back 4174 C("RC-Right"): iEF2(C("Alt-Right"), C("End"), True, True), # Go Forward 4175 C("RC-Up"): iEF2(C("Alt-Up"), True), # Go Up dir 4176 C("RC-Down"): iEF2(C("Enter"), True), # Go Down dir (open folder/file) [universal] 4177 4178 # C("RC-Down"): C("Alt-Down"), # Go Down dir (only works on folders) [not universal] 4179 # C("RC-Down"): C("C-O"), # Go Down dir (open folder/file) [not universal] 4180 ########################################################################################################### 4181 ### Open in New Window | Move to Trash ### 4182 ########################################################################################################### 4183 C("RC-Super-o"): C("Shift-C-o"), # Open in new window (or tab, depends) [not universal] 4184 C("RC-Backspace"): C("Delete"), # Move to Trash (delete) 4185 C("RC-Delete"): None, # Block Ctrl+Delete from performing any action (error in macOS) 4186 ########################################################################################################### 4187 ### ENTER-KEY-TO-RENAME CUSTOM FUNCTION SHORTCUTS ### 4188 ########################################################################################################### 4189 C("Enter"): iEF2(C("F2"),C("Enter")), # Send F2 to rename files, unless var is False 4190 C("Shift-RC-N"): iEF2(C("Shift-C-N"), False), # New folder, set Enter to Enter 4191 C("RC-L"): iEF2(C("C-L"), False), # Set Enter to Enter for Location field 4192 C("RC-F"): iEF2(C("C-F"), False), # Set Enter to Enter for Find field 4193 C("Esc"): iEF2(C("Esc"), True), # Send Escape, set Enter to be F2 next 4194 # C("Tab"): iEF2(C("Tab"), C("Tab"), True, True), # Set Enter to Enter after using Tab key 4195 C("Shift-RC-Space"): iEF2(C("Shift-C-Space"), False), # Set Enter to Enter for alternate overview shortcut 4196 C("Shift-RC-Enter"): C("Enter"), # alternative "Enter" key for unusual cases 4197 }, when = lambda ctx: 4198 cnfg.screen_has_focus and 4199 matchProps(clas=filemanagerStr)(ctx) ) 4200 4201 4202 4203 ################################### BROWSERS ##################################### 4204 ### ### 4205 ### ### 4206 ### ██████ ██████ ██████ ██ ██ ███████ ███████ ██████ ███████ ### 4207 ### ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 4208 ### ██████ ██████ ██ ██ ██ █ ██ ███████ █████ ██████ ███████ ### 4209 ### ██ ██ ██ ██ ██ ██ ██ ███ ██ ██ ██ ██ ██ ██ ### 4210 ### ██████ ██ ██ ██████ ███ ███ ███████ ███████ ██ ██ ███████ ### 4211 ### ### 4212 ### ### 4213 #################################################################################### 4214 4215 keymap("Firefox Browsers Overrides", { 4216 4217 C("C-comma"): [C("C-t"), sleep(0.2), 4218 ST("about:preferences"), 4219 sleep(0.2), C("Enter")], # Open preferences (Settings) 4220 4221 # Open private window with Cmd+Shift+N like other browsers 4222 C("Shift-RC-N"): C("Shift-C-P"), 4223 4224 # Wordwise shortcuts (overrides of general wordwise) 4225 C("RC-Backspace"): [C("Shift-Home"), 4226 C("Backspace")], # Delete Line Left of Cursor 4227 C("RC-Delete"): [C("Shift-End"), C("Delete")], # Delete Line Right of Cursor 4228 4229 # Specific numbered tab navigation - removed from general browsers keymap 4230 C("RC-1"): C("Alt-1"), # Jump to Tab #1 4231 C("RC-2"): C("Alt-2"), # Jump to Tab #2 4232 C("RC-3"): C("Alt-3"), # Jump to Tab #3 4233 C("RC-4"): C("Alt-4"), # Jump to Tab #4 4234 C("RC-5"): C("Alt-5"), # Jump to Tab #5 4235 C("RC-6"): C("Alt-6"), # Jump to Tab #6 4236 C("RC-7"): C("Alt-7"), # Jump to Tab #7 4237 C("RC-8"): C("Alt-8"), # Jump to Tab #8 4238 C("RC-9"): C("Alt-9"), # Jump to last tab 4239 4240 # Block shortcuts that might get confused with Shift+Cmd+[Left/Right]_Brace 4241 C("Shift-RC-Minus"): ignore_combo, # Ignore alternate zoom out shortcut 4242 C("Shift-RC-Equal"): ignore_combo, # Ignore alternate zoom in shortcut 4243 4244 }, when = lambda ctx: 4245 cnfg.screen_has_focus and 4246 matchProps(clas=browsers_firefoxStr)(ctx) ) 4247 4248 # Zotero is a Firefox based research app 4249 keymap("Zotero", { 4250 # (override the Shift+Opt+Cmd+I,I diagnostic dialog shortcut in Zotero) 4251 C("Shift-Alt-RC-i"): C("Shift-Alt-C-i"), # Import from clipboard 4252 }, when = lambda ctx: 4253 cnfg.screen_has_focus and 4254 matchProps(clas="^.*Zotero.*$")(ctx) ) 4255 4256 keymap("Vivaldi browser - Settings dialog", { 4257 C("Esc"): C("Alt-F4"), # Close Settings dialog with Escape 4258 }, when = lambda ctx: 4259 cnfg.screen_has_focus and 4260 matchProps(clas="^Vivaldi.*$", name="^Vivaldi Settings:.*Vivaldi$")(ctx) ) 4261 4262 # Vivaldi is a Chromium based web browser 4263 keymap("Overrides for Vivaldi browser", { 4264 4265 # These get caught by the shell in KDE Plasma!!! (Show Desktop and Go to Desktop 1 shortcuts): 4266 # C("RC-comma"): C("C-F12"), # Open preferences (Settings) 4267 # C("RC-Slash"): C("C-F1"), # Keyboard Cheat Sheet (shortcuts) 4268 4269 # This only opens the normal Chrome-like settings page, not the special Vivaldi settings dialog: 4270 # C("C-comma"): [C("C-t"), sleep(0.1), 4271 # ST("chrome://settings"), 4272 # sleep(0.1), C("Enter")], # Open preferences (Settings) 4273 4274 # Alternatives using macros to avoid issues with KDE Plasma global shortcuts (see above): 4275 C("RC-Slash"): [C("F10"), 4276 sleep(0.2), C("H"), 4277 sleep(0.2), C("K")], # Keyboard Cheat Sheet (shortcuts) 4278 4279 C("C-comma"): [C("F10"), 4280 sleep(0.2), C("S")], # Open preferences (Settings) 4281 4282 }, when = lambda ctx: 4283 cnfg.screen_has_focus and 4284 matchProps(clas="^Vivaldi.*$")(ctx) ) 4285 4286 # Falkon is a Chromium based web browser 4287 keymap("Overrides for Falkon browser", { 4288 C("RC-comma"): C("Shift-C-comma"), # Open preferences (Settings) 4289 }, when = lambda ctx: 4290 cnfg.screen_has_focus and 4291 matchProps(clas="^org.kde.falkon$|^Falkon$")(ctx) ) 4292 4293 keymap("Chrome Browsers Overrides", { 4294 # C("C-comma"): [C("Alt-e"), C("s"),C("Enter")], # Open preferences (Settings) 4295 C("C-comma"): [C("C-t"), sleep(0.2), 4296 ST("chrome://settings"), 4297 sleep(0.2), C("Enter")], # Open preferences (Settings) 4298 C("RC-q"): C("Alt-F4"), # Quit Chrome(s) browsers with Cmd+Q 4299 # C("RC-Left"): C("Alt-Left"), # Page nav: Back to prior page in history (conflict with wordwise) 4300 # C("RC-Right"): C("Alt-Right"), # Page nav: Forward to next page in history (conflict with wordwise) 4301 C("RC-Left_Brace"): C("Alt-Left"), # Page nav: Back to prior page in history 4302 C("RC-Right_Brace"): C("Alt-Right"), # Page nav: Forward to next page in history 4303 4304 C("RC-y"): C("C-H"), # Browser History 4305 C("Alt-RC-u"): C("C-U"), # View Page Source 4306 C("Shift-RC-j"): C("C-J"), # Show Downloads view 4307 }, when = lambda ctx: 4308 cnfg.screen_has_focus and 4309 matchProps(clas=browsers_chromeStr)(ctx) ) 4310 4311 # Keybindings for General Web Browsers 4312 keymap("General Web Browsers", { 4313 4314 C("RC-Q"): C("C-Q"), # Close all browsers Instances 4315 C("Alt-RC-I"): C("Shift-C-I"), # Dev tools 4316 C("Alt-RC-J"): C("Shift-C-J"), # Dev tools 4317 4318 # Enable Cmd+Shift+Braces for tab navigation (redundant with General GUI) 4319 # C("Shift-RC-Left_Brace"): C("C-Page_Up"), # Go to prior tab 4320 # C("Shift-RC-Right_Brace"): C("C-Page_Down"), # Go to next tab 4321 4322 # Enable Cmd+Option+Left/Right for tab navigation 4323 C("RC-Alt-Left"): C("C-Page_Up"), # Go to prior tab 4324 C("RC-Alt-Right"): C("C-Page_Down"), # Go to next tab 4325 4326 # Enable Ctrl+PgUp/PgDn for tab navigation 4327 C("Super-Page_Up"): C("C-Page_Up"), # Go to prior tab 4328 C("Super-Page_Down"): C("C-Page_Down"), # Go to next tab 4329 4330 # Use Cmd+Braces keys for tab navigation instead of page navigation 4331 # C("C-Left_Brace"): C("C-Page_Up"), 4332 # C("C-Right_Brace"): C("C-Page_Down"), 4333 4334 }, when = lambda ctx: 4335 cnfg.screen_has_focus and 4336 matchProps(clas=browsers_allStr)(ctx) ) 4337 4338 4339 4340 ############################################ CODE EDITORS ############################################## 4341 ### ### 4342 ### ### 4343 ### ██████ ██████ ██████ ███████ ███████ ██████ ██ ████████ ██████ ██████ ███████ ### 4344 ### ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 4345 ### ██ ██ ██ ██ ██ █████ █████ ██ ██ ██ ██ ██ ██ ██████ ███████ ### 4346 ### ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 4347 ### ██████ ██████ ██████ ███████ ███████ ██████ ██ ██ ██████ ██ ██ ███████ ### 4348 ### ### 4349 ### ### 4350 ########################################################################################################## 4351 4352 4353 # Keybindings for IntelliJ 4354 keymap("Jetbrains", { 4355 # General 4356 C("C-Key_0"): C("Alt-Key_0"), # Open corresponding tool window 4357 C("C-Key_1"): C("Alt-Key_1"), # Open corresponding tool window 4358 C("C-Key_2"): C("Alt-Key_2"), # Open corresponding tool window 4359 C("C-Key_3"): C("Alt-Key_3"), # Open corresponding tool window 4360 C("C-Key_4"): C("Alt-Key_4"), # Open corresponding tool window 4361 C("C-Key_5"): C("Alt-Key_5"), # Open corresponding tool window 4362 C("C-Key_6"): C("Alt-Key_6"), # Open corresponding tool window 4363 C("C-Key_7"): C("Alt-Key_7"), # Open corresponding tool window 4364 C("C-Key_8"): C("Alt-Key_8"), # Open corresponding tool window 4365 C("C-Key_9"): C("Alt-Key_9"), # Open corresponding tool window 4366 C("Super-Grave"): C("C-Grave"), # Quick switch current scheme 4367 C("C-Comma"): C("C-Alt-s"), # Open Settings dialog 4368 C("C-Semicolon"): C("C-Alt-Shift-s"), # Open Project Structure dialog 4369 # Debugging 4370 C("C-Alt-r"): C("F9"), # Resume program 4371 # Search/Replace 4372 C("C-g"): C("F3"), # Find next 4373 C("C-Shift-F3"): C("Shift-F3"), # Find previous 4374 C("Super-g"): C("Alt-j"), # Select next occurrence 4375 C("C-Super-g"): C("C-Alt-Shift-j"), # Select all occurrences 4376 C("Super-Shift-g"): C("Alt-Shift-j"), # Unselect occurrence 4377 # Editing 4378 # C("Super-Space"): C("C-Space"), # Basic code completion (conflicts with input switching) 4379 # C("Super-Shift-Space"): C("Shift-C-Space"), # Smart code completion (conflicts with input switching) 4380 C("Super-j"): C("C-q"), # Quick documentation lookup 4381 C("C-n"): C("Alt-Insert"), # Generate code... 4382 C("Super-o"): C("C-o"), # Override methods 4383 C("Super-i"): C("C-i"), # Implement methods 4384 C("Alt-Up"): C("C-w"), # Extend selection 4385 C("Alt-Down"): C("C-Shift-w"), # Shrink selection 4386 C("Super-Shift-q"): C("Alt-q"), # Context info 4387 C("Super-Alt-o"): C("C-Alt-o"), # Optimize imports 4388 C("Super-Alt-i"): C("C-Alt-i"), # Auto-indent line(s) 4389 C("C-Backspace"): C("C-y"), # Delete line at caret 4390 C("Super-Shift-j"): C("C-Shift-j"), # Smart line join 4391 C("Alt-Delete"): C("C-Delete"), # Delete to word end 4392 C("Alt-Backspace"): C("C-Backspace"), # Delete to word start 4393 C("C-Shift-Equal"): C("C-KPPLUS"), # Expand code block 4394 C("C-Minus"): C("C-KPMINUS"), # Collapse code block 4395 C("C-Shift-Equal"): C("C-Shift-KPPLUS"), # Expand all 4396 C("C-Shift-Minus"): C("C-Shift-KPMINUS"), # Collapse all 4397 C("C-w"): C("C-F4"), # Close active editor tab 4398 # Refactoring 4399 C("C-Delete"): C("Alt-Delete"), # Safe Delete 4400 C("C-T"): C("C-Alt-Shift-t"), # Refactor this 4401 # Navigation 4402 C("C-o"): C("C-n"), # Go to class 4403 C("C-Shift-o"): C("C-Shift-n"), # Go to file 4404 C("C-Alt-o"): C("C-Alt-Shift-n"), # Go to symbol 4405 C("Super-Right"): C("Alt-Right"), # Go to next editor tab 4406 C("Super-Left"): C("Alt-Left"), # Go to previous editor tab 4407 C("C-l"): C("C-g"), # Go to line 4408 C("Alt-Space"): C("C-Shift-i"), # Open quick definition lookup 4409 C("C-Y"): C("C-Shift-i"), # Open quick definition lookup 4410 C("Super-Shift-b"): C("C-Shift-b"), # Go to type declaration 4411 C("Super-Up"): C("Alt-Up"), # Go to previous 4412 C("Super-Down"): C("Alt-Down"), # Go to next method 4413 C("C-Left_Brace"): C("Alt-Shift-Left"), # Go back 4414 C("C-Right_Brace"): C("Alt-Shift-Right"), # Go forward 4415 C("Super-h"): C("C-h"), # Type hierarchy 4416 C("Super-Alt-h"): C("C-Alt-h"), # Call hierarchy 4417 C("C-Down"): C("C-Enter"), # Edit source/View source 4418 C("Alt-Home"): C("Alt-Home"), # Show navigation bar 4419 C("F2"): C("F11"), # Toggle bookmark 4420 C("Super-F3"): C("C-F11"), # Toggle bookmark with mnemonic 4421 C("Super-Key_0"): C("C-Key_0"), # Go to numbered bookmark 4422 C("Super-Key_1"): C("C-Key_1"), # Go to numbered bookmark 4423 C("Super-Key_2"): C("C-Key_2"), # Go to numbered bookmark 4424 C("Super-Key_3"): C("C-Key_3"), # Go to numbered bookmark 4425 C("Super-Key_4"): C("C-Key_4"), # Go to numbered bookmark 4426 C("Super-Key_5"): C("C-Key_5"), # Go to numbered bookmark 4427 C("Super-Key_6"): C("C-Key_6"), # Go to numbered bookmark 4428 C("Super-Key_7"): C("C-Key_7"), # Go to numbered bookmark 4429 C("Super-Key_8"): C("C-Key_8"), # Go to numbered bookmark 4430 C("Super-Key_9"): C("C-Key_9"), # Go to numbered bookmark 4431 C("C-F3"): C("Shift-F11"), # Show bookmarks 4432 # Compile and Run 4433 C("Super-Alt-r"): C("Alt-Shift-F10"), # Select configuration and run 4434 C("Super-Alt-d"): C("Alt-Shift-F9"), # Select configuration and debug 4435 C("Super-r"): C("Shift-F10"), # Run 4436 C("Super-d"): C("Shift-F9"), # Debug 4437 C("Super-Shift-r"): C("C-Shift-F10"), # Run context configuration from editor 4438 C("Super-Shift-d"): C("C-Shift-F9"), # Debug context configuration from editor 4439 # VCS/Local History 4440 C("Super-v"): C("Alt-Grave"), # VCS quick popup 4441 C("Super-c"): C("C-c"), # Sigints - interrupt 4442 }, when = lambda ctx: 4443 cnfg.screen_has_focus and 4444 matchProps(clas="^jetbrains-(?!.*toolbox).*$")(ctx) ) 4445 4446 keymap("Wordwise - not vscode", { 4447 # Wordwise remaining - for Everything but VS Code 4448 C("Alt-Left"): C("C-Left"), # Left of Word 4449 C("Alt-Shift-Left"): C("C-Shift-Left"), # Select Left of Word 4450 C("Alt-Right"): C("C-Right"), # Right of Word 4451 C("Alt-Shift-Right"): C("C-Shift-Right"), # Select Right of Word 4452 C("Alt-Shift-g"): C("C-Shift-g"), # View source control 4453 # ** VS Code fix ** 4454 # Electron issue precludes normal keybinding fix. 4455 # Alt menu auto-focus/toggle gets in the way. 4456 # 4457 # refer to ./xkeysnail-config/vscode_keybindings.json 4458 # ** 4459 # 4460 # ** Firefox fix ** 4461 # User will need to set "ui.key.menuAccessKeyFocuses" 4462 # under about:config to false. 4463 # 4464 # https://superuser.com/questions/770301/pentadactyl-how-to-disable-menu-bar-toggle-by-alt 4465 # ** 4466 # 4467 }, when = lambda ctx: 4468 cnfg.screen_has_focus and 4469 matchProps(not_clas=vscodes_and_remotes_Str)(ctx) 4470 ) 4471 4472 # Keybindings for VS Code and variants 4473 keymap("VSCodes overrides for Chromebook/IBM - Sublime", { 4474 C("C-Alt-g"): C("C-f2"), # Chromebook/IBM - Sublime - find_all_under 4475 }, when = lambda ctx: 4476 cnfg.screen_has_focus and 4477 cnfg.ST3_in_VSCode and 4478 ( isKBtype('Chromebook', map="vscodes ovr cbook - sublime")(ctx) or 4479 isKBtype('IBM', map="vscodes ovr ibm - sublime")(ctx) ) and 4480 matchProps(clas=vscodeStr)(ctx) 4481 ) 4482 keymap("VSCodes overrides for not Chromebook/IBM - Sublime", { 4483 C("Super-C-g"): C("C-f2"), # Default - Sublime - find_all_under 4484 }, when = lambda ctx: 4485 cnfg.screen_has_focus and 4486 cnfg.ST3_in_VSCode and 4487 not ( isKBtype('Chromebook', map="vscodes ovr not cbook - sublime")(ctx) or 4488 isKBtype('IBM', map="vscodes ovr not ibm - sublime")(ctx) ) and 4489 matchProps(clas=vscodeStr)(ctx) 4490 ) 4491 keymap("VSCodes overrides for Chromebook/IBM", { 4492 C("Alt-c"): C("C-c"), # Chromebook/IBM - Terminal - Sigint 4493 C("Alt-x"): C("C-x"), # Chromebook/IBM - Terminal - Exit nano 4494 }, when = lambda ctx: 4495 cnfg.screen_has_focus and 4496 ( isKBtype('Chromebook', map="vscodes ovr cbook")(ctx) or 4497 isKBtype('IBM', map="vscodes ovr ibm")(ctx) ) and 4498 matchProps(clas=vscodeStr)(ctx) 4499 ) 4500 keymap("VSCodes overrides for not Chromebook/IBM", { 4501 C("Super-c"): C("C-c"), # Default - Terminal - Sigint 4502 C("Super-x"): C("C-x"), # Default - Terminal - Exit nano 4503 }, when = lambda ctx: 4504 cnfg.screen_has_focus and 4505 not ( isKBtype('Chromebook', map="vscodes ovr not cbook")(ctx) or 4506 isKBtype('IBM', map="vscodes ovr not ibm")(ctx) ) and 4507 matchProps(clas=vscodeStr)(ctx) 4508 ) 4509 keymap("VSCodes", { 4510 # C("Super-Space"): C("C-Space"), # Basic code completion (conflicts with input switching) 4511 4512 # Override the global Cmd+Dot (Escape/cancel) shortcut for QuickFix in VSCode(s) 4513 C("RC-Dot"): C("C-Dot"), # QuickFix, overriding global shortcut 4514 4515 # Override the global copy shortcut, to allow Cmd+C to work properly in the embedded 4516 # VSCode terminal, without an internal VSCode keyboard shortcut remap. 4517 C("RC-C"): C("C-Insert"), # Copy 4518 4519 # This override unfortunately seems to paste from the "wrong" clipboard. Only pastes content 4520 # that was copied from within the VSCode window, not content copied from other app windows: 4521 # C("RC-V"): C("Shift-Insert"), # Paste 4522 4523 # In-app terminal operations (Cmd+J is "Toggle Panel Visibility" for problems/output/debug/terminal panel) 4524 C("Super-Grave"): C("C-Grave"), # Terminal: Toggle Terminal 4525 C("Shift-Super-Grave"): C("Shift-C-Grave"), # Terminal: Create New Terminal 4526 4527 # Find dialog options 4528 C("Alt-RC-C"): C("Alt-C"), # Find: toggle "Match Case" 4529 C("Alt-RC-W"): C("Alt-W"), # Find: toggle "Match Whole Word" 4530 C("Alt-RC-R"): C("Alt-R"), # Find: toggle "Use Regular Expression" 4531 C("Alt-RC-L"): C("Alt-L"), # Find: toggle "Find in Selection" 4532 C("Alt-RC-P"): C("Alt-P"), # Replace: toggle "Preserve Case" 4533 C("RC-Enter"): C("C-Alt-Enter"), # Find: Replace All 4534 4535 C("Alt-RC-Z"): C("Alt-Z"), # View: toggle "Word Wrap" 4536 4537 C("Alt-RC-Up"): C("Shift-Alt-Up"), # Insert cursor above 4538 C("Alt-RC-Down"): C("Shift-Alt-Down"), # Insert cursor below 4539 4540 C("Shift-Super-Right"): C("Shift-Alt-Right"), # Expand Selection (increase logical scope of smart selection) 4541 C("Shift-Super-Left"): C("Shift-Alt-Left"), # Shrink Selection (reduce logical scope of smart selection) 4542 4543 C("Shift-Super-RC-Right"): C("Shift-Alt-Right"), # Expand Selection (increase logical scope of smart selection) [alt] 4544 C("Shift-Super-RC-Left"): C("Shift-Alt-Left"), # Shrink Selection (reduce logical scope of smart selection) [alt] 4545 4546 # On Mac, Cmd+G and Shift+Cmd+G are for Find Next/Previous. 4547 # Correct combo on Mac for Source Control sidebar panel is physical Shift+Ctrl+G 4548 C("Shift-Super-g"): C("Shift-C-g"), # Show Source Control 4549 4550 # Wordwise remaining - for VS Code 4551 # Alt-F19 hack fixes Alt menu activation 4552 C("Alt-Left"): [C("Alt-F19"),C("C-Left")], # Left of Word 4553 C("Alt-Right"): [C("Alt-F19"),C("C-Right")], # Right of Word 4554 C("Alt-Shift-Left"): [C("Alt-F19"),C("C-Shift-Left")], # Select Left of Word 4555 C("Alt-Shift-Right"): [C("Alt-F19"),C("C-Shift-Right")], # Select Right of Word 4556 4557 # To make this work, assign these shortcuts to "deleteWordPartLeft" and "deleteWordPartRight" shortcuts 4558 C("Shift-Alt-Backspace"): C("Shift-Alt-Backspace"), # Delete word left of cursor (override GenGUI) 4559 C("Shift-Alt-Delete"): C("Shift-Alt-Delete"), # Delete word right of cursor (override GenGUI) 4560 C("RC-Backspace"): [C("Shift-Home"), C("Delete")], # Delete entire line left of cursor 4561 C("RC-Delete"): [C("Shift-End"), C("Delete")], # Delete entire line right of cursor 4562 4563 # C("C-PAGE_DOWN"): ignore_combo, # cancel next_view 4564 # C("C-PAGE_UP"): ignore_combo, # cancel prev_view 4565 C("C-Alt-Left"): C("C-PAGE_UP"), # next_view 4566 C("C-Alt-Right"): C("C-PAGE_DOWN"), # prev_view 4567 C("Shift-RC-Left_Brace"): C("C-PAGE_UP"), # next_view 4568 C("Shift-RC-Right_Brace"): C("C-PAGE_DOWN"), # prev_view 4569 4570 # VS Code Shortcuts 4571 C("C-g"): ignore_combo, # cancel Go to Line... 4572 C("Super-g"): C("C-g"), # Go to Line... 4573 C("F3"): ignore_combo, # cancel Find next 4574 C("C-h"): ignore_combo, # cancel replace 4575 C("C-Alt-f"): C("C-h"), # replace 4576 C("C-Shift-h"): ignore_combo, # cancel replace_next 4577 C("C-Alt-e"): C("C-Shift-h"), # replace_next 4578 C("f3"): ignore_combo, # cancel find_next 4579 C("C-g"): C("f3"), # find_next 4580 C("Shift-f3"): ignore_combo, # cancel find_prev 4581 C("C-Shift-g"): C("Shift-f3"), # find_prev 4582 }, when = lambda ctx: 4583 cnfg.screen_has_focus and 4584 matchProps(clas=vscodeStr)(ctx) 4585 ) 4586 4587 # Keybindings for Sublime Text 4588 keymap("Sublime Text overrides for Chromebook/IBM", { 4589 C("Alt-c"): C("C-c"), # Chromebook/IBM - Terminal - Sigint 4590 C("Alt-x"): C("C-x"), # Chromebook/IBM - Terminal - Exit nano 4591 C("Alt-Refresh"): ignore_combo, # Chromebook/IBM - cancel find_all_under 4592 C("Alt-C-g"): C("Alt-Refresh"), # Chromebook/IBM - find_all_under 4593 }, when = lambda ctx: 4594 cnfg.screen_has_focus and 4595 ( isKBtype('Chromebook', map="sublime ovr cbook")(ctx) or 4596 isKBtype('IBM', map="sublime ovr ibm")(ctx) ) and 4597 matchProps(clas=sublimeStr)(ctx) 4598 ) 4599 keymap("Sublime Text overrides for not Chromebook/IBM", { 4600 # C("Super-c"): C("C-c"), # Default - Terminal - Sigint 4601 # C("Super-x"): C("C-x"), # Default - Terminal - Exit nano 4602 C("Alt-f3"): ignore_combo, # Default - cancel find_all_under 4603 C("Super-C-g"): C("Alt-f3"), # Default - find_all_under 4604 }, when = lambda ctx: 4605 cnfg.screen_has_focus and 4606 not ( isKBtype('Chromebook', map="sublime ovr not cbook")(ctx) or 4607 isKBtype('IBM', map="sublime ovr not ibm")(ctx) ) and 4608 matchProps(clas=sublimeStr)(ctx) 4609 ) 4610 keymap("Sublime Text", { 4611 # C("Super-c"): C("C-c"), # Default - Terminal - Sigint 4612 # C("Super-x"): C("C-x"), # Default - Terminal - Exit nano 4613 # C("Alt-c"): C("C-c"), # Chromebook/IBM - Terminal - Sigint 4614 # C("Alt-x"): C("C-x"), # Chromebook/IBM - Terminal - Exit nano 4615 # C("Super-Space"): C("C-Space"), # Basic code completion (conflicts with input switching) 4616 C("C-Super-up"): C("Alt-o"), # Switch file 4617 C("Super-RC-f"): C("f11"), # toggle_full_screen 4618 C("C-Alt-v"): [C("C-k"), C("C-v")], # paste_from_history 4619 # C("C-up"): ignore_combo, # cancel scroll_lines up 4620 C("C-Alt-up"): C("C-up"), # scroll_lines up 4621 # C("C-down"): ignore_combo, # cancel scroll_lines down 4622 C("C-Alt-down"): C("C-down"), # scroll_lines down 4623 C("Super-Shift-up"): C("Alt-Shift-up"), # multi-cursor up 4624 C("Super-Shift-down"): C("Alt-Shift-down"), # multi-cursor down 4625 C("C-PAGE_DOWN"): ignore_combo, # cancel next_view 4626 C("C-PAGE_UP"): ignore_combo, # cancel prev_view 4627 C("C-Shift-left_brace"): C("C-PAGE_DOWN"), # next_view 4628 C("C-Shift-right_brace"): C("C-PAGE_UP"), # prev_view 4629 C("C-Alt-right"): C("C-PAGE_DOWN"), # next_view 4630 C("C-Alt-left"): C("C-PAGE_UP"), # prev_view 4631 C("insert"): ignore_combo, # cancel toggle_overwrite 4632 C("C-Alt-o"): C("insert"), # toggle_overwrite 4633 C("Alt-c"): ignore_combo, # cancel toggle_case_sensitive 4634 C("C-Alt-c"): C("Alt-c"), # toggle_case_sensitive 4635 C("C-h"): ignore_combo, # cancel replace 4636 C("C-Alt-f"): C("C-h"), # replace 4637 C("C-Shift-h"): ignore_combo, # cancel replace_next 4638 C("C-Alt-e"): C("C-Shift-h"), # replace_next 4639 C("f3"): ignore_combo, # cancel find_next 4640 C("C-g"): C("f3"), # find_next 4641 C("Shift-f3"): ignore_combo, # cancel find_prev 4642 C("C-Shift-g"): C("Shift-f3"), # find_prev 4643 C("C-f3"): ignore_combo, # cancel find_under 4644 C("Super-Alt-g"): C("C-f3"), # find_under 4645 C("C-Shift-f3"): ignore_combo, # cancel find_under_prev 4646 C("Super-Alt-Shift-g"): C("C-Shift-f3"), # find_under_prev 4647 C("Alt-f3"): ignore_combo, # Default - cancel find_all_under 4648 C("Super-C-g"): C("Alt-f3"), # Default - find_all_under 4649 # C("Alt-Refresh"): ignore_combo, # Chromebook/IBM - cancel find_all_under 4650 # C("Alt-C-g"): C("Alt-Refresh"), # Chromebook/IBM - find_all_under 4651 C("C-Shift-up"): ignore_combo, # cancel swap_line_up 4652 C("Super-Alt-up"): C("C-Shift-up"), # swap_line_up 4653 C("C-Shift-down"): ignore_combo, # cancel swap_line_down 4654 C("Super-Alt-down"): C("C-Shift-down"), # swap_line_down 4655 C("C-Pause"): ignore_combo, # cancel cancel_build 4656 C("Super-c"): C("C-Pause"), # cancel_build 4657 C("f9"): ignore_combo, # cancel sort_lines case_s false 4658 C("f5"): C("f9"), # sort_lines case_s false 4659 C("Super-f9"): ignore_combo, # cancel sort_lines case_s true 4660 C("Super-f5"): C("Super-f9"), # sort_lines case_s true 4661 C("Alt-Shift-Key_1"): ignore_combo, # cancel set_layout 4662 C("C-Alt-Key_1"): C("Alt-Shift-Key_1"), # set_layout 4663 C("Alt-Shift-Key_2"): ignore_combo, # cancel set_layout 4664 C("C-Alt-Key_2"): C("Alt-Shift-Key_2"), # set_layout 4665 C("Alt-Shift-Key_3"): ignore_combo, # cancel set_layout 4666 C("C-Alt-Key_3"): C("Alt-Shift-Key_3"), # set_layout 4667 C("Alt-Shift-Key_4"): ignore_combo, # cancel set_layout 4668 C("C-Alt-Key_4"): C("Alt-Shift-Key_4"), # set_layout 4669 C("Alt-Shift-Key_8"): ignore_combo, # cancel set_layout 4670 C("C-Alt-Shift-Key_2"): C("Alt-Shift-Key_8"), # set_layout 4671 C("Alt-Shift-Key_9"): ignore_combo, # cancel set_layout 4672 C("C-Alt-Shift-Key_3"): C("Alt-Shift-Key_9"), # set_layout 4673 C("Alt-Shift-Key_5"): ignore_combo, # cancel set_layout 4674 C("C-Alt-Shift-Key_5"): C("Alt-Shift-Key_5"), # set_layout 4675 # C(""): ignore_combo, # cancel 4676 # C(""): C(""), # 4677 }, when = lambda ctx: 4678 cnfg.screen_has_focus and 4679 matchProps(clas=sublimeStr)(ctx) ) 4680 4681 keymap("Kate Advanced Text Editor", { 4682 C("RC-Comma"): C("Shift-C-Comma"), # Open settings/preferences 4683 C("RC-g"): C("F3"), # Find next 4684 C("Super-g"): C("C-g"), # Go to line 4685 }, when = lambda ctx: 4686 cnfg.screen_has_focus and 4687 matchProps(clas="^org.kde.kate$")(ctx) ) 4688 4689 keymap("Linux Mint xed text editor", { 4690 C("RC-T"): C("C-N"), # Open new tab (new file) 4691 }, when = lambda ctx: 4692 cnfg.screen_has_focus and 4693 matchProps(clas="^xed$")(ctx) ) 4694 4695 keymap("KWrite text editor - Close Document dialog", { 4696 C("RC-d"): C("Alt-d"), # [D]iscard file without saving (from Close Document dialog) 4697 C("RC-s"): C("Alt-s"), # Save file (from Close Document dialog) 4698 }, when = lambda ctx: 4699 cnfg.screen_has_focus and 4700 matchProps(clas="^kwrite$|^org.kde.Kwrite$", name="^Close Document.*KWrite$")(ctx) ) 4701 keymap("KWrite text editor", { 4702 C("RC-comma"): C("Shift-C-comma"), # Open preferences dialog 4703 C("RC-t"): C("C-n"), # New tab (new document appears in tab) 4704 C("Super-g"): C("C-g"), # Go to line with physical Ctrl+G 4705 C("RC-g"): C("F3"), # Find next instance (Cmd+G) 4706 C("Shift-RC-g"): C("Shift-F3"), # Find previous instance (Shift+Cmd+G) 4707 # wordwise shortcuts 4708 C("RC-Backspace"): C("C-k"), # Delete line (Cmd+Delete) 4709 }, when = lambda ctx: 4710 cnfg.screen_has_focus and 4711 matchProps(clas="^kwrite$|^org.kde.Kwrite$")(ctx) ) 4712 4713 keymap("GNOME Text Editor", { 4714 C("RC-Slash"): None, # Block Cmd+Slash from doing "Select All" 4715 C("RC-Alt-f"): C("C-h"), # Search and replace within the document 4716 }, when = lambda ctx: 4717 cnfg.screen_has_focus and 4718 matchProps(clas="^gnome-text-editor$|^org.gnome.TextEditor$")(ctx) ) 4719 4720 4721 ########################### DIALOG FIXES ########################### 4722 ### ### 4723 ### ### 4724 ### ██████ ██ █████ ██ ██████ ██████ ███████ ### 4725 ### ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 4726 ### ██ ██ ██ ███████ ██ ██ ██ ██ ███ ███████ ### 4727 ### ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 4728 ### ██████ ██ ██ ██ ███████ ██████ ██████ ███████ ### 4729 ### ### 4730 ### ### 4731 ###################################################################### 4732 ### Fixes for the problem of modal dialogs and other "child" 4733 ### windows failing to close with Cmd+W. 4734 ### Many dialogs respond to the Escape key, others may require the 4735 ### "Close window" shortcut (normally Alt+F4 but not always) to close. 4736 ### 4737 ### Cmd+W can't just be always mapped to the "Close window" shortcut for all apps 4738 ### because some apps will "quit" rather than just closing a tab. 4739 ### 4740 ### To add window conditions to the list, search for the list names in 4741 ### the "LISTS" section near the top of this config file. 4742 ### dialogs_Escape_lod = send these windows the Escape key for Cmd+W 4743 ### dialogs_CloseWin_lod = send these windows the "Close window" shortcut for Cmd+W 4744 4745 keymap("Cmd+W dialog fix - send Escape", { 4746 C("RC-W"): iEF2(C("Esc"), True), 4747 }, when = lambda ctx: 4748 cnfg.screen_has_focus and 4749 matchProps(lst=dialogs_Escape_lod)(ctx) 4750 ) 4751 4752 # This keymap for Manjaro GNOME will override the same shortcut from the keymap just below it, 4753 # sending Super+Q to close the dialogs in the matchProps list, instead of sending Alt+F4. 4754 if DISTRO_ID == 'manjaro' and DESKTOP_ENV == 'gnome': 4755 keymap("Cmd+W dialog fix - Super+Q Manjaro GNOME", { 4756 C("RC-W"): iEF2(C("Super-Q"), True), 4757 }, when = lambda ctx: 4758 cnfg.screen_has_focus and 4759 matchProps(lst=dialogs_CloseWin_lod)(ctx) 4760 ) 4761 4762 keymap("Cmd+W dialog fix - Alt+F4", { 4763 C("RC-W"): iEF2(C("Alt-F4"), True), 4764 }, when = lambda ctx: 4765 cnfg.screen_has_focus and 4766 matchProps(lst=dialogs_CloseWin_lod)(ctx) 4767 ) 4768 4769 4770 4771 ########################### TAB NAV FIXES ############################# 4772 ### ### 4773 ### ### 4774 ### ████████ █████ ██████ ███ ██ █████ ██ ██ ### 4775 ### ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ### 4776 ### ██ ███████ ██████ ██ ██ ██ ███████ ██ ██ ### 4777 ### ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 4778 ### ██ ██ ██ ██████ ██ ████ ██ ██ ████ ### 4779 ### ### 4780 ### ### 4781 ######################################################################### 4782 ### Various fixes for supporting tab navigation shortcuts like Shift+Cmd+Braces 4783 4784 4785 tab_UI_fix_CtrlShiftTab_lst = [ 4786 "com.raggesilver.BlackBox", 4787 "com.system76.CosmicTerm", 4788 "org.gnome.Console|Console", 4789 "deepin-terminal", 4790 "hyper", 4791 "kitty", 4792 "Kgx", 4793 ] 4794 tab_UI_fix_CtrlShiftTab_Str = toRgxStr(tab_UI_fix_CtrlShiftTab_lst) 4795 4796 tab_UI_fix_CtrlAltPgUp_lst = [ 4797 "gedit", 4798 "xed", 4799 ] 4800 tab_UI_fix_CtrlAltPgUp_Str = toRgxStr(tab_UI_fix_CtrlAltPgUp_lst) 4801 4802 # Tab navigation overrides for tabbed UI apps that use Ctrl+Shift+Tab/Ctrl+Tab instead of Ctrl+PgUp/PgDn 4803 keymap("Tab Nav fix for apps that use Ctrl+Shift+Tab/Ctrl+Tab", { 4804 C("Shift-RC-Left_Brace"): [bind,C("C-Shift-Tab")], # Tab nav: Go to prior tab (left) 4805 C("Shift-RC-Right_Brace"): [bind,C("C-Tab")], # Tab nav: Go to next tab (right) 4806 C("Shift-RC-Left"): [bind,C("C-Shift-Tab")], # Tab nav: Go to prior tab (left) 4807 C("Shift-RC-Right"): [bind,C("C-Tab")], # Tab nav: Go to next tab (right) 4808 }, when = lambda ctx: 4809 cnfg.screen_has_focus and 4810 matchProps(clas=tab_UI_fix_CtrlShiftTab_Str)(ctx) 4811 ) 4812 4813 # Tab navigation overrides for tabbed UI apps that use Ctrl+Alt+PgUp/PgDn instead of Ctrl+PgUp/PgDn 4814 keymap("Tab Nav fix for apps that use Ctrl+Alt+PgUp/PgDn", { 4815 C("Shift-RC-Left_Brace"): [bind,C("C-Alt-Page_Up")], # Go to prior tab (Left) 4816 C("Shift-RC-Right_Brace"): [bind,C("C-Alt-Page_Down")], # Go to next tab (Right) 4817 }, when = lambda ctx: 4818 cnfg.screen_has_focus and 4819 matchProps(clas=tab_UI_fix_CtrlAltPgUp_Str)(ctx) 4820 ) 4821 4822 keymap("Konsole tab switching", { 4823 # Ctrl Tab - In App Tab Switching 4824 C("Shift-LC-Tab") : [bind,C("Shift-Left")], 4825 C("LC-Tab") : [bind,C("Shift-Right")], 4826 C("LC-Grave") : [bind,C("Shift-Left")], 4827 # Konsole tab switching in KDE4 (not needed in KDE5) 4828 C("Shift-RC-Left_Brace"): [bind,C("Shift-Left")], # Go to prior tab (Left) 4829 C("Shift-RC-Right_Brace"): [bind,C("Shift-Right")], # Go to next tab (Right) 4830 }, when = lambda ctx: 4831 cnfg.screen_has_focus and 4832 matchProps(clas="^konsole$|^org.kde.Konsole$")(ctx) ) 4833 4834 keymap("Elementary Terminal tab switching", { 4835 # Ctrl Tab - In App Tab Switching 4836 C("Shift-LC-Tab") : [bind,C("Shift-C-Left")], # Go to prior tab (Left) 4837 C("LC-Grave") : [bind,C("Shift-C-Left")], # Go to prior tab (Left) 4838 C("LC-Tab") : [bind,C("Shift-C-Right")], # Go to next tab (Right) 4839 }, when = lambda ctx: 4840 cnfg.screen_has_focus and 4841 matchProps(clas="^Io.elementary.terminal$|^kitty$")(ctx) ) 4842 4843 4844 4845 ###################################### TERMINALS ####################################### 4846 ### ### 4847 ### ### 4848 ### ████████ ███████ ██████ ███ ███ ██ ███ ██ █████ ██ ███████ ### 4849 ### ██ ██ ██ ██ ████ ████ ██ ████ ██ ██ ██ ██ ██ ### 4850 ### ██ █████ ██████ ██ ████ ██ ██ ██ ██ ██ ███████ ██ ███████ ### 4851 ### ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 4852 ### ██ ███████ ██ ██ ██ ██ ██ ██ ████ ██ ██ ███████ ███████ ### 4853 ### ### 4854 ### ### 4855 ########################################################################################## 4856 4857 keymap("Alacritty terminal", { 4858 C("RC-K"): C("C-L"), # clear log 4859 }, when = lambda ctx: 4860 cnfg.screen_has_focus and 4861 matchProps(clas="^alacritty$")(ctx) ) 4862 4863 4864 keymap("Contour terminal overrides", { 4865 C("RC-minus"): C("Shift-C-minus"), # Decrease font size (override general terminals remap) 4866 }, when = lambda ctx: 4867 cnfg.screen_has_focus and 4868 matchProps(clas="^contour$")(ctx) ) 4869 4870 4871 keymap("COSMIC Terminal overrides", { 4872 # There are already tab nav fixes in the usual place. 4873 C("RC-equal"): C("C-equal"), # Increase font size (override general terminals remap) 4874 }, when = lambda ctx: 4875 cnfg.screen_has_focus and 4876 matchProps(clas="^com.system76.CosmicTerm$")(ctx) ) 4877 4878 4879 keymap("Deepin Terminal overrides", { 4880 C("RC-w"): C("Alt-w"), # Close only current tab, instead of all other tabs 4881 C("RC-j"): None, # Block Cmd+J from remapping to vertical split (Ctrl+Shift+J) 4882 C("RC-minus"): C("C-minus"), # Decrease font size/zoom out 4883 C("RC-equal"): C("C-equal"), # Increase font size/zoom in 4884 }, when = lambda ctx: 4885 cnfg.screen_has_focus and 4886 matchProps(clas="^deepin-terminal$")(ctx) ) 4887 4888 keymap("Ghostty terminal overrides", { 4889 C("RC-Equal"): C( 4890 "C-Equal" 4891 ), # Increase font size [override general terminals remap] 4892 C("RC-D"): C("RC-Shift-O"), # Open right split 4893 C("RC-Shift-D"): C("RC-Shift-E"), # Open down split 4894 C("RC-Alt-I"): C("RC-Shift-I"), # Open inspector 4895 C("RC-K"): C("C-L"), # clear log 4896 }, when = lambda ctx: 4897 cnfg.screen_has_focus and 4898 matchProps(clas="^.*ghostty.*$")(ctx) 4899 ) 4900 4901 keymap("Hyper terminal tab switching", { 4902 C("RC-Equal"): C("C-Equal"), # Increase font size [override general terminals remap] 4903 C("Shift-LC-Tab"): [bind,C("Shift-C-Tab")], # Tab nav: Go to prior tab (left) [override general remap] 4904 C("LC-Tab"): [bind,C("C-Tab")], # Tab nav: Go to next tab (right) [override general remap] 4905 }, when = lambda ctx: 4906 cnfg.screen_has_focus and 4907 matchProps(clas="^hyper$")(ctx) ) 4908 4909 keymap("Kitty terminal - not tab nav", { 4910 C("RC-L"): C("C-L"), # Clear log 4911 C("RC-K"): C("C-L"), # Clear log (macOS) 4912 }, when = lambda ctx: 4913 cnfg.screen_has_focus and 4914 matchProps(clas="^kitty$")(ctx) ) 4915 4916 keymap("Konsole terminal - not tab nav", { 4917 C("RC-comma"): C("Shift-C-comma"), # Open Preferences dialog 4918 C("RC-0"): C("C-Alt-0"), # Reset font size 4919 C("RC-K"): C("Shift-C-K"), # Clear Scrollback and Reset 4920 }, when = lambda ctx: 4921 cnfg.screen_has_focus and 4922 matchProps(clas="^Konsole$|^org.kde.Konsole$")(ctx) ) 4923 4924 keymap("Terminology terminal", { 4925 C("RC-w"): C("Shift-C-End"), # Close focused tab 4926 C("RC-c"): C("Alt-w"), # Copy selection to primary buffer 4927 C("RC-v"): C("Alt-Enter"), # Paste primary buffer 4928 C("RC-0"): C("C-Alt-0"), # Reset font size 4929 C("RC-Minus"): C("C-Alt-Minus"), # Decrease font size 4930 C("RC-Equal"): C("C-Alt-Equal"), # Increase font size 4931 }, when = lambda ctx: 4932 cnfg.screen_has_focus and 4933 matchProps(clas="^terminology$")(ctx) ) 4934 4935 keymap("Wave terminal", { 4936 C("RC-t"): C("Alt-t"), # Open a new tab 4937 C("RC-n"): C("Alt-n"), # Open a new terminal block 4938 C("Shift-RC-n"): C("Shift-Alt-n"), # Open a new window 4939 C("RC-w"): C("Alt-w"), # Close the current block 4940 C("Shift-RC-w"): C("Shift-Alt-w"), # Close the current tab 4941 }, when = lambda ctx: 4942 cnfg.screen_has_focus and 4943 matchProps(clas="^Wave$")(ctx) ) 4944 4945 keymap("Xfce4 terminal", { 4946 C("RC-comma"): [C("Alt-e"), sleep(0.1), C("e")], # Open Preferences dialog 4947 }, when = lambda ctx: 4948 cnfg.screen_has_focus and 4949 matchProps(clas="^xfce4-terminal$")(ctx) ) 4950 4951 4952 # Overrides to General Terminals shortcuts for specific distros (or are they really just desktop environments?) 4953 4954 if DISTRO_ID in ['fedora', 'almalinux'] and DESKTOP_ENV == 'gnome': 4955 keymap("GenTerms overrides: Fedora GNOME", { 4956 C("RC-H"): C("Super-h"), # Hide Window/Minimize app (gnome/fedora) 4957 }, when = lambda ctx: 4958 cnfg.screen_has_focus and 4959 matchProps(clas=termStr)(ctx) 4960 ) 4961 4962 if DISTRO_ID == 'pop': 4963 keymap("GenTerms overrides: Pop!_OS", { 4964 C("LC-Right"): [bind,C("Super-C-Up")], # SL - Change workspace (pop) 4965 C("LC-Left"): [bind,C("Super-C-Down")], # SL - Change workspace (pop) 4966 }, when = lambda ctx: 4967 cnfg.screen_has_focus and 4968 matchProps(clas=termStr)(ctx) 4969 ) 4970 4971 if DISTRO_ID in ['ubuntu', 'fedora'] and DESKTOP_ENV == 'gnome': 4972 keymap("GenTerms overrides: Ubuntu/Fedora", { 4973 C("LC-RC-Q"): C("Super-L"), # Lock screen (ubuntu/fedora) 4974 C("LC-Right"): [bind,C("Super-Page_Up")], # SL - Change workspace (ubuntu/fedora) 4975 C("LC-Left"): [bind,C("Super-Page_Down")], # SL - Change workspace (ubuntu/fedora) 4976 }, when = lambda ctx: 4977 cnfg.screen_has_focus and 4978 matchProps(clas=termStr)(ctx) 4979 ) 4980 4981 4982 # Overrides to General Terminals shortcuts for specific desktop environments 4983 4984 if DESKTOP_ENV == 'budgie': 4985 keymap("GenTerms overrides: Budgie", { 4986 C("LC-Right"): [bind,C("C-Alt-Right")], # Default SL - Change workspace (budgie) 4987 C("LC-Left"): [bind,C("C-Alt-Left")], # Default SL - Change workspace (budgie) 4988 }, when = lambda ctx: 4989 cnfg.screen_has_focus and 4990 matchProps(clas=termStr)(ctx) 4991 ) 4992 4993 # On Pop!_OS 22.04, System76 seems to have changed the name of the DE from 'cosmic' to 'pop'. 4994 # Probably to avoid overlapping with the new COSMIC desktop environment in Pop!_OS 24.04 and later. 4995 if DESKTOP_ENV in ['cosmic', 'pop']: 4996 keymap("GenTerms overrides: COSMIC", { 4997 C("LC-RC-F"): C("Super-M"), # Maximize window toggle (overrides General terminals) 4998 }, when = lambda ctx: 4999 cnfg.screen_has_focus and 5000 matchProps(clas=termStr)(ctx) 5001 ) 5002 5003 if DESKTOP_ENV == 'gnome': 5004 keymap("GenTerms overrides: GNOME", { 5005 ### Keyboard input source (language/layout) switching in GNOME 5006 C("LC-Space"): [bind,C("Super-Space")], # keyboard input source (layout) switching (gnome) 5007 C("Shift-LC-Space"): [bind,C("Super-Shift-Space")], # keyboard input source (layout) switching (reverse) (gnome) 5008 }, when = lambda ctx: 5009 cnfg.screen_has_focus and 5010 matchProps(clas=termStr)(ctx) 5011 ) 5012 5013 if DESKTOP_ENV == 'kde': 5014 keymap("GenTerms overrides: KDE", { 5015 ### Keyboard input source (language/layout) switching in KDE Plasma 5016 C("LC-Space"): [bind,C("Super-Alt-L")], # keyboard input source (layout) switching (Last-Used) (kde) 5017 C("Shift-LC-Space"): [bind,C("Super-Alt-K")], # keyboard input source (layout) switching (Next) (kde) 5018 C("RC-H"): C("Super-Page_Down"), # Hide Window/Minimize app (KDE Plasma) 5019 5020 # C("LC-RC-f"): C("Alt-F10"), # Toggle window maximized state (pre-Plasma 6) 5021 # F10 key was designated an accessibility key for opening the window/app menu in KDE. 5022 # The shortcut for toggling window maximization state is now Meta+PgUp (so, Super-Page_Up). 5023 C("LC-RC-f"): C("Super-Page_Up"), # Toggle window maximized state 5024 5025 # Workspace (virtual desktop) navigation 5026 C("LC-Left"): C("C-Super-Left"), # Switch one desktop to the left 5027 C("LC-Right"): C("C-Super-Right"), # Switch one desktop to the right 5028 5029 }, when = lambda ctx: 5030 cnfg.screen_has_focus and 5031 matchProps(clas=termStr)(ctx) 5032 ) 5033 5034 if DESKTOP_ENV == 'pantheon': 5035 keymap("GenTerms overrides: elementary OS", { 5036 C("LC-Right"): [bind,C("Super-Right")], # SL - Change workspace (elementary) 5037 C("LC-Left"): [bind,C("Super-Left")], # SL - Change workspace (elementary) 5038 }, when = lambda ctx: 5039 cnfg.screen_has_focus and 5040 matchProps(clas=termStr)(ctx) 5041 ) 5042 5043 if DESKTOP_ENV == 'sway': 5044 keymap("GenTerms overrides: swaywm", { 5045 C("RC-Q"): C("Shift-C-Q"), # Override sway GenGUI Cmd+Q 5046 }, when = lambda ctx: 5047 cnfg.screen_has_focus and 5048 matchProps(clas=termStr)(ctx) 5049 ) 5050 5051 if DESKTOP_ENV == 'xfce': 5052 keymap("GenTerms overrides: Xfce4", { 5053 C("RC-Grave"): [bind,C("Super-Tab")], # xfce4 Switch within app group 5054 C("Shift-RC-Grave"): [bind,C("Super-Shift-Tab")], # xfce4 Switch within app group 5055 C("LC-Right"): [bind,C("C-Alt-Home")], # SL - Change workspace xfce4 5056 C("LC-Left"): [bind,C("C-Alt-End")], # SL - Change workspace xfce4 5057 }, when = lambda ctx: 5058 cnfg.screen_has_focus and 5059 matchProps(clas=termStr)(ctx) 5060 ) 5061 5062 5063 # Active in all apps in the terminals list 5064 keymap("General Terminals", { 5065 5066 ### wordwise overrides of general GUI block 5067 C("Alt-Backspace"): C("C-w"), # Wordwise delete word left of cursor in terminals 5068 # C("Alt-Backspace"): C("Alt-Shift-Backspace"), # Wordwise delete word left of cursor in terminals 5069 C("Alt-Delete"): [C("Esc"),C("d")], # Wordwise delete word right of cursor in terminals 5070 C("RC-Backspace"): C("C-u"), # Wordwise delete line left of cursor in terminals 5071 C("RC-Delete"): C("C-k"), # Wordwise delete line right of cursor in terminals 5072 5073 ### Tab navigation 5074 C("Shift-RC-Left"): [bind,C("C-Page_Up")], # Tab nav: Go to prior tab (Left) 5075 C("Shift-RC-Right"): [bind,C("C-Page_Down")], # Tab nav: Go to next tab (Right) 5076 5077 C("LC-RC-f"): C("Alt-F10"), # Toggle window maximized state (gnome?) 5078 5079 # Ctrl Tab - In App Tab Switching 5080 C("LC-Tab") : C("C-PAGE_DOWN"), 5081 C("Shift-LC-Tab") : C("C-PAGE_UP"), 5082 C("LC-Grave") : C("C-PAGE_UP"), 5083 # C("Alt-Tab"): ignore_combo, # Default - Cmd Tab - App Switching Default 5084 # C("RC-Tab"): C("Alt-Tab"), # Default - Cmd Tab - App Switching Default 5085 # C("Shift-RC-Tab"): C("Alt-Shift-Tab"), # Default - Cmd Tab - App Switching Default 5086 5087 # Converts Cmd to use Ctrl-Shift 5088 C("RC-MINUS"): C("C-MINUS"), # Reduce font size 5089 C("RC-EQUAL"): C("C-Shift-EQUAL"), # Increase font size 5090 # C("RC-BACKSPACE"): C("C-Shift-BACKSPACE"), # Conflicts with wordwise shortcut above 5091 C("RC-W"): C("C-Shift-W"), # Close tab/window 5092 # C("RC-E"): C("C-Shift-E"), # No function - RE-ENABLE IF SOMEONE REPORTS 5093 # C("RC-R"): C("C-Shift-R"), # No function - RE-ENABLE IF SOMEONE REPORTS 5094 C("RC-T"): C("C-Shift-t"), # Open new tab in many terminals 5095 # C("RC-Y"): C("C-Shift-Y"), # No function - RE-ENABLE IF SOMEONE REPORTS 5096 # C("RC-U"): C("C-Shift-U"), # No function - RE-ENABLE IF SOMEONE REPORTS 5097 # C("RC-I"): C("C-Shift-I"), # No function - RE-ENABLE IF SOMEONE REPORTS 5098 # C("RC-O"): C("C-Shift-O"), # No function - RE-ENABLE IF SOMEONE REPORTS 5099 # C("RC-P"): C("C-Shift-P"), # No function - RE-ENABLE IF SOMEONE REPORTS 5100 C("RC-LEFT_BRACE"): C("C-Shift-LEFT_BRACE"), 5101 C("RC-RIGHT_BRACE"): C("C-Shift-RIGHT_BRACE"), 5102 # If focused app is terminal, this stops Cmd+A from working in GNOME overview search field 5103 # C("RC-A"): C("C-Shift-A"), # No function - RE-ENABLE IF SOMEONE REPORTS 5104 C("RC-S"): C("C-Shift-S"), # Save file in some terminals 5105 C("RC-D"): C("C-Shift-D"), # Split horizontal in some terminals 5106 C("RC-F"): C("C-Shift-F"), # Find text in some terminals 5107 # C("RC-G"): C("C-Shift-G"), # No function - RE-ENABLE IF SOMEONE REPORTS 5108 # C("RC-H"): C("C-Shift-H"), # No function - RE-ENABLE IF SOMEONE REPORTS 5109 # C("RC-J"): C("C-Shift-J"), # No function - RE-ENABLE IF SOMEONE REPORTS 5110 # C("RC-K"): C("C-Shift-K"), # No function - RE-ENABLE IF SOMEONE REPORTS 5111 C("RC-L"): C("C-Shift-L"), # Clear screen in some terminals 5112 # C("RC-SEMICOLON"): C("C-Shift-SEMICOLON"), # No function - RE-ENABLE IF SOMEONE REPORTS 5113 # C("RC-APOSTROPHE"): C("C-Shift-APOSTROPHE"), # No function - RE-ENABLE IF SOMEONE REPORTS 5114 # C("RC-GRAVE"): C("C-Shift-GRAVE"), # Conflicts with General GUI window switching 5115 # C("RC-Z"): C("C-Shift-Z"), # No function - RE-ENABLE IF SOMEONE REPORTS 5116 # C("RC-X"): C("C-Shift-X"), # No function - RE-ENABLE IF SOMEONE REPORTS 5117 C("RC-C"): C("C-Shift-C"), # Copy text in many terminals 5118 C("RC-V"): C("C-Shift-V"), # Paste text in many terminals 5119 # C("RC-B"): C("C-Shift-B"), # No function - RE-ENABLE IF SOMEONE REPORTS 5120 C("RC-N"): C("C-Shift-N"), # Open new window in many terminals 5121 # C("RC-M"): C("C-Shift-M"), # No function - RE-ENABLE IF SOMEONE REPORTS 5122 # C("RC-COMMA"): C("C-Shift-COMMA"), # Open Preferences (Replaced by per-app remaps if needed) 5123 C("RC-Dot"): C("C-c"), # Mimic macOS Cmd+Dot to cancel command 5124 # C("RC-SLASH"): C("C-Shift-SLASH"), # No function - RE-ENABLE IF SOMEONE REPORTS 5125 # C("RC-KPASTERISK"): C("C-Shift-KPASTERISK"), # No function - RE-ENABLE IF SOMEONE REPORTS 5126 5127 # Allow access to Linux TTY virtual consoles with the usual physical key locations (General Terminals) 5128 C("LC-RC-F1"): C("C-Alt-F1"), # Go to TTY virtual console 1 5129 C("LC-RC-F2"): C("C-Alt-F2"), # Go to TTY virtual console 2 5130 C("LC-RC-F3"): C("C-Alt-F3"), # Go to TTY virtual console 3 5131 C("LC-RC-F4"): C("C-Alt-F4"), # Go to TTY virtual console 4 5132 C("LC-RC-F5"): C("C-Alt-F5"), # Go to TTY virtual console 5 5133 C("LC-RC-F6"): C("C-Alt-F6"), # Go to TTY virtual console 6 5134 C("LC-RC-F7"): C("C-Alt-F7"), # Go to TTY virtual console 7 5135 5136 }, when = lambda ctx: 5137 cnfg.screen_has_focus and 5138 matchProps(clas=termStr)(ctx) 5139 ) 5140 5141 5142 5143 ############################# GENERAL GUI ################################ 5144 ### ### 5145 ### ### 5146 ### ██████ ███████ ███ ██ ███████ ██████ █████ ██ ### 5147 ### ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ### 5148 ### ██ ███ █████ ██ ██ ██ █████ ██████ ███████ ██ ### 5149 ### ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ### 5150 ### ██████ ███████ ██ ████ ███████ ██ ██ ██ ██ ███████ ### 5151 ### ### 5152 ### ### 5153 ############################################################################ 5154 5155 # Note: terminals extends to remotes as well 5156 keymap("Cmd+Dot not in terminals", { 5157 C("RC-Dot"): C("Esc"), # Mimic macOS Cmd+dot = Escape key (not in terminals) 5158 }, when = lambda ctx: 5159 cnfg.screen_has_focus and 5160 matchProps(not_clas=terms_and_remotes_Str)(ctx) 5161 ) 5162 5163 5164 # Overrides to General GUI shortcuts for specific keyboard types 5165 keymap("GenGUI overrides: Chromebook/IBM", { 5166 # In-App Tab switching 5167 C("Alt-Tab"): [iEF2NT(),bind,C("C-Tab")], # Chromebook/IBM - In-App Tab switching 5168 C("Alt-Shift-Tab"): [iEF2NT(),bind,C("C-Shift-Tab")], # Chromebook/IBM - In-App Tab switching 5169 C("Alt-Grave") : [iEF2NT(),bind,C("C-Shift-Tab")], # Chromebook/IBM - In-App Tab switching 5170 C("RAlt-Backspace"): C("Delete"), # Chromebook/IBM - Delete 5171 C("LAlt-Backspace"): C("C-Backspace"), # Chromebook/IBM - Delete Left Word of Cursor 5172 }, when = lambda ctx: 5173 cnfg.screen_has_focus and 5174 ( isKBtype('Chromebook', map="gengui ovr cbook")(ctx) or 5175 isKBtype('IBM', map="gengui ovr ibm")(ctx) ) and 5176 matchProps(not_clas=remoteStr)(ctx) 5177 ) 5178 keymap("GenGUI overrides: not Chromebook", { 5179 # In-App Tab switching 5180 C("Super-Tab"): [iEF2NT(),bind,C("C-Tab")], # Default not-chromebook 5181 C("Super-Shift-Tab"): [iEF2NT(),bind,C("Shift-C-Tab")], # Default not-chromebook 5182 C("Alt-Backspace"): C("C-Backspace"), # Default not-chromebook 5183 }, when = lambda ctx: 5184 cnfg.screen_has_focus and 5185 not isKBtype('Chromebook', map="gengui ovr not cbook")(ctx) and 5186 matchProps(not_clas=remoteStr)(ctx) 5187 ) 5188 5189 5190 # Overrides to General GUI shortcuts for specific distros 5191 5192 if DISTRO_ID in ['almalinux', 'rhel', 'rocky'] and DESKTOP_ENV == 'xfce': 5193 keymap("GenGUI overrides: Alma/Rocky Xfce4", { 5194 C("RC-Space"): [iEF2NT(),C("Alt-F3")], # Launch App Finder xfce4 (AlmaLinux/Rocky) 5195 }, when = lambda ctx: 5196 cnfg.screen_has_focus and 5197 matchProps(not_clas=remoteStr)(ctx) 5198 ) 5199 5200 if DISTRO_ID == 'debian' and DESKTOP_ENV == 'xfce': 5201 keymap("GenGUI overrides: Debian Xfce4", { 5202 C("RC-Space"): [iEF2NT(),C("Alt-F1")], # Launch Application Menu xfce4 (Debian) 5203 }, when = lambda ctx: 5204 cnfg.screen_has_focus and 5205 matchProps(not_clas=remoteStr)(ctx) 5206 ) 5207 5208 if DISTRO_ID in ['fedora', 'almalinux'] and DESKTOP_ENV == 'gnome': 5209 keymap("GenGUI overrides: Fedora GNOME", { 5210 C("Super-RC-Q"): C("Super-L"), # Lock screen (fedora) 5211 C("RC-H"): C("Super-h"), # Default SL - Minimize app (gnome/budgie/popos/fedora) not-deepin 5212 C("Super-Right"): [bind,C("Super-Page_Up")], # SL - Change workspace (ubuntu/fedora) 5213 C("Super-Left"): [bind,C("Super-Page_Down")], # SL - Change workspace (ubuntu/fedora) 5214 }, when = lambda ctx: 5215 cnfg.screen_has_focus and 5216 matchProps(not_clas=remoteStr)(ctx) 5217 ) 5218 5219 if DISTRO_ID == 'manjaro' and DESKTOP_ENV == 'gnome': 5220 keymap("GenGUI overrides: Manjaro GNOME", { 5221 C("RC-Q"): C("Super-Q"), # Close window 5222 }, when = lambda ctx: 5223 cnfg.screen_has_focus and 5224 matchProps(not_clas=remoteStr)(ctx) 5225 ) 5226 5227 if DISTRO_ID == 'manjaro' and DESKTOP_ENV == 'xfce': 5228 keymap("GenGUI overrides: Manjaro Xfce", { 5229 C("RC-Space"): [iEF2NT(),C("Alt-F1")], # Open Whisker Menu with Cmd+Space 5230 }, when = lambda ctx: 5231 cnfg.screen_has_focus and 5232 matchProps(not_clas=remoteStr)(ctx) 5233 ) 5234 5235 if DISTRO_ID == 'manjaro': 5236 keymap("GenGUI overrides: Manjaro", { 5237 C("Super-RC-f"): C("Super-PAGE_UP"), # SL- Maximize app manjaro 5238 }, when = lambda ctx: 5239 cnfg.screen_has_focus and 5240 matchProps(not_clas=remoteStr)(ctx) 5241 ) 5242 5243 if DISTRO_ID == 'mint' and DESKTOP_ENV == 'xfce': 5244 keymap("GenGUI overrides: Mint Xfce4", { 5245 C("RC-Space"): [iEF2NT(),C("Super-Space")], # Launch Application Menu xfce4 (Linux Mint) 5246 }, when = lambda ctx: 5247 cnfg.screen_has_focus and 5248 matchProps(not_clas=remoteStr)(ctx) 5249 ) 5250 5251 if DISTRO_ID == 'neon': 5252 keymap("GenGUI overrides: KDE Neon", { 5253 C("RC-Super-f"): C("Super-Page_Up"), # SL - Toggle maximized window state (kde_neon) 5254 C("RC-H"): C("Super-Page_Down"), # SL - Minimize app (kde_neon) 5255 # SL - Default SL - Change workspace (kde_neon) 5256 }, when = lambda ctx: 5257 cnfg.screen_has_focus and 5258 matchProps(not_clas=remoteStr)(ctx) 5259 ) 5260 5261 if DISTRO_ID == 'pop': 5262 keymap("GenGUI overrides: Pop!_OS", { 5263 C("RC-Space"): [iEF2NT(),C("Super-slash")], # "Launch and switch applications" (pop) 5264 C("RC-H"): C("Super-h"), # Default SL - Minimize app (gnome/budgie/popos/fedora) not-deepin 5265 C("Super-Right"): [bind,C("Super-C-Up")], # SL - Change workspace (pop) 5266 C("Super-Left"): [bind,C("Super-C-Down")], # SL - Change workspace (pop) 5267 C("RC-Q"): C("Super-q"), # SL - Close Apps (pop) 5268 }, when = lambda ctx: 5269 cnfg.screen_has_focus and 5270 matchProps(not_clas=remoteStr)(ctx) 5271 ) 5272 5273 if DISTRO_ID == 'ubuntu': 5274 keymap("GenGUI overrides: Ubuntu", { 5275 C("Super-RC-Q"): C("Super-L"), # Lock screen (ubuntu) 5276 C("Super-Right"): [bind,C("Super-Page_Up")], # SL - Change workspace (ubuntu) 5277 C("Super-Left"): [bind,C("Super-Page_Down")], # SL - Change workspace (ubuntu) 5278 }, when = lambda ctx: 5279 cnfg.screen_has_focus and 5280 matchProps(not_clas=remoteStr)(ctx) 5281 ) 5282 5283 5284 # Overrides to General GUI shortcuts for specific desktop environments 5285 5286 if DESKTOP_ENV == 'budgie': 5287 keymap("GenGUI overrides: Budgie", { 5288 C("RC-Space"): [iEF2NT(),Key.LEFT_META], # Open panel-main-menu (Budgie menu) 5289 C("Super-Right"): C("C-Alt-Right"), # Change workspace (budgie) 5290 C("Super-Left"): C("C-Alt-Left"), # Change workspace (budgie) 5291 C("RC-H"): C("Super-h"), # Minimize app (gnome/budgie/popos/fedora) not-deepin 5292 }, when = lambda ctx: 5293 cnfg.screen_has_focus and 5294 matchProps(not_clas=remoteStr)(ctx) 5295 ) 5296 5297 if DESKTOP_ENV == 'cinnamon': 5298 keymap("GenGUI overrides: Cinnamon", { 5299 C("RC-Space"): [iEF2NT(),C("C-Esc")], # Right click, configure Mint menu shortcut to Ctrl+Esc 5300 }, when = lambda ctx: 5301 cnfg.screen_has_focus and 5302 matchProps(not_clas=remoteStr)(ctx) 5303 ) 5304 5305 # On Pop!_OS 22.04, System76 seems to have changed the name of the DE from 'cosmic' to 'pop'. 5306 # Probably to avoid overlapping with the new COSMIC desktop environment in Pop!_OS 24.04 and later. 5307 if DESKTOP_ENV in ['cosmic', 'pop']: 5308 keymap("GenGUI overrides: COSMIC", { 5309 # No shortcuts settings panel seems to be available at this time (July 30, 2024), 5310 # so we can't "fix" this during Toshy install to not use the Meta/Super key. 5311 C("RC-Space"): [Key.LEFT_META,iEF2NT()], # Launcher or Workspaces or Applications (user choice) 5312 C("RC-Q"): C("Super-Q"), # Close window/Quit (overrides Alt+F4 from General GUI) 5313 C("Super-RC-F"): C("Super-M"), # Maximize window toggle (overrides General GUI) 5314 }, when = lambda ctx: 5315 cnfg.screen_has_focus and 5316 matchProps(not_clas=remoteStr)(ctx) 5317 ) 5318 5319 if DESKTOP_ENV == 'dde': 5320 keymap("GenGUI overrides: DDE", { 5321 C("RC-Space"): [iEF2NT(),Key.LEFT_META], # Open Launcher menu (Deeping Desktop Environment) 5322 }, when = lambda ctx: 5323 cnfg.screen_has_focus and 5324 matchProps(not_clas=remoteStr)(ctx) 5325 ) 5326 5327 if DESKTOP_ENV == 'deepin': 5328 keymap("GenGUI overrides: Deepin", { 5329 C("RC-H"): C("Super-n"), # Minimize app (deepin) 5330 C("Alt-RC-Space"): C("Super-e"), # Open Finder - (deepin) 5331 }, when = lambda ctx: 5332 cnfg.screen_has_focus and 5333 matchProps(not_clas=remoteStr)(ctx) 5334 ) 5335 5336 if DESKTOP_ENV == 'enlightenment': 5337 keymap("GenGUI overrides: Enlightenment", { 5338 C("RC-q"): C("C-Alt-x"), # Close window (Cmd+Q) 5339 # C("RC-Space"): [iEF2NT(),C("C-Alt-m")], # enlightenment main menu (override in "User Apps" slice if necessary) 5340 C("RC-Space"): [iEF2NT(),C("C-Alt-Space")], # enlightenment main menu (override in "User Apps" slice if necessary) 5341 }, when = lambda ctx: 5342 cnfg.screen_has_focus and 5343 matchProps(not_clas=remoteStr)(ctx) 5344 ) 5345 5346 if DESKTOP_ENV == 'gnome': 5347 if is_pre_GNOME_45(DE_MAJ_VER): 5348 # This keymap, if invoked, must come before the other GNOME overrides in the next keymap, not after. 5349 keymap("GenGUI overrides: pre-GNOME 45 fix", { 5350 C("RC-Space"): [iEF2NT(),C("Super-s")], # Override GNOME 45+ Shift+Ctrl+Space remap 5351 }, when = lambda ctx: 5352 cnfg.screen_has_focus and 5353 matchProps(not_clas=remoteStr)(ctx) 5354 ) 5355 keymap("GenGUI overrides: GNOME", { 5356 C("RC-Space"): [iEF2NT(),C("Shift-C-Space")], # Show GNOME overview/app launcher 5357 C("RC-F3"): C("Super-d"), # Default SL - Show Desktop (gnome/kde,elementary) 5358 C("RC-Super-f"): C("Alt-F10"), # Default SL - Maximize app (gnome/kde) 5359 C("RC-H"): C("Super-h"), # Default SL - Minimize app (gnome/budgie/popos/fedora) not-deepin 5360 # Screenshot shortcuts for GNOME 42+ 5361 C("RC-Shift-Key_3"): C("Shift-Print"), # Take a screenshot immediately (gnome) 5362 C("RC-Shift-Key_4"): C("Alt-Print"), # Take a screenshot of a window (gnome) 5363 C("RC-Shift-Key_5"): C("Print"), # Take a screenshot interactively (gnome) 5364 }, when = lambda ctx: 5365 cnfg.screen_has_focus and 5366 matchProps(not_clas=remoteStr)(ctx) 5367 ) 5368 5369 if DESKTOP_ENV == 'hyprland': 5370 keymap("GenGUI overrides: Hyprland", { 5371 # C("RC-Space"): [iEF2NT(),Key.LEFT_META], # Open Launcher with Cmd+Space 5372 C("RC-Space"): [C("Super-d"), iEF2NT()], # Open Launcher with Cmd+Space 5373 }, when = lambda ctx: 5374 cnfg.screen_has_focus and 5375 matchProps(not_clas=remoteStr)(ctx) 5376 ) 5377 5378 if DESKTOP_ENV == 'icewm': 5379 keymap("GenGUI overrides: IceWM", { 5380 C("RC-Space"): [iEF2NT(),Key.LEFT_META], # IceWM: Win95Keys=1 (Meta shows menu) 5381 }, when = lambda ctx: 5382 cnfg.screen_has_focus and 5383 matchProps(not_clas=remoteStr)(ctx) 5384 ) 5385 5386 if DESKTOP_ENV == 'kde': 5387 keymap("GenGUI overrides: KDE", { 5388 5389 # Application launcher menu remap 5390 # C("RC-Space"): [iEF2NT(),C("Alt-F1")], # Application Launcher Menu 5391 5392 # krunner drop-down (similar to Spotlight) remap 5393 C("RC-Space"): [iEF2NT(),C("Alt-Space")], # Invoke krunner drop-down 5394 5395 C("RC-F3"): C("Super-d"), # Show Desktop (gnome/kde,elementary) 5396 C("RC-H"): C("Super-Page_Down"), # Minimize app (KDE Plasma) 5397 5398 # Workspace (virtual desktop) navigation 5399 C("Super-Left"): C("C-Super-Left"), # Switch one desktop to the left 5400 C("Super-Right"): C("C-Super-Right"), # Switch one desktop to the right 5401 5402 # C("Super-RC-f"): C("Alt-F10"), # Toggle window maximized state (pre-Plasma 6) 5403 # F10 key was designated an accessibility key for opening the window/app menu in KDE. 5404 # The shortcut for toggling window maximization state is now Meta+PgUp (so, Super-Page_Up). 5405 C("Super-RC-f"): C("Super-Page_Up"), # Toggle window maximized state 5406 5407 # Screenshot shortcuts for KDE Plasma desktops (Spectacle app) 5408 C("RC-Shift-Key_3"): C("Shift-Print"), # Take a screenshot immediately (kde) 5409 C("RC-Shift-Key_4"): C("Alt-Print"), # Take a screenshot of a window (kde) 5410 C("RC-Shift-Key_5"): C("Print"), # Take a screenshot interactively (kde) 5411 5412 ### Keyboard input source (language/layout) switching in KDE Plasma 5413 C("Super-Space"): [bind,C("Super-Alt-L")], # keyboard input source (layout) switching (Last-Used) (kde) 5414 C("Shift-Super-Space"): [bind,C("Super-Alt-K")], # keyboard input source (layout) switching (Next) (kde) 5415 5416 }, when = lambda ctx: 5417 cnfg.screen_has_focus and 5418 matchProps(not_clas=remoteStr)(ctx) 5419 ) 5420 5421 if DESKTOP_ENV == 'mate' and DISTRO_ID == 'mint': 5422 keymap("GenGUI overrides: MATE on Mint", { 5423 # Right click, configure Mint menu shortcut to match `Alt+Space` shortcut to make this work 5424 C("RC-Space"): [iEF2NT(), C("Alt-Space")], # Open Mint app menu 5425 }, when = lambda ctx: 5426 cnfg.screen_has_focus and 5427 matchProps(not_clas=remoteStr)(ctx) 5428 ) 5429 5430 if DESKTOP_ENV == 'mate' and DISTRO_ID == 'ubuntu': 5431 keymap("GenGUI overrides: MATE on Ubuntu", { 5432 # No way to reconfigure the shortcut for Brisk Menu Launcher? 5433 C("RC-Space"): [iEF2NT(), Key.LEFT_META], # Open Brisk Menu Launcher 5434 }, when = lambda ctx: 5435 cnfg.screen_has_focus and 5436 matchProps(not_clas=remoteStr)(ctx) 5437 ) 5438 5439 if DESKTOP_ENV == 'miracle-wm': 5440 keymap("GenGUI overrides: MiracleWM", { 5441 # C("RC-Space"): [iEF2NT(),Key.LEFT_META], # Open Launcher with Cmd+Space 5442 C("RC-Space"): [C("Super-d"), iEF2NT()], # Open Launcher with Cmd+Space 5443 }, when = lambda ctx: 5444 cnfg.screen_has_focus and 5445 matchProps(not_clas=remoteStr)(ctx) 5446 ) 5447 5448 if DESKTOP_ENV == 'pantheon': 5449 keymap("GenGUI overrides: Pantheon", { 5450 C("RC-F3"): C("Super-d"), # Show Desktop (gnome/kde,elementary) 5451 # C("RC-Space"): [iEF2NT(),C("Super-Space")], # Launch Application Menu (elementary) 5452 C("RC-Space"): [iEF2NT(),C("Alt-F2")], # Launch Application Menu (elementary OS 8) 5453 C("Super-RC-f"): C("Super-Up"), # Maximize app elementary 5454 }, when = lambda ctx: 5455 cnfg.screen_has_focus and 5456 matchProps(not_clas=remoteStr)(ctx) 5457 ) 5458 5459 if DESKTOP_ENV == 'sway': 5460 keymap("GenGUI overrides: swaywm", { 5461 C("RC-Space"): [iEF2NT(),C("Super-d")], # Open sway launcher 5462 C("RC-Q"): C("C-Q"), # Override General GUI Alt+F4 remap 5463 }, when = lambda ctx: 5464 cnfg.screen_has_focus and 5465 matchProps(not_clas=remoteStr)(ctx) 5466 ) 5467 5468 if DESKTOP_ENV == 'trinity': 5469 keymap("GenGUI overrides: Trinity desktop", { 5470 C("RC-Space"): [iEF2NT(),Key.LEFT_META], # Trinity desktop (Q4OS) 5471 }, when = lambda ctx: 5472 cnfg.screen_has_focus and 5473 matchProps(not_clas=remoteStr)(ctx) 5474 ) 5475 5476 if DESKTOP_ENV == 'unity': 5477 keymap("GenGUI overrides: Unity desktop", { 5478 C("RC-Space"): [iEF2NT(),Key.LEFT_META], # Trinity desktop (Q4OS) 5479 }, when = lambda ctx: 5480 cnfg.screen_has_focus and 5481 matchProps(not_clas=remoteStr)(ctx) 5482 ) 5483 5484 if DESKTOP_ENV == 'xfce' and DISTRO_ID == 'zorin': 5485 keymap("GenGUI overrides: Zorin Xfce", { 5486 C("RC-Space"): [iEF2NT(),C("Alt-Pause")], # "Launch and switch applications" (Xfce on Zorin) 5487 }, when = lambda ctx: 5488 cnfg.screen_has_focus and 5489 matchProps(not_clas=remoteStr)(ctx) 5490 ) 5491 5492 if DESKTOP_ENV == 'xfce': 5493 keymap("GenGUI overrides: Xfce4", { 5494 C("RC-Grave"): [bind,C("Super-Tab")], # xfce4 Switch within app group 5495 C("Shift-RC-Grave"): [bind,C("Super-Shift-Tab")], # xfce4 Switch within app group 5496 C("RC-Space"): [iEF2NT(),C("C-Esc")], # Launch Application Menu xfce4 (Xubuntu) 5497 C("RC-F3"): C("C-Alt-d"), # SL- Show Desktop xfce4 5498 C("RC-H"): C("Alt-F9"), # SL - Minimize app xfce4 5499 # Screenshot shortcuts for Xfce desktops (xfce4-screenshooter app) 5500 C("RC-Shift-Key_3"): C("Print"), # Take a screenshot immediately (xfce4) 5501 C("RC-Shift-Key_4"): C("Alt-Print"), # Take a screenshot of a window (xfce4) 5502 C("RC-Shift-Key_5"): C("Shift-Print"), # Take a screenshot interactively (xfce4) 5503 }, when = lambda ctx: 5504 cnfg.screen_has_focus and 5505 matchProps(not_clas=remoteStr)(ctx) 5506 ) 5507 5508 5509 # None referenced here originally 5510 # - but remote clients and VM software ought to be set here 5511 # These are the typical remaps for ALL GUI based apps 5512 keymap("General GUI", { 5513 5514 C("Alt-Numlock"): toggle_forced_numpad, # Turn the Forced Numpad feature on and off 5515 C("Fn-Numlock"): toggle_forced_numpad, # Turn the Forced Numpad feature on and off 5516 C("Numlock"): isNumlockClearKey, # Numlock key is "Clear" (Esc) if cnfg.forced_numpad is True 5517 5518 C("Shift-RC-Left_Brace"): C("C-Page_Up"), # Tab navigation: Go to prior (left) tab 5519 C("Shift-RC-Right_Brace"): C("C-Page_Down"), # Tab navigation: Go to next (right) tab 5520 C("RC-Space"): [iEF2NT(),C("Alt-F1")], # Default SL - Launch Application Menu (gnome/kde) 5521 C("RC-F3"): C("Super-d"), # Default SL - Show Desktop (gnome/kde,elementary) 5522 C("RC-Super-f"): C("Alt-F10"), # Default SL - Maximize app (gnome/kde) 5523 C("RC-Q"): C("Alt-F4"), # Default SL - not-popos 5524 C("Alt-Tab"): ignore_combo, # Default - Cmd Tab - App Switching Default 5525 5526 C("RC-Tab"): [iEF2NT(),bind, C("Alt-Tab")], # Default - Cmd Tab - App Switching Default 5527 C("Shift-RC-Tab"): [iEF2NT(),bind, C("Alt-Shift-Tab")], # Default - Cmd Tab - App Switching Default 5528 5529 C("RC-Grave"): [iEF2NT(),bind, C("Alt-Grave")], # Default not-xfce4 - Cmd ` - Same App Switching 5530 C("Shift-RC-Grave"): [iEF2NT(),bind, C("Alt-Shift-Grave")], # Default not-xfce4 - Cmd ` - Same App Switching 5531 5532 # Fn to Alt style remaps 5533 C("RAlt-Enter"): C("insert"), # Insert 5534 5535 # emacs style 5536 C("Super-a"): C("Home"), # Beginning of Line 5537 C("Super-e"): C("End"), # End of Line 5538 C("Super-b"): C("Left"), 5539 C("Super-f"): C("Right"), 5540 C("Super-n"): C("Down"), 5541 C("Super-p"): C("Up"), 5542 C("Super-k"): [C("Shift-End"), C("Backspace")], 5543 C("Super-d"): C("Delete"), 5544 5545 # This is better done with a native custom shortcut in each DE 5546 # C("Alt-RC-Space"): C(""), # Open Finder - Placeholder not-deepin 5547 5548 # Wordwise 5549 C("RC-Left"): C("Home"), # Beginning of Line 5550 C("Shift-RC-Left"): C("Shift-Home"), # Select all to Beginning of Line 5551 C("RC-Right"): C("End"), # End of Line 5552 C("Shift-RC-Right"): C("Shift-End"), # Select all to End of Line 5553 C("RC-Up"): C("C-Home"), # Beginning of File 5554 C("Shift-RC-Up"): C("C-Shift-Home"), # Select all to Beginning of File 5555 C("RC-Down"): C("C-End"), # End of File 5556 C("Shift-RC-Down"): C("C-Shift-End"), # Select all to End of File 5557 C("Super-Backspace"): C("C-Backspace"), # Delete Left Word of Cursor 5558 C("Super-Delete"): C("C-Delete"), # Delete Right Word of Cursor 5559 C("RC-Backspace"): C("C-Shift-Backspace"), # Delete Entire Line Left of Cursor 5560 C("Alt-Delete"): C("C-Delete"), # Delete Right Word of Cursor 5561 C("Shift-Alt-Backspace"): C("C-Backspace"), # Delete word left of cursor 5562 C("Shift-Alt-Delete"): C("C-Delete"), # Delete word right of cursor 5563 5564 # Allow access to Linux TTY virtual consoles with the usual physical key locations (General GUI) 5565 C("Super-RC-F1"): C("C-Alt-F1"), # Go to TTY virtual console 1 5566 C("Super-RC-F2"): C("C-Alt-F2"), # Go to TTY virtual console 2 5567 C("Super-RC-F3"): C("C-Alt-F3"), # Go to TTY virtual console 3 5568 C("Super-RC-F4"): C("C-Alt-F4"), # Go to TTY virtual console 4 5569 C("Super-RC-F5"): C("C-Alt-F5"), # Go to TTY virtual console 5 5570 C("Super-RC-F6"): C("C-Alt-F6"), # Go to TTY virtual console 6 5571 C("Super-RC-F7"): C("C-Alt-F7"), # Go to TTY virtual console 7 5572 5573 # C("RC-Left"): C("C-LEFT_BRACE"), # Firefox-nw - Back 5574 # C("RC-Right"): C("C-RIGHT_BRACE"), # Firefox-nw - Forward 5575 # C("RC-Left"): C("Alt-LEFT"), # Chrome-nw - Back 5576 # C("RC-Right"): C("Alt-RIGHT"), # Chrome-nw - Forward 5577 # C(""): ignore_combo, # cancel 5578 # C(""): C(""), # 5579 5580 }, when = lambda ctx: 5581 cnfg.screen_has_focus and 5582 matchProps(not_clas=remoteStr)(ctx) 5583 ) 5584 5585 5586 keymap("Diagnostics (isMultiTap)", { 5587 5588 C("Shift-Alt-RC-i"): isMultiTap( 5589 # tap_1_action=None, # Block single tap 5590 tap_1_action=C("Shift-Alt-C-i"), # Keep original single-tap combo 5591 tap_2_action=notify_context, 5592 ), 5593 5594 C("Shift-Alt-RC-h"): isMultiTap( 5595 tap_1_action=C("Shift-Alt-RC-h"), # Keep original single-tap combo 5596 tap_2_action=notify_context, 5597 tap_3_action=lambda: print("\nTriple tap!\n"), # Shows in terminal 5598 ), 5599 5600 C("Shift-Alt-RC-t"): isMultiTap( 5601 tap_1_action=C("C-n"), # Test single-tap by opening new window 5602 tap_2_action=macro_tester, # Types out a long test macro text 5603 tap_3_action=[ 5604 ST("You tapped Shift-Alt-C-t 3 times!!!"), 5605 C("Enter"), C("Enter")], 5606 tap_4_action=[ 5607 ST("You tapped Shift-Alt-C-t 4 times!!!!"), 5608 C("Enter"), C("Enter")], 5609 tap_5_action=[ 5610 ST("You tapped Shift-Alt-C-t 5 times!!!!!"), 5611 C("Enter"), C("Enter")], 5612 ), 5613 5614 }, when = lambda ctx: ctx is ctx) 5615 5616 5617 # keymap("Diagnostics (isDoubleTap)", { 5618 # C("Shift-Alt-RC-i"): isDoubleTap(notify_context), # Diagnostic dialog (primary) 5619 # C("Shift-Alt-RC-h"): isDoubleTap(notify_context), # Diagnostic dialog (alternate) 5620 # C("Shift-Alt-RC-t"): isDoubleTap(macro_tester), # Type out test macro 5621 # }, when = lambda ctx: ctx is ctx )