{"id":17962391,"url":"https://github.com/grafov/shift-shift","last_synced_at":"2025-03-25T04:31:57.783Z","repository":{"id":85032819,"uuid":"14120609","full_name":"grafov/shift-shift","owner":"grafov","description":"Xorg/Wayland keyboard layout switcher.","archived":false,"fork":false,"pushed_at":"2023-11-04T13:56:56.000Z","size":56,"stargazers_count":15,"open_issues_count":0,"forks_count":5,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-06-21T03:34:42.508Z","etag":null,"topics":["ergonomics","evdev","keyboard","layout-switcher","river","sway","utility","wayland","x11","xorg"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/grafov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-11-04T19:05:35.000Z","updated_at":"2024-05-06T02:44:38.000Z","dependencies_parsed_at":null,"dependency_job_id":"ec76940d-afe2-4207-8a76-85aa2c549e88","html_url":"https://github.com/grafov/shift-shift","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grafov%2Fshift-shift","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grafov%2Fshift-shift/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grafov%2Fshift-shift/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grafov%2Fshift-shift/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/grafov","download_url":"https://codeload.github.com/grafov/shift-shift/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222035692,"owners_count":16919925,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ergonomics","evdev","keyboard","layout-switcher","river","sway","utility","wayland","x11","xorg"],"created_at":"2024-10-29T11:19:14.470Z","updated_at":"2025-03-25T04:31:57.770Z","avatar_url":"https://github.com/grafov.png","language":"Go","readme":"## What is it and why?\n\n*Do you want to use Shift/Ctrl/Alt as modifiers while also switching language\nlayouts? This tool is for you then.*\n\nA language layout switcher for Xorg and Wayland (including Sway and Hyprland)\nthat utilizes modifier keys (such as Shift and Control) as layout switchers.\nThis setup enables the same key to function both as a modifier and a layout\nswitcher without conflicts.\n\nThe utility incorporates two key concepts:\n\n1. Use a key as a modifier when held and as a layout switcher when tapped.\n2. Cyclic switching with a single key is inefficient; dedicated keys for each\n   language group are more effective.\n\nThis approach may not be necessary when using multiple languages simultaneously,\nbut it is beneficial for most cases involving 2-3 languages. Frequent keyboard\nlayout switching, common among non-English speakers, is easier with dedicated\nkeys than with key combinations. For example, old Soviet computers featured a\ndedicated RUS/LAT key to toggle between Latin and Cyrillic. Some computers even\noffered two separate keys: RUS and LAT!\n\nUnfortunately, modern English-oriented keyboards lack dedicated layout-switching\nkeys. Modifier keys are typically used only in combination with other keys. This\nutility provides a solution: these keys can perform their original functions\nwhile also being used to switch layouts.\n\nBy default, the Left Shift key switches to layout 1 and the Right Shift key to\nlayout 2. You can customize this behavior using command-line options. The utility\nsupports up to 4 groups.\n\nAdditionally, you can treat any input device as a keyboard using the `-match`\noption, enabling simultaneous layout switching across multiple keyboards. The\nutility listens to all connected devices.\n\nThe program listens to keypress events from the kernel (via evdev) and sends\nthem to Xorg or your window manager. Different WMs have their own methods for\nkeyboard switching, especially on Wayland. I have added support for Wayland\nwindow managers I have used extensively. See the examples for all variants.\n\n## Install\n\n### Go way\n\nThis is a Go program. You need a Go environment to build it from source.\n\n\tgo get github.com/grafov/shift-shift@latest\n\n`xlib-devel` lib should be installed. Check your distro.\n\n### Get sources\n\n1. Get repository and cd to it.\n2. `make build`\n\nPrerequisites are the same: `xlib-devel` lib should be installed. Check your distro.\n\n## Usage\n\n```\n$ Usage of ./shift-shift:\n  -1 string\n    \tkey used for switching to 1st xkb group (default \"LEFTSHIFT\")\n  -2 string\n    \tkey used for switching to 2nd xkb group (default \"RIGHTSHIFT\")\n  -3 string\n    \tkey used for switching to 3rd xkb group\n  -4 string\n    \tkey used for switching to 4th xkb group\n  -double-keystroke\n    \trequire pressing the same key twice to switch the layout\n  -double-keystroke-timeout int\n    \tsecond keystroke timeout in milliseconds (default 500)\n  -list\n    \tlist all devices that found by evdev (not only keyboards)\n  -list-hypr\n    \tlist all keyboards recognized by Hyprland\n  -list-sway\n    \tlist all devices recognized by Sway (not only keyboards)\n  -match string\n    \tregexp used to match input keyboard device as it listed by evdev (default \"keyboard\")\n  -match-wm string\n    \toptional regexp used to match device in WM, if not set evdev regexp used (default \"keyboard\")\n  -print\n    \tprint pressed keys for debug (verbose output)\n  -quiet\n    \tbe silent\n  -scan-once\n    \tscan for keyboards only at startup (less power consumption)\n  -switcher string\n    \tselect method of switching (possible values are \"auto\", \"xkb\", \"sway\", \"hypr\") (default \"auto\")\n```\n\n## Configuration\n\n### 1. Match keyboard in evdev output\nFirst step is common for all environments. Just try to find your keyboard device. It may look like this:\n\n```\n$ shift-shift -list\n\n/dev/input/event3 PC Speaker\n/dev/input/event4 HDA ATI HDMI HDMI/DP,pcm=3\n/dev/input/event6 HDA ATI HDMI HDMI/DP,pcm=8\n/dev/input/event8 HD-Audio Generic Rear Mic\n/dev/input/event12 HD-Audio Generic Front Headphone\n/dev/input/event20 ZSA Technology Labs ErgoDox EZ System Control\n/dev/input/event21 ZSA Technology Labs ErgoDox EZ Consumer Control\n/dev/input/event23 VIRPIL Controls/20210102 R-VPC Stick MT-50\n/dev/input/event7 HDA ATI HDMI HDMI/DP,pcm=9\n/dev/input/event18 ZSA Technology Labs ErgoDox EZ\n/dev/input/event22 ZSA Technology Labs ErgoDox EZ Keyboard\n/dev/input/event24 ATMEL/VIRPIL/190930 BRD Rudder V3\n/dev/input/event5 HDA ATI HDMI HDMI/DP,pcm=7\n/dev/input/event17 Kensington      Kensington Expert Mouse\n/dev/input/event19 ZSA Technology Labs ErgoDox EZ\n...\n```\n\nAnd consists of any devices recognized by kernel on your machine. Just select any that looks like a keyboard :)\n\n**Note:** you need setup proper access for reading `/dev/input/*`\ndevices. As a fallback try to run with `sudo` or similar tool.\n\nYou should add it `-match` key. You are free to use regular expression or just a substring for matching. Check [The\nsyntax of regexps](https://pkg.go.dev/regexp/syntax) for reference.\n\n```\n-match=\"^ZSA.*Keyboard$\"\n```\n\nHint. You could match several keyboards at once. They will used when connected:\n\n```\n$ shift-shift -match \"Ergodox|Ergohaven\"\n```\n\nWell, we've matched device with evdev. \n\n### 2. Match switcher\n\nNext step is match it to a switcher. It\ndepends of your environment, see variants below.\n\n#### 2.1 WM or DE under XOrg\n\n```\n$ shift-shift -match=\"^ZSA.*Keyboard$\" -switcher=xkb\n```\n\nAnd it will run switcher especially for XOrg.\n\n#### 2.2 Sway WM\n\nIn most of cases you should just add \"-switcher=sway\" to command line and it will works.\n\n``` shell\n$ shift-shift -match=\"^ZSA.*Keyboard$\" -switcher=sway\n```\n\nYou could list keyboards as they seen by Sway:\n\n``` shell\n$ shift-shift -list-sway\n\n  {\n    \"identifier\": \"12951:18804:ZSA_Technology_Labs_ErgoDox_EZ_Keyboard\",\n    \"name\": \"ZSA Technology Labs ErgoDox EZ Keyboard\",\n    \"type\": \"keyboard\",\n    \"repeat_delay\": 350,\n    \"repeat_rate\": 50,\n    \"xkb_layout_names\": [\n      \"English (US)\",\n      \"Russian (typewriter)\"\n    ],\n    \"xkb_active_layout_index\": 0,\n    \"xkb_active_layout_name\": \"English (US)\",\n    \"libinput\": {\n      \"send_events\": \"enabled\"\n    },\n    \"vendor\": 12951,\n    \"product\": 18804\n  },\n  {\n    \"identifier\": \"12951:18804:ZSA_Technology_Labs_ErgoDox_EZ_Consumer_Control\",\n    \"name\": \"ZSA Technology Labs ErgoDox EZ Consumer Control\",\n...\n```\n\nIt will display your list of devices (but not only keyboards). \n\nSometimes Sway may name the keyboard differently. In such cases, you can match\nthe keyboard using a regular expression similar to the evdev example above.\nThen, add the result to the \"-match-wm\" key:\n\n```\n$ shift-shift -match=\"^ZSA.*Keyboard$\" -switcher=sway -match-wm=\"^ZSA.*Keyboard$\"\n```\n\nWhen \"-match-wm\" omited its value set to value of \"-match\".\n\n#### 2.3 Hyprland WM\n\nIn most of cases you should just add \"-switcher=hypr\" to command line and it will works.\n\n``` shell\n$ shift-shift -match=\"(?i)ergodox\" -switcher=hypr\n```\n\nYou could list keyboards as they seen by Hyprland:\n\n``` shell\n$ shift-shift -list-hypr\n\nmodel: name:zsa-technology-labs-ergodox-ez layout:us,ru options:caps:none,misc:typo,lv3:capslock_switch keymap:English (US)\n```\n\nNaming in Hyprland differs from evdev. You can match the keyboard using a\nregular expression, similar to evdev as described above. Then, add the result to\nthe \"-match-wm\" key:\n\n``` shell\n$ shift-shift -match=\"^ZSA.*Keyboard$\" -switcher=hypr -match-wm=\"^zsa-technology-labs-ergodox-ez$\"\n```\n\nWhen \"-match-wm\" omited its value set to value of \"-match\".\n\n#### 3. Print for detected keyboards\n\nFor debugging you could run with \"-print\" option. For example the output for Hyprland config above:\n\n```\n2025/01/30 01:12:28 use Hyprland switcher\n2025/01/30 01:12:28 Hyprland keyboard matched zsa-technology-labs-ergodox-ez\n2025/01/30 01:12:29 evdev keyboard found at /dev/input/event21: ZSA Technology Labs ErgoDox EZ Consumer Control\n2025/01/30 01:12:29 evdev keyboard found at /dev/input/event22: ZSA Technology Labs ErgoDox EZ Keyboard\n\n```\n\n#### 4. Keys for switching\n\nBy default, the left Shift key is used for layout 0, and the right Shift key for\nlayout 1. You can use up to four layouts, naming them with the keys \"-1\" through\n\"-4\". In the example below, the Ctrls key is used:\n\n``` shell\n$ shift-shift -match=\"^ZSA.*Keyboard$\" -switcher=hypr -match-wm=\"^zsa-technology-labs-ergodox-ez$\" -1 LEFT_CTRL -2 RIGHT_CTRL -print\n```\n\nThe output with \"-print\" when you press any of switch keys:\n\n```\n2025/01/30 01:12:29 ZSA Technology Labs ErgoDox EZ type:1 code:90 pressed\n2025/01/30 01:12:29 ZSA Technology Labs ErgoDox EZ type:1 code:90 released\n2025/01/30 01:12:29 ZSA Technology Labs ErgoDox EZ switches group to 1\n2025/01/30 01:12:29 switch hyprland kbd \"zsa-technology-labs-ergodox-ez\" to group 0\n2025/01/30 01:12:30 ZSA Technology Labs ErgoDox EZ type:1 code:91 pressed\n2025/01/30 01:12:30 ZSA Technology Labs ErgoDox EZ type:1 code:91 released\n2025/01/30 01:12:30 ZSA Technology Labs ErgoDox EZ switches group to 2\n```\n\nFor reference full list of key names recognized by evdev:\n\n``` shell\n$ cat /usr/include/linux/input-event-codes.h\n```\n\n#### 5. Final setup\n\nJust remove \"-print\" once everything is working. Then, add the final command to\nyour window manager's autostart.\n\n$ shift-shift -match=\"^ZSA.*Keyboard$\" -switcher=hypr -match-wm=\"^zsa-technology-labs-ergodox-ez$\" -1 LEFT_CTRL -2 RIGHT_CTRL -print\n\n## Thanks\n\nThanks to people who contributed bugreports and improvements for\n`shift-shift`, especially to\n[@kovetsiy](https://github.com/kovetskiy),\n[@ArtemT](https://github.com/ArtemT),\n[@seletskiy](https://github.com/seletskiy).\n\nIdea of Sway integration was inspired by Python code of\nhttps://github.com/nmukhachev/sway-xkb-switcher project.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrafov%2Fshift-shift","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgrafov%2Fshift-shift","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrafov%2Fshift-shift/lists"}