This commit is contained in:
Devaev Maxim 2021-04-16 23:45:11 +03:00
parent ba1e636686
commit 5794fb1c46
7 changed files with 134 additions and 60 deletions

View File

@ -108,19 +108,22 @@ class HidApi:
# ===== # =====
@exposed_http("GET", "/hid/keymaps") def get_keymaps(self) -> Dict: # Ugly hack to generate hid_keymaps_state (see server.py)
async def __keymaps_handler(self, _: Request) -> Response:
keymaps: Set[str] = set() keymaps: Set[str] = set()
for keymap_name in os.listdir(self.__keymaps_dir_path): for keymap_name in os.listdir(self.__keymaps_dir_path):
path = os.path.join(self.__keymaps_dir_path, keymap_name) 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): if os.access(path, os.R_OK) and stat.S_ISREG(os.stat(path).st_mode):
keymaps.add(keymap_name) keymaps.add(keymap_name)
return make_json_response({ return {
"keymaps": { "keymaps": {
"default": self.__default_keymap_name, "default": self.__default_keymap_name,
"available": sorted(keymaps), "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") @exposed_http("POST", "/hid/print")
async def __print_handler(self, request: Request) -> Response: async def __print_handler(self, request: Request) -> Response:

View File

@ -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.__apis: List[object] = [
self, self,
AuthApi(auth_manager), AuthApi(auth_manager),
@ -202,7 +203,7 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins
LogApi(log_reader), LogApi(log_reader),
WolApi(wol), WolApi(wol),
UserGpioApi(user_gpio), UserGpioApi(user_gpio),
HidApi(hid, keymap_path, mouse_x_range, mouse_y_range), self.__hid_api,
AtxApi(atx), AtxApi(atx),
MsdApi(msd, sync_chunk_size), MsdApi(msd, sync_chunk_size),
StreamerApi(streamer), StreamerApi(streamer),
@ -263,6 +264,7 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins
await self.__register_ws_client(client) await self.__register_ws_client(client)
try: try:
await self.__send_event(client.ws, "gpio_model_state", await self.__user_gpio.get_model()) 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(*[ await asyncio.gather(*[
self.__send_event(client.ws, component.event_type, await component.get_state()) self.__send_event(client.ws, component.event_type, await component.get_state())
for component in self.__components for component in self.__components

View File

@ -415,25 +415,58 @@
</li> </li>
<li class="right"><a class="menu-button" href="#">Shortcuts</a> <li class="right"><a class="menu-button" href="#">Shortcuts</a>
<div class="menu" data-dont-hide-menu> <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">&bull; 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"> <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">&bull; &#x21b3; Paste-as-Keys <sup><i>ascii-only</i></sup></button>
<hr>
<div class="buttons-row"> <div class="buttons-row">
<button class="row50" data-force-hide-menu data-shortcut="CapsLock">&bull; Caps Lock &nbsp;<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="CapsLock">&bull; Caps Lock &nbsp;<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">&bull; Left Win</button> <button class="row50" data-force-hide-menu data-shortcut="MetaLeft">&bull; Left Win</button>
</div> </div>
<hr> <hr>
<button data-force-hide-menu data-shortcut="AltLeft ShiftLeft">&bull; Alt+Shift</button> <div class="buttons-row">
<button data-force-hide-menu data-shortcut="ControlLeft ShiftLeft">&bull; Ctrl+Shift</button> <button class="row50" data-force-hide-menu data-shortcut="AltLeft ShiftLeft">&bull; Alt+Shift</button>
<button data-force-hide-menu data-shortcut="ShiftLeft ShiftRight">&bull; Shift+Shift</button> <button class="row50" data-force-hide-menu data-shortcut="ControlLeft KeyW">&bull; Ctrl+W</button>
<button data-force-hide-menu data-shortcut="MetaLeft Space">&bull; Win+Space</button> </div>
<hr> <div class="buttons-row">
<button data-force-hide-menu data-shortcut="ControlLeft KeyW">&bull; Ctrl+W</button> <button class="row50" data-force-hide-menu data-shortcut="ControlLeft ShiftLeft">&bull; Ctrl+Shift</button>
<button data-force-hide-menu data-shortcut="AltLeft Tab">&bull; Alt+Tab</button> <button class="row50" data-force-hide-menu data-shortcut="AltLeft Tab">&bull; Alt+Tab</button>
<button data-force-hide-menu data-shortcut="AltLeft Enter">&bull; Alt+Enter</button> </div>
<button data-force-hide-menu data-shortcut="AltLeft F4">&bull; Alt+F4</button> <div class="buttons-row">
<button class="row50" data-force-hide-menu data-shortcut="ShiftLeft ShiftRight">&bull; Shift+Shift</button>
<button class="row50" data-force-hide-menu data-shortcut="AltLeft Enter">&bull; Alt+Enter</button>
</div>
<div class="buttons-row">
<button class="row50" data-force-hide-menu data-shortcut="MetaLeft Space">&bull; Win+Space</button>
<button class="row50" data-force-hide-menu data-shortcut="AltLeft F4">&bull; Alt+F4</button>
</div>
<hr> <hr>
<button data-force-hide-menu data-shortcut="ControlLeft AltLeft Delete">&bull; Ctrl+Alt+Del</button> <button data-force-hide-menu data-shortcut="ControlLeft AltLeft Delete">&bull; Ctrl+Alt+Del</button>
</div> </div>

View File

@ -1,26 +1,43 @@
li(class="right") li(class="right")
a(class="menu-button" href="#") Shortcuts a(class="menu-button" href="#") Shortcuts
div(data-dont-hide-menu class="menu") 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") &bull; 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") div(class="buttons")
textarea(id="hid-pak-text" placeholder="Paste your text here")
hr
button(disabled data-force-hide-menu id="hid-pak-button") &bull; &#x21b3; Paste-as-Keys #[sup #[i ascii-only]]
hr
div(class="buttons-row") div(class="buttons-row")
button(data-force-hide-menu data-shortcut="CapsLock" class="row50") button(data-force-hide-menu data-shortcut="CapsLock" class="row50")
| &bull; Caps Lock &nbsp; | &bull; Caps Lock &nbsp;
img(class="inline-lamp hid-keyboard-caps-led led-gray" src=`${svg_dir}/led-square.svg`) 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") &bull; Left Win button(data-force-hide-menu data-shortcut="MetaLeft" class="row50") &bull; Left Win
hr hr
button(data-force-hide-menu data-shortcut="AltLeft ShiftLeft") &bull; Alt+Shift div(class="buttons-row")
button(data-force-hide-menu data-shortcut="ControlLeft ShiftLeft") &bull; Ctrl+Shift button(data-force-hide-menu data-shortcut="AltLeft ShiftLeft" class="row50") &bull; Alt+Shift
button(data-force-hide-menu data-shortcut="ShiftLeft ShiftRight") &bull; Shift+Shift button(data-force-hide-menu data-shortcut="ControlLeft KeyW" class="row50") &bull; Ctrl+W
button(data-force-hide-menu data-shortcut="MetaLeft Space") &bull; Win+Space div(class="buttons-row")
hr button(data-force-hide-menu data-shortcut="ControlLeft ShiftLeft" class="row50") &bull; Ctrl+Shift
button(data-force-hide-menu data-shortcut="ControlLeft KeyW") &bull; Ctrl+W button(data-force-hide-menu data-shortcut="AltLeft Tab" class="row50") &bull; Alt+Tab
button(data-force-hide-menu data-shortcut="AltLeft Tab") &bull; Alt+Tab div(class="buttons-row")
button(data-force-hide-menu data-shortcut="AltLeft Enter") &bull; Alt+Enter button(data-force-hide-menu data-shortcut="ShiftLeft ShiftRight" class="row50") &bull; Shift+Shift
button(data-force-hide-menu data-shortcut="AltLeft F4") &bull; Alt+F4 button(data-force-hide-menu data-shortcut="AltLeft Enter" class="row50") &bull; Alt+Enter
div(class="buttons-row")
button(data-force-hide-menu data-shortcut="MetaLeft Space" class="row50") &bull; Win+Space
button(data-force-hide-menu data-shortcut="AltLeft F4" class="row50") &bull; Alt+F4
hr hr
button(data-force-hide-menu data-shortcut="ControlLeft AltLeft Delete") &bull; Ctrl+Alt+Del button(data-force-hide-menu data-shortcut="ControlLeft AltLeft Delete") &bull; Ctrl+Alt+Del
hr hr

View File

@ -23,22 +23,21 @@
textarea#hid-pak-text { textarea#hid-pak-text {
display: block; display: block;
resize: none; resize: none;
height: 60px;
width: 100%; width: 100%;
height: 40px; border-radius: 4px;
color: var(--cs-window-default-fg); color: var(--cs-window-default-fg);
background-color: var(--cs-window-default-bg); background-color: var(--cs-window-default-bg);
border: none;
outline: 0 !important;
-webkit-appearance:none; -webkit-appearance:none;
} }
textarea#hid-pak-text::-moz-placeholder { textarea#hid-pak-text::-moz-placeholder {
line-height: 40px; line-height: 60px;
text-align: center; text-align: center;
} }
textarea#hid-pak-text::-webkit-input-placeholder { textarea#hid-pak-text::-webkit-input-placeholder {
line-height: 40px; line-height: 60px;
text-align: center; text-align: center;
} }

View File

@ -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() { var __releaseAll = function() {
__keyboard.releaseAll(); __keyboard.releaseAll();
__mouse.releaseAll(); __mouse.releaseAll();
@ -196,34 +204,45 @@ export function Hid() {
var __clickPasteAsKeysButton = function() { var __clickPasteAsKeysButton = function() {
let text = $("hid-pak-text").value.replace(/[^\x00-\x7F]/g, ""); // eslint-disable-line no-control-regex let text = $("hid-pak-text").value.replace(/[^\x00-\x7F]/g, ""); // eslint-disable-line no-control-regex
if (text) { if (text) {
let confirm_msg = `You're going to paste ${text.length} character${text.length ? "s" : ""}.<br>`; let paste_as_keys = function() {
confirm_msg += "Are you sure you want to continue?"; wm.setElementEnabled($("hid-pak-text"), false);
wm.setElementEnabled($("hid-pak-button"), false);
wm.setElementEnabled($("hid-pak-keymap-selector"), false);
wm.confirm(confirm_msg).then(function(ok) { let keymap = $("hid-pak-keymap-selector").value;
if (ok) {
wm.setElementEnabled($("hid-pak-text"), false);
wm.setElementEnabled($("hid-pak-button"), false);
tools.debug("HID: paste-as-keys:", text); tools.debug(`HID: paste-as-keys ${keymap}: ${text}`);
let http = tools.makeRequest("POST", "/api/hid/print?limit=0", function() { let http = tools.makeRequest("POST", `/api/hid/print?limit=0&keymap=${keymap}`, function() {
if (http.readyState === 4) { if (http.readyState === 4) {
wm.setElementEnabled($("hid-pak-text"), true); wm.setElementEnabled($("hid-pak-text"), true);
wm.setElementEnabled($("hid-pak-button"), true); wm.setElementEnabled($("hid-pak-button"), true);
$("hid-pak-text").value = ""; wm.setElementEnabled($("hid-pak-keymap-selector"), true);
if (http.status === 413) { $("hid-pak-text").value = "";
wm.error("Too many text for paste!"); if (http.status === 413) {
} else if (http.status !== 200) { wm.error("Too many text for paste!");
wm.error("HID paste error:<br>", http.responseText); } else if (http.status !== 200) {
} else if (http.status === 200) { wm.error("HID paste error:<br>", http.responseText);
__recorder.recordPrintEvent(text); } else if (http.status === 200) {
} __recorder.recordPrintEvent(text);
} }
}, text, "text/plain"); }
} else { }, text, "text/plain");
$("hid-pak-text").value = ""; };
}
}); 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();
}
} }
}; };

View File

@ -221,6 +221,7 @@ export function Session() {
case "wol_state": __wol.setState(data.event); break; case "wol_state": __wol.setState(data.event); break;
case "gpio_model_state": __gpio.setModel(data.event); break; case "gpio_model_state": __gpio.setModel(data.event); break;
case "gpio_state": __gpio.setState(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 "hid_state": __hid.setState(data.event); break;
case "atx_state": __atx.setState(data.event); break; case "atx_state": __atx.setState(data.event); break;
case "msd_state": __msd.setState(data.event); break; case "msd_state": __msd.setState(data.event); break;