{"id":18391308,"url":"https://github.com/thblt/klmc","last_synced_at":"2025-04-12T09:39:05.156Z","repository":{"id":68387326,"uuid":"307981696","full_name":"thblt/klmc","owner":"thblt","description":"A compiler for keyboard layouts","archived":false,"fork":false,"pushed_at":"2021-10-30T13:35:23.000Z","size":27,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-16T01:25:27.369Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Haskell","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/thblt.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2020-10-28T10:32:52.000Z","updated_at":"2021-11-19T12:05:43.000Z","dependencies_parsed_at":null,"dependency_job_id":"dde873f9-0aa0-46a9-8f94-47282a63e2ce","html_url":"https://github.com/thblt/klmc","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thblt%2Fklmc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thblt%2Fklmc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thblt%2Fklmc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thblt%2Fklmc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thblt","download_url":"https://codeload.github.com/thblt/klmc/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248548349,"owners_count":21122681,"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":[],"created_at":"2024-11-06T01:51:27.082Z","updated_at":"2025-04-12T09:39:05.124Z","avatar_url":"https://github.com/thblt.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"klmc\n====\n\n`klmc` is a compiler for keyboard layouts.  Layouts are Haskell\nprograms that compile to XKB layout and Compose file (GNU Linux/BSD),\nMicrosoft Windows C source and MacOS' `keylayout` files.  As these are\nprobably the hardest formats to implement, other targets should be\neasy to add.\n\nLayout format\n-------------\n\nInternally, a layout is a\n\n``` haskell\nnewtype Layout = Map State (Map Key (Map Layer Effect))\n```\n\nThat is, a map of `State` of maps of keys to maps associating `Layer`s\nto `Effect`s.  Internally, the layout is a sort of state machine,\nwhere states are activated by dead keys.  Let's go through this right\nto left.\n\n - An `Effect` is what a key *does*.  There are three main effects:\n   emit a character, like \"K\", \"a\", \"1\" and so on; emit a control\n   character, like an arrow, the backspace key, or return, or enter a\n   state, that is, modify the mapping of further key presses.  States\n   are essentially used to describe dead keys.\n\n - A `Layer` is an abstraction of the various shifted, capslocked,\n   variants of a layout.  Layers are described as both modifier states\n   and a number.  Usually, the principal use of layers is to describe\n   shift/altgr variants of a layout, but in `klmc` layers (for targets\n   that support it) can be defined for any combination of modifiers.\n\n - A `State` is activated by a dead key and modifies the full layout\n   accordingly, on all layers.  For example, the dead acute accent key\n   will enter a state where the letter E emits \"é\" in base layer, \"É\"\n   in shitfed/caps layer, and so on.\n\n   States may feel like an unusual approach to dead keys.  Indeed,\n   most OS don't actually treat dead keys as layout transformers, but\n   as character combinations (eg, XKB uses a character map for its\n   dead keys, not a key map).  The reason we use states is that they\n   match the very powerful representation macOS uses, so we can expose\n   the full power of macOS keylayout format, with a simple degradation\n   mechanism for more limited targets.\n\n   Notice, though, that you actually don't need to be explicit about\n   the obvious combinations, like dead accents: klmc is smart enough\n   to combine a dead acute accent and a letter for you.  States are\n   only really useful for more complex dead keys, like a \"dead Greek\"\n   key that would combine like `dead_greek + a = α`.\n\nLimitations of exporters and degradation strategies\n---------------------------------------------------\n\nNot every target platform supports the full power of the klmc layout\nrepresentation.  This is something you should take into consideration\nwhen designing layouts.  The following table summarizes these features\nand each target's limitations in their regard.\n\n 1. **States**\n   - **XKB** doesn't support states, which are thus degraded to\n     character combinations. This makes it impossible to have the same\n     character on two keys at base state, but make them emit different\n     characters on a dead key state.\n   - **MacOS** fully supports states.\n   - **Windows** support probably the same as XKB.\n 2. **Unlimited layers**\n   - **XKB** has up to eight levels, including shifted levels, maybe\n     more, I need to check.  That means three AltGr-ish keys.\n   - **MacOS** supports as many layers as can be expressed with its\n     standard modifiers.\n   - **Windows** TBD.\n 3. **Layers on special modifiers**\n   - **XKB** doesn't support that, and layers that use Ctrl and other\n     control modifiers are dropped at compilation.  Or [maybe it\n     does](https://unix.stackexchange.com/questions/609605/xkb-transparently-map-modifier-level/610330#610330).\n   - **MacOS** fully supports it.  If you have a key that's \"é\" in the\n     base layer, you can bind it to \"c\" in the \"command key pressed\"\n     layer.  In this case, Command-é actually emits Command-C, the\n     copy shortcut (but *not* the letter C).\n   - **Windows** has an alternative mechanism called *Virtual keys*.\n     Applications actually bind to virtual keys, not actual letters.\n     In the above example, the same key would be bound to é and `vk_c`\n     (the virtual C).  Klmc handles this by collapsing all the\n     modifier layers into one, and converting it into Windows virtual keys.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthblt%2Fklmc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthblt%2Fklmc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthblt%2Fklmc/lists"}