diff options
author | Devaev Maxim <[email protected]> | 2019-04-24 22:32:53 +0300 |
---|---|---|
committer | Devaev Maxim <[email protected]> | 2019-04-24 22:32:53 +0300 |
commit | 3d64401b111d863072c74e81e49de68885c0e084 (patch) | |
tree | b342b911f0836f65fee8163c77c54d004661f2da /web/share | |
parent | 3ecd337b3a259432546e883bc82d83389e0d6aba (diff) |
ipad mouse buttons, keyboard refactoring
Diffstat (limited to 'web/share')
-rw-r--r-- | web/share/css/keypad.css | 134 | ||||
-rw-r--r-- | web/share/css/kvm/keyboard.css | 111 | ||||
-rw-r--r-- | web/share/js/keypad.js | 175 | ||||
-rw-r--r-- | web/share/js/kvm/hid.js | 3 | ||||
-rw-r--r-- | web/share/js/kvm/keyboard.js | 124 | ||||
-rw-r--r-- | web/share/js/kvm/mouse.js | 36 | ||||
-rw-r--r-- | web/share/js/tools.js | 6 |
7 files changed, 350 insertions, 239 deletions
diff --git a/web/share/css/keypad.css b/web/share/css/keypad.css new file mode 100644 index 00000000..c0370fd4 --- /dev/null +++ b/web/share/css/keypad.css @@ -0,0 +1,134 @@ +/***************************************************************************** +# # +# KVMD - The main Pi-KVM daemon. # +# # +# Copyright (C) 2018 Maxim Devaev <[email protected]> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <https://www.gnu.org/licenses/>. # +# # +*****************************************************************************/ + + +div.keypad { + zoom: 0.8; +} + +div.keypad div.keypad-block { + display: table-cell; + padding-right: 0; +} +div.keypad div.keypad-block:not(:first-child) { + padding-left: 15px; +} + +div.keypad div.keypad-row { + white-space: nowrap; + height: 40px; + margin-bottom: 5px; +} +div.keypad div.keypad-row:last-child { + margin-bottom: 0; +} + +div.keypad div.key, div.modifier, div.empty-key { + box-sizing: border-box; + display: inline-block; + margin-right: 5px; + padding: 0; + width: 40px; +} +div.keypad div.key, div.modifier { + font-size: 0.9em; + text-align: center; + vertical-align: top; + box-shadow: var(--shadow-micro); + border: var(--border-key-thin); + border-radius: 6px; + color: var(--cs-key-default-fg); + background-color: var(--cs-key-default-bg); + cursor: pointer; + height: 40px; +} +div.keypad div.key:hover, div.modifier:hover { + color: var(--cs-key-hovered-fg); + background-color: var(--cs-key-hovered-bg); +} +div.keypad div.pressed { + box-shadow: none; + color: var(--cs-key-pressed-fg) !important; + background-color: var(--cs-key-pressed-bg) !important; +} +div.keypad div.holded { + box-shadow: none; + color: var(--cs-key-default-fg) !important; + background-color: var(--cs-key-holded-bg) !important; +} +div.keypad div.key:last-child, div.empty-key:last-child, div.modifier:last-child { + margin-right: 0; +} +div.keypad div.margin-0 { + margin-right: 0px; +} +div.keypad div.wide-0 { + width: 26px; +} +div.keypad div.wide-1 { + width: 61px; +} +div.keypad div.wide-2 { + width: 64px; +} +div.keypad div.wide-3 { + width: 77px; +} +div.keypad div.wide-4 { + width: 102px; +} +div.keypad div.wide-5 { + width: 288px; +} +div.keypad div.left { + text-align: left !important; + padding-left: 6px !important; +} +div.keypad div.right { + text-align: right !important; + padding-right: 6px !important; +} +div.keypad div.small { + font-size: 0.7em; +} + +div.keypad p { + margin: 0; + position: relative; + top: 50%; + -webkit-transform: translateY(-50%); + transform: translateY(-50%); +} +div.keypad b { + color: var(--cs-key-holded-bg); +} + +@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) { + /* iPad */ + div.keypad { + zoom: 1.28 !important; + } + + div.keypad div.key:hover, div.modifier:hover { + color: var(--cs-key-default-fg); + background-color: var(--cs-key-default-bg); + } +} diff --git a/web/share/css/kvm/keyboard.css b/web/share/css/kvm/keyboard.css index 601c6a59..5f7480b4 100644 --- a/web/share/css/kvm/keyboard.css +++ b/web/share/css/kvm/keyboard.css @@ -20,107 +20,6 @@ *****************************************************************************/ -div.keyboard { - zoom: 0.8; -} - -div.keyboard div.keyboard-block { - display: table-cell; - padding-right: 0; -} -div.keyboard div.keyboard-block:not(:first-child) { - padding-left: 15px; -} - -div.keyboard div.keyboard-row { - white-space: nowrap; - height: 40px; - margin-bottom: 5px; -} -div.keyboard div.keyboard-row:last-child { - margin-bottom: 0; -} - -div.keyboard div.key, div.modifier, div.empty-key { - box-sizing: border-box; - display: inline-block; - margin-right: 5px; - padding: 0; - width: 40px; -} -div.keyboard div.key, div.modifier { - font-size: 0.9em; - text-align: center; - vertical-align: top; - box-shadow: var(--shadow-micro); - border: var(--border-key-thin); - border-radius: 6px; - color: var(--cs-key-default-fg); - background-color: var(--cs-key-default-bg); - cursor: pointer; - height: 40px; -} -div.keyboard div.key:hover, div.modifier:hover { - color: var(--cs-key-hovered-fg); - background-color: var(--cs-key-hovered-bg); -} -div.keyboard div.pressed { - box-shadow: none; - color: var(--cs-key-pressed-fg) !important; - background-color: var(--cs-key-pressed-bg) !important; -} -div.keyboard div.holded { - box-shadow: none; - color: var(--cs-key-default-fg) !important; - background-color: var(--cs-key-holded-bg) !important; -} -div.keyboard div.key:last-child, div.empty-key:last-child, div.modifier:last-child { - margin-right: 0; -} -div.keyboard div.margin-0 { - margin-right: 0px; -} -div.keyboard div.wide-0 { - width: 26px; -} -div.keyboard div.wide-1 { - width: 61px; -} -div.keyboard div.wide-2 { - width: 64px; -} -div.keyboard div.wide-3 { - width: 77px; -} -div.keyboard div.wide-4 { - width: 102px; -} -div.keyboard div.wide-5 { - width: 288px; -} -div.keyboard div.left { - text-align: left !important; - padding-left: 6px !important; -} -div.keyboard div.right { - text-align: right !important; - padding-right: 6px !important; -} -div.keyboard div.small { - font-size: 0.7em; -} - -div.keyboard p { - margin: 0; - position: relative; - top: 50%; - -webkit-transform: translateY(-50%); - transform: translateY(-50%); -} -div.keyboard b { - color: var(--cs-key-holded-bg); -} - @media only screen and (min-device-width: 768px) and (max-device-width: 1024px) { div#keyboard-window { visibility: visible !important; @@ -149,16 +48,6 @@ div#keyboard-mobile { display: none; } @media only screen and (min-device-width: 768px) and (max-device-width: 1024px) { - /* iPad */ - div.keyboard { - zoom: 1.28 !important; - } - - div.keyboard div.key:hover, div.modifier:hover { - color: var(--cs-key-default-fg); - background-color: var(--cs-key-default-bg); - } - div#keyboard-desktop { display: none !important; } diff --git a/web/share/js/keypad.js b/web/share/js/keypad.js new file mode 100644 index 00000000..e8da1533 --- /dev/null +++ b/web/share/js/keypad.js @@ -0,0 +1,175 @@ +/***************************************************************************** +# # +# KVMD - The main Pi-KVM daemon. # +# # +# Copyright (C) 2018 Maxim Devaev <[email protected]> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <https://www.gnu.org/licenses/>. # +# # +*****************************************************************************/ + + +function Keypad(keys_parent, key_callback) { + var self = this; + + /************************************************************************/ + + var __merged = {}; + var __keys = {}; + var __modifiers = {}; + + var __init__ = function() { + var code; + var el_key; + + for (el_key of $$$(keys_parent + " div.key")) { + code = el_key.getAttribute("data-code"); + + tools.setDefault(__keys, code, []); + __keys[code].push(el_key); + + tools.setDefault(__merged, code, []); + __merged[code].push(el_key); + + (function(el_key) { + tools.setOnDown(el_key, () => __clickHandler(el_key, true)); + tools.setOnUp(el_key, () => __clickHandler(el_key, false)); + el_key.onmouseout = function() { + if (__isPressed(el_key)) { + __clickHandler(el_key, false); + } + }; + })(el_key); + } + + for (el_key of $$$(keys_parent + " div.modifier")) { + code = el_key.getAttribute("data-code"); + + tools.setDefault(__modifiers, code, []); + __modifiers[code].push(el_key); + + tools.setDefault(__merged, code, []); + __merged[code].push(el_key); + + (function(el_key) { + tools.setOnDown(el_key, () => __toggleModifierHandler(el_key)); + })(el_key); + } + }; + + /************************************************************************/ + + self.releaseAll = function(release_hook=false) { + for (var dict of [__keys, __modifiers]) { + for (var code in dict) { + if (__isActive(dict[code][0])) { + self.emit(code, false, release_hook); + } + } + } + }; + + self.emit = function(code, state, release_hook=false) { + if (code in __merged) { + __commonHandler(__merged[code][0], state, false); + if (release_hook) { + for (code in __keys) { + if (__isActive(__keys[code][0])) { + self.emit(code, false); + } + } + } + __unholdModifiers(); + } + }; + + var __clickHandler = function(el_key, state) { + __commonHandler(el_key, state, false); + __unholdModifiers(); + }; + + var __toggleModifierHandler = function(el_key) { + __commonHandler(el_key, !__isActive(el_key), true); + }; + + var __commonHandler = function(el_key, state, hold) { + if (state && !__isActive(el_key)) { + __deactivate(el_key); + __activate(el_key, (hold ? "holded" : "pressed")); + __process(el_key, true); + } else { + __deactivate(el_key); + __process(el_key, false); + } + }; + + var __unholdModifiers = function() { + for (var code in __modifiers) { + var el_key = __modifiers[code][0]; + if (__isHolded(el_key)) { + __deactivate(el_key); + __process(el_key, false); + } + } + }; + + var __isPressed = function(el_key) { + var is_pressed = false; + for (el_key of __resolveKeys(el_key)) { + is_pressed = (is_pressed || el_key.classList.contains("pressed")); + } + return is_pressed; + }; + + var __isHolded = function(el_key) { + var is_holded = false; + for (el_key of __resolveKeys(el_key)) { + is_holded = (is_holded || el_key.classList.contains("holded")); + } + return is_holded; + }; + + var __isActive = function(el_key) { + var is_active = false; + for (el_key of __resolveKeys(el_key)) { + is_active = (is_active || el_key.classList.contains("pressed") || el_key.classList.contains("holded")); + } + return is_active; + }; + + var __activate = function(el_key, cls) { + for (el_key of __resolveKeys(el_key)) { + el_key.classList.add(cls); + } + }; + + var __deactivate = function(el_key) { + for (el_key of __resolveKeys(el_key)) { + el_key.classList.remove("pressed"); + el_key.classList.remove("holded"); + } + }; + + var __resolveKeys = function(el_key) { + var code = el_key.getAttribute("data-code"); + return __merged[code]; + }; + + var __process = function(el_key, state) { + var code = el_key.getAttribute("data-code"); + key_callback(code, state); + }; + + __init__(); +} diff --git a/web/share/js/kvm/hid.js b/web/share/js/kvm/hid.js index 9ecc4be5..c731843c 100644 --- a/web/share/js/kvm/hid.js +++ b/web/share/js/kvm/hid.js @@ -91,6 +91,7 @@ function Hid() { var __releaseAll = function() { __keyboard.releaseAll(); + __mouse.releaseAll(); }; var __emitShortcut = function(codes) { @@ -107,7 +108,7 @@ function Hid() { var index = 0; var iterate = () => setTimeout(function() { - __keyboard.fireEvent(raw_events[index].code, raw_events[index].state); + __keyboard.emit(raw_events[index].code, raw_events[index].state); ++index; if (index < raw_events.length) { iterate(); diff --git a/web/share/js/kvm/keyboard.js b/web/share/js/kvm/keyboard.js index 189abb2c..23d5665d 100644 --- a/web/share/js/kvm/keyboard.js +++ b/web/share/js/kvm/keyboard.js @@ -28,10 +28,12 @@ function Keyboard() { var __ws = null; var __online = true; - var __keys = [].slice.call($$$("div#keyboard-desktop div.keyboard-block div.keyboard-row div.key")); - var __modifiers = [].slice.call($$$("div#keyboard-desktop div.keyboard-block div.keyboard-row div.modifier")); + var __keypad = null; + var __use_release_hook = false; var __init__ = function() { + __keypad = new Keypad("div#keyboard-window", __sendKey); + $("hid-keyboard-led").title = "Keyboard free"; $("keyboard-window").onkeydown = (event) => __keyboardHandler(event, true); @@ -47,22 +49,11 @@ function Keyboard() { window.addEventListener("focusin", __updateLeds); window.addEventListener("focusout", __updateLeds); - tools.forEach($$("key"), function(el_key) { - tools.setOnDown(el_key, () => __clickHandler(el_key, true)); - tools.setOnUp(el_key, () => __clickHandler(el_key, false)); - el_key.onmouseout = function() { - if (__isPressed(el_key)) { - __clickHandler(el_key, false); - } - }; - }); - - tools.forEach($$("modifier"), function(el_key) { - tools.setOnDown(el_key, () => __toggleModifierHandler(el_key)); - }); - if (tools.browser.is_mac) { + // https://bugs.chromium.org/p/chromium/issues/detail?id=28089 + // https://bugzilla.mozilla.org/show_bug.cgi?id=1299553 tools.info("Keyboard: enabled Mac-CMD-Hook"); + __use_release_hook = true; } }; @@ -82,14 +73,10 @@ function Keyboard() { }; self.releaseAll = function() { - __keys.concat(__modifiers).forEach(function(el_key) { - if (__isActive(el_key)) { - self.fireEvent(el_key.getAttribute("data-key"), false); - } - }); + __keypad.releaseAll(__use_release_hook); }; - self.fireEvent = function(code, state) { + self.emit = function(code, state) { __keyboardHandler({code: code}, state); }; @@ -124,97 +111,14 @@ function Keyboard() { if (event.preventDefault) { event.preventDefault(); } - var el_key = document.querySelector(`[data-key='${event.code}']`); - if (el_key && !event.repeat) { - __commonHandler(el_key, state, "pressed"); - if (tools.browser.is_mac) { - // https://bugs.chromium.org/p/chromium/issues/detail?id=28089 - // https://bugzilla.mozilla.org/show_bug.cgi?id=1299553 - if ((event.code === "MetaLeft" || event.code === "MetaRight") && !state) { - __keys.forEach(function(el_key) { - if (__isActive(el_key)) { - self.fireEvent(el_key.getAttribute("data-key"), false); - } - }); - } - } - __unholdModifiers(); - } - }; - - var __clickHandler = function(el_key, state) { - __commonHandler(el_key, state, "pressed"); - __unholdModifiers(); - }; - - var __toggleModifierHandler = function(el_key) { - __commonHandler(el_key, !__isActive(el_key), "holded"); - }; - - var __unholdModifiers = function() { - __modifiers.forEach(function(el_key) { - if (__isHolded(el_key)) { - __deactivate(el_key); - __sendKey(el_key, false); - } - }); - }; - - var __commonHandler = function(el_key, state, cls) { - if (state && !__isActive(el_key)) { - __deactivate(el_key); - __activate(el_key, cls); - __sendKey(el_key, true); - } else { - __deactivate(el_key); - __sendKey(el_key, false); + if (!event.repeat) { + // https://bugs.chromium.org/p/chromium/issues/detail?id=28089 + // https://bugzilla.mozilla.org/show_bug.cgi?id=1299553 + __keypad.emit(event.code, state, __use_release_hook); } }; - var __isPressed = function(el_key) { - var is_pressed = false; - tools.forEach(__resolveKeys(el_key), function(el_key) { - is_pressed = (is_pressed || el_key.classList.contains("pressed")); - }); - return is_pressed; - }; - - var __isHolded = function(el_key) { - var is_holded = false; - tools.forEach(__resolveKeys(el_key), function(el_key) { - is_holded = (is_holded || el_key.classList.contains("holded")); - }); - return is_holded; - }; - - var __isActive = function(el_key) { - var is_active = false; - tools.forEach(__resolveKeys(el_key), function(el_key) { - is_active = (is_active || el_key.classList.contains("pressed") || el_key.classList.contains("holded")); - }); - return is_active; - }; - - var __activate = function(el_key, cls) { - tools.forEach(__resolveKeys(el_key), function(el_key) { - el_key.classList.add(cls); - }); - }; - - var __deactivate = function(el_key) { - tools.forEach(__resolveKeys(el_key), function(el_key) { - el_key.classList.remove("pressed"); - el_key.classList.remove("holded"); - }); - }; - - var __resolveKeys = function(el_key) { - var code = el_key.getAttribute("data-key"); - return $$$(`[data-key='${code}']`); - }; - - var __sendKey = function(el_key, state) { - var code = el_key.getAttribute("data-key"); + var __sendKey = function(code, state) { tools.debug("Keyboard: key", (state ? "pressed:" : "released:"), code); if (__ws) { __ws.send(JSON.stringify({ diff --git a/web/share/js/kvm/mouse.js b/web/share/js/kvm/mouse.js index 1b93e6ab..e63a639a 100644 --- a/web/share/js/kvm/mouse.js +++ b/web/share/js/kvm/mouse.js @@ -28,6 +28,8 @@ function Mouse() { var __ws = null; var __online = true; + var __keypad = null; + var __current_pos = {x: 0, y:0}; var __sent_pos = {x: 0, y:0}; var __wheel_delta = {x: 0, y: 0}; @@ -35,22 +37,18 @@ function Mouse() { var __stream_hovered = false; var __init__ = function() { + __keypad = new Keypad("div#stream-mouse-buttons", __sendButton); + $("hid-mouse-led").title = "Mouse free"; $("stream-box").onmouseenter = __hoverStream; $("stream-box").onmouseleave = __leaveStream; - $("stream-box").onmousedown = (event) => __buttonHandler(event, true); - $("stream-box").onmouseup = (event) => __buttonHandler(event, false); + $("stream-box").onmousedown = (event) => __streamButtonHandler(event, true); + $("stream-box").onmouseup = (event) => __streamButtonHandler(event, false); $("stream-box").oncontextmenu = (event) => event.preventDefault(); - $("stream-box").onmousemove = __moveHandler; - $("stream-box").onwheel = __wheelHandler; - $("stream-box").ontouchstart = (event) => __touchMoveHandler(event); - - tools.forEach($$$("[data-mouse-button]"), function(el_button) { - var button = el_button.getAttribute("data-mouse-button"); - tools.setOnDown(el_button, () => __sendButton(button, true)); - tools.setOnUp(el_button, () => __sendButton(button, false)); - }); + $("stream-box").onmousemove = __streamMoveHandler; + $("stream-box").onwheel = __streamWheelHandler; + $("stream-box").ontouchstart = (event) => __streamTouchMoveHandler(event); setInterval(__sendMove, 100); }; @@ -72,6 +70,10 @@ function Mouse() { __updateLeds(); }; + self.releaseAll = function() { + __keypad.releaseAll(); + }; + var __hoverStream = function() { __stream_hovered = true; __updateLeds(); @@ -106,16 +108,16 @@ function Mouse() { $("hid-mouse-led").title = title; }; - var __buttonHandler = function(event, state) { + var __streamButtonHandler = function(event, state) { // https://www.w3schools.com/jsref/event_button.asp event.preventDefault(); switch (event.button) { - case 0: __sendButton("left", state); break; - case 2: __sendButton("right", state); break; + case 0: __keypad.emit("left", state); break; + case 2: __keypad.emit("right", state); break; } }; - var __touchMoveHandler = function(event) { + var __streamTouchMoveHandler = function(event) { event.preventDefault(); if (event.touches[0].target && event.touches[0].target.getBoundingClientRect) { var rect = event.touches[0].target.getBoundingClientRect(); @@ -127,7 +129,7 @@ function Mouse() { } }; - var __moveHandler = function(event) { + var __streamMoveHandler = function(event) { var rect = event.target.getBoundingClientRect(); __current_pos = { x: Math.round(event.clientX - rect.left), @@ -172,7 +174,7 @@ function Mouse() { return Math.round((x - a) / (b - a) * (d - c) + c); }; - var __wheelHandler = function(event) { + var __streamWheelHandler = function(event) { // https://learn.javascript.ru/mousewheel if (event.preventDefault) { event.preventDefault(); diff --git a/web/share/js/tools.js b/web/share/js/tools.js index 89b90978..0cae6566 100644 --- a/web/share/js/tools.js +++ b/web/share/js/tools.js @@ -25,6 +25,12 @@ var tools = new function() { this.forEach = (...args) => Array.prototype.forEach.call(...args); + this.setDefault = function(dict, key, value) { + if (!(key in dict)) { + dict[key] = value; + } + }; + this.makeRequest = function(method, url, callback, body=null, content_type=null) { var http = new XMLHttpRequest(); http.open(method, url, true); |