{"id":13870197,"url":"https://github.com/fabiospampinato/shosho","last_synced_at":"2025-08-26T00:09:49.826Z","repository":{"id":163770359,"uuid":"639195404","full_name":"fabiospampinato/shosho","owner":"fabiospampinato","description":"A modern and powerful shortcuts management library.","archived":false,"fork":false,"pushed_at":"2023-10-16T08:41:21.000Z","size":78,"stargazers_count":110,"open_issues_count":1,"forks_count":4,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-08-16T16:47:22.422Z","etag":null,"topics":["library","management","modern","shortcuts"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fabiospampinato.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}},"created_at":"2023-05-11T01:06:43.000Z","updated_at":"2025-06-17T16:13:21.000Z","dependencies_parsed_at":null,"dependency_job_id":"ebd0f1d8-83c6-44c7-8d4e-e7ac07afc66a","html_url":"https://github.com/fabiospampinato/shosho","commit_stats":null,"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"purl":"pkg:github/fabiospampinato/shosho","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabiospampinato%2Fshosho","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabiospampinato%2Fshosho/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabiospampinato%2Fshosho/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabiospampinato%2Fshosho/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fabiospampinato","download_url":"https://codeload.github.com/fabiospampinato/shosho/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fabiospampinato%2Fshosho/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272150009,"owners_count":24882067,"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","status":"online","status_checked_at":"2025-08-25T02:00:12.092Z","response_time":1107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["library","management","modern","shortcuts"],"created_at":"2024-08-05T20:01:33.629Z","updated_at":"2025-08-26T00:09:49.802Z","avatar_url":"https://github.com/fabiospampinato.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# ShoSho\n\nA modern and powerful shortcuts management library.\n\n## Features\n\n- It is largely built on top of [`KeyboardEvent#code`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code) and [`KeyboardEvent#key`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key), for great compatibility across browsers, platforms, languages and layouts.\n- It is _fast_. Almost always this library will do `O(1)` registrations, `O(1)` disposals, `O(1)` lookups and `O(1)` resetting.\n- It supports ~100 keyboard keys, including function keys and numpad keys.\n- It supports mouse buttons too, which can be mixed in shortcts with keyboard keys, like `Ctrl+ClickLeft`.\n- It supports simple shortcuts, like `Ctrl+F`, and shortcuts sequences, like `Ctrl+K Ctrl+F`.\n- It supports detecting which exact modifier key was pressed, like `ControlLeft` or `ControlRight`.\n- It supports common aliases for keys, like `Alt`/`Option`, or `Esc`/`Escape`.\n- It supports some character-based shortcuts, like `Shift+#`, rather than the equivalent key-based shortcut, which might be `Shift+3`.\n- It supports automatically using `Command` under macOS and `Control` elsewhere, by writing for example `CommandOrControl+F`.\n- It supports multi-trigger shortcuts, like `Up+Right` or `Down+Left`, except when the `Meta` key is pressed, which is buggy in browsers.\n- It supports Konami codes, a.k.a. cheatcode shortcuts, like `Up Up Down Down Left Right Left Right B A`.\n- It supports formatting shortcuts in 10 different styles, including formatting for [Electron](https://www.electronjs.org) and as symbols for hints/tooltips.\n- It supports recording a shortcut, for customizing shortcuts easily.\n\n## Shortcut Syntax\n\nThe following keys can be used when defining a shortcut:\n\n- **Modifiers**: \u003ckbd\u003eAlt\u003c/kbd\u003e/\u003ckbd\u003eOption\u003c/kbd\u003e, \u003ckbd\u003eCmd\u003c/kbd\u003e/\u003ckbd\u003eCommand\u003c/kbd\u003e/\u003ckbd\u003eMeta\u003c/kbd\u003e, \u003ckbd\u003eCtrl\u003c/kbd\u003e/\u003ckbd\u003eControl\u003c/kbd\u003e, \u003ckbd\u003eShift\u003c/kbd\u003e, \u003ckbd\u003eCmdOrCtrl\u003c/kbd\u003e/\u003ckbd\u003eCommandOrControl\u003c/kbd\u003e.\n- **Left modifiers**: \u003ckbd\u003eAltLeft\u003c/kbd\u003e/\u003ckbd\u003eOptionLeft\u003c/kbd\u003e, \u003ckbd\u003eCmdLeft\u003c/kbd\u003e/\u003ckbd\u003eCommandLeft\u003c/kbd\u003e/\u003ckbd\u003eMetaLeft\u003c/kbd\u003e, \u003ckbd\u003eCtrlLeft\u003c/kbd\u003e/\u003ckbd\u003eControLeft\u003c/kbd\u003e, \u003ckbd\u003eCmdLeftOrCtrlLeft\u003c/kbd\u003e/\u003ckbd\u003eCommandLeftOrControlLeft\u003c/kbd\u003e.\n- **Right modifiers**: \u003ckbd\u003eAltRight\u003c/kbd\u003e/\u003ckbd\u003eOptionRight\u003c/kbd\u003e, \u003ckbd\u003eCmdRight\u003c/kbd\u003e/\u003ckbd\u003eCommandRight\u003c/kbd\u003e/\u003ckbd\u003eMetaRight\u003c/kbd\u003e, \u003ckbd\u003eCtrlRight\u003c/kbd\u003e/\u003ckbd\u003eControRight\u003c/kbd\u003e, \u003ckbd\u003eCmdRightOrCtrlRight\u003c/kbd\u003e/\u003ckbd\u003eCommandRightOrControlRight\u003c/kbd\u003e.\n- **Digits**: \u003ckbd\u003e0-9\u003c/kbd\u003e.\n- **Alphabet letters**: \u003ckbd\u003eA-Z\u003c/kbd\u003e.\n- **Function keys**: \u003ckbd\u003eF1-F24\u003c/kbd\u003e.\n- **Numpad digits**: \u003ckbd\u003eNumpad0-Numpad9\u003c/kbd\u003e.\n- **Numpad operators**: \u003ckbd\u003eNumpadAdd\u003c/kbd\u003e, \u003ckbd\u003eNumpadComma\u003c/kbd\u003e, \u003ckbd\u003eNumpadDecimal\u003c/kbd\u003e, \u003ckbd\u003eNumpadDivide\u003c/kbd\u003e, \u003ckbd\u003eNumpadEnter\u003c/kbd\u003e, \u003ckbd\u003eNumpadEqual\u003c/kbd\u003e, \u003ckbd\u003eNumpadMultiply\u003c/kbd\u003e, \u003ckbd\u003eNumpadSubtract\u003c/kbd\u003e.\n- **Special keys**: \u003ckbd\u003eBackspace\u003c/kbd\u003e, \u003ckbd\u003eCapslock\u003c/kbd\u003e, \u003ckbd\u003eDel\u003c/kbd\u003e/\u003ckbd\u003eDelete\u003c/kbd\u003e, \u003ckbd\u003eDown\u003c/kbd\u003e, \u003ckbd\u003eEnd\u003c/kbd\u003e, \u003ckbd\u003eEnter\u003c/kbd\u003e/\u003ckbd\u003eReturn\u003c/kbd\u003e, \u003ckbd\u003eEsc\u003c/kbd\u003e/\u003ckbd\u003eEscape\u003c/kbd\u003e, \u003ckbd\u003eHome\u003c/kbd\u003e, \u003ckbd\u003eInsert\u003c/kbd\u003e, \u003ckbd\u003eLeft\u003c/kbd\u003e, \u003ckbd\u003ePageDown\u003c/kbd\u003e, \u003ckbd\u003ePageUp\u003c/kbd\u003e, \u003ckbd\u003eRight\u003c/kbd\u003e, \u003ckbd\u003eSpace\u003c/kbd\u003e/\u003ckbd\u003eSpacebar\u003c/kbd\u003e, \u003ckbd\u003eTab\u003c/kbd\u003e, \u003ckbd\u003eUp\u003c/kbd\u003e, \u003ckbd\u003eNumLock\u003c/kbd\u003e, \u003ckbd\u003eScrollLock\u003c/kbd\u003e.\n- **Punctuation keys**: \u003ckbd\u003e!\u003c/kbd\u003e, \u003ckbd\u003e@\u003c/kbd\u003e, \u003ckbd\u003e#\u003c/kbd\u003e, \u003ckbd\u003e$\u003c/kbd\u003e, \u003ckbd\u003e%\u003c/kbd\u003e, \u003ckbd\u003e^\u003c/kbd\u003e, \u003ckbd\u003e\u0026\u003c/kbd\u003e, \u003ckbd\u003e*\u003c/kbd\u003e, \u003ckbd\u003e(  \u003c/kbd\u003e, \u003ckbd\u003e)\u003c/kbd\u003e, \u003ckbd\u003e_\u003c/kbd\u003e, \u003ckbd\u003e{\u003c/kbd\u003e, \u003ckbd\u003e}\u003c/kbd\u003e, \u003ckbd\u003e|\u003c/kbd\u003e, \u003ckbd\u003e:\u003c/kbd\u003e, \u003ckbd\u003e\"\u003c/kbd\u003e, \u003ckbd\u003e\u003c\u003c/kbd\u003e, \u003ckbd\u003e\u003e\u003c/kbd\u003e, \u003ckbd\u003e?\u003c/kbd\u003e, \u003ckbd\u003e~\u003c/kbd\u003e.\n- **Mouse buttons**: \u003ckbd\u003eClickLeft\u003c/kbd\u003e/\u003ckbd\u003eMouseLeft\u003c/kbd\u003e, \u003ckbd\u003eClickMiddle\u003c/kbd\u003e/\u003ckbd\u003eMouseMiddle\u003c/kbd\u003e, \u003ckbd\u003eClickRight\u003c/kbd\u003e/\u003ckbd\u003eMouseRight\u003c/kbd\u003e, \u003ckbd\u003eMouse0-Mouse9\u003c/kbd\u003e.\n\nPlease note that:\n\n- ℹ️ Other keys are not supported.\n- ℹ️ Shortcuts are case insensitive.\n- ℹ️ Keys in a single shortcut must be joined by a plus sign (e.g. \u003ckbd\u003eCtrl+A\u003c/kbd\u003e).\n- ℹ️ Sequences of shortcuts must be joined by a space (e.g. \u003ckbd\u003eCtrl+K Ctrl+B\u003c/kbd\u003e).\n- ⚠️ Punctuation keys should be avoided when possible, especially when used in combination with Shift/Alt, as they may lead to somewhat different results across different layouts.\n\n## Install\n\n```sh\nnpm install --save shosho\n```\n\n## Usage\n\n```ts\nimport ShoSho from 'shosho';\n\n// Let's create a shortcuts manager\n\nconst shortcuts = new ShoSho ({\n  capture: true,\n  target: document,\n  shouldHandleEvent ( event ) {\n    // Return \"true\" if this event should be handled\n    return true;\n  }\n});\n\n// Let's register some shortcuts. Shortcuts handlers must return \"true\" if they actually handled the shortcut\n\nshortcuts.register ( 'A', event =\u003e { // Single-key shortcut\n  console.log ( 'Handling A' );\n  return true;\n});\n\nshortcuts.register ( 'Ctrl+F', event =\u003e { // Simple modifier+trigger shortcut\n  console.log ( 'Handling Ctrl+F' );\n  return true;\n});\n\nshortcuts.register ( 'Ctrl+K Ctrl+F', event =\u003e { // Advanced sequence shortcut\n  console.log ( 'Handling Ctrl+K Ctrl+F' );\n  return true;\n});\n\nshortcuts.register ( 'ClickMiddle', event =\u003e { // Single-mouse-button shortcut\n  console.log ( 'Skipping ClickMiddle actually' );\n  return false; // Returning \"false\" tells the library to try other potential handlers for this shortcut\n});\n\nshortcuts.register ( 'CmdOrCtrl+ClickRight', event =\u003e { // Advanced mixed keyboard/mouse shortcut\n  console.log ( 'Handling CmdOrCtrl+ClickRight' );\n  return true;\n});\n\n// Let's register a Konami code, which basically is not affected by other registered shortcuts\n\nshortcuts.register ( 'Up Up Down Down Left Right Left Right B A', event =\u003e { // A Konami code\n  console.log ( 'Secret shortcut triggered 🚀' );\n}, { konami: true } ); // Registering it as a Konami code\n\n// Let's register a shortcut but then dispose of it\n\nconst dispose = shortcuts.register ( 'Shift+1', event =\u003e {\n  console.log ( 'Handling Shift+1' );\n  return true;\n});\n\ndispose (); // Unregistering that shortcut with that handler\n\n// Let's trigger a shortcut programmatically, perhaps for debugging purposes\n\nconst handled = shortcuts.trigger ( 'Ctrl+F' );\n\nconsole.log ( handled ); // =\u003e true\n\n// Let's actually start listening for shortcuts\n\nshortcuts.start ();\n\n// Let's stop listening for shortcuts\n\nshortcuts.stop ();\n\n// Let's dispose of all registered shortcuts\n\nshortcuts.reset ();\n\n// Let's format a shortcut, with every supported format\n\nShoSho.format ( 'ControlLeft+A', 'electron' ); // =\u003e 'Ctrl+A'\nShoSho.format ( 'ControlLeft+A', 'symbols' ); // =\u003e '⌃A'\nShoSho.format ( 'ControlLeft+A', 'long-flexible-directional' ); // =\u003e 'CommandOrControlLeft+A'\nShoSho.format ( 'ControlLeft+A', 'long-flexible-nondirectional' ); // =\u003e 'CommandOrControl+A'\nShoSho.format ( 'ControlLeft+A', 'long-inflexible-directional' ); // =\u003e 'ControlLeft+A'\nShoSho.format ( 'ControlLeft+A', 'long-inflexible-nondirectional' ); // =\u003e 'Control+A'\nShoSho.format ( 'ControlLeft+A', 'short-flexible-directional' ); // =\u003e 'CmdOrCtrlLeft+A'\nShoSho.format ( 'ControlLeft+A', 'short-flexible-nondirectional' ); // =\u003e 'CmdOrCtrl+A'\nShoSho.format ( 'ControlLeft+A', 'short-inflexible-directional' ); // =\u003e 'CtrlLeft+A'\nShoSho.format ( 'ControlLeft+A', 'short-inflexible-nondirectional' ); // =\u003e 'Ctrl+A'\n\n// Let's check if something is a valid shortcut\n\nShoSho.isShortcut ( 'Control+A' ); // =\u003e true\nShoSho.isShortcut ( 'ControlA' ); // =\u003e false\n\n// Let's record a shortcut, which will require manual trimming and formatting\n\nconst dispose = ShoSho.record ( shortcut =\u003e {\n\n  console.log ( shortcut ); // =\u003e It could be 'A', 'CtrlLeft+A', 'CtrlLeft+A CtrlRight', 'CtrlLeft+A CtrlRight+B' and so on...\n\n  const trimmed = shortcut.replace ( /(^.*?)((?:Control(?:Left|Right)\\+K )*\\S+$)/, '$2' ); // Allowing only 'ControlLeft+K' and 'ControlRight+K' to not be the last shortcut in the sequence\n  const formatted = ShoSho.format ( trimmed, 'long-inflexible-nondirectional' ); // Ensuring the final shortcut is formatted exactly how we want it\n\n  console.log ( formatted ); // =\u003e It could be 'K', 'CtrlLeft+K', 'CtrlLeft+K CtrlRight', 'Ctrlleft+K CtrlRight+A' and so on...\n\n});\n\n// Let's stop recording\n\ndispose ();\n```\n\n## License\n\nMIT © Fabio Spampinato\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffabiospampinato%2Fshosho","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffabiospampinato%2Fshosho","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffabiospampinato%2Fshosho/lists"}