Merge main into branch
This commit is contained in:
commit
08198a6781
|
@ -66,8 +66,9 @@ profits such as:
|
||||||
RSA-AES, Tight, VeNCrypt Plain, XVP, Apple's Diffie-Hellman,
|
RSA-AES, Tight, VeNCrypt Plain, XVP, Apple's Diffie-Hellman,
|
||||||
UltraVNC's MSLogonII
|
UltraVNC's MSLogonII
|
||||||
* Supported VNC encodings: raw, copyrect, rre, hextile, tight, tightPNG,
|
* Supported VNC encodings: raw, copyrect, rre, hextile, tight, tightPNG,
|
||||||
ZRLE, JPEG, Zlib
|
ZRLE, JPEG, Zlib, H.264
|
||||||
* Supports scaling, clipping and resizing the desktop
|
* Supports scaling, clipping and resizing the desktop
|
||||||
|
* Supports back & forward mouse buttons
|
||||||
* Local cursor rendering
|
* Local cursor rendering
|
||||||
* Clipboard copy/paste with full Unicode support
|
* Clipboard copy/paste with full Unicode support
|
||||||
* Translations
|
* Translations
|
||||||
|
@ -142,7 +143,7 @@ If you want to use certificate files, due to standard snap confinement restricti
|
||||||
#### Running noVNC from snap as a service (daemon)
|
#### Running noVNC from snap as a service (daemon)
|
||||||
The snap package also has the capability to run a 'novnc' service which can be
|
The snap package also has the capability to run a 'novnc' service which can be
|
||||||
configured to listen on multiple ports connecting to multiple VNC servers
|
configured to listen on multiple ports connecting to multiple VNC servers
|
||||||
(effectively a service runing multiple instances of novnc).
|
(effectively a service running multiple instances of novnc).
|
||||||
Instructions (with example values):
|
Instructions (with example values):
|
||||||
|
|
||||||
List current services (out-of-box this will be blank):
|
List current services (out-of-box this will be blank):
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
{
|
{
|
||||||
"HTTPS is required for full functionality": "すべての機能を使用するにはHTTPS接続が必要です",
|
"Running without HTTPS is not recommended, crashes or other issues are likely.": "HTTPS接続なしで実行することは推奨されません。クラッシュしたりその他の問題が発生したりする可能性があります。",
|
||||||
"Connecting...": "接続しています...",
|
"Connecting...": "接続しています...",
|
||||||
"Disconnecting...": "切断しています...",
|
"Disconnecting...": "切断しています...",
|
||||||
"Reconnecting...": "再接続しています...",
|
"Reconnecting...": "再接続しています...",
|
||||||
"Internal error": "内部エラー",
|
"Internal error": "内部エラー",
|
||||||
"Must set host": "ホストを設定する必要があります",
|
"Must set host": "ホストを設定する必要があります",
|
||||||
|
"Failed to connect to server: ": "サーバーへの接続に失敗しました: ",
|
||||||
"Connected (encrypted) to ": "接続しました (暗号化済み): ",
|
"Connected (encrypted) to ": "接続しました (暗号化済み): ",
|
||||||
"Connected (unencrypted) to ": "接続しました (暗号化されていません): ",
|
"Connected (unencrypted) to ": "接続しました (暗号化されていません): ",
|
||||||
"Something went wrong, connection is closed": "何らかの問題で、接続が閉じられました",
|
"Something went wrong, connection is closed": "問題が発生したため、接続が閉じられました",
|
||||||
"Failed to connect to server": "サーバーへの接続に失敗しました",
|
"Failed to connect to server": "サーバーへの接続に失敗しました",
|
||||||
"Disconnected": "切断しました",
|
"Disconnected": "切断しました",
|
||||||
"New connection has been rejected with reason: ": "新規接続は次の理由で拒否されました: ",
|
"New connection has been rejected with reason: ": "新規接続は次の理由で拒否されました: ",
|
||||||
|
@ -48,7 +49,7 @@
|
||||||
"Clip to window": "ウィンドウにクリップ",
|
"Clip to window": "ウィンドウにクリップ",
|
||||||
"Scaling mode:": "スケーリングモード:",
|
"Scaling mode:": "スケーリングモード:",
|
||||||
"None": "なし",
|
"None": "なし",
|
||||||
"Local scaling": "ローカルスケーリング",
|
"Local scaling": "ローカルでスケーリング",
|
||||||
"Remote resizing": "リモートでリサイズ",
|
"Remote resizing": "リモートでリサイズ",
|
||||||
"Advanced": "高度",
|
"Advanced": "高度",
|
||||||
"Quality:": "品質:",
|
"Quality:": "品質:",
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
@ -53,7 +54,7 @@ html {
|
||||||
}
|
}
|
||||||
|
|
||||||
.noVNC_disabled {
|
.noVNC_disabled {
|
||||||
color: rgb(128, 128, 128);
|
color: var(--novnc-grey);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------
|
/* ----------------------------------------
|
||||||
|
@ -174,7 +175,7 @@ html {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
|
||||||
border-radius: 10px;
|
border-radius: 12px;
|
||||||
box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5);
|
box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5);
|
||||||
background: rgba(200,55,55,0.8);
|
background: rgba(200,55,55,0.8);
|
||||||
}
|
}
|
||||||
|
@ -241,8 +242,8 @@ html {
|
||||||
|
|
||||||
transition: 0.5s ease-in-out;
|
transition: 0.5s ease-in-out;
|
||||||
|
|
||||||
background-color: rgb(110, 132, 163);
|
background-color: var(--novnc-blue);
|
||||||
border-radius: 0 10px 10px 0;
|
border-radius: 0 12px 12px 0;
|
||||||
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
|
@ -267,7 +268,7 @@ html {
|
||||||
}
|
}
|
||||||
.noVNC_right #noVNC_control_bar {
|
.noVNC_right #noVNC_control_bar {
|
||||||
left: 100%;
|
left: 100%;
|
||||||
border-radius: 10px 0 0 10px;
|
border-radius: 12px 0 0 12px;
|
||||||
}
|
}
|
||||||
.noVNC_right #noVNC_control_bar.noVNC_open {
|
.noVNC_right #noVNC_control_bar.noVNC_open {
|
||||||
left: 0;
|
left: 0;
|
||||||
|
@ -285,8 +286,8 @@ html {
|
||||||
height: 50px;
|
height: 50px;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 5px;
|
border-radius: 6px;
|
||||||
background-color: rgb(83, 99, 122);
|
background-color: var(--novnc-darkblue);
|
||||||
background-image: url("../images/handle_bg.svg");
|
background-image: url("../images/handle_bg.svg");
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: right;
|
background-position: right;
|
||||||
|
@ -371,8 +372,8 @@ html {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: 0.2s ease-in-out;
|
transition: 0.2s ease-in-out;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
box-shadow: 0 0 10px black, inset 0 0 10px 10px rgba(110, 132, 163, 0.8);
|
box-shadow: 0 0 10px black, inset 0 0 10px 10px var(--novnc-darkblue);
|
||||||
border-radius: 10px;
|
border-radius: 12px;
|
||||||
transition-delay: 0s;
|
transition-delay: 0s;
|
||||||
}
|
}
|
||||||
#noVNC_control_bar_hint.noVNC_active {
|
#noVNC_control_bar_hint.noVNC_active {
|
||||||
|
@ -387,45 +388,21 @@ html {
|
||||||
|
|
||||||
/* Control bar buttons */
|
/* Control bar buttons */
|
||||||
#noVNC_control_bar .noVNC_button {
|
#noVNC_control_bar .noVNC_button {
|
||||||
|
min-width: unset;
|
||||||
padding: 4px 4px;
|
padding: 4px 4px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
border:1px solid rgba(255, 255, 255, 0.2);
|
border:1px solid rgba(255, 255, 255, 0.2);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
background-image: unset; /* we don't want the gradiant from input.css */
|
|
||||||
}
|
}
|
||||||
#noVNC_control_bar .noVNC_button.noVNC_selected {
|
#noVNC_control_bar .noVNC_button.noVNC_selected {
|
||||||
border-color: rgba(0, 0, 0, 0.8);
|
border-color: rgba(0, 0, 0, 0.8);
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
}
|
}
|
||||||
#noVNC_control_bar .noVNC_button.noVNC_selected:not(:disabled):hover {
|
|
||||||
border-color: rgba(0, 0, 0, 0.4);
|
|
||||||
background-color: rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
#noVNC_control_bar .noVNC_button:not(:disabled):hover {
|
|
||||||
background-color: rgba(255, 255, 255, 0.2);
|
|
||||||
}
|
|
||||||
#noVNC_control_bar .noVNC_button:not(:disabled):active {
|
|
||||||
padding-top: 5px;
|
|
||||||
padding-bottom: 3px;
|
|
||||||
}
|
|
||||||
#noVNC_control_bar .noVNC_button.noVNC_hidden {
|
#noVNC_control_bar .noVNC_button.noVNC_hidden {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Android browsers don't properly update hover state if touch events are
|
|
||||||
* intercepted, like they are when clicking on the remote screen. */
|
|
||||||
@media (any-pointer: coarse) {
|
|
||||||
#noVNC_control_bar .noVNC_button:not(:disabled):hover {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
#noVNC_control_bar .noVNC_button.noVNC_selected:not(:disabled):hover {
|
|
||||||
border-color: rgba(0, 0, 0, 0.8);
|
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Panels */
|
/* Panels */
|
||||||
.noVNC_panel {
|
.noVNC_panel {
|
||||||
transform: translateX(25px);
|
transform: translateX(25px);
|
||||||
|
@ -444,7 +421,7 @@ html {
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
|
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 10px;
|
border-radius: 12px;
|
||||||
color: #000;
|
color: #000;
|
||||||
border: 2px solid #E0E0E0;
|
border: 2px solid #E0E0E0;
|
||||||
box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5);
|
box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5);
|
||||||
|
@ -478,7 +455,8 @@ html {
|
||||||
|
|
||||||
.noVNC_panel hr {
|
.noVNC_panel hr {
|
||||||
border: none;
|
border: none;
|
||||||
border-top: 1px solid rgb(192, 192, 192);
|
border-top: 1px solid var(--novnc-lightgrey);
|
||||||
|
width: 100%; /* <hr> inside a flexbox will otherwise be 0px wide */
|
||||||
}
|
}
|
||||||
|
|
||||||
.noVNC_panel label {
|
.noVNC_panel label {
|
||||||
|
@ -486,27 +464,58 @@ html {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
}
|
}
|
||||||
|
@media (max-width: 540px) {
|
||||||
|
/* Allow wrapping on small screens */
|
||||||
|
.noVNC_panel label {
|
||||||
|
white-space: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.noVNC_panel li {
|
.noVNC_panel li {
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.noVNC_panel button,
|
||||||
|
.noVNC_panel select,
|
||||||
|
.noVNC_panel textarea,
|
||||||
|
.noVNC_panel input:not([type=checkbox]):not([type=radio]) {
|
||||||
|
margin-left: 6px;
|
||||||
|
/* Prevent inputs in panels from being too wide */
|
||||||
|
max-width: calc(100% - 6px - var(--input-xpadding) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
.noVNC_panel .noVNC_heading {
|
.noVNC_panel .noVNC_heading {
|
||||||
background-color: rgb(110, 132, 163);
|
background-color: var(--novnc-blue);
|
||||||
border-radius: 5px;
|
border-radius: 6px;
|
||||||
padding: 5px;
|
padding: 5px 8px;
|
||||||
/* Compensate for padding in image */
|
/* Compensate for padding in image */
|
||||||
padding-right: 8px;
|
padding-right: 11px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
color: white;
|
color: white;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
|
font-weight: bold;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
.noVNC_panel .noVNC_heading img {
|
.noVNC_panel .noVNC_heading img {
|
||||||
vertical-align: bottom;
|
vertical-align: bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
.noVNC_submit {
|
.noVNC_panel form {
|
||||||
float: right;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px
|
||||||
|
}
|
||||||
|
|
||||||
|
.noVNC_panel .button_row {
|
||||||
|
margin-top: 10px;
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.noVNC_panel .button_row *:only-child {
|
||||||
|
margin-left: auto; /* Align single buttons to the right */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Expanders */
|
/* Expanders */
|
||||||
|
@ -526,8 +535,8 @@ html {
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
background: rgba(0, 0, 0, 0.05);
|
background: rgba(0, 0, 0, 0.04);
|
||||||
border-radius: 5px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
.noVNC_expander:not(.noVNC_open) ~ * {
|
.noVNC_expander:not(.noVNC_open) ~ * {
|
||||||
display: none;
|
display: none;
|
||||||
|
@ -570,7 +579,7 @@ html {
|
||||||
}
|
}
|
||||||
|
|
||||||
#noVNC_modifiers {
|
#noVNC_modifiers {
|
||||||
background-color: rgb(92, 92, 92);
|
background-color: var(--novnc-darkgrey);
|
||||||
border: none;
|
border: none;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
@ -725,7 +734,7 @@ html {
|
||||||
font-size: 80px;
|
font-size: 80px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
border-radius: 5px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
@media (max-width: 440px) {
|
@media (max-width: 440px) {
|
||||||
#noVNC_connect_dlg {
|
#noVNC_connect_dlg {
|
||||||
|
@ -736,9 +745,9 @@ html {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#noVNC_connect_dlg div {
|
#noVNC_connect_dlg div {
|
||||||
padding: 12px;
|
padding: 18px;
|
||||||
|
|
||||||
background-color: rgb(110, 132, 163);
|
background-color: var(--novnc-darkgrey);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
|
@ -747,21 +756,17 @@ html {
|
||||||
}
|
}
|
||||||
#noVNC_connect_button {
|
#noVNC_connect_button {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 5px 30px;
|
padding: 6px 30px;
|
||||||
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
border-color: transparent;
|
||||||
border-color: rgb(83, 99, 122);
|
border-radius: 12px;
|
||||||
border-radius: 5px;
|
background-color: var(--novnc-blue);
|
||||||
|
|
||||||
background: linear-gradient(to top, rgb(110, 132, 163), rgb(99, 119, 147));
|
|
||||||
color: white;
|
color: white;
|
||||||
|
|
||||||
/* This avoids it jumping around when :active */
|
display: flex;
|
||||||
vertical-align: middle;
|
justify-content: center;
|
||||||
}
|
place-items: center;
|
||||||
#noVNC_connect_button:hover {
|
gap: 4px;
|
||||||
background: linear-gradient(to top, rgb(110, 132, 163), rgb(105, 125, 155));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#noVNC_connect_button img {
|
#noVNC_connect_button img {
|
||||||
|
@ -885,13 +890,13 @@ html {
|
||||||
}
|
}
|
||||||
|
|
||||||
.noVNC_logo {
|
.noVNC_logo {
|
||||||
color:yellow;
|
color: var(--novnc-yellow);
|
||||||
font-family: 'Orbitron', 'OrbitronTTF', sans-serif;
|
font-family: 'Orbitron', 'OrbitronTTF', sans-serif;
|
||||||
line-height: 0.9;
|
line-height: 0.9;
|
||||||
text-shadow: 0.1em 0.1em 0 black;
|
text-shadow: 0.1em 0.1em 0 black;
|
||||||
}
|
}
|
||||||
.noVNC_logo span{
|
.noVNC_logo span{
|
||||||
color:green;
|
color: var(--novnc-green);
|
||||||
}
|
}
|
||||||
|
|
||||||
#noVNC_bell {
|
#noVNC_bell {
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* noVNC general CSS constant variables
|
||||||
|
* Copyright (C) 2025 The noVNC authors
|
||||||
|
* noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
|
||||||
|
* This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ---------- COLORS ----------- */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--novnc-grey: rgb(128, 128, 128);
|
||||||
|
--novnc-lightgrey: rgb(192, 192, 192);
|
||||||
|
--novnc-darkgrey: rgb(92, 92, 92);
|
||||||
|
|
||||||
|
/* Transparent to make button colors adapt to the background */
|
||||||
|
--novnc-buttongrey: rgba(192, 192, 192, 0.5);
|
||||||
|
|
||||||
|
--novnc-blue: rgb(110, 132, 163);
|
||||||
|
--novnc-lightblue: rgb(74, 144, 217);
|
||||||
|
--novnc-darkblue: rgb(83, 99, 122);
|
||||||
|
|
||||||
|
--novnc-green: rgb(0, 128, 0);
|
||||||
|
--novnc-yellow: rgb(255, 255, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------ MISC PROPERTIES ------ */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--input-xpadding: 1em;
|
||||||
|
}
|
|
@ -1,32 +1,170 @@
|
||||||
/*
|
/*
|
||||||
* noVNC general input element CSS
|
* noVNC general input element CSS
|
||||||
* Copyright (C) 2022 The noVNC authors
|
* Copyright (C) 2025 The noVNC authors
|
||||||
* noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
|
* noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
|
||||||
* This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
|
* This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/* ------- SHARED BETWEEN INPUT ELEMENTS -------- */
|
||||||
* Common for all inputs
|
|
||||||
*/
|
input,
|
||||||
input, input::file-selector-button, button, select, textarea {
|
textarea,
|
||||||
|
button,
|
||||||
|
select,
|
||||||
|
input::file-selector-button {
|
||||||
|
padding: 0.5em var(--input-xpadding);
|
||||||
|
border-radius: 6px;
|
||||||
|
appearance: none;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
/* Respect standard font settings */
|
/* Respect standard font settings */
|
||||||
font: inherit;
|
font: inherit;
|
||||||
|
line-height: 1.6;
|
||||||
/* Disable default rendering */
|
}
|
||||||
appearance: none;
|
input:disabled,
|
||||||
background: none;
|
textarea:disabled,
|
||||||
|
button:disabled,
|
||||||
padding: 5px;
|
select:disabled,
|
||||||
border: 1px solid rgb(192, 192, 192);
|
label[disabled] {
|
||||||
border-radius: 5px;
|
opacity: 0.4;
|
||||||
color: black;
|
|
||||||
--bg-gradient: linear-gradient(to top, rgb(255, 255, 255) 80%, rgb(240, 240, 240));
|
|
||||||
background-image: var(--bg-gradient);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
input:focus-visible,
|
||||||
* Buttons
|
textarea:focus-visible,
|
||||||
*/
|
button:focus-visible,
|
||||||
|
select:focus-visible,
|
||||||
|
input:focus-visible::file-selector-button {
|
||||||
|
outline: 2px solid var(--novnc-lightblue);
|
||||||
|
outline-offset: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------- TEXT INPUT -------- */
|
||||||
|
|
||||||
|
input:not([type]),
|
||||||
|
input[type=date],
|
||||||
|
input[type=datetime-local],
|
||||||
|
input[type=email],
|
||||||
|
input[type=month],
|
||||||
|
input[type=number],
|
||||||
|
input[type=password],
|
||||||
|
input[type=search],
|
||||||
|
input[type=tel],
|
||||||
|
input[type=text],
|
||||||
|
input[type=time],
|
||||||
|
input[type=url],
|
||||||
|
input[type=week],
|
||||||
|
textarea {
|
||||||
|
border: 1px solid var(--novnc-lightgrey);
|
||||||
|
/* Account for borders on text inputs, buttons dont have borders */
|
||||||
|
padding: calc(0.5em - 1px) var(--input-xpadding);
|
||||||
|
}
|
||||||
|
input:not([type]):focus-visible,
|
||||||
|
input[type=date]:focus-visible,
|
||||||
|
input[type=datetime-local]:focus-visible,
|
||||||
|
input[type=email]:focus-visible,
|
||||||
|
input[type=month]:focus-visible,
|
||||||
|
input[type=number]:focus-visible,
|
||||||
|
input[type=password]:focus-visible,
|
||||||
|
input[type=search]:focus-visible,
|
||||||
|
input[type=tel]:focus-visible,
|
||||||
|
input[type=text]:focus-visible,
|
||||||
|
input[type=time]:focus-visible,
|
||||||
|
input[type=url]:focus-visible,
|
||||||
|
input[type=week]:focus-visible,
|
||||||
|
textarea:focus-visible {
|
||||||
|
outline-offset: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
margin: unset; /* Remove Firefox's built in margin */
|
||||||
|
/* Prevent layout from shifting when scrollbars show */
|
||||||
|
scrollbar-gutter: stable;
|
||||||
|
/* Make textareas show at minimum one line. This does not work when
|
||||||
|
using box-sizing border-box, in which case, vertical padding and
|
||||||
|
border width needs to be taken into account. */
|
||||||
|
min-height: 1lh;
|
||||||
|
vertical-align: baseline; /* Firefox gives "text-bottom" by default */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------- NUMBER PICKERS ------- */
|
||||||
|
|
||||||
|
/* We can't style the number spinner buttons:
|
||||||
|
https://github.com/w3c/csswg-drafts/issues/8777 */
|
||||||
|
input[type=number]::-webkit-inner-spin-button,
|
||||||
|
input[type=number]::-webkit-outer-spin-button {
|
||||||
|
/* Get rid of increase/decrease buttons in WebKit */
|
||||||
|
appearance: none;
|
||||||
|
}
|
||||||
|
input[type=number] {
|
||||||
|
/* Get rid of increase/decrease buttons in Firefox */
|
||||||
|
appearance: textfield;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------- BUTTON ACTIVATIONS -------- */
|
||||||
|
|
||||||
|
/* A color overlay that depends on the activation level. The level can then be
|
||||||
|
set for different states on an element, for example hover and click on a
|
||||||
|
<button>. */
|
||||||
|
input, button, select, option,
|
||||||
|
input::file-selector-button,
|
||||||
|
.button-activations {
|
||||||
|
--button-activation-level: 0;
|
||||||
|
/* Note that CSS variables aren't functions, beware when inheriting */
|
||||||
|
--button-activation-alpha: calc(0.08 * var(--button-activation-level));
|
||||||
|
/* FIXME: We want the image() function instead of the linear-gradient()
|
||||||
|
function below. But it's not supported in the browsers yet. */
|
||||||
|
--button-activation-overlay:
|
||||||
|
linear-gradient(rgba(0, 0, 0, var(--button-activation-alpha))
|
||||||
|
100%, transparent);
|
||||||
|
--button-activation-overlay-light:
|
||||||
|
linear-gradient(rgba(255, 255, 255, calc(0.23 * var(--button-activation-level)))
|
||||||
|
100%, transparent);
|
||||||
|
}
|
||||||
|
.button-activations {
|
||||||
|
background-image: var(--button-activation-overlay);
|
||||||
|
|
||||||
|
/* Disable Chrome's touch tap highlight to avoid conflicts with overlay */
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
}
|
||||||
|
/* When we want the light overlay on activations instead.
|
||||||
|
This is best used on elements with darker backgrounds. */
|
||||||
|
.button-activations.light-overlay {
|
||||||
|
background-image: var(--button-activation-overlay-light);
|
||||||
|
/* Can't use the normal blend mode since that gives washed out colors. */
|
||||||
|
/* FIXME: For elements with these activation overlays we'd like only
|
||||||
|
the luminosity to change. The proprty "background-blend-mode" set
|
||||||
|
to "luminosity" sounds good, but it doesn't work as intended,
|
||||||
|
see: https://bugzilla.mozilla.org/show_bug.cgi?id=1806417 */
|
||||||
|
background-blend-mode: overlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:hover, button:hover, select:hover, option:hover,
|
||||||
|
input::file-selector-button:hover,
|
||||||
|
.button-activations:hover {
|
||||||
|
--button-activation-level: 1;
|
||||||
|
}
|
||||||
|
/* Unfortunately we have to disable the :hover effect on touch devices,
|
||||||
|
otherwise the style lingers after tapping the button. */
|
||||||
|
@media (any-pointer: coarse) {
|
||||||
|
input:hover, button:hover, select:hover, option:hover,
|
||||||
|
input::file-selector-button:hover,
|
||||||
|
.button-activations:hover {
|
||||||
|
--button-activation-level: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input:active, button:active, select:active, option:active,
|
||||||
|
input::file-selector-button:active,
|
||||||
|
.button-activations:active {
|
||||||
|
--button-activation-level: 2;
|
||||||
|
}
|
||||||
|
input:disabled, button:disabled, select:disabled, select:disabled option,
|
||||||
|
input:disabled::file-selector-button,
|
||||||
|
.button-activations:disabled {
|
||||||
|
--button-activation-level: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------- BUTTONS -------- */
|
||||||
|
|
||||||
input[type=button],
|
input[type=button],
|
||||||
input[type=color],
|
input[type=color],
|
||||||
input[type=image],
|
input[type=image],
|
||||||
|
@ -35,227 +173,16 @@ input[type=submit],
|
||||||
input::file-selector-button,
|
input::file-selector-button,
|
||||||
button,
|
button,
|
||||||
select {
|
select {
|
||||||
border-bottom-width: 2px;
|
min-width: 8em;
|
||||||
|
border: none;
|
||||||
/* This avoids it jumping around when :active */
|
color: black;
|
||||||
vertical-align: middle;
|
font-weight: bold;
|
||||||
margin-top: 0;
|
background-color: var(--novnc-buttongrey);
|
||||||
|
background-image: var(--button-activation-overlay);
|
||||||
padding-left: 20px;
|
cursor: pointer;
|
||||||
padding-right: 20px;
|
|
||||||
|
|
||||||
/* Disable Chrome's touch tap highlight */
|
/* Disable Chrome's touch tap highlight */
|
||||||
-webkit-tap-highlight-color: transparent;
|
-webkit-tap-highlight-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Select dropdowns
|
|
||||||
*/
|
|
||||||
select {
|
|
||||||
--select-arrow: url('data:image/svg+xml;utf8, \
|
|
||||||
<svg width="8" height="6" version="1.1" viewBox="0 0 8 6" \
|
|
||||||
xmlns="http://www.w3.org/2000/svg"> \
|
|
||||||
<path d="m6.5 1.5 -2.5 3 -2.5 -3 5 0" stroke-width="3" \
|
|
||||||
stroke="rgb(31,31,31)" fill="none" \
|
|
||||||
stroke-linecap="round" stroke-linejoin="round" /> \
|
|
||||||
</svg>');
|
|
||||||
background-image: var(--select-arrow), var(--bg-gradient);
|
|
||||||
background-position: calc(100% - 7px), left top;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
padding-right: calc(2*7px + 8px);
|
|
||||||
padding-left: 7px;
|
|
||||||
}
|
|
||||||
/* FIXME: :active isn't set when the <select> is opened in Firefox:
|
|
||||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1805406 */
|
|
||||||
select:active {
|
|
||||||
/* Rotated arrow */
|
|
||||||
background-image: url('data:image/svg+xml;utf8, \
|
|
||||||
<svg width="8" height="6" version="1.1" viewBox="0 0 8 6" \
|
|
||||||
xmlns="http://www.w3.org/2000/svg" transform="rotate(180)" > \
|
|
||||||
<path d="m6.5 1.5 -2.5 3 -2.5 -3 5 0" stroke-width="3" \
|
|
||||||
stroke="rgb(31,31,31)" fill="none" \
|
|
||||||
stroke-linecap="round" stroke-linejoin="round" /> \
|
|
||||||
</svg>'), var(--bg-gradient);
|
|
||||||
}
|
|
||||||
option {
|
|
||||||
color: black;
|
|
||||||
background: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Checkboxes
|
|
||||||
*/
|
|
||||||
input[type=checkbox] {
|
|
||||||
display: inline-flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
background-color: white;
|
|
||||||
background-image: unset;
|
|
||||||
border: 1px solid dimgrey;
|
|
||||||
border-radius: 3px;
|
|
||||||
width: 13px;
|
|
||||||
height: 13px;
|
|
||||||
padding: 0;
|
|
||||||
margin-right: 6px;
|
|
||||||
vertical-align: bottom;
|
|
||||||
transition: 0.2s background-color linear;
|
|
||||||
}
|
|
||||||
input[type=checkbox]:checked {
|
|
||||||
background-color: rgb(110, 132, 163);
|
|
||||||
border-color: rgb(110, 132, 163);
|
|
||||||
}
|
|
||||||
input[type=checkbox]:checked::after {
|
|
||||||
content: "";
|
|
||||||
display: block; /* width & height doesn't work on inline elements */
|
|
||||||
width: 3px;
|
|
||||||
height: 7px;
|
|
||||||
border: 1px solid white;
|
|
||||||
border-width: 0 2px 2px 0;
|
|
||||||
transform: rotate(40deg) translateY(-1px);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Radiobuttons
|
|
||||||
*/
|
|
||||||
input[type=radio] {
|
|
||||||
border-radius: 50%;
|
|
||||||
border: 1px solid dimgrey;
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
padding: 0;
|
|
||||||
margin-right: 6px;
|
|
||||||
transition: 0.2s border linear;
|
|
||||||
}
|
|
||||||
input[type=radio]:checked {
|
|
||||||
border: 6px solid rgb(110, 132, 163);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Range sliders
|
|
||||||
*/
|
|
||||||
input[type=range] {
|
|
||||||
border: unset;
|
|
||||||
border-radius: 3px;
|
|
||||||
height: 20px;
|
|
||||||
padding: 0;
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
/* -webkit-slider.. & -moz-range.. cant be in selector lists:
|
|
||||||
https://bugs.chromium.org/p/chromium/issues/detail?id=1154623 */
|
|
||||||
input[type=range]::-webkit-slider-runnable-track {
|
|
||||||
background-color: rgb(110, 132, 163);
|
|
||||||
height: 6px;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
input[type=range]::-moz-range-track {
|
|
||||||
background-color: rgb(110, 132, 163);
|
|
||||||
height: 6px;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
input[type=range]::-webkit-slider-thumb {
|
|
||||||
appearance: none;
|
|
||||||
width: 18px;
|
|
||||||
height: 20px;
|
|
||||||
border-radius: 5px;
|
|
||||||
background-color: white;
|
|
||||||
border: 1px solid dimgray;
|
|
||||||
margin-top: -7px;
|
|
||||||
}
|
|
||||||
input[type=range]::-moz-range-thumb {
|
|
||||||
appearance: none;
|
|
||||||
width: 18px;
|
|
||||||
height: 20px;
|
|
||||||
border-radius: 5px;
|
|
||||||
background-color: white;
|
|
||||||
border: 1px solid dimgray;
|
|
||||||
margin-top: -7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* File choosers
|
|
||||||
*/
|
|
||||||
input[type=file] {
|
|
||||||
background-image: none;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
input::file-selector-button {
|
|
||||||
margin-right: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Hover
|
|
||||||
*/
|
|
||||||
input[type=button]:hover,
|
|
||||||
input[type=color]:hover,
|
|
||||||
input[type=image]:hover,
|
|
||||||
input[type=reset]:hover,
|
|
||||||
input[type=submit]:hover,
|
|
||||||
input::file-selector-button:hover,
|
|
||||||
button:hover {
|
|
||||||
background-image: linear-gradient(to top, rgb(255, 255, 255), rgb(250, 250, 250));
|
|
||||||
}
|
|
||||||
select:hover {
|
|
||||||
background-image: var(--select-arrow),
|
|
||||||
linear-gradient(to top, rgb(255, 255, 255), rgb(250, 250, 250));
|
|
||||||
background-position: calc(100% - 7px), left top;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
}
|
|
||||||
@media (any-pointer: coarse) {
|
|
||||||
/* We don't want a hover style after touch input */
|
|
||||||
input[type=button]:hover,
|
|
||||||
input[type=color]:hover,
|
|
||||||
input[type=image]:hover,
|
|
||||||
input[type=reset]:hover,
|
|
||||||
input[type=submit]:hover,
|
|
||||||
input::file-selector-button:hover,
|
|
||||||
button:hover {
|
|
||||||
background-image: var(--bg-gradient);
|
|
||||||
}
|
|
||||||
select:hover {
|
|
||||||
background-image: var(--select-arrow), var(--bg-gradient);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Active (clicked)
|
|
||||||
*/
|
|
||||||
input[type=button]:active,
|
|
||||||
input[type=color]:active,
|
|
||||||
input[type=image]:active,
|
|
||||||
input[type=reset]:active,
|
|
||||||
input[type=submit]:active,
|
|
||||||
input::file-selector-button:active,
|
|
||||||
button:active,
|
|
||||||
select:active {
|
|
||||||
border-bottom-width: 1px;
|
|
||||||
margin-top: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Focus (tab)
|
|
||||||
*/
|
|
||||||
input:focus-visible,
|
|
||||||
input:focus-visible::file-selector-button,
|
|
||||||
button:focus-visible,
|
|
||||||
select:focus-visible,
|
|
||||||
textarea:focus-visible {
|
|
||||||
outline: 2px solid rgb(74, 144, 217);
|
|
||||||
outline-offset: 1px;
|
|
||||||
}
|
|
||||||
input[type=file]:focus-visible {
|
|
||||||
outline: none; /* We outline the button instead of the entire element */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Disabled
|
|
||||||
*/
|
|
||||||
input:disabled,
|
|
||||||
input:disabled::file-selector-button,
|
|
||||||
button:disabled,
|
|
||||||
select:disabled,
|
|
||||||
textarea:disabled {
|
|
||||||
opacity: 0.4;
|
|
||||||
}
|
|
||||||
input[type=button]:disabled,
|
input[type=button]:disabled,
|
||||||
input[type=color]:disabled,
|
input[type=color]:disabled,
|
||||||
input[type=image]:disabled,
|
input[type=image]:disabled,
|
||||||
|
@ -264,18 +191,438 @@ input[type=submit]:disabled,
|
||||||
input:disabled::file-selector-button,
|
input:disabled::file-selector-button,
|
||||||
button:disabled,
|
button:disabled,
|
||||||
select:disabled {
|
select:disabled {
|
||||||
background-image: var(--bg-gradient);
|
|
||||||
border-bottom-width: 2px;
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
input[type=file]:disabled {
|
|
||||||
background-image: none;
|
|
||||||
}
|
|
||||||
select:disabled {
|
|
||||||
background-image: var(--select-arrow), var(--bg-gradient);
|
|
||||||
}
|
|
||||||
input[type=image]:disabled {
|
|
||||||
/* See Firefox bug:
|
/* See Firefox bug:
|
||||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1798304 */
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1798304 */
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input[type=button],
|
||||||
|
input[type=color],
|
||||||
|
input[type=reset],
|
||||||
|
input[type=submit] {
|
||||||
|
/* Workaround for text-overflow bugs in Firefox and Chromium:
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1800077
|
||||||
|
https://bugs.chromium.org/p/chromium/issues/detail?id=1383144 */
|
||||||
|
overflow: clip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------- COLOR PICKERS ------- */
|
||||||
|
|
||||||
|
input[type=color] {
|
||||||
|
min-width: unset;
|
||||||
|
box-sizing: content-box;
|
||||||
|
width: 1.4em;
|
||||||
|
height: 1.4em;
|
||||||
|
}
|
||||||
|
input[type=color]::-webkit-color-swatch-wrapper {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
/* -webkit-color-swatch & -moz-color-swatch cant be in a selector list:
|
||||||
|
https://bugs.chromium.org/p/chromium/issues/detail?id=1154623 */
|
||||||
|
input[type=color]::-webkit-color-swatch {
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
input[type=color]::-moz-color-swatch {
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- SHARED BETWEEN CHECKBOXES, RADIOBUTTONS AND THE TOGGLE CLASS -- */
|
||||||
|
|
||||||
|
input[type=radio],
|
||||||
|
input[type=checkbox] {
|
||||||
|
display: inline-flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background-color: var(--novnc-buttongrey);
|
||||||
|
background-image: var(--button-activation-overlay);
|
||||||
|
/* Disable Chrome's touch tap highlight to avoid conflicts with overlay */
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
width: 16px;
|
||||||
|
--checkradio-height: 16px;
|
||||||
|
height: var(--checkradio-height);
|
||||||
|
padding: 0;
|
||||||
|
margin: 0 6px 0 0;
|
||||||
|
/* Don't have transitions for outline in order to be consistent
|
||||||
|
with other elements */
|
||||||
|
transition: all 0.2s, outline-color 0s, outline-offset 0s;
|
||||||
|
|
||||||
|
/* A transparent outline in order to work around a graphical clipping issue
|
||||||
|
in WebKit. See bug: https://bugs.webkit.org/show_bug.cgi?id=256003 */
|
||||||
|
outline: 1px solid transparent;
|
||||||
|
position: relative; /* Since ::before & ::after are absolute positioned */
|
||||||
|
|
||||||
|
/* We want to align with the middle of capital letters, this requires
|
||||||
|
a workaround. The default behavior is to align the bottom of the element
|
||||||
|
on top of the text baseline, this is too far up.
|
||||||
|
We want to push the element down half the difference in height between
|
||||||
|
it and a capital X. In our font, the height of a capital "X" is 0.698em.
|
||||||
|
*/
|
||||||
|
vertical-align: calc(0px - (var(--checkradio-height) - 0.698em) / 2);
|
||||||
|
/* FIXME: Could write 1cap instead of 0.698em, but it's only supported in
|
||||||
|
Firefox as of 2023 */
|
||||||
|
/* FIXME: We probably want to use round() here, see bug 8148 */
|
||||||
|
}
|
||||||
|
input[type=radio]:focus-visible,
|
||||||
|
input[type=checkbox]:focus-visible {
|
||||||
|
outline-color: var(--novnc-lightblue);
|
||||||
|
}
|
||||||
|
input[type=checkbox]::before,
|
||||||
|
input[type=checkbox]:not(.toggle)::after,
|
||||||
|
input[type=radio]::before,
|
||||||
|
input[type=radio]::after {
|
||||||
|
content: "";
|
||||||
|
display: block; /* width & height doesn't work on inline elements */
|
||||||
|
transition: inherit;
|
||||||
|
/* Let's prevent the pseudo-elements from taking up layout space so that
|
||||||
|
the ::before and ::after pseudo-elements can be in the same place. This
|
||||||
|
is also required for vertical-align: baseline to work like we want it to
|
||||||
|
on radio/checkboxes. If the pseudo-elements take up layout space, the
|
||||||
|
baseline of text inside them will be used instead. */
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
input[type=checkbox]:not(.toggle)::after,
|
||||||
|
input[type=radio]::after {
|
||||||
|
width: 10px;
|
||||||
|
height: 2px;
|
||||||
|
background-color: transparent;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------- CHECKBOXES ------- */
|
||||||
|
|
||||||
|
input[type=checkbox]:not(.toggle) {
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
input[type=checkbox]:not(.toggle):checked,
|
||||||
|
input[type=checkbox]:not(.toggle):indeterminate {
|
||||||
|
background-color: var(--novnc-blue);
|
||||||
|
background-image: var(--button-activation-overlay-light);
|
||||||
|
background-blend-mode: overlay;
|
||||||
|
}
|
||||||
|
input[type=checkbox]:not(.toggle)::before {
|
||||||
|
width: 25%;
|
||||||
|
height: 55%;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: transparent;
|
||||||
|
border-width: 0 2px 2px 0;
|
||||||
|
border-radius: 1px;
|
||||||
|
transform: translateY(-1px) rotate(35deg);
|
||||||
|
}
|
||||||
|
input[type=checkbox]:not(.toggle):checked::before {
|
||||||
|
border-color: white;
|
||||||
|
}
|
||||||
|
input[type=checkbox]:not(.toggle):indeterminate::after {
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------- RADIO BUTTONS ------- */
|
||||||
|
|
||||||
|
input[type=radio] {
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 1px solid transparent; /* To ensure a smooth transition */
|
||||||
|
}
|
||||||
|
input[type=radio]:checked {
|
||||||
|
border: 4px solid var(--novnc-blue);
|
||||||
|
background-color: white;
|
||||||
|
/* button-activation-overlay should be removed from the radio
|
||||||
|
element to not interfere with button-activation-overlay-light
|
||||||
|
that is set on the ::before element. */
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
input[type=radio]::before {
|
||||||
|
width: inherit;
|
||||||
|
height: inherit;
|
||||||
|
border-radius: inherit;
|
||||||
|
/* We can achieve the highlight overlay effect on border colors by
|
||||||
|
setting button-activation-overlay-light on an element that stays
|
||||||
|
on top (z-axis) of the element with a border. */
|
||||||
|
background-image: var(--button-activation-overlay-light);
|
||||||
|
mix-blend-mode: overlay;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
input[type=radio]:checked::before {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
input[type=radio]:indeterminate::after {
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------- TOGGLE SWITCHES ------- */
|
||||||
|
|
||||||
|
/* These are meant to be used instead of checkboxes in some cases. If all of
|
||||||
|
the following critera are true you should use a toggle switch:
|
||||||
|
|
||||||
|
* The choice is a simple ON/OFF or ENABLE/DISABLE
|
||||||
|
* The choice doesn't give the feeling of "I agree" or "I confirm"
|
||||||
|
* There are not multiple related & grouped options
|
||||||
|
*/
|
||||||
|
|
||||||
|
input[type=checkbox].toggle {
|
||||||
|
display: inline-block;
|
||||||
|
--checkradio-height: 18px; /* Height value used in calc, see above */
|
||||||
|
width: 31px;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
border-radius: 9px;
|
||||||
|
}
|
||||||
|
input[type=checkbox].toggle:disabled {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
input[type=checkbox].toggle:indeterminate {
|
||||||
|
background-color: var(--novnc-buttongrey);
|
||||||
|
background-image: var(--button-activation-overlay);
|
||||||
|
}
|
||||||
|
input[type=checkbox].toggle:checked {
|
||||||
|
background-color: var(--novnc-blue);
|
||||||
|
background-image: var(--button-activation-overlay-light);
|
||||||
|
background-blend-mode: overlay;
|
||||||
|
}
|
||||||
|
input[type=checkbox].toggle::before {
|
||||||
|
--circle-diameter: 10px;
|
||||||
|
--circle-offset: 4px;
|
||||||
|
width: var(--circle-diameter);
|
||||||
|
height: var(--circle-diameter);
|
||||||
|
top: var(--circle-offset);
|
||||||
|
left: var(--circle-offset);
|
||||||
|
background: white;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
input[type=checkbox].toggle:checked::before {
|
||||||
|
left: calc(100% - var(--circle-offset) - var(--circle-diameter));
|
||||||
|
}
|
||||||
|
input[type=checkbox].toggle:indeterminate::before {
|
||||||
|
left: calc(50% - var(--circle-diameter) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------- RANGE SLIDERS ------- */
|
||||||
|
|
||||||
|
input[type=range] {
|
||||||
|
border: unset;
|
||||||
|
border-radius: 8px;
|
||||||
|
height: 15px;
|
||||||
|
padding: 0;
|
||||||
|
background: transparent;
|
||||||
|
/* Needed to get properly rounded corners on -moz-range-progress
|
||||||
|
when the thumb is all the way to the right. Without overflow
|
||||||
|
hidden, the pointy edges of the progress track shows to the
|
||||||
|
right of the thumb. */
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
@supports selector(::-webkit-slider-thumb) {
|
||||||
|
input[type=range] {
|
||||||
|
/* Needs a fixed width to match clip-path */
|
||||||
|
width: 125px;
|
||||||
|
/* overflow: hidden is not ideal for hiding the left part of the box
|
||||||
|
shadow of -webkit-slider-thumb since it doesn't match the smaller
|
||||||
|
border-radius of the progress track. The below clip-path has two
|
||||||
|
circular sides to make the ends of the track have correctly rounded
|
||||||
|
corners. The clip path shape looks something like this:
|
||||||
|
|
||||||
|
+-------------------------------+
|
||||||
|
/---| |---\
|
||||||
|
| |
|
||||||
|
\---| |---/
|
||||||
|
+-------------------------------+
|
||||||
|
|
||||||
|
The larger middle part of the clip path is made to have room for the
|
||||||
|
thumb. By using margins on the track, we prevent the thumb from
|
||||||
|
touching the ends of the track.
|
||||||
|
*/
|
||||||
|
clip-path: path(' \
|
||||||
|
M 4.5 3 \
|
||||||
|
L 4.5 0 \
|
||||||
|
L 120.5 0 \
|
||||||
|
L 120.5 3 \
|
||||||
|
A 1 1 0 0 1 120.5 12 \
|
||||||
|
L 120.5 15 \
|
||||||
|
L 4.5 15 \
|
||||||
|
L 4.5 12 \
|
||||||
|
A 1 1 0 0 1 4.5 3 \
|
||||||
|
');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input[type=range]:hover {
|
||||||
|
cursor: grab;
|
||||||
|
}
|
||||||
|
input[type=range]:active {
|
||||||
|
cursor: grabbing;
|
||||||
|
}
|
||||||
|
input[type=range]:disabled {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
input[type=range]:focus-visible {
|
||||||
|
clip-path: none; /* Otherwise it hides the outline */
|
||||||
|
}
|
||||||
|
/* -webkit-slider.. & -moz-range.. cant be in selector lists:
|
||||||
|
https://bugs.chromium.org/p/chromium/issues/detail?id=1154623 */
|
||||||
|
input[type=range]::-webkit-slider-runnable-track {
|
||||||
|
background-color: var(--novnc-buttongrey);
|
||||||
|
height: 7px;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin: 0 3px;
|
||||||
|
}
|
||||||
|
input[type=range]::-moz-range-track {
|
||||||
|
background-color: var(--novnc-buttongrey);
|
||||||
|
height: 7px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
input[type=range]::-moz-range-progress {
|
||||||
|
background-color: var(--novnc-blue);
|
||||||
|
height: 9px;
|
||||||
|
/* Needs rounded corners only on the left side. Otherwise the rounding of
|
||||||
|
the progress track starts before the thumb, when the thumb is close to
|
||||||
|
the left edge. */
|
||||||
|
border-radius: 5px 0 0 5px;
|
||||||
|
}
|
||||||
|
input[type=range]::-webkit-slider-thumb {
|
||||||
|
appearance: none;
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: white;
|
||||||
|
background-image: var(--button-activation-overlay);
|
||||||
|
/* Disable Chrome's touch tap highlight to avoid conflicts with overlay */
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
border: 3px solid var(--novnc-blue);
|
||||||
|
margin-top: -4px; /* (track height / 2) - (thumb height /2) */
|
||||||
|
|
||||||
|
/* Since there is no way to style the left part of the range track in
|
||||||
|
webkit, we add a large shadow (1000px wide) to the left of the thumb and
|
||||||
|
then crop it with a clip-path shaped like this:
|
||||||
|
___
|
||||||
|
+-------------------/ \
|
||||||
|
| progress |Thumb|
|
||||||
|
+-------------------\ ___ /
|
||||||
|
|
||||||
|
The large left part of the shadow is clipped by another clip-path on on
|
||||||
|
the main range input element. */
|
||||||
|
/* FIXME: We can remove the box shadow workaround when this is standardized:
|
||||||
|
https://github.com/w3c/csswg-drafts/issues/4410 */
|
||||||
|
|
||||||
|
box-shadow: calc(-100vw - 8px) 0 0 100vw var(--novnc-blue);
|
||||||
|
clip-path: path(' \
|
||||||
|
M -1000 3 \
|
||||||
|
L 3 3 \
|
||||||
|
L 15 7.5 \
|
||||||
|
A 1 1 0 0 1 0 7.5 \
|
||||||
|
A 1 1 0 0 1 15 7.5 \
|
||||||
|
L 3 12 \
|
||||||
|
L -1000 12 Z \
|
||||||
|
');
|
||||||
|
}
|
||||||
|
input[type=range]::-moz-range-thumb {
|
||||||
|
appearance: none;
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: white;
|
||||||
|
background-image: var(--button-activation-overlay);
|
||||||
|
border: 3px solid var(--novnc-blue);
|
||||||
|
margin-top: -7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------- FILE CHOOSERS ------- */
|
||||||
|
|
||||||
|
input[type=file] {
|
||||||
|
background-image: none;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
input::file-selector-button {
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
input[type=file]:focus-visible {
|
||||||
|
outline: none; /* We outline the button instead of the entire element */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------- SELECT BUTTONS ------- */
|
||||||
|
|
||||||
|
select {
|
||||||
|
--select-arrow: url('data:image/svg+xml;utf8, \
|
||||||
|
<svg width="11" height="6" version="1.1" viewBox="0 0 11 6" \
|
||||||
|
xmlns="http://www.w3.org/2000/svg"> \
|
||||||
|
<path d="m10.5.5-5 5-5-5" fill="none" \
|
||||||
|
stroke="black" stroke-width="1.5" \
|
||||||
|
stroke-linecap="round" stroke-linejoin="round"/> \
|
||||||
|
</svg>');
|
||||||
|
|
||||||
|
/* FIXME: A bug in Firefox, requires a workaround for the background:
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1810958 */
|
||||||
|
/* The dropdown list will show the select element's background above and
|
||||||
|
below the options in Firefox. We want the entire dropdown to be white. */
|
||||||
|
background-color: white;
|
||||||
|
/* However, we don't want the select element to actually show a white
|
||||||
|
background, so let's place a gradient above it with the color we want. */
|
||||||
|
--grey-background: linear-gradient(var(--novnc-buttongrey) 100%,
|
||||||
|
transparent);
|
||||||
|
background-image:
|
||||||
|
var(--select-arrow),
|
||||||
|
var(--button-activation-overlay),
|
||||||
|
var(--grey-background);
|
||||||
|
background-position: calc(100% - var(--input-xpadding)), left top, left top;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
padding-right: calc(2*var(--input-xpadding) + 11px);
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
/* FIXME: :active isn't set when the <select> is opened in Firefox:
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1805406 */
|
||||||
|
select:active {
|
||||||
|
/* Rotated arrow */
|
||||||
|
background-image: url('data:image/svg+xml;utf8, \
|
||||||
|
<svg width="11" height="6" version="1.1" viewBox="0 0 11 6" \
|
||||||
|
xmlns="http://www.w3.org/2000/svg" transform="rotate(180)"> \
|
||||||
|
<path d="m10.5.5-5 5-5-5" fill="none" \
|
||||||
|
stroke="black" stroke-width="1.5" \
|
||||||
|
stroke-linecap="round" stroke-linejoin="round"/> \
|
||||||
|
</svg>'),
|
||||||
|
var(--button-activation-overlay),
|
||||||
|
var(--grey-background);
|
||||||
|
}
|
||||||
|
select:disabled {
|
||||||
|
background-image:
|
||||||
|
var(--select-arrow),
|
||||||
|
var(--grey-background);
|
||||||
|
}
|
||||||
|
/* Note that styling for <option> doesn't work in all browsers
|
||||||
|
since its often drawn directly by the OS. We are generally very
|
||||||
|
limited in what we can change here. */
|
||||||
|
option {
|
||||||
|
/* Prevent Chrome from inheriting background-color from the <select> */
|
||||||
|
background-color: white;
|
||||||
|
color: black;
|
||||||
|
font-weight: normal;
|
||||||
|
background-image: var(--button-activation-overlay);
|
||||||
|
}
|
||||||
|
option:checked {
|
||||||
|
background-color: var(--novnc-lightgrey);
|
||||||
|
}
|
||||||
|
/* Change the look when the <select> isn't used as a dropdown. When "size"
|
||||||
|
or "multiple" are set, these elements behaves more like lists. */
|
||||||
|
select[size]:not([size="1"]), select[multiple] {
|
||||||
|
background-color: white;
|
||||||
|
background-image: unset; /* Don't show the arrow and other gradients */
|
||||||
|
border: 1px solid var(--novnc-lightgrey);
|
||||||
|
padding: 0;
|
||||||
|
font-weight: normal; /* Without this, options get bold font in WebKit. */
|
||||||
|
|
||||||
|
/* As an exception to the "list"-look, multi-selects in Chrome on Android,
|
||||||
|
and Safari on iOS, are unfortunately designed to be shown as a single
|
||||||
|
line. We can mitigate this inconsistency by at least fixing the height
|
||||||
|
here. By setting a min-height that matches other input elements, it
|
||||||
|
doesn't look too much out of place:
|
||||||
|
(1px border * 2) + (6.5px padding * 2) + 24px line-height = 39px */
|
||||||
|
min-height: 39px;
|
||||||
|
}
|
||||||
|
select[size]:not([size="1"]):focus-visible,
|
||||||
|
select[multiple]:focus-visible {
|
||||||
|
/* Text input style focus-visible highlight */
|
||||||
|
outline-offset: -1px;
|
||||||
|
}
|
||||||
|
select[size]:not([size="1"]) option, select[multiple] option {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
padding: 4px var(--input-xpadding);
|
||||||
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ export const encodings = {
|
||||||
pseudoEncodingXvp: -309,
|
pseudoEncodingXvp: -309,
|
||||||
pseudoEncodingFence: -312,
|
pseudoEncodingFence: -312,
|
||||||
pseudoEncodingContinuousUpdates: -313,
|
pseudoEncodingContinuousUpdates: -313,
|
||||||
|
pseudoEncodingExtendedMouseButtons: -316,
|
||||||
pseudoEncodingCompressLevel9: -247,
|
pseudoEncodingCompressLevel9: -247,
|
||||||
pseudoEncodingCompressLevel0: -256,
|
pseudoEncodingCompressLevel0: -256,
|
||||||
pseudoEncodingVMwareCursor: 0x574d5664,
|
pseudoEncodingVMwareCursor: 0x574d5664,
|
||||||
|
|
320
core/rfb.js
320
core/rfb.js
|
@ -151,9 +151,13 @@ export default class RFB extends EventTargetMixin {
|
||||||
this._supportsSetDesktopSize = false;
|
this._supportsSetDesktopSize = false;
|
||||||
this._screenID = 0;
|
this._screenID = 0;
|
||||||
this._screenFlags = 0;
|
this._screenFlags = 0;
|
||||||
|
this._pendingRemoteResize = false;
|
||||||
|
this._lastResize = 0;
|
||||||
|
|
||||||
this._qemuExtKeyEventSupported = false;
|
this._qemuExtKeyEventSupported = false;
|
||||||
|
|
||||||
|
this._extendedPointerEventSupported = false;
|
||||||
|
|
||||||
this._clipboardText = null;
|
this._clipboardText = null;
|
||||||
this._clipboardServerCapabilitiesActions = {};
|
this._clipboardServerCapabilitiesActions = {};
|
||||||
this._clipboardServerCapabilitiesFormats = {};
|
this._clipboardServerCapabilitiesFormats = {};
|
||||||
|
@ -743,6 +747,7 @@ export default class RFB extends EventTargetMixin {
|
||||||
currentHeight == this._expectedClientHeight;
|
currentHeight == this._expectedClientHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle browser window resizes
|
||||||
_handleResize() {
|
_handleResize() {
|
||||||
// Don't change anything if the client size is already as expected
|
// Don't change anything if the client size is already as expected
|
||||||
if (this._clientHasExpectedSize()) {
|
if (this._clientHasExpectedSize()) {
|
||||||
|
@ -753,17 +758,12 @@ export default class RFB extends EventTargetMixin {
|
||||||
window.requestAnimationFrame(() => {
|
window.requestAnimationFrame(() => {
|
||||||
this._updateClip();
|
this._updateClip();
|
||||||
this._updateScale();
|
this._updateScale();
|
||||||
|
this._saveExpectedClientSize();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this._resizeSession) {
|
|
||||||
// Request changing the resolution of the remote display to
|
// Request changing the resolution of the remote display to
|
||||||
// the size of the local browser viewport.
|
// the size of the local browser viewport.
|
||||||
|
this._requestRemoteResize();
|
||||||
// In order to not send multiple requests before the browser-resize
|
|
||||||
// is finished we wait 0.5 seconds before sending the request.
|
|
||||||
clearTimeout(this._resizeTimeout);
|
|
||||||
this._resizeTimeout = setTimeout(this._requestRemoteResize.bind(this), 500);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update state of clipping in Display object, and make sure the
|
// Update state of clipping in Display object, and make sure the
|
||||||
|
@ -813,16 +813,39 @@ export default class RFB extends EventTargetMixin {
|
||||||
// Requests a change of remote desktop size. This message is an extension
|
// Requests a change of remote desktop size. This message is an extension
|
||||||
// and may only be sent if we have received an ExtendedDesktopSize message
|
// and may only be sent if we have received an ExtendedDesktopSize message
|
||||||
_requestRemoteResize() {
|
_requestRemoteResize() {
|
||||||
clearTimeout(this._resizeTimeout);
|
if (!this._resizeSession) {
|
||||||
this._resizeTimeout = null;
|
return;
|
||||||
|
}
|
||||||
if (!this._resizeSession || this._viewOnly ||
|
if (this._viewOnly) {
|
||||||
!this._supportsSetDesktopSize) {
|
return;
|
||||||
|
}
|
||||||
|
if (!this._supportsSetDesktopSize) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rate limit to one pending resize at a time
|
||||||
|
if (this._pendingRemoteResize) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// And no more than once every 100ms
|
||||||
|
if ((Date.now() - this._lastResize) < 100) {
|
||||||
|
clearTimeout(this._resizeTimeout);
|
||||||
|
this._resizeTimeout = setTimeout(this._requestRemoteResize.bind(this),
|
||||||
|
100 - (Date.now() - this._lastResize));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._resizeTimeout = null;
|
||||||
|
|
||||||
const size = this._screenSize();
|
const size = this._screenSize();
|
||||||
|
|
||||||
|
// Do we actually change anything?
|
||||||
|
if (size.w === this._fbWidth && size.h === this._fbHeight) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._pendingRemoteResize = true;
|
||||||
|
this._lastResize = Date.now();
|
||||||
RFB.messages.setDesktopSize(this._sock,
|
RFB.messages.setDesktopSize(this._sock,
|
||||||
Math.floor(size.w), Math.floor(size.h),
|
Math.floor(size.w), Math.floor(size.h),
|
||||||
this._screenID, this._screenFlags);
|
this._screenID, this._screenFlags);
|
||||||
|
@ -1054,6 +1077,36 @@ export default class RFB extends EventTargetMixin {
|
||||||
this.sendKey(keysym, code, down);
|
this.sendKey(keysym, code, down);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static _convertButtonMask(buttons) {
|
||||||
|
/* The bits in MouseEvent.buttons property correspond
|
||||||
|
* to the following mouse buttons:
|
||||||
|
* 0: Left
|
||||||
|
* 1: Right
|
||||||
|
* 2: Middle
|
||||||
|
* 3: Back
|
||||||
|
* 4: Forward
|
||||||
|
*
|
||||||
|
* These bits needs to be converted to what they are defined as
|
||||||
|
* in the RFB protocol.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const buttonMaskMap = {
|
||||||
|
0: 1 << 0, // Left
|
||||||
|
1: 1 << 2, // Right
|
||||||
|
2: 1 << 1, // Middle
|
||||||
|
3: 1 << 7, // Back
|
||||||
|
4: 1 << 8, // Forward
|
||||||
|
};
|
||||||
|
|
||||||
|
let bmask = 0;
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
if (buttons & (1 << i)) {
|
||||||
|
bmask |= buttonMaskMap[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bmask;
|
||||||
|
}
|
||||||
|
|
||||||
_handleMouse(ev) {
|
_handleMouse(ev) {
|
||||||
/*
|
/*
|
||||||
* We don't check connection status or viewOnly here as the
|
* We don't check connection status or viewOnly here as the
|
||||||
|
@ -1083,80 +1136,75 @@ export default class RFB extends EventTargetMixin {
|
||||||
let pos = clientToElement(ev.clientX, ev.clientY,
|
let pos = clientToElement(ev.clientX, ev.clientY,
|
||||||
this._canvas);
|
this._canvas);
|
||||||
|
|
||||||
|
let bmask = RFB._convertButtonMask(ev.buttons);
|
||||||
|
|
||||||
|
let down = ev.type == 'mousedown';
|
||||||
switch (ev.type) {
|
switch (ev.type) {
|
||||||
case 'mousedown':
|
case 'mousedown':
|
||||||
setCapture(this._canvas);
|
|
||||||
this._handleMouseButton(pos.x, pos.y,
|
|
||||||
true, 1 << ev.button);
|
|
||||||
break;
|
|
||||||
case 'mouseup':
|
case 'mouseup':
|
||||||
this._handleMouseButton(pos.x, pos.y,
|
|
||||||
false, 1 << ev.button);
|
|
||||||
break;
|
|
||||||
case 'mousemove':
|
|
||||||
this._handleMouseMove(pos.x, pos.y);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_handleMouseButton(x, y, down, bmask) {
|
|
||||||
if (this.dragViewport) {
|
if (this.dragViewport) {
|
||||||
if (down && !this._viewportDragging) {
|
if (down && !this._viewportDragging) {
|
||||||
this._viewportDragging = true;
|
this._viewportDragging = true;
|
||||||
this._viewportDragPos = {'x': x, 'y': y};
|
this._viewportDragPos = {'x': pos.x, 'y': pos.y};
|
||||||
this._viewportHasMoved = false;
|
this._viewportHasMoved = false;
|
||||||
|
|
||||||
// Skip sending mouse events
|
this._flushMouseMoveTimer(pos.x, pos.y);
|
||||||
return;
|
|
||||||
|
// Skip sending mouse events, instead save the current
|
||||||
|
// mouse mask so we can send it later.
|
||||||
|
this._mouseButtonMask = bmask;
|
||||||
|
break;
|
||||||
} else {
|
} else {
|
||||||
this._viewportDragging = false;
|
this._viewportDragging = false;
|
||||||
|
|
||||||
// If we actually performed a drag then we are done
|
// If we actually performed a drag then we are done
|
||||||
// here and should not send any mouse events
|
// here and should not send any mouse events
|
||||||
if (this._viewportHasMoved) {
|
if (this._viewportHasMoved) {
|
||||||
return;
|
this._mouseButtonMask = bmask;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise we treat this as a mouse click event.
|
// Otherwise we treat this as a mouse click event.
|
||||||
// Send the button down event here, as the button up
|
// Send the previously saved button mask, followed
|
||||||
// event is sent at the end of this function.
|
// by the current button mask at the end of this
|
||||||
this._sendMouse(x, y, bmask);
|
// function.
|
||||||
|
this._sendMouse(pos.x, pos.y, this._mouseButtonMask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush waiting move event first
|
|
||||||
if (this._mouseMoveTimer !== null) {
|
|
||||||
clearTimeout(this._mouseMoveTimer);
|
|
||||||
this._mouseMoveTimer = null;
|
|
||||||
this._sendMouse(x, y, this._mouseButtonMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (down) {
|
if (down) {
|
||||||
this._mouseButtonMask |= bmask;
|
setCapture(this._canvas);
|
||||||
} else {
|
|
||||||
this._mouseButtonMask &= ~bmask;
|
|
||||||
}
|
}
|
||||||
|
this._handleMouseButton(pos.x, pos.y, bmask);
|
||||||
this._sendMouse(x, y, this._mouseButtonMask);
|
break;
|
||||||
}
|
case 'mousemove':
|
||||||
|
|
||||||
_handleMouseMove(x, y) {
|
|
||||||
if (this._viewportDragging) {
|
if (this._viewportDragging) {
|
||||||
const deltaX = this._viewportDragPos.x - x;
|
const deltaX = this._viewportDragPos.x - pos.x;
|
||||||
const deltaY = this._viewportDragPos.y - y;
|
const deltaY = this._viewportDragPos.y - pos.y;
|
||||||
|
|
||||||
if (this._viewportHasMoved || (Math.abs(deltaX) > dragThreshold ||
|
if (this._viewportHasMoved || (Math.abs(deltaX) > dragThreshold ||
|
||||||
Math.abs(deltaY) > dragThreshold)) {
|
Math.abs(deltaY) > dragThreshold)) {
|
||||||
this._viewportHasMoved = true;
|
this._viewportHasMoved = true;
|
||||||
|
|
||||||
this._viewportDragPos = {'x': x, 'y': y};
|
this._viewportDragPos = {'x': pos.x, 'y': pos.y};
|
||||||
this._display.viewportChangePos(deltaX, deltaY);
|
this._display.viewportChangePos(deltaX, deltaY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip sending mouse events
|
// Skip sending mouse events
|
||||||
return;
|
break;
|
||||||
|
}
|
||||||
|
this._handleMouseMove(pos.x, pos.y);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_handleMouseButton(x, y, bmask) {
|
||||||
|
// Flush waiting move event first
|
||||||
|
this._flushMouseMoveTimer(x, y);
|
||||||
|
|
||||||
|
this._mouseButtonMask = bmask;
|
||||||
|
this._sendMouse(x, y, this._mouseButtonMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleMouseMove(x, y) {
|
||||||
this._mousePos = { 'x': x, 'y': y };
|
this._mousePos = { 'x': x, 'y': y };
|
||||||
|
|
||||||
// Limit many mouse move events to one every MOUSE_MOVE_DELAY ms
|
// Limit many mouse move events to one every MOUSE_MOVE_DELAY ms
|
||||||
|
@ -1186,9 +1234,21 @@ export default class RFB extends EventTargetMixin {
|
||||||
if (this._rfbConnectionState !== 'connected') { return; }
|
if (this._rfbConnectionState !== 'connected') { return; }
|
||||||
if (this._viewOnly) { return; } // View only, skip mouse events
|
if (this._viewOnly) { return; } // View only, skip mouse events
|
||||||
|
|
||||||
|
// Highest bit in mask is never sent to the server
|
||||||
|
if (mask & 0x8000) {
|
||||||
|
throw new Error("Illegal mouse button mask (mask: " + mask + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
let extendedMouseButtons = mask & 0x7f80;
|
||||||
|
|
||||||
|
if (this._extendedPointerEventSupported && extendedMouseButtons) {
|
||||||
|
RFB.messages.extendedPointerEvent(this._sock, this._display.absX(x),
|
||||||
|
this._display.absY(y), mask);
|
||||||
|
} else {
|
||||||
RFB.messages.pointerEvent(this._sock, this._display.absX(x),
|
RFB.messages.pointerEvent(this._sock, this._display.absX(x),
|
||||||
this._display.absY(y), mask);
|
this._display.absY(y), mask);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_handleWheel(ev) {
|
_handleWheel(ev) {
|
||||||
if (this._rfbConnectionState !== 'connected') { return; }
|
if (this._rfbConnectionState !== 'connected') { return; }
|
||||||
|
@ -1200,6 +1260,7 @@ export default class RFB extends EventTargetMixin {
|
||||||
let pos = clientToElement(ev.clientX, ev.clientY,
|
let pos = clientToElement(ev.clientX, ev.clientY,
|
||||||
this._canvas);
|
this._canvas);
|
||||||
|
|
||||||
|
let bmask = RFB._convertButtonMask(ev.buttons);
|
||||||
let dX = ev.deltaX;
|
let dX = ev.deltaX;
|
||||||
let dY = ev.deltaY;
|
let dY = ev.deltaY;
|
||||||
|
|
||||||
|
@ -1219,26 +1280,27 @@ export default class RFB extends EventTargetMixin {
|
||||||
this._accumulatedWheelDeltaX += dX;
|
this._accumulatedWheelDeltaX += dX;
|
||||||
this._accumulatedWheelDeltaY += dY;
|
this._accumulatedWheelDeltaY += dY;
|
||||||
|
|
||||||
|
|
||||||
// Generate a mouse wheel step event when the accumulated delta
|
// Generate a mouse wheel step event when the accumulated delta
|
||||||
// for one of the axes is large enough.
|
// for one of the axes is large enough.
|
||||||
if (Math.abs(this._accumulatedWheelDeltaX) >= WHEEL_STEP) {
|
if (Math.abs(this._accumulatedWheelDeltaX) >= WHEEL_STEP) {
|
||||||
if (this._accumulatedWheelDeltaX < 0) {
|
if (this._accumulatedWheelDeltaX < 0) {
|
||||||
this._handleMouseButton(pos.x, pos.y, true, 1 << 5);
|
this._handleMouseButton(pos.x, pos.y, bmask | 1 << 5);
|
||||||
this._handleMouseButton(pos.x, pos.y, false, 1 << 5);
|
this._handleMouseButton(pos.x, pos.y, bmask);
|
||||||
} else if (this._accumulatedWheelDeltaX > 0) {
|
} else if (this._accumulatedWheelDeltaX > 0) {
|
||||||
this._handleMouseButton(pos.x, pos.y, true, 1 << 6);
|
this._handleMouseButton(pos.x, pos.y, bmask | 1 << 6);
|
||||||
this._handleMouseButton(pos.x, pos.y, false, 1 << 6);
|
this._handleMouseButton(pos.x, pos.y, bmask);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._accumulatedWheelDeltaX = 0;
|
this._accumulatedWheelDeltaX = 0;
|
||||||
}
|
}
|
||||||
if (Math.abs(this._accumulatedWheelDeltaY) >= WHEEL_STEP) {
|
if (Math.abs(this._accumulatedWheelDeltaY) >= WHEEL_STEP) {
|
||||||
if (this._accumulatedWheelDeltaY < 0) {
|
if (this._accumulatedWheelDeltaY < 0) {
|
||||||
this._handleMouseButton(pos.x, pos.y, true, 1 << 3);
|
this._handleMouseButton(pos.x, pos.y, bmask | 1 << 3);
|
||||||
this._handleMouseButton(pos.x, pos.y, false, 1 << 3);
|
this._handleMouseButton(pos.x, pos.y, bmask);
|
||||||
} else if (this._accumulatedWheelDeltaY > 0) {
|
} else if (this._accumulatedWheelDeltaY > 0) {
|
||||||
this._handleMouseButton(pos.x, pos.y, true, 1 << 4);
|
this._handleMouseButton(pos.x, pos.y, bmask | 1 << 4);
|
||||||
this._handleMouseButton(pos.x, pos.y, false, 1 << 4);
|
this._handleMouseButton(pos.x, pos.y, bmask);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._accumulatedWheelDeltaY = 0;
|
this._accumulatedWheelDeltaY = 0;
|
||||||
|
@ -1277,8 +1339,8 @@ export default class RFB extends EventTargetMixin {
|
||||||
this._gestureLastTapTime = Date.now();
|
this._gestureLastTapTime = Date.now();
|
||||||
|
|
||||||
this._fakeMouseMove(this._gestureFirstDoubleTapEv, pos.x, pos.y);
|
this._fakeMouseMove(this._gestureFirstDoubleTapEv, pos.x, pos.y);
|
||||||
this._handleMouseButton(pos.x, pos.y, true, bmask);
|
this._handleMouseButton(pos.x, pos.y, bmask);
|
||||||
this._handleMouseButton(pos.x, pos.y, false, bmask);
|
this._handleMouseButton(pos.x, pos.y, 0x0);
|
||||||
}
|
}
|
||||||
|
|
||||||
_handleGesture(ev) {
|
_handleGesture(ev) {
|
||||||
|
@ -1299,14 +1361,27 @@ export default class RFB extends EventTargetMixin {
|
||||||
this._handleTapEvent(ev, 0x2);
|
this._handleTapEvent(ev, 0x2);
|
||||||
break;
|
break;
|
||||||
case 'drag':
|
case 'drag':
|
||||||
|
if (this.dragViewport) {
|
||||||
|
this._viewportHasMoved = false;
|
||||||
|
this._viewportDragging = true;
|
||||||
|
this._viewportDragPos = {'x': pos.x, 'y': pos.y};
|
||||||
|
} else {
|
||||||
this._fakeMouseMove(ev, pos.x, pos.y);
|
this._fakeMouseMove(ev, pos.x, pos.y);
|
||||||
this._handleMouseButton(pos.x, pos.y, true, 0x1);
|
this._handleMouseButton(pos.x, pos.y, 0x1);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'longpress':
|
case 'longpress':
|
||||||
|
if (this.dragViewport) {
|
||||||
|
// If dragViewport is true, we need to wait to see
|
||||||
|
// if we have dragged outside the threshold before
|
||||||
|
// sending any events to the server.
|
||||||
|
this._viewportHasMoved = false;
|
||||||
|
this._viewportDragPos = {'x': pos.x, 'y': pos.y};
|
||||||
|
} else {
|
||||||
this._fakeMouseMove(ev, pos.x, pos.y);
|
this._fakeMouseMove(ev, pos.x, pos.y);
|
||||||
this._handleMouseButton(pos.x, pos.y, true, 0x4);
|
this._handleMouseButton(pos.x, pos.y, 0x4);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'twodrag':
|
case 'twodrag':
|
||||||
this._gestureLastMagnitudeX = ev.detail.magnitudeX;
|
this._gestureLastMagnitudeX = ev.detail.magnitudeX;
|
||||||
this._gestureLastMagnitudeY = ev.detail.magnitudeY;
|
this._gestureLastMagnitudeY = ev.detail.magnitudeY;
|
||||||
|
@ -1328,7 +1403,21 @@ export default class RFB extends EventTargetMixin {
|
||||||
break;
|
break;
|
||||||
case 'drag':
|
case 'drag':
|
||||||
case 'longpress':
|
case 'longpress':
|
||||||
|
if (this.dragViewport) {
|
||||||
|
this._viewportDragging = true;
|
||||||
|
const deltaX = this._viewportDragPos.x - pos.x;
|
||||||
|
const deltaY = this._viewportDragPos.y - pos.y;
|
||||||
|
|
||||||
|
if (this._viewportHasMoved || (Math.abs(deltaX) > dragThreshold ||
|
||||||
|
Math.abs(deltaY) > dragThreshold)) {
|
||||||
|
this._viewportHasMoved = true;
|
||||||
|
|
||||||
|
this._viewportDragPos = {'x': pos.x, 'y': pos.y};
|
||||||
|
this._display.viewportChangePos(deltaX, deltaY);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
this._fakeMouseMove(ev, pos.x, pos.y);
|
this._fakeMouseMove(ev, pos.x, pos.y);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'twodrag':
|
case 'twodrag':
|
||||||
// Always scroll in the same position.
|
// Always scroll in the same position.
|
||||||
|
@ -1336,23 +1425,23 @@ export default class RFB extends EventTargetMixin {
|
||||||
// every update.
|
// every update.
|
||||||
this._fakeMouseMove(ev, pos.x, pos.y);
|
this._fakeMouseMove(ev, pos.x, pos.y);
|
||||||
while ((ev.detail.magnitudeY - this._gestureLastMagnitudeY) > GESTURE_SCRLSENS) {
|
while ((ev.detail.magnitudeY - this._gestureLastMagnitudeY) > GESTURE_SCRLSENS) {
|
||||||
this._handleMouseButton(pos.x, pos.y, true, 0x8);
|
this._handleMouseButton(pos.x, pos.y, 0x8);
|
||||||
this._handleMouseButton(pos.x, pos.y, false, 0x8);
|
this._handleMouseButton(pos.x, pos.y, 0x0);
|
||||||
this._gestureLastMagnitudeY += GESTURE_SCRLSENS;
|
this._gestureLastMagnitudeY += GESTURE_SCRLSENS;
|
||||||
}
|
}
|
||||||
while ((ev.detail.magnitudeY - this._gestureLastMagnitudeY) < -GESTURE_SCRLSENS) {
|
while ((ev.detail.magnitudeY - this._gestureLastMagnitudeY) < -GESTURE_SCRLSENS) {
|
||||||
this._handleMouseButton(pos.x, pos.y, true, 0x10);
|
this._handleMouseButton(pos.x, pos.y, 0x10);
|
||||||
this._handleMouseButton(pos.x, pos.y, false, 0x10);
|
this._handleMouseButton(pos.x, pos.y, 0x0);
|
||||||
this._gestureLastMagnitudeY -= GESTURE_SCRLSENS;
|
this._gestureLastMagnitudeY -= GESTURE_SCRLSENS;
|
||||||
}
|
}
|
||||||
while ((ev.detail.magnitudeX - this._gestureLastMagnitudeX) > GESTURE_SCRLSENS) {
|
while ((ev.detail.magnitudeX - this._gestureLastMagnitudeX) > GESTURE_SCRLSENS) {
|
||||||
this._handleMouseButton(pos.x, pos.y, true, 0x20);
|
this._handleMouseButton(pos.x, pos.y, 0x20);
|
||||||
this._handleMouseButton(pos.x, pos.y, false, 0x20);
|
this._handleMouseButton(pos.x, pos.y, 0x0);
|
||||||
this._gestureLastMagnitudeX += GESTURE_SCRLSENS;
|
this._gestureLastMagnitudeX += GESTURE_SCRLSENS;
|
||||||
}
|
}
|
||||||
while ((ev.detail.magnitudeX - this._gestureLastMagnitudeX) < -GESTURE_SCRLSENS) {
|
while ((ev.detail.magnitudeX - this._gestureLastMagnitudeX) < -GESTURE_SCRLSENS) {
|
||||||
this._handleMouseButton(pos.x, pos.y, true, 0x40);
|
this._handleMouseButton(pos.x, pos.y, 0x40);
|
||||||
this._handleMouseButton(pos.x, pos.y, false, 0x40);
|
this._handleMouseButton(pos.x, pos.y, 0x0);
|
||||||
this._gestureLastMagnitudeX -= GESTURE_SCRLSENS;
|
this._gestureLastMagnitudeX -= GESTURE_SCRLSENS;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1365,13 +1454,13 @@ export default class RFB extends EventTargetMixin {
|
||||||
if (Math.abs(magnitude - this._gestureLastMagnitudeX) > GESTURE_ZOOMSENS) {
|
if (Math.abs(magnitude - this._gestureLastMagnitudeX) > GESTURE_ZOOMSENS) {
|
||||||
this._handleKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true);
|
this._handleKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true);
|
||||||
while ((magnitude - this._gestureLastMagnitudeX) > GESTURE_ZOOMSENS) {
|
while ((magnitude - this._gestureLastMagnitudeX) > GESTURE_ZOOMSENS) {
|
||||||
this._handleMouseButton(pos.x, pos.y, true, 0x8);
|
this._handleMouseButton(pos.x, pos.y, 0x8);
|
||||||
this._handleMouseButton(pos.x, pos.y, false, 0x8);
|
this._handleMouseButton(pos.x, pos.y, 0x0);
|
||||||
this._gestureLastMagnitudeX += GESTURE_ZOOMSENS;
|
this._gestureLastMagnitudeX += GESTURE_ZOOMSENS;
|
||||||
}
|
}
|
||||||
while ((magnitude - this._gestureLastMagnitudeX) < -GESTURE_ZOOMSENS) {
|
while ((magnitude - this._gestureLastMagnitudeX) < -GESTURE_ZOOMSENS) {
|
||||||
this._handleMouseButton(pos.x, pos.y, true, 0x10);
|
this._handleMouseButton(pos.x, pos.y, 0x10);
|
||||||
this._handleMouseButton(pos.x, pos.y, false, 0x10);
|
this._handleMouseButton(pos.x, pos.y, 0x0);
|
||||||
this._gestureLastMagnitudeX -= GESTURE_ZOOMSENS;
|
this._gestureLastMagnitudeX -= GESTURE_ZOOMSENS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1389,12 +1478,32 @@ export default class RFB extends EventTargetMixin {
|
||||||
case 'twodrag':
|
case 'twodrag':
|
||||||
break;
|
break;
|
||||||
case 'drag':
|
case 'drag':
|
||||||
|
if (this.dragViewport) {
|
||||||
|
this._viewportDragging = false;
|
||||||
|
} else {
|
||||||
this._fakeMouseMove(ev, pos.x, pos.y);
|
this._fakeMouseMove(ev, pos.x, pos.y);
|
||||||
this._handleMouseButton(pos.x, pos.y, false, 0x1);
|
this._handleMouseButton(pos.x, pos.y, 0x0);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'longpress':
|
case 'longpress':
|
||||||
|
if (this._viewportHasMoved) {
|
||||||
|
// We don't want to send any events if we have moved
|
||||||
|
// our viewport
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.dragViewport && !this._viewportHasMoved) {
|
||||||
this._fakeMouseMove(ev, pos.x, pos.y);
|
this._fakeMouseMove(ev, pos.x, pos.y);
|
||||||
this._handleMouseButton(pos.x, pos.y, false, 0x4);
|
// If dragViewport is true, we need to wait to see
|
||||||
|
// if we have dragged outside the threshold before
|
||||||
|
// sending any events to the server.
|
||||||
|
this._handleMouseButton(pos.x, pos.y, 0x4);
|
||||||
|
this._handleMouseButton(pos.x, pos.y, 0x0);
|
||||||
|
this._viewportDragging = false;
|
||||||
|
} else {
|
||||||
|
this._fakeMouseMove(ev, pos.x, pos.y);
|
||||||
|
this._handleMouseButton(pos.x, pos.y, 0x0);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1479,6 +1588,14 @@ export default class RFB extends EventTargetMixin {
|
||||||
this._sock.flush();
|
this._sock.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_flushMouseMoveTimer(x, y) {
|
||||||
|
if (this._mouseMoveTimer !== null) {
|
||||||
|
clearTimeout(this._mouseMoveTimer);
|
||||||
|
this._mouseMoveTimer = null;
|
||||||
|
this._sendMouse(x, y, this._mouseButtonMask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Message handlers
|
// Message handlers
|
||||||
|
|
||||||
_negotiateProtocolVersion() {
|
_negotiateProtocolVersion() {
|
||||||
|
@ -2247,6 +2364,7 @@ export default class RFB extends EventTargetMixin {
|
||||||
encs.push(encodings.pseudoEncodingContinuousUpdates);
|
encs.push(encodings.pseudoEncodingContinuousUpdates);
|
||||||
encs.push(encodings.pseudoEncodingDesktopName);
|
encs.push(encodings.pseudoEncodingDesktopName);
|
||||||
encs.push(encodings.pseudoEncodingExtendedClipboard);
|
encs.push(encodings.pseudoEncodingExtendedClipboard);
|
||||||
|
encs.push(encodings.pseudoEncodingExtendedMouseButtons);
|
||||||
|
|
||||||
if (this._gesturesMode === 'ultravnc') {
|
if (this._gesturesMode === 'ultravnc') {
|
||||||
encs.push(encodings.pseudoEncodingGii);
|
encs.push(encodings.pseudoEncodingGii);
|
||||||
|
@ -2707,6 +2825,10 @@ export default class RFB extends EventTargetMixin {
|
||||||
case encodings.pseudoEncodingExtendedDesktopSize:
|
case encodings.pseudoEncodingExtendedDesktopSize:
|
||||||
return this._handleExtendedDesktopSize();
|
return this._handleExtendedDesktopSize();
|
||||||
|
|
||||||
|
case encodings.pseudoEncodingExtendedMouseButtons:
|
||||||
|
this._extendedPointerEventSupported = true;
|
||||||
|
return true;
|
||||||
|
|
||||||
case encodings.pseudoEncodingQEMULedEvent:
|
case encodings.pseudoEncodingQEMULedEvent:
|
||||||
return this._handleLedEvent();
|
return this._handleLedEvent();
|
||||||
|
|
||||||
|
@ -2942,6 +3064,10 @@ export default class RFB extends EventTargetMixin {
|
||||||
* 2 - another client requested the resize
|
* 2 - another client requested the resize
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
if (this._FBU.x === 1) {
|
||||||
|
this._pendingRemoteResize = false;
|
||||||
|
}
|
||||||
|
|
||||||
// We need to handle errors when we requested the resize.
|
// We need to handle errors when we requested the resize.
|
||||||
if (this._FBU.x === 1 && this._FBU.y !== 0) {
|
if (this._FBU.x === 1 && this._FBU.y !== 0) {
|
||||||
let msg = "";
|
let msg = "";
|
||||||
|
@ -2974,6 +3100,12 @@ export default class RFB extends EventTargetMixin {
|
||||||
this._requestRemoteResize();
|
this._requestRemoteResize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this._FBU.x === 1 && this._FBU.y === 0) {
|
||||||
|
// We might have resized again whilst waiting for the
|
||||||
|
// previous request, so check if we are in sync
|
||||||
|
this._requestRemoteResize();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3003,6 +3135,7 @@ export default class RFB extends EventTargetMixin {
|
||||||
this._fbWidth, this._fbHeight);
|
this._fbWidth, this._fbHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle resize-messages from the server
|
||||||
_resize(width, height) {
|
_resize(width, height) {
|
||||||
this._fbWidth = width;
|
this._fbWidth = width;
|
||||||
this._fbHeight = height;
|
this._fbHeight = height;
|
||||||
|
@ -3125,6 +3258,10 @@ RFB.messages = {
|
||||||
pointerEvent(sock, x, y, mask) {
|
pointerEvent(sock, x, y, mask) {
|
||||||
sock.sQpush8(5); // msg-type
|
sock.sQpush8(5); // msg-type
|
||||||
|
|
||||||
|
// Marker bit must be set to 0, otherwise the server might
|
||||||
|
// confuse the marker bit with the highest bit in a normal
|
||||||
|
// PointerEvent message.
|
||||||
|
mask = mask & 0x7f;
|
||||||
sock.sQpush8(mask);
|
sock.sQpush8(mask);
|
||||||
|
|
||||||
sock.sQpush16(x);
|
sock.sQpush16(x);
|
||||||
|
@ -3133,6 +3270,27 @@ RFB.messages = {
|
||||||
sock.flush();
|
sock.flush();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
extendedPointerEvent(sock, x, y, mask) {
|
||||||
|
sock.sQpush8(5); // msg-type
|
||||||
|
|
||||||
|
let higherBits = (mask >> 7) & 0xff;
|
||||||
|
|
||||||
|
// Bits 2-7 are reserved
|
||||||
|
if (higherBits & 0xfc) {
|
||||||
|
throw new Error("Invalid mouse button mask: " + mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
let lowerBits = mask & 0x7f;
|
||||||
|
lowerBits |= 0x80; // Set marker bit to 1
|
||||||
|
|
||||||
|
sock.sQpush8(lowerBits);
|
||||||
|
sock.sQpush16(x);
|
||||||
|
sock.sQpush16(y);
|
||||||
|
sock.sQpush8(higherBits);
|
||||||
|
|
||||||
|
sock.flush();
|
||||||
|
},
|
||||||
|
|
||||||
// Used to build Notify and Request data.
|
// Used to build Notify and Request data.
|
||||||
_buildExtendedClipboardFlags(actions, formats) {
|
_buildExtendedClipboardFlags(actions, formats) {
|
||||||
let data = new Uint8Array(4);
|
let data = new Uint8Array(4);
|
||||||
|
|
|
@ -13,7 +13,7 @@ import Base64 from '../base64.js';
|
||||||
|
|
||||||
// Touch detection
|
// Touch detection
|
||||||
export let isTouchDevice = ('ontouchstart' in document.documentElement) ||
|
export let isTouchDevice = ('ontouchstart' in document.documentElement) ||
|
||||||
// requried for Chrome debugger
|
// required for Chrome debugger
|
||||||
(document.ontouchstart !== undefined) ||
|
(document.ontouchstart !== undefined) ||
|
||||||
// required for MS Surface
|
// required for MS Surface
|
||||||
(navigator.maxTouchPoints > 0) ||
|
(navigator.maxTouchPoints > 0) ||
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@novnc/novnc",
|
"name": "@novnc/novnc",
|
||||||
"version": "1.5.0",
|
"version": "1.6.0-beta",
|
||||||
"description": "An HTML5 VNC client",
|
"description": "An HTML5 VNC client",
|
||||||
"browser": "lib/rfb",
|
"browser": "lib/rfb",
|
||||||
"directories": {
|
"directories": {
|
||||||
|
@ -56,8 +56,7 @@
|
||||||
"karma-safari-launcher": "latest",
|
"karma-safari-launcher": "latest",
|
||||||
"karma-script-launcher": "latest",
|
"karma-script-launcher": "latest",
|
||||||
"mocha": "latest",
|
"mocha": "latest",
|
||||||
"node-getopt": "latest",
|
"pofile": "latest",
|
||||||
"po2json": "latest",
|
|
||||||
"sinon": "latest",
|
"sinon": "latest",
|
||||||
"sinon-chai": "latest"
|
"sinon-chai": "latest"
|
||||||
},
|
},
|
||||||
|
|
199
po/ja.po
199
po/ja.po
|
@ -1,15 +1,15 @@
|
||||||
# Japanese translations for noVNC package
|
# Japanese translations for noVNC package
|
||||||
# noVNC パッケージに対する日訳
|
# noVNC パッケージに対する日訳
|
||||||
# Copyright (C) 2019 The noVNC authors
|
# Copyright (C) 2019-2024 The noVNC authors
|
||||||
# This file is distributed under the same license as the noVNC package.
|
# This file is distributed under the same license as the noVNC package.
|
||||||
# nnn1590 <nnn1590@nnn1590.org>, 2019-2020.
|
# nnn1590 <nnn1590@nnn1590.org>, 2019-2024.
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: noVNC 1.1.0\n"
|
"Project-Id-Version: noVNC 1.5.0\n"
|
||||||
"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
|
"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
|
||||||
"POT-Creation-Date: 2022-12-27 15:24+0100\n"
|
"POT-Creation-Date: 2024-06-03 14:10+0200\n"
|
||||||
"PO-Revision-Date: 2023-03-21 12:42+0900\n"
|
"PO-Revision-Date: 2024-12-14 15:22+0900\n"
|
||||||
"Last-Translator: nnn1590 <nnn1590@nnn1590.org>\n"
|
"Last-Translator: nnn1590 <nnn1590@nnn1590.org>\n"
|
||||||
"Language-Team: Japanese\n"
|
"Language-Team: Japanese\n"
|
||||||
"Language: ja\n"
|
"Language: ja\n"
|
||||||
|
@ -20,8 +20,11 @@ msgstr ""
|
||||||
"X-Generator: Poedit 2.3\n"
|
"X-Generator: Poedit 2.3\n"
|
||||||
|
|
||||||
#: ../app/ui.js:69
|
#: ../app/ui.js:69
|
||||||
msgid "HTTPS is required for full functionality"
|
msgid ""
|
||||||
msgstr "すべての機能を使用するにはHTTPS接続が必要です"
|
"Running without HTTPS is not recommended, crashes or other issues are likely."
|
||||||
|
msgstr ""
|
||||||
|
"HTTPS接続なしで実行することは推奨されません。クラッシュしたりその他の問題が発"
|
||||||
|
"生したりする可能性があります。"
|
||||||
|
|
||||||
#: ../app/ui.js:410
|
#: ../app/ui.js:410
|
||||||
msgid "Connecting..."
|
msgid "Connecting..."
|
||||||
|
@ -43,321 +46,297 @@ msgstr "内部エラー"
|
||||||
msgid "Must set host"
|
msgid "Must set host"
|
||||||
msgstr "ホストを設定する必要があります"
|
msgstr "ホストを設定する必要があります"
|
||||||
|
|
||||||
#: ../app/ui.js:1110
|
#: ../app/ui.js:1052
|
||||||
|
msgid "Failed to connect to server: "
|
||||||
|
msgstr "サーバーへの接続に失敗しました: "
|
||||||
|
|
||||||
|
#: ../app/ui.js:1118
|
||||||
msgid "Connected (encrypted) to "
|
msgid "Connected (encrypted) to "
|
||||||
msgstr "接続しました (暗号化済み): "
|
msgstr "接続しました (暗号化済み): "
|
||||||
|
|
||||||
#: ../app/ui.js:1112
|
#: ../app/ui.js:1120
|
||||||
msgid "Connected (unencrypted) to "
|
msgid "Connected (unencrypted) to "
|
||||||
msgstr "接続しました (暗号化されていません): "
|
msgstr "接続しました (暗号化されていません): "
|
||||||
|
|
||||||
#: ../app/ui.js:1135
|
#: ../app/ui.js:1143
|
||||||
msgid "Something went wrong, connection is closed"
|
msgid "Something went wrong, connection is closed"
|
||||||
msgstr "何らかの問題で、接続が閉じられました"
|
msgstr "問題が発生したため、接続が閉じられました"
|
||||||
|
|
||||||
#: ../app/ui.js:1138
|
#: ../app/ui.js:1146
|
||||||
msgid "Failed to connect to server"
|
msgid "Failed to connect to server"
|
||||||
msgstr "サーバーへの接続に失敗しました"
|
msgstr "サーバーへの接続に失敗しました"
|
||||||
|
|
||||||
#: ../app/ui.js:1150
|
#: ../app/ui.js:1158
|
||||||
msgid "Disconnected"
|
msgid "Disconnected"
|
||||||
msgstr "切断しました"
|
msgstr "切断しました"
|
||||||
|
|
||||||
#: ../app/ui.js:1165
|
#: ../app/ui.js:1173
|
||||||
msgid "New connection has been rejected with reason: "
|
msgid "New connection has been rejected with reason: "
|
||||||
msgstr "新規接続は次の理由で拒否されました: "
|
msgstr "新規接続は次の理由で拒否されました: "
|
||||||
|
|
||||||
#: ../app/ui.js:1168
|
#: ../app/ui.js:1176
|
||||||
msgid "New connection has been rejected"
|
msgid "New connection has been rejected"
|
||||||
msgstr "新規接続は拒否されました"
|
msgstr "新規接続は拒否されました"
|
||||||
|
|
||||||
#: ../app/ui.js:1234
|
#: ../app/ui.js:1242
|
||||||
msgid "Credentials are required"
|
msgid "Credentials are required"
|
||||||
msgstr "資格情報が必要です"
|
msgstr "資格情報が必要です"
|
||||||
|
|
||||||
#: ../vnc.html:57
|
#: ../vnc.html:55
|
||||||
msgid "noVNC encountered an error:"
|
msgid "noVNC encountered an error:"
|
||||||
msgstr "noVNC でエラーが発生しました:"
|
msgstr "noVNC でエラーが発生しました:"
|
||||||
|
|
||||||
#: ../vnc.html:67
|
#: ../vnc.html:65
|
||||||
msgid "Hide/Show the control bar"
|
msgid "Hide/Show the control bar"
|
||||||
msgstr "コントロールバーを隠す/表示する"
|
msgstr "コントロールバーを隠す/表示する"
|
||||||
|
|
||||||
#: ../vnc.html:76
|
#: ../vnc.html:74
|
||||||
msgid "Drag"
|
msgid "Drag"
|
||||||
msgstr "ドラッグ"
|
msgstr "ドラッグ"
|
||||||
|
|
||||||
#: ../vnc.html:76
|
#: ../vnc.html:74
|
||||||
msgid "Move/Drag viewport"
|
msgid "Move/Drag viewport"
|
||||||
msgstr "ビューポートを移動/ドラッグ"
|
msgstr "ビューポートを移動/ドラッグ"
|
||||||
|
|
||||||
#: ../vnc.html:82
|
#: ../vnc.html:80
|
||||||
msgid "Keyboard"
|
msgid "Keyboard"
|
||||||
msgstr "キーボード"
|
msgstr "キーボード"
|
||||||
|
|
||||||
#: ../vnc.html:82
|
#: ../vnc.html:80
|
||||||
msgid "Show keyboard"
|
msgid "Show keyboard"
|
||||||
msgstr "キーボードを表示"
|
msgstr "キーボードを表示"
|
||||||
|
|
||||||
#: ../vnc.html:87
|
#: ../vnc.html:85
|
||||||
msgid "Extra keys"
|
msgid "Extra keys"
|
||||||
msgstr "追加キー"
|
msgstr "追加キー"
|
||||||
|
|
||||||
#: ../vnc.html:87
|
#: ../vnc.html:85
|
||||||
msgid "Show extra keys"
|
msgid "Show extra keys"
|
||||||
msgstr "追加キーを表示"
|
msgstr "追加キーを表示"
|
||||||
|
|
||||||
#: ../vnc.html:92
|
#: ../vnc.html:90
|
||||||
msgid "Ctrl"
|
msgid "Ctrl"
|
||||||
msgstr "Ctrl"
|
msgstr "Ctrl"
|
||||||
|
|
||||||
#: ../vnc.html:92
|
#: ../vnc.html:90
|
||||||
msgid "Toggle Ctrl"
|
msgid "Toggle Ctrl"
|
||||||
msgstr "Ctrl キーをトグル"
|
msgstr "Ctrl キーをトグル"
|
||||||
|
|
||||||
#: ../vnc.html:95
|
#: ../vnc.html:93
|
||||||
msgid "Alt"
|
msgid "Alt"
|
||||||
msgstr "Alt"
|
msgstr "Alt"
|
||||||
|
|
||||||
#: ../vnc.html:95
|
#: ../vnc.html:93
|
||||||
msgid "Toggle Alt"
|
msgid "Toggle Alt"
|
||||||
msgstr "Alt キーをトグル"
|
msgstr "Alt キーをトグル"
|
||||||
|
|
||||||
#: ../vnc.html:98
|
#: ../vnc.html:96
|
||||||
msgid "Toggle Windows"
|
msgid "Toggle Windows"
|
||||||
msgstr "Windows キーをトグル"
|
msgstr "Windows キーをトグル"
|
||||||
|
|
||||||
#: ../vnc.html:98
|
#: ../vnc.html:96
|
||||||
msgid "Windows"
|
msgid "Windows"
|
||||||
msgstr "Windows"
|
msgstr "Windows"
|
||||||
|
|
||||||
#: ../vnc.html:101
|
#: ../vnc.html:99
|
||||||
msgid "Send Tab"
|
msgid "Send Tab"
|
||||||
msgstr "Tab キーを送信"
|
msgstr "Tab キーを送信"
|
||||||
|
|
||||||
#: ../vnc.html:101
|
#: ../vnc.html:99
|
||||||
msgid "Tab"
|
msgid "Tab"
|
||||||
msgstr "Tab"
|
msgstr "Tab"
|
||||||
|
|
||||||
#: ../vnc.html:104
|
#: ../vnc.html:102
|
||||||
msgid "Esc"
|
msgid "Esc"
|
||||||
msgstr "Esc"
|
msgstr "Esc"
|
||||||
|
|
||||||
#: ../vnc.html:104
|
#: ../vnc.html:102
|
||||||
msgid "Send Escape"
|
msgid "Send Escape"
|
||||||
msgstr "Escape キーを送信"
|
msgstr "Escape キーを送信"
|
||||||
|
|
||||||
#: ../vnc.html:107
|
#: ../vnc.html:105
|
||||||
msgid "Ctrl+Alt+Del"
|
msgid "Ctrl+Alt+Del"
|
||||||
msgstr "Ctrl+Alt+Del"
|
msgstr "Ctrl+Alt+Del"
|
||||||
|
|
||||||
#: ../vnc.html:107
|
#: ../vnc.html:105
|
||||||
msgid "Send Ctrl-Alt-Del"
|
msgid "Send Ctrl-Alt-Del"
|
||||||
msgstr "Ctrl-Alt-Del を送信"
|
msgstr "Ctrl-Alt-Del を送信"
|
||||||
|
|
||||||
#: ../vnc.html:114
|
#: ../vnc.html:112
|
||||||
msgid "Shutdown/Reboot"
|
msgid "Shutdown/Reboot"
|
||||||
msgstr "シャットダウン/再起動"
|
msgstr "シャットダウン/再起動"
|
||||||
|
|
||||||
#: ../vnc.html:114
|
#: ../vnc.html:112
|
||||||
msgid "Shutdown/Reboot..."
|
msgid "Shutdown/Reboot..."
|
||||||
msgstr "シャットダウン/再起動..."
|
msgstr "シャットダウン/再起動..."
|
||||||
|
|
||||||
#: ../vnc.html:120
|
#: ../vnc.html:118
|
||||||
msgid "Power"
|
msgid "Power"
|
||||||
msgstr "電源"
|
msgstr "電源"
|
||||||
|
|
||||||
#: ../vnc.html:122
|
#: ../vnc.html:120
|
||||||
msgid "Shutdown"
|
msgid "Shutdown"
|
||||||
msgstr "シャットダウン"
|
msgstr "シャットダウン"
|
||||||
|
|
||||||
#: ../vnc.html:123
|
#: ../vnc.html:121
|
||||||
msgid "Reboot"
|
msgid "Reboot"
|
||||||
msgstr "再起動"
|
msgstr "再起動"
|
||||||
|
|
||||||
#: ../vnc.html:124
|
#: ../vnc.html:122
|
||||||
msgid "Reset"
|
msgid "Reset"
|
||||||
msgstr "リセット"
|
msgstr "リセット"
|
||||||
|
|
||||||
#: ../vnc.html:129 ../vnc.html:135
|
#: ../vnc.html:127 ../vnc.html:133
|
||||||
msgid "Clipboard"
|
msgid "Clipboard"
|
||||||
msgstr "クリップボード"
|
msgstr "クリップボード"
|
||||||
|
|
||||||
#: ../vnc.html:137
|
#: ../vnc.html:135
|
||||||
msgid "Edit clipboard content in the textarea below."
|
msgid "Edit clipboard content in the textarea below."
|
||||||
msgstr "以下の入力欄からクリップボードの内容を編集できます。"
|
msgstr "以下の入力欄からクリップボードの内容を編集できます。"
|
||||||
|
|
||||||
#: ../vnc.html:145
|
#: ../vnc.html:143
|
||||||
msgid "Full screen"
|
msgid "Full screen"
|
||||||
msgstr "全画面表示"
|
msgstr "全画面表示"
|
||||||
|
|
||||||
#: ../vnc.html:150 ../vnc.html:156
|
#: ../vnc.html:148 ../vnc.html:154
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr "設定"
|
msgstr "設定"
|
||||||
|
|
||||||
#: ../vnc.html:160
|
#: ../vnc.html:158
|
||||||
msgid "Shared mode"
|
msgid "Shared mode"
|
||||||
msgstr "共有モード"
|
msgstr "共有モード"
|
||||||
|
|
||||||
#: ../vnc.html:163
|
#: ../vnc.html:161
|
||||||
msgid "View only"
|
msgid "View only"
|
||||||
msgstr "表示専用"
|
msgstr "表示専用"
|
||||||
|
|
||||||
#: ../vnc.html:167
|
#: ../vnc.html:165
|
||||||
msgid "Clip to window"
|
msgid "Clip to window"
|
||||||
msgstr "ウィンドウにクリップ"
|
msgstr "ウィンドウにクリップ"
|
||||||
|
|
||||||
#: ../vnc.html:170
|
#: ../vnc.html:168
|
||||||
msgid "Scaling mode:"
|
msgid "Scaling mode:"
|
||||||
msgstr "スケーリングモード:"
|
msgstr "スケーリングモード:"
|
||||||
|
|
||||||
#: ../vnc.html:172
|
#: ../vnc.html:170
|
||||||
msgid "None"
|
msgid "None"
|
||||||
msgstr "なし"
|
msgstr "なし"
|
||||||
|
|
||||||
#: ../vnc.html:173
|
#: ../vnc.html:171
|
||||||
msgid "Local scaling"
|
msgid "Local scaling"
|
||||||
msgstr "ローカルスケーリング"
|
msgstr "ローカルでスケーリング"
|
||||||
|
|
||||||
#: ../vnc.html:174
|
#: ../vnc.html:172
|
||||||
msgid "Remote resizing"
|
msgid "Remote resizing"
|
||||||
msgstr "リモートでリサイズ"
|
msgstr "リモートでリサイズ"
|
||||||
|
|
||||||
#: ../vnc.html:179
|
#: ../vnc.html:177
|
||||||
msgid "Advanced"
|
msgid "Advanced"
|
||||||
msgstr "高度"
|
msgstr "高度"
|
||||||
|
|
||||||
#: ../vnc.html:182
|
#: ../vnc.html:180
|
||||||
msgid "Quality:"
|
msgid "Quality:"
|
||||||
msgstr "品質:"
|
msgstr "品質:"
|
||||||
|
|
||||||
#: ../vnc.html:186
|
#: ../vnc.html:184
|
||||||
msgid "Compression level:"
|
msgid "Compression level:"
|
||||||
msgstr "圧縮レベル:"
|
msgstr "圧縮レベル:"
|
||||||
|
|
||||||
#: ../vnc.html:191
|
#: ../vnc.html:189
|
||||||
msgid "Repeater ID:"
|
msgid "Repeater ID:"
|
||||||
msgstr "リピーター ID:"
|
msgstr "リピーター ID:"
|
||||||
|
|
||||||
#: ../vnc.html:195
|
#: ../vnc.html:193
|
||||||
msgid "WebSocket"
|
msgid "WebSocket"
|
||||||
msgstr "WebSocket"
|
msgstr "WebSocket"
|
||||||
|
|
||||||
#: ../vnc.html:198
|
#: ../vnc.html:196
|
||||||
msgid "Encrypt"
|
msgid "Encrypt"
|
||||||
msgstr "暗号化"
|
msgstr "暗号化"
|
||||||
|
|
||||||
#: ../vnc.html:201
|
#: ../vnc.html:199
|
||||||
msgid "Host:"
|
msgid "Host:"
|
||||||
msgstr "ホスト:"
|
msgstr "ホスト:"
|
||||||
|
|
||||||
#: ../vnc.html:205
|
#: ../vnc.html:203
|
||||||
msgid "Port:"
|
msgid "Port:"
|
||||||
msgstr "ポート:"
|
msgstr "ポート:"
|
||||||
|
|
||||||
#: ../vnc.html:209
|
#: ../vnc.html:207
|
||||||
msgid "Path:"
|
msgid "Path:"
|
||||||
msgstr "パス:"
|
msgstr "パス:"
|
||||||
|
|
||||||
#: ../vnc.html:216
|
#: ../vnc.html:214
|
||||||
msgid "Automatic reconnect"
|
msgid "Automatic reconnect"
|
||||||
msgstr "自動再接続"
|
msgstr "自動再接続"
|
||||||
|
|
||||||
#: ../vnc.html:219
|
#: ../vnc.html:217
|
||||||
msgid "Reconnect delay (ms):"
|
msgid "Reconnect delay (ms):"
|
||||||
msgstr "再接続する遅延 (ミリ秒):"
|
msgstr "再接続する遅延 (ミリ秒):"
|
||||||
|
|
||||||
#: ../vnc.html:224
|
#: ../vnc.html:222
|
||||||
msgid "Show dot when no cursor"
|
msgid "Show dot when no cursor"
|
||||||
msgstr "カーソルがないときにドットを表示する"
|
msgstr "カーソルがないときにドットを表示する"
|
||||||
|
|
||||||
#: ../vnc.html:229
|
#: ../vnc.html:227
|
||||||
msgid "Logging:"
|
msgid "Logging:"
|
||||||
msgstr "ロギング:"
|
msgstr "ロギング:"
|
||||||
|
|
||||||
#: ../vnc.html:238
|
#: ../vnc.html:236
|
||||||
msgid "Version:"
|
msgid "Version:"
|
||||||
msgstr "バージョン:"
|
msgstr "バージョン:"
|
||||||
|
|
||||||
#: ../vnc.html:246
|
#: ../vnc.html:244
|
||||||
msgid "Disconnect"
|
msgid "Disconnect"
|
||||||
msgstr "切断"
|
msgstr "切断"
|
||||||
|
|
||||||
#: ../vnc.html:269
|
#: ../vnc.html:267
|
||||||
msgid "Connect"
|
msgid "Connect"
|
||||||
msgstr "接続"
|
msgstr "接続"
|
||||||
|
|
||||||
#: ../vnc.html:278
|
#: ../vnc.html:276
|
||||||
msgid "Server identity"
|
msgid "Server identity"
|
||||||
msgstr "サーバーの識別情報"
|
msgstr "サーバーの識別情報"
|
||||||
|
|
||||||
#: ../vnc.html:281
|
#: ../vnc.html:279
|
||||||
msgid "The server has provided the following identifying information:"
|
msgid "The server has provided the following identifying information:"
|
||||||
msgstr "サーバーは以下の識別情報を提供しています:"
|
msgstr "サーバーは以下の識別情報を提供しています:"
|
||||||
|
|
||||||
#: ../vnc.html:285
|
#: ../vnc.html:283
|
||||||
msgid "Fingerprint:"
|
msgid "Fingerprint:"
|
||||||
msgstr "フィンガープリント:"
|
msgstr "フィンガープリント:"
|
||||||
|
|
||||||
#: ../vnc.html:288
|
#: ../vnc.html:286
|
||||||
msgid ""
|
msgid ""
|
||||||
"Please verify that the information is correct and press \"Approve\". "
|
"Please verify that the information is correct and press \"Approve\". "
|
||||||
"Otherwise press \"Reject\"."
|
"Otherwise press \"Reject\"."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"この情報が正しい場合は「承認」を、そうでない場合は「拒否」を押してく"
|
"この情報が正しい場合は「承認」を、そうでない場合は「拒否」を押してください。"
|
||||||
"ださい。"
|
|
||||||
|
|
||||||
#: ../vnc.html:293
|
#: ../vnc.html:291
|
||||||
msgid "Approve"
|
msgid "Approve"
|
||||||
msgstr "承認"
|
msgstr "承認"
|
||||||
|
|
||||||
#: ../vnc.html:294
|
#: ../vnc.html:292
|
||||||
msgid "Reject"
|
msgid "Reject"
|
||||||
msgstr "拒否"
|
msgstr "拒否"
|
||||||
|
|
||||||
#: ../vnc.html:302
|
#: ../vnc.html:300
|
||||||
msgid "Credentials"
|
msgid "Credentials"
|
||||||
msgstr "資格情報"
|
msgstr "資格情報"
|
||||||
|
|
||||||
#: ../vnc.html:306
|
#: ../vnc.html:304
|
||||||
msgid "Username:"
|
msgid "Username:"
|
||||||
msgstr "ユーザー名:"
|
msgstr "ユーザー名:"
|
||||||
|
|
||||||
#: ../vnc.html:310
|
#: ../vnc.html:308
|
||||||
msgid "Password:"
|
msgid "Password:"
|
||||||
msgstr "パスワード:"
|
msgstr "パスワード:"
|
||||||
|
|
||||||
#: ../vnc.html:314
|
#: ../vnc.html:312
|
||||||
msgid "Send credentials"
|
msgid "Send credentials"
|
||||||
msgstr "資格情報を送信"
|
msgstr "資格情報を送信"
|
||||||
|
|
||||||
#: ../vnc.html:323
|
#: ../vnc.html:321
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "キャンセル"
|
msgstr "キャンセル"
|
||||||
|
|
||||||
#~ msgid "Clear"
|
|
||||||
#~ msgstr "クリア"
|
|
||||||
|
|
||||||
#~ msgid "Password is required"
|
|
||||||
#~ msgstr "パスワードが必要です"
|
|
||||||
|
|
||||||
#~ msgid "viewport drag"
|
|
||||||
#~ msgstr "ビューポートをドラッグ"
|
|
||||||
|
|
||||||
#~ msgid "Active Mouse Button"
|
|
||||||
#~ msgstr "アクティブなマウスボタン"
|
|
||||||
|
|
||||||
#~ msgid "No mousebutton"
|
|
||||||
#~ msgstr "マウスボタンなし"
|
|
||||||
|
|
||||||
#~ msgid "Left mousebutton"
|
|
||||||
#~ msgstr "左マウスボタン"
|
|
||||||
|
|
||||||
#~ msgid "Middle mousebutton"
|
|
||||||
#~ msgstr "中マウスボタン"
|
|
||||||
|
|
||||||
#~ msgid "Right mousebutton"
|
|
||||||
#~ msgstr "右マウスボタン"
|
|
||||||
|
|
||||||
#~ msgid "Send Password"
|
|
||||||
#~ msgstr "パスワードを送信"
|
|
||||||
|
|
164
po/noVNC.pot
164
po/noVNC.pot
|
@ -6,9 +6,9 @@
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: noVNC 1.5.0\n"
|
"Project-Id-Version: noVNC 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
|
"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
|
||||||
"POT-Creation-Date: 2024-06-03 14:10+0200\n"
|
"POT-Creation-Date: 2025-02-14 10:14+0100\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -17,321 +17,317 @@ msgstr ""
|
||||||
"Content-Type: text/plain; charset=CHARSET\n"
|
"Content-Type: text/plain; charset=CHARSET\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
#: ../app/ui.js:69
|
#: ../app/ui.js:84
|
||||||
msgid ""
|
msgid ""
|
||||||
"Running without HTTPS is not recommended, crashes or other issues are likely."
|
"Running without HTTPS is not recommended, crashes or other issues are likely."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../app/ui.js:410
|
#: ../app/ui.js:413
|
||||||
msgid "Connecting..."
|
msgid "Connecting..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../app/ui.js:417
|
#: ../app/ui.js:420
|
||||||
msgid "Disconnecting..."
|
msgid "Disconnecting..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../app/ui.js:423
|
#: ../app/ui.js:426
|
||||||
msgid "Reconnecting..."
|
msgid "Reconnecting..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../app/ui.js:428
|
#: ../app/ui.js:431
|
||||||
msgid "Internal error"
|
msgid "Internal error"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../app/ui.js:1026
|
#: ../app/ui.js:1079
|
||||||
msgid "Must set host"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../app/ui.js:1052
|
|
||||||
msgid "Failed to connect to server: "
|
msgid "Failed to connect to server: "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../app/ui.js:1118
|
#: ../app/ui.js:1145
|
||||||
msgid "Connected (encrypted) to "
|
msgid "Connected (encrypted) to "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../app/ui.js:1120
|
#: ../app/ui.js:1147
|
||||||
msgid "Connected (unencrypted) to "
|
msgid "Connected (unencrypted) to "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../app/ui.js:1143
|
#: ../app/ui.js:1170
|
||||||
msgid "Something went wrong, connection is closed"
|
msgid "Something went wrong, connection is closed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../app/ui.js:1146
|
#: ../app/ui.js:1173
|
||||||
msgid "Failed to connect to server"
|
msgid "Failed to connect to server"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../app/ui.js:1158
|
#: ../app/ui.js:1185
|
||||||
msgid "Disconnected"
|
msgid "Disconnected"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../app/ui.js:1173
|
#: ../app/ui.js:1200
|
||||||
msgid "New connection has been rejected with reason: "
|
msgid "New connection has been rejected with reason: "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../app/ui.js:1176
|
#: ../app/ui.js:1203
|
||||||
msgid "New connection has been rejected"
|
msgid "New connection has been rejected"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../app/ui.js:1242
|
#: ../app/ui.js:1269
|
||||||
msgid "Credentials are required"
|
msgid "Credentials are required"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:55
|
#: ../vnc.html:106
|
||||||
msgid "noVNC encountered an error:"
|
msgid "noVNC encountered an error:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:65
|
#: ../vnc.html:116
|
||||||
msgid "Hide/Show the control bar"
|
msgid "Hide/Show the control bar"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:74
|
#: ../vnc.html:125
|
||||||
msgid "Drag"
|
msgid "Drag"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:74
|
#: ../vnc.html:125
|
||||||
msgid "Move/Drag viewport"
|
msgid "Move/Drag viewport"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:80
|
#: ../vnc.html:131
|
||||||
msgid "Keyboard"
|
msgid "Keyboard"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:80
|
#: ../vnc.html:131
|
||||||
msgid "Show keyboard"
|
msgid "Show keyboard"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:85
|
#: ../vnc.html:136
|
||||||
msgid "Extra keys"
|
msgid "Extra keys"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:85
|
#: ../vnc.html:136
|
||||||
msgid "Show extra keys"
|
msgid "Show extra keys"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:90
|
#: ../vnc.html:141
|
||||||
msgid "Ctrl"
|
msgid "Ctrl"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:90
|
#: ../vnc.html:141
|
||||||
msgid "Toggle Ctrl"
|
msgid "Toggle Ctrl"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:93
|
#: ../vnc.html:144
|
||||||
msgid "Alt"
|
msgid "Alt"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:93
|
#: ../vnc.html:144
|
||||||
msgid "Toggle Alt"
|
msgid "Toggle Alt"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:96
|
#: ../vnc.html:147
|
||||||
msgid "Toggle Windows"
|
msgid "Toggle Windows"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:96
|
#: ../vnc.html:147
|
||||||
msgid "Windows"
|
msgid "Windows"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:99
|
#: ../vnc.html:150
|
||||||
msgid "Send Tab"
|
msgid "Send Tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:99
|
#: ../vnc.html:150
|
||||||
msgid "Tab"
|
msgid "Tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:102
|
#: ../vnc.html:153
|
||||||
msgid "Esc"
|
msgid "Esc"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:102
|
#: ../vnc.html:153
|
||||||
msgid "Send Escape"
|
msgid "Send Escape"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:105
|
#: ../vnc.html:156
|
||||||
msgid "Ctrl+Alt+Del"
|
msgid "Ctrl+Alt+Del"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:105
|
#: ../vnc.html:156
|
||||||
msgid "Send Ctrl-Alt-Del"
|
msgid "Send Ctrl-Alt-Del"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:112
|
#: ../vnc.html:163
|
||||||
msgid "Shutdown/Reboot"
|
msgid "Shutdown/Reboot"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:112
|
#: ../vnc.html:163
|
||||||
msgid "Shutdown/Reboot..."
|
msgid "Shutdown/Reboot..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:118
|
#: ../vnc.html:169
|
||||||
msgid "Power"
|
msgid "Power"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:120
|
#: ../vnc.html:171
|
||||||
msgid "Shutdown"
|
msgid "Shutdown"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:121
|
#: ../vnc.html:172
|
||||||
msgid "Reboot"
|
msgid "Reboot"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:122
|
#: ../vnc.html:173
|
||||||
msgid "Reset"
|
msgid "Reset"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:127 ../vnc.html:133
|
#: ../vnc.html:178 ../vnc.html:184
|
||||||
msgid "Clipboard"
|
msgid "Clipboard"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:135
|
#: ../vnc.html:186
|
||||||
msgid "Edit clipboard content in the textarea below."
|
msgid "Edit clipboard content in the textarea below."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:143
|
#: ../vnc.html:194
|
||||||
msgid "Full screen"
|
msgid "Full screen"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:148 ../vnc.html:154
|
#: ../vnc.html:199 ../vnc.html:205
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:158
|
#: ../vnc.html:211
|
||||||
msgid "Shared mode"
|
msgid "Shared mode"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:161
|
#: ../vnc.html:218
|
||||||
msgid "View only"
|
msgid "View only"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:165
|
#: ../vnc.html:226
|
||||||
msgid "Clip to window"
|
msgid "Clip to window"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:168
|
#: ../vnc.html:231
|
||||||
msgid "Scaling mode:"
|
msgid "Scaling mode:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:170
|
#: ../vnc.html:233
|
||||||
msgid "None"
|
msgid "None"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:171
|
#: ../vnc.html:234
|
||||||
msgid "Local scaling"
|
msgid "Local scaling"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:172
|
#: ../vnc.html:235
|
||||||
msgid "Remote resizing"
|
msgid "Remote resizing"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:177
|
#: ../vnc.html:240
|
||||||
msgid "Advanced"
|
msgid "Advanced"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:180
|
#: ../vnc.html:243
|
||||||
msgid "Quality:"
|
msgid "Quality:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:184
|
#: ../vnc.html:247
|
||||||
msgid "Compression level:"
|
msgid "Compression level:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:189
|
#: ../vnc.html:252
|
||||||
msgid "Repeater ID:"
|
msgid "Repeater ID:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:193
|
#: ../vnc.html:256
|
||||||
msgid "WebSocket"
|
msgid "WebSocket"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:196
|
#: ../vnc.html:261
|
||||||
msgid "Encrypt"
|
msgid "Encrypt"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:199
|
#: ../vnc.html:266
|
||||||
msgid "Host:"
|
msgid "Host:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:203
|
#: ../vnc.html:270
|
||||||
msgid "Port:"
|
msgid "Port:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:207
|
#: ../vnc.html:274
|
||||||
msgid "Path:"
|
msgid "Path:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:214
|
#: ../vnc.html:283
|
||||||
msgid "Automatic reconnect"
|
msgid "Automatic reconnect"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:217
|
#: ../vnc.html:288
|
||||||
msgid "Reconnect delay (ms):"
|
msgid "Reconnect delay (ms):"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:222
|
#: ../vnc.html:295
|
||||||
msgid "Show dot when no cursor"
|
msgid "Show dot when no cursor"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:227
|
#: ../vnc.html:302
|
||||||
msgid "Logging:"
|
msgid "Logging:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:236
|
#: ../vnc.html:311
|
||||||
msgid "Version:"
|
msgid "Version:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:244
|
#: ../vnc.html:319
|
||||||
msgid "Disconnect"
|
msgid "Disconnect"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:267
|
#: ../vnc.html:342
|
||||||
msgid "Connect"
|
msgid "Connect"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:276
|
#: ../vnc.html:351
|
||||||
msgid "Server identity"
|
msgid "Server identity"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:279
|
#: ../vnc.html:354
|
||||||
msgid "The server has provided the following identifying information:"
|
msgid "The server has provided the following identifying information:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:283
|
#: ../vnc.html:357
|
||||||
msgid "Fingerprint:"
|
msgid "Fingerprint:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:286
|
#: ../vnc.html:361
|
||||||
msgid ""
|
msgid ""
|
||||||
"Please verify that the information is correct and press \"Approve\". "
|
"Please verify that the information is correct and press \"Approve\". "
|
||||||
"Otherwise press \"Reject\"."
|
"Otherwise press \"Reject\"."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:291
|
#: ../vnc.html:366
|
||||||
msgid "Approve"
|
msgid "Approve"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:292
|
#: ../vnc.html:367
|
||||||
msgid "Reject"
|
msgid "Reject"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:300
|
#: ../vnc.html:375
|
||||||
msgid "Credentials"
|
msgid "Credentials"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:304
|
#: ../vnc.html:379
|
||||||
msgid "Username:"
|
msgid "Username:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:308
|
#: ../vnc.html:383
|
||||||
msgid "Password:"
|
msgid "Password:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:312
|
#: ../vnc.html:387
|
||||||
msgid "Send credentials"
|
msgid "Send credentials"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../vnc.html:321
|
#: ../vnc.html:396
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
33
po/po2js
33
po/po2js
|
@ -17,29 +17,24 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const getopt = require('node-getopt');
|
const { program } = require('commander');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const po2json = require("po2json");
|
const pofile = require("pofile");
|
||||||
|
|
||||||
const opt = getopt.create([
|
program
|
||||||
['h', 'help', 'display this help'],
|
.argument('<input>')
|
||||||
]).bindHelp().parseSystem();
|
.argument('<output>')
|
||||||
|
.parse(process.argv);
|
||||||
|
|
||||||
if (opt.argv.length != 2) {
|
let data = fs.readFileSync(program.args[0], "utf8");
|
||||||
console.error("Incorrect number of arguments given");
|
let po = pofile.parse(data);
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = po2json.parseFileSync(opt.argv[0]);
|
const bodyPart = po.items
|
||||||
|
.filter(item => item.msgid !== "")
|
||||||
const bodyPart = Object.keys(data)
|
.filter(item => item.msgstr[0] !== "")
|
||||||
.filter(msgid => msgid !== "")
|
.map(item => " " + JSON.stringify(item.msgid) + ": " + JSON.stringify(item.msgstr[0]))
|
||||||
.filter(msgid => data[msgid][1] !== "")
|
.join(",\n");
|
||||||
.map((msgid) => {
|
|
||||||
const msgstr = data[msgid][1];
|
|
||||||
return " " + JSON.stringify(msgid) + ": " + JSON.stringify(msgstr);
|
|
||||||
}).join(",\n");
|
|
||||||
|
|
||||||
const output = "{\n" + bodyPart + "\n}";
|
const output = "{\n" + bodyPart + "\n}";
|
||||||
|
|
||||||
fs.writeFileSync(opt.argv[1], output);
|
fs.writeFileSync(program.args[1], output);
|
||||||
|
|
215
po/sv.po
215
po/sv.po
|
@ -1,312 +1,308 @@
|
||||||
# Swedish translations for noVNC package
|
# Swedish translations for noVNC package
|
||||||
# Svenska översättningar för paketet noVNC.
|
# Svenska översättningar för paketet noVNC.
|
||||||
# Copyright (C) 2020 The noVNC authors
|
# Copyright (C) 2025 The noVNC authors
|
||||||
# This file is distributed under the same license as the noVNC package.
|
# This file is distributed under the same license as the noVNC package.
|
||||||
# Samuel Mannehed <samuel@cendio.se>, 2020.
|
# Samuel Mannehed <samuel@cendio.se>, 2020.
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: noVNC 1.3.0\n"
|
"Project-Id-Version: noVNC 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
|
"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
|
||||||
"POT-Creation-Date: 2024-06-03 14:10+0200\n"
|
"POT-Creation-Date: 2025-02-14 10:14+0100\n"
|
||||||
"PO-Revision-Date: 2024-06-18 13:52+0200\n"
|
"PO-Revision-Date: 2025-02-14 10:29+0100\n"
|
||||||
"Last-Translator: Pierre Ossman <ossman@cendio.se>\n"
|
"Last-Translator: Alexander Zeijlon <aleze@cendio.com>\n"
|
||||||
"Language-Team: none\n"
|
"Language-Team: none\n"
|
||||||
"Language: sv\n"
|
"Language: sv\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"X-Generator: Poedit 3.4.4\n"
|
"X-Generator: Poedit 3.5\n"
|
||||||
|
|
||||||
#: ../app/ui.js:69
|
#: ../app/ui.js:84
|
||||||
msgid ""
|
msgid ""
|
||||||
"Running without HTTPS is not recommended, crashes or other issues are likely."
|
"Running without HTTPS is not recommended, crashes or other issues are likely."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Det är ej rekommenderat att köra utan HTTPS, krascher och andra problem är "
|
"Det är ej rekommenderat att köra utan HTTPS, krascher och andra problem är "
|
||||||
"troliga."
|
"troliga."
|
||||||
|
|
||||||
#: ../app/ui.js:410
|
#: ../app/ui.js:413
|
||||||
msgid "Connecting..."
|
msgid "Connecting..."
|
||||||
msgstr "Ansluter..."
|
msgstr "Ansluter..."
|
||||||
|
|
||||||
#: ../app/ui.js:417
|
#: ../app/ui.js:420
|
||||||
msgid "Disconnecting..."
|
msgid "Disconnecting..."
|
||||||
msgstr "Kopplar ner..."
|
msgstr "Kopplar ner..."
|
||||||
|
|
||||||
#: ../app/ui.js:423
|
#: ../app/ui.js:426
|
||||||
msgid "Reconnecting..."
|
msgid "Reconnecting..."
|
||||||
msgstr "Återansluter..."
|
msgstr "Återansluter..."
|
||||||
|
|
||||||
#: ../app/ui.js:428
|
#: ../app/ui.js:431
|
||||||
msgid "Internal error"
|
msgid "Internal error"
|
||||||
msgstr "Internt fel"
|
msgstr "Internt fel"
|
||||||
|
|
||||||
#: ../app/ui.js:1026
|
#: ../app/ui.js:1079
|
||||||
msgid "Must set host"
|
|
||||||
msgstr "Du måste specifiera en värd"
|
|
||||||
|
|
||||||
#: ../app/ui.js:1052
|
|
||||||
msgid "Failed to connect to server: "
|
msgid "Failed to connect to server: "
|
||||||
msgstr "Misslyckades att ansluta till servern: "
|
msgstr "Misslyckades att ansluta till servern: "
|
||||||
|
|
||||||
#: ../app/ui.js:1118
|
#: ../app/ui.js:1145
|
||||||
msgid "Connected (encrypted) to "
|
msgid "Connected (encrypted) to "
|
||||||
msgstr "Ansluten (krypterat) till "
|
msgstr "Ansluten (krypterat) till "
|
||||||
|
|
||||||
#: ../app/ui.js:1120
|
#: ../app/ui.js:1147
|
||||||
msgid "Connected (unencrypted) to "
|
msgid "Connected (unencrypted) to "
|
||||||
msgstr "Ansluten (okrypterat) till "
|
msgstr "Ansluten (okrypterat) till "
|
||||||
|
|
||||||
#: ../app/ui.js:1143
|
#: ../app/ui.js:1170
|
||||||
msgid "Something went wrong, connection is closed"
|
msgid "Something went wrong, connection is closed"
|
||||||
msgstr "Något gick fel, anslutningen avslutades"
|
msgstr "Något gick fel, anslutningen avslutades"
|
||||||
|
|
||||||
#: ../app/ui.js:1146
|
#: ../app/ui.js:1173
|
||||||
msgid "Failed to connect to server"
|
msgid "Failed to connect to server"
|
||||||
msgstr "Misslyckades att ansluta till servern"
|
msgstr "Misslyckades att ansluta till servern"
|
||||||
|
|
||||||
#: ../app/ui.js:1158
|
#: ../app/ui.js:1185
|
||||||
msgid "Disconnected"
|
msgid "Disconnected"
|
||||||
msgstr "Frånkopplad"
|
msgstr "Frånkopplad"
|
||||||
|
|
||||||
#: ../app/ui.js:1173
|
#: ../app/ui.js:1200
|
||||||
msgid "New connection has been rejected with reason: "
|
msgid "New connection has been rejected with reason: "
|
||||||
msgstr "Ny anslutning har blivit nekad med följande skäl: "
|
msgstr "Ny anslutning har blivit nekad med följande skäl: "
|
||||||
|
|
||||||
#: ../app/ui.js:1176
|
#: ../app/ui.js:1203
|
||||||
msgid "New connection has been rejected"
|
msgid "New connection has been rejected"
|
||||||
msgstr "Ny anslutning har blivit nekad"
|
msgstr "Ny anslutning har blivit nekad"
|
||||||
|
|
||||||
#: ../app/ui.js:1242
|
#: ../app/ui.js:1269
|
||||||
msgid "Credentials are required"
|
msgid "Credentials are required"
|
||||||
msgstr "Användaruppgifter krävs"
|
msgstr "Användaruppgifter krävs"
|
||||||
|
|
||||||
#: ../vnc.html:55
|
#: ../vnc.html:106
|
||||||
msgid "noVNC encountered an error:"
|
msgid "noVNC encountered an error:"
|
||||||
msgstr "noVNC stötte på ett problem:"
|
msgstr "noVNC stötte på ett problem:"
|
||||||
|
|
||||||
#: ../vnc.html:65
|
#: ../vnc.html:116
|
||||||
msgid "Hide/Show the control bar"
|
msgid "Hide/Show the control bar"
|
||||||
msgstr "Göm/Visa kontrollbaren"
|
msgstr "Göm/Visa kontrollbaren"
|
||||||
|
|
||||||
#: ../vnc.html:74
|
#: ../vnc.html:125
|
||||||
msgid "Drag"
|
msgid "Drag"
|
||||||
msgstr "Dra"
|
msgstr "Dra"
|
||||||
|
|
||||||
#: ../vnc.html:74
|
#: ../vnc.html:125
|
||||||
msgid "Move/Drag Viewport"
|
msgid "Move/Drag viewport"
|
||||||
msgstr "Flytta/Dra Vyn"
|
msgstr "Flytta/Dra vyn"
|
||||||
|
|
||||||
#: ../vnc.html:80
|
#: ../vnc.html:131
|
||||||
msgid "Keyboard"
|
msgid "Keyboard"
|
||||||
msgstr "Tangentbord"
|
msgstr "Tangentbord"
|
||||||
|
|
||||||
#: ../vnc.html:80
|
#: ../vnc.html:131
|
||||||
msgid "Show Keyboard"
|
msgid "Show keyboard"
|
||||||
msgstr "Visa Tangentbord"
|
msgstr "Visa tangentbord"
|
||||||
|
|
||||||
#: ../vnc.html:85
|
#: ../vnc.html:136
|
||||||
msgid "Extra keys"
|
msgid "Extra keys"
|
||||||
msgstr "Extraknappar"
|
msgstr "Extraknappar"
|
||||||
|
|
||||||
#: ../vnc.html:85
|
#: ../vnc.html:136
|
||||||
msgid "Show Extra Keys"
|
msgid "Show extra keys"
|
||||||
msgstr "Visa Extraknappar"
|
msgstr "Visa extraknappar"
|
||||||
|
|
||||||
#: ../vnc.html:90
|
#: ../vnc.html:141
|
||||||
msgid "Ctrl"
|
msgid "Ctrl"
|
||||||
msgstr "Ctrl"
|
msgstr "Ctrl"
|
||||||
|
|
||||||
#: ../vnc.html:90
|
#: ../vnc.html:141
|
||||||
msgid "Toggle Ctrl"
|
msgid "Toggle Ctrl"
|
||||||
msgstr "Växla Ctrl"
|
msgstr "Växla Ctrl"
|
||||||
|
|
||||||
#: ../vnc.html:93
|
#: ../vnc.html:144
|
||||||
msgid "Alt"
|
msgid "Alt"
|
||||||
msgstr "Alt"
|
msgstr "Alt"
|
||||||
|
|
||||||
#: ../vnc.html:93
|
#: ../vnc.html:144
|
||||||
msgid "Toggle Alt"
|
msgid "Toggle Alt"
|
||||||
msgstr "Växla Alt"
|
msgstr "Växla Alt"
|
||||||
|
|
||||||
#: ../vnc.html:96
|
#: ../vnc.html:147
|
||||||
msgid "Toggle Windows"
|
msgid "Toggle Windows"
|
||||||
msgstr "Växla Windows"
|
msgstr "Växla Windows"
|
||||||
|
|
||||||
#: ../vnc.html:96
|
#: ../vnc.html:147
|
||||||
msgid "Windows"
|
msgid "Windows"
|
||||||
msgstr "Windows"
|
msgstr "Windows"
|
||||||
|
|
||||||
#: ../vnc.html:99
|
#: ../vnc.html:150
|
||||||
msgid "Send Tab"
|
msgid "Send Tab"
|
||||||
msgstr "Skicka Tab"
|
msgstr "Skicka Tab"
|
||||||
|
|
||||||
#: ../vnc.html:99
|
#: ../vnc.html:150
|
||||||
msgid "Tab"
|
msgid "Tab"
|
||||||
msgstr "Tab"
|
msgstr "Tab"
|
||||||
|
|
||||||
#: ../vnc.html:102
|
#: ../vnc.html:153
|
||||||
msgid "Esc"
|
msgid "Esc"
|
||||||
msgstr "Esc"
|
msgstr "Esc"
|
||||||
|
|
||||||
#: ../vnc.html:102
|
#: ../vnc.html:153
|
||||||
msgid "Send Escape"
|
msgid "Send Escape"
|
||||||
msgstr "Skicka Escape"
|
msgstr "Skicka Escape"
|
||||||
|
|
||||||
#: ../vnc.html:105
|
#: ../vnc.html:156
|
||||||
msgid "Ctrl+Alt+Del"
|
msgid "Ctrl+Alt+Del"
|
||||||
msgstr "Ctrl+Alt+Del"
|
msgstr "Ctrl+Alt+Del"
|
||||||
|
|
||||||
#: ../vnc.html:105
|
#: ../vnc.html:156
|
||||||
msgid "Send Ctrl-Alt-Del"
|
msgid "Send Ctrl-Alt-Del"
|
||||||
msgstr "Skicka Ctrl-Alt-Del"
|
msgstr "Skicka Ctrl-Alt-Del"
|
||||||
|
|
||||||
#: ../vnc.html:112
|
#: ../vnc.html:163
|
||||||
msgid "Shutdown/Reboot"
|
msgid "Shutdown/Reboot"
|
||||||
msgstr "Stäng av/Boota om"
|
msgstr "Stäng av/Boota om"
|
||||||
|
|
||||||
#: ../vnc.html:112
|
#: ../vnc.html:163
|
||||||
msgid "Shutdown/Reboot..."
|
msgid "Shutdown/Reboot..."
|
||||||
msgstr "Stäng av/Boota om..."
|
msgstr "Stäng av/Boota om..."
|
||||||
|
|
||||||
#: ../vnc.html:118
|
#: ../vnc.html:169
|
||||||
msgid "Power"
|
msgid "Power"
|
||||||
msgstr "Ström"
|
msgstr "Ström"
|
||||||
|
|
||||||
#: ../vnc.html:120
|
#: ../vnc.html:171
|
||||||
msgid "Shutdown"
|
msgid "Shutdown"
|
||||||
msgstr "Stäng av"
|
msgstr "Stäng av"
|
||||||
|
|
||||||
#: ../vnc.html:121
|
#: ../vnc.html:172
|
||||||
msgid "Reboot"
|
msgid "Reboot"
|
||||||
msgstr "Boota om"
|
msgstr "Boota om"
|
||||||
|
|
||||||
#: ../vnc.html:122
|
#: ../vnc.html:173
|
||||||
msgid "Reset"
|
msgid "Reset"
|
||||||
msgstr "Återställ"
|
msgstr "Återställ"
|
||||||
|
|
||||||
#: ../vnc.html:127 ../vnc.html:133
|
#: ../vnc.html:178 ../vnc.html:184
|
||||||
msgid "Clipboard"
|
msgid "Clipboard"
|
||||||
msgstr "Urklipp"
|
msgstr "Urklipp"
|
||||||
|
|
||||||
#: ../vnc.html:135
|
#: ../vnc.html:186
|
||||||
msgid "Edit clipboard content in the textarea below."
|
msgid "Edit clipboard content in the textarea below."
|
||||||
msgstr "Redigera urklippets innehåll i fältet nedan."
|
msgstr "Redigera urklippets innehåll i fältet nedan."
|
||||||
|
|
||||||
#: ../vnc.html:143
|
#: ../vnc.html:194
|
||||||
msgid "Full screen"
|
msgid "Full screen"
|
||||||
msgstr "Fullskärm"
|
msgstr "Fullskärm"
|
||||||
|
|
||||||
#: ../vnc.html:148 ../vnc.html:154
|
#: ../vnc.html:199 ../vnc.html:205
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr "Inställningar"
|
msgstr "Inställningar"
|
||||||
|
|
||||||
#: ../vnc.html:158
|
#: ../vnc.html:211
|
||||||
msgid "Shared Mode"
|
msgid "Shared mode"
|
||||||
msgstr "Delat Läge"
|
msgstr "Delat läge"
|
||||||
|
|
||||||
#: ../vnc.html:161
|
#: ../vnc.html:218
|
||||||
msgid "View Only"
|
msgid "View only"
|
||||||
msgstr "Endast Visning"
|
msgstr "Endast visning"
|
||||||
|
|
||||||
#: ../vnc.html:165
|
#: ../vnc.html:226
|
||||||
msgid "Clip to Window"
|
msgid "Clip to window"
|
||||||
msgstr "Begränsa till Fönster"
|
msgstr "Begränsa till fönster"
|
||||||
|
|
||||||
#: ../vnc.html:168
|
#: ../vnc.html:231
|
||||||
msgid "Scaling mode:"
|
msgid "Scaling mode:"
|
||||||
msgstr "Skalningsläge:"
|
msgstr "Skalningsläge:"
|
||||||
|
|
||||||
#: ../vnc.html:170
|
#: ../vnc.html:233
|
||||||
msgid "None"
|
msgid "None"
|
||||||
msgstr "Ingen"
|
msgstr "Ingen"
|
||||||
|
|
||||||
#: ../vnc.html:171
|
#: ../vnc.html:234
|
||||||
msgid "Local Scaling"
|
msgid "Local scaling"
|
||||||
msgstr "Lokal Skalning"
|
msgstr "Lokal skalning"
|
||||||
|
|
||||||
#: ../vnc.html:172
|
#: ../vnc.html:235
|
||||||
msgid "Remote Resizing"
|
msgid "Remote resizing"
|
||||||
msgstr "Ändra Storlek"
|
msgstr "Ändra storlek"
|
||||||
|
|
||||||
#: ../vnc.html:177
|
#: ../vnc.html:240
|
||||||
msgid "Advanced"
|
msgid "Advanced"
|
||||||
msgstr "Avancerat"
|
msgstr "Avancerat"
|
||||||
|
|
||||||
#: ../vnc.html:180
|
#: ../vnc.html:243
|
||||||
msgid "Quality:"
|
msgid "Quality:"
|
||||||
msgstr "Kvalitet:"
|
msgstr "Kvalitet:"
|
||||||
|
|
||||||
#: ../vnc.html:184
|
#: ../vnc.html:247
|
||||||
msgid "Compression level:"
|
msgid "Compression level:"
|
||||||
msgstr "Kompressionsnivå:"
|
msgstr "Kompressionsnivå:"
|
||||||
|
|
||||||
#: ../vnc.html:189
|
#: ../vnc.html:252
|
||||||
msgid "Repeater ID:"
|
msgid "Repeater ID:"
|
||||||
msgstr "Repeater-ID:"
|
msgstr "Repeater-ID:"
|
||||||
|
|
||||||
#: ../vnc.html:193
|
#: ../vnc.html:256
|
||||||
msgid "WebSocket"
|
msgid "WebSocket"
|
||||||
msgstr "WebSocket"
|
msgstr "WebSocket"
|
||||||
|
|
||||||
#: ../vnc.html:196
|
#: ../vnc.html:261
|
||||||
msgid "Encrypt"
|
msgid "Encrypt"
|
||||||
msgstr "Kryptera"
|
msgstr "Kryptera"
|
||||||
|
|
||||||
#: ../vnc.html:199
|
#: ../vnc.html:266
|
||||||
msgid "Host:"
|
msgid "Host:"
|
||||||
msgstr "Värd:"
|
msgstr "Värd:"
|
||||||
|
|
||||||
#: ../vnc.html:203
|
#: ../vnc.html:270
|
||||||
msgid "Port:"
|
msgid "Port:"
|
||||||
msgstr "Port:"
|
msgstr "Port:"
|
||||||
|
|
||||||
#: ../vnc.html:207
|
#: ../vnc.html:274
|
||||||
msgid "Path:"
|
msgid "Path:"
|
||||||
msgstr "Sökväg:"
|
msgstr "Sökväg:"
|
||||||
|
|
||||||
#: ../vnc.html:214
|
#: ../vnc.html:283
|
||||||
msgid "Automatic Reconnect"
|
msgid "Automatic reconnect"
|
||||||
msgstr "Automatisk Återanslutning"
|
msgstr "Automatisk återanslutning"
|
||||||
|
|
||||||
#: ../vnc.html:217
|
#: ../vnc.html:288
|
||||||
msgid "Reconnect delay (ms):"
|
msgid "Reconnect delay (ms):"
|
||||||
msgstr "Fördröjning (ms):"
|
msgstr "Fördröjning (ms):"
|
||||||
|
|
||||||
#: ../vnc.html:222
|
#: ../vnc.html:295
|
||||||
msgid "Show dot when no cursor"
|
msgid "Show dot when no cursor"
|
||||||
msgstr "Visa prick när ingen muspekare finns"
|
msgstr "Visa prick när ingen muspekare finns"
|
||||||
|
|
||||||
#: ../vnc.html:227
|
#: ../vnc.html:302
|
||||||
msgid "Logging:"
|
msgid "Logging:"
|
||||||
msgstr "Loggning:"
|
msgstr "Loggning:"
|
||||||
|
|
||||||
#: ../vnc.html:236
|
#: ../vnc.html:311
|
||||||
msgid "Version:"
|
msgid "Version:"
|
||||||
msgstr "Version:"
|
msgstr "Version:"
|
||||||
|
|
||||||
#: ../vnc.html:244
|
#: ../vnc.html:319
|
||||||
msgid "Disconnect"
|
msgid "Disconnect"
|
||||||
msgstr "Koppla från"
|
msgstr "Koppla från"
|
||||||
|
|
||||||
#: ../vnc.html:267
|
#: ../vnc.html:342
|
||||||
msgid "Connect"
|
msgid "Connect"
|
||||||
msgstr "Anslut"
|
msgstr "Anslut"
|
||||||
|
|
||||||
#: ../vnc.html:276
|
#: ../vnc.html:351
|
||||||
msgid "Server identity"
|
msgid "Server identity"
|
||||||
msgstr "Server-identitet"
|
msgstr "Server-identitet"
|
||||||
|
|
||||||
#: ../vnc.html:279
|
#: ../vnc.html:354
|
||||||
msgid "The server has provided the following identifying information:"
|
msgid "The server has provided the following identifying information:"
|
||||||
msgstr "Servern har gett följande identifierande information:"
|
msgstr "Servern har gett följande identifierande information:"
|
||||||
|
|
||||||
#: ../vnc.html:283
|
#: ../vnc.html:357
|
||||||
msgid "Fingerprint:"
|
msgid "Fingerprint:"
|
||||||
msgstr "Fingeravtryck:"
|
msgstr "Fingeravtryck:"
|
||||||
|
|
||||||
#: ../vnc.html:286
|
#: ../vnc.html:361
|
||||||
msgid ""
|
msgid ""
|
||||||
"Please verify that the information is correct and press \"Approve\". "
|
"Please verify that the information is correct and press \"Approve\". "
|
||||||
"Otherwise press \"Reject\"."
|
"Otherwise press \"Reject\"."
|
||||||
|
@ -314,34 +310,37 @@ msgstr ""
|
||||||
"Kontrollera att informationen är korrekt och tryck sedan \"Godkänn\". Tryck "
|
"Kontrollera att informationen är korrekt och tryck sedan \"Godkänn\". Tryck "
|
||||||
"annars \"Neka\"."
|
"annars \"Neka\"."
|
||||||
|
|
||||||
#: ../vnc.html:291
|
#: ../vnc.html:366
|
||||||
msgid "Approve"
|
msgid "Approve"
|
||||||
msgstr "Godkänn"
|
msgstr "Godkänn"
|
||||||
|
|
||||||
#: ../vnc.html:292
|
#: ../vnc.html:367
|
||||||
msgid "Reject"
|
msgid "Reject"
|
||||||
msgstr "Neka"
|
msgstr "Neka"
|
||||||
|
|
||||||
#: ../vnc.html:300
|
#: ../vnc.html:375
|
||||||
msgid "Credentials"
|
msgid "Credentials"
|
||||||
msgstr "Användaruppgifter"
|
msgstr "Användaruppgifter"
|
||||||
|
|
||||||
#: ../vnc.html:304
|
#: ../vnc.html:379
|
||||||
msgid "Username:"
|
msgid "Username:"
|
||||||
msgstr "Användarnamn:"
|
msgstr "Användarnamn:"
|
||||||
|
|
||||||
#: ../vnc.html:308
|
#: ../vnc.html:383
|
||||||
msgid "Password:"
|
msgid "Password:"
|
||||||
msgstr "Lösenord:"
|
msgstr "Lösenord:"
|
||||||
|
|
||||||
#: ../vnc.html:312
|
#: ../vnc.html:387
|
||||||
msgid "Send Credentials"
|
msgid "Send credentials"
|
||||||
msgstr "Skicka Användaruppgifter"
|
msgstr "Skicka användaruppgifter"
|
||||||
|
|
||||||
#: ../vnc.html:321
|
#: ../vnc.html:396
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Avbryt"
|
msgstr "Avbryt"
|
||||||
|
|
||||||
|
#~ msgid "Must set host"
|
||||||
|
#~ msgstr "Du måste specifiera en värd"
|
||||||
|
|
||||||
#~ msgid "HTTPS is required for full functionality"
|
#~ msgid "HTTPS is required for full functionality"
|
||||||
#~ msgstr "HTTPS krävs för full funktionalitet"
|
#~ msgstr "HTTPS krävs för full funktionalitet"
|
||||||
|
|
||||||
|
|
|
@ -5,14 +5,14 @@
|
||||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const getopt = require('node-getopt');
|
const { program } = require('commander');
|
||||||
const jsdom = require("jsdom");
|
const jsdom = require("jsdom");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
|
|
||||||
const opt = getopt.create([
|
program
|
||||||
['o', 'output=FILE', 'write output to specified file'],
|
.argument('<INPUT...>')
|
||||||
['h', 'help', 'display this help'],
|
.requiredOption('-o, --output <FILE>', 'write output to specified file')
|
||||||
]).bindHelp().parseSystem();
|
.parse(process.argv);
|
||||||
|
|
||||||
const strings = {};
|
const strings = {};
|
||||||
|
|
||||||
|
@ -87,8 +87,8 @@ function process(elem, locator, enabled) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < opt.argv.length; i++) {
|
for (let i = 0; i < program.args.length; i++) {
|
||||||
const fn = opt.argv[i];
|
const fn = program.args[i];
|
||||||
const file = fs.readFileSync(fn, "utf8");
|
const file = fs.readFileSync(fn, "utf8");
|
||||||
const dom = new jsdom.JSDOM(file, { includeNodeLocations: true });
|
const dom = new jsdom.JSDOM(file, { includeNodeLocations: true });
|
||||||
const body = dom.window.document.body;
|
const body = dom.window.document.body;
|
||||||
|
@ -116,4 +116,4 @@ for (let str in strings) {
|
||||||
output += "\n";
|
output += "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.writeFileSync(opt.options.output, output);
|
fs.writeFileSync(program.opts().output, output);
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
# "vnc": "localhost:5902"
|
# "vnc": "localhost:5902"
|
||||||
#}
|
#}
|
||||||
#}
|
#}
|
||||||
snapctl get services | jq -c '.[]' | while read service; do # for each service the user sepcified..
|
snapctl get services | jq -c '.[]' | while read service; do # for each service the user specified..
|
||||||
# get the important data for the service (listen port, VNC host:port)
|
# get the important data for the service (listen port, VNC host:port)
|
||||||
listen_port="$(echo $service | jq --raw-output '.listen')"
|
listen_port="$(echo $service | jq --raw-output '.listen')"
|
||||||
vnc_host_port="$(echo $service | jq --raw-output '.vnc')" # --raw-output removes any quotation marks from the output
|
vnc_host_port="$(echo $service | jq --raw-output '.vnc')" # --raw-output removes any quotation marks from the output
|
||||||
|
|
|
@ -42,7 +42,7 @@ parts:
|
||||||
- jq
|
- jq
|
||||||
|
|
||||||
websockify:
|
websockify:
|
||||||
source: https://github.com/novnc/websockify/archive/v0.12.0.tar.gz
|
source: https://github.com/novnc/websockify/archive/v0.13.0.tar.gz
|
||||||
plugin: python
|
plugin: python
|
||||||
stage-packages:
|
stage-packages:
|
||||||
- python3-numpy
|
- python3-numpy
|
||||||
|
|
|
@ -525,6 +525,37 @@ describe('Key event handling', function () {
|
||||||
expect(kbd.onkeyevent).to.not.have.been.called;
|
expect(kbd.onkeyevent).to.not.have.been.called;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should generate AltGraph for quick Ctrl+AltGraph sequence', function () {
|
||||||
|
const kbd = new Keyboard(document);
|
||||||
|
kbd.onkeyevent = sinon.spy();
|
||||||
|
kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1, timeStamp: Date.now()}));
|
||||||
|
this.clock.tick(20);
|
||||||
|
kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'AltGraph', location: 2, timeStamp: Date.now()}));
|
||||||
|
expect(kbd.onkeyevent).to.have.been.calledOnce;
|
||||||
|
expect(kbd.onkeyevent).to.have.been.calledWith(0xfe03, 'AltRight', true);
|
||||||
|
|
||||||
|
// Check that the timer is properly dead
|
||||||
|
kbd.onkeyevent.resetHistory();
|
||||||
|
this.clock.tick(100);
|
||||||
|
expect(kbd.onkeyevent).to.not.have.been.called;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate Ctrl, AltGraph for slow Ctrl+AltGraph sequence', function () {
|
||||||
|
const kbd = new Keyboard(document);
|
||||||
|
kbd.onkeyevent = sinon.spy();
|
||||||
|
kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1, timeStamp: Date.now()}));
|
||||||
|
this.clock.tick(60);
|
||||||
|
kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'AltGraph', location: 2, timeStamp: Date.now()}));
|
||||||
|
expect(kbd.onkeyevent).to.have.been.calledTwice;
|
||||||
|
expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0xffe3, "ControlLeft", true);
|
||||||
|
expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0xfe03, "AltRight", true);
|
||||||
|
|
||||||
|
// Check that the timer is properly dead
|
||||||
|
kbd.onkeyevent.resetHistory();
|
||||||
|
this.clock.tick(100);
|
||||||
|
expect(kbd.onkeyevent).to.not.have.been.called;
|
||||||
|
});
|
||||||
|
|
||||||
it('should pass through single Alt', function () {
|
it('should pass through single Alt', function () {
|
||||||
const kbd = new Keyboard(document);
|
const kbd = new Keyboard(document);
|
||||||
kbd.onkeyevent = sinon.spy();
|
kbd.onkeyevent = sinon.spy();
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -28,16 +28,63 @@ for fn in "$@"; do
|
||||||
curl --silent \
|
curl --silent \
|
||||||
--header "Content-Type: ${type}; charset=utf-8" \
|
--header "Content-Type: ${type}; charset=utf-8" \
|
||||||
--data-binary @${fn} \
|
--data-binary @${fn} \
|
||||||
https://validator.w3.org/nu/?out=text > $OUT
|
"https://validator.w3.org/nu/?out=gnu&level=error&asciiquotes=yes" \
|
||||||
cat $OUT
|
> $OUT
|
||||||
echo
|
|
||||||
|
|
||||||
# We don't fail the check for warnings as some warnings are
|
# We don't fail the check for warnings as some warnings are
|
||||||
# not relevant for us, and we don't currently have a way to
|
# not relevant for us, and we don't currently have a way to
|
||||||
# ignore just those
|
# ignore just those
|
||||||
if grep -q -s -E "^Error:" $OUT; then
|
while read -r line; do
|
||||||
RET=1
|
echo
|
||||||
|
|
||||||
|
line_info=$(echo $line | cut -d ":" -f 2)
|
||||||
|
start_info=$(echo $line_info | cut -d "-" -f 1)
|
||||||
|
end_info=$(echo $line_info | cut -d "-" -f 2)
|
||||||
|
|
||||||
|
line_start=$(echo $start_info | cut -d "." -f 1)
|
||||||
|
col_start=$(echo $start_info | cut -d "." -f 2)
|
||||||
|
|
||||||
|
line_end=$(echo $end_info | cut -d "." -f 1)
|
||||||
|
col_end=$(echo $end_info | cut -d "." -f 2)
|
||||||
|
|
||||||
|
error=$(echo $line | cut -d ":" -f 4-)
|
||||||
|
|
||||||
|
case $error in
|
||||||
|
*"\"scrollbar-gutter\": Property \"scrollbar-gutter\" doesn't exist.")
|
||||||
|
# FIXME: https://github.com/validator/validator/issues/1788
|
||||||
|
echo "Ignoring below error on line ${line_start}," \
|
||||||
|
"the scrollbar-gutter property actually exist and is widely" \
|
||||||
|
"supported:"
|
||||||
|
echo $error
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
*"\"clip-path\": \"path("*)
|
||||||
|
# FIXME: https://github.com/validator/validator/issues/1786
|
||||||
|
echo "Ignoring below error on line ${line_start}," \
|
||||||
|
"the path() function is valid for clip-path and is" \
|
||||||
|
"widely supported:"
|
||||||
|
echo $error
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
*"Parse Error.")
|
||||||
|
# FIXME: https://github.com/validator/validator/issues/1786
|
||||||
|
lineofselector=$(grep -n "@supports selector(" $fn | cut -d ":" -f 1)
|
||||||
|
linediff=$((lineofselector-line_start))
|
||||||
|
# Only ignore if parse error is within 50 lines of "selector()"
|
||||||
|
if [ ${linediff#-} -lt 50 ]; then
|
||||||
|
echo "Ignoring below error on line ${line_start}," \
|
||||||
|
"the @supports selector() function should not give a parse" \
|
||||||
|
"error:"
|
||||||
|
echo $error
|
||||||
|
continue
|
||||||
fi
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo "ERROR between line ${line_start} (col ${col_start})" \
|
||||||
|
"and line ${line_end} (col ${col_end}):"
|
||||||
|
echo $error
|
||||||
|
RET=1
|
||||||
|
done < "$OUT"
|
||||||
done
|
done
|
||||||
|
|
||||||
rm $OUT
|
rm $OUT
|
||||||
|
|
51
vnc.html
51
vnc.html
|
@ -37,6 +37,7 @@
|
||||||
<link rel="apple-touch-icon" sizes="180x180" type="image/png" href="app/images/icons/novnc-ios-180.png">
|
<link rel="apple-touch-icon" sizes="180x180" type="image/png" href="app/images/icons/novnc-ios-180.png">
|
||||||
|
|
||||||
<!-- Stylesheets -->
|
<!-- Stylesheets -->
|
||||||
|
<link rel="stylesheet" href="app/styles/constants.css">
|
||||||
<link rel="stylesheet" href="app/styles/base.css">
|
<link rel="stylesheet" href="app/styles/base.css">
|
||||||
<link rel="stylesheet" href="app/styles/input.css">
|
<link rel="stylesheet" href="app/styles/input.css">
|
||||||
|
|
||||||
|
@ -205,14 +206,26 @@
|
||||||
</div>
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<label><input id="noVNC_setting_shared" type="checkbox"> Shared mode</label>
|
<label>
|
||||||
|
<input id="noVNC_setting_shared" type="checkbox"
|
||||||
|
class="toggle">
|
||||||
|
Shared mode
|
||||||
|
</label>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label><input id="noVNC_setting_view_only" type="checkbox"> View only</label>
|
<label>
|
||||||
|
<input id="noVNC_setting_view_only" type="checkbox"
|
||||||
|
class="toggle">
|
||||||
|
View only
|
||||||
|
</label>
|
||||||
</li>
|
</li>
|
||||||
<li><hr></li>
|
<li><hr></li>
|
||||||
<li>
|
<li>
|
||||||
<label><input id="noVNC_setting_view_clip" type="checkbox"> Clip to window</label>
|
<label>
|
||||||
|
<input id="noVNC_setting_view_clip" type="checkbox"
|
||||||
|
class="toggle">
|
||||||
|
Clip to window
|
||||||
|
</label>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label for="noVNC_setting_resize">Scaling mode:</label>
|
<label for="noVNC_setting_resize">Scaling mode:</label>
|
||||||
|
@ -243,7 +256,11 @@
|
||||||
<div class="noVNC_expander">WebSocket</div>
|
<div class="noVNC_expander">WebSocket</div>
|
||||||
<div><ul>
|
<div><ul>
|
||||||
<li>
|
<li>
|
||||||
<label><input id="noVNC_setting_encrypt" type="checkbox"> Encrypt</label>
|
<label>
|
||||||
|
<input id="noVNC_setting_encrypt" type="checkbox"
|
||||||
|
class="toggle">
|
||||||
|
Encrypt
|
||||||
|
</label>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label for="noVNC_setting_host">Host:</label>
|
<label for="noVNC_setting_host">Host:</label>
|
||||||
|
@ -261,7 +278,11 @@
|
||||||
</li>
|
</li>
|
||||||
<li><hr></li>
|
<li><hr></li>
|
||||||
<li>
|
<li>
|
||||||
<label><input id="noVNC_setting_reconnect" type="checkbox"> Automatic reconnect</label>
|
<label>
|
||||||
|
<input id="noVNC_setting_reconnect" type="checkbox"
|
||||||
|
class="toggle">
|
||||||
|
Automatic reconnect
|
||||||
|
</label>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label for="noVNC_setting_reconnect_delay">Reconnect delay (ms):</label>
|
<label for="noVNC_setting_reconnect_delay">Reconnect delay (ms):</label>
|
||||||
|
@ -269,7 +290,11 @@
|
||||||
</li>
|
</li>
|
||||||
<li><hr></li>
|
<li><hr></li>
|
||||||
<li>
|
<li>
|
||||||
<label><input id="noVNC_setting_show_dot" type="checkbox"> Show dot when no cursor</label>
|
<label>
|
||||||
|
<input id="noVNC_setting_show_dot" type="checkbox"
|
||||||
|
class="toggle">
|
||||||
|
Show dot when no cursor
|
||||||
|
</label>
|
||||||
<label for="noVNC_setting_gestures_mode">Gestures mode:</label>
|
<label for="noVNC_setting_gestures_mode">Gestures mode:</label>
|
||||||
<select id="noVNC_setting_gestures_mode" name="vncGestures">
|
<select id="noVNC_setting_gestures_mode" name="vncGestures">
|
||||||
<option value="novnc">Default (noVNC)</option>
|
<option value="novnc">Default (noVNC)</option>
|
||||||
|
@ -335,16 +360,16 @@
|
||||||
The server has provided the following identifying information:
|
The server has provided the following identifying information:
|
||||||
</div>
|
</div>
|
||||||
<div id="noVNC_fingerprint_block">
|
<div id="noVNC_fingerprint_block">
|
||||||
<b>Fingerprint:</b>
|
Fingerprint:
|
||||||
<span id="noVNC_fingerprint"></span>
|
<span id="noVNC_fingerprint"></span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
Please verify that the information is correct and press
|
Please verify that the information is correct and press
|
||||||
"Approve". Otherwise press "Reject".
|
"Approve". Otherwise press "Reject".
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="button_row">
|
||||||
<input id="noVNC_approve_server_button" type="submit" value="Approve" class="noVNC_submit">
|
<input id="noVNC_approve_server_button" type="submit" value="Approve">
|
||||||
<input id="noVNC_reject_server_button" type="button" value="Reject" class="noVNC_submit">
|
<input id="noVNC_reject_server_button" type="button" value="Reject">
|
||||||
</div>
|
</div>
|
||||||
</form></div>
|
</form></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -363,8 +388,8 @@
|
||||||
<label for="noVNC_password_input">Password:</label>
|
<label for="noVNC_password_input">Password:</label>
|
||||||
<input id="noVNC_password_input" type="password">
|
<input id="noVNC_password_input" type="password">
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="button_row">
|
||||||
<input id="noVNC_credentials_button" type="submit" value="Send credentials" class="noVNC_submit">
|
<input id="noVNC_credentials_button" type="submit" value="Send credentials">
|
||||||
</div>
|
</div>
|
||||||
</form></div>
|
</form></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -373,7 +398,7 @@
|
||||||
<div id="noVNC_transition">
|
<div id="noVNC_transition">
|
||||||
<div id="noVNC_transition_text"></div>
|
<div id="noVNC_transition_text"></div>
|
||||||
<div>
|
<div>
|
||||||
<input type="button" id="noVNC_cancel_reconnect_button" value="Cancel" class="noVNC_submit">
|
<input type="button" id="noVNC_cancel_reconnect_button" value="Cancel">
|
||||||
</div>
|
</div>
|
||||||
<div class="noVNC_spinner"></div>
|
<div class="noVNC_spinner"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue