{"id":3275,"date":"2026-08-20T13:47:42","date_gmt":"2026-08-20T04:47:42","guid":{"rendered":"https:\/\/mindtech.jp\/?p=3275"},"modified":"2026-08-20T13:52:15","modified_gmt":"2026-08-20T04:52:15","slug":"post-3275","status":"publish","type":"post","link":"https:\/\/mindtech.jp\/?p=3275","title":{"rendered":"Fakeymacs\u7121\u304dKeyhac2\u306econfig.py\u306e\u8a2d\u5b9a\u306e\u4f8b"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">\u65e5\u5e38\u7684\u306a\u30d5\u30a1\u30a4\u30eb\u306e\u30b3\u30d4\u30da\u3082Ctrl+Y \u3067\u3084\u3063\u3066\u3057\u307e\u3046Emacs\u306b\u624b\u7656\u3092\u30ab\u30b9\u30bf\u30de\u30a4\u30ba\u3055\u308c\u305f\u4eba\u9593\u3068\u3057\u3066\u306f\u3001keyhac + Fakeymacs \u306f\u975e\u5e38\u306b\u4fbf\u5229\u306a\u30c4\u30fc\u30eb\u3067\u3057\u305f\u3002\u65b0\u3057\u3044PC\u3092\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u3059\u308b\u969b\u306b\u6539\u3081\u3066keyhac\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3092\u3057\u3088\u3046\u3068\u3059\u308c\u3070\u3001\u306a\u3093\u3068Keyhac2\u304c\u30ea\u30ea\u30fc\u30b9\u3055\u308c\u3066\u3044\u3066\u3001Microsoft Store\u30a2\u30d7\u30ea\u3068\u3057\u3066\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3067\u304d\u308b\u3088\u3046\u306b\u306a\u3063\u305f\u3068\u306a\u3002\u4f7f\u3046\u5074\u3068\u3057\u3066\u306f\u5b89\u5fc3\uff06\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u306b\u3082\u4fbf\u5229\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/crftwr.github.io\/keyhac\">https:\/\/crftwr.github.io\/keyhac<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u305d\u3046\u306a\u308b\u3068\u3001\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u306eFakeymacs \u3067\u3059\u304c\u3001\u3053\u3061\u3089\u306f\u307e\u3060Keyhac2\u306b\u306f\u5bfe\u5fdc\u3057\u3066\u3044\u306a\u3044\u3002\u3068\u3044\u3046\u304bAPI\u304c\u5909\u308f\u3063\u3061\u3083\u3063\u305f\u306e\u3067\u3001\u304a\u305d\u3089\u304f\u306f\u5225\u306b\u4f5c\u308a\u76f4\u3059\u5fc5\u8981\u304c\u51fa\u3066\u304d\u305d\u3046\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/smzht\/fakeymacs\">https:\/\/github.com\/smzht\/fakeymacs<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u7121\u3044\u3082\u306e\u306f\u4f5c\u308b\u3057\u304b\u306a\u3044\u306e\u3067\u3001\u3068\u308a\u3042\u3048\u305a\u5fc5\u8981\u6700\u4f4e\u9650\u306e\u5206\u3092\u4f5c\u3063\u3066\u307f\u305f\u306e\u3067\u5171\u6709\u3057\u307e\u3059\u3002\u7d30\u304b\u3044\u4f7f\u3044\u5fc3\u5730\u306e\u90e8\u5206\u306b\u3064\u3044\u3066\u306f\u201dFakeymacs-style key bindings\u201d\u4ee5\u4e0b\u306e\u90e8\u5206\u3092\u3088\u3057\u306a\u306b\u8abf\u6574\u3057\u3066\u307f\u3066\u304f\u3060\u3055\u3044\u3002<br>Win\u3067\u3057\u304b\u8a66\u3057\u3066\u3044\u306a\u3044\u306e\u3067Mac\u3067\u5909\u3060\u3063\u305f\u3089\u30b4\u30e1\u30f3\u3067\u3059\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><br>\u30af\u30ea\u30c3\u30d7\u30dc\u30fc\u30c9\u5c65\u6b74\uff06\u5b9a\u578b\u6587\u306b\u3064\u3044\u3066\u306f\u3001Alt+Y \u306b\u30d0\u30a4\u30f3\u30c9\u3057\u3066\u307e\u3059\u3002\u30a2\u30d7\u30ea\u30e9\u30f3\u30c1\u30e3\u30fc\u306fAlt+l \u306b\u5272\u308a\u5f53\u3066\u3066\u307e\u3059\u304c\u3001\u9069\u5f53\u306b\u5909\u3048\u3066\u4f7f\u3063\u3066\u304f\u3060\u3055\u3044\u3002\u30af\u30ea\u30c3\u30d7\u30dc\u30fc\u30c9\u5c65\u6b74\u306eUI\u306fkeihac2\u3067\u7d50\u69cb\u5909\u308f\u3063\u3066\u307e\u3059\u306e\u3067\u3001\u307e\u3042\u4f55\u3068\u306a\u304f\u8fd1\u3044\u64cd\u4f5c\u611f\u306b\u306a\u308c\u3070\u3044\u3044\u3084\u304f\u3089\u3044\u306b\u3057\u3066\u307e\u3059\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u30ea\u30fc\u30b8\u30e7\u30f3\u9078\u629e\u306b\u3064\u3044\u3066\u306f\u3001\u307e\u3060\u672a\u5b9f\u88c5\u3067\u3059\u3002\u305d\u306e\u3046\u3061\u4f59\u88d5\u304c\u3067\u304d\u305f\u3089\u3084\u308a\u307e\u3059\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u56f0\u3063\u305f\u30dd\u30a4\u30f3\u30c8\u3068\u3057\u3066\u306f\u3001Win+Ctrl+\u5de6\u53f3\u30ad\u30fc\u3067\u4eee\u60f3\u30c7\u30b9\u30af\u30c8\u30c3\u30d7\u306e\u5207\u308a\u66ff\u3048\u3092\u884c\u3063\u3066\u3044\u305f\u306e\u3067\u3059\u304c\u3001\u3053\u3044\u3064\u304c\u52d5\u304b\u306a\u304f\u306a\u3063\u3066\u3057\u307e\u3044\u3001\u7d50\u5c40\u3001Win\u30ad\u30fc\u3092&#8221;LUser0&#8243;\u306b\u5272\u308a\u5f53\u3066\u308b\u306e\u3092\u3084\u3081\u307e\u3057\u305f\u3002LEADER\u306f\u500b\u5225\u306b\u8a2d\u5b9a\u3059\u308b\u3088\u3046\u306b\u3057\u305f\u306e\u3067\u554f\u984c\u7121\u3044\u3068\u601d\u3044\u307e\u3059\u304c\u3001&#8221;LUser0\/User0&#8243;\u3092\u4f7f\u3063\u3066\u8a2d\u5b9a\u3092\u5165\u308c\u3066\u3044\u308b\u4eba\u306f\u3054\u6ce8\u610f\u304f\u3060\u3055\u3044\u3002\u305f\u3076\u3093\u52d5\u304b\u306a\u304f\u306a\u308b\u304b\u3001\u6319\u52d5\u304c\u304a\u304b\u3057\u304f\u306a\u308b\u3068\u601d\u3044\u307e\u3059\u3002<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n&quot;&quot;&quot;Keyhac 2 configuration file.\n\nThis file is copied to ~\/.keyhac\/config.py on first run.  Edit that copy \u2014\nKeyhac reloads it from the tray menu or the console&#039;s hook toggle.\n\nThe same file runs on Windows and macOS.  Where the OSes genuinely differ,\nbranch on `keymap.platform`; the two constants set up at the top (LEADER and\nMOD) absorb most of it, so the samples below rarely have to.\n\nEverything here is a working example, not pseudo-code.  Delete what you do\nnot want.\n&quot;&quot;&quot;\n\nimport json\n\nfrom keyhac import *\nfrom keyhac.core.keymap import Keymap\nfrom keyhac.core.const import MODKEY_SHIFT\nfrom keyhac.core.const import MODKEY_ALT\nfrom keyhac.core.const import MODKEY_CTRL\nfrom keyhac.core.const import MODKEY_WIN\nfrom keyhac.core.const import MODKEY_CMD\nfrom keyhac.core.const import MODKEY_FN\nfrom keyhac.ui.chooser import ChooserWindow\nfrom puikit.event import EventType\n\nlogger = getLogger(&quot;Config&quot;)\n\n_EVENT_MODKEYS = {\n    &quot;shift&quot;: MODKEY_SHIFT,\n    &quot;ctrl&quot;: MODKEY_CTRL,\n    &quot;alt&quot;: MODKEY_ALT,\n    &quot;win&quot;: MODKEY_WIN,\n    &quot;cmd&quot;: MODKEY_CMD,\n}\n\n\ndef configure(keymap):\n\n    mac = keymap.platform == &quot;mac&quot;\n\n    # ==================================================================\n    # Setup\n    # ==================================================================\n\n    # --- user modifier -------------------------------------------------\n    # Turn a key into User0, a modifier of your own that no application\n    # sees.  User0-User3 are available; a key used this way is never\n    # emitted, so it loses its original meaning while defined.\n    if mac:\n        # The right Option key; it stops acting as Option.\n        keymap.define_modifier(&quot;RAlt&quot;, &quot;RUser0&quot;)\n    else:\n        # The left Windows key; the Start menu no longer opens on a tap\n        # (bind kt&#x5B;&quot;O-LWin&quot;] = &quot;LWin&quot; below if you want that back).\n        # keymap.define_modifier(&quot;LWin&quot;, &quot;LUser0&quot;)  # \u4eee\u60f3\u30c7\u30b9\u30af\u30c8\u30c3\u30d7\u5207\u308a\u66ff\u3048\u304c\u3046\u307e\u304f\u3044\u304b\u306a\u3044\u306e\u3067\u3001Win\u30ad\u30fc\u3092\u958b\u653e\n        pass\n    \n    # --- the two portability constants ---------------------------------\n    # LEADER: the modifier most samples below hang off.\n    #   macOS   - the Fn key, which Windows does not expose to software\n    #   Windows - User0, i.e. the left Windows key defined just above\n    # LEADER = &quot;Fn&quot; if mac else &quot;User0&quot;  # \u4e0a\u8a18\u306e\u5909\u66f4\u306b\u4f34\u3044\u3001&quot;User0&quot;\n    LEADER = &quot;Fn&quot; if mac else &quot;LWin&quot;\n\n    # MOD: the OS&#039;s primary shortcut modifier, so one binding can mean\n    # &quot;Cmd-C&quot; on macOS and &quot;Ctrl-C&quot; on Windows.\n    MOD = &quot;Cmd&quot; if mac else &quot;Ctrl&quot;\n\n    # --- swap a key entirely (uncomment to try) ------------------------\n    # replace_key runs before any key table, so the rest of the config\n    # only ever sees the replacement.\n    # keymap.replace_key(&quot;CapsLock&quot;, &quot;LCtrl&quot;)\n\n    # --- text editor for &quot;Edit Config&quot; ---------------------------------\n    # The tray menu&#039;s &quot;Edit Config&quot; opens this file.  Unset, a default is\n    # picked (VS Code \/ Xcode \/ TextEdit on macOS, Notepad on Windows).\n    # Name an editor application, or set a callable taking the path:\n    # keymap.editor = &quot;CotEditor&quot; if mac else &quot;notepad.exe&quot;\n\n    # --- clipboard history ---------------------------------------------\n    keymap.clipboard_history.max_items = 500\n    keymap.clipboard_history.max_data_size = 10 * 1024 * 1024\n\n    # ==================================================================\n    # Global key table (active everywhere)\n    # ==================================================================\n\n    kt = keymap.define_keytable(focus_path_pattern=&quot;*&quot;)\n\n    # ==================================================================\n    # Fakeymacs-style key bindings\n    # ==================================================================\n\n    # Basic Emacs cursor movement.\n    kt&#x5B;&quot;Ctrl-B&quot;] = &quot;Left&quot;\n    kt&#x5B;&quot;Ctrl-F&quot;] = &quot;Right&quot;\n    kt&#x5B;&quot;Ctrl-P&quot;] = &quot;Up&quot;\n    kt&#x5B;&quot;Ctrl-N&quot;] = &quot;Down&quot;\n    kt&#x5B;&quot;Ctrl-A&quot;] = &quot;Home&quot;\n    kt&#x5B;&quot;Ctrl-E&quot;] = &quot;End&quot;\n\n    # Word movement.\n    kt&#x5B;&quot;Alt-B&quot;] = &quot;Ctrl-Left&quot;\n    kt&#x5B;&quot;Alt-F&quot;] = &quot;Ctrl-Right&quot;\n\n    # Page movement.\n    kt&#x5B;&quot;Ctrl-V&quot;] = &quot;PageDown&quot;\n    kt&#x5B;&quot;Alt-V&quot;] = &quot;PageUp&quot;\n\n    # Delete \/ kill.\n    kt&#x5B;&quot;Ctrl-D&quot;] = &quot;Delete&quot;\n    kt&#x5B;&quot;Alt-D&quot;] = &quot;Ctrl-Delete&quot;\n    kt&#x5B;&quot;Alt-Back&quot;] = &quot;Ctrl-Backspace&quot;\n    kt&#x5B;&quot;Ctrl-K&quot;] = &quot;Shift-End&quot;, &quot;Ctrl-C&quot;, &quot;Delete&quot;\n    kt&#x5B;&quot;Ctrl-H&quot;] = &quot;Back&quot;\n\n    # Clipboard.\n    kt&#x5B;&quot;Ctrl-W&quot;] = &quot;Ctrl-X&quot;\n    kt&#x5B;&quot;Alt-W&quot;] = &quot;Ctrl-C&quot;\n    kt&#x5B;&quot;Ctrl-Y&quot;] = &quot;Ctrl-V&quot;\n\n    # Newline \/ undo \/ cancel.\n    kt&#x5B;&quot;Ctrl-M&quot;] = &quot;Enter&quot;\n    kt&#x5B;&quot;Ctrl-J&quot;] = &quot;Enter&quot;\n    kt&#x5B;&quot;Ctrl-O&quot;] = &quot;Enter&quot;, &quot;Left&quot;\n    kt&#x5B;&quot;Ctrl-Slash&quot;] = &quot;Ctrl-Z&quot;\n    kt&#x5B;&quot;Ctrl-G&quot;] = &quot;Esc&quot;\n\n    # Search.\n    kt&#x5B;&quot;Ctrl-S&quot;] = &quot;Ctrl-F&quot;\n    kt&#x5B;&quot;Ctrl-R&quot;] = &quot;Ctrl-Shift-F3&quot;\n\n    # --------------------------------------------------------------\n    # Fakeymacs-like C-x prefix\n    # --------------------------------------------------------------\n    kt_x_emacs = keymap.define_keytable(name=&quot;Emacs-C-X&quot;)\n    kt&#x5B;&quot;Ctrl-X&quot;] = kt_x_emacs\n\n    kt_x_emacs&#x5B;&quot;H&quot;] = &quot;Ctrl-Home&quot;, &quot;Ctrl-A&quot;   # mark whole buffer\n    kt_x_emacs&#x5B;&quot;Ctrl-F&quot;] = &quot;Ctrl-O&quot;           # open\n    kt_x_emacs&#x5B;&quot;Ctrl-S&quot;] = &quot;Ctrl-S&quot;           # save\n    kt_x_emacs&#x5B;&quot;K&quot;] = &quot;Ctrl-F4&quot;               # close tab\/window\n    kt_x_emacs&#x5B;&quot;U&quot;] = &quot;Ctrl-Z&quot;                # undo\n    kt_x_emacs&#x5B;&quot;Ctrl-C&quot;] = &quot;Alt-F4&quot;           # quit\n\n    # --------------------------------------------------------------\n    # Clipboard history + categorized preset snippets\n    #\n    # Alt-Y opens a custom chooser.  Left\/Right switches categories,\n    # Up\/Down selects an item, Enter pastes it, and Shift-Enter only\n    # copies it to the clipboard.\n    #\n    # The categories below are intentionally easy to customize.\n    # Each category is: (icon, label, text\/callable).\n    # --------------------------------------------------------------\n    clipboard_categories = &#x5B;\n        (&quot;&amp;#x1f4cb; \u5c65\u6b74&quot;, None),       # populated dynamically\n        (&quot;&amp;#x1f4e7; \u30e1\u30fc\u30eb&quot;, &#x5B;\n            (&quot;&amp;#x1f4e7;&quot;, &quot;\u30e1\u30fc\u30eb\u30a2\u30c9\u30ec\u30b9&quot;, &quot;me@example.com&quot;),\n            (&quot;&amp;#x270d;&quot;, &quot;\u7f72\u540d&quot;, &quot;\u3088\u308d\u3057\u304f\u304a\u9858\u3044\u3044\u305f\u3057\u307e\u3059\u3002&quot;),\n        ]),\n        (&quot;&amp;#x1f4bb; \u958b\u767a&quot;, &#x5B;\n            (&quot;&amp;#x1f517;&quot;, &quot;GitHub&quot;, &quot;https:\/\/github.com\/&quot;),\n            (&quot;&amp;#x1f40d;&quot;, &quot;Python&quot;, &quot;```python\\n\\n```&quot;),\n            (&quot;&amp;#x1f4dd;&quot;, &quot;Markdown code block&quot;, &quot;```\\n\\n```&quot;),\n        ]),\n        (&quot;&amp;#x1f552; \u65e5\u6642&quot;, &#x5B;\n            (&quot;&amp;#x1f4c5;&quot;, &quot;YYYY-MM-DD&quot;, DateTimeSnippet(&quot;%Y-%m-%d&quot;)),\n            (&quot;&amp;#x1f552;&quot;, &quot;YYYY-MM-DD HH:MM:SS&quot;,\n             DateTimeSnippet(&quot;%Y-%m-%d %H:%M:%S&quot;)),\n            (&quot;&amp;#x1f4c1;&quot;, &quot;YYYYMMDD_HHMMSS&quot;,\n             DateTimeSnippet(&quot;%Y%m%d_%H%M%S&quot;)),\n        ]),\n    ]\n\n    class CategorizedChooserWindow(ChooserWindow):\n        &quot;&quot;&quot;ChooserWindow with Left\/Right category switching.&quot;&quot;&quot;\n\n        def __init__(self, backend, categories, *args, **kwargs):\n            self._categories = categories\n            self._category_index = 0\n            self._category_titles = &#x5B;c&#x5B;0] for c in categories]\n            self._filter_text = &quot;&quot;\n            super().__init__(backend, self._category_items(), *args, **kwargs)\n\n        def _category_items(self):\n            title, items = self._categories&#x5B;self._category_index]\n            return list(items)\n\n        def _category_header(self):\n            n = len(self._categories)\n            title = self._category_titles&#x5B;self._category_index]\n            return f&quot;\u2190 {title} \u2192   ({self._category_index + 1}\/{n})&quot;\n\n        def _labels(self):\n            # Put the category indicator at the top of the chooser.\n            return &#x5B;self._category_header()] + &#x5B;\n                f&quot;{item&#x5B;0]} {item&#x5B;1]}&quot; if item&#x5B;0] else item&#x5B;1]\n                for item in self._filtered\n            ]\n\n        def _on_filter_change(self, text: str) -&gt; None:\n            # Category header is not part of filtering.\n            self._filter_text = text\n            words = &#x5B;w for w in text.lower().split() if w]\n            items = self._category_items()\n            self._filtered = &#x5B;\n                item for item in items\n                if all(w in item&#x5B;1].lower() for w in words)\n            ]\n            self._list.set_items(self._labels())\n            self._list.selected = 1 if self._filtered else 0\n            self.panel.render()\n\n        def _switch_category(self, delta):\n            self._category_index = (\n                self._category_index + delta\n            ) % len(self._categories)\n\n            # Re-apply the current filter to the new category.  This\n            # avoids relying on undocumented TextEdit methods.\n            self._on_filter_change(self._filter_text)\n\n        def _on_event(self, event) -&gt; None:\n            if event.type is EventType.KEY:\n                if event.key == &quot;left&quot;:\n                    self._switch_category(-1)\n                    return\n\n                if event.key == &quot;right&quot;:\n                    self._switch_category(+1)\n                    return\n\n                # The first row is the category header.  Skip over it\n                # when navigating with Up\/Down.\n                if event.key in (&quot;up&quot;, &quot;down&quot;, &quot;pageup&quot;, &quot;pagedown&quot;):\n                    delta = {\n                        &quot;up&quot;: -1,\n                        &quot;down&quot;: 1,\n                        &quot;pageup&quot;: -10,\n                        &quot;pagedown&quot;: 10,\n                    }&#x5B;event.key]\n\n                    if self._filtered:\n                        selected = self._list.selected - 1\n                        selected = max(\n                            0,\n                            min(len(self._filtered) - 1, selected + delta),\n                        )\n                        self._list.selected = selected + 1\n                        self.panel.render()\n                    return\n\n                if event.key == &quot;enter&quot;:\n                    # Don&#039;t select the category header itself.\n                    index = self._list.selected - 1\n                    if 0 &lt;= index &lt; len(self._filtered):\n                        mod = 0\n                        for name in event.modifiers:\n                            mod |= _EVENT_MODKEYS.get(name, 0)\n                        self._finish(self._filtered&#x5B;index], mod)\n                    return\n\n            self.panel.dispatch_event(event)\n            self.panel.render()\n\n\n    class CategorizedClipboardChooser(ChooserAction):\n        &quot;&quot;&quot;Fakeymacs-style clipboard\/snippet chooser with categories.&quot;&quot;&quot;\n\n        _open = None\n\n        def __init__(self, categories):\n            self.categories = categories\n\n        def __repr__(self):\n            return &quot;CategorizedClipboardChooser()&quot;\n\n        def _make_categories(self):\n            categories = &#x5B;]\n\n            for title, items in self.categories:\n                if items is None:\n                    # Clipboard history: Keyhac 2 returns (text, label).\n                    history = Keymap.get_instance().clipboard_history\n                    history_items = &#x5B;\n                        (&quot;&amp;#x1f4cb;&quot;, label, text)\n                        for text, label in history.items()\n                    ]\n                    categories.append((title, history_items))\n                else:\n                    categories.append((title, list(items)))\n\n            return categories\n\n        def __call__(self):\n            from keyhac.ui import runtime\n            from keyhac.ui.chooser import ChooserWindow\n\n            if runtime.backend is None:\n                logger.error(\n                    &quot;CategorizedClipboardChooser requires the Keyhac UI.&quot;\n                )\n                return\n\n            keymap = Keymap.get_instance()\n\n            # Close an already-open categorized chooser.\n            if self._open is not None:\n                old_window, old_pid = self._open\n                old_window.dismiss()\n                self._open = None\n                if old_pid is not None and keymap.app_control is not None:\n                    keymap.app_control.activate_pid(old_pid)\n                return\n\n            focus = keymap.focus\n            original_pid = focus.pid if focus else None\n\n            def refocus():\n                if original_pid is not None and keymap.app_control is not None:\n                    keymap.app_control.activate_pid(original_pid)\n\n            def selected(item, modifier_flags):\n                self._open = None\n                refocus()\n\n                value = item&#x5B;2] if len(item) &gt; 2 else item&#x5B;1]\n                if callable(value):\n                    value = value()\n                if value is None:\n                    return\n\n                keymap.clipboard_history.set_current(str(value))\n\n                # Shift-Enter = clipboard only.\n                if modifier_flags &amp; MODKEY_SHIFT:\n                    return\n\n                # Normal Enter = paste into the original application.\n                runtime.backend.call_later(\n                    0.15,\n                    lambda: self._paste(),\n                )\n\n            def canceled():\n                self._open = None\n                refocus()\n\n            center_on = clamp_to = None\n            active = keymap.get_active_window()\n            if active is not None:\n                center_on = active.get_frame()\n\n            if center_on is not None and keymap.window_provider is not None:\n                clamp_to = MoveWindow._get_best_screen(\n                    center_on,\n                    keymap.window_provider.screen_frames(),\n                )\n\n            categories = self._make_categories()\n\n            chooser = CategorizedChooserWindow(\n                runtime.backend,\n                categories,\n                on_selected=selected,\n                on_canceled=canceled,\n                title=&quot;Clipboard \/ Snippets&quot;,\n                center_on=center_on,\n                clamp_to=clamp_to,\n            )\n\n            self._open = (chooser, original_pid)\n\n            if keymap.app_control is not None:\n                import os\n                keymap.app_control.activate_pid(os.getpid())\n\n        def _paste(self):\n            keymap = Keymap.get_instance()\n            with keymap.get_input_context() as ctx:\n                ctx.send_key(\n                    &quot;Cmd-V&quot; if keymap.platform == &quot;mac&quot; else &quot;Ctrl-V&quot;\n                )\n\n    kt&#x5B;&quot;Alt-Y&quot;] = CategorizedClipboardChooser(clipboard_categories)\n\n    # --------------------------------------------------------------\n    # Application launcher\n    #\n    # Alt-L opens a selectable application list.\n    # Add\/remove entries here to match the applications you use.\n    # --------------------------------------------------------------\n    def show_application_launcher():\n        applications = &#x5B;\n            (&quot;&amp;#x1f4dd;&quot;, &quot;Notepad&quot;, &quot;notepad.exe&quot;),\n            (&quot;&amp;#x1f4c1;&quot;, &quot;Explorer&quot;, &quot;explorer.exe&quot;),\n            (&quot;&amp;#x2328;&quot;, &quot;Windows Terminal&quot;, &quot;wt.exe&quot;),\n            (&quot;&amp;#x1f4bb;&quot;, &quot;PowerShell&quot;, &quot;powershell.exe&quot;),\n            (&quot;&amp;#x1f310;&quot;, &quot;Microsoft Edge&quot;, &quot;msedge.exe&quot;),\n            (&quot;&amp;#x1f310;&quot;, &quot;Google Chrome&quot;, &quot;chrome.exe&quot;),\n            (&quot;&amp;#x1f9d1;&amp;#x200d;&amp;#x1f4bb;&quot;, &quot;Visual Studio Code&quot;, &quot;code&quot;),\n        ]\n\n        entries = &#x5B;]\n        for icon, name, command in applications:\n            def launch(command=command):\n                LaunchApplication(command)()\n            entries.append((icon, name, launch))\n\n        ShowClipboardSnippets(entries)()\n\n    kt&#x5B;&quot;Alt-L&quot;] = show_application_launcher\n\n\n    # --- key -&gt; key ----------------------------------------------------\n    # IJKL as arrow keys while LEADER is held.\n    kt&#x5B;f&quot;{LEADER}-I&quot;] = &quot;Up&quot;\n    kt&#x5B;f&quot;{LEADER}-J&quot;] = &quot;Left&quot;\n    kt&#x5B;f&quot;{LEADER}-K&quot;] = &quot;Down&quot;\n    kt&#x5B;f&quot;{LEADER}-L&quot;] = &quot;Right&quot;\n    kt&#x5B;f&quot;{LEADER}-U&quot;] = &quot;Home&quot;\n    kt&#x5B;f&quot;{LEADER}-O&quot;] = &quot;End&quot;\n\n    # --- key -&gt; sequence of keys ---------------------------------------\n    # Select the whole line: Home, then Shift-End.\n    kt&#x5B;f&quot;{LEADER}-A&quot;] = &quot;Home&quot;, &quot;Shift-End&quot;\n\n    # --- one-shot: tap for one key, hold to modify ---------------------\n    # A one-shot key held down still works as its modifier; only a lone\n    # tap-and-release fires the assignment.  Picked so a stray tap is\n    # harmless (an Escape here, say, would cancel dialogs mid-typing).\n    if mac:\n        # The classic macOS setup: tap Left\/Right Cmd alone for Eisu\/Kana\n        # (IME off\/on) - a no-op unless a Japanese input source is\n        # installed.  Held, they are still plain Cmd.\n        kt&#x5B;&quot;O-LCmd&quot;] = &quot;Eisu&quot;\n        kt&#x5B;&quot;O-RCmd&quot;] = &quot;Kana&quot;\n    else:\n        # Tap right Ctrl alone to open the Start-menu search; held, it is\n        # still plain Ctrl.\n        kt&#x5B;&quot;O-RCtrl&quot;] = &quot;Win-S&quot;\n\n    # --- key -&gt; your own function --------------------------------------\n    def hello():\n        # print() and the logger both reach the console window.\n        print(&quot;Hello from config.py&quot;)\n        logger.info(f&quot;platform={keymap.platform}&quot;)\n\n    kt&#x5B;f&quot;{LEADER}-H&quot;] = hello\n\n    # --- typing literal text -------------------------------------------\n    kt&#x5B;f&quot;{LEADER}-Semicolon&quot;] = InputText(&quot;me@example.com&quot;)\n\n    # --- sending keys from your own function ---------------------------\n    # get_input_context() batches virtual key input; it is safe to use from\n    # a worker thread as well (see the ThreadedAction sample below).\n    def wrap_in_quotes():\n        with keymap.get_input_context() as ctx:\n            ctx.send_key(f&quot;{MOD}-C&quot;)\n\n    kt&#x5B;f&quot;{LEADER}-Q&quot;] = wrap_in_quotes\n\n    # ==================================================================\n    # Clipboard\n    # ==================================================================\n\n    # --- history, in a chooser window ----------------------------------\n    # Enter pastes; Shift-Enter only sets the clipboard.  Type to filter.\n    kt&#x5B;f&quot;{LEADER}-V&quot;] = ShowClipboardHistory()\n\n    # --- fixed snippets -------------------------------------------------\n    # (icon, label) | (icon, label, text) | (icon, label, callable)\n    kt&#x5B;f&quot;{LEADER}-Shift-V&quot;] = ShowClipboardSnippets(&#x5B;\n        (&quot;&amp;#x1f4e7;&quot;, &quot;me@example.com&quot;),\n        (&quot;&amp;#x1f4ee;&quot;, &quot;Mailing address&quot;, &quot;400 Broad St, Seattle, WA 98109&quot;),\n        (&quot;&amp;#x1f552;&quot;, &quot;Date&quot;, DateTimeSnippet(&quot;%Y-%m-%d&quot;)),\n        (&quot;&amp;#x1f552;&quot;, &quot;Timestamp&quot;, DateTimeSnippet(&quot;%Y-%m-%d %H:%M:%S&quot;)),\n        (&quot;&amp;#x1f552;&quot;, &quot;For filenames&quot;, DateTimeSnippet(&quot;%Y%m%d_%H%M%S&quot;)),\n    ])\n\n    # --- transform whatever is on the clipboard -------------------------\n    # A tool takes the clipboard text and returns the replacement.\n    def pretty_json(s):\n        try:\n            return json.dumps(json.loads(s), indent=4, ensure_ascii=False)\n\n\n\n\n        except json.JSONDecodeError:\n            logger.error(&quot;Clipboard content is not valid JSON.&quot;)\n            return s\n\n    kt&#x5B;f&quot;{LEADER}-Ctrl-V&quot;] = ShowClipboardTools(&#x5B;\n        (&quot;&amp;#x1f504;&quot;, &quot;Quote&quot;, ShowClipboardTools.quote),\n        (&quot;&amp;#x1f504;&quot;, &quot;Unindent&quot;, ShowClipboardTools.unindent),\n        (&quot;&amp;#x1f504;&quot;, &quot;Upper case&quot;, str.upper),\n        (&quot;&amp;#x1f504;&quot;, &quot;Lower case&quot;, str.lower),\n        (&quot;&amp;#x1f504;&quot;, &quot;Half width&quot;, ShowClipboardTools.to_half_width),\n        (&quot;&amp;#x1f504;&quot;, &quot;Full width&quot;, ShowClipboardTools.to_full_width),\n        (&quot;&amp;#x1f504;&quot;, &quot;Pretty JSON&quot;, pretty_json),\n    ])\n\n    # ==================================================================\n    # Windows and applications\n    # ==================================================================\n\n    # --- move the focused window ---------------------------------------\n    # Apple keyboards translate Fn-Arrow into Home\/End\/PageUp\/PageDown in\n    # hardware (the Fn modifier itself still arrives), so with LEADER = Fn\n    # the &quot;...-Left&quot; spellings would never fire on macOS - bind the keys\n    # that actually arrive there.  Ctrl\/Alt rather than Shift, because\n    # Fn-Shift-Arrow is how you *select text* on a Mac laptop (it arrives\n    # as Shift-Home etc.) - a Shift binding here would steal it.\n    LEFT, RIGHT, UP, DOWN = ((&quot;Home&quot;, &quot;End&quot;, &quot;PageUp&quot;, &quot;PageDown&quot;) if mac\n                             else (&quot;Left&quot;, &quot;Right&quot;, &quot;Up&quot;, &quot;Down&quot;))\n\n    # Nudge by 20 px...\n    kt&#x5B;f&quot;{LEADER}-Ctrl-{LEFT}&quot;] = MoveWindow(direction=&quot;left&quot;, distance=20)\n    kt&#x5B;f&quot;{LEADER}-Ctrl-{RIGHT}&quot;] = MoveWindow(direction=&quot;right&quot;, distance=20)\n    kt&#x5B;f&quot;{LEADER}-Ctrl-{UP}&quot;] = MoveWindow(direction=&quot;up&quot;, distance=20)\n    kt&#x5B;f&quot;{LEADER}-Ctrl-{DOWN}&quot;] = MoveWindow(direction=&quot;down&quot;, distance=20)\n\n    # ...or send it as far as it goes, stopping at other windows&#039; edges\n    # and screen edges (and hopping to the next monitor when already there).\n    kt&#x5B;f&quot;{LEADER}-Alt-{LEFT}&quot;] = MoveWindow(direction=&quot;left&quot;, distance=9999,\n                                            window_edge=True, screen_edge=True)\n    kt&#x5B;f&quot;{LEADER}-Alt-{RIGHT}&quot;] = MoveWindow(direction=&quot;right&quot;, distance=9999,\n                                             window_edge=True, screen_edge=True)\n    kt&#x5B;f&quot;{LEADER}-Alt-{UP}&quot;] = MoveWindow(direction=&quot;up&quot;, distance=9999,\n                                          window_edge=True, screen_edge=True)\n    kt&#x5B;f&quot;{LEADER}-Alt-{DOWN}&quot;] = MoveWindow(direction=&quot;down&quot;, distance=9999,\n                                            window_edge=True, screen_edge=True)\n\n    # --- snap to screen regions (tiling) --------------------------------\n    # Resizes to a half of the window&#039;s current screen, inside the work\n    # area (menu bar, Dock and taskbar stay uncovered).  Same IJKL layout\n    # as the arrows above.  ratio= picks a different split, e.g.\n    # SnapWindow(&quot;left&quot;, ratio=2\/3).\n    kt&#x5B;f&quot;{LEADER}-Ctrl-J&quot;] = SnapWindow(&quot;left&quot;)\n    kt&#x5B;f&quot;{LEADER}-Ctrl-L&quot;] = SnapWindow(&quot;right&quot;)\n    kt&#x5B;f&quot;{LEADER}-Ctrl-I&quot;] = SnapWindow(&quot;top&quot;)\n    kt&#x5B;f&quot;{LEADER}-Ctrl-K&quot;] = SnapWindow(&quot;bottom&quot;)\n    kt&#x5B;f&quot;{LEADER}-F&quot;] = SnapWindow(&quot;full&quot;)\n\n    # --- minimize the focused window -------------------------------------\n    def minimize_window():\n        window = keymap.get_active_window()\n        if window is not None:\n            window.minimize()\n\n    kt&#x5B;f&quot;{LEADER}-M&quot;] = minimize_window\n\n    # --- bring an application forward -----------------------------------\n    # Matches like the focus conditions below: wildcards, &quot;|&quot; alternation,\n    # case-insensitive, &quot;.exe&quot; optional.\n    kt&#x5B;f&quot;{LEADER}-1&quot;] = ActivateWindow(app=&quot;code|Visual Studio Code&quot;)\n    kt&#x5B;f&quot;{LEADER}-2&quot;] = ActivateWindow(app=&quot;chrome|Google Chrome&quot;)\n\n    # --- launch an application ------------------------------------------\n    if mac:\n        kt&#x5B;f&quot;{LEADER}-T&quot;] = LaunchApplication(&quot;Terminal.app&quot;)\n    else:\n        kt&#x5B;f&quot;{LEADER}-T&quot;] = LaunchApplication(&quot;wt.exe&quot;)   # Windows Terminal\n\n    # --- inspect windows yourself ---------------------------------------\n    # keymap.get_active_window() \/ find_window() \/ list_windows() return\n    # portable Window objects: title, app_name, pid, class_name (Windows),\n    # get_frame(), set_frame(), activate(), minimize(), is_minimized(),\n    # restore().  Screen geometry: keymap.screen_frames() (whole screens),\n    # keymap.screen_work_frames() (minus menu bar \/ Dock \/ taskbar) and\n    # keymap.window_frames().  Window objects and screen_work_frames() are\n    # UI-thread only - never touch them from a ThreadedAction.run(); the\n    # thread-safe pair there is screen_frames() \/ window_frames().\n    def describe_window():\n        window = keymap.get_active_window()\n        if window is None:\n            logger.warning(&quot;No active window.&quot;)\n            return\n        x, y, w, h = window.get_frame()\n        logger.info(f&quot;{window.app_name}: \\&quot;{window.title}\\&quot; &quot;\n                    f&quot;at ({x:.0f},{y:.0f}) {w:.0f}x{h:.0f}&quot;)\n        logger.info(f&quot;{len(keymap.list_windows())} windows open on &quot;\n                    f&quot;{len(keymap.screen_frames())} screen(s)&quot;)\n\n    kt&#x5B;f&quot;{LEADER}-W&quot;] = describe_window\n\n    # --- activate, or launch if it is not running ------------------------\n    def activate_or_launch_editor():\n        window = keymap.find_window(app=&quot;code|Visual Studio Code&quot;)\n        if window:\n            window.activate()\n        else:\n            LaunchApplication(&quot;Visual Studio Code.app&quot; if mac else &quot;code&quot;)()\n\n    kt&#x5B;f&quot;{LEADER}-E&quot;] = activate_or_launch_editor\n\n    # ==================================================================\n    # Keyboard macros\n    # ==================================================================\n\n    kt&#x5B;f&quot;{LEADER}-OpenBracket&quot;] = ToggleRecordingKeys()    # record on\/off\n    kt&#x5B;f&quot;{LEADER}-CloseBracket&quot;] = PlaybackRecordedKeys()  # replay\n    # StartRecordingKeys() \/ StopRecordingKeys() exist too, if you would\n    # rather have separate keys than a toggle.\n\n    # ==================================================================\n    # Background work: ThreadedAction\n    # ==================================================================\n\n    # Anything slow (network, subprocess, sleeping) must not run inline -\n    # it would block the keyboard hook.  ThreadedAction gives you a worker\n    # thread; starting() and finished() run under the engine lock, run()\n    # does not.\n    class TypeSlowly(ThreadedAction):\n        def __init__(self, text):\n            self.text = text\n\n        def starting(self):\n            logger.info(f&quot;Typing {self.text!r}...&quot;)\n\n        def run(self):\n            import time\n            for char in self.text:\n                time.sleep(0.05)\n                with keymap.get_input_context() as ctx:\n                    ctx.send_key(f&quot;Shift-{char}&quot; if char.isupper() else char)\n            return len(self.text)\n\n        def finished(self, result):\n            logger.info(f&quot;Typed {result} characters.&quot;)\n\n        def __repr__(self):\n            return f&quot;TypeSlowly({self.text!r})&quot;\n\n    kt&#x5B;f&quot;{LEADER}-Y&quot;] = TypeSlowly(&quot;keyhac&quot;)\n\n    # ==================================================================\n    # Multi-stroke key tables\n    # ==================================================================\n\n    # Press LEADER-X, then a second key.  A balloon shows the table&#039;s name\n    # while it is armed.\n    kt_x = keymap.define_keytable(name=&quot;LEADER-X&quot;)\n    kt&#x5B;f&quot;{LEADER}-X&quot;] = kt_x\n    kt_x&#x5B;&quot;C&quot;] = f&quot;{MOD}-C&quot;\n    kt_x&#x5B;&quot;V&quot;] = f&quot;{MOD}-V&quot;\n    kt_x&#x5B;&quot;S&quot;] = f&quot;{MOD}-S&quot;\n\n    # --- balloon messages of your own ------------------------------------\n    def show_balloon():\n        # Absent when running with --no-ui, so ask before using it.\n        pop = getattr(keymap, &quot;pop_balloon&quot;, None)\n        if pop:\n            pop(&quot;hello&quot;, &quot;Keyhac is running&quot;, 2.0)\n\n    kt&#x5B;f&quot;{LEADER}-B&quot;] = show_balloon\n\n    # ==================================================================\n    # Application-specific key tables\n    # ==================================================================\n    # Tables are merged in definition order and later ones win, so anything\n    # below overrides the global table for the apps it matches.\n\n    # --- by application name (portable) ----------------------------------\n    kt_browser = keymap.define_keytable(app=&quot;chrome|Google Chrome|firefox|Safari&quot;)\n    kt_browser&#x5B;f&quot;{LEADER}-R&quot;] = f&quot;{MOD}-R&quot;          # reload\n\n    # --- by window title -------------------------------------------------\n    # kt_docs = keymap.define_keytable(title=&quot;*Google Docs*&quot;)\n\n    # --- by Win32 window class (Windows only) -----------------------------\n    if not mac:\n        kt_notepad = keymap.define_keytable(app=&quot;notepad&quot;, class_name=&quot;Edit&quot;)\n        kt_notepad&#x5B;f&quot;{LEADER}-D&quot;] = &quot;Home&quot;, &quot;Shift-Down&quot;, &quot;Shift-End&quot;, &quot;Delete&quot;\n\n    # --- by focus path ----------------------------------------------------\n    # The focus path is the control hierarchy down to the focused element -\n    # the AX tree on macOS, the UI Automation tree on Windows.  Watch the\n    # console&#039;s &quot;Focus path&quot; field to see the live value, and use &quot;*&quot; freely\n    # to skip levels.\n    #   macOS   : \/AXApplication(Xcode)\/AXWindow(...)\/...\/AXTextArea()\n    #   Windows : \/Application(Code)\/Window(...)\/...\/Edit(Message input)\n    # Note the trailing &quot;(*)&quot;: a component is &quot;Role(Name)&quot;, and many controls\n    # do carry a name, so &quot;*\/Edit()&quot; would only match unnamed ones.\n    kt_textarea = keymap.define_keytable(\n        focus_path_pattern=&quot;*\/AXTextArea(*)&quot; if mac else &quot;*\/Edit(*)&quot;)\n    kt_textarea&#x5B;f&quot;{LEADER}-Slash&quot;] = InputText(&quot;# &quot;)\n\n    # --- by your own test -------------------------------------------------\n    # custom_condition_func receives the portable Focus object: app_name,\n    # window_title, class_name (Windows), path, and element - the focused\n    # element in the OS&#039;s own vocabulary.\n    def is_terminal(focus):\n        if focus.app_name in (&quot;Terminal&quot;, &quot;iTerm2&quot;, &quot;WindowsTerminal&quot;, &quot;cmd&quot;,\n                              &quot;powershell&quot;, &quot;pwsh&quot;):\n            return True\n        # Element attributes differ per OS: AX names on macOS, UI Automation\n        # names on Windows.  An unknown name simply reads back as None.\n        element = focus.element\n        if element is None:\n            return False\n        role = element.get_attribute_value(&quot;AXRole&quot; if mac else &quot;ControlType&quot;)\n        return role in (&quot;AXTextArea&quot;, &quot;Document&quot;)\n\n    kt_terminal = keymap.define_keytable(custom_condition_func=is_terminal)\n    kt_terminal&#x5B;f&quot;{LEADER}-K&quot;] = &quot;Ctrl-K&quot;     # clear, rather than &quot;Down&quot;\n\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u4eee\u60f3\u30c7\u30b9\u30af\u30c8\u30c3\u30d7\u5207\u308a\u66ff\u3048\u306b\u95a2\u3057\u3066\u306f\u3001\u7d50\u69cb\u30cf\u30de\u3063\u305f\u3068\u3053\u308d\u3067\u3001\u5143\u306e\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u306b\u306f\u65e2\u5b58\u306e\u5272\u308a\u5f53\u3066\u304c\u3042\u3063\u305f\u306e\u3067\u3001\u30b3\u30e1\u30f3\u30c8\u30a2\u30a6\u30c8\u3057\u3001\u6539\u3081\u3066\u5b9a\u7fa9\u3057\u3066\u307f\u305f\u306e\u3067\u3059\u304c\u52d5\u3044\u3066\u304f\u308c\u306a\u3044\u3093\u3067\u3059\u3088\u306d\u3002\u4ee5\u4e0b\u306e\u4f8b\u4ee5\u5916\u306b\u3082\u3044\u308d\u3044\u308d\u8a66\u3057\u305f\u306e\u3067\u3059\u304c\u3001\u7d50\u5c40\u30c0\u30e1\u3060\u3063\u305f\u306e\u3067\u5192\u982d\u306b\u8a18\u8f09\u3057\u305f\u3088\u3046\u306b\u3001Win\u30ad\u30fc\u3092&#8221;LUser0&#8243;\u3078\u306e\u5272\u308a\u5f53\u3066\u3092\u3084\u3081\u308b\u65b9\u6cd5\u3067\u304a\u8336\u3092\u6fc1\u3057\u3066\u3044\u307e\u3059\u3002\u4f55\u304b\u3044\u3044\u611f\u3058\u306e\u3084\u308a\u65b9\u3092\u898b\u3064\u3051\u305f\u3089\u3001\u6539\u3081\u3066\u66f4\u65b0\u3057\u307e\u3059\u3002<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n    # -------------------------------------------------------------\n    # \u65e2\u5b58\u306e\u30a6\u30a3\u30f3\u30c9\u30a620px\u79fb\u52d5\u8a2d\u5b9a\u3092\u30b3\u30e1\u30f3\u30c8\u30a2\u30a6\u30c8\n    # -------------------------------------------------------------\n    # kt&#x5B;f&quot;{LEADER}-Ctrl-{LEFT}&quot;] = MoveWindow(direction=&quot;left&quot;, distance=20)\n    # kt&#x5B;f&quot;{LEADER}-Ctrl-{RIGHT}&quot;] = MoveWindow(direction=&quot;right&quot;, distance=20)\n    kt&#x5B;f&quot;{LEADER}-Ctrl-{UP}&quot;] = MoveWindow(direction=&quot;up&quot;, distance=20)\n    kt&#x5B;f&quot;{LEADER}-Ctrl-{DOWN}&quot;] = MoveWindow(direction=&quot;down&quot;, distance=20)\n\n    # -------------------------------------------------------------\n    # \u4eee\u60f3\u30c7\u30b9\u30af\u30c8\u30c3\u30d7\u5207\u308a\u66ff\u3048\u3092\u8a2d\u5b9a\u3000\u2192\u3000\u30c0\u30e1\u3060\u3063\u305f\u30fb\u30fb\u30fb\n    # -------------------------------------------------------------\n    # Win + Ctrl + \u5de6\u53f3\u30ad\u30fc \u3067\u4eee\u60f3\u30c7\u30b9\u30af\u30c8\u30c3\u30d7\u5207\u308a\u66ff\u3048\u3092\u884c\u3046\u5834\u5408\n    kt&#x5B;f&quot;{LEADER}-Ctrl-Left&quot;] = &quot;Win-Ctrl-Left&quot;\n    kt&#x5B;f&quot;{LEADER}-Ctrl-Right&quot;] = &quot;Win-Ctrl-Right&quot;\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u65e5\u5e38\u7684\u306a\u30d5\u30a1\u30a4\u30eb\u306e\u30b3\u30d4\u30da\u3082Ctrl+Y \u3067\u3084\u3063\u3066\u3057\u307e\u3046Emacs\u306b\u624b\u7656\u3092\u30ab\u30b9\u30bf\u30de\u30a4\u30ba\u3055\u308c\u305f\u4eba\u9593\u3068\u3057\u3066\u306f\u3001keyhac + Fakeymacs \u306f\u975e\u5e38\u306b\u4fbf\u5229\u306a\u30c4\u30fc\u30eb\u3067\u3057\u305f\u3002\u65b0\u3057\u3044PC\u3092\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u3059\u308b\u969b\u306b\u6539\u3081\u3066keyhac [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[6],"tags":[12,46],"class_list":["post-3275","post","type-post","status-publish","format-standard","hentry","category-6","tag-emacs","tag-windows"],"jetpack_publicize_connections":[],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p4rHn0-QP","amp_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/mindtech.jp\/index.php?rest_route=\/wp\/v2\/posts\/3275","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mindtech.jp\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mindtech.jp\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mindtech.jp\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mindtech.jp\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3275"}],"version-history":[{"count":4,"href":"https:\/\/mindtech.jp\/index.php?rest_route=\/wp\/v2\/posts\/3275\/revisions"}],"predecessor-version":[{"id":3280,"href":"https:\/\/mindtech.jp\/index.php?rest_route=\/wp\/v2\/posts\/3275\/revisions\/3280"}],"wp:attachment":[{"href":"https:\/\/mindtech.jp\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3275"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mindtech.jp\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3275"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mindtech.jp\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3275"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}