diff options
-rw-r--r-- | kvmd/apps/kvmd/api/hid.py | 11 | ||||
-rw-r--r-- | kvmd/apps/kvmd/server.py | 4 | ||||
-rw-r--r-- | web/kvm/index.html | 59 | ||||
-rw-r--r-- | web/kvm/navbar-shortcuts.pug | 43 | ||||
-rw-r--r-- | web/share/css/kvm/hid.css | 9 | ||||
-rw-r--r-- | web/share/js/kvm/hid.js | 73 | ||||
-rw-r--r-- | web/share/js/kvm/session.js | 1 |
7 files changed, 137 insertions, 63 deletions
diff --git a/kvmd/apps/kvmd/api/hid.py b/kvmd/apps/kvmd/api/hid.py index 418e065d..71e711ff 100644 --- a/kvmd/apps/kvmd/api/hid.py +++ b/kvmd/apps/kvmd/api/hid.py @@ -108,19 +108,22 @@ class HidApi: # ===== - @exposed_http("GET", "/hid/keymaps") - async def __keymaps_handler(self, _: Request) -> Response: + def get_keymaps(self) -> Dict: # Ugly hack to generate hid_keymaps_state (see server.py) keymaps: Set[str] = set() for keymap_name in os.listdir(self.__keymaps_dir_path): path = os.path.join(self.__keymaps_dir_path, keymap_name) if os.access(path, os.R_OK) and stat.S_ISREG(os.stat(path).st_mode): keymaps.add(keymap_name) - return make_json_response({ + return { "keymaps": { "default": self.__default_keymap_name, "available": sorted(keymaps), }, - }) + } + + @exposed_http("GET", "/hid/keymaps") + async def __keymaps_handler(self, _: Request) -> Response: + return make_json_response(self.get_keymaps()) @exposed_http("POST", "/hid/print") async def __print_handler(self, request: Request) -> Response: diff --git a/kvmd/apps/kvmd/server.py b/kvmd/apps/kvmd/server.py index 84f21c08..fcd21ae0 100644 --- a/kvmd/apps/kvmd/server.py +++ b/kvmd/apps/kvmd/server.py @@ -195,6 +195,7 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins ], ] + self.__hid_api = HidApi(hid, keymap_path, mouse_x_range, mouse_y_range) # Ugly hack to get keymaps state self.__apis: List[object] = [ self, AuthApi(auth_manager), @@ -202,7 +203,7 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins LogApi(log_reader), WolApi(wol), UserGpioApi(user_gpio), - HidApi(hid, keymap_path, mouse_x_range, mouse_y_range), + self.__hid_api, AtxApi(atx), MsdApi(msd, sync_chunk_size), StreamerApi(streamer), @@ -263,6 +264,7 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins await self.__register_ws_client(client) try: await self.__send_event(client.ws, "gpio_model_state", await self.__user_gpio.get_model()) + await self.__send_event(client.ws, "hid_keymaps_state", self.__hid_api.get_keymaps()) await asyncio.gather(*[ self.__send_event(client.ws, component.event_type, await component.get_state()) for component in self.__components diff --git a/web/kvm/index.html b/web/kvm/index.html index f044cd6c..730c5b4a 100644 --- a/web/kvm/index.html +++ b/web/kvm/index.html @@ -415,25 +415,58 @@ </li> <li class="right"><a class="menu-button" href="#">Shortcuts</a> <div class="menu" data-dont-hide-menu> + <div class="text"><b>Paste text as keypress sequence<br></b></div> + <hr> + <div class="text" style="margin-right: 20px"> + <textarea id="hid-pak-text" placeholder="Enter your text here"></textarea> + </div> + <hr> + <table class="kv"> + <tr> + <td> + <button disabled data-force-hide-menu id="hid-pak-button">• Paste</button> + </td> + <td>using host keymap</td> + <td> + <select id="hid-pak-keymap-selector"></select> + </td> + </tr> + </table> + <hr> + <table class="kv"> + <td>Ask paste confirmation:</td> + <td align="right"> + <div class="switch-box"> + <input checked type="checkbox" id="hid-pak-ask-switch"> + <label for="hid-pak-ask-switch"><span class="switch-inner"></span><span class="switch"></span></label> + </div> + </td> + </table> + <hr> + <div class="text"></div> + <hr> <div class="buttons"> - <textarea id="hid-pak-text" placeholder="Paste your text here"></textarea> - <hr> - <button disabled data-force-hide-menu id="hid-pak-button">• ↳ Paste-as-Keys <sup><i>ascii-only</i></sup></button> - <hr> <div class="buttons-row"> <button class="row50" data-force-hide-menu data-shortcut="CapsLock">• Caps Lock <img class="inline-lamp hid-keyboard-caps-led led-gray" src="/share/svg/led-square.svg"></button> <button class="row50" data-force-hide-menu data-shortcut="MetaLeft">• Left Win</button> </div> <hr> - <button data-force-hide-menu data-shortcut="AltLeft ShiftLeft">• Alt+Shift</button> - <button data-force-hide-menu data-shortcut="ControlLeft ShiftLeft">• Ctrl+Shift</button> - <button data-force-hide-menu data-shortcut="ShiftLeft ShiftRight">• Shift+Shift</button> - <button data-force-hide-menu data-shortcut="MetaLeft Space">• Win+Space</button> - <hr> - <button data-force-hide-menu data-shortcut="ControlLeft KeyW">• Ctrl+W</button> - <button data-force-hide-menu data-shortcut="AltLeft Tab">• Alt+Tab</button> - <button data-force-hide-menu data-shortcut="AltLeft Enter">• Alt+Enter</button> - <button data-force-hide-menu data-shortcut="AltLeft F4">• Alt+F4</button> + <div class="buttons-row"> + <button class="row50" data-force-hide-menu data-shortcut="AltLeft ShiftLeft">• Alt+Shift</button> + <button class="row50" data-force-hide-menu data-shortcut="ControlLeft KeyW">• Ctrl+W</button> + </div> + <div class="buttons-row"> + <button class="row50" data-force-hide-menu data-shortcut="ControlLeft ShiftLeft">• Ctrl+Shift</button> + <button class="row50" data-force-hide-menu data-shortcut="AltLeft Tab">• Alt+Tab</button> + </div> + <div class="buttons-row"> + <button class="row50" data-force-hide-menu data-shortcut="ShiftLeft ShiftRight">• Shift+Shift</button> + <button class="row50" data-force-hide-menu data-shortcut="AltLeft Enter">• Alt+Enter</button> + </div> + <div class="buttons-row"> + <button class="row50" data-force-hide-menu data-shortcut="MetaLeft Space">• Win+Space</button> + <button class="row50" data-force-hide-menu data-shortcut="AltLeft F4">• Alt+F4</button> + </div> <hr> <button data-force-hide-menu data-shortcut="ControlLeft AltLeft Delete">• Ctrl+Alt+Del</button> </div> diff --git a/web/kvm/navbar-shortcuts.pug b/web/kvm/navbar-shortcuts.pug index 9f3a94b0..c0062071 100644 --- a/web/kvm/navbar-shortcuts.pug +++ b/web/kvm/navbar-shortcuts.pug @@ -1,26 +1,43 @@ li(class="right") a(class="menu-button" href="#") Shortcuts div(data-dont-hide-menu class="menu") + div(class="text") + b Paste text as keypress sequence#[br] + hr + div(class="text" style="margin-right: 20px") + textarea(id="hid-pak-text" placeholder="Enter your text here") + hr + table(class="kv") + tr + td + button(disabled data-force-hide-menu id="hid-pak-button") • Paste + td using host keymap + td + select(id="hid-pak-keymap-selector") + hr + +menu_switch("hid-pak-ask-switch", "Ask paste confirmation", true, true) + hr + div(class="text") + hr div(class="buttons") - textarea(id="hid-pak-text" placeholder="Paste your text here") - hr - button(disabled data-force-hide-menu id="hid-pak-button") • ↳ Paste-as-Keys #[sup #[i ascii-only]] - hr div(class="buttons-row") button(data-force-hide-menu data-shortcut="CapsLock" class="row50") | • Caps Lock img(class="inline-lamp hid-keyboard-caps-led led-gray" src=`${svg_dir}/led-square.svg`) button(data-force-hide-menu data-shortcut="MetaLeft" class="row50") • Left Win hr - button(data-force-hide-menu data-shortcut="AltLeft ShiftLeft") • Alt+Shift - button(data-force-hide-menu data-shortcut="ControlLeft ShiftLeft") • Ctrl+Shift - button(data-force-hide-menu data-shortcut="ShiftLeft ShiftRight") • Shift+Shift - button(data-force-hide-menu data-shortcut="MetaLeft Space") • Win+Space - hr - button(data-force-hide-menu data-shortcut="ControlLeft KeyW") • Ctrl+W - button(data-force-hide-menu data-shortcut="AltLeft Tab") • Alt+Tab - button(data-force-hide-menu data-shortcut="AltLeft Enter") • Alt+Enter - button(data-force-hide-menu data-shortcut="AltLeft F4") • Alt+F4 + div(class="buttons-row") + button(data-force-hide-menu data-shortcut="AltLeft ShiftLeft" class="row50") • Alt+Shift + button(data-force-hide-menu data-shortcut="ControlLeft KeyW" class="row50") • Ctrl+W + div(class="buttons-row") + button(data-force-hide-menu data-shortcut="ControlLeft ShiftLeft" class="row50") • Ctrl+Shift + button(data-force-hide-menu data-shortcut="AltLeft Tab" class="row50") • Alt+Tab + div(class="buttons-row") + button(data-force-hide-menu data-shortcut="ShiftLeft ShiftRight" class="row50") • Shift+Shift + button(data-force-hide-menu data-shortcut="AltLeft Enter" class="row50") • Alt+Enter + div(class="buttons-row") + button(data-force-hide-menu data-shortcut="MetaLeft Space" class="row50") • Win+Space + button(data-force-hide-menu data-shortcut="AltLeft F4" class="row50") • Alt+F4 hr button(data-force-hide-menu data-shortcut="ControlLeft AltLeft Delete") • Ctrl+Alt+Del hr diff --git a/web/share/css/kvm/hid.css b/web/share/css/kvm/hid.css index 10daad98..d32c3d98 100644 --- a/web/share/css/kvm/hid.css +++ b/web/share/css/kvm/hid.css @@ -23,22 +23,21 @@ textarea#hid-pak-text { display: block; resize: none; + height: 60px; width: 100%; - height: 40px; + border-radius: 4px; color: var(--cs-window-default-fg); background-color: var(--cs-window-default-bg); - border: none; - outline: 0 !important; -webkit-appearance:none; } textarea#hid-pak-text::-moz-placeholder { - line-height: 40px; + line-height: 60px; text-align: center; } textarea#hid-pak-text::-webkit-input-placeholder { - line-height: 40px; + line-height: 60px; text-align: center; } diff --git a/web/share/js/kvm/hid.js b/web/share/js/kvm/hid.js index bcd1e479..f4f2b589 100644 --- a/web/share/js/kvm/hid.js +++ b/web/share/js/kvm/hid.js @@ -162,6 +162,14 @@ export function Hid() { } }; + self.setKeymaps = function(state) { + let html = ""; + for (let variant of state.keymaps.available) { + html += `<option value=${variant} ${variant === state.keymaps.default ? "selected" : ""}>${variant}</option>`; + } + $("hid-pak-keymap-selector").innerHTML = html; + }; + var __releaseAll = function() { __keyboard.releaseAll(); __mouse.releaseAll(); @@ -196,34 +204,45 @@ export function Hid() { var __clickPasteAsKeysButton = function() { let text = $("hid-pak-text").value.replace(/[^\x00-\x7F]/g, ""); // eslint-disable-line no-control-regex if (text) { - let confirm_msg = `You're going to paste ${text.length} character${text.length ? "s" : ""}.<br>`; - confirm_msg += "Are you sure you want to continue?"; - - wm.confirm(confirm_msg).then(function(ok) { - if (ok) { - wm.setElementEnabled($("hid-pak-text"), false); - wm.setElementEnabled($("hid-pak-button"), false); - - tools.debug("HID: paste-as-keys:", text); - - let http = tools.makeRequest("POST", "/api/hid/print?limit=0", function() { - if (http.readyState === 4) { - wm.setElementEnabled($("hid-pak-text"), true); - wm.setElementEnabled($("hid-pak-button"), true); - $("hid-pak-text").value = ""; - if (http.status === 413) { - wm.error("Too many text for paste!"); - } else if (http.status !== 200) { - wm.error("HID paste error:<br>", http.responseText); - } else if (http.status === 200) { - __recorder.recordPrintEvent(text); - } + let paste_as_keys = function() { + wm.setElementEnabled($("hid-pak-text"), false); + wm.setElementEnabled($("hid-pak-button"), false); + wm.setElementEnabled($("hid-pak-keymap-selector"), false); + + let keymap = $("hid-pak-keymap-selector").value; + + tools.debug(`HID: paste-as-keys ${keymap}: ${text}`); + + let http = tools.makeRequest("POST", `/api/hid/print?limit=0&keymap=${keymap}`, function() { + if (http.readyState === 4) { + wm.setElementEnabled($("hid-pak-text"), true); + wm.setElementEnabled($("hid-pak-button"), true); + wm.setElementEnabled($("hid-pak-keymap-selector"), true); + $("hid-pak-text").value = ""; + if (http.status === 413) { + wm.error("Too many text for paste!"); + } else if (http.status !== 200) { + wm.error("HID paste error:<br>", http.responseText); + } else if (http.status === 200) { + __recorder.recordPrintEvent(text); } - }, text, "text/plain"); - } else { - $("hid-pak-text").value = ""; - } - }); + } + }, text, "text/plain"); + }; + + if ($("hid-pak-ask-switch").checked) { + let confirm_msg = `You're going to paste ${text.length} character${text.length ? "s" : ""}.<br>`; + confirm_msg += "Are you sure you want to continue?"; + wm.confirm(confirm_msg).then(function(ok) { + if (ok) { + paste_as_keys(); + } else { + $("hid-pak-text").value = ""; + } + }); + } else { + paste_as_keys(); + } } }; diff --git a/web/share/js/kvm/session.js b/web/share/js/kvm/session.js index 5aa0a6a0..b278dd06 100644 --- a/web/share/js/kvm/session.js +++ b/web/share/js/kvm/session.js @@ -221,6 +221,7 @@ export function Session() { case "wol_state": __wol.setState(data.event); break; case "gpio_model_state": __gpio.setModel(data.event); break; case "gpio_state": __gpio.setState(data.event); break; + case "hid_keymaps_state": __hid.setKeymaps(data.event); break; case "hid_state": __hid.setState(data.event); break; case "atx_state": __atx.setState(data.event); break; case "msd_state": __msd.setState(data.event); break; |