Compare commits
502 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0f4a06ffcd | |||
| f69d55c02f | |||
| 7841037618 | |||
| 1afa18f09e | |||
| 375f36c575 | |||
| a9c2ff30b6 | |||
| fcb95821b7 | |||
| f796b05e42 | |||
| 0a8ced2cfe | |||
| 7a76fbb767 | |||
| cb56f35fab | |||
| 7485e82b72 | |||
| d44ddbe186 | |||
| 89e206c146 | |||
| dd20b17d49 | |||
| 8ab18125f9 | |||
| e283f08d04 | |||
| dbd519558c | |||
| de9fc9508c | |||
| 9376191fc4 | |||
| b7b7e4e26b | |||
| 2244f53774 | |||
| 42100e8233 | |||
| ae3c01f782 | |||
| f0e4908dec | |||
| ae5f3f6909 | |||
| 84f102d6a9 | |||
| ef27628c6d | |||
| 89f9ac0016 | |||
| f9a8c4ccd5 | |||
| 9ca337d3a8 | |||
| 4c96d4b7bd | |||
| 0c55c64757 | |||
| 44d384b99c | |||
| 18593154d3 | |||
| 5a0cceb815 | |||
| d56e042fee | |||
| babd665c03 | |||
| 199910e63b | |||
| 4a319c414d | |||
| adfb99e7ec | |||
| 32222304f4 | |||
| 4a8efa6bc9 | |||
| cd9f535eb3 | |||
| 23249c7263 | |||
| 76aa3d1256 | |||
| 6784bb312f | |||
| 67ac9f9c0d | |||
| 4ae9d3e75a | |||
| 0cdf2962c0 | |||
| 146258291a | |||
| 3e55d5d71a | |||
| bd1bb2ed75 | |||
| dc9da4a042 | |||
| 6a4c411976 | |||
| 27496941a0 | |||
| 5b5b747494 | |||
| 6cd9bacf8b | |||
| 273acf3e89 | |||
| 60c7518f8c | |||
| 90456dbeed | |||
| 5dbacc5e41 | |||
| 18256baad0 | |||
| 1f7e1c7572 | |||
| dccf6facdc | |||
| 890cff921d | |||
| c01eb5e74d | |||
| 499eee4d06 | |||
| c1281b136d | |||
| 20e4f1b3f8 | |||
| b91b1e8edc | |||
| 3037eb16f7 | |||
| 3762300399 | |||
| 113fa27ebc | |||
| 0630352e19 | |||
| 7ce1b071ec | |||
| ecdd075672 | |||
| 9142f8f0f7 | |||
| b053b3f86d | |||
| 2334a7a7c3 | |||
| 4fa8051949 | |||
| 2654bcd354 | |||
| e17de291b9 | |||
| 81898d7cea | |||
| dcdc17bf24 | |||
| 72ca470750 | |||
| ef5db94a89 | |||
| 90ead240c7 | |||
| 244c02c5ea | |||
| fe2ad57077 | |||
| 9b3cea950a | |||
| 794b06b2bd | |||
| 484a9551d1 | |||
| 6c6776a7a0 | |||
| ffb9dfdc0a | |||
| 2835616b75 | |||
| 643442feac | |||
| 57ba67f306 | |||
| 48f15efa69 | |||
| 35de121ac5 | |||
| bb09e766ba | |||
| 32ed7c6724 | |||
| 50cde2faab | |||
| 88589a44f7 | |||
| f84bc57bda | |||
| 4a87038080 | |||
| 77c32d164d | |||
| 07a69954b1 | |||
| 8be924c9d9 | |||
| 440ec8a0b6 | |||
| 97b86abc94 | |||
| 0a6aec3578 | |||
| 6a19390baa | |||
| f5b5767c98 | |||
| 34f52a8f41 | |||
| 18a68dfac1 | |||
| 15cfa13563 | |||
| 111225fa41 | |||
| 224f95f997 | |||
| f694c32fd5 | |||
| 0e37a3f83a | |||
| cfb824ed03 | |||
| 756af5b44c | |||
| f2fbaacc82 | |||
| 164bf50fda | |||
| a7fe079f81 | |||
| ea858bfa27 | |||
| 5d570207f7 | |||
| 95632e413d | |||
| 8b0034ee84 | |||
| 80187d158c | |||
| dff4fefa3c | |||
| 150596be83 | |||
| 11a22dbf0c | |||
| 006743857b | |||
| e7dec5270e | |||
| b5ff33a556 | |||
| 42e3b03fa8 | |||
| 776cda5dc4 | |||
| 479d8cefd1 | |||
| a672168d4d | |||
| 0f81407c64 | |||
| f477469fb5 | |||
| c9582690ac | |||
| 44eb1fe59b | |||
| e7fa686f32 | |||
| 8df281cce6 | |||
| c12e5b2b54 | |||
| 302895cdf3 | |||
| 27a6978e30 | |||
| a1015d8db5 | |||
| a040c402ed | |||
| c4633ab333 | |||
| 5243cbf611 | |||
| 71429d45d0 | |||
| efd1f8a4f2 | |||
| 9253e178fc | |||
| ceb8ef4ec1 | |||
| e4e6a9b9b4 | |||
| 384232fb56 | |||
| f73fdc3ed3 | |||
| 9a31083a8a | |||
| 13be552d60 | |||
| 2cee106eee | |||
| 3cf11004b4 | |||
| f6669ff7b2 | |||
| fe5aa6408a | |||
| 183cab0eca | |||
| 9575ded8da | |||
| f52e979082 | |||
| 3b562e8a0f | |||
| 4ab5070548 | |||
| 546edcd4a0 | |||
| 71bb3fdfa5 | |||
| eb05b45b70 | |||
| 8394462356 | |||
| 2d53a785d5 | |||
| 64fdd336a0 | |||
| 80c72e92d2 | |||
| cbf090fe70 | |||
| 274652d119 | |||
| 208e34bc34 | |||
| 11ae8f0ef4 | |||
| c32d4f3cd0 | |||
| e52a278ed7 | |||
| 8f230f45cc | |||
| 78bbf6bad2 | |||
| 3a64043f28 | |||
| 49db41ea4b | |||
| d507d1415e | |||
| c4eb4ddcfe | |||
| 4babdf33bd | |||
| b8d1a8bb57 | |||
| 2cf82a5c8e | |||
| 06a8f7d91a | |||
| dbbb676da9 | |||
| 84a8c1b0cc | |||
| ff1b10ca66 | |||
| 1c9826140a | |||
| 5b453ed4a8 | |||
| b39caa7469 | |||
| 01d4514dee | |||
| 80b078c469 | |||
| 9f557f5280 | |||
| 94c89284fc | |||
| b17f6c6929 | |||
| afa1f8a2ab | |||
| 686c8d259a | |||
| d01ecc18d5 | |||
| 66ab0d98d7 | |||
| 0dd439a874 | |||
| ae127d8a38 | |||
| b88a92afe8 | |||
| 6b20803401 | |||
| 8cfa673d94 | |||
| c6e37040de | |||
| 9653598af7 | |||
| a6304f91d0 | |||
| c15502525e | |||
| 175b843b66 | |||
| ccb511a527 | |||
| 3388c92c7f | |||
| 1096555414 | |||
| ebee9cddbf | |||
| 5736ea0bd5 | |||
| 94a01b0ae0 | |||
| 8c51e9a8a2 | |||
| 9d956e9198 | |||
| dd4341fe67 | |||
| 758399050d | |||
| 1dd1bf0306 | |||
| a5aa8e1282 | |||
| c568ad4c74 | |||
| 0c4b3e802f | |||
| 65066326c5 | |||
| ffdd0dfeef | |||
| c3a7524c9e | |||
| 7a96fc3785 | |||
| 938690375b | |||
| fcd99d04fb | |||
| 2b4c655405 | |||
| f2d42dc357 | |||
| 412d93060d | |||
| e8614e20ef | |||
| c90d53565a | |||
| 3aeaea50af | |||
| 3055307d3d | |||
| 8dc47f3c06 | |||
| c51a77c2eb | |||
| d39e0d1244 | |||
| ebb58c34da | |||
| 35b78e95d2 | |||
| 0b51419ca4 | |||
| 296ba51f49 | |||
| a1afb2a215 | |||
| c90245da25 | |||
| 8d6f686b59 | |||
| ce66b46986 | |||
| 9886d5951d | |||
| 30ff15a35a | |||
| e5255fc246 | |||
| 3855a7bee4 | |||
| 6aed0b4dd2 | |||
| 1f2bb52850 | |||
| 4222d72bfe | |||
| e24b501c47 | |||
| c47a3a3e09 | |||
| 90d463f969 | |||
| 08567b08ac | |||
| 7d755d10dc | |||
| e9f489a629 | |||
| 776024a008 | |||
| 604edf07d2 | |||
| ff7882c44c | |||
| c9765e5066 | |||
| b875486db8 | |||
| e1d50c8c10 | |||
| 897b465b87 | |||
| e14aa4d0fe | |||
| c912230309 | |||
| 21387f9c24 | |||
| 25b3d49d32 | |||
| 8f2bcfbe79 | |||
| 15c7b7a619 | |||
| 21ac6ca0f2 | |||
| df4b7515a3 | |||
| 188c9a591b | |||
| 23af6e142a | |||
| 97924ebd5d | |||
| 7ded517823 | |||
| 32e081950c | |||
| 755d6eae99 | |||
| 19cdc15aa3 | |||
| 2b2b6073dd | |||
| 9fe2fd04d4 | |||
| 3ba5cefef2 | |||
| e94e83c6c8 | |||
| d6804167ef | |||
| a136b4b078 | |||
| 2aa3b5bc79 | |||
| dcc41bde61 | |||
| a98a223e13 | |||
| f5d76dd5bb | |||
| effd53838c | |||
| 94e6f8c2fa | |||
| 2500f65d01 | |||
| 26a9c1c14d | |||
| fe8d784bce | |||
| 5a76000848 | |||
| 892c3330cf | |||
| 45c644a68d | |||
| daff988e17 | |||
| 80c52ba7cb | |||
| 6e7e6f9c9e | |||
| 9a823732a0 | |||
| 1c9b904d1a | |||
| 41ddb35458 | |||
| 44f4c5545f | |||
| d917ccdaf7 | |||
| 0505214cd9 | |||
| 9d2c9d1a75 | |||
| 667f3cc20e | |||
| fe5974a740 | |||
| 9255e0fb47 | |||
| b00a608af7 | |||
| 47c66517ae | |||
| 9e03a98182 | |||
| 70e6795829 | |||
| c02b18f06f | |||
| 3bb15d4aa0 | |||
| c13df5ae67 | |||
| b8ff5d1bde | |||
| 17eea9574d | |||
| 36bfcb0714 | |||
| d7791ebbcd | |||
| 7dc0a67808 | |||
| 20de5749d2 | |||
| f50ccd80d1 | |||
| 823daa8002 | |||
| 099c419996 | |||
| b4819c2558 | |||
| 69a9fd6029 | |||
| 1ced5688b5 | |||
| 364849c67b | |||
| 6532b4d1b8 | |||
| ea4065f33a | |||
| ef64917a90 | |||
| 47b3eac82b | |||
| 97e23ebbb2 | |||
| 77e261dba3 | |||
| 3e835a5d37 | |||
| 7a1f2e4cf5 | |||
| e35570227c | |||
| 568f6567e1 | |||
| 527a1fd0ae | |||
| 879e33ab64 | |||
| 8a189a6291 | |||
| 18439b0680 | |||
| 2bab9a0460 | |||
| ae1f7a8f5c | |||
| 11ef53544f | |||
| d3ed883a8f | |||
| 84a5a2d827 | |||
| cffb42ee8f | |||
| 7449170cc8 | |||
| 56c82ecd35 | |||
| 84586c0f17 | |||
| d105040581 | |||
| 679535ec29 | |||
| 9881899e7b | |||
| 934c606d91 | |||
| 772c686776 | |||
| 4c38179d15 | |||
| d1314d4b3a | |||
| 0997b319a3 | |||
| 2c5491e131 | |||
| 3f1cda2e37 | |||
| 0ae5c54ab3 | |||
| 426a8c927b | |||
| 4a16dc51a8 | |||
| 35068204f4 | |||
| 942a312779 | |||
| 22d10c756a | |||
| e777765320 | |||
| d80d9d3731 | |||
| f77f41ee95 | |||
| 6786fd8719 | |||
| 7b536961b2 | |||
| 1404984668 | |||
| a98881151f | |||
| e15950a8ef | |||
| e20f0ee9b6 | |||
| 1c945f812b | |||
| 8613f6f4ae | |||
| 011e4bff34 | |||
| 5271e30049 | |||
| 26d51e490e | |||
| c756665e81 | |||
| 25551b6b40 | |||
| 6517c498b9 | |||
| 51f9f0098d | |||
| 8c2866df36 | |||
| 923cd22083 | |||
| 11309f3243 | |||
| e17cae8f32 | |||
| 71960cda85 | |||
| 27dff4a0a2 | |||
| de79ae92e5 | |||
| e0d4e5a1c0 | |||
| e7c1074b65 | |||
| ce6287574f | |||
| 7407c1f4e2 | |||
| cc2fe2c26e | |||
| 0f207c808c | |||
| c995c0863e | |||
| 2c0b146630 | |||
| 16f0861501 | |||
| 22000b93d5 | |||
| a793df3d6d | |||
| 4ddcc7537f | |||
| 6d1c036e0c | |||
| 3b7c47417e | |||
| b3ac94a978 | |||
| eebef339be | |||
| ee3493c060 | |||
| 2bbd15ccaf | |||
| 0b903af296 | |||
| cccf3b008a | |||
| ab1ace383e | |||
| 862967e089 | |||
| 599588fe5f | |||
| f9b6d7665d | |||
| 7bcdbbc65b | |||
| 800abf1277 | |||
| 9eaea86234 | |||
| d131633471 | |||
| ae2e1ff7bd | |||
| 885363a373 | |||
| 651c23ece3 | |||
| 0e4808bf6f | |||
| 67fefcf184 | |||
| baa4f23ee5 | |||
| 1073b60155 | |||
| 8acadd9e97 | |||
| 9700e3592b | |||
| f90c2a6d4b | |||
| d9814c06bf | |||
| 4318c8cafd | |||
| 178b92d380 | |||
| db9daa98a5 | |||
| 362bd5e3a2 | |||
| e87b645b56 | |||
| aaa2ecbd95 | |||
| 11715f2092 | |||
| 8f47bd296c | |||
| e6bad200e4 | |||
| 13364d70dd | |||
| 0342e4f489 | |||
| 127b63b79f | |||
| 81207ffebd | |||
| fe70a1d51f | |||
| 2b5f94fa6a | |||
| cdb860ad84 | |||
| 8727f598c2 | |||
| 5dad77b9d5 | |||
| 5858f472e3 | |||
| cfe1e44ed7 | |||
| 2bb8b28d78 | |||
| f3e2fc58ec | |||
| 43bbaa8d6e | |||
| 9dc580db27 | |||
| 024aca48e5 | |||
| 24231f1ae3 | |||
| dcee7c5e91 | |||
| 3328675b44 | |||
| 7d60e97cc9 | |||
| b475eed5fa | |||
| 3f9ca4f5dc | |||
| 25cbf00e13 | |||
| a07d4abe1f | |||
| 35dd3c2299 | |||
| 3a7c0c67c1 | |||
| e9118e3bda | |||
| b22c9ef954 | |||
| d6ae445773 | |||
| 06309160ee | |||
| d7a575a2c8 | |||
| e62b4ccb5e | |||
| 4a65d50d0c | |||
| 8aad8f269c | |||
| e1802cac7f | |||
| 5bdcf5d31c | |||
| 2c813a33fe | |||
| e91a095ad6 | |||
| 8ad8f15cf6 | |||
| e0750f9b2c | |||
| 37b4d13db8 | |||
| 7c332ad930 | |||
| 1a76fb843a | |||
| d584c5f624 | |||
| be7b4e88f0 | |||
| 2163326888 |
@@ -0,0 +1 @@
|
||||
**/xtscancodes.js
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"sourceType": "module"
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"rules": {
|
||||
// Unsafe or confusing stuff that we forbid
|
||||
|
||||
"no-unused-vars": ["error", { "vars": "all", "args": "none", "ignoreRestSiblings": true }],
|
||||
"no-constant-condition": ["error", { "checkLoops": false }],
|
||||
"no-var": "error",
|
||||
"no-useless-constructor": "error",
|
||||
"object-shorthand": ["error", "methods", { "avoidQuotes": true }],
|
||||
"prefer-arrow-callback": "error",
|
||||
"arrow-body-style": ["error", "as-needed", { "requireReturnForObjectLiteral": false } ],
|
||||
"arrow-parens": ["error", "as-needed", { "requireForBlockBody": true }],
|
||||
"arrow-spacing": ["error"],
|
||||
"no-confusing-arrow": ["error", { "allowParens": true }],
|
||||
|
||||
// Enforced coding style
|
||||
|
||||
"brace-style": ["error", "1tbs", { "allowSingleLine": true }],
|
||||
"indent": ["error", 4, { "SwitchCase": 1,
|
||||
"FunctionDeclaration": { "parameters": "first" },
|
||||
"CallExpression": { "arguments": "first" },
|
||||
"ArrayExpression": "first",
|
||||
"ObjectExpression": "first",
|
||||
"ignoreComments": true }],
|
||||
"comma-spacing": ["error"],
|
||||
"comma-style": ["error"],
|
||||
"curly": ["error", "multi-line"],
|
||||
"func-call-spacing": ["error"],
|
||||
"func-names": ["error"],
|
||||
"func-style": ["error", "declaration", { "allowArrowFunctions": true }],
|
||||
"key-spacing": ["error"],
|
||||
"keyword-spacing": ["error"],
|
||||
"no-trailing-spaces": ["error"],
|
||||
"semi": ["error"],
|
||||
"space-before-blocks": ["error"],
|
||||
"space-before-function-paren": ["error", { "anonymous": "always",
|
||||
"named": "never",
|
||||
"asyncArrow": "always" }],
|
||||
"switch-colon-spacing": ["error"],
|
||||
"camelcase": ["error", { allow: ["^XK_", "^XF86XK_"] }],
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Client (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Browser: [e.g. chrome, safari]
|
||||
- Browser version: [e.g. 22]
|
||||
|
||||
**Server (please complete the following information):**
|
||||
- noVNC version: [e.g. 1.0.0 or git commit id]
|
||||
- VNC server: [e.g. QEMU, TigerVNC]
|
||||
- WebSocket proxy: [e.g. websockify]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Question or discussion
|
||||
url: https://groups.google.com/forum/?fromgroups#!forum/novnc
|
||||
about: Ask a question or start a discussion
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -0,0 +1,56 @@
|
||||
name: Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
npm:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
# Needs to be explicitly specified for auth to work
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
- run: npm install
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: npm
|
||||
path: lib
|
||||
- run: npm publish --access public
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
||||
if: ${{ github.event_name == 'release' && !github.event.release.prerelease }}
|
||||
- run: npm publish --access public --tag beta
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
||||
if: ${{ github.event_name == 'release' && github.event.release.prerelease }}
|
||||
snap:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: |
|
||||
VERSION=$(grep '"version"' package.json | cut -d '"' -f 4)
|
||||
echo $VERSION
|
||||
sed -i "s/@VERSION@/$VERSION/g" snap/snapcraft.yaml
|
||||
- uses: snapcore/action-build@v1
|
||||
id: snapcraft
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: snap
|
||||
path: ${{ steps.snapcraft.outputs.snap }}
|
||||
- uses: snapcore/action-publish@v1
|
||||
with:
|
||||
store_login: ${{ secrets.SNAPCRAFT_LOGIN }}
|
||||
snap: ${{ steps.build.outputs.snap }}
|
||||
release: stable
|
||||
if: ${{ github.event_name == 'release' && !github.event.release.prerelease }}
|
||||
- uses: snapcore/action-publish@v1
|
||||
with:
|
||||
store_login: ${{ secrets.SNAPCRAFT_LOGIN }}
|
||||
snap: ${{ steps.build.outputs.snap }}
|
||||
release: beta
|
||||
if: ${{ github.event_name == 'release' && github.event.release.prerelease }}
|
||||
@@ -0,0 +1,19 @@
|
||||
name: Lint
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
eslint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
- run: npm install
|
||||
- run: npm run lint
|
||||
html:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
- run: npm install
|
||||
- run: git ls-tree --name-only -r HEAD | grep -E "[.](html|css)$" | xargs ./utils/validate
|
||||
@@ -0,0 +1,28 @@
|
||||
name: Test
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
browser:
|
||||
- ChromeHeadless
|
||||
- FirefoxHeadless
|
||||
include:
|
||||
- os: macos-latest
|
||||
browser: Safari
|
||||
- os: windows-latest
|
||||
browser: EdgeHeadless
|
||||
fail-fast: false
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
- run: npm install
|
||||
- run: npm run test
|
||||
env:
|
||||
TEST_BROWSER_NAME: ${{ matrix.browser }}
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
# infra JS
|
||||
/build/
|
||||
/node_modules/
|
||||
/tests/
|
||||
/utils/
|
||||
/recordings/
|
||||
/vendor/sinon.js
|
||||
|
||||
# noVNC application files
|
||||
/app
|
||||
/vendor/browser-es-module-loader
|
||||
/vendor/promise.js
|
||||
/vnc.html
|
||||
/vnc_lite.html
|
||||
|
||||
# raw translation files
|
||||
/po
|
||||
|
||||
# config files
|
||||
/.travis.yml
|
||||
/karma.conf.js
|
||||
|
||||
# various other files
|
||||
/.gitmodules
|
||||
.*
|
||||
*~
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# documentation (except licenses)
|
||||
/docs/notes
|
||||
/docs/links
|
||||
/docs/release.txt
|
||||
/docs/rfb_notes
|
||||
/docs/*.pdf
|
||||
/docs/flash_policy.txt
|
||||
/CONTRIBUTING.md
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
language: node_js
|
||||
sudo: false
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
node_js:
|
||||
- '6.1'
|
||||
env:
|
||||
matrix:
|
||||
- TEST_BROWSER_NAME=chrome TEST_BROWSER_OS='Windows 10,Linux,OS X 10.11'
|
||||
- TEST_BROWSER_NAME=firefox TEST_BROWSER_OS='Windows 10,Linux,OS X 10.11'
|
||||
- TEST_BROWSER_NAME='internet explorer' TEST_BROWSER_OS='Windows 10'
|
||||
- TEST_BROWSER_NAME=safari TEST_BROWSER_OS='OS X 10.11'
|
||||
before_script: npm install -g karma-cli
|
||||
addons:
|
||||
sauce_connect:
|
||||
username: "directxman12"
|
||||
jwt:
|
||||
secure: "d3ekMYslpn6R4f0ajtRMt9SUFmNGDiItHpqaXC5T4KI0KMEsxgvEOfJot5PiFFJWg1DSpJZH6oaW2UxGZ3duJLZrXIEd/JePY8a6NtT35BNgiDPgcp+eu2Bu3rhrSNg7/HEsD1ma+JeUTnv18Ai5oMFfCCQJx2J6osIxyl/ZVxA="
|
||||
stages:
|
||||
- test
|
||||
- name: deploy
|
||||
if: tag is PRESENT
|
||||
jobs:
|
||||
include:
|
||||
- stage: deploy
|
||||
script: skip
|
||||
before_script: skip
|
||||
deploy:
|
||||
provider: npm
|
||||
email: directxman12+npm@gmail.com
|
||||
api_key:
|
||||
secure: cIidkFmvkdmdwWsqBpxyPUCzBqgK8LhPiNxTrIfhwbUunMsJep9MiiBJtv8poVYG2Y4yfiZmqGn4nfetUdc/LDctd73j+/EM4Z/NUDexVAhJ+9/qCogvpJsSQ96VQo7yBceW4E1fBM3WCU0kcGToYIVSSrwvvRDtJfeYJf2Qqw0=
|
||||
on:
|
||||
tags: true
|
||||
repo: novnc/noVNC
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
maintainers:
|
||||
- Joel Martin (@kanaka)
|
||||
- Solly Ross (@directxman12)
|
||||
- Samuel Mannehed for Cendio AB (@samhed)
|
||||
- Pierre Ossman for Cendio AB (@CendioOssman)
|
||||
maintainersEmeritus:
|
||||
- @astrand
|
||||
contributors:
|
||||
# There are a bunch of people that should be here.
|
||||
# If you want to be on this list, feel free send a PR
|
||||
# to add yourself.
|
||||
- jalf <git@jalf.dk>
|
||||
- NTT corp.
|
||||
+2
-7
@@ -1,4 +1,5 @@
|
||||
noVNC is Copyright (C) 2011 Joel Martin <github@martintribe.org>
|
||||
noVNC is Copyright (C) 2019 The noVNC Authors
|
||||
(./AUTHORS)
|
||||
|
||||
The noVNC core library files are licensed under the MPL 2.0 (Mozilla
|
||||
Public License 2.0). The noVNC core library is composed of the
|
||||
@@ -41,12 +42,6 @@ licenses (all MPL 2.0 compatible):
|
||||
|
||||
vendor/pako/ : MIT
|
||||
|
||||
vendor/browser-es-module-loader/src/ : MIT
|
||||
|
||||
vendor/browser-es-module-loader/dist/ : Various BSD style licenses
|
||||
|
||||
vendor/promise.js : MIT
|
||||
|
||||
Any other files not mentioned above are typically marked with
|
||||
a copyright/license header at the top of the file. The default noVNC
|
||||
license is MPL-2.0.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
## noVNC: HTML VNC Client Library and Application
|
||||
|
||||
[](https://travis-ci.org/novnc/noVNC)
|
||||
[](https://github.com/novnc/noVNC/actions?query=workflow%3ATest)
|
||||
[](https://github.com/novnc/noVNC/actions?query=workflow%3ALint)
|
||||
|
||||
### Description
|
||||
|
||||
@@ -24,6 +25,7 @@ for a more complete list with additional info and links.
|
||||
- [Browser Requirements](#browser-requirements)
|
||||
- [Server Requirements](#server-requirements)
|
||||
- [Quick Start](#quick-start)
|
||||
- [Installation from Snap Package](#installation-from-snap-package)
|
||||
- [Integration and Deployment](#integration-and-deployment)
|
||||
- [Authors/Contributors](#authorscontributors)
|
||||
|
||||
@@ -67,6 +69,8 @@ Please tweet [@noVNC](http://www.twitter.com/noVNC) if you do.
|
||||
* Supports scaling, clipping and resizing the desktop
|
||||
* Local cursor rendering
|
||||
* Clipboard copy/paste
|
||||
* Translations
|
||||
* Touch gestures for emulating common mouse actions
|
||||
* Licensed mainly under the [MPL 2.0](http://www.mozilla.org/MPL/2.0/), see
|
||||
[the license document](LICENSE.txt) for details
|
||||
|
||||
@@ -87,7 +91,7 @@ noVNC uses many modern web technologies so a formal requirement list is
|
||||
not available. However these are the minimum versions we are currently
|
||||
aware of:
|
||||
|
||||
* Chrome 49, Firefox 44, Safari 10, Opera 36, IE 11, Edge 12
|
||||
* Chrome 64, Firefox 79, Safari 13.4, Opera 51, Edge 79
|
||||
|
||||
|
||||
### Server Requirements
|
||||
@@ -104,16 +108,76 @@ proxy.
|
||||
|
||||
### Quick Start
|
||||
|
||||
* Use the launch script to automatically download and start websockify, which
|
||||
* Use the `novnc_proxy` script to automatically download and start websockify, which
|
||||
includes a mini-webserver and the WebSockets proxy. The `--vnc` option is
|
||||
used to specify the location of a running VNC server:
|
||||
|
||||
`./utils/launch.sh --vnc localhost:5901`
|
||||
`./utils/novnc_proxy --vnc localhost:5901`
|
||||
|
||||
* Point your browser to the cut-and-paste URL that is output by the launch
|
||||
* Point your browser to the cut-and-paste URL that is output by the `novnc_procy`
|
||||
script. Hit the Connect button, enter a password if the VNC server has one
|
||||
configured, and enjoy!
|
||||
|
||||
### Installation from Snap Package
|
||||
Running the command below will install the latest release of noVNC from Snap:
|
||||
|
||||
`sudo snap install novnc`
|
||||
|
||||
#### Running noVNC
|
||||
|
||||
You can run the Snap-package installed novnc directly with, for example:
|
||||
|
||||
`novnc --listen 6081 --vnc localhost:5901 # /snap/bin/novnc if /snap/bin is not in your PATH`
|
||||
|
||||
#### Running as a Service (Daemon)
|
||||
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
|
||||
(effectively a service runing multiple instances of novnc).
|
||||
Instructions (with example values):
|
||||
|
||||
List current services (out-of-box this will be blank):
|
||||
|
||||
```
|
||||
sudo snap get novnc services
|
||||
Key Value
|
||||
services.n6080 {...}
|
||||
services.n6081 {...}
|
||||
```
|
||||
|
||||
Create a new service that listens on port 6082 and connects to the VNC server
|
||||
running on port 5902 on localhost:
|
||||
|
||||
`sudo snap set novnc services.n6082.listen=6082 services.n6082.vnc=localhost:5902`
|
||||
|
||||
(Any services you define with 'snap set' will be automatically started)
|
||||
Note that the name of the service, 'n6082' in this example, can be anything
|
||||
as long as it doesn't start with a number or contain spaces/special characters.
|
||||
|
||||
View the configuration of the service just created:
|
||||
|
||||
```
|
||||
sudo snap get novnc services.n6082
|
||||
Key Value
|
||||
services.n6082.listen 6082
|
||||
services.n6082.vnc localhost:5902
|
||||
```
|
||||
|
||||
Disable a service (note that because of a limitation in Snap it's currently not
|
||||
possible to unset config variables, setting them to blank values is the way
|
||||
to disable a service):
|
||||
|
||||
`sudo snap set novnc services.n6082.listen='' services.n6082.vnc=''`
|
||||
|
||||
(Any services you set to blank with 'snap set' like this will be automatically stopped)
|
||||
|
||||
Verify that the service is disabled (blank values):
|
||||
|
||||
```
|
||||
sudo snap get novnc services.n6082
|
||||
Key Value
|
||||
services.n6082.listen
|
||||
services.n6082.vnc
|
||||
```
|
||||
|
||||
### Integration and Deployment
|
||||
|
||||
@@ -126,10 +190,12 @@ or deploying the noVNC application in production environments:
|
||||
|
||||
### Authors/Contributors
|
||||
|
||||
See [AUTHORS](AUTHORS) for a (full-ish) list of authors. If you're not on
|
||||
that list and you think you should be, feel free to send a PR to fix that.
|
||||
|
||||
* Core team:
|
||||
* [Joel Martin](https://github.com/kanaka)
|
||||
* [Samuel Mannehed](https://github.com/samhed) (Cendio)
|
||||
* [Peter Åstrand](https://github.com/astrand) (Cendio)
|
||||
* [Solly Ross](https://github.com/DirectXMan12) (Red Hat / OpenStack)
|
||||
* [Pierre Ossman](https://github.com/CendioOssman) (Cendio)
|
||||
|
||||
|
||||
+18
-8
@@ -1,22 +1,32 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2019 The noVNC Authors
|
||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||
*
|
||||
* See README.md for usage and integration instructions.
|
||||
*/
|
||||
|
||||
// NB: this should *not* be included as a module until we have
|
||||
// native support in the browsers, so that our error handler
|
||||
// can catch script-loading errors.
|
||||
|
||||
// No ES6 can be used in this file since it's used for the translation
|
||||
/* eslint-disable prefer-arrow-callback */
|
||||
|
||||
(function(){
|
||||
(function _scope() {
|
||||
"use strict";
|
||||
|
||||
// Fallback for all uncought errors
|
||||
function handleError (event, err) {
|
||||
function handleError(event, err) {
|
||||
try {
|
||||
var msg = document.getElementById('noVNC_fallback_errormsg');
|
||||
const msg = document.getElementById('noVNC_fallback_errormsg');
|
||||
|
||||
// Only show the initial error
|
||||
if (msg.hasChildNodes()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var div = document.createElement("div");
|
||||
let div = document.createElement("div");
|
||||
div.classList.add('noVNC_message');
|
||||
div.appendChild(document.createTextNode(event.message));
|
||||
msg.appendChild(div);
|
||||
@@ -24,7 +34,7 @@
|
||||
if (event.filename) {
|
||||
div = document.createElement("div");
|
||||
div.className = 'noVNC_location';
|
||||
var text = event.filename;
|
||||
let text = event.filename;
|
||||
if (event.lineno !== undefined) {
|
||||
text += ":" + event.lineno;
|
||||
if (event.colno !== undefined) {
|
||||
@@ -35,7 +45,7 @@
|
||||
msg.appendChild(div);
|
||||
}
|
||||
|
||||
if (err && (err.stack !== undefined)) {
|
||||
if (err && err.stack) {
|
||||
div = document.createElement("div");
|
||||
div.className = 'noVNC_stack';
|
||||
div.appendChild(document.createTextNode(err.stack));
|
||||
@@ -51,6 +61,6 @@
|
||||
// from being printed to the browser console.
|
||||
return false;
|
||||
}
|
||||
window.addEventListener('error', function (evt) { handleError(evt, evt.error); });
|
||||
window.addEventListener('unhandledrejection', function (evt) { handleError(evt.reason, evt.reason); });
|
||||
window.addEventListener('error', function onerror(evt) { handleError(evt, evt.error); });
|
||||
window.addEventListener('unhandledrejection', function onreject(evt) { handleError(evt.reason, evt.reason); });
|
||||
})();
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="25"
|
||||
height="25"
|
||||
viewBox="0 0 25 25"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="mouse_left.svg"
|
||||
inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#959595"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.313708"
|
||||
inkscape:cx="15.551515"
|
||||
inkscape:cy="12.205592"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:object-paths="true"
|
||||
showguides="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1136"
|
||||
inkscape:window-x="1920"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-smooth-nodes="true"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:snap-intersection-paths="true"
|
||||
inkscape:snap-nodes="true"
|
||||
inkscape:snap-global="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid4136" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-1027.3622)">
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0068f6;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 8,1030.3622 c -2.1987124,0 -4,1.8013 -4,4 l 0,2 5,0 0,-2 c 0,-1.4738 1.090393,-2.7071 2.5,-2.9492 l 0,-1.0508 -3.5,0 z"
|
||||
id="path6219" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 13.5,1030.3622 0,1.0508 c 1.409607,0.2421 2.5,1.4754 2.5,2.9492 l 0,2 5,0 0,-2 c 0,-2.1987 -1.801288,-4 -4,-4 l -3.5,0 z"
|
||||
id="path6217" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 12,1033.3622 c -0.571311,0 -1,0.4287 -1,1 l 0,5 c 0,0.5713 0.428689,1 1,1 l 1,0 c 0.571311,0 1,-0.4287 1,-1 l 0,-5 c 0,-0.5713 -0.428689,-1 -1,-1 l -1,0 z"
|
||||
id="path6215" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 4,1038.3622 0,3.5 c 0,4.1377 3.362302,7.5 7.5,7.5 l 2,0 c 4.137698,0 7.5,-3.3623 7.5,-7.5 l 0,-3.5 -5,0 0,1 c 0,1.6447 -1.355293,3 -3,3 l -1,0 c -1.644707,0 -3,-1.3553 -3,-3 l 0,-1 -5,0 z"
|
||||
id="rect6178" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 6.8 KiB |
@@ -1,92 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="25"
|
||||
height="25"
|
||||
viewBox="0 0 25 25"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="mouse_middle.svg"
|
||||
inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#959595"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.313708"
|
||||
inkscape:cx="15.551515"
|
||||
inkscape:cy="12.205592"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:object-paths="true"
|
||||
showguides="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1136"
|
||||
inkscape:window-x="1920"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-smooth-nodes="true"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:snap-intersection-paths="true"
|
||||
inkscape:snap-nodes="true"
|
||||
inkscape:snap-global="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid4136" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-1027.3622)">
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 8,1030.3622 c -2.1987124,0 -4,1.8013 -4,4 l 0,2 5,0 0,-2 c 0,-1.4738 1.090393,-2.7071 2.5,-2.9492 l 0,-1.0508 -3.5,0 z"
|
||||
id="path6219" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 13.5,1030.3622 0,1.0508 c 1.409607,0.2421 2.5,1.4754 2.5,2.9492 l 0,2 5,0 0,-2 c 0,-2.1987 -1.801288,-4 -4,-4 l -3.5,0 z"
|
||||
id="path6217" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0068f6;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 12,1033.3622 c -0.571311,0 -1,0.4287 -1,1 l 0,5 c 0,0.5713 0.428689,1 1,1 l 1,0 c 0.571311,0 1,-0.4287 1,-1 l 0,-5 c 0,-0.5713 -0.428689,-1 -1,-1 l -1,0 z"
|
||||
id="path6215" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 4,1038.3622 0,3.5 c 0,4.1377 3.362302,7.5 7.5,7.5 l 2,0 c 4.137698,0 7.5,-3.3623 7.5,-7.5 l 0,-3.5 -5,0 0,1 c 0,1.6447 -1.355293,3 -3,3 l -1,0 c -1.644707,0 -3,-1.3553 -3,-3 l 0,-1 -5,0 z"
|
||||
id="rect6178" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 6.8 KiB |
@@ -1,92 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="25"
|
||||
height="25"
|
||||
viewBox="0 0 25 25"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="mouse_none.svg"
|
||||
inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#959595"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="16"
|
||||
inkscape:cx="23.160825"
|
||||
inkscape:cy="13.208262"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:object-paths="true"
|
||||
showguides="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1136"
|
||||
inkscape:window-x="1920"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-smooth-nodes="true"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:snap-intersection-paths="true"
|
||||
inkscape:snap-nodes="true"
|
||||
inkscape:snap-global="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid4136" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-1027.3622)">
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 8,1030.3622 c -2.1987124,0 -4,1.8013 -4,4 l 0,2 5,0 0,-2 c 0,-1.4738 1.090393,-2.7071 2.5,-2.9492 l 0,-1.0508 -3.5,0 z"
|
||||
id="path6219" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 13.5,1030.3622 0,1.0508 c 1.409607,0.2421 2.5,1.4754 2.5,2.9492 l 0,2 5,0 0,-2 c 0,-2.1987 -1.801288,-4 -4,-4 l -3.5,0 z"
|
||||
id="path6217" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 12,1033.3622 c -0.571311,0 -1,0.4287 -1,1 l 0,5 c 0,0.5713 0.428689,1 1,1 l 1,0 c 0.571311,0 1,-0.4287 1,-1 l 0,-5 c 0,-0.5713 -0.428689,-1 -1,-1 l -1,0 z"
|
||||
id="path6215" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 4,1038.3622 0,3.5 c 0,4.1377 3.362302,7.5 7.5,7.5 l 2,0 c 4.137698,0 7.5,-3.3623 7.5,-7.5 l 0,-3.5 -5,0 0,1 c 0,1.6447 -1.355293,3 -3,3 l -1,0 c -1.644707,0 -3,-1.3553 -3,-3 l 0,-1 -5,0 z"
|
||||
id="rect6178" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 6.8 KiB |
@@ -1,92 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="25"
|
||||
height="25"
|
||||
viewBox="0 0 25 25"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="mouse_right.svg"
|
||||
inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#959595"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.313708"
|
||||
inkscape:cx="15.551515"
|
||||
inkscape:cy="12.205592"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:object-paths="true"
|
||||
showguides="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1136"
|
||||
inkscape:window-x="1920"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-smooth-nodes="true"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:snap-intersection-paths="true"
|
||||
inkscape:snap-nodes="true"
|
||||
inkscape:snap-global="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid4136" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-1027.3622)">
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 8,1030.3622 c -2.1987124,0 -4,1.8013 -4,4 l 0,2 5,0 0,-2 c 0,-1.4738 1.090393,-2.7071 2.5,-2.9492 l 0,-1.0508 -3.5,0 z"
|
||||
id="path6219" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0068f6;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 13.5,1030.3622 0,1.0508 c 1.409607,0.2421 2.5,1.4754 2.5,2.9492 l 0,2 5,0 0,-2 c 0,-2.1987 -1.801288,-4 -4,-4 l -3.5,0 z"
|
||||
id="path6217" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 12,1033.3622 c -0.571311,0 -1,0.4287 -1,1 l 0,5 c 0,0.5713 0.428689,1 1,1 l 1,0 c 0.571311,0 1,-0.4287 1,-1 l 0,-5 c 0,-0.5713 -0.428689,-1 -1,-1 l -1,0 z"
|
||||
id="path6215" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 4,1038.3622 0,3.5 c 0,4.1377 3.362302,7.5 7.5,7.5 l 2,0 c 4.137698,0 7.5,-3.3623 7.5,-7.5 l 0,-3.5 -5,0 0,1 c 0,1.6447 -1.355293,3 -3,3 l -1,0 c -1.644707,0 -3,-1.3553 -3,-3 l 0,-1 -5,0 z"
|
||||
id="rect6178" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 6.8 KiB |
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="svg2"
|
||||
inkscape:export-ydpi="90"
|
||||
inkscape:export-xdpi="90"
|
||||
sodipodi:docname="windows.svg"
|
||||
inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
|
||||
inkscape:version="0.92.4 (unknown)"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="-293 384 25 25"
|
||||
xml:space="preserve"
|
||||
width="25"
|
||||
height="25"><metadata
|
||||
id="metadata21"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs19" /><sodipodi:namedview
|
||||
pagecolor="#959595"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1136"
|
||||
id="namedview17"
|
||||
showgrid="true"
|
||||
inkscape:pagecheckerboard="false"
|
||||
inkscape:zoom="32"
|
||||
inkscape:cx="3.926913"
|
||||
inkscape:cy="13.255959"
|
||||
inkscape:window-x="1920"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2"><inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid818" /></sodipodi:namedview>
|
||||
<style
|
||||
type="text/css"
|
||||
id="style2">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
|
||||
<path
|
||||
style="fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1"
|
||||
d="M 21 4 L 11 5.1757812 L 11 12 L 21 12 L 21 4 z M 10 5.2949219 L 4 6 L 4 12 L 10 12 L 10 5.2949219 z "
|
||||
transform="translate(-293,384)"
|
||||
id="path853" /><path
|
||||
id="path858"
|
||||
d="m -272,405 -10,-1.17578 V 397 h 10 z M -283,403.70508 -289,403 v -6 h 6 z"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
inkscape:connector-curvature="0" /></svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1 @@
|
||||
DO NOT MODIFY THE FILES IN THIS FOLDER, THEY ARE AUTOMATICALLY GENERATED FROM THE PO-FILES.
|
||||
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"Connecting...": "Připojení...",
|
||||
"Disconnecting...": "Odpojení...",
|
||||
"Reconnecting...": "Obnova připojení...",
|
||||
"Internal error": "Vnitřní chyba",
|
||||
"Must set host": "Hostitel musí být nastavení",
|
||||
"Connected (encrypted) to ": "Připojení (šifrované) k ",
|
||||
"Connected (unencrypted) to ": "Připojení (nešifrované) k ",
|
||||
"Something went wrong, connection is closed": "Něco se pokazilo, odpojeno",
|
||||
"Failed to connect to server": "Chyba připojení k serveru",
|
||||
"Disconnected": "Odpojeno",
|
||||
"New connection has been rejected with reason: ": "Nové připojení bylo odmítnuto s odůvodněním: ",
|
||||
"New connection has been rejected": "Nové připojení bylo odmítnuto",
|
||||
"Password is required": "Je vyžadováno heslo",
|
||||
"noVNC encountered an error:": "noVNC narazilo na chybu:",
|
||||
"Hide/Show the control bar": "Skrýt/zobrazit ovládací panel",
|
||||
"Move/Drag Viewport": "Přesunout/přetáhnout výřez",
|
||||
"viewport drag": "přesun výřezu",
|
||||
"Active Mouse Button": "Aktivní tlačítka myši",
|
||||
"No mousebutton": "Žádné",
|
||||
"Left mousebutton": "Levé tlačítko myši",
|
||||
"Middle mousebutton": "Prostřední tlačítko myši",
|
||||
"Right mousebutton": "Pravé tlačítko myši",
|
||||
"Keyboard": "Klávesnice",
|
||||
"Show Keyboard": "Zobrazit klávesnici",
|
||||
"Extra keys": "Extra klávesy",
|
||||
"Show Extra Keys": "Zobrazit extra klávesy",
|
||||
"Ctrl": "Ctrl",
|
||||
"Toggle Ctrl": "Přepnout Ctrl",
|
||||
"Alt": "Alt",
|
||||
"Toggle Alt": "Přepnout Alt",
|
||||
"Send Tab": "Odeslat tabulátor",
|
||||
"Tab": "Tab",
|
||||
"Esc": "Esc",
|
||||
"Send Escape": "Odeslat Esc",
|
||||
"Ctrl+Alt+Del": "Ctrl+Alt+Del",
|
||||
"Send Ctrl-Alt-Del": "Poslat Ctrl-Alt-Del",
|
||||
"Shutdown/Reboot": "Vypnutí/Restart",
|
||||
"Shutdown/Reboot...": "Vypnutí/Restart...",
|
||||
"Power": "Napájení",
|
||||
"Shutdown": "Vypnout",
|
||||
"Reboot": "Restart",
|
||||
"Reset": "Reset",
|
||||
"Clipboard": "Schránka",
|
||||
"Clear": "Vymazat",
|
||||
"Fullscreen": "Celá obrazovka",
|
||||
"Settings": "Nastavení",
|
||||
"Shared Mode": "Sdílený režim",
|
||||
"View Only": "Pouze prohlížení",
|
||||
"Clip to Window": "Přizpůsobit oknu",
|
||||
"Scaling Mode:": "Přizpůsobení velikosti",
|
||||
"None": "Žádné",
|
||||
"Local Scaling": "Místní",
|
||||
"Remote Resizing": "Vzdálené",
|
||||
"Advanced": "Pokročilé",
|
||||
"Repeater ID:": "ID opakovače",
|
||||
"WebSocket": "WebSocket",
|
||||
"Encrypt": "Šifrování:",
|
||||
"Host:": "Hostitel:",
|
||||
"Port:": "Port:",
|
||||
"Path:": "Cesta",
|
||||
"Automatic Reconnect": "Automatická obnova připojení",
|
||||
"Reconnect Delay (ms):": "Zpoždění připojení (ms)",
|
||||
"Show Dot when No Cursor": "Tečka místo chybějícího kurzoru myši",
|
||||
"Logging:": "Logování:",
|
||||
"Disconnect": "Odpojit",
|
||||
"Connect": "Připojit",
|
||||
"Password:": "Heslo",
|
||||
"Send Password": "Odeslat heslo",
|
||||
"Cancel": "Zrušit"
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"Connecting...": "Conectando...",
|
||||
"Connected (encrypted) to ": "Conectado (con encriptación) a",
|
||||
"Connected (unencrypted) to ": "Conectado (sin encriptación) a",
|
||||
"Disconnecting...": "Desconectando...",
|
||||
"Disconnected": "Desconectado",
|
||||
"Must set host": "Debes configurar el host",
|
||||
"Reconnecting...": "Reconectando...",
|
||||
"Password is required": "Contraseña es obligatoria",
|
||||
"Disconnect timeout": "Tiempo de desconexión agotado",
|
||||
"noVNC encountered an error:": "noVNC ha encontrado un error:",
|
||||
"Hide/Show the control bar": "Ocultar/Mostrar la barra de control",
|
||||
"Move/Drag Viewport": "Mover/Arrastrar la ventana",
|
||||
"viewport drag": "Arrastrar la ventana",
|
||||
"Active Mouse Button": "Botón activo del ratón",
|
||||
"No mousebutton": "Ningún botón del ratón",
|
||||
"Left mousebutton": "Botón izquierdo del ratón",
|
||||
"Middle mousebutton": "Botón central del ratón",
|
||||
"Right mousebutton": "Botón derecho del ratón",
|
||||
"Keyboard": "Teclado",
|
||||
"Show Keyboard": "Mostrar teclado",
|
||||
"Extra keys": "Teclas adicionales",
|
||||
"Show Extra Keys": "Mostrar Teclas Adicionales",
|
||||
"Ctrl": "Ctrl",
|
||||
"Toggle Ctrl": "Pulsar/Soltar Ctrl",
|
||||
"Alt": "Alt",
|
||||
"Toggle Alt": "Pulsar/Soltar Alt",
|
||||
"Send Tab": "Enviar Tabulación",
|
||||
"Tab": "Tabulación",
|
||||
"Esc": "Esc",
|
||||
"Send Escape": "Enviar Escape",
|
||||
"Ctrl+Alt+Del": "Ctrl+Alt+Del",
|
||||
"Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del",
|
||||
"Shutdown/Reboot": "Apagar/Reiniciar",
|
||||
"Shutdown/Reboot...": "Apagar/Reiniciar...",
|
||||
"Power": "Encender",
|
||||
"Shutdown": "Apagar",
|
||||
"Reboot": "Reiniciar",
|
||||
"Reset": "Restablecer",
|
||||
"Clipboard": "Portapapeles",
|
||||
"Clear": "Vaciar",
|
||||
"Fullscreen": "Pantalla Completa",
|
||||
"Settings": "Configuraciones",
|
||||
"Shared Mode": "Modo Compartido",
|
||||
"View Only": "Solo visualización",
|
||||
"Clip to Window": "Recortar al tamaño de la ventana",
|
||||
"Scaling Mode:": "Modo de escalado:",
|
||||
"None": "Ninguno",
|
||||
"Local Scaling": "Escalado Local",
|
||||
"Local Downscaling": "Reducción de escala local",
|
||||
"Remote Resizing": "Cambio de tamaño remoto",
|
||||
"Advanced": "Avanzado",
|
||||
"Local Cursor": "Cursor Local",
|
||||
"Repeater ID:": "ID del Repetidor",
|
||||
"WebSocket": "WebSocket",
|
||||
"Encrypt": "",
|
||||
"Host:": "Host",
|
||||
"Port:": "Puesto",
|
||||
"Path:": "Ruta",
|
||||
"Automatic Reconnect": "Reconexión automática",
|
||||
"Reconnect Delay (ms):": "Retraso en la reconexión (ms)",
|
||||
"Logging:": "Logging",
|
||||
"Disconnect": "Desconectar",
|
||||
"Connect": "Conectar",
|
||||
"Password:": "Contraseña",
|
||||
"Cancel": "Cancelar",
|
||||
"Canvas not supported.": "Canvas no está soportado"
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"Connecting...": "接続しています...",
|
||||
"Disconnecting...": "切断しています...",
|
||||
"Reconnecting...": "再接続しています...",
|
||||
"Internal error": "内部エラー",
|
||||
"Must set host": "ホストを設定する必要があります",
|
||||
"Connected (encrypted) to ": "接続しました (暗号化済み): ",
|
||||
"Connected (unencrypted) to ": "接続しました (暗号化されていません): ",
|
||||
"Something went wrong, connection is closed": "何らかの問題で、接続が閉じられました",
|
||||
"Failed to connect to server": "サーバーへの接続に失敗しました",
|
||||
"Disconnected": "切断しました",
|
||||
"New connection has been rejected with reason: ": "新規接続は次の理由で拒否されました: ",
|
||||
"New connection has been rejected": "新規接続は拒否されました",
|
||||
"Credentials are required": "資格情報が必要です",
|
||||
"noVNC encountered an error:": "noVNC でエラーが発生しました:",
|
||||
"Hide/Show the control bar": "コントロールバーを隠す/表示する",
|
||||
"Drag": "ドラッグ",
|
||||
"Move/Drag Viewport": "ビューポートを移動/ドラッグ",
|
||||
"Keyboard": "キーボード",
|
||||
"Show Keyboard": "キーボードを表示",
|
||||
"Extra keys": "追加キー",
|
||||
"Show Extra Keys": "追加キーを表示",
|
||||
"Ctrl": "Ctrl",
|
||||
"Toggle Ctrl": "Ctrl キーを切り替え",
|
||||
"Alt": "Alt",
|
||||
"Toggle Alt": "Alt キーを切り替え",
|
||||
"Toggle Windows": "Windows キーを切り替え",
|
||||
"Windows": "Windows",
|
||||
"Send Tab": "Tab キーを送信",
|
||||
"Tab": "Tab",
|
||||
"Esc": "Esc",
|
||||
"Send Escape": "Escape キーを送信",
|
||||
"Ctrl+Alt+Del": "Ctrl+Alt+Del",
|
||||
"Send Ctrl-Alt-Del": "Ctrl-Alt-Del を送信",
|
||||
"Shutdown/Reboot": "シャットダウン/再起動",
|
||||
"Shutdown/Reboot...": "シャットダウン/再起動...",
|
||||
"Power": "電源",
|
||||
"Shutdown": "シャットダウン",
|
||||
"Reboot": "再起動",
|
||||
"Reset": "リセット",
|
||||
"Clipboard": "クリップボード",
|
||||
"Clear": "クリア",
|
||||
"Fullscreen": "全画面表示",
|
||||
"Settings": "設定",
|
||||
"Shared Mode": "共有モード",
|
||||
"View Only": "表示のみ",
|
||||
"Clip to Window": "ウィンドウにクリップ",
|
||||
"Scaling Mode:": "スケーリングモード:",
|
||||
"None": "なし",
|
||||
"Local Scaling": "ローカルスケーリング",
|
||||
"Remote Resizing": "リモートでリサイズ",
|
||||
"Advanced": "高度",
|
||||
"Quality:": "品質:",
|
||||
"Compression level:": "圧縮レベル:",
|
||||
"Repeater ID:": "リピーター ID:",
|
||||
"WebSocket": "WebSocket",
|
||||
"Encrypt": "暗号化",
|
||||
"Host:": "ホスト:",
|
||||
"Port:": "ポート:",
|
||||
"Path:": "パス:",
|
||||
"Automatic Reconnect": "自動再接続",
|
||||
"Reconnect Delay (ms):": "再接続する遅延 (ミリ秒):",
|
||||
"Show Dot when No Cursor": "カーソルがないときにドットを表示",
|
||||
"Logging:": "ロギング:",
|
||||
"Version:": "バージョン:",
|
||||
"Disconnect": "切断",
|
||||
"Connect": "接続",
|
||||
"Username:": "ユーザー名:",
|
||||
"Password:": "パスワード:",
|
||||
"Send Credentials": "資格情報を送信",
|
||||
"Cancel": "キャンセル"
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"Connecting...": "연결중...",
|
||||
"Disconnecting...": "연결 해제중...",
|
||||
"Reconnecting...": "재연결중...",
|
||||
"Internal error": "내부 오류",
|
||||
"Must set host": "호스트는 설정되어야 합니다.",
|
||||
"Connected (encrypted) to ": "다음과 (암호화되어) 연결되었습니다:",
|
||||
"Connected (unencrypted) to ": "다음과 (암호화 없이) 연결되었습니다:",
|
||||
"Something went wrong, connection is closed": "무언가 잘못되었습니다, 연결이 닫혔습니다.",
|
||||
"Failed to connect to server": "서버에 연결하지 못했습니다.",
|
||||
"Disconnected": "연결이 해제되었습니다.",
|
||||
"New connection has been rejected with reason: ": "새 연결이 다음 이유로 거부되었습니다:",
|
||||
"New connection has been rejected": "새 연결이 거부되었습니다.",
|
||||
"Password is required": "비밀번호가 필요합니다.",
|
||||
"noVNC encountered an error:": "noVNC에 오류가 발생했습니다:",
|
||||
"Hide/Show the control bar": "컨트롤 바 숨기기/보이기",
|
||||
"Move/Drag Viewport": "움직이기/드래그 뷰포트",
|
||||
"viewport drag": "뷰포트 드래그",
|
||||
"Active Mouse Button": "마우스 버튼 활성화",
|
||||
"No mousebutton": "마우스 버튼 없음",
|
||||
"Left mousebutton": "왼쪽 마우스 버튼",
|
||||
"Middle mousebutton": "중간 마우스 버튼",
|
||||
"Right mousebutton": "오른쪽 마우스 버튼",
|
||||
"Keyboard": "키보드",
|
||||
"Show Keyboard": "키보드 보이기",
|
||||
"Extra keys": "기타 키들",
|
||||
"Show Extra Keys": "기타 키들 보이기",
|
||||
"Ctrl": "Ctrl",
|
||||
"Toggle Ctrl": "Ctrl 켜기/끄기",
|
||||
"Alt": "Alt",
|
||||
"Toggle Alt": "Alt 켜기/끄기",
|
||||
"Send Tab": "Tab 보내기",
|
||||
"Tab": "Tab",
|
||||
"Esc": "Esc",
|
||||
"Send Escape": "Esc 보내기",
|
||||
"Ctrl+Alt+Del": "Ctrl+Alt+Del",
|
||||
"Send Ctrl-Alt-Del": "Ctrl+Alt+Del 보내기",
|
||||
"Shutdown/Reboot": "셧다운/리붓",
|
||||
"Shutdown/Reboot...": "셧다운/리붓...",
|
||||
"Power": "전원",
|
||||
"Shutdown": "셧다운",
|
||||
"Reboot": "리붓",
|
||||
"Reset": "리셋",
|
||||
"Clipboard": "클립보드",
|
||||
"Clear": "지우기",
|
||||
"Fullscreen": "전체화면",
|
||||
"Settings": "설정",
|
||||
"Shared Mode": "공유 모드",
|
||||
"View Only": "보기 전용",
|
||||
"Clip to Window": "창에 클립",
|
||||
"Scaling Mode:": "스케일링 모드:",
|
||||
"None": "없음",
|
||||
"Local Scaling": "로컬 스케일링",
|
||||
"Remote Resizing": "원격 크기 조절",
|
||||
"Advanced": "고급",
|
||||
"Repeater ID:": "중계 ID",
|
||||
"WebSocket": "웹소켓",
|
||||
"Encrypt": "암호화",
|
||||
"Host:": "호스트:",
|
||||
"Port:": "포트:",
|
||||
"Path:": "위치:",
|
||||
"Automatic Reconnect": "자동 재연결",
|
||||
"Reconnect Delay (ms):": "재연결 지연 시간 (ms)",
|
||||
"Logging:": "로깅",
|
||||
"Disconnect": "연결 해제",
|
||||
"Connect": "연결",
|
||||
"Password:": "비밀번호:",
|
||||
"Send Password": "비밀번호 전송",
|
||||
"Cancel": "취소"
|
||||
}
|
||||
+15
-10
@@ -1,13 +1,17 @@
|
||||
{
|
||||
"Connecting...": "Verbinden...",
|
||||
"Disconnecting...": "Verbinding verbreken...",
|
||||
"Reconnecting...": "Opnieuw verbinding maken...",
|
||||
"Internal error": "Interne fout",
|
||||
"Must set host": "Host moeten worden ingesteld",
|
||||
"Connected (encrypted) to ": "Verbonden (versleuteld) met ",
|
||||
"Connected (unencrypted) to ": "Verbonden (onversleuteld) met ",
|
||||
"Disconnecting...": "Verbinding verbreken...",
|
||||
"Something went wrong, connection is closed": "Er iets fout gelopen, verbinding werd verbroken",
|
||||
"Failed to connect to server": "Verbinding maken met server is mislukt",
|
||||
"Disconnected": "Verbinding verbroken",
|
||||
"Must set host": "Host moeten worden ingesteld",
|
||||
"Reconnecting...": "Opnieuw verbinding maken...",
|
||||
"New connection has been rejected with reason: ": "Nieuwe verbinding is geweigerd omwille van de volgende reden: ",
|
||||
"New connection has been rejected": "Nieuwe verbinding is geweigerd",
|
||||
"Password is required": "Wachtwoord is vereist",
|
||||
"Disconnect timeout": "Timeout tijdens verbreken van verbinding",
|
||||
"noVNC encountered an error:": "noVNC heeft een fout bemerkt:",
|
||||
"Hide/Show the control bar": "Verberg/Toon de bedieningsbalk",
|
||||
"Move/Drag Viewport": "Verplaats/Versleep Kijkvenster",
|
||||
@@ -22,9 +26,11 @@
|
||||
"Extra keys": "Extra toetsen",
|
||||
"Show Extra Keys": "Toon Extra Toetsen",
|
||||
"Ctrl": "Ctrl",
|
||||
"Toggle Ctrl": "Ctrl aan/uitzetten",
|
||||
"Toggle Ctrl": "Ctrl omschakelen",
|
||||
"Alt": "Alt",
|
||||
"Toggle Alt": "Alt aan/uitzetten",
|
||||
"Toggle Alt": "Alt omschakelen",
|
||||
"Toggle Windows": "Windows omschakelen",
|
||||
"Windows": "Windows",
|
||||
"Send Tab": "Tab Sturen",
|
||||
"Tab": "Tab",
|
||||
"Esc": "Esc",
|
||||
@@ -47,10 +53,8 @@
|
||||
"Scaling Mode:": "Schaalmodus:",
|
||||
"None": "Geen",
|
||||
"Local Scaling": "Lokaal Schalen",
|
||||
"Local Downscaling": "Lokaal Neerschalen",
|
||||
"Remote Resizing": "Op Afstand Formaat Wijzigen",
|
||||
"Advanced": "Geavanceerd",
|
||||
"Local Cursor": "Lokale Cursor",
|
||||
"Repeater ID:": "Repeater ID:",
|
||||
"WebSocket": "WebSocket",
|
||||
"Encrypt": "Versleutelen",
|
||||
@@ -59,10 +63,11 @@
|
||||
"Path:": "Pad:",
|
||||
"Automatic Reconnect": "Automatisch Opnieuw Verbinden",
|
||||
"Reconnect Delay (ms):": "Vertraging voor Opnieuw Verbinden (ms):",
|
||||
"Show Dot when No Cursor": "Geef stip weer indien geen cursor",
|
||||
"Logging:": "Logmeldingen:",
|
||||
"Disconnect": "Verbinding verbreken",
|
||||
"Connect": "Verbinden",
|
||||
"Password:": "Wachtwoord:",
|
||||
"Cancel": "Annuleren",
|
||||
"Canvas not supported.": "Canvas wordt niet ondersteund."
|
||||
"Send Password": "Verzend Wachtwoord:",
|
||||
"Cancel": "Annuleren"
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"Connecting...": "Conectando...",
|
||||
"Disconnecting...": "Desconectando...",
|
||||
"Reconnecting...": "Reconectando...",
|
||||
"Internal error": "Erro interno",
|
||||
"Must set host": "É necessário definir o host",
|
||||
"Connected (encrypted) to ": "Conectado (com criptografia) a ",
|
||||
"Connected (unencrypted) to ": "Conectado (sem criptografia) a ",
|
||||
"Something went wrong, connection is closed": "Algo deu errado. A conexão foi encerrada.",
|
||||
"Failed to connect to server": "Falha ao conectar-se ao servidor",
|
||||
"Disconnected": "Desconectado",
|
||||
"New connection has been rejected with reason: ": "A nova conexão foi rejeitada pelo motivo: ",
|
||||
"New connection has been rejected": "A nova conexão foi rejeitada",
|
||||
"Credentials are required": "Credenciais são obrigatórias",
|
||||
"noVNC encountered an error:": "O noVNC encontrou um erro:",
|
||||
"Hide/Show the control bar": "Esconder/mostrar a barra de controles",
|
||||
"Drag": "Arrastar",
|
||||
"Move/Drag Viewport": "Mover/arrastar a janela",
|
||||
"Keyboard": "Teclado",
|
||||
"Show Keyboard": "Mostrar teclado",
|
||||
"Extra keys": "Teclas adicionais",
|
||||
"Show Extra Keys": "Mostar teclas adicionais",
|
||||
"Ctrl": "Ctrl",
|
||||
"Toggle Ctrl": "Pressionar/soltar Ctrl",
|
||||
"Alt": "Alt",
|
||||
"Toggle Alt": "Pressionar/soltar Alt",
|
||||
"Toggle Windows": "Pressionar/soltar Windows",
|
||||
"Windows": "Windows",
|
||||
"Send Tab": "Enviar Tab",
|
||||
"Tab": "Tab",
|
||||
"Esc": "Esc",
|
||||
"Send Escape": "Enviar Esc",
|
||||
"Ctrl+Alt+Del": "Ctrl+Alt+Del",
|
||||
"Send Ctrl-Alt-Del": "Enviar Ctrl-Alt-Del",
|
||||
"Shutdown/Reboot": "Desligar/reiniciar",
|
||||
"Shutdown/Reboot...": "Desligar/reiniciar...",
|
||||
"Power": "Ligar",
|
||||
"Shutdown": "Desligar",
|
||||
"Reboot": "Reiniciar",
|
||||
"Reset": "Reiniciar (forçado)",
|
||||
"Clipboard": "Área de transferência",
|
||||
"Clear": "Limpar",
|
||||
"Fullscreen": "Tela cheia",
|
||||
"Settings": "Configurações",
|
||||
"Shared Mode": "Modo compartilhado",
|
||||
"View Only": "Apenas visualizar",
|
||||
"Clip to Window": "Recortar à janela",
|
||||
"Scaling Mode:": "Modo de dimensionamento:",
|
||||
"None": "Nenhum",
|
||||
"Local Scaling": "Local",
|
||||
"Remote Resizing": "Remoto",
|
||||
"Advanced": "Avançado",
|
||||
"Quality:": "Qualidade:",
|
||||
"Compression level:": "Nível de compressão:",
|
||||
"Repeater ID:": "ID do repetidor:",
|
||||
"WebSocket": "WebSocket",
|
||||
"Encrypt": "Criptografar",
|
||||
"Host:": "Host:",
|
||||
"Port:": "Porta:",
|
||||
"Path:": "Caminho:",
|
||||
"Automatic Reconnect": "Reconexão automática",
|
||||
"Reconnect Delay (ms):": "Atraso da reconexão (ms)",
|
||||
"Show Dot when No Cursor": "Mostrar ponto quando não há cursor",
|
||||
"Logging:": "Registros:",
|
||||
"Version:": "Versão:",
|
||||
"Disconnect": "Desconectar",
|
||||
"Connect": "Conectar",
|
||||
"Username:": "Nome de usuário:",
|
||||
"Password:": "Senha:",
|
||||
"Send Credentials": "Enviar credenciais",
|
||||
"Cancel": "Cancelar"
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"Connecting...": "Подключение...",
|
||||
"Disconnecting...": "Отключение...",
|
||||
"Reconnecting...": "Переподключение...",
|
||||
"Internal error": "Внутренняя ошибка",
|
||||
"Must set host": "Задайте имя сервера или IP",
|
||||
"Connected (encrypted) to ": "Подключено (с шифрованием) к ",
|
||||
"Connected (unencrypted) to ": "Подключено (без шифрования) к ",
|
||||
"Something went wrong, connection is closed": "Что-то пошло не так, подключение разорвано",
|
||||
"Failed to connect to server": "Ошибка подключения к серверу",
|
||||
"Disconnected": "Отключено",
|
||||
"New connection has been rejected with reason: ": "Подключиться не удалось: ",
|
||||
"New connection has been rejected": "Подключиться не удалось",
|
||||
"Password is required": "Требуется пароль",
|
||||
"noVNC encountered an error:": "Ошибка noVNC: ",
|
||||
"Hide/Show the control bar": "Скрыть/Показать контрольную панель",
|
||||
"Move/Drag Viewport": "Переместить окно",
|
||||
"viewport drag": "Переместить окно",
|
||||
"Active Mouse Button": "Активировать кнопки мыши",
|
||||
"No mousebutton": "Отключить кнопки мыши",
|
||||
"Left mousebutton": "Левая кнопка мыши",
|
||||
"Middle mousebutton": "Средняя кнопка мыши",
|
||||
"Right mousebutton": "Правая кнопка мыши",
|
||||
"Keyboard": "Клавиатура",
|
||||
"Show Keyboard": "Показать клавиатуру",
|
||||
"Extra keys": "Доп. кнопки",
|
||||
"Show Extra Keys": "Показать дополнительные кнопки",
|
||||
"Ctrl": "Ctrl",
|
||||
"Toggle Ctrl": "Передать нажатие Ctrl",
|
||||
"Alt": "Alt",
|
||||
"Toggle Alt": "Передать нажатие Alt",
|
||||
"Toggle Windows": "Переключение вкладок",
|
||||
"Windows": "Вкладка",
|
||||
"Send Tab": "Передать нажатие Tab",
|
||||
"Tab": "Tab",
|
||||
"Esc": "Esc",
|
||||
"Send Escape": "Передать нажатие Escape",
|
||||
"Ctrl+Alt+Del": "Ctrl+Alt+Del",
|
||||
"Send Ctrl-Alt-Del": "Передать нажатие Ctrl-Alt-Del",
|
||||
"Shutdown/Reboot": "Выключить/Перезагрузить",
|
||||
"Shutdown/Reboot...": "Выключить/Перезагрузить...",
|
||||
"Power": "Питание",
|
||||
"Shutdown": "Выключить",
|
||||
"Reboot": "Перезагрузить",
|
||||
"Reset": "Сброс",
|
||||
"Clipboard": "Буфер обмена",
|
||||
"Clear": "Очистить",
|
||||
"Fullscreen": "Во весь экран",
|
||||
"Settings": "Настройки",
|
||||
"Shared Mode": "Общий режим",
|
||||
"View Only": "Просмотр",
|
||||
"Clip to Window": "В окно",
|
||||
"Scaling Mode:": "Масштаб:",
|
||||
"None": "Нет",
|
||||
"Local Scaling": "Локльный масштаб",
|
||||
"Remote Resizing": "Удаленный масштаб",
|
||||
"Advanced": "Дополнительно",
|
||||
"Repeater ID:": "Идентификатор ID:",
|
||||
"WebSocket": "WebSocket",
|
||||
"Encrypt": "Шифрование",
|
||||
"Host:": "Сервер:",
|
||||
"Port:": "Порт:",
|
||||
"Path:": "Путь:",
|
||||
"Automatic Reconnect": "Автоматическое переподключение",
|
||||
"Reconnect Delay (ms):": "Задержка переподключения (мс):",
|
||||
"Show Dot when No Cursor": "Показать точку вместо курсора",
|
||||
"Logging:": "Лог:",
|
||||
"Disconnect": "Отключение",
|
||||
"Connect": "Подключение",
|
||||
"Password:": "Пароль:",
|
||||
"Send Password": "Пароль: ",
|
||||
"Cancel": "Выход"
|
||||
}
|
||||
+19
-15
@@ -1,22 +1,21 @@
|
||||
{
|
||||
"Connecting...": "Ansluter...",
|
||||
"Disconnecting...": "Kopplar ner...",
|
||||
"Reconnecting...": "Återansluter...",
|
||||
"Internal error": "Internt fel",
|
||||
"Must set host": "Du måste specifiera en värd",
|
||||
"Connected (encrypted) to ": "Ansluten (krypterat) till ",
|
||||
"Connected (unencrypted) to ": "Ansluten (okrypterat) till ",
|
||||
"Disconnecting...": "Kopplar ner...",
|
||||
"Something went wrong, connection is closed": "Något gick fel, anslutningen avslutades",
|
||||
"Failed to connect to server": "Misslyckades att ansluta till servern",
|
||||
"Disconnected": "Frånkopplad",
|
||||
"Must set host": "Du måste specifiera en värd",
|
||||
"Reconnecting...": "Återansluter...",
|
||||
"Password is required": "Lösenord krävs",
|
||||
"Disconnect timeout": "Det tog för lång tid att koppla ner",
|
||||
"New connection has been rejected with reason: ": "Ny anslutning har blivit nekad med följande skäl: ",
|
||||
"New connection has been rejected": "Ny anslutning har blivit nekad",
|
||||
"Credentials are required": "Användaruppgifter krävs",
|
||||
"noVNC encountered an error:": "noVNC stötte på ett problem:",
|
||||
"Hide/Show the control bar": "Göm/Visa kontrollbaren",
|
||||
"Drag": "Dra",
|
||||
"Move/Drag Viewport": "Flytta/Dra Vyn",
|
||||
"viewport drag": "dra vy",
|
||||
"Active Mouse Button": "Aktiv musknapp",
|
||||
"No mousebutton": "Ingen musknapp",
|
||||
"Left mousebutton": "Vänster musknapp",
|
||||
"Middle mousebutton": "Mitten-musknapp",
|
||||
"Right mousebutton": "Höger musknapp",
|
||||
"Keyboard": "Tangentbord",
|
||||
"Show Keyboard": "Visa Tangentbord",
|
||||
"Extra keys": "Extraknappar",
|
||||
@@ -25,6 +24,8 @@
|
||||
"Toggle Ctrl": "Växla Ctrl",
|
||||
"Alt": "Alt",
|
||||
"Toggle Alt": "Växla Alt",
|
||||
"Toggle Windows": "Växla Windows",
|
||||
"Windows": "Windows",
|
||||
"Send Tab": "Skicka Tab",
|
||||
"Tab": "Tab",
|
||||
"Esc": "Esc",
|
||||
@@ -47,10 +48,10 @@
|
||||
"Scaling Mode:": "Skalningsläge:",
|
||||
"None": "Ingen",
|
||||
"Local Scaling": "Lokal Skalning",
|
||||
"Local Downscaling": "Lokal Nedskalning",
|
||||
"Remote Resizing": "Ändra Storlek",
|
||||
"Advanced": "Avancerat",
|
||||
"Local Cursor": "Lokal Muspekare",
|
||||
"Quality:": "Kvalitet:",
|
||||
"Compression level:": "Kompressionsnivå:",
|
||||
"Repeater ID:": "Repeater-ID:",
|
||||
"WebSocket": "WebSocket",
|
||||
"Encrypt": "Kryptera",
|
||||
@@ -59,10 +60,13 @@
|
||||
"Path:": "Sökväg:",
|
||||
"Automatic Reconnect": "Automatisk Återanslutning",
|
||||
"Reconnect Delay (ms):": "Fördröjning (ms):",
|
||||
"Show Dot when No Cursor": "Visa prick när ingen muspekare finns",
|
||||
"Logging:": "Loggning:",
|
||||
"Version:": "Version:",
|
||||
"Disconnect": "Koppla från",
|
||||
"Connect": "Anslut",
|
||||
"Username:": "Användarnamn:",
|
||||
"Password:": "Lösenord:",
|
||||
"Cancel": "Avbryt",
|
||||
"Canvas not supported.": "Canvas stöds ej"
|
||||
"Send Credentials": "Skicka Användaruppgifter",
|
||||
"Cancel": "Avbryt"
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"Connecting...": "Bağlanıyor...",
|
||||
"Disconnecting...": "Bağlantı kesiliyor...",
|
||||
"Reconnecting...": "Yeniden bağlantı kuruluyor...",
|
||||
"Internal error": "İç hata",
|
||||
"Must set host": "Sunucuyu kur",
|
||||
"Connected (encrypted) to ": "Bağlı (şifrelenmiş)",
|
||||
"Connected (unencrypted) to ": "Bağlandı (şifrelenmemiş)",
|
||||
"Something went wrong, connection is closed": "Bir şeyler ters gitti, bağlantı kesildi",
|
||||
"Disconnected": "Bağlantı kesildi",
|
||||
"New connection has been rejected with reason: ": "Bağlantı aşağıdaki nedenlerden dolayı reddedildi: ",
|
||||
"New connection has been rejected": "Bağlantı reddedildi",
|
||||
"Password is required": "Şifre gerekli",
|
||||
"noVNC encountered an error:": "Bir hata oluştu:",
|
||||
"Hide/Show the control bar": "Denetim masasını Gizle/Göster",
|
||||
"Move/Drag Viewport": "Görünümü Taşı/Sürükle",
|
||||
"viewport drag": "Görüntü penceresini sürükle",
|
||||
"Active Mouse Button": "Aktif Fare Düğmesi",
|
||||
"No mousebutton": "Fare düğmesi yok",
|
||||
"Left mousebutton": "Farenin sol düğmesi",
|
||||
"Middle mousebutton": "Farenin orta düğmesi",
|
||||
"Right mousebutton": "Farenin sağ düğmesi",
|
||||
"Keyboard": "Klavye",
|
||||
"Show Keyboard": "Klavye Düzenini Göster",
|
||||
"Extra keys": "Ekstra tuşlar",
|
||||
"Show Extra Keys": "Ekstra tuşları göster",
|
||||
"Ctrl": "Ctrl",
|
||||
"Toggle Ctrl": "Ctrl Değiştir ",
|
||||
"Alt": "Alt",
|
||||
"Toggle Alt": "Alt Değiştir",
|
||||
"Send Tab": "Sekme Gönder",
|
||||
"Tab": "Sekme",
|
||||
"Esc": "Esc",
|
||||
"Send Escape": "Boşluk Gönder",
|
||||
"Ctrl+Alt+Del": "Ctrl + Alt + Del",
|
||||
"Send Ctrl-Alt-Del": "Ctrl-Alt-Del Gönder",
|
||||
"Shutdown/Reboot": "Kapat/Yeniden Başlat",
|
||||
"Shutdown/Reboot...": "Kapat/Yeniden Başlat...",
|
||||
"Power": "Güç",
|
||||
"Shutdown": "Kapat",
|
||||
"Reboot": "Yeniden Başlat",
|
||||
"Reset": "Sıfırla",
|
||||
"Clipboard": "Pano",
|
||||
"Clear": "Temizle",
|
||||
"Fullscreen": "Tam Ekran",
|
||||
"Settings": "Ayarlar",
|
||||
"Shared Mode": "Paylaşım Modu",
|
||||
"View Only": "Sadece Görüntüle",
|
||||
"Clip to Window": "Pencereye Tıkla",
|
||||
"Scaling Mode:": "Ölçekleme Modu:",
|
||||
"None": "Bilinmeyen",
|
||||
"Local Scaling": "Yerel Ölçeklendirme",
|
||||
"Remote Resizing": "Uzaktan Yeniden Boyutlandırma",
|
||||
"Advanced": "Gelişmiş",
|
||||
"Repeater ID:": "Tekralayıcı ID:",
|
||||
"WebSocket": "WebSocket",
|
||||
"Encrypt": "Şifrele",
|
||||
"Host:": "Ana makine:",
|
||||
"Port:": "Port:",
|
||||
"Path:": "Yol:",
|
||||
"Automatic Reconnect": "Otomatik Yeniden Bağlan",
|
||||
"Reconnect Delay (ms):": "Yeniden Bağlanma Süreci (ms):",
|
||||
"Logging:": "Giriş yapılıyor:",
|
||||
"Disconnect": "Bağlantıyı Kes",
|
||||
"Connect": "Bağlan",
|
||||
"Password:": "Parola:",
|
||||
"Cancel": "Vazgeç",
|
||||
"Canvas not supported.": "Tuval desteklenmiyor."
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"Connecting...": "连接中...",
|
||||
"Disconnecting...": "正在断开连接...",
|
||||
"Reconnecting...": "重新连接中...",
|
||||
"Internal error": "内部错误",
|
||||
"Must set host": "请提供主机名",
|
||||
"Connected (encrypted) to ": "已连接到(加密)",
|
||||
"Connected (unencrypted) to ": "已连接到(未加密)",
|
||||
"Something went wrong, connection is closed": "发生错误,连接已关闭",
|
||||
"Failed to connect to server": "无法连接到服务器",
|
||||
"Disconnected": "已断开连接",
|
||||
"New connection has been rejected with reason: ": "连接被拒绝,原因:",
|
||||
"New connection has been rejected": "连接被拒绝",
|
||||
"Password is required": "请提供密码",
|
||||
"noVNC encountered an error:": "noVNC 遇到一个错误:",
|
||||
"Hide/Show the control bar": "显示/隐藏控制栏",
|
||||
"Move/Drag Viewport": "拖放显示范围",
|
||||
"viewport drag": "显示范围拖放",
|
||||
"Active Mouse Button": "启动鼠标按鍵",
|
||||
"No mousebutton": "禁用鼠标按鍵",
|
||||
"Left mousebutton": "鼠标左鍵",
|
||||
"Middle mousebutton": "鼠标中鍵",
|
||||
"Right mousebutton": "鼠标右鍵",
|
||||
"Keyboard": "键盘",
|
||||
"Show Keyboard": "显示键盘",
|
||||
"Extra keys": "额外按键",
|
||||
"Show Extra Keys": "显示额外按键",
|
||||
"Ctrl": "Ctrl",
|
||||
"Toggle Ctrl": "切换 Ctrl",
|
||||
"Alt": "Alt",
|
||||
"Toggle Alt": "切换 Alt",
|
||||
"Send Tab": "发送 Tab 键",
|
||||
"Tab": "Tab",
|
||||
"Esc": "Esc",
|
||||
"Send Escape": "发送 Escape 键",
|
||||
"Ctrl+Alt+Del": "Ctrl-Alt-Del",
|
||||
"Send Ctrl-Alt-Del": "发送 Ctrl-Alt-Del 键",
|
||||
"Shutdown/Reboot": "关机/重新启动",
|
||||
"Shutdown/Reboot...": "关机/重新启动...",
|
||||
"Power": "电源",
|
||||
"Shutdown": "关机",
|
||||
"Reboot": "重新启动",
|
||||
"Reset": "重置",
|
||||
"Clipboard": "剪贴板",
|
||||
"Clear": "清除",
|
||||
"Fullscreen": "全屏",
|
||||
"Settings": "设置",
|
||||
"Shared Mode": "分享模式",
|
||||
"View Only": "仅查看",
|
||||
"Clip to Window": "限制/裁切窗口大小",
|
||||
"Scaling Mode:": "缩放模式:",
|
||||
"None": "无",
|
||||
"Local Scaling": "本地缩放",
|
||||
"Remote Resizing": "远程调整大小",
|
||||
"Advanced": "高级",
|
||||
"Repeater ID:": "中继站 ID",
|
||||
"WebSocket": "WebSocket",
|
||||
"Encrypt": "加密",
|
||||
"Host:": "主机:",
|
||||
"Port:": "端口:",
|
||||
"Path:": "路径:",
|
||||
"Automatic Reconnect": "自动重新连接",
|
||||
"Reconnect Delay (ms):": "重新连接间隔 (ms):",
|
||||
"Logging:": "日志级别:",
|
||||
"Disconnect": "中断连接",
|
||||
"Connect": "连接",
|
||||
"Password:": "密码:",
|
||||
"Cancel": "取消"
|
||||
}
|
||||
+47
-45
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2012 Joel Martin
|
||||
* Copyright (C) 2018 The noVNC Authors
|
||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||
*
|
||||
* See README.md for usage and integration instructions.
|
||||
@@ -10,36 +10,35 @@
|
||||
* Localization Utilities
|
||||
*/
|
||||
|
||||
export function Localizer() {
|
||||
// Currently configured language
|
||||
this.language = 'en';
|
||||
export class Localizer {
|
||||
constructor() {
|
||||
// Currently configured language
|
||||
this.language = 'en';
|
||||
|
||||
// Current dictionary of translations
|
||||
this.dictionary = undefined;
|
||||
}
|
||||
// Current dictionary of translations
|
||||
this.dictionary = undefined;
|
||||
}
|
||||
|
||||
Localizer.prototype = {
|
||||
// Configure suitable language based on user preferences
|
||||
setup: function (supportedLanguages) {
|
||||
var userLanguages;
|
||||
|
||||
setup(supportedLanguages) {
|
||||
this.language = 'en'; // Default: US English
|
||||
|
||||
/*
|
||||
* Navigator.languages only available in Chrome (32+) and FireFox (32+)
|
||||
* Fall back to navigator.language for other browsers
|
||||
*/
|
||||
let userLanguages;
|
||||
if (typeof window.navigator.languages == 'object') {
|
||||
userLanguages = window.navigator.languages;
|
||||
} else {
|
||||
userLanguages = [navigator.language || navigator.userLanguage];
|
||||
}
|
||||
|
||||
for (var i = 0;i < userLanguages.length;i++) {
|
||||
var userLang = userLanguages[i];
|
||||
userLang = userLang.toLowerCase();
|
||||
userLang = userLang.replace("_", "-");
|
||||
userLang = userLang.split("-");
|
||||
for (let i = 0;i < userLanguages.length;i++) {
|
||||
const userLang = userLanguages[i]
|
||||
.toLowerCase()
|
||||
.replace("_", "-")
|
||||
.split("-");
|
||||
|
||||
// Built-in default?
|
||||
if ((userLang[0] === 'en') &&
|
||||
@@ -48,66 +47,69 @@ Localizer.prototype = {
|
||||
}
|
||||
|
||||
// First pass: perfect match
|
||||
for (var j = 0;j < supportedLanguages.length;j++) {
|
||||
var supLang = supportedLanguages[j];
|
||||
supLang = supLang.toLowerCase();
|
||||
supLang = supLang.replace("_", "-");
|
||||
supLang = supLang.split("-");
|
||||
for (let j = 0; j < supportedLanguages.length; j++) {
|
||||
const supLang = supportedLanguages[j]
|
||||
.toLowerCase()
|
||||
.replace("_", "-")
|
||||
.split("-");
|
||||
|
||||
if (userLang[0] !== supLang[0])
|
||||
if (userLang[0] !== supLang[0]) {
|
||||
continue;
|
||||
if (userLang[1] !== supLang[1])
|
||||
}
|
||||
if (userLang[1] !== supLang[1]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this.language = supportedLanguages[j];
|
||||
return;
|
||||
}
|
||||
|
||||
// Second pass: fallback
|
||||
for (var j = 0;j < supportedLanguages.length;j++) {
|
||||
supLang = supportedLanguages[j];
|
||||
supLang = supLang.toLowerCase();
|
||||
supLang = supLang.replace("_", "-");
|
||||
supLang = supLang.split("-");
|
||||
for (let j = 0;j < supportedLanguages.length;j++) {
|
||||
const supLang = supportedLanguages[j]
|
||||
.toLowerCase()
|
||||
.replace("_", "-")
|
||||
.split("-");
|
||||
|
||||
if (userLang[0] !== supLang[0])
|
||||
if (userLang[0] !== supLang[0]) {
|
||||
continue;
|
||||
if (supLang[1] !== undefined)
|
||||
}
|
||||
if (supLang[1] !== undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this.language = supportedLanguages[j];
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// Retrieve localised text
|
||||
get: function (id) {
|
||||
get(id) {
|
||||
if (typeof this.dictionary !== 'undefined' && this.dictionary[id]) {
|
||||
return this.dictionary[id];
|
||||
} else {
|
||||
return id;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// Traverses the DOM and translates relevant fields
|
||||
// See https://html.spec.whatwg.org/multipage/dom.html#attr-translate
|
||||
translateDOM: function () {
|
||||
var self = this;
|
||||
translateDOM() {
|
||||
const self = this;
|
||||
|
||||
function process(elem, enabled) {
|
||||
function isAnyOf(searchElement, items) {
|
||||
return items.indexOf(searchElement) !== -1;
|
||||
}
|
||||
|
||||
function translateAttribute(elem, attr) {
|
||||
var str = elem.getAttribute(attr);
|
||||
str = self.get(str);
|
||||
const str = self.get(elem.getAttribute(attr));
|
||||
elem.setAttribute(attr, str);
|
||||
}
|
||||
|
||||
function translateTextNode(node) {
|
||||
var str = node.data.trim();
|
||||
str = self.get(str);
|
||||
const str = self.get(node.data.trim());
|
||||
node.data = str;
|
||||
}
|
||||
|
||||
@@ -134,7 +136,7 @@ Localizer.prototype = {
|
||||
}
|
||||
if (elem.hasAttribute("label") &&
|
||||
isAnyOf(elem.tagName, ["MENUITEM", "MENU", "OPTGROUP",
|
||||
"OPTION", "TRACK"])) {
|
||||
"OPTION", "TRACK"])) {
|
||||
translateAttribute(elem, "label");
|
||||
}
|
||||
// FIXME: Should update "lang"
|
||||
@@ -152,8 +154,8 @@ Localizer.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0;i < elem.childNodes.length;i++) {
|
||||
var node = elem.childNodes[i];
|
||||
for (let i = 0; i < elem.childNodes.length; i++) {
|
||||
const node = elem.childNodes[i];
|
||||
if (node.nodeType === node.ELEMENT_NODE) {
|
||||
process(node, enabled);
|
||||
} else if (node.nodeType === node.TEXT_NODE && enabled) {
|
||||
@@ -163,8 +165,8 @@ Localizer.prototype = {
|
||||
}
|
||||
|
||||
process(document.body, true);
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export var l10n = new Localizer();
|
||||
export const l10n = new Localizer();
|
||||
export default l10n.get.bind(l10n);
|
||||
|
||||
+87
-19
@@ -1,8 +1,6 @@
|
||||
/*
|
||||
* noVNC base CSS
|
||||
* Copyright (C) 2012 Joel Martin
|
||||
* Copyright (C) 2016 Samuel Mannehed for Cendio AB
|
||||
* Copyright (C) 2016 Pierre Ossman for Cendio AB
|
||||
* Copyright (C) 2019 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).
|
||||
*/
|
||||
@@ -85,8 +83,20 @@ html {
|
||||
* ----------------------------------------
|
||||
*/
|
||||
|
||||
input[type=input], input[type=password], input[type=number],
|
||||
input:not([type]), textarea {
|
||||
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 {
|
||||
/* Disable default rendering */
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
@@ -100,7 +110,11 @@ input:not([type]), textarea {
|
||||
background: linear-gradient(to top, rgb(255, 255, 255) 80%, rgb(240, 240, 240));
|
||||
}
|
||||
|
||||
input[type=button], input[type=submit], select {
|
||||
input[type=button],
|
||||
input[type=color],
|
||||
input[type=reset],
|
||||
input[type=submit],
|
||||
select {
|
||||
/* Disable default rendering */
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
@@ -118,7 +132,10 @@ input[type=button], input[type=submit], select {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
input[type=button], input[type=submit] {
|
||||
input[type=button],
|
||||
input[type=color],
|
||||
input[type=reset],
|
||||
input[type=submit] {
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
@@ -128,35 +145,72 @@ option {
|
||||
background: white;
|
||||
}
|
||||
|
||||
input[type=input]:focus, input[type=password]:focus,
|
||||
input:not([type]):focus, input[type=button]:focus,
|
||||
input:not([type]):focus,
|
||||
input[type=button]:focus,
|
||||
input[type=color]:focus,
|
||||
input[type=date]:focus,
|
||||
input[type=datetime-local]:focus,
|
||||
input[type=email]:focus,
|
||||
input[type=month]:focus,
|
||||
input[type=number]:focus,
|
||||
input[type=password]:focus,
|
||||
input[type=reset]:focus,
|
||||
input[type=search]:focus,
|
||||
input[type=submit]:focus,
|
||||
textarea:focus, select:focus {
|
||||
input[type=tel]:focus,
|
||||
input[type=text]:focus,
|
||||
input[type=time]:focus,
|
||||
input[type=url]:focus,
|
||||
input[type=week]:focus,
|
||||
select:focus,
|
||||
textarea:focus {
|
||||
box-shadow: 0px 0px 3px rgba(74, 144, 217, 0.5);
|
||||
border-color: rgb(74, 144, 217);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
input[type=button]::-moz-focus-inner,
|
||||
input[type=color]::-moz-focus-inner,
|
||||
input[type=reset]::-moz-focus-inner,
|
||||
input[type=submit]::-moz-focus-inner {
|
||||
border: none;
|
||||
}
|
||||
|
||||
input[type=input]:disabled, input[type=password]:disabled,
|
||||
input:not([type]):disabled, input[type=button]:disabled,
|
||||
input[type=submit]:disabled, input[type=number]:disabled,
|
||||
textarea:disabled, select:disabled {
|
||||
input:not([type]):disabled,
|
||||
input[type=button]:disabled,
|
||||
input[type=color]:disabled,
|
||||
input[type=date]:disabled,
|
||||
input[type=datetime-local]:disabled,
|
||||
input[type=email]:disabled,
|
||||
input[type=month]:disabled,
|
||||
input[type=number]:disabled,
|
||||
input[type=password]:disabled,
|
||||
input[type=reset]:disabled,
|
||||
input[type=search]:disabled,
|
||||
input[type=submit]:disabled,
|
||||
input[type=tel]:disabled,
|
||||
input[type=text]:disabled,
|
||||
input[type=time]:disabled,
|
||||
input[type=url]:disabled,
|
||||
input[type=week]:disabled,
|
||||
select:disabled,
|
||||
textarea:disabled {
|
||||
color: rgb(128, 128, 128);
|
||||
background: rgb(240, 240, 240);
|
||||
}
|
||||
|
||||
input[type=button]:active, input[type=submit]:active,
|
||||
input[type=button]:active,
|
||||
input[type=color]:active,
|
||||
input[type=reset]:active,
|
||||
input[type=submit]:active,
|
||||
select:active {
|
||||
border-bottom-width: 1px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
:root:not(.noVNC_touch) input[type=button]:hover:not(:disabled),
|
||||
:root:not(.noVNC_touch) input[type=color]:hover:not(:disabled),
|
||||
:root:not(.noVNC_touch) input[type=reset]:hover:not(:disabled),
|
||||
:root:not(.noVNC_touch) input[type=submit]:hover:not(:disabled),
|
||||
:root:not(.noVNC_touch) select:hover:not(:disabled) {
|
||||
background: linear-gradient(to top, rgb(255, 255, 255), rgb(250, 250, 250));
|
||||
@@ -581,7 +635,7 @@ select:active {
|
||||
}
|
||||
|
||||
/* Extra manual keys */
|
||||
:root:not(.noVNC_connected) #noVNC_extra_keys {
|
||||
:root:not(.noVNC_connected) #noVNC_toggle_extra_keys_button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -633,6 +687,16 @@ select:active {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
/* Version */
|
||||
|
||||
.noVNC_version_wrapper {
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.noVNC_version {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
/* Connection Controls */
|
||||
:root:not(.noVNC_connected) #noVNC_disconnect_button {
|
||||
display: none;
|
||||
@@ -782,19 +846,23 @@ select:active {
|
||||
* ----------------------------------------
|
||||
*/
|
||||
|
||||
#noVNC_password_dlg {
|
||||
#noVNC_credentials_dlg {
|
||||
position: relative;
|
||||
|
||||
transform: translateY(-50px);
|
||||
}
|
||||
#noVNC_password_dlg.noVNC_open {
|
||||
#noVNC_credentials_dlg.noVNC_open {
|
||||
transform: translateY(0);
|
||||
}
|
||||
#noVNC_password_dlg ul {
|
||||
#noVNC_credentials_dlg ul {
|
||||
list-style: none;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
.noVNC_hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------
|
||||
* Main Area
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* noVNC auto CSS
|
||||
* Copyright (C) 2012 Joel Martin
|
||||
* Copyright (C) 2017 Samuel Mannehed for Cendio AB
|
||||
* noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
|
||||
* This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
|
||||
*/
|
||||
|
||||
body {
|
||||
margin:0;
|
||||
background-color:#313131;
|
||||
border-bottom-right-radius: 800px 600px;
|
||||
height:100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
html {
|
||||
background-color:#494949;
|
||||
height:100%;
|
||||
}
|
||||
|
||||
#noVNC_status_bar {
|
||||
width: 100%;
|
||||
display:flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#noVNC_status {
|
||||
color: #fff;
|
||||
font: bold 12px Helvetica;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.noVNC_status_normal {
|
||||
background: linear-gradient(#b2bdcd 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%);
|
||||
}
|
||||
|
||||
.noVNC_status_error {
|
||||
background: linear-gradient(#c83737 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%);
|
||||
}
|
||||
|
||||
.noVNC_status_warn {
|
||||
background: linear-gradient(#b4b41e 0%,#899cb3 49%,#7e93af 51%,#6e84a3 100%);
|
||||
}
|
||||
|
||||
.noNVC_shown {
|
||||
display: inline;
|
||||
}
|
||||
.noVNC_hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#noVNC_left_dummy_elem {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
#noVNC_buttons {
|
||||
padding: 1px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
+89
-133
@@ -1,70 +1,82 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2012 Joel Martin
|
||||
* Copyright (C) 2013 NTT corp.
|
||||
* Copyright (C) 2019 The noVNC Authors
|
||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||
*
|
||||
* See README.md for usage and integration instructions.
|
||||
*/
|
||||
|
||||
import { init_logging as main_init_logging } from '../core/util/logging.js';
|
||||
import { initLogging as mainInitLogging } from '../core/util/logging.js';
|
||||
|
||||
// init log level reading the logging HTTP param
|
||||
export function init_logging (level) {
|
||||
export function initLogging(level) {
|
||||
"use strict";
|
||||
if (typeof level !== "undefined") {
|
||||
main_init_logging(level);
|
||||
mainInitLogging(level);
|
||||
} else {
|
||||
var param = document.location.href.match(/logging=([A-Za-z0-9\._\-]*)/);
|
||||
main_init_logging(param || undefined);
|
||||
const param = document.location.href.match(/logging=([A-Za-z0-9._-]*)/);
|
||||
mainInitLogging(param || undefined);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Read a query string variable
|
||||
export function getQueryVar (name, defVal) {
|
||||
// A URL with a query parameter can look like this (But will most probably get logged on the http server):
|
||||
// https://www.example.com?myqueryparam=myvalue
|
||||
//
|
||||
// For privacy (Using a hastag #, the parameters will not be sent to the server)
|
||||
// the url can be requested in the following way:
|
||||
// https://www.example.com#myqueryparam=myvalue&password=secreatvalue
|
||||
//
|
||||
// Even Mixing public and non public parameters will work:
|
||||
// https://www.example.com?nonsecretparam=example.com#password=secreatvalue
|
||||
export function getQueryVar(name, defVal) {
|
||||
"use strict";
|
||||
var re = new RegExp('.*[?&]' + name + '=([^&#]*)'),
|
||||
match = document.location.href.match(re);
|
||||
const re = new RegExp('.*[?&]' + name + '=([^&#]*)'),
|
||||
match = ''.concat(document.location.href, window.location.hash).match(re);
|
||||
if (typeof defVal === 'undefined') { defVal = null; }
|
||||
|
||||
if (match) {
|
||||
return decodeURIComponent(match[1]);
|
||||
} else {
|
||||
return defVal;
|
||||
}
|
||||
};
|
||||
|
||||
return defVal;
|
||||
}
|
||||
|
||||
// Read a hash fragment variable
|
||||
export function getHashVar (name, defVal) {
|
||||
export function getHashVar(name, defVal) {
|
||||
"use strict";
|
||||
var re = new RegExp('.*[&#]' + name + '=([^&]*)'),
|
||||
const re = new RegExp('.*[&#]' + name + '=([^&]*)'),
|
||||
match = document.location.hash.match(re);
|
||||
if (typeof defVal === 'undefined') { defVal = null; }
|
||||
|
||||
if (match) {
|
||||
return decodeURIComponent(match[1]);
|
||||
} else {
|
||||
return defVal;
|
||||
}
|
||||
};
|
||||
|
||||
return defVal;
|
||||
}
|
||||
|
||||
// Read a variable from the fragment or the query string
|
||||
// Fragment takes precedence
|
||||
export function getConfigVar (name, defVal) {
|
||||
export function getConfigVar(name, defVal) {
|
||||
"use strict";
|
||||
var val = getHashVar(name);
|
||||
const val = getHashVar(name);
|
||||
|
||||
if (val === null) {
|
||||
val = getQueryVar(name, defVal);
|
||||
return getQueryVar(name, defVal);
|
||||
}
|
||||
|
||||
return val;
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Cookie handling. Dervied from: http://www.quirksmode.org/js/cookies.html
|
||||
*/
|
||||
|
||||
// No days means only for this browser session
|
||||
export function createCookie (name, value, days) {
|
||||
export function createCookie(name, value, days) {
|
||||
"use strict";
|
||||
var date, expires;
|
||||
let date, expires;
|
||||
if (days) {
|
||||
date = new Date();
|
||||
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||
@@ -73,158 +85,102 @@ export function createCookie (name, value, days) {
|
||||
expires = "";
|
||||
}
|
||||
|
||||
var secure;
|
||||
let secure;
|
||||
if (document.location.protocol === "https:") {
|
||||
secure = "; secure";
|
||||
} else {
|
||||
secure = "";
|
||||
}
|
||||
document.cookie = name + "=" + value + expires + "; path=/" + secure;
|
||||
};
|
||||
}
|
||||
|
||||
export function readCookie (name, defaultValue) {
|
||||
export function readCookie(name, defaultValue) {
|
||||
"use strict";
|
||||
var nameEQ = name + "=",
|
||||
ca = document.cookie.split(';');
|
||||
const nameEQ = name + "=";
|
||||
const ca = document.cookie.split(';');
|
||||
|
||||
for (var i = 0; i < ca.length; i += 1) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0) === ' ') { c = c.substring(1, c.length); }
|
||||
if (c.indexOf(nameEQ) === 0) { return c.substring(nameEQ.length, c.length); }
|
||||
for (let i = 0; i < ca.length; i += 1) {
|
||||
let c = ca[i];
|
||||
while (c.charAt(0) === ' ') {
|
||||
c = c.substring(1, c.length);
|
||||
}
|
||||
if (c.indexOf(nameEQ) === 0) {
|
||||
return c.substring(nameEQ.length, c.length);
|
||||
}
|
||||
}
|
||||
return (typeof defaultValue !== 'undefined') ? defaultValue : null;
|
||||
};
|
||||
|
||||
export function eraseCookie (name) {
|
||||
return (typeof defaultValue !== 'undefined') ? defaultValue : null;
|
||||
}
|
||||
|
||||
export function eraseCookie(name) {
|
||||
"use strict";
|
||||
createCookie(name, "", -1);
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Setting handling.
|
||||
*/
|
||||
|
||||
var settings = {};
|
||||
let settings = {};
|
||||
|
||||
export function initSettings (callback /*, ...callbackArgs */) {
|
||||
"use strict";
|
||||
var callbackArgs = Array.prototype.slice.call(arguments, 1);
|
||||
if (window.chrome && window.chrome.storage) {
|
||||
window.chrome.storage.sync.get(function (cfg) {
|
||||
settings = cfg;
|
||||
if (callback) {
|
||||
callback.apply(this, callbackArgs);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// No-op
|
||||
if (callback) {
|
||||
callback.apply(this, callbackArgs);
|
||||
}
|
||||
export function initSettings() {
|
||||
if (!window.chrome || !window.chrome.storage) {
|
||||
settings = {};
|
||||
return Promise.resolve();
|
||||
}
|
||||
};
|
||||
|
||||
return new Promise(resolve => window.chrome.storage.sync.get(resolve))
|
||||
.then((cfg) => { settings = cfg; });
|
||||
}
|
||||
|
||||
// Update the settings cache, but do not write to permanent storage
|
||||
export function setSetting(name, value) {
|
||||
settings[name] = value;
|
||||
}
|
||||
|
||||
// No days means only for this browser session
|
||||
export function writeSetting (name, value) {
|
||||
export function writeSetting(name, value) {
|
||||
"use strict";
|
||||
if (settings[name] === value) return;
|
||||
settings[name] = value;
|
||||
if (window.chrome && window.chrome.storage) {
|
||||
if (settings[name] !== value) {
|
||||
settings[name] = value;
|
||||
window.chrome.storage.sync.set(settings);
|
||||
}
|
||||
window.chrome.storage.sync.set(settings);
|
||||
} else {
|
||||
localStorage.setItem(name, value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function readSetting (name, defaultValue) {
|
||||
export function readSetting(name, defaultValue) {
|
||||
"use strict";
|
||||
var value;
|
||||
if (window.chrome && window.chrome.storage) {
|
||||
let value;
|
||||
if ((name in settings) || (window.chrome && window.chrome.storage)) {
|
||||
value = settings[name];
|
||||
} else {
|
||||
value = localStorage.getItem(name);
|
||||
settings[name] = value;
|
||||
}
|
||||
if (typeof value === "undefined") {
|
||||
value = null;
|
||||
}
|
||||
|
||||
if (value === null && typeof defaultValue !== "undefined") {
|
||||
return defaultValue;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
export function eraseSetting (name) {
|
||||
return value;
|
||||
}
|
||||
|
||||
export function eraseSetting(name) {
|
||||
"use strict";
|
||||
// Deleting here means that next time the setting is read when using local
|
||||
// storage, it will be pulled from local storage again.
|
||||
// If the setting in local storage is changed (e.g. in another tab)
|
||||
// between this delete and the next read, it could lead to an unexpected
|
||||
// value change.
|
||||
delete settings[name];
|
||||
if (window.chrome && window.chrome.storage) {
|
||||
window.chrome.storage.sync.remove(name);
|
||||
delete settings[name];
|
||||
} else {
|
||||
localStorage.removeItem(name);
|
||||
}
|
||||
};
|
||||
|
||||
export function injectParamIfMissing (path, param, value) {
|
||||
// force pretend that we're dealing with a relative path
|
||||
// (assume that we wanted an extra if we pass one in)
|
||||
path = "/" + path;
|
||||
|
||||
var elem = document.createElement('a');
|
||||
elem.href = path;
|
||||
|
||||
var param_eq = encodeURIComponent(param) + "=";
|
||||
var query;
|
||||
if (elem.search) {
|
||||
query = elem.search.slice(1).split('&');
|
||||
} else {
|
||||
query = [];
|
||||
}
|
||||
|
||||
if (!query.some(function (v) { return v.startsWith(param_eq); })) {
|
||||
query.push(param_eq + encodeURIComponent(value));
|
||||
elem.search = "?" + query.join("&");
|
||||
}
|
||||
|
||||
// some browsers (e.g. IE11) may occasionally omit the leading slash
|
||||
// in the elem.pathname string. Handle that case gracefully.
|
||||
if (elem.pathname.charAt(0) == "/") {
|
||||
return elem.pathname.slice(1) + elem.search + elem.hash;
|
||||
} else {
|
||||
return elem.pathname + elem.search + elem.hash;
|
||||
}
|
||||
};
|
||||
|
||||
// sadly, we can't use the Fetch API until we decide to drop
|
||||
// IE11 support or polyfill promises and fetch in IE11.
|
||||
// resolve will receive an object on success, while reject
|
||||
// will receive either an event or an error on failure.
|
||||
export function fetchJSON(path, resolve, reject) {
|
||||
// NB: IE11 doesn't support JSON as a responseType
|
||||
var req = new XMLHttpRequest();
|
||||
req.open('GET', path);
|
||||
|
||||
req.onload = function () {
|
||||
if (req.status === 200) {
|
||||
try {
|
||||
var resObj = JSON.parse(req.responseText);
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
resolve(resObj);
|
||||
} else {
|
||||
reject(new Error("XHR got non-200 status while trying to load '" + path + "': " + req.status));
|
||||
}
|
||||
};
|
||||
|
||||
req.onerror = function (evt) {
|
||||
reject(new Error("XHR encountered an error while trying to load '" + path + "': " + evt.message));
|
||||
};
|
||||
|
||||
req.ontimeout = function (evt) {
|
||||
reject(new Error("XHR timed out while trying to load '" + path + "'"));
|
||||
};
|
||||
|
||||
req.send();
|
||||
}
|
||||
|
||||
+35
-41
@@ -8,45 +8,43 @@ import * as Log from './util/logging.js';
|
||||
|
||||
export default {
|
||||
/* Convert data (an array of integers) to a Base64 string. */
|
||||
toBase64Table : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split(''),
|
||||
base64Pad : '=',
|
||||
toBase64Table: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split(''),
|
||||
base64Pad: '=',
|
||||
|
||||
encode: function (data) {
|
||||
encode(data) {
|
||||
"use strict";
|
||||
var result = '';
|
||||
var toBase64Table = this.toBase64Table;
|
||||
var length = data.length;
|
||||
var lengthpad = (length % 3);
|
||||
let result = '';
|
||||
const length = data.length;
|
||||
const lengthpad = (length % 3);
|
||||
// Convert every three bytes to 4 ascii characters.
|
||||
|
||||
for (var i = 0; i < (length - 2); i += 3) {
|
||||
result += toBase64Table[data[i] >> 2];
|
||||
result += toBase64Table[((data[i] & 0x03) << 4) + (data[i + 1] >> 4)];
|
||||
result += toBase64Table[((data[i + 1] & 0x0f) << 2) + (data[i + 2] >> 6)];
|
||||
result += toBase64Table[data[i + 2] & 0x3f];
|
||||
for (let i = 0; i < (length - 2); i += 3) {
|
||||
result += this.toBase64Table[data[i] >> 2];
|
||||
result += this.toBase64Table[((data[i] & 0x03) << 4) + (data[i + 1] >> 4)];
|
||||
result += this.toBase64Table[((data[i + 1] & 0x0f) << 2) + (data[i + 2] >> 6)];
|
||||
result += this.toBase64Table[data[i + 2] & 0x3f];
|
||||
}
|
||||
|
||||
// Convert the remaining 1 or 2 bytes, pad out to 4 characters.
|
||||
var j = 0;
|
||||
const j = length - lengthpad;
|
||||
if (lengthpad === 2) {
|
||||
j = length - lengthpad;
|
||||
result += toBase64Table[data[j] >> 2];
|
||||
result += toBase64Table[((data[j] & 0x03) << 4) + (data[j + 1] >> 4)];
|
||||
result += toBase64Table[(data[j + 1] & 0x0f) << 2];
|
||||
result += toBase64Table[64];
|
||||
result += this.toBase64Table[data[j] >> 2];
|
||||
result += this.toBase64Table[((data[j] & 0x03) << 4) + (data[j + 1] >> 4)];
|
||||
result += this.toBase64Table[(data[j + 1] & 0x0f) << 2];
|
||||
result += this.toBase64Table[64];
|
||||
} else if (lengthpad === 1) {
|
||||
j = length - lengthpad;
|
||||
result += toBase64Table[data[j] >> 2];
|
||||
result += toBase64Table[(data[j] & 0x03) << 4];
|
||||
result += toBase64Table[64];
|
||||
result += toBase64Table[64];
|
||||
result += this.toBase64Table[data[j] >> 2];
|
||||
result += this.toBase64Table[(data[j] & 0x03) << 4];
|
||||
result += this.toBase64Table[64];
|
||||
result += this.toBase64Table[64];
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
/* Convert Base64 data to a string */
|
||||
toBinaryTable : [
|
||||
/* eslint-disable comma-spacing */
|
||||
toBinaryTable: [
|
||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
|
||||
@@ -56,27 +54,23 @@ export default {
|
||||
-1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
|
||||
41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
|
||||
],
|
||||
/* eslint-enable comma-spacing */
|
||||
|
||||
decode: function (data, offset) {
|
||||
"use strict";
|
||||
offset = typeof(offset) !== 'undefined' ? offset : 0;
|
||||
var toBinaryTable = this.toBinaryTable;
|
||||
var base64Pad = this.base64Pad;
|
||||
var result, result_length;
|
||||
var leftbits = 0; // number of bits decoded, but yet to be appended
|
||||
var leftdata = 0; // bits decoded, but yet to be appended
|
||||
var data_length = data.indexOf('=') - offset;
|
||||
|
||||
if (data_length < 0) { data_length = data.length - offset; }
|
||||
decode(data, offset = 0) {
|
||||
let dataLength = data.indexOf('=') - offset;
|
||||
if (dataLength < 0) { dataLength = data.length - offset; }
|
||||
|
||||
/* Every four characters is 3 resulting numbers */
|
||||
result_length = (data_length >> 2) * 3 + Math.floor((data_length % 4) / 1.5);
|
||||
result = new Array(result_length);
|
||||
const resultLength = (dataLength >> 2) * 3 + Math.floor((dataLength % 4) / 1.5);
|
||||
const result = new Array(resultLength);
|
||||
|
||||
// Convert one by one.
|
||||
for (var idx = 0, i = offset; i < data.length; i++) {
|
||||
var c = toBinaryTable[data.charCodeAt(i) & 0x7f];
|
||||
var padding = (data.charAt(i) === base64Pad);
|
||||
|
||||
let leftbits = 0; // number of bits decoded, but yet to be appended
|
||||
let leftdata = 0; // bits decoded, but yet to be appended
|
||||
for (let idx = 0, i = offset; i < data.length; i++) {
|
||||
const c = this.toBinaryTable[data.charCodeAt(i) & 0x7f];
|
||||
const padding = (data.charAt(i) === this.base64Pad);
|
||||
// Skip illegal characters and whitespace
|
||||
if (c === -1) {
|
||||
Log.Error("Illegal character code " + data.charCodeAt(i) + " at position " + i);
|
||||
@@ -100,7 +94,7 @@ export default {
|
||||
|
||||
// If there are any bits left, the base64 string was corrupted
|
||||
if (leftbits) {
|
||||
err = new Error('Corrupted base64 string');
|
||||
const err = new Error('Corrupted base64 string');
|
||||
err.name = 'Base64-Error';
|
||||
throw err;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2019 The noVNC Authors
|
||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||
*
|
||||
* See README.md for usage and integration instructions.
|
||||
*
|
||||
*/
|
||||
|
||||
export default class CopyRectDecoder {
|
||||
decodeRect(x, y, width, height, sock, display, depth) {
|
||||
if (sock.rQwait("COPYRECT", 4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let deltaX = sock.rQshift16();
|
||||
let deltaY = sock.rQshift16();
|
||||
|
||||
if ((width === 0) || (height === 0)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
display.copyImage(deltaX, deltaY, x, y, width, height);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2019 The noVNC Authors
|
||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||
*
|
||||
* See README.md for usage and integration instructions.
|
||||
*
|
||||
*/
|
||||
|
||||
import * as Log from '../util/logging.js';
|
||||
|
||||
export default class HextileDecoder {
|
||||
constructor() {
|
||||
this._tiles = 0;
|
||||
this._lastsubencoding = 0;
|
||||
this._tileBuffer = new Uint8Array(16 * 16 * 4);
|
||||
}
|
||||
|
||||
decodeRect(x, y, width, height, sock, display, depth) {
|
||||
if (this._tiles === 0) {
|
||||
this._tilesX = Math.ceil(width / 16);
|
||||
this._tilesY = Math.ceil(height / 16);
|
||||
this._totalTiles = this._tilesX * this._tilesY;
|
||||
this._tiles = this._totalTiles;
|
||||
}
|
||||
|
||||
while (this._tiles > 0) {
|
||||
let bytes = 1;
|
||||
|
||||
if (sock.rQwait("HEXTILE", bytes)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let rQ = sock.rQ;
|
||||
let rQi = sock.rQi;
|
||||
|
||||
let subencoding = rQ[rQi]; // Peek
|
||||
if (subencoding > 30) { // Raw
|
||||
throw new Error("Illegal hextile subencoding (subencoding: " +
|
||||
subencoding + ")");
|
||||
}
|
||||
|
||||
const currTile = this._totalTiles - this._tiles;
|
||||
const tileX = currTile % this._tilesX;
|
||||
const tileY = Math.floor(currTile / this._tilesX);
|
||||
const tx = x + tileX * 16;
|
||||
const ty = y + tileY * 16;
|
||||
const tw = Math.min(16, (x + width) - tx);
|
||||
const th = Math.min(16, (y + height) - ty);
|
||||
|
||||
// Figure out how much we are expecting
|
||||
if (subencoding & 0x01) { // Raw
|
||||
bytes += tw * th * 4;
|
||||
} else {
|
||||
if (subencoding & 0x02) { // Background
|
||||
bytes += 4;
|
||||
}
|
||||
if (subencoding & 0x04) { // Foreground
|
||||
bytes += 4;
|
||||
}
|
||||
if (subencoding & 0x08) { // AnySubrects
|
||||
bytes++; // Since we aren't shifting it off
|
||||
|
||||
if (sock.rQwait("HEXTILE", bytes)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let subrects = rQ[rQi + bytes - 1]; // Peek
|
||||
if (subencoding & 0x10) { // SubrectsColoured
|
||||
bytes += subrects * (4 + 2);
|
||||
} else {
|
||||
bytes += subrects * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sock.rQwait("HEXTILE", bytes)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We know the encoding and have a whole tile
|
||||
rQi++;
|
||||
if (subencoding === 0) {
|
||||
if (this._lastsubencoding & 0x01) {
|
||||
// Weird: ignore blanks are RAW
|
||||
Log.Debug(" Ignoring blank after RAW");
|
||||
} else {
|
||||
display.fillRect(tx, ty, tw, th, this._background);
|
||||
}
|
||||
} else if (subencoding & 0x01) { // Raw
|
||||
let pixels = tw * th;
|
||||
// Max sure the image is fully opaque
|
||||
for (let i = 0;i < pixels;i++) {
|
||||
rQ[rQi + i * 4 + 3] = 255;
|
||||
}
|
||||
display.blitImage(tx, ty, tw, th, rQ, rQi);
|
||||
rQi += bytes - 1;
|
||||
} else {
|
||||
if (subencoding & 0x02) { // Background
|
||||
this._background = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]];
|
||||
rQi += 4;
|
||||
}
|
||||
if (subencoding & 0x04) { // Foreground
|
||||
this._foreground = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]];
|
||||
rQi += 4;
|
||||
}
|
||||
|
||||
this._startTile(tx, ty, tw, th, this._background);
|
||||
if (subencoding & 0x08) { // AnySubrects
|
||||
let subrects = rQ[rQi];
|
||||
rQi++;
|
||||
|
||||
for (let s = 0; s < subrects; s++) {
|
||||
let color;
|
||||
if (subencoding & 0x10) { // SubrectsColoured
|
||||
color = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]];
|
||||
rQi += 4;
|
||||
} else {
|
||||
color = this._foreground;
|
||||
}
|
||||
const xy = rQ[rQi];
|
||||
rQi++;
|
||||
const sx = (xy >> 4);
|
||||
const sy = (xy & 0x0f);
|
||||
|
||||
const wh = rQ[rQi];
|
||||
rQi++;
|
||||
const sw = (wh >> 4) + 1;
|
||||
const sh = (wh & 0x0f) + 1;
|
||||
|
||||
this._subTile(sx, sy, sw, sh, color);
|
||||
}
|
||||
}
|
||||
this._finishTile(display);
|
||||
}
|
||||
sock.rQi = rQi;
|
||||
this._lastsubencoding = subencoding;
|
||||
this._tiles--;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// start updating a tile
|
||||
_startTile(x, y, width, height, color) {
|
||||
this._tileX = x;
|
||||
this._tileY = y;
|
||||
this._tileW = width;
|
||||
this._tileH = height;
|
||||
|
||||
const red = color[0];
|
||||
const green = color[1];
|
||||
const blue = color[2];
|
||||
|
||||
const data = this._tileBuffer;
|
||||
for (let i = 0; i < width * height * 4; i += 4) {
|
||||
data[i] = red;
|
||||
data[i + 1] = green;
|
||||
data[i + 2] = blue;
|
||||
data[i + 3] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
// update sub-rectangle of the current tile
|
||||
_subTile(x, y, w, h, color) {
|
||||
const red = color[0];
|
||||
const green = color[1];
|
||||
const blue = color[2];
|
||||
const xend = x + w;
|
||||
const yend = y + h;
|
||||
|
||||
const data = this._tileBuffer;
|
||||
const width = this._tileW;
|
||||
for (let j = y; j < yend; j++) {
|
||||
for (let i = x; i < xend; i++) {
|
||||
const p = (i + (j * width)) * 4;
|
||||
data[p] = red;
|
||||
data[p + 1] = green;
|
||||
data[p + 2] = blue;
|
||||
data[p + 3] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// draw the current tile to the screen
|
||||
_finishTile(display) {
|
||||
display.blitImage(this._tileX, this._tileY,
|
||||
this._tileW, this._tileH,
|
||||
this._tileBuffer, 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2019 The noVNC Authors
|
||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||
*
|
||||
* See README.md for usage and integration instructions.
|
||||
*
|
||||
*/
|
||||
|
||||
export default class RawDecoder {
|
||||
constructor() {
|
||||
this._lines = 0;
|
||||
}
|
||||
|
||||
decodeRect(x, y, width, height, sock, display, depth) {
|
||||
if ((width === 0) || (height === 0)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this._lines === 0) {
|
||||
this._lines = height;
|
||||
}
|
||||
|
||||
const pixelSize = depth == 8 ? 1 : 4;
|
||||
const bytesPerLine = width * pixelSize;
|
||||
|
||||
if (sock.rQwait("RAW", bytesPerLine)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const curY = y + (height - this._lines);
|
||||
const currHeight = Math.min(this._lines,
|
||||
Math.floor(sock.rQlen / bytesPerLine));
|
||||
const pixels = width * currHeight;
|
||||
|
||||
let data = sock.rQ;
|
||||
let index = sock.rQi;
|
||||
|
||||
// Convert data if needed
|
||||
if (depth == 8) {
|
||||
const newdata = new Uint8Array(pixels * 4);
|
||||
for (let i = 0; i < pixels; i++) {
|
||||
newdata[i * 4 + 0] = ((data[index + i] >> 0) & 0x3) * 255 / 3;
|
||||
newdata[i * 4 + 1] = ((data[index + i] >> 2) & 0x3) * 255 / 3;
|
||||
newdata[i * 4 + 2] = ((data[index + i] >> 4) & 0x3) * 255 / 3;
|
||||
newdata[i * 4 + 3] = 255;
|
||||
}
|
||||
data = newdata;
|
||||
index = 0;
|
||||
}
|
||||
|
||||
// Max sure the image is fully opaque
|
||||
for (let i = 0; i < pixels; i++) {
|
||||
data[i * 4 + 3] = 255;
|
||||
}
|
||||
|
||||
display.blitImage(x, curY, width, currHeight, data, index);
|
||||
sock.rQskipBytes(currHeight * bytesPerLine);
|
||||
this._lines -= currHeight;
|
||||
if (this._lines > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2019 The noVNC Authors
|
||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||
*
|
||||
* See README.md for usage and integration instructions.
|
||||
*
|
||||
*/
|
||||
|
||||
export default class RREDecoder {
|
||||
constructor() {
|
||||
this._subrects = 0;
|
||||
}
|
||||
|
||||
decodeRect(x, y, width, height, sock, display, depth) {
|
||||
if (this._subrects === 0) {
|
||||
if (sock.rQwait("RRE", 4 + 4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this._subrects = sock.rQshift32();
|
||||
|
||||
let color = sock.rQshiftBytes(4); // Background
|
||||
display.fillRect(x, y, width, height, color);
|
||||
}
|
||||
|
||||
while (this._subrects > 0) {
|
||||
if (sock.rQwait("RRE", 4 + 8)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let color = sock.rQshiftBytes(4);
|
||||
let sx = sock.rQshift16();
|
||||
let sy = sock.rQshift16();
|
||||
let swidth = sock.rQshift16();
|
||||
let sheight = sock.rQshift16();
|
||||
display.fillRect(x + sx, y + sy, swidth, sheight, color);
|
||||
|
||||
this._subrects--;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2019 The noVNC Authors
|
||||
* (c) 2012 Michael Tinglof, Joe Balaz, Les Piech (Mercuri.ca)
|
||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||
*
|
||||
* See README.md for usage and integration instructions.
|
||||
*
|
||||
*/
|
||||
|
||||
import * as Log from '../util/logging.js';
|
||||
import Inflator from "../inflator.js";
|
||||
|
||||
export default class TightDecoder {
|
||||
constructor() {
|
||||
this._ctl = null;
|
||||
this._filter = null;
|
||||
this._numColors = 0;
|
||||
this._palette = new Uint8Array(1024); // 256 * 4 (max palette size * max bytes-per-pixel)
|
||||
this._len = 0;
|
||||
|
||||
this._zlibs = [];
|
||||
for (let i = 0; i < 4; i++) {
|
||||
this._zlibs[i] = new Inflator();
|
||||
}
|
||||
}
|
||||
|
||||
decodeRect(x, y, width, height, sock, display, depth) {
|
||||
if (this._ctl === null) {
|
||||
if (sock.rQwait("TIGHT compression-control", 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this._ctl = sock.rQshift8();
|
||||
|
||||
// Reset streams if the server requests it
|
||||
for (let i = 0; i < 4; i++) {
|
||||
if ((this._ctl >> i) & 1) {
|
||||
this._zlibs[i].reset();
|
||||
Log.Info("Reset zlib stream " + i);
|
||||
}
|
||||
}
|
||||
|
||||
// Figure out filter
|
||||
this._ctl = this._ctl >> 4;
|
||||
}
|
||||
|
||||
let ret;
|
||||
|
||||
if (this._ctl === 0x08) {
|
||||
ret = this._fillRect(x, y, width, height,
|
||||
sock, display, depth);
|
||||
} else if (this._ctl === 0x09) {
|
||||
ret = this._jpegRect(x, y, width, height,
|
||||
sock, display, depth);
|
||||
} else if (this._ctl === 0x0A) {
|
||||
ret = this._pngRect(x, y, width, height,
|
||||
sock, display, depth);
|
||||
} else if ((this._ctl & 0x08) == 0) {
|
||||
ret = this._basicRect(this._ctl, x, y, width, height,
|
||||
sock, display, depth);
|
||||
} else {
|
||||
throw new Error("Illegal tight compression received (ctl: " +
|
||||
this._ctl + ")");
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
this._ctl = null;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
_fillRect(x, y, width, height, sock, display, depth) {
|
||||
if (sock.rQwait("TIGHT", 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const rQi = sock.rQi;
|
||||
const rQ = sock.rQ;
|
||||
|
||||
display.fillRect(x, y, width, height,
|
||||
[rQ[rQi], rQ[rQi + 1], rQ[rQi + 2]], false);
|
||||
sock.rQskipBytes(3);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_jpegRect(x, y, width, height, sock, display, depth) {
|
||||
let data = this._readData(sock);
|
||||
if (data === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
display.imageRect(x, y, width, height, "image/jpeg", data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_pngRect(x, y, width, height, sock, display, depth) {
|
||||
throw new Error("PNG received in standard Tight rect");
|
||||
}
|
||||
|
||||
_basicRect(ctl, x, y, width, height, sock, display, depth) {
|
||||
if (this._filter === null) {
|
||||
if (ctl & 0x4) {
|
||||
if (sock.rQwait("TIGHT", 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this._filter = sock.rQshift8();
|
||||
} else {
|
||||
// Implicit CopyFilter
|
||||
this._filter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
let streamId = ctl & 0x3;
|
||||
|
||||
let ret;
|
||||
|
||||
switch (this._filter) {
|
||||
case 0: // CopyFilter
|
||||
ret = this._copyFilter(streamId, x, y, width, height,
|
||||
sock, display, depth);
|
||||
break;
|
||||
case 1: // PaletteFilter
|
||||
ret = this._paletteFilter(streamId, x, y, width, height,
|
||||
sock, display, depth);
|
||||
break;
|
||||
case 2: // GradientFilter
|
||||
ret = this._gradientFilter(streamId, x, y, width, height,
|
||||
sock, display, depth);
|
||||
break;
|
||||
default:
|
||||
throw new Error("Illegal tight filter received (ctl: " +
|
||||
this._filter + ")");
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
this._filter = null;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
_copyFilter(streamId, x, y, width, height, sock, display, depth) {
|
||||
const uncompressedSize = width * height * 3;
|
||||
let data;
|
||||
|
||||
if (uncompressedSize === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (uncompressedSize < 12) {
|
||||
if (sock.rQwait("TIGHT", uncompressedSize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
data = sock.rQshiftBytes(uncompressedSize);
|
||||
} else {
|
||||
data = this._readData(sock);
|
||||
if (data === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this._zlibs[streamId].setInput(data);
|
||||
data = this._zlibs[streamId].inflate(uncompressedSize);
|
||||
this._zlibs[streamId].setInput(null);
|
||||
}
|
||||
|
||||
let rgbx = new Uint8Array(width * height * 4);
|
||||
for (let i = 0, j = 0; i < width * height * 4; i += 4, j += 3) {
|
||||
rgbx[i] = data[j];
|
||||
rgbx[i + 1] = data[j + 1];
|
||||
rgbx[i + 2] = data[j + 2];
|
||||
rgbx[i + 3] = 255; // Alpha
|
||||
}
|
||||
|
||||
display.blitImage(x, y, width, height, rgbx, 0, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_paletteFilter(streamId, x, y, width, height, sock, display, depth) {
|
||||
if (this._numColors === 0) {
|
||||
if (sock.rQwait("TIGHT palette", 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const numColors = sock.rQpeek8() + 1;
|
||||
const paletteSize = numColors * 3;
|
||||
|
||||
if (sock.rQwait("TIGHT palette", 1 + paletteSize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this._numColors = numColors;
|
||||
sock.rQskipBytes(1);
|
||||
|
||||
sock.rQshiftTo(this._palette, paletteSize);
|
||||
}
|
||||
|
||||
const bpp = (this._numColors <= 2) ? 1 : 8;
|
||||
const rowSize = Math.floor((width * bpp + 7) / 8);
|
||||
const uncompressedSize = rowSize * height;
|
||||
|
||||
let data;
|
||||
|
||||
if (uncompressedSize === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (uncompressedSize < 12) {
|
||||
if (sock.rQwait("TIGHT", uncompressedSize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
data = sock.rQshiftBytes(uncompressedSize);
|
||||
} else {
|
||||
data = this._readData(sock);
|
||||
if (data === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this._zlibs[streamId].setInput(data);
|
||||
data = this._zlibs[streamId].inflate(uncompressedSize);
|
||||
this._zlibs[streamId].setInput(null);
|
||||
}
|
||||
|
||||
// Convert indexed (palette based) image data to RGB
|
||||
if (this._numColors == 2) {
|
||||
this._monoRect(x, y, width, height, data, this._palette, display);
|
||||
} else {
|
||||
this._paletteRect(x, y, width, height, data, this._palette, display);
|
||||
}
|
||||
|
||||
this._numColors = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_monoRect(x, y, width, height, data, palette, display) {
|
||||
// Convert indexed (palette based) image data to RGB
|
||||
// TODO: reduce number of calculations inside loop
|
||||
const dest = this._getScratchBuffer(width * height * 4);
|
||||
const w = Math.floor((width + 7) / 8);
|
||||
const w1 = Math.floor(width / 8);
|
||||
|
||||
for (let y = 0; y < height; y++) {
|
||||
let dp, sp, x;
|
||||
for (x = 0; x < w1; x++) {
|
||||
for (let b = 7; b >= 0; b--) {
|
||||
dp = (y * width + x * 8 + 7 - b) * 4;
|
||||
sp = (data[y * w + x] >> b & 1) * 3;
|
||||
dest[dp] = palette[sp];
|
||||
dest[dp + 1] = palette[sp + 1];
|
||||
dest[dp + 2] = palette[sp + 2];
|
||||
dest[dp + 3] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
for (let b = 7; b >= 8 - width % 8; b--) {
|
||||
dp = (y * width + x * 8 + 7 - b) * 4;
|
||||
sp = (data[y * w + x] >> b & 1) * 3;
|
||||
dest[dp] = palette[sp];
|
||||
dest[dp + 1] = palette[sp + 1];
|
||||
dest[dp + 2] = palette[sp + 2];
|
||||
dest[dp + 3] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
display.blitImage(x, y, width, height, dest, 0, false);
|
||||
}
|
||||
|
||||
_paletteRect(x, y, width, height, data, palette, display) {
|
||||
// Convert indexed (palette based) image data to RGB
|
||||
const dest = this._getScratchBuffer(width * height * 4);
|
||||
const total = width * height * 4;
|
||||
for (let i = 0, j = 0; i < total; i += 4, j++) {
|
||||
const sp = data[j] * 3;
|
||||
dest[i] = palette[sp];
|
||||
dest[i + 1] = palette[sp + 1];
|
||||
dest[i + 2] = palette[sp + 2];
|
||||
dest[i + 3] = 255;
|
||||
}
|
||||
|
||||
display.blitImage(x, y, width, height, dest, 0, false);
|
||||
}
|
||||
|
||||
_gradientFilter(streamId, x, y, width, height, sock, display, depth) {
|
||||
throw new Error("Gradient filter not implemented");
|
||||
}
|
||||
|
||||
_readData(sock) {
|
||||
if (this._len === 0) {
|
||||
if (sock.rQwait("TIGHT", 3)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let byte;
|
||||
|
||||
byte = sock.rQshift8();
|
||||
this._len = byte & 0x7f;
|
||||
if (byte & 0x80) {
|
||||
byte = sock.rQshift8();
|
||||
this._len |= (byte & 0x7f) << 7;
|
||||
if (byte & 0x80) {
|
||||
byte = sock.rQshift8();
|
||||
this._len |= byte << 14;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sock.rQwait("TIGHT", this._len)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let data = sock.rQshiftBytes(this._len);
|
||||
this._len = 0;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
_getScratchBuffer(size) {
|
||||
if (!this._scratchBuffer || (this._scratchBuffer.length < size)) {
|
||||
this._scratchBuffer = new Uint8Array(size);
|
||||
}
|
||||
return this._scratchBuffer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2019 The noVNC Authors
|
||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||
*
|
||||
* See README.md for usage and integration instructions.
|
||||
*
|
||||
*/
|
||||
|
||||
import TightDecoder from './tight.js';
|
||||
|
||||
export default class TightPNGDecoder extends TightDecoder {
|
||||
_pngRect(x, y, width, height, sock, display, depth) {
|
||||
let data = this._readData(sock);
|
||||
if (data === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
display.imageRect(x, y, width, height, "image/png", data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_basicRect(ctl, x, y, width, height, sock, display, depth) {
|
||||
throw new Error("BasicCompression received in TightPNG rect");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2020 The noVNC Authors
|
||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||
*
|
||||
* See README.md for usage and integration instructions.
|
||||
*/
|
||||
|
||||
import { deflateInit, deflate } from "../vendor/pako/lib/zlib/deflate.js";
|
||||
import { Z_FULL_FLUSH } from "../vendor/pako/lib/zlib/deflate.js";
|
||||
import ZStream from "../vendor/pako/lib/zlib/zstream.js";
|
||||
|
||||
export default class Deflator {
|
||||
constructor() {
|
||||
this.strm = new ZStream();
|
||||
this.chunkSize = 1024 * 10 * 10;
|
||||
this.outputBuffer = new Uint8Array(this.chunkSize);
|
||||
this.windowBits = 5;
|
||||
|
||||
deflateInit(this.strm, this.windowBits);
|
||||
}
|
||||
|
||||
deflate(inData) {
|
||||
/* eslint-disable camelcase */
|
||||
this.strm.input = inData;
|
||||
this.strm.avail_in = this.strm.input.length;
|
||||
this.strm.next_in = 0;
|
||||
this.strm.output = this.outputBuffer;
|
||||
this.strm.avail_out = this.chunkSize;
|
||||
this.strm.next_out = 0;
|
||||
/* eslint-enable camelcase */
|
||||
|
||||
let lastRet = deflate(this.strm, Z_FULL_FLUSH);
|
||||
let outData = new Uint8Array(this.strm.output.buffer, 0, this.strm.next_out);
|
||||
|
||||
if (lastRet < 0) {
|
||||
throw new Error("zlib deflate failed");
|
||||
}
|
||||
|
||||
if (this.strm.avail_in > 0) {
|
||||
// Read chunks until done
|
||||
|
||||
let chunks = [outData];
|
||||
let totalLen = outData.length;
|
||||
do {
|
||||
/* eslint-disable camelcase */
|
||||
this.strm.output = new Uint8Array(this.chunkSize);
|
||||
this.strm.next_out = 0;
|
||||
this.strm.avail_out = this.chunkSize;
|
||||
/* eslint-enable camelcase */
|
||||
|
||||
lastRet = deflate(this.strm, Z_FULL_FLUSH);
|
||||
|
||||
if (lastRet < 0) {
|
||||
throw new Error("zlib deflate failed");
|
||||
}
|
||||
|
||||
let chunk = new Uint8Array(this.strm.output.buffer, 0, this.strm.next_out);
|
||||
totalLen += chunk.length;
|
||||
chunks.push(chunk);
|
||||
} while (this.strm.avail_in > 0);
|
||||
|
||||
// Combine chunks into a single data
|
||||
|
||||
let newData = new Uint8Array(totalLen);
|
||||
let offset = 0;
|
||||
|
||||
for (let i = 0; i < chunks.length; i++) {
|
||||
newData.set(chunks[i], offset);
|
||||
offset += chunks[i].length;
|
||||
}
|
||||
|
||||
outData = newData;
|
||||
}
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
this.strm.input = null;
|
||||
this.strm.avail_in = 0;
|
||||
this.strm.next_in = 0;
|
||||
/* eslint-enable camelcase */
|
||||
|
||||
return outData;
|
||||
}
|
||||
|
||||
}
|
||||
+90
-95
@@ -75,84 +75,83 @@
|
||||
* fine Java utilities: http://www.acme.com/java/
|
||||
*/
|
||||
|
||||
export default function DES(passwd) {
|
||||
"use strict";
|
||||
/* eslint-disable comma-spacing */
|
||||
|
||||
// Tables, permutations, S-boxes, etc.
|
||||
var PC2 = [13,16,10,23, 0, 4, 2,27,14, 5,20, 9,22,18,11, 3,
|
||||
25, 7,15, 6,26,19,12, 1,40,51,30,36,46,54,29,39,
|
||||
50,44,32,47,43,48,38,55,33,52,45,41,49,35,28,31 ],
|
||||
totrot = [ 1, 2, 4, 6, 8,10,12,14,15,17,19,21,23,25,27,28],
|
||||
z = 0x0, a,b,c,d,e,f, SP1,SP2,SP3,SP4,SP5,SP6,SP7,SP8,
|
||||
keys = [];
|
||||
// Tables, permutations, S-boxes, etc.
|
||||
const PC2 = [13,16,10,23, 0, 4, 2,27,14, 5,20, 9,22,18,11, 3,
|
||||
25, 7,15, 6,26,19,12, 1,40,51,30,36,46,54,29,39,
|
||||
50,44,32,47,43,48,38,55,33,52,45,41,49,35,28,31 ],
|
||||
totrot = [ 1, 2, 4, 6, 8,10,12,14,15,17,19,21,23,25,27,28];
|
||||
|
||||
a=1<<16; b=1<<24; c=a|b; d=1<<2; e=1<<10; f=d|e;
|
||||
SP1 = [c|e,z|z,a|z,c|f,c|d,a|f,z|d,a|z,z|e,c|e,c|f,z|e,b|f,c|d,b|z,z|d,
|
||||
z|f,b|e,b|e,a|e,a|e,c|z,c|z,b|f,a|d,b|d,b|d,a|d,z|z,z|f,a|f,b|z,
|
||||
a|z,c|f,z|d,c|z,c|e,b|z,b|z,z|e,c|d,a|z,a|e,b|d,z|e,z|d,b|f,a|f,
|
||||
c|f,a|d,c|z,b|f,b|d,z|f,a|f,c|e,z|f,b|e,b|e,z|z,a|d,a|e,z|z,c|d];
|
||||
a=1<<20; b=1<<31; c=a|b; d=1<<5; e=1<<15; f=d|e;
|
||||
SP2 = [c|f,b|e,z|e,a|f,a|z,z|d,c|d,b|f,b|d,c|f,c|e,b|z,b|e,a|z,z|d,c|d,
|
||||
a|e,a|d,b|f,z|z,b|z,z|e,a|f,c|z,a|d,b|d,z|z,a|e,z|f,c|e,c|z,z|f,
|
||||
z|z,a|f,c|d,a|z,b|f,c|z,c|e,z|e,c|z,b|e,z|d,c|f,a|f,z|d,z|e,b|z,
|
||||
z|f,c|e,a|z,b|d,a|d,b|f,b|d,a|d,a|e,z|z,b|e,z|f,b|z,c|d,c|f,a|e];
|
||||
a=1<<17; b=1<<27; c=a|b; d=1<<3; e=1<<9; f=d|e;
|
||||
SP3 = [z|f,c|e,z|z,c|d,b|e,z|z,a|f,b|e,a|d,b|d,b|d,a|z,c|f,a|d,c|z,z|f,
|
||||
b|z,z|d,c|e,z|e,a|e,c|z,c|d,a|f,b|f,a|e,a|z,b|f,z|d,c|f,z|e,b|z,
|
||||
c|e,b|z,a|d,z|f,a|z,c|e,b|e,z|z,z|e,a|d,c|f,b|e,b|d,z|e,z|z,c|d,
|
||||
b|f,a|z,b|z,c|f,z|d,a|f,a|e,b|d,c|z,b|f,z|f,c|z,a|f,z|d,c|d,a|e];
|
||||
a=1<<13; b=1<<23; c=a|b; d=1<<0; e=1<<7; f=d|e;
|
||||
SP4 = [c|d,a|f,a|f,z|e,c|e,b|f,b|d,a|d,z|z,c|z,c|z,c|f,z|f,z|z,b|e,b|d,
|
||||
z|d,a|z,b|z,c|d,z|e,b|z,a|d,a|e,b|f,z|d,a|e,b|e,a|z,c|e,c|f,z|f,
|
||||
b|e,b|d,c|z,c|f,z|f,z|z,z|z,c|z,a|e,b|e,b|f,z|d,c|d,a|f,a|f,z|e,
|
||||
c|f,z|f,z|d,a|z,b|d,a|d,c|e,b|f,a|d,a|e,b|z,c|d,z|e,b|z,a|z,c|e];
|
||||
a=1<<25; b=1<<30; c=a|b; d=1<<8; e=1<<19; f=d|e;
|
||||
SP5 = [z|d,a|f,a|e,c|d,z|e,z|d,b|z,a|e,b|f,z|e,a|d,b|f,c|d,c|e,z|f,b|z,
|
||||
a|z,b|e,b|e,z|z,b|d,c|f,c|f,a|d,c|e,b|d,z|z,c|z,a|f,a|z,c|z,z|f,
|
||||
z|e,c|d,z|d,a|z,b|z,a|e,c|d,b|f,a|d,b|z,c|e,a|f,b|f,z|d,a|z,c|e,
|
||||
c|f,z|f,c|z,c|f,a|e,z|z,b|e,c|z,z|f,a|d,b|d,z|e,z|z,b|e,a|f,b|d];
|
||||
a=1<<22; b=1<<29; c=a|b; d=1<<4; e=1<<14; f=d|e;
|
||||
SP6 = [b|d,c|z,z|e,c|f,c|z,z|d,c|f,a|z,b|e,a|f,a|z,b|d,a|d,b|e,b|z,z|f,
|
||||
z|z,a|d,b|f,z|e,a|e,b|f,z|d,c|d,c|d,z|z,a|f,c|e,z|f,a|e,c|e,b|z,
|
||||
b|e,z|d,c|d,a|e,c|f,a|z,z|f,b|d,a|z,b|e,b|z,z|f,b|d,c|f,a|e,c|z,
|
||||
a|f,c|e,z|z,c|d,z|d,z|e,c|z,a|f,z|e,a|d,b|f,z|z,c|e,b|z,a|d,b|f];
|
||||
a=1<<21; b=1<<26; c=a|b; d=1<<1; e=1<<11; f=d|e;
|
||||
SP7 = [a|z,c|d,b|f,z|z,z|e,b|f,a|f,c|e,c|f,a|z,z|z,b|d,z|d,b|z,c|d,z|f,
|
||||
b|e,a|f,a|d,b|e,b|d,c|z,c|e,a|d,c|z,z|e,z|f,c|f,a|e,z|d,b|z,a|e,
|
||||
b|z,a|e,a|z,b|f,b|f,c|d,c|d,z|d,a|d,b|z,b|e,a|z,c|e,z|f,a|f,c|e,
|
||||
z|f,b|d,c|f,c|z,a|e,z|z,z|d,c|f,z|z,a|f,c|z,z|e,b|d,b|e,z|e,a|d];
|
||||
a=1<<18; b=1<<28; c=a|b; d=1<<6; e=1<<12; f=d|e;
|
||||
SP8 = [b|f,z|e,a|z,c|f,b|z,b|f,z|d,b|z,a|d,c|z,c|f,a|e,c|e,a|f,z|e,z|d,
|
||||
c|z,b|d,b|e,z|f,a|e,a|d,c|d,c|e,z|f,z|z,z|z,c|d,b|d,b|e,a|f,a|z,
|
||||
a|f,a|z,c|e,z|e,z|d,c|d,z|e,a|f,b|e,z|d,b|d,c|z,c|d,b|z,a|z,b|f,
|
||||
z|z,c|f,a|d,b|d,c|z,b|e,b|f,z|z,c|f,a|e,a|e,z|f,z|f,a|d,b|z,c|e];
|
||||
const z = 0x0;
|
||||
let a,b,c,d,e,f;
|
||||
a=1<<16; b=1<<24; c=a|b; d=1<<2; e=1<<10; f=d|e;
|
||||
const SP1 = [c|e,z|z,a|z,c|f,c|d,a|f,z|d,a|z,z|e,c|e,c|f,z|e,b|f,c|d,b|z,z|d,
|
||||
z|f,b|e,b|e,a|e,a|e,c|z,c|z,b|f,a|d,b|d,b|d,a|d,z|z,z|f,a|f,b|z,
|
||||
a|z,c|f,z|d,c|z,c|e,b|z,b|z,z|e,c|d,a|z,a|e,b|d,z|e,z|d,b|f,a|f,
|
||||
c|f,a|d,c|z,b|f,b|d,z|f,a|f,c|e,z|f,b|e,b|e,z|z,a|d,a|e,z|z,c|d];
|
||||
a=1<<20; b=1<<31; c=a|b; d=1<<5; e=1<<15; f=d|e;
|
||||
const SP2 = [c|f,b|e,z|e,a|f,a|z,z|d,c|d,b|f,b|d,c|f,c|e,b|z,b|e,a|z,z|d,c|d,
|
||||
a|e,a|d,b|f,z|z,b|z,z|e,a|f,c|z,a|d,b|d,z|z,a|e,z|f,c|e,c|z,z|f,
|
||||
z|z,a|f,c|d,a|z,b|f,c|z,c|e,z|e,c|z,b|e,z|d,c|f,a|f,z|d,z|e,b|z,
|
||||
z|f,c|e,a|z,b|d,a|d,b|f,b|d,a|d,a|e,z|z,b|e,z|f,b|z,c|d,c|f,a|e];
|
||||
a=1<<17; b=1<<27; c=a|b; d=1<<3; e=1<<9; f=d|e;
|
||||
const SP3 = [z|f,c|e,z|z,c|d,b|e,z|z,a|f,b|e,a|d,b|d,b|d,a|z,c|f,a|d,c|z,z|f,
|
||||
b|z,z|d,c|e,z|e,a|e,c|z,c|d,a|f,b|f,a|e,a|z,b|f,z|d,c|f,z|e,b|z,
|
||||
c|e,b|z,a|d,z|f,a|z,c|e,b|e,z|z,z|e,a|d,c|f,b|e,b|d,z|e,z|z,c|d,
|
||||
b|f,a|z,b|z,c|f,z|d,a|f,a|e,b|d,c|z,b|f,z|f,c|z,a|f,z|d,c|d,a|e];
|
||||
a=1<<13; b=1<<23; c=a|b; d=1<<0; e=1<<7; f=d|e;
|
||||
const SP4 = [c|d,a|f,a|f,z|e,c|e,b|f,b|d,a|d,z|z,c|z,c|z,c|f,z|f,z|z,b|e,b|d,
|
||||
z|d,a|z,b|z,c|d,z|e,b|z,a|d,a|e,b|f,z|d,a|e,b|e,a|z,c|e,c|f,z|f,
|
||||
b|e,b|d,c|z,c|f,z|f,z|z,z|z,c|z,a|e,b|e,b|f,z|d,c|d,a|f,a|f,z|e,
|
||||
c|f,z|f,z|d,a|z,b|d,a|d,c|e,b|f,a|d,a|e,b|z,c|d,z|e,b|z,a|z,c|e];
|
||||
a=1<<25; b=1<<30; c=a|b; d=1<<8; e=1<<19; f=d|e;
|
||||
const SP5 = [z|d,a|f,a|e,c|d,z|e,z|d,b|z,a|e,b|f,z|e,a|d,b|f,c|d,c|e,z|f,b|z,
|
||||
a|z,b|e,b|e,z|z,b|d,c|f,c|f,a|d,c|e,b|d,z|z,c|z,a|f,a|z,c|z,z|f,
|
||||
z|e,c|d,z|d,a|z,b|z,a|e,c|d,b|f,a|d,b|z,c|e,a|f,b|f,z|d,a|z,c|e,
|
||||
c|f,z|f,c|z,c|f,a|e,z|z,b|e,c|z,z|f,a|d,b|d,z|e,z|z,b|e,a|f,b|d];
|
||||
a=1<<22; b=1<<29; c=a|b; d=1<<4; e=1<<14; f=d|e;
|
||||
const SP6 = [b|d,c|z,z|e,c|f,c|z,z|d,c|f,a|z,b|e,a|f,a|z,b|d,a|d,b|e,b|z,z|f,
|
||||
z|z,a|d,b|f,z|e,a|e,b|f,z|d,c|d,c|d,z|z,a|f,c|e,z|f,a|e,c|e,b|z,
|
||||
b|e,z|d,c|d,a|e,c|f,a|z,z|f,b|d,a|z,b|e,b|z,z|f,b|d,c|f,a|e,c|z,
|
||||
a|f,c|e,z|z,c|d,z|d,z|e,c|z,a|f,z|e,a|d,b|f,z|z,c|e,b|z,a|d,b|f];
|
||||
a=1<<21; b=1<<26; c=a|b; d=1<<1; e=1<<11; f=d|e;
|
||||
const SP7 = [a|z,c|d,b|f,z|z,z|e,b|f,a|f,c|e,c|f,a|z,z|z,b|d,z|d,b|z,c|d,z|f,
|
||||
b|e,a|f,a|d,b|e,b|d,c|z,c|e,a|d,c|z,z|e,z|f,c|f,a|e,z|d,b|z,a|e,
|
||||
b|z,a|e,a|z,b|f,b|f,c|d,c|d,z|d,a|d,b|z,b|e,a|z,c|e,z|f,a|f,c|e,
|
||||
z|f,b|d,c|f,c|z,a|e,z|z,z|d,c|f,z|z,a|f,c|z,z|e,b|d,b|e,z|e,a|d];
|
||||
a=1<<18; b=1<<28; c=a|b; d=1<<6; e=1<<12; f=d|e;
|
||||
const SP8 = [b|f,z|e,a|z,c|f,b|z,b|f,z|d,b|z,a|d,c|z,c|f,a|e,c|e,a|f,z|e,z|d,
|
||||
c|z,b|d,b|e,z|f,a|e,a|d,c|d,c|e,z|f,z|z,z|z,c|d,b|d,b|e,a|f,a|z,
|
||||
a|f,a|z,c|e,z|e,z|d,c|d,z|e,a|f,b|e,z|d,b|d,c|z,c|d,b|z,a|z,b|f,
|
||||
z|z,c|f,a|d,b|d,c|z,b|e,b|f,z|z,c|f,a|e,a|e,z|f,z|f,a|d,b|z,c|e];
|
||||
|
||||
// Set the key.
|
||||
function setKeys(keyBlock) {
|
||||
var i, j, l, m, n, o, pc1m = [], pcr = [], kn = [],
|
||||
raw0, raw1, rawi, KnLi;
|
||||
/* eslint-enable comma-spacing */
|
||||
|
||||
for (j = 0, l = 56; j < 56; ++j, l -= 8) {
|
||||
export default class DES {
|
||||
constructor(password) {
|
||||
this.keys = [];
|
||||
|
||||
// Set the key.
|
||||
const pc1m = [], pcr = [], kn = [];
|
||||
|
||||
for (let j = 0, l = 56; j < 56; ++j, l -= 8) {
|
||||
l += l < -5 ? 65 : l < -3 ? 31 : l < -1 ? 63 : l === 27 ? 35 : 0; // PC1
|
||||
m = l & 0x7;
|
||||
pc1m[j] = ((keyBlock[l >>> 3] & (1<<m)) !== 0) ? 1: 0;
|
||||
const m = l & 0x7;
|
||||
pc1m[j] = ((password[l >>> 3] & (1<<m)) !== 0) ? 1: 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; ++i) {
|
||||
m = i << 1;
|
||||
n = m + 1;
|
||||
for (let i = 0; i < 16; ++i) {
|
||||
const m = i << 1;
|
||||
const n = m + 1;
|
||||
kn[m] = kn[n] = 0;
|
||||
for (o = 28; o < 59; o += 28) {
|
||||
for (j = o - 28; j < o; ++j) {
|
||||
l = j + totrot[i];
|
||||
if (l < o) {
|
||||
pcr[j] = pc1m[l];
|
||||
} else {
|
||||
pcr[j] = pc1m[l - 28];
|
||||
}
|
||||
for (let o = 28; o < 59; o += 28) {
|
||||
for (let j = o - 28; j < o; ++j) {
|
||||
const l = j + totrot[i];
|
||||
pcr[j] = l < o ? pc1m[l] : pc1m[l - 28];
|
||||
}
|
||||
}
|
||||
for (j = 0; j < 24; ++j) {
|
||||
for (let j = 0; j < 24; ++j) {
|
||||
if (pcr[PC2[j]] !== 0) {
|
||||
kn[m] |= 1 << (23 - j);
|
||||
}
|
||||
@@ -163,26 +162,26 @@ export default function DES(passwd) {
|
||||
}
|
||||
|
||||
// cookey
|
||||
for (i = 0, rawi = 0, KnLi = 0; i < 16; ++i) {
|
||||
raw0 = kn[rawi++];
|
||||
raw1 = kn[rawi++];
|
||||
keys[KnLi] = (raw0 & 0x00fc0000) << 6;
|
||||
keys[KnLi] |= (raw0 & 0x00000fc0) << 10;
|
||||
keys[KnLi] |= (raw1 & 0x00fc0000) >>> 10;
|
||||
keys[KnLi] |= (raw1 & 0x00000fc0) >>> 6;
|
||||
for (let i = 0, rawi = 0, KnLi = 0; i < 16; ++i) {
|
||||
const raw0 = kn[rawi++];
|
||||
const raw1 = kn[rawi++];
|
||||
this.keys[KnLi] = (raw0 & 0x00fc0000) << 6;
|
||||
this.keys[KnLi] |= (raw0 & 0x00000fc0) << 10;
|
||||
this.keys[KnLi] |= (raw1 & 0x00fc0000) >>> 10;
|
||||
this.keys[KnLi] |= (raw1 & 0x00000fc0) >>> 6;
|
||||
++KnLi;
|
||||
keys[KnLi] = (raw0 & 0x0003f000) << 12;
|
||||
keys[KnLi] |= (raw0 & 0x0000003f) << 16;
|
||||
keys[KnLi] |= (raw1 & 0x0003f000) >>> 4;
|
||||
keys[KnLi] |= (raw1 & 0x0000003f);
|
||||
this.keys[KnLi] = (raw0 & 0x0003f000) << 12;
|
||||
this.keys[KnLi] |= (raw0 & 0x0000003f) << 16;
|
||||
this.keys[KnLi] |= (raw1 & 0x0003f000) >>> 4;
|
||||
this.keys[KnLi] |= (raw1 & 0x0000003f);
|
||||
++KnLi;
|
||||
}
|
||||
}
|
||||
|
||||
// Encrypt 8 bytes of text
|
||||
function enc8(text) {
|
||||
var i = 0, b = text.slice(), fval, keysi = 0,
|
||||
l, r, x; // left, right, accumulator
|
||||
enc8(text) {
|
||||
const b = text.slice();
|
||||
let i = 0, l, r, x; // left, right, accumulator
|
||||
|
||||
// Squash 8 bytes to 2 ints
|
||||
l = b[i++]<<24 | b[i++]<<16 | b[i++]<<8 | b[i++];
|
||||
@@ -206,26 +205,26 @@ export default function DES(passwd) {
|
||||
r ^= x;
|
||||
l = (l << 1) | ((l >>> 31) & 1);
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
for (let i = 0, keysi = 0; i < 8; ++i) {
|
||||
x = (r << 28) | (r >>> 4);
|
||||
x ^= keys[keysi++];
|
||||
fval = SP7[x & 0x3f];
|
||||
x ^= this.keys[keysi++];
|
||||
let fval = SP7[x & 0x3f];
|
||||
fval |= SP5[(x >>> 8) & 0x3f];
|
||||
fval |= SP3[(x >>> 16) & 0x3f];
|
||||
fval |= SP1[(x >>> 24) & 0x3f];
|
||||
x = r ^ keys[keysi++];
|
||||
x = r ^ this.keys[keysi++];
|
||||
fval |= SP8[x & 0x3f];
|
||||
fval |= SP6[(x >>> 8) & 0x3f];
|
||||
fval |= SP4[(x >>> 16) & 0x3f];
|
||||
fval |= SP2[(x >>> 24) & 0x3f];
|
||||
l ^= fval;
|
||||
x = (l << 28) | (l >>> 4);
|
||||
x ^= keys[keysi++];
|
||||
x ^= this.keys[keysi++];
|
||||
fval = SP7[x & 0x3f];
|
||||
fval |= SP5[(x >>> 8) & 0x3f];
|
||||
fval |= SP3[(x >>> 16) & 0x3f];
|
||||
fval |= SP1[(x >>> 24) & 0x3f];
|
||||
x = l ^ keys[keysi++];
|
||||
x = l ^ this.keys[keysi++];
|
||||
fval |= SP8[x & 0x0000003f];
|
||||
fval |= SP6[(x >>> 8) & 0x3f];
|
||||
fval |= SP4[(x >>> 16) & 0x3f];
|
||||
@@ -261,11 +260,7 @@ export default function DES(passwd) {
|
||||
}
|
||||
|
||||
// Encrypt 16 bytes of text using passwd as key
|
||||
function encrypt(t) {
|
||||
return enc8(t.slice(0, 8)).concat(enc8(t.slice(8, 16)));
|
||||
encrypt(t) {
|
||||
return this.enc8(t.slice(0, 8)).concat(this.enc8(t.slice(8, 16)));
|
||||
}
|
||||
|
||||
setKeys(passwd); // Setup keys
|
||||
return {'encrypt': encrypt}; // Public interface
|
||||
|
||||
}; // function DES
|
||||
}
|
||||
|
||||
+205
-390
@@ -1,7 +1,6 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2012 Joel Martin
|
||||
* Copyright (C) 2015 Samuel Mannehed for Cendio AB
|
||||
* Copyright (C) 2019 The noVNC Authors
|
||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||
*
|
||||
* See README.md for usage and integration instructions.
|
||||
@@ -9,111 +8,93 @@
|
||||
|
||||
import * as Log from './util/logging.js';
|
||||
import Base64 from "./base64.js";
|
||||
import { toSigned32bit } from './util/int.js';
|
||||
|
||||
export default function Display(target) {
|
||||
this._drawCtx = null;
|
||||
this._c_forceCanvas = false;
|
||||
export default class Display {
|
||||
constructor(target) {
|
||||
this._drawCtx = null;
|
||||
|
||||
this._renderQ = []; // queue drawing actions for in-oder rendering
|
||||
this._flushing = false;
|
||||
this._renderQ = []; // queue drawing actions for in-oder rendering
|
||||
this._flushing = false;
|
||||
|
||||
// the full frame buffer (logical canvas) size
|
||||
this._fb_width = 0;
|
||||
this._fb_height = 0;
|
||||
// the full frame buffer (logical canvas) size
|
||||
this._fbWidth = 0;
|
||||
this._fbHeight = 0;
|
||||
|
||||
this._prevDrawStyle = "";
|
||||
this._tile = null;
|
||||
this._tile16x16 = null;
|
||||
this._tile_x = 0;
|
||||
this._tile_y = 0;
|
||||
this._prevDrawStyle = "";
|
||||
|
||||
Log.Debug(">> Display.constructor");
|
||||
Log.Debug(">> Display.constructor");
|
||||
|
||||
// The visible canvas
|
||||
this._target = target;
|
||||
// The visible canvas
|
||||
this._target = target;
|
||||
|
||||
if (!this._target) {
|
||||
throw new Error("Target must be set");
|
||||
if (!this._target) {
|
||||
throw new Error("Target must be set");
|
||||
}
|
||||
|
||||
if (typeof this._target === 'string') {
|
||||
throw new Error('target must be a DOM element');
|
||||
}
|
||||
|
||||
if (!this._target.getContext) {
|
||||
throw new Error("no getContext method");
|
||||
}
|
||||
|
||||
this._targetCtx = this._target.getContext('2d');
|
||||
|
||||
// the visible canvas viewport (i.e. what actually gets seen)
|
||||
this._viewportLoc = { 'x': 0, 'y': 0, 'w': this._target.width, 'h': this._target.height };
|
||||
|
||||
// The hidden canvas, where we do the actual rendering
|
||||
this._backbuffer = document.createElement('canvas');
|
||||
this._drawCtx = this._backbuffer.getContext('2d');
|
||||
|
||||
this._damageBounds = { left: 0, top: 0,
|
||||
right: this._backbuffer.width,
|
||||
bottom: this._backbuffer.height };
|
||||
|
||||
Log.Debug("User Agent: " + navigator.userAgent);
|
||||
|
||||
Log.Debug("<< Display.constructor");
|
||||
|
||||
// ===== PROPERTIES =====
|
||||
|
||||
this._scale = 1.0;
|
||||
this._clipViewport = false;
|
||||
|
||||
// ===== EVENT HANDLERS =====
|
||||
|
||||
this.onflush = () => {}; // A flush request has finished
|
||||
}
|
||||
|
||||
if (typeof this._target === 'string') {
|
||||
throw new Error('target must be a DOM element');
|
||||
}
|
||||
|
||||
if (!this._target.getContext) {
|
||||
throw new Error("no getContext method");
|
||||
}
|
||||
|
||||
this._targetCtx = this._target.getContext('2d');
|
||||
|
||||
// the visible canvas viewport (i.e. what actually gets seen)
|
||||
this._viewportLoc = { 'x': 0, 'y': 0, 'w': this._target.width, 'h': this._target.height };
|
||||
|
||||
// The hidden canvas, where we do the actual rendering
|
||||
this._backbuffer = document.createElement('canvas');
|
||||
this._drawCtx = this._backbuffer.getContext('2d');
|
||||
|
||||
this._damageBounds = { left:0, top:0,
|
||||
right: this._backbuffer.width,
|
||||
bottom: this._backbuffer.height };
|
||||
|
||||
Log.Debug("User Agent: " + navigator.userAgent);
|
||||
|
||||
this.clear();
|
||||
|
||||
// Check canvas features
|
||||
if (!('createImageData' in this._drawCtx)) {
|
||||
throw new Error("Canvas does not support createImageData");
|
||||
}
|
||||
|
||||
this._tile16x16 = this._drawCtx.createImageData(16, 16);
|
||||
Log.Debug("<< Display.constructor");
|
||||
};
|
||||
|
||||
var SUPPORTS_IMAGEDATA_CONSTRUCTOR = false;
|
||||
try {
|
||||
new ImageData(new Uint8ClampedArray(4), 1, 1);
|
||||
SUPPORTS_IMAGEDATA_CONSTRUCTOR = true;
|
||||
} catch (ex) {
|
||||
// ignore failure
|
||||
}
|
||||
|
||||
Display.prototype = {
|
||||
// ===== PROPERTIES =====
|
||||
|
||||
_scale: 1.0,
|
||||
get scale() { return this._scale; },
|
||||
get scale() { return this._scale; }
|
||||
set scale(scale) {
|
||||
this._rescale(scale);
|
||||
},
|
||||
}
|
||||
|
||||
_clipViewport: false,
|
||||
get clipViewport() { return this._clipViewport; },
|
||||
get clipViewport() { return this._clipViewport; }
|
||||
set clipViewport(viewport) {
|
||||
this._clipViewport = viewport;
|
||||
// May need to readjust the viewport dimensions
|
||||
var vp = this._viewportLoc;
|
||||
const vp = this._viewportLoc;
|
||||
this.viewportChangeSize(vp.w, vp.h);
|
||||
this.viewportChangePos(0, 0);
|
||||
},
|
||||
}
|
||||
|
||||
get width() {
|
||||
return this._fb_width;
|
||||
},
|
||||
return this._fbWidth;
|
||||
}
|
||||
|
||||
get height() {
|
||||
return this._fb_height;
|
||||
},
|
||||
|
||||
logo: null,
|
||||
|
||||
// ===== EVENT HANDLERS =====
|
||||
|
||||
onflush: function () {}, // A flush request has finished
|
||||
return this._fbHeight;
|
||||
}
|
||||
|
||||
// ===== PUBLIC METHODS =====
|
||||
|
||||
viewportChangePos: function (deltaX, deltaY) {
|
||||
var vp = this._viewportLoc;
|
||||
viewportChangePos(deltaX, deltaY) {
|
||||
const vp = this._viewportLoc;
|
||||
deltaX = Math.floor(deltaX);
|
||||
deltaY = Math.floor(deltaY);
|
||||
|
||||
@@ -122,23 +103,23 @@ Display.prototype = {
|
||||
deltaY = -vp.h;
|
||||
}
|
||||
|
||||
var vx2 = vp.x + vp.w - 1;
|
||||
var vy2 = vp.y + vp.h - 1;
|
||||
const vx2 = vp.x + vp.w - 1;
|
||||
const vy2 = vp.y + vp.h - 1;
|
||||
|
||||
// Position change
|
||||
|
||||
if (deltaX < 0 && vp.x + deltaX < 0) {
|
||||
deltaX = -vp.x;
|
||||
}
|
||||
if (vx2 + deltaX >= this._fb_width) {
|
||||
deltaX -= vx2 + deltaX - this._fb_width + 1;
|
||||
if (vx2 + deltaX >= this._fbWidth) {
|
||||
deltaX -= vx2 + deltaX - this._fbWidth + 1;
|
||||
}
|
||||
|
||||
if (vp.y + deltaY < 0) {
|
||||
deltaY = -vp.y;
|
||||
}
|
||||
if (vy2 + deltaY >= this._fb_height) {
|
||||
deltaY -= (vy2 + deltaY - this._fb_height + 1);
|
||||
if (vy2 + deltaY >= this._fbHeight) {
|
||||
deltaY -= (vy2 + deltaY - this._fbHeight + 1);
|
||||
}
|
||||
|
||||
if (deltaX === 0 && deltaY === 0) {
|
||||
@@ -152,32 +133,35 @@ Display.prototype = {
|
||||
this._damage(vp.x, vp.y, vp.w, vp.h);
|
||||
|
||||
this.flip();
|
||||
},
|
||||
}
|
||||
|
||||
viewportChangeSize: function(width, height) {
|
||||
viewportChangeSize(width, height) {
|
||||
|
||||
if (!this._clipViewport ||
|
||||
typeof(width) === "undefined" ||
|
||||
typeof(height) === "undefined") {
|
||||
|
||||
Log.Debug("Setting viewport to full display region");
|
||||
width = this._fb_width;
|
||||
height = this._fb_height;
|
||||
width = this._fbWidth;
|
||||
height = this._fbHeight;
|
||||
}
|
||||
|
||||
if (width > this._fb_width) {
|
||||
width = this._fb_width;
|
||||
width = Math.floor(width);
|
||||
height = Math.floor(height);
|
||||
|
||||
if (width > this._fbWidth) {
|
||||
width = this._fbWidth;
|
||||
}
|
||||
if (height > this._fb_height) {
|
||||
height = this._fb_height;
|
||||
if (height > this._fbHeight) {
|
||||
height = this._fbHeight;
|
||||
}
|
||||
|
||||
var vp = this._viewportLoc;
|
||||
const vp = this._viewportLoc;
|
||||
if (vp.w !== width || vp.h !== height) {
|
||||
vp.w = width;
|
||||
vp.h = height;
|
||||
|
||||
var canvas = this._target;
|
||||
const canvas = this._target;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
@@ -190,27 +174,33 @@ Display.prototype = {
|
||||
// Update the visible size of the target canvas
|
||||
this._rescale(this._scale);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
absX: function (x) {
|
||||
return x / this._scale + this._viewportLoc.x;
|
||||
},
|
||||
absX(x) {
|
||||
if (this._scale === 0) {
|
||||
return 0;
|
||||
}
|
||||
return toSigned32bit(x / this._scale + this._viewportLoc.x);
|
||||
}
|
||||
|
||||
absY: function (y) {
|
||||
return y / this._scale + this._viewportLoc.y;
|
||||
},
|
||||
absY(y) {
|
||||
if (this._scale === 0) {
|
||||
return 0;
|
||||
}
|
||||
return toSigned32bit(y / this._scale + this._viewportLoc.y);
|
||||
}
|
||||
|
||||
resize: function (width, height) {
|
||||
resize(width, height) {
|
||||
this._prevDrawStyle = "";
|
||||
|
||||
this._fb_width = width;
|
||||
this._fb_height = height;
|
||||
this._fbWidth = width;
|
||||
this._fbHeight = height;
|
||||
|
||||
var canvas = this._backbuffer;
|
||||
const canvas = this._backbuffer;
|
||||
if (canvas.width !== width || canvas.height !== height) {
|
||||
|
||||
// We have to save the canvas data since changing the size will clear it
|
||||
var saveImg = null;
|
||||
let saveImg = null;
|
||||
if (canvas.width > 0 && canvas.height > 0) {
|
||||
saveImg = this._drawCtx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
@@ -229,13 +219,13 @@ Display.prototype = {
|
||||
|
||||
// Readjust the viewport as it may be incorrectly sized
|
||||
// and positioned
|
||||
var vp = this._viewportLoc;
|
||||
const vp = this._viewportLoc;
|
||||
this.viewportChangeSize(vp.w, vp.h);
|
||||
this.viewportChangePos(0, 0);
|
||||
},
|
||||
}
|
||||
|
||||
// Track what parts of the visible canvas that need updating
|
||||
_damage: function(x, y, w, h) {
|
||||
_damage(x, y, w, h) {
|
||||
if (x < this._damageBounds.left) {
|
||||
this._damageBounds.left = x;
|
||||
}
|
||||
@@ -248,25 +238,23 @@ Display.prototype = {
|
||||
if ((y + h) > this._damageBounds.bottom) {
|
||||
this._damageBounds.bottom = y + h;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// Update the visible canvas with the contents of the
|
||||
// rendering canvas
|
||||
flip: function(from_queue) {
|
||||
if (this._renderQ.length !== 0 && !from_queue) {
|
||||
this._renderQ_push({
|
||||
flip(fromQueue) {
|
||||
if (this._renderQ.length !== 0 && !fromQueue) {
|
||||
this._renderQPush({
|
||||
'type': 'flip'
|
||||
});
|
||||
} else {
|
||||
var x, y, vx, vy, w, h;
|
||||
let x = this._damageBounds.left;
|
||||
let y = this._damageBounds.top;
|
||||
let w = this._damageBounds.right - x;
|
||||
let h = this._damageBounds.bottom - y;
|
||||
|
||||
x = this._damageBounds.left;
|
||||
y = this._damageBounds.top;
|
||||
w = this._damageBounds.right - x;
|
||||
h = this._damageBounds.bottom - y;
|
||||
|
||||
vx = x - this._viewportLoc.x;
|
||||
vy = y - this._viewportLoc.y;
|
||||
let vx = x - this._viewportLoc.x;
|
||||
let vy = y - this._viewportLoc.y;
|
||||
|
||||
if (vx < 0) {
|
||||
w += vx;
|
||||
@@ -298,34 +286,23 @@ Display.prototype = {
|
||||
this._damageBounds.left = this._damageBounds.top = 65535;
|
||||
this._damageBounds.right = this._damageBounds.bottom = 0;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
clear: function () {
|
||||
if (this._logo) {
|
||||
this.resize(this._logo.width, this._logo.height);
|
||||
this.imageRect(0, 0, this._logo.type, this._logo.data);
|
||||
} else {
|
||||
this.resize(240, 20);
|
||||
this._drawCtx.clearRect(0, 0, this._fb_width, this._fb_height);
|
||||
}
|
||||
this.flip();
|
||||
},
|
||||
|
||||
pending: function() {
|
||||
pending() {
|
||||
return this._renderQ.length > 0;
|
||||
},
|
||||
}
|
||||
|
||||
flush: function() {
|
||||
flush() {
|
||||
if (this._renderQ.length === 0) {
|
||||
this.onflush();
|
||||
} else {
|
||||
this._flushing = true;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
fillRect: function (x, y, width, height, color, from_queue) {
|
||||
if (this._renderQ.length !== 0 && !from_queue) {
|
||||
this._renderQ_push({
|
||||
fillRect(x, y, width, height, color, fromQueue) {
|
||||
if (this._renderQ.length !== 0 && !fromQueue) {
|
||||
this._renderQPush({
|
||||
'type': 'fill',
|
||||
'x': x,
|
||||
'y': y,
|
||||
@@ -338,16 +315,16 @@ Display.prototype = {
|
||||
this._drawCtx.fillRect(x, y, width, height);
|
||||
this._damage(x, y, width, height);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
copyImage: function (old_x, old_y, new_x, new_y, w, h, from_queue) {
|
||||
if (this._renderQ.length !== 0 && !from_queue) {
|
||||
this._renderQ_push({
|
||||
copyImage(oldX, oldY, newX, newY, w, h, fromQueue) {
|
||||
if (this._renderQ.length !== 0 && !fromQueue) {
|
||||
this._renderQPush({
|
||||
'type': 'copy',
|
||||
'old_x': old_x,
|
||||
'old_y': old_y,
|
||||
'x': new_x,
|
||||
'y': new_y,
|
||||
'oldX': oldX,
|
||||
'oldY': oldY,
|
||||
'x': newX,
|
||||
'y': newY,
|
||||
'width': w,
|
||||
'height': h,
|
||||
});
|
||||
@@ -365,259 +342,138 @@ Display.prototype = {
|
||||
this._drawCtx.imageSmoothingEnabled = false;
|
||||
|
||||
this._drawCtx.drawImage(this._backbuffer,
|
||||
old_x, old_y, w, h,
|
||||
new_x, new_y, w, h);
|
||||
this._damage(new_x, new_y, w, h);
|
||||
oldX, oldY, w, h,
|
||||
newX, newY, w, h);
|
||||
this._damage(newX, newY, w, h);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
imageRect: function(x, y, mime, arr) {
|
||||
var img = new Image();
|
||||
imageRect(x, y, width, height, mime, arr) {
|
||||
/* The internal logic cannot handle empty images, so bail early */
|
||||
if ((width === 0) || (height === 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const img = new Image();
|
||||
img.src = "data: " + mime + ";base64," + Base64.encode(arr);
|
||||
this._renderQ_push({
|
||||
|
||||
this._renderQPush({
|
||||
'type': 'img',
|
||||
'img': img,
|
||||
'x': x,
|
||||
'y': y
|
||||
'y': y,
|
||||
'width': width,
|
||||
'height': height
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
// start updating a tile
|
||||
startTile: function (x, y, width, height, color) {
|
||||
this._tile_x = x;
|
||||
this._tile_y = y;
|
||||
if (width === 16 && height === 16) {
|
||||
this._tile = this._tile16x16;
|
||||
} else {
|
||||
this._tile = this._drawCtx.createImageData(width, height);
|
||||
}
|
||||
|
||||
var red = color[2];
|
||||
var green = color[1];
|
||||
var blue = color[0];
|
||||
|
||||
var data = this._tile.data;
|
||||
for (var i = 0; i < width * height * 4; i += 4) {
|
||||
data[i] = red;
|
||||
data[i + 1] = green;
|
||||
data[i + 2] = blue;
|
||||
data[i + 3] = 255;
|
||||
}
|
||||
},
|
||||
|
||||
// update sub-rectangle of the current tile
|
||||
subTile: function (x, y, w, h, color) {
|
||||
var red = color[2];
|
||||
var green = color[1];
|
||||
var blue = color[0];
|
||||
var xend = x + w;
|
||||
var yend = y + h;
|
||||
|
||||
var data = this._tile.data;
|
||||
var width = this._tile.width;
|
||||
for (var j = y; j < yend; j++) {
|
||||
for (var i = x; i < xend; i++) {
|
||||
var p = (i + (j * width)) * 4;
|
||||
data[p] = red;
|
||||
data[p + 1] = green;
|
||||
data[p + 2] = blue;
|
||||
data[p + 3] = 255;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// draw the current tile to the screen
|
||||
finishTile: function () {
|
||||
this._drawCtx.putImageData(this._tile, this._tile_x, this._tile_y);
|
||||
this._damage(this._tile_x, this._tile_y,
|
||||
this._tile.width, this._tile.height);
|
||||
},
|
||||
|
||||
blitImage: function (x, y, width, height, arr, offset, from_queue) {
|
||||
if (this._renderQ.length !== 0 && !from_queue) {
|
||||
blitImage(x, y, width, height, arr, offset, fromQueue) {
|
||||
if (this._renderQ.length !== 0 && !fromQueue) {
|
||||
// NB(directxman12): it's technically more performant here to use preallocated arrays,
|
||||
// but it's a lot of extra work for not a lot of payoff -- if we're using the render queue,
|
||||
// this probably isn't getting called *nearly* as much
|
||||
var new_arr = new Uint8Array(width * height * 4);
|
||||
new_arr.set(new Uint8Array(arr.buffer, 0, new_arr.length));
|
||||
this._renderQ_push({
|
||||
const newArr = new Uint8Array(width * height * 4);
|
||||
newArr.set(new Uint8Array(arr.buffer, 0, newArr.length));
|
||||
this._renderQPush({
|
||||
'type': 'blit',
|
||||
'data': new_arr,
|
||||
'data': newArr,
|
||||
'x': x,
|
||||
'y': y,
|
||||
'width': width,
|
||||
'height': height,
|
||||
});
|
||||
} else {
|
||||
this._bgrxImageData(x, y, width, height, arr, offset);
|
||||
// NB(directxman12): arr must be an Type Array view
|
||||
let data = new Uint8ClampedArray(arr.buffer,
|
||||
arr.byteOffset + offset,
|
||||
width * height * 4);
|
||||
let img = new ImageData(data, width, height);
|
||||
this._drawCtx.putImageData(img, x, y);
|
||||
this._damage(x, y, width, height);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
blitRgbImage: function (x, y , width, height, arr, offset, from_queue) {
|
||||
if (this._renderQ.length !== 0 && !from_queue) {
|
||||
// NB(directxman12): it's technically more performant here to use preallocated arrays,
|
||||
// but it's a lot of extra work for not a lot of payoff -- if we're using the render queue,
|
||||
// this probably isn't getting called *nearly* as much
|
||||
var new_arr = new Uint8Array(width * height * 3);
|
||||
new_arr.set(new Uint8Array(arr.buffer, 0, new_arr.length));
|
||||
this._renderQ_push({
|
||||
'type': 'blitRgb',
|
||||
'data': new_arr,
|
||||
'x': x,
|
||||
'y': y,
|
||||
'width': width,
|
||||
'height': height,
|
||||
});
|
||||
} else {
|
||||
this._rgbImageData(x, y, width, height, arr, offset);
|
||||
}
|
||||
},
|
||||
|
||||
blitRgbxImage: function (x, y, width, height, arr, offset, from_queue) {
|
||||
if (this._renderQ.length !== 0 && !from_queue) {
|
||||
// NB(directxman12): it's technically more performant here to use preallocated arrays,
|
||||
// but it's a lot of extra work for not a lot of payoff -- if we're using the render queue,
|
||||
// this probably isn't getting called *nearly* as much
|
||||
var new_arr = new Uint8Array(width * height * 4);
|
||||
new_arr.set(new Uint8Array(arr.buffer, 0, new_arr.length));
|
||||
this._renderQ_push({
|
||||
'type': 'blitRgbx',
|
||||
'data': new_arr,
|
||||
'x': x,
|
||||
'y': y,
|
||||
'width': width,
|
||||
'height': height,
|
||||
});
|
||||
} else {
|
||||
this._rgbxImageData(x, y, width, height, arr, offset);
|
||||
}
|
||||
},
|
||||
|
||||
drawImage: function (img, x, y) {
|
||||
drawImage(img, x, y) {
|
||||
this._drawCtx.drawImage(img, x, y);
|
||||
this._damage(x, y, img.width, img.height);
|
||||
},
|
||||
}
|
||||
|
||||
changeCursor: function (pixels, mask, hotx, hoty, w, h) {
|
||||
Display.changeCursor(this._target, pixels, mask, hotx, hoty, w, h);
|
||||
},
|
||||
autoscale(containerWidth, containerHeight) {
|
||||
let scaleRatio;
|
||||
|
||||
defaultCursor: function () {
|
||||
this._target.style.cursor = "default";
|
||||
},
|
||||
if (containerWidth === 0 || containerHeight === 0) {
|
||||
scaleRatio = 0;
|
||||
|
||||
disableLocalCursor: function () {
|
||||
this._target.style.cursor = "none";
|
||||
},
|
||||
|
||||
autoscale: function (containerWidth, containerHeight) {
|
||||
var vp = this._viewportLoc;
|
||||
var targetAspectRatio = containerWidth / containerHeight;
|
||||
var fbAspectRatio = vp.w / vp.h;
|
||||
|
||||
var scaleRatio;
|
||||
if (fbAspectRatio >= targetAspectRatio) {
|
||||
scaleRatio = containerWidth / vp.w;
|
||||
} else {
|
||||
scaleRatio = containerHeight / vp.h;
|
||||
|
||||
const vp = this._viewportLoc;
|
||||
const targetAspectRatio = containerWidth / containerHeight;
|
||||
const fbAspectRatio = vp.w / vp.h;
|
||||
|
||||
if (fbAspectRatio >= targetAspectRatio) {
|
||||
scaleRatio = containerWidth / vp.w;
|
||||
} else {
|
||||
scaleRatio = containerHeight / vp.h;
|
||||
}
|
||||
}
|
||||
|
||||
this._rescale(scaleRatio);
|
||||
},
|
||||
}
|
||||
|
||||
// ===== PRIVATE METHODS =====
|
||||
|
||||
_rescale: function (factor) {
|
||||
_rescale(factor) {
|
||||
this._scale = factor;
|
||||
var vp = this._viewportLoc;
|
||||
const vp = this._viewportLoc;
|
||||
|
||||
// NB(directxman12): If you set the width directly, or set the
|
||||
// style width to a number, the canvas is cleared.
|
||||
// However, if you set the style width to a string
|
||||
// ('NNNpx'), the canvas is scaled without clearing.
|
||||
var width = Math.round(factor * vp.w) + 'px';
|
||||
var height = Math.round(factor * vp.h) + 'px';
|
||||
const width = factor * vp.w + 'px';
|
||||
const height = factor * vp.h + 'px';
|
||||
|
||||
if ((this._target.style.width !== width) ||
|
||||
(this._target.style.height !== height)) {
|
||||
this._target.style.width = width;
|
||||
this._target.style.height = height;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_setFillColor: function (color) {
|
||||
var newStyle = 'rgb(' + color[2] + ',' + color[1] + ',' + color[0] + ')';
|
||||
_setFillColor(color) {
|
||||
const newStyle = 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] + ')';
|
||||
if (newStyle !== this._prevDrawStyle) {
|
||||
this._drawCtx.fillStyle = newStyle;
|
||||
this._prevDrawStyle = newStyle;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_rgbImageData: function (x, y, width, height, arr, offset) {
|
||||
var img = this._drawCtx.createImageData(width, height);
|
||||
var data = img.data;
|
||||
for (var i = 0, j = offset; i < width * height * 4; i += 4, j += 3) {
|
||||
data[i] = arr[j];
|
||||
data[i + 1] = arr[j + 1];
|
||||
data[i + 2] = arr[j + 2];
|
||||
data[i + 3] = 255; // Alpha
|
||||
}
|
||||
this._drawCtx.putImageData(img, x, y);
|
||||
this._damage(x, y, img.width, img.height);
|
||||
},
|
||||
|
||||
_bgrxImageData: function (x, y, width, height, arr, offset) {
|
||||
var img = this._drawCtx.createImageData(width, height);
|
||||
var data = img.data;
|
||||
for (var i = 0, j = offset; i < width * height * 4; i += 4, j += 4) {
|
||||
data[i] = arr[j + 2];
|
||||
data[i + 1] = arr[j + 1];
|
||||
data[i + 2] = arr[j];
|
||||
data[i + 3] = 255; // Alpha
|
||||
}
|
||||
this._drawCtx.putImageData(img, x, y);
|
||||
this._damage(x, y, img.width, img.height);
|
||||
},
|
||||
|
||||
_rgbxImageData: function (x, y, width, height, arr, offset) {
|
||||
// NB(directxman12): arr must be an Type Array view
|
||||
var img;
|
||||
if (SUPPORTS_IMAGEDATA_CONSTRUCTOR) {
|
||||
img = new ImageData(new Uint8ClampedArray(arr.buffer, arr.byteOffset, width * height * 4), width, height);
|
||||
} else {
|
||||
img = this._drawCtx.createImageData(width, height);
|
||||
img.data.set(new Uint8ClampedArray(arr.buffer, arr.byteOffset, width * height * 4));
|
||||
}
|
||||
this._drawCtx.putImageData(img, x, y);
|
||||
this._damage(x, y, img.width, img.height);
|
||||
},
|
||||
|
||||
_renderQ_push: function (action) {
|
||||
_renderQPush(action) {
|
||||
this._renderQ.push(action);
|
||||
if (this._renderQ.length === 1) {
|
||||
// If this can be rendered immediately it will be, otherwise
|
||||
// the scanner will wait for the relevant event
|
||||
this._scan_renderQ();
|
||||
this._scanRenderQ();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_resume_renderQ: function() {
|
||||
_resumeRenderQ() {
|
||||
// "this" is the object that is ready, not the
|
||||
// display object
|
||||
this.removeEventListener('load', this._noVNC_display._resume_renderQ);
|
||||
this._noVNC_display._scan_renderQ();
|
||||
},
|
||||
this.removeEventListener('load', this._noVNCDisplay._resumeRenderQ);
|
||||
this._noVNCDisplay._scanRenderQ();
|
||||
}
|
||||
|
||||
_scan_renderQ: function () {
|
||||
var ready = true;
|
||||
_scanRenderQ() {
|
||||
let ready = true;
|
||||
while (ready && this._renderQ.length > 0) {
|
||||
var a = this._renderQ[0];
|
||||
const a = this._renderQ[0];
|
||||
switch (a.type) {
|
||||
case 'flip':
|
||||
this.flip(true);
|
||||
break;
|
||||
case 'copy':
|
||||
this.copyImage(a.old_x, a.old_y, a.x, a.y, a.width, a.height, true);
|
||||
this.copyImage(a.oldX, a.oldY, a.x, a.y, a.width, a.height, true);
|
||||
break;
|
||||
case 'fill':
|
||||
this.fillRect(a.x, a.y, a.width, a.height, a.color, true);
|
||||
@@ -625,18 +481,18 @@ Display.prototype = {
|
||||
case 'blit':
|
||||
this.blitImage(a.x, a.y, a.width, a.height, a.data, 0, true);
|
||||
break;
|
||||
case 'blitRgb':
|
||||
this.blitRgbImage(a.x, a.y, a.width, a.height, a.data, 0, true);
|
||||
break;
|
||||
case 'blitRgbx':
|
||||
this.blitRgbxImage(a.x, a.y, a.width, a.height, a.data, 0, true);
|
||||
break;
|
||||
case 'img':
|
||||
if (a.img.complete) {
|
||||
if (a.img.width !== a.width || a.img.height !== a.height) {
|
||||
Log.Error("Decoded image has incorrect dimensions. Got " +
|
||||
a.img.width + "x" + a.img.height + ". Expected " +
|
||||
a.width + "x" + a.height + ".");
|
||||
return;
|
||||
}
|
||||
this.drawImage(a.img, a.x, a.y);
|
||||
} else {
|
||||
a.img._noVNC_display = this;
|
||||
a.img.addEventListener('load', this._resume_renderQ);
|
||||
a.img._noVNCDisplay = this;
|
||||
a.img.addEventListener('load', this._resumeRenderQ);
|
||||
// We need to wait for this image to 'load'
|
||||
// to keep things in-order
|
||||
ready = false;
|
||||
@@ -653,46 +509,5 @@ Display.prototype = {
|
||||
this._flushing = false;
|
||||
this.onflush();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Class Methods
|
||||
Display.changeCursor = function (target, pixels, mask, hotx, hoty, w, h) {
|
||||
if ((w === 0) || (h === 0)) {
|
||||
target.style.cursor = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
var cur = []
|
||||
var y, x;
|
||||
for (y = 0; y < h; y++) {
|
||||
for (x = 0; x < w; x++) {
|
||||
var idx = y * Math.ceil(w / 8) + Math.floor(x / 8);
|
||||
var alpha = (mask[idx] << (x % 8)) & 0x80 ? 255 : 0;
|
||||
idx = ((w * y) + x) * 4;
|
||||
cur.push(pixels[idx + 2]); // red
|
||||
cur.push(pixels[idx + 1]); // green
|
||||
cur.push(pixels[idx]); // blue
|
||||
cur.push(alpha); // alpha
|
||||
}
|
||||
}
|
||||
|
||||
var canvas = document.createElement('canvas');
|
||||
var ctx = canvas.getContext('2d');
|
||||
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
|
||||
var img;
|
||||
if (SUPPORTS_IMAGEDATA_CONSTRUCTOR) {
|
||||
img = new ImageData(new Uint8ClampedArray(cur), w, h);
|
||||
} else {
|
||||
img = ctx.createImageData(w, h);
|
||||
img.data.set(new Uint8ClampedArray(cur));
|
||||
}
|
||||
ctx.clearRect(0, 0, w, h);
|
||||
ctx.putImageData(img, 0, 0);
|
||||
|
||||
var url = canvas.toDataURL();
|
||||
target.style.cursor = 'url(' + url + ')' + hotx + ' ' + hoty + ', default';
|
||||
};
|
||||
}
|
||||
|
||||
+7
-3
@@ -1,17 +1,18 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2017 Pierre Ossman for Cendio AB
|
||||
* Copyright (C) 2019 The noVNC Authors
|
||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||
*
|
||||
* See README.md for usage and integration instructions.
|
||||
*/
|
||||
|
||||
export var encodings = {
|
||||
export const encodings = {
|
||||
encodingRaw: 0,
|
||||
encodingCopyRect: 1,
|
||||
encodingRRE: 2,
|
||||
encodingHextile: 5,
|
||||
encodingTight: 7,
|
||||
encodingTightPNG: -260,
|
||||
|
||||
pseudoEncodingQualityLevel9: -23,
|
||||
pseudoEncodingQualityLevel0: -32,
|
||||
@@ -19,13 +20,15 @@ export var encodings = {
|
||||
pseudoEncodingLastRect: -224,
|
||||
pseudoEncodingCursor: -239,
|
||||
pseudoEncodingQEMUExtendedKeyEvent: -258,
|
||||
pseudoEncodingTightPNG: -260,
|
||||
pseudoEncodingDesktopName: -307,
|
||||
pseudoEncodingExtendedDesktopSize: -308,
|
||||
pseudoEncodingXvp: -309,
|
||||
pseudoEncodingFence: -312,
|
||||
pseudoEncodingContinuousUpdates: -313,
|
||||
pseudoEncodingCompressLevel9: -247,
|
||||
pseudoEncodingCompressLevel0: -256,
|
||||
pseudoEncodingVMwareCursor: 0x574d5664,
|
||||
pseudoEncodingExtendedClipboard: 0xc0a1e5ce
|
||||
};
|
||||
|
||||
export function encodingName(num) {
|
||||
@@ -35,6 +38,7 @@ export function encodingName(num) {
|
||||
case encodings.encodingRRE: return "RRE";
|
||||
case encodings.encodingHextile: return "Hextile";
|
||||
case encodings.encodingTight: return "Tight";
|
||||
case encodings.encodingTightPNG: return "TightPNG";
|
||||
default: return "[unknown encoding " + num + "]";
|
||||
}
|
||||
}
|
||||
|
||||
+48
-20
@@ -1,13 +1,40 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2020 The noVNC Authors
|
||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||
*
|
||||
* See README.md for usage and integration instructions.
|
||||
*/
|
||||
|
||||
import { inflateInit, inflate, inflateReset } from "../vendor/pako/lib/zlib/inflate.js";
|
||||
import ZStream from "../vendor/pako/lib/zlib/zstream.js";
|
||||
|
||||
Inflate.prototype = {
|
||||
inflate: function (data, flush, expected) {
|
||||
this.strm.input = data;
|
||||
this.strm.avail_in = this.strm.input.length;
|
||||
this.strm.next_in = 0;
|
||||
this.strm.next_out = 0;
|
||||
export default class Inflate {
|
||||
constructor() {
|
||||
this.strm = new ZStream();
|
||||
this.chunkSize = 1024 * 10 * 10;
|
||||
this.strm.output = new Uint8Array(this.chunkSize);
|
||||
this.windowBits = 5;
|
||||
|
||||
inflateInit(this.strm, this.windowBits);
|
||||
}
|
||||
|
||||
setInput(data) {
|
||||
if (!data) {
|
||||
//FIXME: flush remaining data.
|
||||
/* eslint-disable camelcase */
|
||||
this.strm.input = null;
|
||||
this.strm.avail_in = 0;
|
||||
this.strm.next_in = 0;
|
||||
} else {
|
||||
this.strm.input = data;
|
||||
this.strm.avail_in = this.strm.input.length;
|
||||
this.strm.next_in = 0;
|
||||
/* eslint-enable camelcase */
|
||||
}
|
||||
}
|
||||
|
||||
inflate(expected) {
|
||||
// resize our output buffer if it's too small
|
||||
// (we could just use multiple chunks, but that would cause an extra
|
||||
// allocation each time to flatten the chunks)
|
||||
@@ -16,23 +43,24 @@ Inflate.prototype = {
|
||||
this.strm.output = new Uint8Array(this.chunkSize);
|
||||
}
|
||||
|
||||
this.strm.avail_out = this.chunkSize;
|
||||
/* eslint-disable camelcase */
|
||||
this.strm.next_out = 0;
|
||||
this.strm.avail_out = expected;
|
||||
/* eslint-enable camelcase */
|
||||
|
||||
inflate(this.strm, flush);
|
||||
let ret = inflate(this.strm, 0); // Flush argument not used.
|
||||
if (ret < 0) {
|
||||
throw new Error("zlib inflate failed");
|
||||
}
|
||||
|
||||
if (this.strm.next_out != expected) {
|
||||
throw new Error("Incomplete zlib block");
|
||||
}
|
||||
|
||||
return new Uint8Array(this.strm.output.buffer, 0, this.strm.next_out);
|
||||
},
|
||||
}
|
||||
|
||||
reset: function () {
|
||||
reset() {
|
||||
inflateReset(this.strm);
|
||||
}
|
||||
};
|
||||
|
||||
export default function Inflate() {
|
||||
this.strm = new ZStream();
|
||||
this.chunkSize = 1024 * 10 * 10;
|
||||
this.strm.output = new Uint8Array(this.chunkSize);
|
||||
this.windowBits = 5;
|
||||
|
||||
inflateInit(this.strm, this.windowBits);
|
||||
};
|
||||
}
|
||||
|
||||
+46
-45
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2017 Pierre Ossman for Cendio AB
|
||||
* Copyright (C) 2018 The noVNC Authors
|
||||
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
||||
*/
|
||||
|
||||
@@ -13,32 +13,29 @@ import KeyTable from "./keysym.js";
|
||||
* See https://www.w3.org/TR/uievents-key/ for possible values.
|
||||
*/
|
||||
|
||||
var DOMKeyTable = {};
|
||||
const DOMKeyTable = {};
|
||||
|
||||
function addStandard(key, standard)
|
||||
{
|
||||
if (standard === undefined) throw "Undefined keysym for key \"" + key + "\"";
|
||||
if (key in DOMKeyTable) throw "Duplicate entry for key \"" + key + "\"";
|
||||
function addStandard(key, standard) {
|
||||
if (standard === undefined) throw new Error("Undefined keysym for key \"" + key + "\"");
|
||||
if (key in DOMKeyTable) throw new Error("Duplicate entry for key \"" + key + "\"");
|
||||
DOMKeyTable[key] = [standard, standard, standard, standard];
|
||||
}
|
||||
|
||||
function addLeftRight(key, left, right)
|
||||
{
|
||||
if (left === undefined) throw "Undefined keysym for key \"" + key + "\"";
|
||||
if (right === undefined) throw "Undefined keysym for key \"" + key + "\"";
|
||||
if (key in DOMKeyTable) throw "Duplicate entry for key \"" + key + "\"";
|
||||
function addLeftRight(key, left, right) {
|
||||
if (left === undefined) throw new Error("Undefined keysym for key \"" + key + "\"");
|
||||
if (right === undefined) throw new Error("Undefined keysym for key \"" + key + "\"");
|
||||
if (key in DOMKeyTable) throw new Error("Duplicate entry for key \"" + key + "\"");
|
||||
DOMKeyTable[key] = [left, left, right, left];
|
||||
}
|
||||
|
||||
function addNumpad(key, standard, numpad)
|
||||
{
|
||||
if (standard === undefined) throw "Undefined keysym for key \"" + key + "\"";
|
||||
if (numpad === undefined) throw "Undefined keysym for key \"" + key + "\"";
|
||||
if (key in DOMKeyTable) throw "Duplicate entry for key \"" + key + "\"";
|
||||
function addNumpad(key, standard, numpad) {
|
||||
if (standard === undefined) throw new Error("Undefined keysym for key \"" + key + "\"");
|
||||
if (numpad === undefined) throw new Error("Undefined keysym for key \"" + key + "\"");
|
||||
if (key in DOMKeyTable) throw new Error("Duplicate entry for key \"" + key + "\"");
|
||||
DOMKeyTable[key] = [standard, standard, standard, numpad];
|
||||
}
|
||||
|
||||
// 2.2. Modifier Keys
|
||||
// 3.2. Modifier Keys
|
||||
|
||||
addLeftRight("Alt", KeyTable.XK_Alt_L, KeyTable.XK_Alt_R);
|
||||
addStandard("AltGraph", KeyTable.XK_ISO_Level3_Shift);
|
||||
@@ -46,36 +43,39 @@ addStandard("CapsLock", KeyTable.XK_Caps_Lock);
|
||||
addLeftRight("Control", KeyTable.XK_Control_L, KeyTable.XK_Control_R);
|
||||
// - Fn
|
||||
// - FnLock
|
||||
addLeftRight("Hyper", KeyTable.XK_Super_L, KeyTable.XK_Super_R);
|
||||
addLeftRight("Meta", KeyTable.XK_Super_L, KeyTable.XK_Super_R);
|
||||
addStandard("NumLock", KeyTable.XK_Num_Lock);
|
||||
addStandard("ScrollLock", KeyTable.XK_Scroll_Lock);
|
||||
addLeftRight("Shift", KeyTable.XK_Shift_L, KeyTable.XK_Shift_R);
|
||||
addLeftRight("Super", KeyTable.XK_Super_L, KeyTable.XK_Super_R);
|
||||
// - Symbol
|
||||
// - SymbolLock
|
||||
// - Hyper
|
||||
// - Super
|
||||
|
||||
// 2.3. Whitespace Keys
|
||||
// 3.3. Whitespace Keys
|
||||
|
||||
addNumpad("Enter", KeyTable.XK_Return, KeyTable.XK_KP_Enter);
|
||||
addStandard("Tab", KeyTable.XK_Tab);
|
||||
addNumpad(" ", KeyTable.XK_space, KeyTable.XK_KP_Space);
|
||||
|
||||
// 2.4. Navigation Keys
|
||||
// 3.4. Navigation Keys
|
||||
|
||||
addNumpad("ArrowDown", KeyTable.XK_Down, KeyTable.XK_KP_Down);
|
||||
addNumpad("ArrowUp", KeyTable.XK_Up, KeyTable.XK_KP_Up);
|
||||
addNumpad("ArrowLeft", KeyTable.XK_Left, KeyTable.XK_KP_Left);
|
||||
addNumpad("ArrowRight", KeyTable.XK_Right, KeyTable.XK_KP_Right);
|
||||
addNumpad("ArrowUp", KeyTable.XK_Up, KeyTable.XK_KP_Up);
|
||||
addNumpad("End", KeyTable.XK_End, KeyTable.XK_KP_End);
|
||||
addNumpad("Home", KeyTable.XK_Home, KeyTable.XK_KP_Home);
|
||||
addNumpad("PageDown", KeyTable.XK_Next, KeyTable.XK_KP_Next);
|
||||
addNumpad("PageUp", KeyTable.XK_Prior, KeyTable.XK_KP_Prior);
|
||||
|
||||
// 2.5. Editing Keys
|
||||
// 3.5. Editing Keys
|
||||
|
||||
addStandard("Backspace", KeyTable.XK_BackSpace);
|
||||
addStandard("Clear", KeyTable.XK_Clear);
|
||||
// Browsers send "Clear" for the numpad 5 without NumLock because
|
||||
// Windows uses VK_Clear for that key. But Unix expects KP_Begin for
|
||||
// that scenario.
|
||||
addNumpad("Clear", KeyTable.XK_Clear, KeyTable.XK_KP_Begin);
|
||||
addStandard("Copy", KeyTable.XF86XK_Copy);
|
||||
// - CrSel
|
||||
addStandard("Cut", KeyTable.XF86XK_Cut);
|
||||
@@ -87,7 +87,7 @@ addStandard("Paste", KeyTable.XF86XK_Paste);
|
||||
addStandard("Redo", KeyTable.XK_Redo);
|
||||
addStandard("Undo", KeyTable.XK_Undo);
|
||||
|
||||
// 2.6. UI Keys
|
||||
// 3.6. UI Keys
|
||||
|
||||
// - Accept
|
||||
// - Again (could just be XK_Redo)
|
||||
@@ -105,7 +105,7 @@ addStandard("Select", KeyTable.XK_Select);
|
||||
addStandard("ZoomIn", KeyTable.XF86XK_ZoomIn);
|
||||
addStandard("ZoomOut", KeyTable.XF86XK_ZoomOut);
|
||||
|
||||
// 2.7. Device Keys
|
||||
// 3.7. Device Keys
|
||||
|
||||
addStandard("BrightnessDown", KeyTable.XF86XK_MonBrightnessDown);
|
||||
addStandard("BrightnessUp", KeyTable.XF86XK_MonBrightnessUp);
|
||||
@@ -118,10 +118,10 @@ addStandard("Hibernate", KeyTable.XF86XK_Hibernate);
|
||||
addStandard("Standby", KeyTable.XF86XK_Standby);
|
||||
addStandard("WakeUp", KeyTable.XF86XK_WakeUp);
|
||||
|
||||
// 2.8. IME and Composition Keys
|
||||
// 3.8. IME and Composition Keys
|
||||
|
||||
addStandard("AllCandidates", KeyTable.XK_MultipleCandidate);
|
||||
addStandard("Alphanumeric", KeyTable.XK_Eisu_Shift); // could also be _Eisu_Toggle
|
||||
addStandard("Alphanumeric", KeyTable.XK_Eisu_toggle);
|
||||
addStandard("CodeInput", KeyTable.XK_Codeinput);
|
||||
addStandard("Compose", KeyTable.XK_Multi_key);
|
||||
addStandard("Convert", KeyTable.XK_Henkan);
|
||||
@@ -139,7 +139,7 @@ addStandard("PreviousCandidate", KeyTable.XK_PreviousCandidate);
|
||||
addStandard("SingleCandidate", KeyTable.XK_SingleCandidate);
|
||||
addStandard("HangulMode", KeyTable.XK_Hangul);
|
||||
addStandard("HanjaMode", KeyTable.XK_Hangul_Hanja);
|
||||
addStandard("JunjuaMode", KeyTable.XK_Hangul_Jeonja);
|
||||
addStandard("JunjaMode", KeyTable.XK_Hangul_Jeonja);
|
||||
addStandard("Eisu", KeyTable.XK_Eisu_toggle);
|
||||
addStandard("Hankaku", KeyTable.XK_Hankaku);
|
||||
addStandard("Hiragana", KeyTable.XK_Hiragana);
|
||||
@@ -149,9 +149,9 @@ addStandard("KanjiMode", KeyTable.XK_Kanji);
|
||||
addStandard("Katakana", KeyTable.XK_Katakana);
|
||||
addStandard("Romaji", KeyTable.XK_Romaji);
|
||||
addStandard("Zenkaku", KeyTable.XK_Zenkaku);
|
||||
addStandard("ZenkakuHanaku", KeyTable.XK_Zenkaku_Hankaku);
|
||||
addStandard("ZenkakuHankaku", KeyTable.XK_Zenkaku_Hankaku);
|
||||
|
||||
// 2.9. General-Purpose Function Keys
|
||||
// 3.9. General-Purpose Function Keys
|
||||
|
||||
addStandard("F1", KeyTable.XK_F1);
|
||||
addStandard("F2", KeyTable.XK_F2);
|
||||
@@ -190,17 +190,19 @@ addStandard("F34", KeyTable.XK_F34);
|
||||
addStandard("F35", KeyTable.XK_F35);
|
||||
// - Soft1...
|
||||
|
||||
// 2.10. Multimedia Keys
|
||||
// 3.10. Multimedia Keys
|
||||
|
||||
// - ChannelDown
|
||||
// - ChannelUp
|
||||
addStandard("Close", KeyTable.XF86XK_Close);
|
||||
addStandard("MailForward", KeyTable.XF86XK_MailForward);
|
||||
addStandard("MailReply", KeyTable.XF86XK_Reply);
|
||||
addStandard("MainSend", KeyTable.XF86XK_Send);
|
||||
addStandard("MailSend", KeyTable.XF86XK_Send);
|
||||
// - MediaClose
|
||||
addStandard("MediaFastForward", KeyTable.XF86XK_AudioForward);
|
||||
addStandard("MediaPause", KeyTable.XF86XK_AudioPause);
|
||||
addStandard("MediaPlay", KeyTable.XF86XK_AudioPlay);
|
||||
// - MediaPlayPause
|
||||
addStandard("MediaRecord", KeyTable.XF86XK_AudioRecord);
|
||||
addStandard("MediaRewind", KeyTable.XF86XK_AudioRewind);
|
||||
addStandard("MediaStop", KeyTable.XF86XK_AudioStop);
|
||||
@@ -212,20 +214,18 @@ addStandard("Print", KeyTable.XK_Print);
|
||||
addStandard("Save", KeyTable.XF86XK_Save);
|
||||
addStandard("SpellCheck", KeyTable.XF86XK_Spell);
|
||||
|
||||
// 2.11. Multimedia Numpad Keys
|
||||
// 3.11. Multimedia Numpad Keys
|
||||
|
||||
// - Key11
|
||||
// - Key12
|
||||
|
||||
// 2.12. Audio Keys
|
||||
// 3.12. Audio Keys
|
||||
|
||||
// - AudioBalanceLeft
|
||||
// - AudioBalanceRight
|
||||
// - AudioBassDown
|
||||
// - AudioBassBoostDown
|
||||
// - AudioBassBoostToggle
|
||||
// - AudioBassBoostUp
|
||||
// - AudioBassUp
|
||||
// - AudioFaderFront
|
||||
// - AudioFaderRear
|
||||
// - AudioSurroundModeNext
|
||||
@@ -239,19 +239,20 @@ addStandard("AudioVolumeMute", KeyTable.XF86XK_AudioMute);
|
||||
// - MicrophoneVolumeUp
|
||||
addStandard("MicrophoneVolumeMute", KeyTable.XF86XK_AudioMicMute);
|
||||
|
||||
// 2.13. Speech Keys
|
||||
// 3.13. Speech Keys
|
||||
|
||||
// - SpeechCorrectionList
|
||||
// - SpeechInputToggle
|
||||
|
||||
// 2.14. Application Keys
|
||||
// 3.14. Application Keys
|
||||
|
||||
addStandard("LaunchCalculator", KeyTable.XF86XK_Calculator);
|
||||
addStandard("LaunchApplication1", KeyTable.XF86XK_MyComputer);
|
||||
addStandard("LaunchApplication2", KeyTable.XF86XK_Calculator);
|
||||
addStandard("LaunchCalendar", KeyTable.XF86XK_Calendar);
|
||||
// - LaunchContacts
|
||||
addStandard("LaunchMail", KeyTable.XF86XK_Mail);
|
||||
addStandard("LaunchMediaPlayer", KeyTable.XF86XK_AudioMedia);
|
||||
addStandard("LaunchMusicPlayer", KeyTable.XF86XK_Music);
|
||||
addStandard("LaunchMyComputer", KeyTable.XF86XK_MyComputer);
|
||||
addStandard("LaunchPhone", KeyTable.XF86XK_Phone);
|
||||
addStandard("LaunchScreenSaver", KeyTable.XF86XK_ScreenSaver);
|
||||
addStandard("LaunchSpreadsheet", KeyTable.XF86XK_Excel);
|
||||
@@ -259,7 +260,7 @@ addStandard("LaunchWebBrowser", KeyTable.XF86XK_WWW);
|
||||
addStandard("LaunchWebCam", KeyTable.XF86XK_WebCam);
|
||||
addStandard("LaunchWordProcessor", KeyTable.XF86XK_Word);
|
||||
|
||||
// 2.15. Browser Keys
|
||||
// 3.15. Browser Keys
|
||||
|
||||
addStandard("BrowserBack", KeyTable.XF86XK_Back);
|
||||
addStandard("BrowserFavorites", KeyTable.XF86XK_Favorites);
|
||||
@@ -269,15 +270,15 @@ addStandard("BrowserRefresh", KeyTable.XF86XK_Refresh);
|
||||
addStandard("BrowserSearch", KeyTable.XF86XK_Search);
|
||||
addStandard("BrowserStop", KeyTable.XF86XK_Stop);
|
||||
|
||||
// 2.16. Mobile Phone Keys
|
||||
// 3.16. Mobile Phone Keys
|
||||
|
||||
// - A whole bunch...
|
||||
|
||||
// 2.17. TV Keys
|
||||
// 3.17. TV Keys
|
||||
|
||||
// - A whole bunch...
|
||||
|
||||
// 2.18. Media Controller Keys
|
||||
// 3.18. Media Controller Keys
|
||||
|
||||
// - A whole bunch...
|
||||
addStandard("Dimmer", KeyTable.XF86XK_BrightnessAdjust);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2017 Pierre Ossman for Cendio AB
|
||||
* Copyright (C) 2018 The noVNC Authors
|
||||
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
||||
*/
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
* See https://www.w3.org/TR/uievents-key/ for possible values.
|
||||
*/
|
||||
|
||||
/* eslint-disable key-spacing */
|
||||
|
||||
export default {
|
||||
|
||||
// 3.1.1.1. Writing System Keys
|
||||
|
||||
@@ -0,0 +1,567 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2020 The noVNC Authors
|
||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||
*
|
||||
* See README.md for usage and integration instructions.
|
||||
*
|
||||
*/
|
||||
|
||||
const GH_NOGESTURE = 0;
|
||||
const GH_ONETAP = 1;
|
||||
const GH_TWOTAP = 2;
|
||||
const GH_THREETAP = 4;
|
||||
const GH_DRAG = 8;
|
||||
const GH_LONGPRESS = 16;
|
||||
const GH_TWODRAG = 32;
|
||||
const GH_PINCH = 64;
|
||||
|
||||
const GH_INITSTATE = 127;
|
||||
|
||||
const GH_MOVE_THRESHOLD = 50;
|
||||
const GH_ANGLE_THRESHOLD = 90; // Degrees
|
||||
|
||||
// Timeout when waiting for gestures (ms)
|
||||
const GH_MULTITOUCH_TIMEOUT = 250;
|
||||
|
||||
// Maximum time between press and release for a tap (ms)
|
||||
const GH_TAP_TIMEOUT = 1000;
|
||||
|
||||
// Timeout when waiting for longpress (ms)
|
||||
const GH_LONGPRESS_TIMEOUT = 1000;
|
||||
|
||||
// Timeout when waiting to decide between PINCH and TWODRAG (ms)
|
||||
const GH_TWOTOUCH_TIMEOUT = 50;
|
||||
|
||||
export default class GestureHandler {
|
||||
constructor() {
|
||||
this._target = null;
|
||||
|
||||
this._state = GH_INITSTATE;
|
||||
|
||||
this._tracked = [];
|
||||
this._ignored = [];
|
||||
|
||||
this._waitingRelease = false;
|
||||
this._releaseStart = 0.0;
|
||||
|
||||
this._longpressTimeoutId = null;
|
||||
this._twoTouchTimeoutId = null;
|
||||
|
||||
this._boundEventHandler = this._eventHandler.bind(this);
|
||||
}
|
||||
|
||||
attach(target) {
|
||||
this.detach();
|
||||
|
||||
this._target = target;
|
||||
this._target.addEventListener('touchstart',
|
||||
this._boundEventHandler);
|
||||
this._target.addEventListener('touchmove',
|
||||
this._boundEventHandler);
|
||||
this._target.addEventListener('touchend',
|
||||
this._boundEventHandler);
|
||||
this._target.addEventListener('touchcancel',
|
||||
this._boundEventHandler);
|
||||
}
|
||||
|
||||
detach() {
|
||||
if (!this._target) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._stopLongpressTimeout();
|
||||
this._stopTwoTouchTimeout();
|
||||
|
||||
this._target.removeEventListener('touchstart',
|
||||
this._boundEventHandler);
|
||||
this._target.removeEventListener('touchmove',
|
||||
this._boundEventHandler);
|
||||
this._target.removeEventListener('touchend',
|
||||
this._boundEventHandler);
|
||||
this._target.removeEventListener('touchcancel',
|
||||
this._boundEventHandler);
|
||||
this._target = null;
|
||||
}
|
||||
|
||||
_eventHandler(e) {
|
||||
let fn;
|
||||
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
switch (e.type) {
|
||||
case 'touchstart':
|
||||
fn = this._touchStart;
|
||||
break;
|
||||
case 'touchmove':
|
||||
fn = this._touchMove;
|
||||
break;
|
||||
case 'touchend':
|
||||
case 'touchcancel':
|
||||
fn = this._touchEnd;
|
||||
break;
|
||||
}
|
||||
|
||||
for (let i = 0; i < e.changedTouches.length; i++) {
|
||||
let touch = e.changedTouches[i];
|
||||
fn.call(this, touch.identifier, touch.clientX, touch.clientY);
|
||||
}
|
||||
}
|
||||
|
||||
_touchStart(id, x, y) {
|
||||
// Ignore any new touches if there is already an active gesture,
|
||||
// or we're in a cleanup state
|
||||
if (this._hasDetectedGesture() || (this._state === GH_NOGESTURE)) {
|
||||
this._ignored.push(id);
|
||||
return;
|
||||
}
|
||||
|
||||
// Did it take too long between touches that we should no longer
|
||||
// consider this a single gesture?
|
||||
if ((this._tracked.length > 0) &&
|
||||
((Date.now() - this._tracked[0].started) > GH_MULTITOUCH_TIMEOUT)) {
|
||||
this._state = GH_NOGESTURE;
|
||||
this._ignored.push(id);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we're waiting for fingers to release then we should no longer
|
||||
// recognize new touches
|
||||
if (this._waitingRelease) {
|
||||
this._state = GH_NOGESTURE;
|
||||
this._ignored.push(id);
|
||||
return;
|
||||
}
|
||||
|
||||
this._tracked.push({
|
||||
id: id,
|
||||
started: Date.now(),
|
||||
active: true,
|
||||
firstX: x,
|
||||
firstY: y,
|
||||
lastX: x,
|
||||
lastY: y,
|
||||
angle: 0
|
||||
});
|
||||
|
||||
switch (this._tracked.length) {
|
||||
case 1:
|
||||
this._startLongpressTimeout();
|
||||
break;
|
||||
|
||||
case 2:
|
||||
this._state &= ~(GH_ONETAP | GH_DRAG | GH_LONGPRESS);
|
||||
this._stopLongpressTimeout();
|
||||
break;
|
||||
|
||||
case 3:
|
||||
this._state &= ~(GH_TWOTAP | GH_TWODRAG | GH_PINCH);
|
||||
break;
|
||||
|
||||
default:
|
||||
this._state = GH_NOGESTURE;
|
||||
}
|
||||
}
|
||||
|
||||
_touchMove(id, x, y) {
|
||||
let touch = this._tracked.find(t => t.id === id);
|
||||
|
||||
// If this is an update for a touch we're not tracking, ignore it
|
||||
if (touch === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the touches last position with the event coordinates
|
||||
touch.lastX = x;
|
||||
touch.lastY = y;
|
||||
|
||||
let deltaX = x - touch.firstX;
|
||||
let deltaY = y - touch.firstY;
|
||||
|
||||
// Update angle when the touch has moved
|
||||
if ((touch.firstX !== touch.lastX) ||
|
||||
(touch.firstY !== touch.lastY)) {
|
||||
touch.angle = Math.atan2(deltaY, deltaX) * 180 / Math.PI;
|
||||
}
|
||||
|
||||
if (!this._hasDetectedGesture()) {
|
||||
// Ignore moves smaller than the minimum threshold
|
||||
if (Math.hypot(deltaX, deltaY) < GH_MOVE_THRESHOLD) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Can't be a tap or long press as we've seen movement
|
||||
this._state &= ~(GH_ONETAP | GH_TWOTAP | GH_THREETAP | GH_LONGPRESS);
|
||||
this._stopLongpressTimeout();
|
||||
|
||||
if (this._tracked.length !== 1) {
|
||||
this._state &= ~(GH_DRAG);
|
||||
}
|
||||
if (this._tracked.length !== 2) {
|
||||
this._state &= ~(GH_TWODRAG | GH_PINCH);
|
||||
}
|
||||
|
||||
// We need to figure out which of our different two touch gestures
|
||||
// this might be
|
||||
if (this._tracked.length === 2) {
|
||||
|
||||
// The other touch is the one where the id doesn't match
|
||||
let prevTouch = this._tracked.find(t => t.id !== id);
|
||||
|
||||
// How far the previous touch point has moved since start
|
||||
let prevDeltaMove = Math.hypot(prevTouch.firstX - prevTouch.lastX,
|
||||
prevTouch.firstY - prevTouch.lastY);
|
||||
|
||||
// We know that the current touch moved far enough,
|
||||
// but unless both touches moved further than their
|
||||
// threshold we don't want to disqualify any gestures
|
||||
if (prevDeltaMove > GH_MOVE_THRESHOLD) {
|
||||
|
||||
// The angle difference between the direction of the touch points
|
||||
let deltaAngle = Math.abs(touch.angle - prevTouch.angle);
|
||||
deltaAngle = Math.abs(((deltaAngle + 180) % 360) - 180);
|
||||
|
||||
// PINCH or TWODRAG can be eliminated depending on the angle
|
||||
if (deltaAngle > GH_ANGLE_THRESHOLD) {
|
||||
this._state &= ~GH_TWODRAG;
|
||||
} else {
|
||||
this._state &= ~GH_PINCH;
|
||||
}
|
||||
|
||||
if (this._isTwoTouchTimeoutRunning()) {
|
||||
this._stopTwoTouchTimeout();
|
||||
}
|
||||
} else if (!this._isTwoTouchTimeoutRunning()) {
|
||||
// We can't determine the gesture right now, let's
|
||||
// wait and see if more events are on their way
|
||||
this._startTwoTouchTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
if (!this._hasDetectedGesture()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._pushEvent('gesturestart');
|
||||
}
|
||||
|
||||
this._pushEvent('gesturemove');
|
||||
}
|
||||
|
||||
_touchEnd(id, x, y) {
|
||||
// Check if this is an ignored touch
|
||||
if (this._ignored.indexOf(id) !== -1) {
|
||||
// Remove this touch from ignored
|
||||
this._ignored.splice(this._ignored.indexOf(id), 1);
|
||||
|
||||
// And reset the state if there are no more touches
|
||||
if ((this._ignored.length === 0) &&
|
||||
(this._tracked.length === 0)) {
|
||||
this._state = GH_INITSTATE;
|
||||
this._waitingRelease = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// We got a touchend before the timer triggered,
|
||||
// this cannot result in a gesture anymore.
|
||||
if (!this._hasDetectedGesture() &&
|
||||
this._isTwoTouchTimeoutRunning()) {
|
||||
this._stopTwoTouchTimeout();
|
||||
this._state = GH_NOGESTURE;
|
||||
}
|
||||
|
||||
// Some gestures don't trigger until a touch is released
|
||||
if (!this._hasDetectedGesture()) {
|
||||
// Can't be a gesture that relies on movement
|
||||
this._state &= ~(GH_DRAG | GH_TWODRAG | GH_PINCH);
|
||||
// Or something that relies on more time
|
||||
this._state &= ~GH_LONGPRESS;
|
||||
this._stopLongpressTimeout();
|
||||
|
||||
if (!this._waitingRelease) {
|
||||
this._releaseStart = Date.now();
|
||||
this._waitingRelease = true;
|
||||
|
||||
// Can't be a tap that requires more touches than we current have
|
||||
switch (this._tracked.length) {
|
||||
case 1:
|
||||
this._state &= ~(GH_TWOTAP | GH_THREETAP);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
this._state &= ~(GH_ONETAP | GH_THREETAP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Waiting for all touches to release? (i.e. some tap)
|
||||
if (this._waitingRelease) {
|
||||
// Were all touches released at roughly the same time?
|
||||
if ((Date.now() - this._releaseStart) > GH_MULTITOUCH_TIMEOUT) {
|
||||
this._state = GH_NOGESTURE;
|
||||
}
|
||||
|
||||
// Did too long time pass between press and release?
|
||||
if (this._tracked.some(t => (Date.now() - t.started) > GH_TAP_TIMEOUT)) {
|
||||
this._state = GH_NOGESTURE;
|
||||
}
|
||||
|
||||
let touch = this._tracked.find(t => t.id === id);
|
||||
touch.active = false;
|
||||
|
||||
// Are we still waiting for more releases?
|
||||
if (this._hasDetectedGesture()) {
|
||||
this._pushEvent('gesturestart');
|
||||
} else {
|
||||
// Have we reached a dead end?
|
||||
if (this._state !== GH_NOGESTURE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this._hasDetectedGesture()) {
|
||||
this._pushEvent('gestureend');
|
||||
}
|
||||
|
||||
// Ignore any remaining touches until they are ended
|
||||
for (let i = 0; i < this._tracked.length; i++) {
|
||||
if (this._tracked[i].active) {
|
||||
this._ignored.push(this._tracked[i].id);
|
||||
}
|
||||
}
|
||||
this._tracked = [];
|
||||
|
||||
this._state = GH_NOGESTURE;
|
||||
|
||||
// Remove this touch from ignored if it's in there
|
||||
if (this._ignored.indexOf(id) !== -1) {
|
||||
this._ignored.splice(this._ignored.indexOf(id), 1);
|
||||
}
|
||||
|
||||
// We reset the state if ignored is empty
|
||||
if ((this._ignored.length === 0)) {
|
||||
this._state = GH_INITSTATE;
|
||||
this._waitingRelease = false;
|
||||
}
|
||||
}
|
||||
|
||||
_hasDetectedGesture() {
|
||||
if (this._state === GH_NOGESTURE) {
|
||||
return false;
|
||||
}
|
||||
// Check to see if the bitmask value is a power of 2
|
||||
// (i.e. only one bit set). If it is, we have a state.
|
||||
if (this._state & (this._state - 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// For taps we also need to have all touches released
|
||||
// before we've fully detected the gesture
|
||||
if (this._state & (GH_ONETAP | GH_TWOTAP | GH_THREETAP)) {
|
||||
if (this._tracked.some(t => t.active)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_startLongpressTimeout() {
|
||||
this._stopLongpressTimeout();
|
||||
this._longpressTimeoutId = setTimeout(() => this._longpressTimeout(),
|
||||
GH_LONGPRESS_TIMEOUT);
|
||||
}
|
||||
|
||||
_stopLongpressTimeout() {
|
||||
clearTimeout(this._longpressTimeoutId);
|
||||
this._longpressTimeoutId = null;
|
||||
}
|
||||
|
||||
_longpressTimeout() {
|
||||
if (this._hasDetectedGesture()) {
|
||||
throw new Error("A longpress gesture failed, conflict with a different gesture");
|
||||
}
|
||||
|
||||
this._state = GH_LONGPRESS;
|
||||
this._pushEvent('gesturestart');
|
||||
}
|
||||
|
||||
_startTwoTouchTimeout() {
|
||||
this._stopTwoTouchTimeout();
|
||||
this._twoTouchTimeoutId = setTimeout(() => this._twoTouchTimeout(),
|
||||
GH_TWOTOUCH_TIMEOUT);
|
||||
}
|
||||
|
||||
_stopTwoTouchTimeout() {
|
||||
clearTimeout(this._twoTouchTimeoutId);
|
||||
this._twoTouchTimeoutId = null;
|
||||
}
|
||||
|
||||
_isTwoTouchTimeoutRunning() {
|
||||
return this._twoTouchTimeoutId !== null;
|
||||
}
|
||||
|
||||
_twoTouchTimeout() {
|
||||
if (this._tracked.length === 0) {
|
||||
throw new Error("A pinch or two drag gesture failed, no tracked touches");
|
||||
}
|
||||
|
||||
// How far each touch point has moved since start
|
||||
let avgM = this._getAverageMovement();
|
||||
let avgMoveH = Math.abs(avgM.x);
|
||||
let avgMoveV = Math.abs(avgM.y);
|
||||
|
||||
// The difference in the distance between where
|
||||
// the touch points started and where they are now
|
||||
let avgD = this._getAverageDistance();
|
||||
let deltaTouchDistance = Math.abs(Math.hypot(avgD.first.x, avgD.first.y) -
|
||||
Math.hypot(avgD.last.x, avgD.last.y));
|
||||
|
||||
if ((avgMoveV < deltaTouchDistance) &&
|
||||
(avgMoveH < deltaTouchDistance)) {
|
||||
this._state = GH_PINCH;
|
||||
} else {
|
||||
this._state = GH_TWODRAG;
|
||||
}
|
||||
|
||||
this._pushEvent('gesturestart');
|
||||
this._pushEvent('gesturemove');
|
||||
}
|
||||
|
||||
_pushEvent(type) {
|
||||
let detail = { type: this._stateToGesture(this._state) };
|
||||
|
||||
// For most gesture events the current (average) position is the
|
||||
// most useful
|
||||
let avg = this._getPosition();
|
||||
let pos = avg.last;
|
||||
|
||||
// However we have a slight distance to detect gestures, so for the
|
||||
// first gesture event we want to use the first positions we saw
|
||||
if (type === 'gesturestart') {
|
||||
pos = avg.first;
|
||||
}
|
||||
|
||||
// For these gestures, we always want the event coordinates
|
||||
// to be where the gesture began, not the current touch location.
|
||||
switch (this._state) {
|
||||
case GH_TWODRAG:
|
||||
case GH_PINCH:
|
||||
pos = avg.first;
|
||||
break;
|
||||
}
|
||||
|
||||
detail['clientX'] = pos.x;
|
||||
detail['clientY'] = pos.y;
|
||||
|
||||
// FIXME: other coordinates?
|
||||
|
||||
// Some gestures also have a magnitude
|
||||
if (this._state === GH_PINCH) {
|
||||
let distance = this._getAverageDistance();
|
||||
if (type === 'gesturestart') {
|
||||
detail['magnitudeX'] = distance.first.x;
|
||||
detail['magnitudeY'] = distance.first.y;
|
||||
} else {
|
||||
detail['magnitudeX'] = distance.last.x;
|
||||
detail['magnitudeY'] = distance.last.y;
|
||||
}
|
||||
} else if (this._state === GH_TWODRAG) {
|
||||
if (type === 'gesturestart') {
|
||||
detail['magnitudeX'] = 0.0;
|
||||
detail['magnitudeY'] = 0.0;
|
||||
} else {
|
||||
let movement = this._getAverageMovement();
|
||||
detail['magnitudeX'] = movement.x;
|
||||
detail['magnitudeY'] = movement.y;
|
||||
}
|
||||
}
|
||||
|
||||
let gev = new CustomEvent(type, { detail: detail });
|
||||
this._target.dispatchEvent(gev);
|
||||
}
|
||||
|
||||
_stateToGesture(state) {
|
||||
switch (state) {
|
||||
case GH_ONETAP:
|
||||
return 'onetap';
|
||||
case GH_TWOTAP:
|
||||
return 'twotap';
|
||||
case GH_THREETAP:
|
||||
return 'threetap';
|
||||
case GH_DRAG:
|
||||
return 'drag';
|
||||
case GH_LONGPRESS:
|
||||
return 'longpress';
|
||||
case GH_TWODRAG:
|
||||
return 'twodrag';
|
||||
case GH_PINCH:
|
||||
return 'pinch';
|
||||
}
|
||||
|
||||
throw new Error("Unknown gesture state: " + state);
|
||||
}
|
||||
|
||||
_getPosition() {
|
||||
if (this._tracked.length === 0) {
|
||||
throw new Error("Failed to get gesture position, no tracked touches");
|
||||
}
|
||||
|
||||
let size = this._tracked.length;
|
||||
let fx = 0, fy = 0, lx = 0, ly = 0;
|
||||
|
||||
for (let i = 0; i < this._tracked.length; i++) {
|
||||
fx += this._tracked[i].firstX;
|
||||
fy += this._tracked[i].firstY;
|
||||
lx += this._tracked[i].lastX;
|
||||
ly += this._tracked[i].lastY;
|
||||
}
|
||||
|
||||
return { first: { x: fx / size,
|
||||
y: fy / size },
|
||||
last: { x: lx / size,
|
||||
y: ly / size } };
|
||||
}
|
||||
|
||||
_getAverageMovement() {
|
||||
if (this._tracked.length === 0) {
|
||||
throw new Error("Failed to get gesture movement, no tracked touches");
|
||||
}
|
||||
|
||||
let totalH, totalV;
|
||||
totalH = totalV = 0;
|
||||
let size = this._tracked.length;
|
||||
|
||||
for (let i = 0; i < this._tracked.length; i++) {
|
||||
totalH += this._tracked[i].lastX - this._tracked[i].firstX;
|
||||
totalV += this._tracked[i].lastY - this._tracked[i].firstY;
|
||||
}
|
||||
|
||||
return { x: totalH / size,
|
||||
y: totalV / size };
|
||||
}
|
||||
|
||||
_getAverageDistance() {
|
||||
if (this._tracked.length === 0) {
|
||||
throw new Error("Failed to get gesture distance, no tracked touches");
|
||||
}
|
||||
|
||||
// Distance between the first and last tracked touches
|
||||
|
||||
let first = this._tracked[0];
|
||||
let last = this._tracked[this._tracked.length - 1];
|
||||
|
||||
let fdx = Math.abs(last.firstX - first.firstX);
|
||||
let fdy = Math.abs(last.firstY - first.firstY);
|
||||
|
||||
let ldx = Math.abs(last.lastX - first.lastX);
|
||||
let ldy = Math.abs(last.lastY - first.lastY);
|
||||
|
||||
return { first: { x: fdx, y: fdy },
|
||||
last: { x: ldx, y: ldy } };
|
||||
}
|
||||
}
|
||||
+140
-181
@@ -1,7 +1,6 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2012 Joel Martin
|
||||
* Copyright (C) 2013 Samuel Mannehed for Cendio AB
|
||||
* Copyright (C) 2019 The noVNC Authors
|
||||
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
||||
*/
|
||||
|
||||
@@ -15,71 +14,52 @@ import * as browser from "../util/browser.js";
|
||||
// Keyboard event handler
|
||||
//
|
||||
|
||||
export default function Keyboard(target) {
|
||||
this._target = target || null;
|
||||
export default class Keyboard {
|
||||
constructor(target) {
|
||||
this._target = target || null;
|
||||
|
||||
this._keyDownList = {}; // List of depressed keys
|
||||
// (even if they are happy)
|
||||
this._pendingKey = null; // Key waiting for keypress
|
||||
this._keyDownList = {}; // List of depressed keys
|
||||
// (even if they are happy)
|
||||
this._altGrArmed = false; // Windows AltGr detection
|
||||
|
||||
// keep these here so we can refer to them later
|
||||
this._eventHandlers = {
|
||||
'keyup': this._handleKeyUp.bind(this),
|
||||
'keydown': this._handleKeyDown.bind(this),
|
||||
'keypress': this._handleKeyPress.bind(this),
|
||||
'blur': this._allKeysUp.bind(this)
|
||||
};
|
||||
};
|
||||
// keep these here so we can refer to them later
|
||||
this._eventHandlers = {
|
||||
'keyup': this._handleKeyUp.bind(this),
|
||||
'keydown': this._handleKeyDown.bind(this),
|
||||
'blur': this._allKeysUp.bind(this),
|
||||
};
|
||||
|
||||
Keyboard.prototype = {
|
||||
// ===== EVENT HANDLERS =====
|
||||
// ===== EVENT HANDLERS =====
|
||||
|
||||
onkeyevent: function () {}, // Handler for key press/release
|
||||
this.onkeyevent = () => {}; // Handler for key press/release
|
||||
}
|
||||
|
||||
// ===== PRIVATE METHODS =====
|
||||
|
||||
_sendKeyEvent: function (keysym, code, down) {
|
||||
_sendKeyEvent(keysym, code, down) {
|
||||
if (down) {
|
||||
this._keyDownList[code] = keysym;
|
||||
} else {
|
||||
// Do we really think this key is down?
|
||||
if (!(code in this._keyDownList)) {
|
||||
return;
|
||||
}
|
||||
delete this._keyDownList[code];
|
||||
}
|
||||
|
||||
Log.Debug("onkeyevent " + (down ? "down" : "up") +
|
||||
", keysym: " + keysym, ", code: " + code);
|
||||
|
||||
// Windows sends CtrlLeft+AltRight when you press
|
||||
// AltGraph, which tends to confuse the hell out of
|
||||
// remote systems. Fake a release of these keys until
|
||||
// there is a way to detect AltGraph properly.
|
||||
var fakeAltGraph = false;
|
||||
if (down && browser.isWindows()) {
|
||||
if ((code !== 'ControlLeft') &&
|
||||
(code !== 'AltRight') &&
|
||||
('ControlLeft' in this._keyDownList) &&
|
||||
('AltRight' in this._keyDownList)) {
|
||||
fakeAltGraph = true;
|
||||
this.onkeyevent(this._keyDownList['AltRight'],
|
||||
'AltRight', false);
|
||||
this.onkeyevent(this._keyDownList['ControlLeft'],
|
||||
'ControlLeft', false);
|
||||
}
|
||||
}
|
||||
|
||||
this.onkeyevent(keysym, code, down);
|
||||
}
|
||||
|
||||
if (fakeAltGraph) {
|
||||
this.onkeyevent(this._keyDownList['ControlLeft'],
|
||||
'ControlLeft', true);
|
||||
this.onkeyevent(this._keyDownList['AltRight'],
|
||||
'AltRight', true);
|
||||
}
|
||||
},
|
||||
|
||||
_getKeyCode: function (e) {
|
||||
var code = KeyboardUtil.getKeycode(e);
|
||||
_getKeyCode(e) {
|
||||
const code = KeyboardUtil.getKeycode(e);
|
||||
if (code !== 'Unidentified') {
|
||||
return code;
|
||||
}
|
||||
|
||||
// Unstable, but we don't have anything else to go on
|
||||
// (don't use it for 'keypress' events thought since
|
||||
// WebKit sets it to the same as charCode)
|
||||
if (e.keyCode && (e.type !== 'keypress')) {
|
||||
if (e.keyCode) {
|
||||
// 229 is used for composition events
|
||||
if (e.keyCode !== 229) {
|
||||
return 'Platform' + e.keyCode;
|
||||
@@ -94,26 +74,46 @@ Keyboard.prototype = {
|
||||
return e.keyIdentifier;
|
||||
}
|
||||
|
||||
var codepoint = parseInt(e.keyIdentifier.substr(2), 16);
|
||||
var char = String.fromCharCode(codepoint);
|
||||
// Some implementations fail to uppercase the symbols
|
||||
char = char.toUpperCase();
|
||||
const codepoint = parseInt(e.keyIdentifier.substr(2), 16);
|
||||
const char = String.fromCharCode(codepoint).toUpperCase();
|
||||
|
||||
return 'Platform' + char.charCodeAt();
|
||||
}
|
||||
|
||||
return 'Unidentified';
|
||||
},
|
||||
}
|
||||
|
||||
_handleKeyDown: function (e) {
|
||||
var code = this._getKeyCode(e);
|
||||
var keysym = KeyboardUtil.getKeysym(e);
|
||||
_handleKeyDown(e) {
|
||||
const code = this._getKeyCode(e);
|
||||
let keysym = KeyboardUtil.getKeysym(e);
|
||||
|
||||
// Windows doesn't have a proper AltGr, but handles it using
|
||||
// fake Ctrl+Alt. However the remote end might not be Windows,
|
||||
// so we need to merge those in to a single AltGr event. We
|
||||
// detect this case by seeing the two key events directly after
|
||||
// each other with a very short time between them (<50ms).
|
||||
if (this._altGrArmed) {
|
||||
this._altGrArmed = false;
|
||||
clearTimeout(this._altGrTimeout);
|
||||
|
||||
if ((code === "AltRight") &&
|
||||
((e.timeStamp - this._altGrCtrlTime) < 50)) {
|
||||
// FIXME: We fail to detect this if either Ctrl key is
|
||||
// first manually pressed as Windows then no
|
||||
// longer sends the fake Ctrl down event. It
|
||||
// does however happily send real Ctrl events
|
||||
// even when AltGr is already down. Some
|
||||
// browsers detect this for us though and set the
|
||||
// key to "AltGraph".
|
||||
keysym = KeyTable.XK_ISO_Level3_Shift;
|
||||
} else {
|
||||
this._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true);
|
||||
}
|
||||
}
|
||||
|
||||
// We cannot handle keys we cannot track, but we also need
|
||||
// to deal with virtual keyboards which omit key info
|
||||
// (iOS omits tracking info on keyup events, which forces us to
|
||||
// special treat that platform here)
|
||||
if ((code === 'Unidentified') || browser.isIOS()) {
|
||||
if (code === 'Unidentified') {
|
||||
if (keysym) {
|
||||
// If it's a virtual keyboard then it should be
|
||||
// sufficient to just send press and release right
|
||||
@@ -130,20 +130,20 @@ Keyboard.prototype = {
|
||||
// keys around a bit to make things more sane for the remote
|
||||
// server. This method is used by RealVNC and TigerVNC (and
|
||||
// possibly others).
|
||||
if (browser.isMac()) {
|
||||
if (browser.isMac() || browser.isIOS()) {
|
||||
switch (keysym) {
|
||||
case KeyTable.XK_Super_L:
|
||||
keysym = KeyTable.XK_Alt_L;
|
||||
break;
|
||||
case KeyTable.XK_Super_R:
|
||||
keysym = KeyTable.XK_Super_L;
|
||||
break;
|
||||
case KeyTable.XK_Alt_L:
|
||||
keysym = KeyTable.XK_Mode_switch;
|
||||
break;
|
||||
case KeyTable.XK_Alt_R:
|
||||
keysym = KeyTable.XK_ISO_Level3_Shift;
|
||||
break;
|
||||
case KeyTable.XK_Super_L:
|
||||
keysym = KeyTable.XK_Alt_L;
|
||||
break;
|
||||
case KeyTable.XK_Super_R:
|
||||
keysym = KeyTable.XK_Super_L;
|
||||
break;
|
||||
case KeyTable.XK_Alt_L:
|
||||
keysym = KeyTable.XK_Mode_switch;
|
||||
break;
|
||||
case KeyTable.XK_Alt_R:
|
||||
keysym = KeyTable.XK_ISO_Level3_Shift;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,158 +157,117 @@ Keyboard.prototype = {
|
||||
// state change events. That gets extra confusing for CapsLock
|
||||
// which toggles on each press, but not on release. So pretend
|
||||
// it was a quick press and release of the button.
|
||||
if (browser.isMac() && (code === 'CapsLock')) {
|
||||
if ((browser.isMac() || browser.isIOS()) && (code === 'CapsLock')) {
|
||||
this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', true);
|
||||
this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', false);
|
||||
stopEvent(e);
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is a legacy browser then we'll need to wait for
|
||||
// a keypress event as well
|
||||
// (IE and Edge has a broken KeyboardEvent.key, so we can't
|
||||
// just check for the presence of that field)
|
||||
if (!keysym && (!e.key || browser.isIE() || browser.isEdge())) {
|
||||
this._pendingKey = code;
|
||||
// However we might not get a keypress event if the key
|
||||
// is non-printable, which needs some special fallback
|
||||
// handling
|
||||
setTimeout(this._handleKeyPressTimeout.bind(this), 10, e);
|
||||
// Windows doesn't send proper key releases for a bunch of
|
||||
// Japanese IM keys so we have to fake the release right away
|
||||
const jpBadKeys = [ KeyTable.XK_Zenkaku_Hankaku,
|
||||
KeyTable.XK_Eisu_toggle,
|
||||
KeyTable.XK_Katakana,
|
||||
KeyTable.XK_Hiragana,
|
||||
KeyTable.XK_Romaji ];
|
||||
if (browser.isWindows() && jpBadKeys.includes(keysym)) {
|
||||
this._sendKeyEvent(keysym, code, true);
|
||||
this._sendKeyEvent(keysym, code, false);
|
||||
stopEvent(e);
|
||||
return;
|
||||
}
|
||||
|
||||
this._pendingKey = null;
|
||||
stopEvent(e);
|
||||
|
||||
this._keyDownList[code] = keysym;
|
||||
// Possible start of AltGr sequence? (see above)
|
||||
if ((code === "ControlLeft") && browser.isWindows() &&
|
||||
!("ControlLeft" in this._keyDownList)) {
|
||||
this._altGrArmed = true;
|
||||
this._altGrTimeout = setTimeout(this._handleAltGrTimeout.bind(this), 100);
|
||||
this._altGrCtrlTime = e.timeStamp;
|
||||
return;
|
||||
}
|
||||
|
||||
this._sendKeyEvent(keysym, code, true);
|
||||
},
|
||||
}
|
||||
|
||||
// Legacy event for browsers without code/key
|
||||
_handleKeyPress: function (e) {
|
||||
_handleKeyUp(e) {
|
||||
stopEvent(e);
|
||||
|
||||
// Are we expecting a keypress?
|
||||
if (this._pendingKey === null) {
|
||||
return;
|
||||
const code = this._getKeyCode(e);
|
||||
|
||||
// We can't get a release in the middle of an AltGr sequence, so
|
||||
// abort that detection
|
||||
if (this._altGrArmed) {
|
||||
this._altGrArmed = false;
|
||||
clearTimeout(this._altGrTimeout);
|
||||
this._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true);
|
||||
}
|
||||
|
||||
var code = this._getKeyCode(e);
|
||||
var keysym = KeyboardUtil.getKeysym(e);
|
||||
|
||||
// The key we were waiting for?
|
||||
if ((code !== 'Unidentified') && (code != this._pendingKey)) {
|
||||
return;
|
||||
}
|
||||
|
||||
code = this._pendingKey;
|
||||
this._pendingKey = null;
|
||||
|
||||
if (!keysym) {
|
||||
Log.Info('keypress with no keysym:', e);
|
||||
return;
|
||||
}
|
||||
|
||||
this._keyDownList[code] = keysym;
|
||||
|
||||
this._sendKeyEvent(keysym, code, true);
|
||||
},
|
||||
_handleKeyPressTimeout: function (e) {
|
||||
// Did someone manage to sort out the key already?
|
||||
if (this._pendingKey === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var code, keysym;
|
||||
|
||||
code = this._pendingKey;
|
||||
this._pendingKey = null;
|
||||
|
||||
// We have no way of knowing the proper keysym with the
|
||||
// information given, but the following are true for most
|
||||
// layouts
|
||||
if ((e.keyCode >= 0x30) && (e.keyCode <= 0x39)) {
|
||||
// Digit
|
||||
keysym = e.keyCode;
|
||||
} else if ((e.keyCode >= 0x41) && (e.keyCode <= 0x5a)) {
|
||||
// Character (A-Z)
|
||||
var char = String.fromCharCode(e.keyCode);
|
||||
// A feeble attempt at the correct case
|
||||
if (e.shiftKey)
|
||||
char = char.toUpperCase();
|
||||
else
|
||||
char = char.toLowerCase();
|
||||
keysym = char.charCodeAt();
|
||||
} else {
|
||||
// Unknown, give up
|
||||
keysym = 0;
|
||||
}
|
||||
|
||||
this._keyDownList[code] = keysym;
|
||||
|
||||
this._sendKeyEvent(keysym, code, true);
|
||||
},
|
||||
|
||||
_handleKeyUp: function (e) {
|
||||
stopEvent(e);
|
||||
|
||||
var code = this._getKeyCode(e);
|
||||
|
||||
// See comment in _handleKeyDown()
|
||||
if (browser.isMac() && (code === 'CapsLock')) {
|
||||
if ((browser.isMac() || browser.isIOS()) && (code === 'CapsLock')) {
|
||||
this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', true);
|
||||
this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Do we really think this key is down?
|
||||
if (!(code in this._keyDownList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._sendKeyEvent(this._keyDownList[code], code, false);
|
||||
|
||||
delete this._keyDownList[code];
|
||||
},
|
||||
// Windows has a rather nasty bug where it won't send key
|
||||
// release events for a Shift button if the other Shift is still
|
||||
// pressed
|
||||
if (browser.isWindows() && ((code === 'ShiftLeft') ||
|
||||
(code === 'ShiftRight'))) {
|
||||
if ('ShiftRight' in this._keyDownList) {
|
||||
this._sendKeyEvent(this._keyDownList['ShiftRight'],
|
||||
'ShiftRight', false);
|
||||
}
|
||||
if ('ShiftLeft' in this._keyDownList) {
|
||||
this._sendKeyEvent(this._keyDownList['ShiftLeft'],
|
||||
'ShiftLeft', false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_allKeysUp: function () {
|
||||
_handleAltGrTimeout() {
|
||||
this._altGrArmed = false;
|
||||
clearTimeout(this._altGrTimeout);
|
||||
this._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true);
|
||||
}
|
||||
|
||||
_allKeysUp() {
|
||||
Log.Debug(">> Keyboard.allKeysUp");
|
||||
for (var code in this._keyDownList) {
|
||||
for (let code in this._keyDownList) {
|
||||
this._sendKeyEvent(this._keyDownList[code], code, false);
|
||||
};
|
||||
this._keyDownList = {};
|
||||
}
|
||||
Log.Debug("<< Keyboard.allKeysUp");
|
||||
},
|
||||
}
|
||||
|
||||
// ===== PUBLIC METHODS =====
|
||||
|
||||
grab: function () {
|
||||
grab() {
|
||||
//Log.Debug(">> Keyboard.grab");
|
||||
var c = this._target;
|
||||
|
||||
c.addEventListener('keydown', this._eventHandlers.keydown);
|
||||
c.addEventListener('keyup', this._eventHandlers.keyup);
|
||||
c.addEventListener('keypress', this._eventHandlers.keypress);
|
||||
this._target.addEventListener('keydown', this._eventHandlers.keydown);
|
||||
this._target.addEventListener('keyup', this._eventHandlers.keyup);
|
||||
|
||||
// Release (key up) if window loses focus
|
||||
window.addEventListener('blur', this._eventHandlers.blur);
|
||||
|
||||
//Log.Debug("<< Keyboard.grab");
|
||||
},
|
||||
}
|
||||
|
||||
ungrab: function () {
|
||||
ungrab() {
|
||||
//Log.Debug(">> Keyboard.ungrab");
|
||||
var c = this._target;
|
||||
|
||||
c.removeEventListener('keydown', this._eventHandlers.keydown);
|
||||
c.removeEventListener('keyup', this._eventHandlers.keyup);
|
||||
c.removeEventListener('keypress', this._eventHandlers.keypress);
|
||||
this._target.removeEventListener('keydown', this._eventHandlers.keydown);
|
||||
this._target.removeEventListener('keyup', this._eventHandlers.keyup);
|
||||
window.removeEventListener('blur', this._eventHandlers.blur);
|
||||
|
||||
// Release (key up) all keys that are in a down state
|
||||
this._allKeysUp();
|
||||
|
||||
//Log.Debug(">> Keyboard.ungrab");
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/* eslint-disable key-spacing */
|
||||
|
||||
export default {
|
||||
XK_VoidSymbol: 0xffffff, /* Void symbol */
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
/* Functions at the bottom */
|
||||
|
||||
var codepoints = {
|
||||
const codepoints = {
|
||||
0x0100: 0x03c0, // XK_Amacron
|
||||
0x0101: 0x03e0, // XK_amacron
|
||||
0x0102: 0x01c3, // XK_Abreve
|
||||
@@ -670,14 +670,14 @@ var codepoints = {
|
||||
};
|
||||
|
||||
export default {
|
||||
lookup : function(u) {
|
||||
lookup(u) {
|
||||
// Latin-1 is one-to-one mapping
|
||||
if ((u >= 0x20) && (u <= 0xff)) {
|
||||
return u;
|
||||
}
|
||||
|
||||
// Lookup table (fairly random)
|
||||
var keysym = codepoints[u];
|
||||
const keysym = codepoints[u];
|
||||
if (keysym !== undefined) {
|
||||
return keysym;
|
||||
}
|
||||
|
||||
@@ -1,280 +0,0 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2012 Joel Martin
|
||||
* Copyright (C) 2013 Samuel Mannehed for Cendio AB
|
||||
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
||||
*/
|
||||
|
||||
import * as Log from '../util/logging.js';
|
||||
import { isTouchDevice } from '../util/browser.js';
|
||||
import { setCapture, stopEvent, getPointerEvent } from '../util/events.js';
|
||||
|
||||
var WHEEL_STEP = 10; // Delta threshold for a mouse wheel step
|
||||
var WHEEL_STEP_TIMEOUT = 50; // ms
|
||||
var WHEEL_LINE_HEIGHT = 19;
|
||||
|
||||
export default function Mouse(target) {
|
||||
this._target = target || document;
|
||||
|
||||
this._doubleClickTimer = null;
|
||||
this._lastTouchPos = null;
|
||||
|
||||
this._pos = null;
|
||||
this._wheelStepXTimer = null;
|
||||
this._wheelStepYTimer = null;
|
||||
this._accumulatedWheelDeltaX = 0;
|
||||
this._accumulatedWheelDeltaY = 0;
|
||||
|
||||
this._eventHandlers = {
|
||||
'mousedown': this._handleMouseDown.bind(this),
|
||||
'mouseup': this._handleMouseUp.bind(this),
|
||||
'mousemove': this._handleMouseMove.bind(this),
|
||||
'mousewheel': this._handleMouseWheel.bind(this),
|
||||
'mousedisable': this._handleMouseDisable.bind(this)
|
||||
};
|
||||
};
|
||||
|
||||
Mouse.prototype = {
|
||||
// ===== PROPERTIES =====
|
||||
|
||||
touchButton: 1, // Button mask (1, 2, 4) for touch devices (0 means ignore clicks)
|
||||
|
||||
// ===== EVENT HANDLERS =====
|
||||
|
||||
onmousebutton: function () {}, // Handler for mouse button click/release
|
||||
onmousemove: function () {}, // Handler for mouse movement
|
||||
|
||||
// ===== PRIVATE METHODS =====
|
||||
|
||||
_resetDoubleClickTimer: function () {
|
||||
this._doubleClickTimer = null;
|
||||
},
|
||||
|
||||
_handleMouseButton: function (e, down) {
|
||||
this._updateMousePosition(e);
|
||||
var pos = this._pos;
|
||||
|
||||
var bmask;
|
||||
if (e.touches || e.changedTouches) {
|
||||
// Touch device
|
||||
|
||||
// When two touches occur within 500 ms of each other and are
|
||||
// close enough together a double click is triggered.
|
||||
if (down == 1) {
|
||||
if (this._doubleClickTimer === null) {
|
||||
this._lastTouchPos = pos;
|
||||
} else {
|
||||
clearTimeout(this._doubleClickTimer);
|
||||
|
||||
// When the distance between the two touches is small enough
|
||||
// force the position of the latter touch to the position of
|
||||
// the first.
|
||||
|
||||
var xs = this._lastTouchPos.x - pos.x;
|
||||
var ys = this._lastTouchPos.y - pos.y;
|
||||
var d = Math.sqrt((xs * xs) + (ys * ys));
|
||||
|
||||
// The goal is to trigger on a certain physical width, the
|
||||
// devicePixelRatio brings us a bit closer but is not optimal.
|
||||
var threshold = 20 * (window.devicePixelRatio || 1);
|
||||
if (d < threshold) {
|
||||
pos = this._lastTouchPos;
|
||||
}
|
||||
}
|
||||
this._doubleClickTimer = setTimeout(this._resetDoubleClickTimer.bind(this), 500);
|
||||
}
|
||||
bmask = this.touchButton;
|
||||
// If bmask is set
|
||||
} else if (e.which) {
|
||||
/* everything except IE */
|
||||
bmask = 1 << e.button;
|
||||
} else {
|
||||
/* IE including 9 */
|
||||
bmask = (e.button & 0x1) + // Left
|
||||
(e.button & 0x2) * 2 + // Right
|
||||
(e.button & 0x4) / 2; // Middle
|
||||
}
|
||||
|
||||
Log.Debug("onmousebutton " + (down ? "down" : "up") +
|
||||
", x: " + pos.x + ", y: " + pos.y + ", bmask: " + bmask);
|
||||
this.onmousebutton(pos.x, pos.y, down, bmask);
|
||||
|
||||
stopEvent(e);
|
||||
},
|
||||
|
||||
_handleMouseDown: function (e) {
|
||||
// Touch events have implicit capture
|
||||
if (e.type === "mousedown") {
|
||||
setCapture(this._target);
|
||||
}
|
||||
|
||||
this._handleMouseButton(e, 1);
|
||||
},
|
||||
|
||||
_handleMouseUp: function (e) {
|
||||
this._handleMouseButton(e, 0);
|
||||
},
|
||||
|
||||
// Mouse wheel events are sent in steps over VNC. This means that the VNC
|
||||
// protocol can't handle a wheel event with specific distance or speed.
|
||||
// Therefor, if we get a lot of small mouse wheel events we combine them.
|
||||
_generateWheelStepX: function () {
|
||||
|
||||
if (this._accumulatedWheelDeltaX < 0) {
|
||||
this.onmousebutton(this._pos.x, this._pos.y, 1, 1 << 5);
|
||||
this.onmousebutton(this._pos.x, this._pos.y, 0, 1 << 5);
|
||||
} else if (this._accumulatedWheelDeltaX > 0) {
|
||||
this.onmousebutton(this._pos.x, this._pos.y, 1, 1 << 6);
|
||||
this.onmousebutton(this._pos.x, this._pos.y, 0, 1 << 6);
|
||||
}
|
||||
|
||||
this._accumulatedWheelDeltaX = 0;
|
||||
},
|
||||
|
||||
_generateWheelStepY: function () {
|
||||
|
||||
if (this._accumulatedWheelDeltaY < 0) {
|
||||
this.onmousebutton(this._pos.x, this._pos.y, 1, 1 << 3);
|
||||
this.onmousebutton(this._pos.x, this._pos.y, 0, 1 << 3);
|
||||
} else if (this._accumulatedWheelDeltaY > 0) {
|
||||
this.onmousebutton(this._pos.x, this._pos.y, 1, 1 << 4);
|
||||
this.onmousebutton(this._pos.x, this._pos.y, 0, 1 << 4);
|
||||
}
|
||||
|
||||
this._accumulatedWheelDeltaY = 0;
|
||||
},
|
||||
|
||||
_resetWheelStepTimers: function () {
|
||||
window.clearTimeout(this._wheelStepXTimer);
|
||||
window.clearTimeout(this._wheelStepYTimer);
|
||||
this._wheelStepXTimer = null;
|
||||
this._wheelStepYTimer = null;
|
||||
},
|
||||
|
||||
_handleMouseWheel: function (e) {
|
||||
this._resetWheelStepTimers();
|
||||
|
||||
this._updateMousePosition(e);
|
||||
|
||||
var dX = e.deltaX;
|
||||
var dY = e.deltaY;
|
||||
|
||||
// Pixel units unless it's non-zero.
|
||||
// Note that if deltamode is line or page won't matter since we aren't
|
||||
// sending the mouse wheel delta to the server anyway.
|
||||
// The difference between pixel and line can be important however since
|
||||
// we have a threshold that can be smaller than the line height.
|
||||
if (e.deltaMode !== 0) {
|
||||
dX *= WHEEL_LINE_HEIGHT;
|
||||
dY *= WHEEL_LINE_HEIGHT;
|
||||
}
|
||||
|
||||
this._accumulatedWheelDeltaX += dX;
|
||||
this._accumulatedWheelDeltaY += dY;
|
||||
|
||||
// Generate a mouse wheel step event when the accumulated delta
|
||||
// for one of the axes is large enough.
|
||||
// Small delta events that do not pass the threshold get sent
|
||||
// after a timeout.
|
||||
if (Math.abs(this._accumulatedWheelDeltaX) > WHEEL_STEP) {
|
||||
this._generateWheelStepX();
|
||||
} else {
|
||||
this._wheelStepXTimer =
|
||||
window.setTimeout(this._generateWheelStepX.bind(this),
|
||||
WHEEL_STEP_TIMEOUT);
|
||||
}
|
||||
if (Math.abs(this._accumulatedWheelDeltaY) > WHEEL_STEP) {
|
||||
this._generateWheelStepY();
|
||||
} else {
|
||||
this._wheelStepYTimer =
|
||||
window.setTimeout(this._generateWheelStepY.bind(this),
|
||||
WHEEL_STEP_TIMEOUT);
|
||||
}
|
||||
|
||||
stopEvent(e);
|
||||
},
|
||||
|
||||
_handleMouseMove: function (e) {
|
||||
this._updateMousePosition(e);
|
||||
this.onmousemove(this._pos.x, this._pos.y);
|
||||
stopEvent(e);
|
||||
},
|
||||
|
||||
_handleMouseDisable: function (e) {
|
||||
/*
|
||||
* Stop propagation if inside canvas area
|
||||
* Note: This is only needed for the 'click' event as it fails
|
||||
* to fire properly for the target element so we have
|
||||
* to listen on the document element instead.
|
||||
*/
|
||||
if (e.target == this._target) {
|
||||
stopEvent(e);
|
||||
}
|
||||
},
|
||||
|
||||
// Update coordinates relative to target
|
||||
_updateMousePosition: function(e) {
|
||||
e = getPointerEvent(e);
|
||||
var bounds = this._target.getBoundingClientRect();
|
||||
var x, y;
|
||||
// Clip to target bounds
|
||||
if (e.clientX < bounds.left) {
|
||||
x = 0;
|
||||
} else if (e.clientX >= bounds.right) {
|
||||
x = bounds.width - 1;
|
||||
} else {
|
||||
x = e.clientX - bounds.left;
|
||||
}
|
||||
if (e.clientY < bounds.top) {
|
||||
y = 0;
|
||||
} else if (e.clientY >= bounds.bottom) {
|
||||
y = bounds.height - 1;
|
||||
} else {
|
||||
y = e.clientY - bounds.top;
|
||||
}
|
||||
this._pos = {x:x, y:y};
|
||||
},
|
||||
|
||||
// ===== PUBLIC METHODS =====
|
||||
|
||||
grab: function () {
|
||||
var c = this._target;
|
||||
|
||||
if (isTouchDevice) {
|
||||
c.addEventListener('touchstart', this._eventHandlers.mousedown);
|
||||
c.addEventListener('touchend', this._eventHandlers.mouseup);
|
||||
c.addEventListener('touchmove', this._eventHandlers.mousemove);
|
||||
}
|
||||
c.addEventListener('mousedown', this._eventHandlers.mousedown);
|
||||
c.addEventListener('mouseup', this._eventHandlers.mouseup);
|
||||
c.addEventListener('mousemove', this._eventHandlers.mousemove);
|
||||
c.addEventListener('wheel', this._eventHandlers.mousewheel);
|
||||
|
||||
/* Prevent middle-click pasting (see above for why we bind to document) */
|
||||
document.addEventListener('click', this._eventHandlers.mousedisable);
|
||||
|
||||
/* preventDefault() on mousedown doesn't stop this event for some
|
||||
reason so we have to explicitly block it */
|
||||
c.addEventListener('contextmenu', this._eventHandlers.mousedisable);
|
||||
},
|
||||
|
||||
ungrab: function () {
|
||||
var c = this._target;
|
||||
|
||||
this._resetWheelStepTimers();
|
||||
|
||||
if (isTouchDevice) {
|
||||
c.removeEventListener('touchstart', this._eventHandlers.mousedown);
|
||||
c.removeEventListener('touchend', this._eventHandlers.mouseup);
|
||||
c.removeEventListener('touchmove', this._eventHandlers.mousemove);
|
||||
}
|
||||
c.removeEventListener('mousedown', this._eventHandlers.mousedown);
|
||||
c.removeEventListener('mouseup', this._eventHandlers.mouseup);
|
||||
c.removeEventListener('mousemove', this._eventHandlers.mousemove);
|
||||
c.removeEventListener('wheel', this._eventHandlers.mousewheel);
|
||||
|
||||
document.removeEventListener('click', this._eventHandlers.mousedisable);
|
||||
|
||||
c.removeEventListener('contextmenu', this._eventHandlers.mousedisable);
|
||||
}
|
||||
};
|
||||
+60
-36
@@ -6,7 +6,7 @@ import DOMKeyTable from "./domkeytable.js";
|
||||
import * as browser from "../util/browser.js";
|
||||
|
||||
// Get 'KeyboardEvent.code', handling legacy browsers
|
||||
export function getKeycode(evt){
|
||||
export function getKeycode(evt) {
|
||||
// Are we getting proper key identifiers?
|
||||
// (unfortunately Firefox and Chrome are crappy here and gives
|
||||
// us an empty string on some platforms, rather than leaving it
|
||||
@@ -22,10 +22,9 @@ export function getKeycode(evt){
|
||||
}
|
||||
|
||||
// The de-facto standard is to use Windows Virtual-Key codes
|
||||
// in the 'keyCode' field for non-printable characters. However
|
||||
// Webkit sets it to the same as charCode in 'keypress' events.
|
||||
if ((evt.type !== 'keypress') && (evt.keyCode in vkeys)) {
|
||||
var code = vkeys[evt.keyCode];
|
||||
// in the 'keyCode' field for non-printable characters
|
||||
if (evt.keyCode in vkeys) {
|
||||
let code = vkeys[evt.keyCode];
|
||||
|
||||
// macOS has messed up this code for some reason
|
||||
if (browser.isMac() && (code === 'ContextMenu')) {
|
||||
@@ -69,29 +68,11 @@ export function getKeycode(evt){
|
||||
export function getKey(evt) {
|
||||
// Are we getting a proper key value?
|
||||
if (evt.key !== undefined) {
|
||||
// IE and Edge use some ancient version of the spec
|
||||
// https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/8860571/
|
||||
switch (evt.key) {
|
||||
case 'Spacebar': return ' ';
|
||||
case 'Esc': return 'Escape';
|
||||
case 'Scroll': return 'ScrollLock';
|
||||
case 'Win': return 'Meta';
|
||||
case 'Apps': return 'ContextMenu';
|
||||
case 'Up': return 'ArrowUp';
|
||||
case 'Left': return 'ArrowLeft';
|
||||
case 'Right': return 'ArrowRight';
|
||||
case 'Down': return 'ArrowDown';
|
||||
case 'Del': return 'Delete';
|
||||
case 'Divide': return '/';
|
||||
case 'Multiply': return '*';
|
||||
case 'Subtract': return '-';
|
||||
case 'Add': return '+';
|
||||
case 'Decimal': return evt.char;
|
||||
}
|
||||
|
||||
// Mozilla isn't fully in sync with the spec yet
|
||||
switch (evt.key) {
|
||||
case 'OS': return 'Meta';
|
||||
case 'LaunchMyComputer': return 'LaunchApplication1';
|
||||
case 'LaunchCalculator': return 'LaunchApplication2';
|
||||
}
|
||||
|
||||
// iOS leaks some OS names
|
||||
@@ -103,15 +84,16 @@ export function getKey(evt) {
|
||||
case 'UIKeyInputEscape': return 'Escape';
|
||||
}
|
||||
|
||||
// IE and Edge have broken handling of AltGraph so we cannot
|
||||
// trust them for printable characters
|
||||
if ((evt.key.length !== 1) || (!browser.isIE() && !browser.isEdge())) {
|
||||
return evt.key;
|
||||
// Broken behaviour in Chrome
|
||||
if ((evt.key === '\x00') && (evt.code === 'NumpadDecimal')) {
|
||||
return 'Delete';
|
||||
}
|
||||
|
||||
return evt.key;
|
||||
}
|
||||
|
||||
// Try to deduce it based on the physical key
|
||||
var code = getKeycode(evt);
|
||||
const code = getKeycode(evt);
|
||||
if (code in fixedkeys) {
|
||||
return fixedkeys[code];
|
||||
}
|
||||
@@ -126,8 +108,8 @@ export function getKey(evt) {
|
||||
}
|
||||
|
||||
// Get the most reliable keysym value we can get from a key event
|
||||
export function getKeysym(evt){
|
||||
var key = getKey(evt);
|
||||
export function getKeysym(evt) {
|
||||
const key = getKey(evt);
|
||||
|
||||
if (key === 'Unidentified') {
|
||||
return null;
|
||||
@@ -135,30 +117,72 @@ export function getKeysym(evt){
|
||||
|
||||
// First look up special keys
|
||||
if (key in DOMKeyTable) {
|
||||
var location = evt.location;
|
||||
let location = evt.location;
|
||||
|
||||
// Safari screws up location for the right cmd key
|
||||
if ((key === 'Meta') && (location === 0)) {
|
||||
location = 2;
|
||||
}
|
||||
|
||||
// And for Clear
|
||||
if ((key === 'Clear') && (location === 3)) {
|
||||
let code = getKeycode(evt);
|
||||
if (code === 'NumLock') {
|
||||
location = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((location === undefined) || (location > 3)) {
|
||||
location = 0;
|
||||
}
|
||||
|
||||
// The original Meta key now gets confused with the Windows key
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=1020141
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1232918
|
||||
if (key === 'Meta') {
|
||||
let code = getKeycode(evt);
|
||||
if (code === 'AltLeft') {
|
||||
return KeyTable.XK_Meta_L;
|
||||
} else if (code === 'AltRight') {
|
||||
return KeyTable.XK_Meta_R;
|
||||
}
|
||||
}
|
||||
|
||||
// macOS has Clear instead of NumLock, but the remote system is
|
||||
// probably not macOS, so lying here is probably best...
|
||||
if (key === 'Clear') {
|
||||
let code = getKeycode(evt);
|
||||
if (code === 'NumLock') {
|
||||
return KeyTable.XK_Num_Lock;
|
||||
}
|
||||
}
|
||||
|
||||
// Windows sends alternating symbols for some keys when using a
|
||||
// Japanese layout. We have no way of synchronising with the IM
|
||||
// running on the remote system, so we send some combined keysym
|
||||
// instead and hope for the best.
|
||||
if (browser.isWindows()) {
|
||||
switch (key) {
|
||||
case 'Zenkaku':
|
||||
case 'Hankaku':
|
||||
return KeyTable.XK_Zenkaku_Hankaku;
|
||||
case 'Romaji':
|
||||
case 'KanaMode':
|
||||
return KeyTable.XK_Romaji;
|
||||
}
|
||||
}
|
||||
|
||||
return DOMKeyTable[key][location];
|
||||
}
|
||||
|
||||
// Now we need to look at the Unicode symbol instead
|
||||
|
||||
var codepoint;
|
||||
|
||||
// Special key? (FIXME: Should have been caught earlier)
|
||||
if (key.length !== 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
codepoint = key.charCodeAt();
|
||||
const codepoint = key.charCodeAt();
|
||||
if (codepoint) {
|
||||
return keysyms.lookup(codepoint);
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2017 Pierre Ossman for Cendio AB
|
||||
* Copyright (C) 2018 The noVNC Authors
|
||||
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* This file is auto-generated from keymaps.csv on 2017-05-31 16:20
|
||||
* Database checksum sha256(92fd165507f2a3b8c5b3fa56e425d45788dbcb98cf067a307527d91ce22cab94)
|
||||
* This file is auto-generated from keymaps.csv
|
||||
* Database checksum sha256(76d68c10e97d37fe2ea459e210125ae41796253fb217e900bf2983ade13a7920)
|
||||
* To re-generate, run:
|
||||
* keymap-gen --lang=js code-map keymaps.csv html atset1
|
||||
* keymap-gen code-map --lang=js keymaps.csv html atset1
|
||||
*/
|
||||
export default {
|
||||
"Again": 0xe005, /* html:Again (Again) -> linux:129 (KEY_AGAIN) -> atset1:57349 */
|
||||
@@ -111,6 +111,8 @@ export default {
|
||||
"KeyX": 0x2d, /* html:KeyX (KeyX) -> linux:45 (KEY_X) -> atset1:45 */
|
||||
"KeyY": 0x15, /* html:KeyY (KeyY) -> linux:21 (KEY_Y) -> atset1:21 */
|
||||
"KeyZ": 0x2c, /* html:KeyZ (KeyZ) -> linux:44 (KEY_Z) -> atset1:44 */
|
||||
"Lang1": 0x72, /* html:Lang1 (Lang1) -> linux:122 (KEY_HANGEUL) -> atset1:114 */
|
||||
"Lang2": 0x71, /* html:Lang2 (Lang2) -> linux:123 (KEY_HANJA) -> atset1:113 */
|
||||
"Lang3": 0x78, /* html:Lang3 (Lang3) -> linux:90 (KEY_KATAKANA) -> atset1:120 */
|
||||
"Lang4": 0x77, /* html:Lang4 (Lang4) -> linux:91 (KEY_HIRAGANA) -> atset1:119 */
|
||||
"Lang5": 0x76, /* html:Lang5 (Lang5) -> linux:85 (KEY_ZENKAKUHANKAKU) -> atset1:118 */
|
||||
|
||||
+2001
-1553
File diff suppressed because it is too large
Load Diff
+63
-29
@@ -1,15 +1,17 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2012 Joel Martin
|
||||
* Copyright (C) 2019 The noVNC Authors
|
||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||
*
|
||||
* See README.md for usage and integration instructions.
|
||||
*
|
||||
* Browser feature support detection
|
||||
*/
|
||||
|
||||
import * as Log from './logging.js';
|
||||
|
||||
// Touch detection
|
||||
export var isTouchDevice = ('ontouchstart' in document.documentElement) ||
|
||||
export let isTouchDevice = ('ontouchstart' in document.documentElement) ||
|
||||
// requried for Chrome debugger
|
||||
(document.ontouchstart !== undefined) ||
|
||||
// required for MS Surface
|
||||
@@ -20,42 +22,65 @@ window.addEventListener('touchstart', function onFirstTouch() {
|
||||
window.removeEventListener('touchstart', onFirstTouch, false);
|
||||
}, false);
|
||||
|
||||
var _cursor_uris_supported = null;
|
||||
|
||||
export function supportsCursorURIs () {
|
||||
if (_cursor_uris_supported === null) {
|
||||
try {
|
||||
var target = document.createElement('canvas');
|
||||
target.style.cursor = 'url("data:image/x-icon;base64,AAACAAEACAgAAAIAAgA4AQAAFgAAACgAAAAIAAAAEAAAAAEAIAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAAAAAAAAAAAAAAAAAAAAA==") 2 2, default';
|
||||
// The goal is to find a certain physical width, the devicePixelRatio
|
||||
// brings us a bit closer but is not optimal.
|
||||
export let dragThreshold = 10 * (window.devicePixelRatio || 1);
|
||||
|
||||
if (target.style.cursor) {
|
||||
Log.Info("Data URI scheme cursor supported");
|
||||
_cursor_uris_supported = true;
|
||||
} else {
|
||||
Log.Warn("Data URI scheme cursor not supported");
|
||||
_cursor_uris_supported = false;
|
||||
}
|
||||
} catch (exc) {
|
||||
Log.Error("Data URI scheme cursor test exception: " + exc);
|
||||
_cursor_uris_supported = false;
|
||||
}
|
||||
let _supportsCursorURIs = false;
|
||||
|
||||
try {
|
||||
const target = document.createElement('canvas');
|
||||
target.style.cursor = 'url("data:image/x-icon;base64,AAACAAEACAgAAAIAAgA4AQAAFgAAACgAAAAIAAAAEAAAAAEAIAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAAAAAAAAAAAAAAAAAAAAA==") 2 2, default';
|
||||
|
||||
if (target.style.cursor.indexOf("url") === 0) {
|
||||
Log.Info("Data URI scheme cursor supported");
|
||||
_supportsCursorURIs = true;
|
||||
} else {
|
||||
Log.Warn("Data URI scheme cursor not supported");
|
||||
}
|
||||
} catch (exc) {
|
||||
Log.Error("Data URI scheme cursor test exception: " + exc);
|
||||
}
|
||||
|
||||
return _cursor_uris_supported;
|
||||
};
|
||||
export const supportsCursorURIs = _supportsCursorURIs;
|
||||
|
||||
let _hasScrollbarGutter = true;
|
||||
try {
|
||||
// Create invisible container
|
||||
const container = document.createElement('div');
|
||||
container.style.visibility = 'hidden';
|
||||
container.style.overflow = 'scroll'; // forcing scrollbars
|
||||
document.body.appendChild(container);
|
||||
|
||||
// Create a div and place it in the container
|
||||
const child = document.createElement('div');
|
||||
container.appendChild(child);
|
||||
|
||||
// Calculate the difference between the container's full width
|
||||
// and the child's width - the difference is the scrollbars
|
||||
const scrollbarWidth = (container.offsetWidth - child.offsetWidth);
|
||||
|
||||
// Clean up
|
||||
container.parentNode.removeChild(container);
|
||||
|
||||
_hasScrollbarGutter = scrollbarWidth != 0;
|
||||
} catch (exc) {
|
||||
Log.Error("Scrollbar test exception: " + exc);
|
||||
}
|
||||
export const hasScrollbarGutter = _hasScrollbarGutter;
|
||||
|
||||
/*
|
||||
* The functions for detection of platforms and browsers below are exported
|
||||
* but the use of these should be minimized as much as possible.
|
||||
*
|
||||
* It's better to use feature detection than platform detection.
|
||||
*/
|
||||
|
||||
export function isMac() {
|
||||
return navigator && !!(/mac/i).exec(navigator.platform);
|
||||
}
|
||||
|
||||
export function isIE() {
|
||||
return navigator && !!(/trident/i).exec(navigator.userAgent);
|
||||
}
|
||||
|
||||
export function isEdge() {
|
||||
return navigator && !!(/edge/i).exec(navigator.userAgent);
|
||||
}
|
||||
|
||||
export function isWindows() {
|
||||
return navigator && !!(/win/i).exec(navigator.platform);
|
||||
}
|
||||
@@ -67,3 +92,12 @@ export function isIOS() {
|
||||
!!(/ipod/i).exec(navigator.platform));
|
||||
}
|
||||
|
||||
export function isSafari() {
|
||||
return navigator && (navigator.userAgent.indexOf('Safari') !== -1 &&
|
||||
navigator.userAgent.indexOf('Chrome') === -1);
|
||||
}
|
||||
|
||||
export function isFirefox() {
|
||||
return navigator && !!(/firefox/i).exec(navigator.userAgent);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2019 The noVNC Authors
|
||||
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
||||
*/
|
||||
|
||||
import { supportsCursorURIs, isTouchDevice } from './browser.js';
|
||||
|
||||
const useFallback = !supportsCursorURIs || isTouchDevice;
|
||||
|
||||
export default class Cursor {
|
||||
constructor() {
|
||||
this._target = null;
|
||||
|
||||
this._canvas = document.createElement('canvas');
|
||||
|
||||
if (useFallback) {
|
||||
this._canvas.style.position = 'fixed';
|
||||
this._canvas.style.zIndex = '65535';
|
||||
this._canvas.style.pointerEvents = 'none';
|
||||
// Can't use "display" because of Firefox bug #1445997
|
||||
this._canvas.style.visibility = 'hidden';
|
||||
}
|
||||
|
||||
this._position = { x: 0, y: 0 };
|
||||
this._hotSpot = { x: 0, y: 0 };
|
||||
|
||||
this._eventHandlers = {
|
||||
'mouseover': this._handleMouseOver.bind(this),
|
||||
'mouseleave': this._handleMouseLeave.bind(this),
|
||||
'mousemove': this._handleMouseMove.bind(this),
|
||||
'mouseup': this._handleMouseUp.bind(this),
|
||||
};
|
||||
}
|
||||
|
||||
attach(target) {
|
||||
if (this._target) {
|
||||
this.detach();
|
||||
}
|
||||
|
||||
this._target = target;
|
||||
|
||||
if (useFallback) {
|
||||
document.body.appendChild(this._canvas);
|
||||
|
||||
const options = { capture: true, passive: true };
|
||||
this._target.addEventListener('mouseover', this._eventHandlers.mouseover, options);
|
||||
this._target.addEventListener('mouseleave', this._eventHandlers.mouseleave, options);
|
||||
this._target.addEventListener('mousemove', this._eventHandlers.mousemove, options);
|
||||
this._target.addEventListener('mouseup', this._eventHandlers.mouseup, options);
|
||||
}
|
||||
|
||||
this.clear();
|
||||
}
|
||||
|
||||
detach() {
|
||||
if (!this._target) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (useFallback) {
|
||||
const options = { capture: true, passive: true };
|
||||
this._target.removeEventListener('mouseover', this._eventHandlers.mouseover, options);
|
||||
this._target.removeEventListener('mouseleave', this._eventHandlers.mouseleave, options);
|
||||
this._target.removeEventListener('mousemove', this._eventHandlers.mousemove, options);
|
||||
this._target.removeEventListener('mouseup', this._eventHandlers.mouseup, options);
|
||||
|
||||
document.body.removeChild(this._canvas);
|
||||
}
|
||||
|
||||
this._target = null;
|
||||
}
|
||||
|
||||
change(rgba, hotx, hoty, w, h) {
|
||||
if ((w === 0) || (h === 0)) {
|
||||
this.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
this._position.x = this._position.x + this._hotSpot.x - hotx;
|
||||
this._position.y = this._position.y + this._hotSpot.y - hoty;
|
||||
this._hotSpot.x = hotx;
|
||||
this._hotSpot.y = hoty;
|
||||
|
||||
let ctx = this._canvas.getContext('2d');
|
||||
|
||||
this._canvas.width = w;
|
||||
this._canvas.height = h;
|
||||
|
||||
let img = new ImageData(new Uint8ClampedArray(rgba), w, h);
|
||||
ctx.clearRect(0, 0, w, h);
|
||||
ctx.putImageData(img, 0, 0);
|
||||
|
||||
if (useFallback) {
|
||||
this._updatePosition();
|
||||
} else {
|
||||
let url = this._canvas.toDataURL();
|
||||
this._target.style.cursor = 'url(' + url + ')' + hotx + ' ' + hoty + ', default';
|
||||
}
|
||||
}
|
||||
|
||||
clear() {
|
||||
this._target.style.cursor = 'none';
|
||||
this._canvas.width = 0;
|
||||
this._canvas.height = 0;
|
||||
this._position.x = this._position.x + this._hotSpot.x;
|
||||
this._position.y = this._position.y + this._hotSpot.y;
|
||||
this._hotSpot.x = 0;
|
||||
this._hotSpot.y = 0;
|
||||
}
|
||||
|
||||
// Mouse events might be emulated, this allows
|
||||
// moving the cursor in such cases
|
||||
move(clientX, clientY) {
|
||||
if (!useFallback) {
|
||||
return;
|
||||
}
|
||||
// clientX/clientY are relative the _visual viewport_,
|
||||
// but our position is relative the _layout viewport_,
|
||||
// so try to compensate when we can
|
||||
if (window.visualViewport) {
|
||||
this._position.x = clientX + window.visualViewport.offsetLeft;
|
||||
this._position.y = clientY + window.visualViewport.offsetTop;
|
||||
} else {
|
||||
this._position.x = clientX;
|
||||
this._position.y = clientY;
|
||||
}
|
||||
this._updatePosition();
|
||||
let target = document.elementFromPoint(clientX, clientY);
|
||||
this._updateVisibility(target);
|
||||
}
|
||||
|
||||
_handleMouseOver(event) {
|
||||
// This event could be because we're entering the target, or
|
||||
// moving around amongst its sub elements. Let the move handler
|
||||
// sort things out.
|
||||
this._handleMouseMove(event);
|
||||
}
|
||||
|
||||
_handleMouseLeave(event) {
|
||||
// Check if we should show the cursor on the element we are leaving to
|
||||
this._updateVisibility(event.relatedTarget);
|
||||
}
|
||||
|
||||
_handleMouseMove(event) {
|
||||
this._updateVisibility(event.target);
|
||||
|
||||
this._position.x = event.clientX - this._hotSpot.x;
|
||||
this._position.y = event.clientY - this._hotSpot.y;
|
||||
|
||||
this._updatePosition();
|
||||
}
|
||||
|
||||
_handleMouseUp(event) {
|
||||
// We might get this event because of a drag operation that
|
||||
// moved outside of the target. Check what's under the cursor
|
||||
// now and adjust visibility based on that.
|
||||
let target = document.elementFromPoint(event.clientX, event.clientY);
|
||||
this._updateVisibility(target);
|
||||
|
||||
// Captures end with a mouseup but we can't know the event order of
|
||||
// mouseup vs releaseCapture.
|
||||
//
|
||||
// In the cases when releaseCapture comes first, the code above is
|
||||
// enough.
|
||||
//
|
||||
// In the cases when the mouseup comes first, we need wait for the
|
||||
// browser to flush all events and then check again if the cursor
|
||||
// should be visible.
|
||||
if (this._captureIsActive()) {
|
||||
window.setTimeout(() => {
|
||||
// We might have detached at this point
|
||||
if (!this._target) {
|
||||
return;
|
||||
}
|
||||
// Refresh the target from elementFromPoint since queued events
|
||||
// might have altered the DOM
|
||||
target = document.elementFromPoint(event.clientX,
|
||||
event.clientY);
|
||||
this._updateVisibility(target);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
_showCursor() {
|
||||
if (this._canvas.style.visibility === 'hidden') {
|
||||
this._canvas.style.visibility = '';
|
||||
}
|
||||
}
|
||||
|
||||
_hideCursor() {
|
||||
if (this._canvas.style.visibility !== 'hidden') {
|
||||
this._canvas.style.visibility = 'hidden';
|
||||
}
|
||||
}
|
||||
|
||||
// Should we currently display the cursor?
|
||||
// (i.e. are we over the target, or a child of the target without a
|
||||
// different cursor set)
|
||||
_shouldShowCursor(target) {
|
||||
if (!target) {
|
||||
return false;
|
||||
}
|
||||
// Easy case
|
||||
if (target === this._target) {
|
||||
return true;
|
||||
}
|
||||
// Other part of the DOM?
|
||||
if (!this._target.contains(target)) {
|
||||
return false;
|
||||
}
|
||||
// Has the child its own cursor?
|
||||
// FIXME: How can we tell that a sub element has an
|
||||
// explicit "cursor: none;"?
|
||||
if (window.getComputedStyle(target).cursor !== 'none') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
_updateVisibility(target) {
|
||||
// When the cursor target has capture we want to show the cursor.
|
||||
// So, if a capture is active - look at the captured element instead.
|
||||
if (this._captureIsActive()) {
|
||||
target = document.captureElement;
|
||||
}
|
||||
if (this._shouldShowCursor(target)) {
|
||||
this._showCursor();
|
||||
} else {
|
||||
this._hideCursor();
|
||||
}
|
||||
}
|
||||
|
||||
_updatePosition() {
|
||||
this._canvas.style.left = this._position.x + "px";
|
||||
this._canvas.style.top = this._position.y + "px";
|
||||
}
|
||||
|
||||
_captureIsActive() {
|
||||
return document.captureElement &&
|
||||
document.documentElement.contains(document.captureElement);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2020 The noVNC Authors
|
||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||
*
|
||||
* See README.md for usage and integration instructions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* HTML element utility functions
|
||||
*/
|
||||
|
||||
export function clientToElement(x, y, elem) {
|
||||
const bounds = elem.getBoundingClientRect();
|
||||
let pos = { x: 0, y: 0 };
|
||||
// Clip to target bounds
|
||||
if (x < bounds.left) {
|
||||
pos.x = 0;
|
||||
} else if (x >= bounds.right) {
|
||||
pos.x = bounds.width - 1;
|
||||
} else {
|
||||
pos.x = x - bounds.left;
|
||||
}
|
||||
if (y < bounds.top) {
|
||||
pos.y = 0;
|
||||
} else if (y >= bounds.bottom) {
|
||||
pos.y = bounds.height - 1;
|
||||
} else {
|
||||
pos.y = y - bounds.top;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
+58
-58
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2012 Joel Martin
|
||||
* Copyright (C) 2018 The noVNC Authors
|
||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||
*
|
||||
* See README.md for usage and integration instructions.
|
||||
@@ -10,27 +10,32 @@
|
||||
* Cross-browser event and position routines
|
||||
*/
|
||||
|
||||
export function getPointerEvent (e) {
|
||||
export function getPointerEvent(e) {
|
||||
return e.changedTouches ? e.changedTouches[0] : e.touches ? e.touches[0] : e;
|
||||
};
|
||||
}
|
||||
|
||||
export function stopEvent (e) {
|
||||
export function stopEvent(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
};
|
||||
}
|
||||
|
||||
// Emulate Element.setCapture() when not supported
|
||||
var _captureRecursion = false;
|
||||
var _captureElem = null;
|
||||
let _captureRecursion = false;
|
||||
let _elementForUnflushedEvents = null;
|
||||
document.captureElement = null;
|
||||
function _captureProxy(e) {
|
||||
// Recursion protection as we'll see our own event
|
||||
if (_captureRecursion) return;
|
||||
|
||||
// Clone the event as we cannot dispatch an already dispatched event
|
||||
var newEv = new e.constructor(e.type, e);
|
||||
const newEv = new e.constructor(e.type, e);
|
||||
|
||||
_captureRecursion = true;
|
||||
_captureElem.dispatchEvent(newEv);
|
||||
if (document.captureElement) {
|
||||
document.captureElement.dispatchEvent(newEv);
|
||||
} else {
|
||||
_elementForUnflushedEvents.dispatchEvent(newEv);
|
||||
}
|
||||
_captureRecursion = false;
|
||||
|
||||
// Avoid double events
|
||||
@@ -45,94 +50,89 @@ function _captureProxy(e) {
|
||||
if (e.type === "mouseup") {
|
||||
releaseCapture();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Follow cursor style of target element
|
||||
function _captureElemChanged() {
|
||||
var captureElem = document.getElementById("noVNC_mouse_capture_elem");
|
||||
captureElem.style.cursor = window.getComputedStyle(_captureElem).cursor;
|
||||
};
|
||||
var _captureObserver = new MutationObserver(_captureElemChanged);
|
||||
function _capturedElemChanged() {
|
||||
const proxyElem = document.getElementById("noVNC_mouse_capture_elem");
|
||||
proxyElem.style.cursor = window.getComputedStyle(document.captureElement).cursor;
|
||||
}
|
||||
|
||||
var _captureIndex = 0;
|
||||
const _captureObserver = new MutationObserver(_capturedElemChanged);
|
||||
|
||||
export function setCapture (elem) {
|
||||
if (elem.setCapture) {
|
||||
|
||||
elem.setCapture();
|
||||
|
||||
// IE releases capture on 'click' events which might not trigger
|
||||
elem.addEventListener('mouseup', releaseCapture);
|
||||
export function setCapture(target) {
|
||||
if (target.setCapture) {
|
||||
|
||||
target.setCapture();
|
||||
document.captureElement = target;
|
||||
} else {
|
||||
// Release any existing capture in case this method is
|
||||
// called multiple times without coordination
|
||||
releaseCapture();
|
||||
|
||||
var captureElem = document.getElementById("noVNC_mouse_capture_elem");
|
||||
let proxyElem = document.getElementById("noVNC_mouse_capture_elem");
|
||||
|
||||
if (captureElem === null) {
|
||||
captureElem = document.createElement("div");
|
||||
captureElem.id = "noVNC_mouse_capture_elem";
|
||||
captureElem.style.position = "fixed";
|
||||
captureElem.style.top = "0px";
|
||||
captureElem.style.left = "0px";
|
||||
captureElem.style.width = "100%";
|
||||
captureElem.style.height = "100%";
|
||||
captureElem.style.zIndex = 10000;
|
||||
captureElem.style.display = "none";
|
||||
document.body.appendChild(captureElem);
|
||||
if (proxyElem === null) {
|
||||
proxyElem = document.createElement("div");
|
||||
proxyElem.id = "noVNC_mouse_capture_elem";
|
||||
proxyElem.style.position = "fixed";
|
||||
proxyElem.style.top = "0px";
|
||||
proxyElem.style.left = "0px";
|
||||
proxyElem.style.width = "100%";
|
||||
proxyElem.style.height = "100%";
|
||||
proxyElem.style.zIndex = 10000;
|
||||
proxyElem.style.display = "none";
|
||||
document.body.appendChild(proxyElem);
|
||||
|
||||
// This is to make sure callers don't get confused by having
|
||||
// our blocking element as the target
|
||||
captureElem.addEventListener('contextmenu', _captureProxy);
|
||||
proxyElem.addEventListener('contextmenu', _captureProxy);
|
||||
|
||||
captureElem.addEventListener('mousemove', _captureProxy);
|
||||
captureElem.addEventListener('mouseup', _captureProxy);
|
||||
proxyElem.addEventListener('mousemove', _captureProxy);
|
||||
proxyElem.addEventListener('mouseup', _captureProxy);
|
||||
}
|
||||
|
||||
_captureElem = elem;
|
||||
_captureIndex++;
|
||||
document.captureElement = target;
|
||||
|
||||
// Track cursor and get initial cursor
|
||||
_captureObserver.observe(elem, {attributes:true});
|
||||
_captureElemChanged();
|
||||
_captureObserver.observe(target, {attributes: true});
|
||||
_capturedElemChanged();
|
||||
|
||||
captureElem.style.display = "";
|
||||
proxyElem.style.display = "";
|
||||
|
||||
// We listen to events on window in order to keep tracking if it
|
||||
// happens to leave the viewport
|
||||
window.addEventListener('mousemove', _captureProxy);
|
||||
window.addEventListener('mouseup', _captureProxy);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function releaseCapture () {
|
||||
export function releaseCapture() {
|
||||
if (document.releaseCapture) {
|
||||
|
||||
document.releaseCapture();
|
||||
document.captureElement = null;
|
||||
|
||||
} else {
|
||||
if (!_captureElem) {
|
||||
if (!document.captureElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
// There might be events already queued, so we need to wait for
|
||||
// them to flush. E.g. contextmenu in Microsoft Edge
|
||||
window.setTimeout(function(expected) {
|
||||
// Only clear it if it's the expected grab (i.e. no one
|
||||
// else has initiated a new grab)
|
||||
if (_captureIndex === expected) {
|
||||
_captureElem = null;
|
||||
}
|
||||
}, 0, _captureIndex);
|
||||
// There might be events already queued. The event proxy needs
|
||||
// access to the captured element for these queued events.
|
||||
// E.g. contextmenu (right-click) in Microsoft Edge
|
||||
//
|
||||
// Before removing the capturedElem pointer we save it to a
|
||||
// temporary variable that the unflushed events can use.
|
||||
_elementForUnflushedEvents = document.captureElement;
|
||||
document.captureElement = null;
|
||||
|
||||
_captureObserver.disconnect();
|
||||
|
||||
var captureElem = document.getElementById("noVNC_mouse_capture_elem");
|
||||
captureElem.style.display = "none";
|
||||
const proxyElem = document.getElementById("noVNC_mouse_capture_elem");
|
||||
proxyElem.style.display = "none";
|
||||
|
||||
window.removeEventListener('mousemove', _captureProxy);
|
||||
window.removeEventListener('mouseup', _captureProxy);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+25
-30
@@ -1,40 +1,35 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright 2017 Pierre Ossman for Cendio AB
|
||||
* Copyright (C) 2019 The noVNC Authors
|
||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||
*
|
||||
* See README.md for usage and integration instructions.
|
||||
*/
|
||||
|
||||
var EventTargetMixin = {
|
||||
_listeners: null,
|
||||
export default class EventTargetMixin {
|
||||
constructor() {
|
||||
this._listeners = new Map();
|
||||
}
|
||||
|
||||
addEventListener: function(type, callback) {
|
||||
if (!this._listeners) {
|
||||
this._listeners = new Map();
|
||||
}
|
||||
if (!this._listeners.has(type)) {
|
||||
this._listeners.set(type, new Set());
|
||||
}
|
||||
this._listeners.get(type).add(callback);
|
||||
},
|
||||
addEventListener(type, callback) {
|
||||
if (!this._listeners.has(type)) {
|
||||
this._listeners.set(type, new Set());
|
||||
}
|
||||
this._listeners.get(type).add(callback);
|
||||
}
|
||||
|
||||
removeEventListener: function(type, callback) {
|
||||
if (!this._listeners || !this._listeners.has(type)) {
|
||||
return;
|
||||
}
|
||||
this._listeners.get(type).delete(callback);
|
||||
},
|
||||
removeEventListener(type, callback) {
|
||||
if (this._listeners.has(type)) {
|
||||
this._listeners.get(type).delete(callback);
|
||||
}
|
||||
}
|
||||
|
||||
dispatchEvent: function(event) {
|
||||
if (!this._listeners || !this._listeners.has(event.type)) {
|
||||
return true;
|
||||
}
|
||||
this._listeners.get(event.type).forEach(function (callback) {
|
||||
callback.call(this, event);
|
||||
}, this);
|
||||
return !event.defaultPrevented;
|
||||
},
|
||||
};
|
||||
|
||||
export default EventTargetMixin;
|
||||
dispatchEvent(event) {
|
||||
if (!this._listeners.has(event.type)) {
|
||||
return true;
|
||||
}
|
||||
this._listeners.get(event.type)
|
||||
.forEach(callback => callback.call(this, event));
|
||||
return !event.defaultPrevented;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2020 The noVNC Authors
|
||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||
*
|
||||
* See README.md for usage and integration instructions.
|
||||
*/
|
||||
|
||||
export function toUnsigned32bit(toConvert) {
|
||||
return toConvert >>> 0;
|
||||
}
|
||||
|
||||
export function toSigned32bit(toConvert) {
|
||||
return toConvert | 0;
|
||||
}
|
||||
+21
-16
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2012 Joel Martin
|
||||
* Copyright (C) 2019 The noVNC Authors
|
||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||
*
|
||||
* See README.md for usage and integration instructions.
|
||||
@@ -10,22 +10,24 @@
|
||||
* Logging/debug routines
|
||||
*/
|
||||
|
||||
var _log_level = 'warn';
|
||||
let _logLevel = 'warn';
|
||||
|
||||
var Debug = function (msg) {};
|
||||
var Info = function (msg) {};
|
||||
var Warn = function (msg) {};
|
||||
var Error = function (msg) {};
|
||||
let Debug = () => {};
|
||||
let Info = () => {};
|
||||
let Warn = () => {};
|
||||
let Error = () => {};
|
||||
|
||||
export function init_logging (level) {
|
||||
export function initLogging(level) {
|
||||
if (typeof level === 'undefined') {
|
||||
level = _log_level;
|
||||
level = _logLevel;
|
||||
} else {
|
||||
_log_level = level;
|
||||
_logLevel = level;
|
||||
}
|
||||
|
||||
Debug = Info = Warn = Error = function (msg) {};
|
||||
Debug = Info = Warn = Error = () => {};
|
||||
|
||||
if (typeof window.console !== "undefined") {
|
||||
/* eslint-disable no-console, no-fallthrough */
|
||||
switch (level) {
|
||||
case 'debug':
|
||||
Debug = console.debug.bind(window.console);
|
||||
@@ -38,14 +40,17 @@ export function init_logging (level) {
|
||||
case 'none':
|
||||
break;
|
||||
default:
|
||||
throw new Error("invalid logging type '" + level + "'");
|
||||
throw new window.Error("invalid logging type '" + level + "'");
|
||||
}
|
||||
/* eslint-enable no-console, no-fallthrough */
|
||||
}
|
||||
};
|
||||
export function get_logging () {
|
||||
return _log_level;
|
||||
};
|
||||
}
|
||||
|
||||
export function getLogging() {
|
||||
return _logLevel;
|
||||
}
|
||||
|
||||
export { Debug, Info, Warn, Error };
|
||||
|
||||
// Initialize logging level
|
||||
init_logging();
|
||||
initLogging();
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright 2017 Pierre Ossman for noVNC
|
||||
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
||||
*/
|
||||
|
||||
/* Polyfills to provide new APIs in old browsers */
|
||||
|
||||
/* Object.assign() (taken from MDN) */
|
||||
if (typeof Object.assign != 'function') {
|
||||
// Must be writable: true, enumerable: false, configurable: true
|
||||
Object.defineProperty(Object, "assign", {
|
||||
value: function assign(target, varArgs) { // .length of function is 2
|
||||
'use strict';
|
||||
if (target == null) { // TypeError if undefined or null
|
||||
throw new TypeError('Cannot convert undefined or null to object');
|
||||
}
|
||||
|
||||
var to = Object(target);
|
||||
|
||||
for (var index = 1; index < arguments.length; index++) {
|
||||
var nextSource = arguments[index];
|
||||
|
||||
if (nextSource != null) { // Skip over if undefined or null
|
||||
for (var nextKey in nextSource) {
|
||||
// Avoid bugs when hasOwnProperty is shadowed
|
||||
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
|
||||
to[nextKey] = nextSource[nextKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return to;
|
||||
},
|
||||
writable: true,
|
||||
configurable: true
|
||||
});
|
||||
}
|
||||
|
||||
/* CustomEvent constructor (taken from MDN) */
|
||||
(function () {
|
||||
function CustomEvent ( event, params ) {
|
||||
params = params || { bubbles: false, cancelable: false, detail: undefined };
|
||||
var evt = document.createEvent( 'CustomEvent' );
|
||||
evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
|
||||
return evt;
|
||||
}
|
||||
|
||||
CustomEvent.prototype = window.Event.prototype;
|
||||
|
||||
if (typeof window.CustomEvent !== "function") {
|
||||
window.CustomEvent = CustomEvent;
|
||||
}
|
||||
})();
|
||||
+21
-8
@@ -1,15 +1,28 @@
|
||||
/*
|
||||
* noVNC: HTML5 VNC client
|
||||
* Copyright (C) 2012 Joel Martin
|
||||
* Copyright (C) 2019 The noVNC Authors
|
||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||
*
|
||||
* See README.md for usage and integration instructions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Decode from UTF-8
|
||||
*/
|
||||
export function decodeUTF8 (utf8string) {
|
||||
"use strict";
|
||||
return decodeURIComponent(escape(utf8string));
|
||||
};
|
||||
// Decode from UTF-8
|
||||
export function decodeUTF8(utf8string, allowLatin1=false) {
|
||||
try {
|
||||
return decodeURIComponent(escape(utf8string));
|
||||
} catch (e) {
|
||||
if (e instanceof URIError) {
|
||||
if (allowLatin1) {
|
||||
// If we allow Latin1 we can ignore any decoding fails
|
||||
// and in these cases return the original string
|
||||
return utf8string;
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// Encode to UTF-8
|
||||
export function encodeUTF8(DOMString) {
|
||||
return unescape(encodeURIComponent(DOMString));
|
||||
}
|
||||
|
||||
+212
-175
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
* Websock: high-performance binary WebSockets
|
||||
* Copyright (C) 2012 Joel Martin
|
||||
* Websock: high-performance buffering wrapper
|
||||
* Copyright (C) 2019 The noVNC Authors
|
||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||
*
|
||||
* Websock is similar to the standard WebSocket object but with extra
|
||||
* buffer handling.
|
||||
* Websock is similar to the standard WebSocket / RTCDataChannel object
|
||||
* but with extra buffer handling.
|
||||
*
|
||||
* Websock has built-in receive queue buffering; the message event
|
||||
* does not contain actual data but is simply a notification that
|
||||
@@ -14,143 +14,169 @@
|
||||
|
||||
import * as Log from './util/logging.js';
|
||||
|
||||
export default function Websock() {
|
||||
"use strict";
|
||||
|
||||
this._websocket = null; // WebSocket object
|
||||
|
||||
this._rQi = 0; // Receive queue index
|
||||
this._rQlen = 0; // Next write position in the receive queue
|
||||
this._rQbufferSize = 1024 * 1024 * 4; // Receive queue buffer size (4 MiB)
|
||||
this._rQmax = this._rQbufferSize / 8;
|
||||
// called in init: this._rQ = new Uint8Array(this._rQbufferSize);
|
||||
this._rQ = null; // Receive queue
|
||||
|
||||
this._sQbufferSize = 1024 * 10; // 10 KiB
|
||||
// called in init: this._sQ = new Uint8Array(this._sQbufferSize);
|
||||
this._sQlen = 0;
|
||||
this._sQ = null; // Send queue
|
||||
|
||||
this._eventHandlers = {
|
||||
'message': function () {},
|
||||
'open': function () {},
|
||||
'close': function () {},
|
||||
'error': function () {}
|
||||
};
|
||||
};
|
||||
|
||||
// this has performance issues in some versions Chromium, and
|
||||
// doesn't gain a tremendous amount of performance increase in Firefox
|
||||
// at the moment. It may be valuable to turn it on in the future.
|
||||
var ENABLE_COPYWITHIN = false;
|
||||
const MAX_RQ_GROW_SIZE = 40 * 1024 * 1024; // 40 MiB
|
||||
|
||||
var MAX_RQ_GROW_SIZE = 40 * 1024 * 1024; // 40 MiB
|
||||
// Constants pulled from RTCDataChannelState enum
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel/readyState#RTCDataChannelState_enum
|
||||
const DataChannel = {
|
||||
CONNECTING: "connecting",
|
||||
OPEN: "open",
|
||||
CLOSING: "closing",
|
||||
CLOSED: "closed"
|
||||
};
|
||||
|
||||
var typedArrayToString = (function () {
|
||||
// This is only for PhantomJS, which doesn't like apply-ing
|
||||
// with Typed Arrays
|
||||
try {
|
||||
var arr = new Uint8Array([1, 2, 3]);
|
||||
String.fromCharCode.apply(null, arr);
|
||||
return function (a) { return String.fromCharCode.apply(null, a); };
|
||||
} catch (ex) {
|
||||
return function (a) {
|
||||
return String.fromCharCode.apply(
|
||||
null, Array.prototype.slice.call(a));
|
||||
const ReadyStates = {
|
||||
CONNECTING: [WebSocket.CONNECTING, DataChannel.CONNECTING],
|
||||
OPEN: [WebSocket.OPEN, DataChannel.OPEN],
|
||||
CLOSING: [WebSocket.CLOSING, DataChannel.CLOSING],
|
||||
CLOSED: [WebSocket.CLOSED, DataChannel.CLOSED],
|
||||
};
|
||||
|
||||
// Properties a raw channel must have, WebSocket and RTCDataChannel are two examples
|
||||
const rawChannelProps = [
|
||||
"send",
|
||||
"close",
|
||||
"binaryType",
|
||||
"onerror",
|
||||
"onmessage",
|
||||
"onopen",
|
||||
"protocol",
|
||||
"readyState",
|
||||
];
|
||||
|
||||
export default class Websock {
|
||||
constructor() {
|
||||
this._websocket = null; // WebSocket or RTCDataChannel object
|
||||
|
||||
this._rQi = 0; // Receive queue index
|
||||
this._rQlen = 0; // Next write position in the receive queue
|
||||
this._rQbufferSize = 1024 * 1024 * 4; // Receive queue buffer size (4 MiB)
|
||||
// called in init: this._rQ = new Uint8Array(this._rQbufferSize);
|
||||
this._rQ = null; // Receive queue
|
||||
|
||||
this._sQbufferSize = 1024 * 10; // 10 KiB
|
||||
// called in init: this._sQ = new Uint8Array(this._sQbufferSize);
|
||||
this._sQlen = 0;
|
||||
this._sQ = null; // Send queue
|
||||
|
||||
this._eventHandlers = {
|
||||
message: () => {},
|
||||
open: () => {},
|
||||
close: () => {},
|
||||
error: () => {}
|
||||
};
|
||||
}
|
||||
})();
|
||||
|
||||
Websock.prototype = {
|
||||
// Getters and Setters
|
||||
get_sQ: function () {
|
||||
|
||||
get readyState() {
|
||||
let subState;
|
||||
|
||||
if (this._websocket === null) {
|
||||
return "unused";
|
||||
}
|
||||
|
||||
subState = this._websocket.readyState;
|
||||
|
||||
if (ReadyStates.CONNECTING.includes(subState)) {
|
||||
return "connecting";
|
||||
} else if (ReadyStates.OPEN.includes(subState)) {
|
||||
return "open";
|
||||
} else if (ReadyStates.CLOSING.includes(subState)) {
|
||||
return "closing";
|
||||
} else if (ReadyStates.CLOSED.includes(subState)) {
|
||||
return "closed";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
get sQ() {
|
||||
return this._sQ;
|
||||
},
|
||||
}
|
||||
|
||||
get_rQ: function () {
|
||||
get rQ() {
|
||||
return this._rQ;
|
||||
},
|
||||
}
|
||||
|
||||
get_rQi: function () {
|
||||
get rQi() {
|
||||
return this._rQi;
|
||||
},
|
||||
}
|
||||
|
||||
set_rQi: function (val) {
|
||||
set rQi(val) {
|
||||
this._rQi = val;
|
||||
},
|
||||
}
|
||||
|
||||
// Receive Queue
|
||||
rQlen: function () {
|
||||
get rQlen() {
|
||||
return this._rQlen - this._rQi;
|
||||
},
|
||||
}
|
||||
|
||||
rQpeek8: function () {
|
||||
rQpeek8() {
|
||||
return this._rQ[this._rQi];
|
||||
},
|
||||
}
|
||||
|
||||
rQshift8: function () {
|
||||
return this._rQ[this._rQi++];
|
||||
},
|
||||
rQskipBytes(bytes) {
|
||||
this._rQi += bytes;
|
||||
}
|
||||
|
||||
rQskip8: function () {
|
||||
this._rQi++;
|
||||
},
|
||||
rQshift8() {
|
||||
return this._rQshift(1);
|
||||
}
|
||||
|
||||
rQskipBytes: function (num) {
|
||||
this._rQi += num;
|
||||
},
|
||||
rQshift16() {
|
||||
return this._rQshift(2);
|
||||
}
|
||||
|
||||
rQshift32() {
|
||||
return this._rQshift(4);
|
||||
}
|
||||
|
||||
// TODO(directxman12): test performance with these vs a DataView
|
||||
rQshift16: function () {
|
||||
return (this._rQ[this._rQi++] << 8) +
|
||||
this._rQ[this._rQi++];
|
||||
},
|
||||
_rQshift(bytes) {
|
||||
let res = 0;
|
||||
for (let byte = bytes - 1; byte >= 0; byte--) {
|
||||
res += this._rQ[this._rQi++] << (byte * 8);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
rQshift32: function () {
|
||||
return (this._rQ[this._rQi++] << 24) +
|
||||
(this._rQ[this._rQi++] << 16) +
|
||||
(this._rQ[this._rQi++] << 8) +
|
||||
this._rQ[this._rQi++];
|
||||
},
|
||||
rQshiftStr(len) {
|
||||
if (typeof(len) === 'undefined') { len = this.rQlen; }
|
||||
let str = "";
|
||||
// Handle large arrays in steps to avoid long strings on the stack
|
||||
for (let i = 0; i < len; i += 4096) {
|
||||
let part = this.rQshiftBytes(Math.min(4096, len - i));
|
||||
str += String.fromCharCode.apply(null, part);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
rQshiftStr: function (len) {
|
||||
if (typeof(len) === 'undefined') { len = this.rQlen(); }
|
||||
var arr = new Uint8Array(this._rQ.buffer, this._rQi, len);
|
||||
this._rQi += len;
|
||||
return typedArrayToString(arr);
|
||||
},
|
||||
|
||||
rQshiftBytes: function (len) {
|
||||
if (typeof(len) === 'undefined') { len = this.rQlen(); }
|
||||
rQshiftBytes(len) {
|
||||
if (typeof(len) === 'undefined') { len = this.rQlen; }
|
||||
this._rQi += len;
|
||||
return new Uint8Array(this._rQ.buffer, this._rQi - len, len);
|
||||
},
|
||||
}
|
||||
|
||||
rQshiftTo: function (target, len) {
|
||||
if (len === undefined) { len = this.rQlen(); }
|
||||
rQshiftTo(target, len) {
|
||||
if (len === undefined) { len = this.rQlen; }
|
||||
// TODO: make this just use set with views when using a ArrayBuffer to store the rQ
|
||||
target.set(new Uint8Array(this._rQ.buffer, this._rQi, len));
|
||||
this._rQi += len;
|
||||
},
|
||||
}
|
||||
|
||||
rQwhole: function () {
|
||||
return new Uint8Array(this._rQ.buffer, 0, this._rQlen);
|
||||
},
|
||||
|
||||
rQslice: function (start, end) {
|
||||
if (end) {
|
||||
return new Uint8Array(this._rQ.buffer, this._rQi + start, end - start);
|
||||
} else {
|
||||
return new Uint8Array(this._rQ.buffer, this._rQi + start, this._rQlen - this._rQi - start);
|
||||
}
|
||||
},
|
||||
rQslice(start, end = this.rQlen) {
|
||||
return new Uint8Array(this._rQ.buffer, this._rQi + start, end - start);
|
||||
}
|
||||
|
||||
// Check to see if we must wait for 'num' bytes (default to FBU.bytes)
|
||||
// to be available in the receive queue. Return true if we need to
|
||||
// wait (and possibly print a debug message), otherwise false.
|
||||
rQwait: function (msg, num, goback) {
|
||||
var rQlen = this._rQlen - this._rQi; // Skip rQlen() function call
|
||||
if (rQlen < num) {
|
||||
rQwait(msg, num, goback) {
|
||||
if (this.rQlen < num) {
|
||||
if (goback) {
|
||||
if (this._rQi < goback) {
|
||||
throw new Error("rQwait cannot backup " + goback + " bytes");
|
||||
@@ -160,58 +186,68 @@ Websock.prototype = {
|
||||
return true; // true means need more data
|
||||
}
|
||||
return false;
|
||||
},
|
||||
}
|
||||
|
||||
// Send Queue
|
||||
|
||||
flush: function () {
|
||||
if (this._sQlen > 0 && this._websocket.readyState === WebSocket.OPEN) {
|
||||
this._websocket.send(this._encode_message());
|
||||
flush() {
|
||||
if (this._sQlen > 0 && this.readyState === 'open') {
|
||||
this._websocket.send(this._encodeMessage());
|
||||
this._sQlen = 0;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
send: function (arr) {
|
||||
send(arr) {
|
||||
this._sQ.set(arr, this._sQlen);
|
||||
this._sQlen += arr.length;
|
||||
this.flush();
|
||||
},
|
||||
}
|
||||
|
||||
send_string: function (str) {
|
||||
this.send(str.split('').map(function (chr) {
|
||||
return chr.charCodeAt(0);
|
||||
}));
|
||||
},
|
||||
sendString(str) {
|
||||
this.send(str.split('').map(chr => chr.charCodeAt(0)));
|
||||
}
|
||||
|
||||
// Event Handlers
|
||||
off: function (evt) {
|
||||
this._eventHandlers[evt] = function () {};
|
||||
},
|
||||
off(evt) {
|
||||
this._eventHandlers[evt] = () => {};
|
||||
}
|
||||
|
||||
on: function (evt, handler) {
|
||||
on(evt, handler) {
|
||||
this._eventHandlers[evt] = handler;
|
||||
},
|
||||
}
|
||||
|
||||
_allocate_buffers: function () {
|
||||
_allocateBuffers() {
|
||||
this._rQ = new Uint8Array(this._rQbufferSize);
|
||||
this._sQ = new Uint8Array(this._sQbufferSize);
|
||||
},
|
||||
}
|
||||
|
||||
init: function () {
|
||||
this._allocate_buffers();
|
||||
init() {
|
||||
this._allocateBuffers();
|
||||
this._rQi = 0;
|
||||
this._websocket = null;
|
||||
},
|
||||
}
|
||||
|
||||
open: function (uri, protocols) {
|
||||
var ws_schema = uri.match(/^([a-z]+):\/\//)[1];
|
||||
open(uri, protocols) {
|
||||
this.attach(new WebSocket(uri, protocols));
|
||||
}
|
||||
|
||||
attach(rawChannel) {
|
||||
this.init();
|
||||
|
||||
this._websocket = new WebSocket(uri, protocols);
|
||||
this._websocket.binaryType = 'arraybuffer';
|
||||
// Must get object and class methods to be compatible with the tests.
|
||||
const channelProps = [...Object.keys(rawChannel), ...Object.getOwnPropertyNames(Object.getPrototypeOf(rawChannel))];
|
||||
for (let i = 0; i < rawChannelProps.length; i++) {
|
||||
const prop = rawChannelProps[i];
|
||||
if (channelProps.indexOf(prop) < 0) {
|
||||
throw new Error('Raw channel missing property: ' + prop);
|
||||
}
|
||||
}
|
||||
|
||||
this._websocket.onmessage = this._recv_message.bind(this);
|
||||
this._websocket.onopen = (function () {
|
||||
this._websocket = rawChannel;
|
||||
this._websocket.binaryType = "arraybuffer";
|
||||
this._websocket.onmessage = this._recvMessage.bind(this);
|
||||
|
||||
this._websocket.onopen = () => {
|
||||
Log.Debug('>> WebSock.onopen');
|
||||
if (this._websocket.protocol) {
|
||||
Log.Info("Server choose sub-protocol: " + this._websocket.protocol);
|
||||
@@ -219,98 +255,99 @@ Websock.prototype = {
|
||||
|
||||
this._eventHandlers.open();
|
||||
Log.Debug("<< WebSock.onopen");
|
||||
}).bind(this);
|
||||
this._websocket.onclose = (function (e) {
|
||||
};
|
||||
|
||||
this._websocket.onclose = (e) => {
|
||||
Log.Debug(">> WebSock.onclose");
|
||||
this._eventHandlers.close(e);
|
||||
Log.Debug("<< WebSock.onclose");
|
||||
}).bind(this);
|
||||
this._websocket.onerror = (function (e) {
|
||||
};
|
||||
|
||||
this._websocket.onerror = (e) => {
|
||||
Log.Debug(">> WebSock.onerror: " + e);
|
||||
this._eventHandlers.error(e);
|
||||
Log.Debug("<< WebSock.onerror: " + e);
|
||||
}).bind(this);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
close: function () {
|
||||
close() {
|
||||
if (this._websocket) {
|
||||
if ((this._websocket.readyState === WebSocket.OPEN) ||
|
||||
(this._websocket.readyState === WebSocket.CONNECTING)) {
|
||||
if (this.readyState === 'connecting' ||
|
||||
this.readyState === 'open') {
|
||||
Log.Info("Closing WebSocket connection");
|
||||
this._websocket.close();
|
||||
}
|
||||
|
||||
this._websocket.onmessage = function (e) { return; };
|
||||
this._websocket.onmessage = () => {};
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// private methods
|
||||
_encode_message: function () {
|
||||
_encodeMessage() {
|
||||
// Put in a binary arraybuffer
|
||||
// according to the spec, you can send ArrayBufferViews with the send method
|
||||
return new Uint8Array(this._sQ.buffer, 0, this._sQlen);
|
||||
},
|
||||
}
|
||||
|
||||
// We want to move all the unread data to the start of the queue,
|
||||
// e.g. compacting.
|
||||
// The function also expands the receive que if needed, and for
|
||||
// performance reasons we combine these two actions to avoid
|
||||
// unneccessary copying.
|
||||
_expandCompactRQ(minFit) {
|
||||
// if we're using less than 1/8th of the buffer even with the incoming bytes, compact in place
|
||||
// instead of resizing
|
||||
const requiredBufferSize = (this._rQlen - this._rQi + minFit) * 8;
|
||||
const resizeNeeded = this._rQbufferSize < requiredBufferSize;
|
||||
|
||||
_expand_compact_rQ: function (min_fit) {
|
||||
var resizeNeeded = min_fit || this._rQlen - this._rQi > this._rQbufferSize / 2;
|
||||
if (resizeNeeded) {
|
||||
if (!min_fit) {
|
||||
// just double the size if we need to do compaction
|
||||
this._rQbufferSize *= 2;
|
||||
} else {
|
||||
// otherwise, make sure we satisy rQlen - rQi + min_fit < rQbufferSize / 8
|
||||
this._rQbufferSize = (this._rQlen - this._rQi + min_fit) * 8;
|
||||
}
|
||||
// Make sure we always *at least* double the buffer size, and have at least space for 8x
|
||||
// the current amount of data
|
||||
this._rQbufferSize = Math.max(this._rQbufferSize * 2, requiredBufferSize);
|
||||
}
|
||||
|
||||
// we don't want to grow unboundedly
|
||||
if (this._rQbufferSize > MAX_RQ_GROW_SIZE) {
|
||||
this._rQbufferSize = MAX_RQ_GROW_SIZE;
|
||||
if (this._rQbufferSize - this._rQlen - this._rQi < min_fit) {
|
||||
throw new Exception("Receive Queue buffer exceeded " + MAX_RQ_GROW_SIZE + " bytes, and the new message could not fit");
|
||||
if (this._rQbufferSize - this.rQlen < minFit) {
|
||||
throw new Error("Receive Queue buffer exceeded " + MAX_RQ_GROW_SIZE + " bytes, and the new message could not fit");
|
||||
}
|
||||
}
|
||||
|
||||
if (resizeNeeded) {
|
||||
var old_rQbuffer = this._rQ.buffer;
|
||||
this._rQmax = this._rQbufferSize / 8;
|
||||
const oldRQbuffer = this._rQ.buffer;
|
||||
this._rQ = new Uint8Array(this._rQbufferSize);
|
||||
this._rQ.set(new Uint8Array(old_rQbuffer, this._rQi));
|
||||
this._rQ.set(new Uint8Array(oldRQbuffer, this._rQi, this._rQlen - this._rQi));
|
||||
} else {
|
||||
if (ENABLE_COPYWITHIN) {
|
||||
this._rQ.copyWithin(0, this._rQi);
|
||||
} else {
|
||||
this._rQ.set(new Uint8Array(this._rQ.buffer, this._rQi));
|
||||
}
|
||||
this._rQ.copyWithin(0, this._rQi, this._rQlen);
|
||||
}
|
||||
|
||||
this._rQlen = this._rQlen - this._rQi;
|
||||
this._rQi = 0;
|
||||
},
|
||||
}
|
||||
|
||||
_decode_message: function (data) {
|
||||
// push arraybuffer values onto the end
|
||||
var u8 = new Uint8Array(data);
|
||||
// push arraybuffer values onto the end of the receive que
|
||||
_DecodeMessage(data) {
|
||||
const u8 = new Uint8Array(data);
|
||||
if (u8.length > this._rQbufferSize - this._rQlen) {
|
||||
this._expand_compact_rQ(u8.length);
|
||||
this._expandCompactRQ(u8.length);
|
||||
}
|
||||
this._rQ.set(u8, this._rQlen);
|
||||
this._rQlen += u8.length;
|
||||
},
|
||||
}
|
||||
|
||||
_recv_message: function (e) {
|
||||
this._decode_message(e.data);
|
||||
if (this.rQlen() > 0) {
|
||||
_recvMessage(e) {
|
||||
this._DecodeMessage(e.data);
|
||||
if (this.rQlen > 0) {
|
||||
this._eventHandlers.message();
|
||||
// Compact the receive queue
|
||||
if (this._rQlen == this._rQi) {
|
||||
// All data has now been processed, this means we
|
||||
// can reset the receive queue.
|
||||
this._rQlen = 0;
|
||||
this._rQi = 0;
|
||||
} else if (this._rQlen > this._rQmax) {
|
||||
this._expand_compact_rQ();
|
||||
}
|
||||
} else {
|
||||
Log.Debug("Ignoring empty message");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+9
-45
@@ -11,9 +11,6 @@ official external API.
|
||||
|
||||
## 1.1 Module List
|
||||
|
||||
* __Mouse__ (core/input/mouse.js): Mouse input event handler with
|
||||
limited touch support.
|
||||
|
||||
* __Keyboard__ (core/input/keyboard.js): Keyboard input event handler with
|
||||
non-US keyboard support. Translates keyDown and keyUp events to X11
|
||||
keysym values.
|
||||
@@ -23,7 +20,7 @@ layered on the HTML5 canvas element.
|
||||
|
||||
* __Websock__ (core/websock.js): Websock client from websockify
|
||||
with transparent binary data support.
|
||||
[Websock API](https://github.com/novnc/websockify/wiki/websock.js) wiki page.
|
||||
[Websock API](https://github.com/novnc/websockify-js/wiki/websock.js) wiki page.
|
||||
|
||||
|
||||
## 1.2 Callbacks
|
||||
@@ -35,62 +32,38 @@ callback event name, and the callback function.
|
||||
|
||||
## 2. Modules
|
||||
|
||||
## 2.1 Mouse Module
|
||||
## 2.1 Keyboard Module
|
||||
|
||||
### 2.1.1 Configuration Attributes
|
||||
|
||||
| name | type | mode | default | description
|
||||
| ----------- | ---- | ---- | -------- | ------------
|
||||
| touchButton | int | RW | 1 | Button mask (1, 2, 4) for which click to send on touch devices. 0 means ignore clicks.
|
||||
|
||||
### 2.1.2 Methods
|
||||
|
||||
| name | parameters | description
|
||||
| ------ | ---------- | ------------
|
||||
| grab | () | Begin capturing mouse events
|
||||
| ungrab | () | Stop capturing mouse events
|
||||
|
||||
### 2.1.2 Callbacks
|
||||
|
||||
| name | parameters | description
|
||||
| ------------- | ------------------- | ------------
|
||||
| onmousebutton | (x, y, down, bmask) | Handler for mouse button click/release
|
||||
| onmousemove | (x, y) | Handler for mouse movement
|
||||
|
||||
|
||||
## 2.2 Keyboard Module
|
||||
|
||||
### 2.2.1 Configuration Attributes
|
||||
|
||||
None
|
||||
|
||||
### 2.2.2 Methods
|
||||
### 2.1.2 Methods
|
||||
|
||||
| name | parameters | description
|
||||
| ------ | ---------- | ------------
|
||||
| grab | () | Begin capturing keyboard events
|
||||
| ungrab | () | Stop capturing keyboard events
|
||||
|
||||
### 2.2.3 Callbacks
|
||||
### 2.1.3 Callbacks
|
||||
|
||||
| name | parameters | description
|
||||
| ---------- | -------------------- | ------------
|
||||
| onkeypress | (keysym, code, down) | Handler for key press/release
|
||||
|
||||
|
||||
## 2.3 Display Module
|
||||
## 2.2 Display Module
|
||||
|
||||
### 2.3.1 Configuration Attributes
|
||||
### 2.2.1 Configuration Attributes
|
||||
|
||||
| name | type | mode | default | description
|
||||
| ------------ | ----- | ---- | ------- | ------------
|
||||
| logo | raw | RW | | Logo to display when cleared: {"width": width, "height": height, "type": mime-type, "data": data}
|
||||
| scale | float | RW | 1.0 | Display area scale factor 0.0 - 1.0
|
||||
| clipViewport | bool | RW | false | Use viewport clipping
|
||||
| width | int | RO | | Display area width
|
||||
| height | int | RO | | Display area height
|
||||
|
||||
### 2.3.2 Methods
|
||||
### 2.2.2 Methods
|
||||
|
||||
| name | parameters | description
|
||||
| ------------------ | ------------------------------------------------------- | ------------
|
||||
@@ -100,25 +73,16 @@ None
|
||||
| absY | (y) | Return Y relative to the remote display
|
||||
| resize | (width, height) | Set width and height
|
||||
| flip | (from_queue) | Update the visible canvas with the contents of the rendering canvas
|
||||
| clear | () | Clear the display (show logo if set)
|
||||
| pending | () | Check if there are waiting items in the render queue
|
||||
| flush | () | Resume processing the render queue unless it's empty
|
||||
| fillRect | (x, y, width, height, color, from_queue) | Draw a filled in rectangle
|
||||
| copyImage | (old_x, old_y, new_x, new_y, width, height, from_queue) | Copy a rectangular area
|
||||
| imageRect | (x, y, mime, arr) | Draw a rectangle with an image
|
||||
| startTile | (x, y, width, height, color) | Begin updating a tile
|
||||
| subTile | (tile, x, y, w, h, color) | Update a sub-rectangle within the given tile
|
||||
| finishTile | () | Draw the current tile to the display
|
||||
| imageRect | (x, y, width, height, mime, arr) | Draw a rectangle with an image
|
||||
| blitImage | (x, y, width, height, arr, offset, from_queue) | Blit pixels (of R,G,B,A) to the display
|
||||
| blitRgbImage | (x, y, width, height, arr, offset, from_queue) | Blit RGB encoded image to display
|
||||
| blitRgbxImage | (x, y, width, height, arr, offset, from_queue) | Blit RGBX encoded image to display
|
||||
| drawImage | (img, x, y) | Draw image and track damage
|
||||
| changeCursor | (pixels, mask, hotx, hoty, w, h) | Change cursor appearance
|
||||
| defaultCursor | () | Restore default cursor appearance
|
||||
| disableLocalCursor | () | Disable local (client-side) cursor
|
||||
| autoscale | (containerWidth, containerHeight) | Scale the display
|
||||
|
||||
### 2.3.3 Callbacks
|
||||
### 2.2.3 Callbacks
|
||||
|
||||
| name | parameters | description
|
||||
| ------- | ---------- | ------------
|
||||
|
||||
+33
-12
@@ -24,13 +24,7 @@ protocol stream.
|
||||
`focusOnClick`
|
||||
- Is a `boolean` indicating if keyboard focus should automatically be
|
||||
moved to the remote session when a `mousedown` or `touchstart`
|
||||
event is received.
|
||||
|
||||
`touchButton`
|
||||
- Is a `long` controlling the button mask that should be simulated
|
||||
when a touch event is recieved. Uses the same values as
|
||||
[`MouseEvent.button`](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button).
|
||||
Is set to `1` by default.
|
||||
event is received. Enabled by default.
|
||||
|
||||
`clipViewport`
|
||||
- Is a `boolean` indicating if the remote session should be clipped
|
||||
@@ -53,6 +47,30 @@ protocol stream.
|
||||
should be sent whenever the container changes dimensions. Disabled
|
||||
by default.
|
||||
|
||||
`showDotCursor`
|
||||
- Is a `boolean` indicating whether a dot cursor should be shown
|
||||
instead of a zero-sized or fully-transparent cursor if the server
|
||||
sets such invisible cursor. Disabled by default.
|
||||
|
||||
`background`
|
||||
- Is a valid CSS [background](https://developer.mozilla.org/en-US/docs/Web/CSS/background)
|
||||
style value indicating which background style should be applied
|
||||
to the element containing the remote session screen. The default value is `rgb(40, 40, 40)`
|
||||
(solid gray color).
|
||||
|
||||
`qualityLevel`
|
||||
- Is an `int` in range `[0-9]` controlling the desired JPEG quality.
|
||||
Value `0` implies low quality and `9` implies high quality.
|
||||
Default value is `6`.
|
||||
|
||||
`compressionLevel`
|
||||
- Is an `int` in range `[0-9]` controlling the desired compression
|
||||
level. Value `0` means no compression. Level 1 uses a minimum of CPU
|
||||
resources and achieves weak compression ratios, while level 9 offers
|
||||
best compression but is slow in terms of CPU consumption on the server
|
||||
side. Use high levels with very slow network connections.
|
||||
Default value is `2`.
|
||||
|
||||
`capabilities` *Read only*
|
||||
- Is an `Object` indicating which optional extensions are available
|
||||
on the server. Some methods may only be called if the corresponding
|
||||
@@ -137,7 +155,7 @@ connection to a specified VNC server.
|
||||
|
||||
##### Syntax
|
||||
|
||||
var rfb = new RFB( target, url [, options] );
|
||||
let rfb = new RFB( target, url [, options] );
|
||||
|
||||
###### Parameters
|
||||
|
||||
@@ -147,9 +165,9 @@ connection to a specified VNC server.
|
||||
existing contents of the `HTMLElement` will be untouched, but new
|
||||
elements will be added during the lifetime of the `RFB` object.
|
||||
|
||||
**`url`**
|
||||
**`urlOrDataChannel`**
|
||||
- A `DOMString` specifying the VNC server to connect to. This must be
|
||||
a valid WebSocket URL.
|
||||
a valid WebSocket URL. This can also be a `WebSocket` or `RTCDataChannel`.
|
||||
|
||||
**`options`** *Optional*
|
||||
- An `Object` specifying extra details about how the connection
|
||||
@@ -176,6 +194,10 @@ connection to a specified VNC server.
|
||||
- A `DOMString` specifying the ID to provide to any VNC repeater
|
||||
encountered.
|
||||
|
||||
`wsProtocols`
|
||||
- An `Array` of `DOMString`s specifying the sub-protocols to use
|
||||
in the WebSocket connection. Empty by default.
|
||||
|
||||
#### connect
|
||||
|
||||
The `connect` event is fired after all the handshaking with the server
|
||||
@@ -360,5 +382,4 @@ to the remote server.
|
||||
###### Parameters
|
||||
|
||||
**`text`**
|
||||
- A `DOMString` specifying the clipboard data to send. Currently only
|
||||
characters from ISO 8859-1 are supported.
|
||||
- A `DOMString` specifying the clipboard data to send.
|
||||
|
||||
+35
-13
@@ -61,23 +61,45 @@ query string. Currently the following options are available:
|
||||
* `resize` - How to resize the remote session if it is not the same size as
|
||||
the browser window. Can be one of `off`, `scale` and `remote`.
|
||||
|
||||
* `quality` - The session JPEG quality level. Can be `0` to `9`.
|
||||
|
||||
* `compression` - The session compression level. Can be `0` to `9`.
|
||||
|
||||
* `show_dot` - If a dot cursor should be shown when the remote server provides
|
||||
no local cursor, or provides a fully-transparent (invisible) cursor.
|
||||
|
||||
* `logging` - The console log level. Can be one of `error`, `warn`, `info` or
|
||||
`debug`.
|
||||
|
||||
## Pre-conversion of Modules
|
||||
## HTTP Serving Considerations
|
||||
### Browser Cache Issue
|
||||
|
||||
noVNC is written using ECMAScript 6 modules. Many of the major browsers support
|
||||
these modules natively, but not all. By default the noVNC application includes
|
||||
a script that can convert these modules to an older format as they are being
|
||||
loaded. However this process can be slow and severely increases the load time
|
||||
for the application.
|
||||
If you serve noVNC files using a web server that provides an ETag header, and
|
||||
include any options in the query string, a nasty browser cache issue can bite
|
||||
you on upgrade, resulting in a red error box. The issue is caused by a mismatch
|
||||
between the new vnc.html (which is reloaded because the user has used it with
|
||||
new query string after the upgrade) and the old javascript files (that the
|
||||
browser reuses from its cache). To avoid this issue, the browser must be told
|
||||
to always revalidate cached files using conditional requests. The correct
|
||||
semantics are achieved via the (confusingly named) `Cache-Control: no-cache`
|
||||
header that needs to be provided in the web server responses.
|
||||
|
||||
It is possible to perform this conversion ahead of time, avoiding the extra
|
||||
load times. To do this please follow these steps:
|
||||
### Example Server Configurations
|
||||
|
||||
1. Install Node.js
|
||||
2. Run `npm install` in the noVNC directory
|
||||
3. Run `./utils/use_require.js --with-app --as commonjs`
|
||||
Apache:
|
||||
|
||||
This will produce a `build/` directory that includes everything needed to run
|
||||
the noVNC application.
|
||||
```
|
||||
# In the main configuration file
|
||||
# (Debian/Ubuntu users: use "a2enmod headers" instead)
|
||||
LoadModule headers_module modules/mod_headers.so
|
||||
|
||||
# In the <Directory> or <Location> block related to noVNC
|
||||
Header set Cache-Control "no-cache"
|
||||
```
|
||||
|
||||
Nginx:
|
||||
|
||||
```
|
||||
# In the location block related to noVNC
|
||||
add_header Cache-Control no-cache;
|
||||
```
|
||||
|
||||
+3
-7
@@ -18,18 +18,14 @@ do things.
|
||||
|
||||
## Conversion of Modules
|
||||
|
||||
noVNC is written using ECMAScript 6 modules. Many of the major browsers support
|
||||
these modules natively, but not all. They are also not supported by Node.js. To
|
||||
use noVNC in these places the library must first be converted.
|
||||
noVNC is written using ECMAScript 6 modules. This is not supported by older
|
||||
versions of Node.js. To use noVNC with those older versions of Node.js the
|
||||
library must first be converted.
|
||||
|
||||
Fortunately noVNC includes a script to handle this conversion. Please follow
|
||||
the following steps:
|
||||
|
||||
1. Install Node.js
|
||||
2. Run `npm install` in the noVNC directory
|
||||
3. Run `./utils/use_require.js --as <module format>`
|
||||
|
||||
Several module formats are available. Please run
|
||||
`./utils/use_require.js --help` to see them all.
|
||||
|
||||
The result of the conversion is available in the `lib/` directory.
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
1.0.0-testing.2
|
||||
@@ -0,0 +1,37 @@
|
||||
.TH novnc_proxy 1 "June 25, 2020" "version 1.2.0" "USER COMMANDS"
|
||||
|
||||
.SH NAME
|
||||
novnc_proxy - noVNC proxy server
|
||||
.SH SYNOPSIS
|
||||
.B novnc_proxy [--listen PORT] [--vnc VNC_HOST:PORT] [--cert CERT] [--ssl-only]
|
||||
|
||||
Starts the WebSockets proxy and a mini-webserver and
|
||||
provides a cut-and-paste URL to go to.
|
||||
|
||||
--listen PORT Port for proxy/webserver to listen on
|
||||
Default: 6080
|
||||
--vnc VNC_HOST:PORT VNC server host:port proxy target
|
||||
Default: localhost:5900
|
||||
--cert CERT Path to combined cert/key file, or just
|
||||
the cert file if used with --key
|
||||
Default: self.pem
|
||||
--key KEY Path to key file, when not combined with cert
|
||||
--web WEB Path to web files (e.g. vnc.html)
|
||||
Default: ./
|
||||
--ssl-only Disable non-https connections.
|
||||
|
||||
--record FILE Record traffic to FILE.session.js
|
||||
|
||||
--syslog SERVER Can be local socket such as /dev/log, or a UDP host:port pair.
|
||||
|
||||
--heartbeat SEC send a ping to the client every SEC seconds
|
||||
--timeout SEC after SEC seconds exit when not connected
|
||||
--idle-timeout SEC server exits after SEC seconds if there are no
|
||||
active connections
|
||||
|
||||
.SH AUTHOR
|
||||
The noVNC Authors
|
||||
https://github.com/novnc/noVNC
|
||||
|
||||
.SH SEE ALSO
|
||||
websockify(1), nova-novncproxy(1)
|
||||
@@ -1,34 +0,0 @@
|
||||
- Decide a new version number X.Y.Z (follow SemVer)
|
||||
- Update version in package.json
|
||||
- Update version in docs/VERSION
|
||||
- Commit the change with a commit like "Release X.Y.Z"
|
||||
- Add a new release on GitHub called "vX.Y.Z", and populate it with
|
||||
release notes of the following form (where A.B.C is the last release):
|
||||
|
||||
Major Changes Since A.B.C
|
||||
=========================
|
||||
|
||||
*Insert warnings here about incompatibilities*
|
||||
|
||||
*Thanks to all the contributors who filed bugs, added features, and fixed bugs
|
||||
during this release :tada:*
|
||||
|
||||
App-visible Changes
|
||||
-------------------
|
||||
|
||||
- *feature* a feature which improves the app usage (#PRNUM)
|
||||
- *bugfix* a bug fix which fixes the app usage (#PRNUM)
|
||||
- *refactor* a refactor which changes the app usage (#PRNUM)
|
||||
|
||||
Library-visible Changes
|
||||
-----------------------
|
||||
|
||||
- *feature* a feature which improves the noVNC APIs (#PRNUM)
|
||||
- *bugfix* a bug fix which fixes the noVNC APIs (#PRNUM)
|
||||
- *refactor* a refactor which changes the noVNC APIs (#PRNUM)
|
||||
|
||||
App-internals Changes
|
||||
---------------------
|
||||
|
||||
- *bugfix* a bug fix with affects the internals of noVNC only (#PRNUM)
|
||||
- *refactor* a refactor which affects the internals of noVNC only (#PRNUM)
|
||||
+31
-100
@@ -1,73 +1,43 @@
|
||||
// Karma configuration
|
||||
|
||||
module.exports = function(config) {
|
||||
var customLaunchers = {};
|
||||
var browsers = [];
|
||||
var useSauce = false;
|
||||
// The Safari launcher is broken, so construct our own
|
||||
function SafariBrowser(id, baseBrowserDecorator, args) {
|
||||
baseBrowserDecorator(this);
|
||||
|
||||
// use Sauce when running on Travis
|
||||
if (process.env.TRAVIS_JOB_NUMBER) {
|
||||
useSauce = true;
|
||||
this._start = function(url) {
|
||||
this._execCommand('/usr/bin/open', ['-W', '-n', '-a', 'Safari', url]);
|
||||
}
|
||||
}
|
||||
|
||||
SafariBrowser.prototype = {
|
||||
name: 'Safari'
|
||||
}
|
||||
|
||||
module.exports = (config) => {
|
||||
let browsers = [];
|
||||
|
||||
if (process.env.TEST_BROWSER_NAME) {
|
||||
browsers = process.env.TEST_BROWSER_NAME.split(',');
|
||||
}
|
||||
|
||||
if (useSauce && process.env.TEST_BROWSER_NAME && process.env.TEST_BROWSER_NAME != 'PhantomJS') {
|
||||
var names = process.env.TEST_BROWSER_NAME.split(',');
|
||||
var platforms = process.env.TEST_BROWSER_OS.split(',');
|
||||
var versions = [];
|
||||
if (process.env.TEST_BROWSER_VERSION) {
|
||||
versions = process.env.TEST_BROWSER_VERSION.split(',');
|
||||
} else {
|
||||
versions = [null];
|
||||
}
|
||||
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
for (var j = 0; j < platforms.length; j++) {
|
||||
for (var k = 0; k < versions.length; k++) {
|
||||
var launcher_name = 'sl_' + platforms[j].replace(/[^a-zA-Z0-9]/g, '') + '_' + names[i];
|
||||
if (versions[k]) {
|
||||
launcher_name += '_' + versions[k];
|
||||
}
|
||||
|
||||
customLaunchers[launcher_name] = {
|
||||
base: 'SauceLabs',
|
||||
browserName: names[i],
|
||||
platform: platforms[j],
|
||||
};
|
||||
|
||||
if (versions[i]) {
|
||||
customLaunchers[launcher_name].version = versions[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
browsers = Object.keys(customLaunchers);
|
||||
} else {
|
||||
useSauce = false;
|
||||
//browsers = ['PhantomJS'];
|
||||
browsers = [];
|
||||
}
|
||||
|
||||
var my_conf = {
|
||||
const my_conf = {
|
||||
|
||||
// base path that will be used to resolve all patterns (eg. files, exclude)
|
||||
basePath: '',
|
||||
|
||||
// frameworks to use
|
||||
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
||||
frameworks: ['requirejs', 'mocha', 'chai'],
|
||||
frameworks: ['mocha', 'sinon-chai'],
|
||||
|
||||
// list of files / patterns to load in the browser (loaded in order)
|
||||
files: [
|
||||
{ pattern: 'vendor/sinon.js', included: false },
|
||||
{ pattern: 'node_modules/sinon-chai/lib/sinon-chai.js', included: false },
|
||||
{ pattern: 'app/localization.js', included: false },
|
||||
{ pattern: 'core/**/*.js', included: false },
|
||||
{ pattern: 'vendor/pako/**/*.js', included: false },
|
||||
{ pattern: 'tests/test.*.js', included: false },
|
||||
{ pattern: 'tests/fake.*.js', included: false },
|
||||
{ pattern: 'tests/assertions.js', included: false },
|
||||
'tests/karma-test-main.js',
|
||||
{ pattern: 'app/localization.js', included: false, type: 'module' },
|
||||
{ pattern: 'app/webutil.js', included: false, type: 'module' },
|
||||
{ pattern: 'core/**/*.js', included: false, type: 'module' },
|
||||
{ pattern: 'vendor/pako/**/*.js', included: false, type: 'module' },
|
||||
{ pattern: 'tests/test.*.js', type: 'module' },
|
||||
{ pattern: 'tests/fake.*.js', included: false, type: 'module' },
|
||||
{ pattern: 'tests/assertions.js', type: 'module' },
|
||||
],
|
||||
|
||||
client: {
|
||||
@@ -82,44 +52,22 @@ module.exports = function(config) {
|
||||
exclude: [
|
||||
],
|
||||
|
||||
customLaunchers: customLaunchers,
|
||||
plugins: [
|
||||
'karma-*',
|
||||
'@chiragrupani/karma-chromium-edge-launcher',
|
||||
{ 'launcher:Safari': [ 'type', SafariBrowser ] },
|
||||
],
|
||||
|
||||
// start these browsers
|
||||
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
|
||||
browsers: browsers,
|
||||
|
||||
// preprocess matching files before serving them to the browser
|
||||
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
|
||||
preprocessors: {
|
||||
'app/localization.js': ['babel'],
|
||||
'core/**/*.js': ['babel'],
|
||||
'tests/test.*.js': ['babel'],
|
||||
'tests/fake.*.js': ['babel'],
|
||||
'tests/assertions.js': ['babel'],
|
||||
'vendor/pako/**/*.js': ['babel'],
|
||||
},
|
||||
|
||||
babelPreprocessor: {
|
||||
options: {
|
||||
plugins: ['transform-es2015-modules-amd', 'syntax-dynamic-import'],
|
||||
sourceMap: 'inline',
|
||||
},
|
||||
},
|
||||
|
||||
// test results reporter to use
|
||||
// possible values: 'dots', 'progress'
|
||||
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
||||
reporters: ['mocha'],
|
||||
|
||||
|
||||
// web server port
|
||||
port: 9876,
|
||||
|
||||
|
||||
// enable / disable colors in the output (reporters and logs)
|
||||
colors: true,
|
||||
|
||||
|
||||
// level of logging
|
||||
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
|
||||
logLevel: config.LOG_INFO,
|
||||
@@ -131,24 +79,7 @@ module.exports = function(config) {
|
||||
// Continuous Integration mode
|
||||
// if true, Karma captures browsers, runs the tests and exits
|
||||
singleRun: true,
|
||||
|
||||
// Increase timeout in case connection is slow/we run more browsers than possible
|
||||
// (we currently get 3 for free, and we try to run 7, so it can take a while)
|
||||
captureTimeout: 240000,
|
||||
|
||||
// similarly to above
|
||||
browserNoActivityTimeout: 100000,
|
||||
};
|
||||
|
||||
if (useSauce) {
|
||||
my_conf.reporters.push('saucelabs');
|
||||
my_conf.captureTimeout = 0; // use SL timeout
|
||||
my_conf.sauceLabs = {
|
||||
testName: 'noVNC Tests (all)',
|
||||
startConnect: false,
|
||||
tunnelIdentifier: process.env.TRAVIS_JOB_NUMBER
|
||||
};
|
||||
}
|
||||
|
||||
config.set(my_conf);
|
||||
};
|
||||
|
||||
+45
-28
@@ -1,14 +1,27 @@
|
||||
{
|
||||
"name": "@novnc/novnc",
|
||||
"version": "1.0.0-beta",
|
||||
"version": "1.3.0-beta",
|
||||
"description": "An HTML5 VNC client",
|
||||
"browser": "lib/rfb",
|
||||
"directories": {
|
||||
"lib": "lib",
|
||||
"doc": "docs",
|
||||
"test": "tests"
|
||||
},
|
||||
"files": [
|
||||
"lib",
|
||||
"AUTHORS",
|
||||
"VERSION",
|
||||
"docs/API.md",
|
||||
"docs/LIBRARY.md",
|
||||
"docs/LICENSE*",
|
||||
"core",
|
||||
"vendor/pako"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "PATH=$PATH:node_modules/karma/bin karma start karma.conf.js",
|
||||
"prepare": "node ./utils/use_require.js --as commonjs --clean"
|
||||
"lint": "eslint app core po/po2js po/xgettext-html tests utils",
|
||||
"test": "karma start karma.conf.js",
|
||||
"prepublish": "node ./utils/use_require.js --clean"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -27,35 +40,39 @@
|
||||
},
|
||||
"homepage": "https://github.com/novnc/noVNC",
|
||||
"devDependencies": {
|
||||
"babel-core": "^6.22.1",
|
||||
"babel-plugin-add-module-exports": "^0.2.1",
|
||||
"@babel/core": "*",
|
||||
"@babel/plugin-syntax-dynamic-import": "*",
|
||||
"@babel/plugin-transform-modules-commonjs": "*",
|
||||
"@babel/preset-env": "*",
|
||||
"@babel/cli": "*",
|
||||
"babel-plugin-import-redirect": "*",
|
||||
"babel-plugin-syntax-dynamic-import": "^6.18.0",
|
||||
"babel-plugin-transform-es2015-modules-amd": "^6.22.0",
|
||||
"babel-plugin-transform-es2015-modules-commonjs": "^6.18.0",
|
||||
"babel-plugin-transform-es2015-modules-systemjs": "^6.22.0",
|
||||
"babel-plugin-transform-es2015-modules-umd": "^6.22.0",
|
||||
"babelify": "^7.3.0",
|
||||
"browserify": "^13.1.0",
|
||||
"chai": "^3.5.0",
|
||||
"commander": "^2.9.0",
|
||||
"es-module-loader": "^2.1.0",
|
||||
"fs-extra": "^1.0.0",
|
||||
"browserify": "*",
|
||||
"babelify": "*",
|
||||
"core-js": "*",
|
||||
"chai": "*",
|
||||
"commander": "*",
|
||||
"es-module-loader": "*",
|
||||
"eslint": "*",
|
||||
"fs-extra": "*",
|
||||
"jsdom": "*",
|
||||
"karma": "^1.3.0",
|
||||
"karma-babel-preprocessor": "^6.0.1",
|
||||
"karma-chai": "^0.1.0",
|
||||
"karma-mocha": "^1.3.0",
|
||||
"karma-mocha-reporter": "^2.2.0",
|
||||
"karma-requirejs": "^1.1.0",
|
||||
"karma-sauce-launcher": "^1.0.0",
|
||||
"mocha": "^3.1.2",
|
||||
"karma": "*",
|
||||
"karma-mocha": "*",
|
||||
"karma-chrome-launcher": "*",
|
||||
"@chiragrupani/karma-chromium-edge-launcher": "*",
|
||||
"karma-firefox-launcher": "*",
|
||||
"karma-ie-launcher": "*",
|
||||
"karma-mocha-reporter": "*",
|
||||
"karma-safari-launcher": "*",
|
||||
"karma-script-launcher": "*",
|
||||
"karma-sinon-chai": "*",
|
||||
"mocha": "*",
|
||||
"node-getopt": "*",
|
||||
"po2json": "*",
|
||||
"requirejs": "^2.3.2",
|
||||
"rollup": "^0.41.4",
|
||||
"rollup-plugin-node-resolve": "^2.0.0",
|
||||
"sinon-chai": "^2.8.0"
|
||||
"requirejs": "*",
|
||||
"rollup": "*",
|
||||
"rollup-plugin-node-resolve": "*",
|
||||
"sinon": "*",
|
||||
"sinon-chai": "*"
|
||||
},
|
||||
"dependencies": {},
|
||||
"keywords": [
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"env": {
|
||||
"node": true,
|
||||
},
|
||||
}
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
all:
|
||||
.PHONY: update-po update-js update-pot
|
||||
|
||||
LINGUAS := de el es nl pl sv tr zh
|
||||
LINGUAS := cs de el es fr ja ko nl pl pt_BR ru sv tr zh_CN zh_TW
|
||||
|
||||
VERSION := $(shell grep '"version"' ../package.json | cut -d '"' -f 4)
|
||||
|
||||
@@ -18,7 +18,7 @@ update-js: $(JSONFILES)
|
||||
|
||||
update-pot:
|
||||
xgettext --output=noVNC.js.pot \
|
||||
--copyright-holder="Various Authors" \
|
||||
--copyright-holder="The noVNC Authors" \
|
||||
--package-name="noVNC" \
|
||||
--package-version="$(VERSION)" \
|
||||
--msgid-bugs-address="novnc@googlegroups.com" \
|
||||
|
||||
@@ -0,0 +1,294 @@
|
||||
# Czech translations for noVNC package.
|
||||
# Copyright (C) 2018 The noVNC Authors
|
||||
# This file is distributed under the same license as the noVNC package.
|
||||
# Petr <petr@kle.cz>, 2018.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: noVNC 1.0.0-testing.2\n"
|
||||
"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
|
||||
"POT-Creation-Date: 2018-10-19 12:00+0200\n"
|
||||
"PO-Revision-Date: 2018-10-19 12:00+0200\n"
|
||||
"Last-Translator: Petr <petr@kle.cz>\n"
|
||||
"Language-Team: Czech\n"
|
||||
"Language: cs\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
|
||||
|
||||
#: ../app/ui.js:389
|
||||
msgid "Connecting..."
|
||||
msgstr "Připojení..."
|
||||
|
||||
#: ../app/ui.js:396
|
||||
msgid "Disconnecting..."
|
||||
msgstr "Odpojení..."
|
||||
|
||||
#: ../app/ui.js:402
|
||||
msgid "Reconnecting..."
|
||||
msgstr "Obnova připojení..."
|
||||
|
||||
#: ../app/ui.js:407
|
||||
msgid "Internal error"
|
||||
msgstr "Vnitřní chyba"
|
||||
|
||||
#: ../app/ui.js:997
|
||||
msgid "Must set host"
|
||||
msgstr "Hostitel musí být nastavení"
|
||||
|
||||
#: ../app/ui.js:1079
|
||||
msgid "Connected (encrypted) to "
|
||||
msgstr "Připojení (šifrované) k "
|
||||
|
||||
#: ../app/ui.js:1081
|
||||
msgid "Connected (unencrypted) to "
|
||||
msgstr "Připojení (nešifrované) k "
|
||||
|
||||
#: ../app/ui.js:1104
|
||||
msgid "Something went wrong, connection is closed"
|
||||
msgstr "Něco se pokazilo, odpojeno"
|
||||
|
||||
#: ../app/ui.js:1107
|
||||
msgid "Failed to connect to server"
|
||||
msgstr "Chyba připojení k serveru"
|
||||
|
||||
#: ../app/ui.js:1117
|
||||
msgid "Disconnected"
|
||||
msgstr "Odpojeno"
|
||||
|
||||
#: ../app/ui.js:1130
|
||||
msgid "New connection has been rejected with reason: "
|
||||
msgstr "Nové připojení bylo odmítnuto s odůvodněním: "
|
||||
|
||||
#: ../app/ui.js:1133
|
||||
msgid "New connection has been rejected"
|
||||
msgstr "Nové připojení bylo odmítnuto"
|
||||
|
||||
#: ../app/ui.js:1153
|
||||
msgid "Password is required"
|
||||
msgstr "Je vyžadováno heslo"
|
||||
|
||||
#: ../vnc.html:84
|
||||
msgid "noVNC encountered an error:"
|
||||
msgstr "noVNC narazilo na chybu:"
|
||||
|
||||
#: ../vnc.html:94
|
||||
msgid "Hide/Show the control bar"
|
||||
msgstr "Skrýt/zobrazit ovládací panel"
|
||||
|
||||
#: ../vnc.html:101
|
||||
msgid "Move/Drag Viewport"
|
||||
msgstr "Přesunout/přetáhnout výřez"
|
||||
|
||||
#: ../vnc.html:101
|
||||
msgid "viewport drag"
|
||||
msgstr "přesun výřezu"
|
||||
|
||||
#: ../vnc.html:107 ../vnc.html:110 ../vnc.html:113 ../vnc.html:116
|
||||
msgid "Active Mouse Button"
|
||||
msgstr "Aktivní tlačítka myši"
|
||||
|
||||
#: ../vnc.html:107
|
||||
msgid "No mousebutton"
|
||||
msgstr "Žádné"
|
||||
|
||||
#: ../vnc.html:110
|
||||
msgid "Left mousebutton"
|
||||
msgstr "Levé tlačítko myši"
|
||||
|
||||
#: ../vnc.html:113
|
||||
msgid "Middle mousebutton"
|
||||
msgstr "Prostřední tlačítko myši"
|
||||
|
||||
#: ../vnc.html:116
|
||||
msgid "Right mousebutton"
|
||||
msgstr "Pravé tlačítko myši"
|
||||
|
||||
#: ../vnc.html:119
|
||||
msgid "Keyboard"
|
||||
msgstr "Klávesnice"
|
||||
|
||||
#: ../vnc.html:119
|
||||
msgid "Show Keyboard"
|
||||
msgstr "Zobrazit klávesnici"
|
||||
|
||||
#: ../vnc.html:126
|
||||
msgid "Extra keys"
|
||||
msgstr "Extra klávesy"
|
||||
|
||||
#: ../vnc.html:126
|
||||
msgid "Show Extra Keys"
|
||||
msgstr "Zobrazit extra klávesy"
|
||||
|
||||
#: ../vnc.html:131
|
||||
msgid "Ctrl"
|
||||
msgstr "Ctrl"
|
||||
|
||||
#: ../vnc.html:131
|
||||
msgid "Toggle Ctrl"
|
||||
msgstr "Přepnout Ctrl"
|
||||
|
||||
#: ../vnc.html:134
|
||||
msgid "Alt"
|
||||
msgstr "Alt"
|
||||
|
||||
#: ../vnc.html:134
|
||||
msgid "Toggle Alt"
|
||||
msgstr "Přepnout Alt"
|
||||
|
||||
#: ../vnc.html:137
|
||||
msgid "Send Tab"
|
||||
msgstr "Odeslat tabulátor"
|
||||
|
||||
#: ../vnc.html:137
|
||||
msgid "Tab"
|
||||
msgstr "Tab"
|
||||
|
||||
#: ../vnc.html:140
|
||||
msgid "Esc"
|
||||
msgstr "Esc"
|
||||
|
||||
#: ../vnc.html:140
|
||||
msgid "Send Escape"
|
||||
msgstr "Odeslat Esc"
|
||||
|
||||
#: ../vnc.html:143
|
||||
msgid "Ctrl+Alt+Del"
|
||||
msgstr "Ctrl+Alt+Del"
|
||||
|
||||
#: ../vnc.html:143
|
||||
msgid "Send Ctrl-Alt-Del"
|
||||
msgstr "Poslat Ctrl-Alt-Del"
|
||||
|
||||
#: ../vnc.html:151
|
||||
msgid "Shutdown/Reboot"
|
||||
msgstr "Vypnutí/Restart"
|
||||
|
||||
#: ../vnc.html:151
|
||||
msgid "Shutdown/Reboot..."
|
||||
msgstr "Vypnutí/Restart..."
|
||||
|
||||
#: ../vnc.html:157
|
||||
msgid "Power"
|
||||
msgstr "Napájení"
|
||||
|
||||
#: ../vnc.html:159
|
||||
msgid "Shutdown"
|
||||
msgstr "Vypnout"
|
||||
|
||||
#: ../vnc.html:160
|
||||
msgid "Reboot"
|
||||
msgstr "Restart"
|
||||
|
||||
#: ../vnc.html:161
|
||||
msgid "Reset"
|
||||
msgstr "Reset"
|
||||
|
||||
#: ../vnc.html:166 ../vnc.html:172
|
||||
msgid "Clipboard"
|
||||
msgstr "Schránka"
|
||||
|
||||
#: ../vnc.html:176
|
||||
msgid "Clear"
|
||||
msgstr "Vymazat"
|
||||
|
||||
#: ../vnc.html:182
|
||||
msgid "Fullscreen"
|
||||
msgstr "Celá obrazovka"
|
||||
|
||||
#: ../vnc.html:187 ../vnc.html:194
|
||||
msgid "Settings"
|
||||
msgstr "Nastavení"
|
||||
|
||||
#: ../vnc.html:197
|
||||
msgid "Shared Mode"
|
||||
msgstr "Sdílený režim"
|
||||
|
||||
#: ../vnc.html:200
|
||||
msgid "View Only"
|
||||
msgstr "Pouze prohlížení"
|
||||
|
||||
#: ../vnc.html:204
|
||||
msgid "Clip to Window"
|
||||
msgstr "Přizpůsobit oknu"
|
||||
|
||||
#: ../vnc.html:207
|
||||
msgid "Scaling Mode:"
|
||||
msgstr "Přizpůsobení velikosti"
|
||||
|
||||
#: ../vnc.html:209
|
||||
msgid "None"
|
||||
msgstr "Žádné"
|
||||
|
||||
#: ../vnc.html:210
|
||||
msgid "Local Scaling"
|
||||
msgstr "Místní"
|
||||
|
||||
#: ../vnc.html:211
|
||||
msgid "Remote Resizing"
|
||||
msgstr "Vzdálené"
|
||||
|
||||
#: ../vnc.html:216
|
||||
msgid "Advanced"
|
||||
msgstr "Pokročilé"
|
||||
|
||||
#: ../vnc.html:219
|
||||
msgid "Repeater ID:"
|
||||
msgstr "ID opakovače"
|
||||
|
||||
#: ../vnc.html:223
|
||||
msgid "WebSocket"
|
||||
msgstr "WebSocket"
|
||||
|
||||
#: ../vnc.html:226
|
||||
msgid "Encrypt"
|
||||
msgstr "Šifrování:"
|
||||
|
||||
#: ../vnc.html:229
|
||||
msgid "Host:"
|
||||
msgstr "Hostitel:"
|
||||
|
||||
#: ../vnc.html:233
|
||||
msgid "Port:"
|
||||
msgstr "Port:"
|
||||
|
||||
#: ../vnc.html:237
|
||||
msgid "Path:"
|
||||
msgstr "Cesta"
|
||||
|
||||
#: ../vnc.html:244
|
||||
msgid "Automatic Reconnect"
|
||||
msgstr "Automatická obnova připojení"
|
||||
|
||||
#: ../vnc.html:247
|
||||
msgid "Reconnect Delay (ms):"
|
||||
msgstr "Zpoždění připojení (ms)"
|
||||
|
||||
#: ../vnc.html:252
|
||||
msgid "Show Dot when No Cursor"
|
||||
msgstr "Tečka místo chybějícího kurzoru myši"
|
||||
|
||||
#: ../vnc.html:257
|
||||
msgid "Logging:"
|
||||
msgstr "Logování:"
|
||||
|
||||
#: ../vnc.html:269
|
||||
msgid "Disconnect"
|
||||
msgstr "Odpojit"
|
||||
|
||||
#: ../vnc.html:288
|
||||
msgid "Connect"
|
||||
msgstr "Připojit"
|
||||
|
||||
#: ../vnc.html:298
|
||||
msgid "Password:"
|
||||
msgstr "Heslo"
|
||||
|
||||
#: ../vnc.html:302
|
||||
msgid "Send Password"
|
||||
msgstr "Odeslat heslo"
|
||||
|
||||
#: ../vnc.html:312
|
||||
msgid "Cancel"
|
||||
msgstr "Zrušit"
|
||||
@@ -1,6 +1,6 @@
|
||||
# German translations for noVNC package
|
||||
# German translation for noVNC.
|
||||
# Copyright (C) 2016 Various Authors
|
||||
# Copyright (C) 2018 The noVNC Authors
|
||||
# This file is distributed under the same license as the noVNC package.
|
||||
# Loek Janssen <loekjanssen@gmail.com>, 2016.
|
||||
#
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Greek translations for noVNC package.
|
||||
# Copyright (C) 2016 Various Authors
|
||||
# Copyright (C) 2018 The noVNC Authors
|
||||
# This file is distributed under the same license as the noVNC package.
|
||||
# Giannis Kosmas <kosmasgiannis@gmail.com>, 2016.
|
||||
#
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
# Spanish translations for noVNC package
|
||||
# Traducciones al español para el paquete noVNC.
|
||||
# Copyright (C) 2018 Various Authors
|
||||
# Copyright (C) 2018 The noVNC Authors
|
||||
# This file is distributed under the same license as the noVNC package.
|
||||
# Juanjo Diaz <juanjo.diazmo@gmail.com>, 2018.
|
||||
# Adrian Scillato <ascillato@gmail.com>, 2021.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: noVNC 1.0.0-testing.2\n"
|
||||
"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
|
||||
"POT-Creation-Date: 2017-10-06 10:07+0200\n"
|
||||
"PO-Revision-Date: 2018-01-30 19:14-0800\n"
|
||||
"Last-Translator: Juanjo Diaz <juanjo.diazmo@gmail.com>\n"
|
||||
"PO-Revision-Date: 2021-04-23 12:00-0300\n"
|
||||
"Last-Translator: Adrian Scillato <ascillato@gmail.com>\n"
|
||||
"Language-Team: Spanish\n"
|
||||
"Language: es\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@@ -40,7 +41,7 @@ msgstr "Desconectado"
|
||||
|
||||
#: ../app/ui.js:1052 ../core/rfb.js:248
|
||||
msgid "Must set host"
|
||||
msgstr "Debes configurar el host"
|
||||
msgstr "Se debe configurar el host"
|
||||
|
||||
#: ../app/ui.js:1101
|
||||
msgid "Reconnecting..."
|
||||
@@ -48,7 +49,7 @@ msgstr "Reconectando..."
|
||||
|
||||
#: ../app/ui.js:1140
|
||||
msgid "Password is required"
|
||||
msgstr "Contraseña es obligatoria"
|
||||
msgstr "La contraseña es obligatoria"
|
||||
|
||||
#: ../core/rfb.js:548
|
||||
msgid "Disconnect timeout"
|
||||
@@ -186,6 +187,10 @@ msgstr "Pantalla Completa"
|
||||
msgid "Settings"
|
||||
msgstr "Configuraciones"
|
||||
|
||||
#: ../vnc.html:200
|
||||
msgid "Encrypt"
|
||||
msgstr "Encriptar"
|
||||
|
||||
#: ../vnc.html:202
|
||||
msgid "Shared Mode"
|
||||
msgstr "Modo Compartido"
|
||||
@@ -228,27 +233,23 @@ msgstr "Cursor Local"
|
||||
|
||||
#: ../vnc.html:229
|
||||
msgid "Repeater ID:"
|
||||
msgstr "ID del Repetidor"
|
||||
msgstr "ID del Repetidor:"
|
||||
|
||||
#: ../vnc.html:233
|
||||
msgid "WebSocket"
|
||||
msgstr "WebSocket"
|
||||
|
||||
#: ../vnc.html:236
|
||||
msgid "Encrypt"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:239
|
||||
msgid "Host:"
|
||||
msgstr "Host"
|
||||
msgstr "Host:"
|
||||
|
||||
#: ../vnc.html:243
|
||||
msgid "Port:"
|
||||
msgstr "Puesto"
|
||||
msgstr "Puerto:"
|
||||
|
||||
#: ../vnc.html:247
|
||||
msgid "Path:"
|
||||
msgstr "Ruta"
|
||||
msgstr "Ruta:"
|
||||
|
||||
#: ../vnc.html:254
|
||||
msgid "Automatic Reconnect"
|
||||
@@ -256,11 +257,11 @@ msgstr "Reconexión automática"
|
||||
|
||||
#: ../vnc.html:257
|
||||
msgid "Reconnect Delay (ms):"
|
||||
msgstr "Retraso en la reconexión (ms)"
|
||||
msgstr "Retraso en la reconexión (ms):"
|
||||
|
||||
#: ../vnc.html:263
|
||||
msgid "Logging:"
|
||||
msgstr "Logging"
|
||||
msgstr "Registrando:"
|
||||
|
||||
#: ../vnc.html:275
|
||||
msgid "Disconnect"
|
||||
@@ -272,7 +273,7 @@ msgstr "Conectar"
|
||||
|
||||
#: ../vnc.html:304
|
||||
msgid "Password:"
|
||||
msgstr "Contraseña"
|
||||
msgstr "Contraseña:"
|
||||
|
||||
#: ../vnc.html:318
|
||||
msgid "Cancel"
|
||||
@@ -280,4 +281,4 @@ msgstr "Cancelar"
|
||||
|
||||
#: ../vnc.html:334
|
||||
msgid "Canvas not supported."
|
||||
msgstr "Canvas no está soportado"
|
||||
msgstr "Canvas no soportado."
|
||||
|
||||
@@ -0,0 +1,299 @@
|
||||
# French translations for noVNC package
|
||||
# Traductions françaises du paquet noVNC.
|
||||
# Copyright (C) 2021 The noVNC Authors
|
||||
# This file is distributed under the same license as the noVNC package.
|
||||
# Jose <jose.matsuda@canada.ca>, 2021.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: noVNC 1.2.0\n"
|
||||
"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
|
||||
"POT-Creation-Date: 2020-07-03 16:11+0200\n"
|
||||
"PO-Revision-Date: 2021-05-05 20:19-0400\n"
|
||||
"Last-Translator: Jose <jose.matsuda@canada.ca>\n"
|
||||
"Language-Team: French\n"
|
||||
"Language: fr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#: ../app/ui.js:394
|
||||
msgid "Connecting..."
|
||||
msgstr "En cours de connexion..."
|
||||
|
||||
#: ../app/ui.js:401
|
||||
msgid "Disconnecting..."
|
||||
msgstr "Déconnexion en cours..."
|
||||
|
||||
#: ../app/ui.js:407
|
||||
msgid "Reconnecting..."
|
||||
msgstr "Reconnexion en cours..."
|
||||
|
||||
#: ../app/ui.js:412
|
||||
msgid "Internal error"
|
||||
msgstr "Erreur interne"
|
||||
|
||||
#: ../app/ui.js:1008
|
||||
msgid "Must set host"
|
||||
msgstr "Doit définir l'hôte"
|
||||
|
||||
#: ../app/ui.js:1090
|
||||
msgid "Connected (encrypted) to "
|
||||
msgstr "Connecté (crypté) à "
|
||||
|
||||
#: ../app/ui.js:1092
|
||||
msgid "Connected (unencrypted) to "
|
||||
msgstr "Connecté (non crypté) à "
|
||||
|
||||
#: ../app/ui.js:1115
|
||||
msgid "Something went wrong, connection is closed"
|
||||
msgstr "Quelque chose est arrivé, la connexion est fermée"
|
||||
|
||||
#: ../app/ui.js:1118
|
||||
msgid "Failed to connect to server"
|
||||
msgstr "Échec de connexion au serveur"
|
||||
|
||||
#: ../app/ui.js:1128
|
||||
msgid "Disconnected"
|
||||
msgstr "Déconnecté"
|
||||
|
||||
#: ../app/ui.js:1143
|
||||
msgid "New connection has been rejected with reason: "
|
||||
msgstr "Une nouvelle connexion a été rejetée avec raison: "
|
||||
|
||||
#: ../app/ui.js:1146
|
||||
msgid "New connection has been rejected"
|
||||
msgstr "Une nouvelle connexion a été rejetée"
|
||||
|
||||
#: ../app/ui.js:1181
|
||||
msgid "Credentials are required"
|
||||
msgstr "Les identifiants sont requis"
|
||||
|
||||
#: ../vnc.html:74
|
||||
msgid "noVNC encountered an error:"
|
||||
msgstr "noVNC a rencontré une erreur:"
|
||||
|
||||
#: ../vnc.html:84
|
||||
msgid "Hide/Show the control bar"
|
||||
msgstr "Masquer/Afficher la barre de contrôle"
|
||||
|
||||
#: ../vnc.html:91
|
||||
msgid "Drag"
|
||||
msgstr "Faire glisser"
|
||||
|
||||
#: ../vnc.html:91
|
||||
msgid "Move/Drag Viewport"
|
||||
msgstr "Déplacer/faire glisser Viewport"
|
||||
|
||||
#: ../vnc.html:97
|
||||
msgid "Keyboard"
|
||||
msgstr "Clavier"
|
||||
|
||||
#: ../vnc.html:97
|
||||
msgid "Show Keyboard"
|
||||
msgstr "Afficher le clavier"
|
||||
|
||||
#: ../vnc.html:102
|
||||
msgid "Extra keys"
|
||||
msgstr "Touches supplémentaires"
|
||||
|
||||
#: ../vnc.html:102
|
||||
msgid "Show Extra Keys"
|
||||
msgstr "Afficher les touches supplémentaires"
|
||||
|
||||
#: ../vnc.html:107
|
||||
msgid "Ctrl"
|
||||
msgstr "Ctrl"
|
||||
|
||||
#: ../vnc.html:107
|
||||
msgid "Toggle Ctrl"
|
||||
msgstr "Basculer Ctrl"
|
||||
|
||||
#: ../vnc.html:110
|
||||
msgid "Alt"
|
||||
msgstr "Alt"
|
||||
|
||||
#: ../vnc.html:110
|
||||
msgid "Toggle Alt"
|
||||
msgstr "Basculer Alt"
|
||||
|
||||
#: ../vnc.html:113
|
||||
msgid "Toggle Windows"
|
||||
msgstr "Basculer Windows"
|
||||
|
||||
#: ../vnc.html:113
|
||||
msgid "Windows"
|
||||
msgstr "Windows"
|
||||
|
||||
#: ../vnc.html:116
|
||||
msgid "Send Tab"
|
||||
msgstr "Envoyer l'onglet"
|
||||
|
||||
#: ../vnc.html:116
|
||||
msgid "Tab"
|
||||
msgstr "l'onglet"
|
||||
|
||||
#: ../vnc.html:119
|
||||
msgid "Esc"
|
||||
msgstr "Esc"
|
||||
|
||||
#: ../vnc.html:119
|
||||
msgid "Send Escape"
|
||||
msgstr "Envoyer Escape"
|
||||
|
||||
#: ../vnc.html:122
|
||||
msgid "Ctrl+Alt+Del"
|
||||
msgstr "Ctrl+Alt+Del"
|
||||
|
||||
#: ../vnc.html:122
|
||||
msgid "Send Ctrl-Alt-Del"
|
||||
msgstr "Envoyer Ctrl-Alt-Del"
|
||||
|
||||
#: ../vnc.html:129
|
||||
msgid "Shutdown/Reboot"
|
||||
msgstr "Arrêter/Redémarrer"
|
||||
|
||||
#: ../vnc.html:129
|
||||
msgid "Shutdown/Reboot..."
|
||||
msgstr "Arrêter/Redémarrer..."
|
||||
|
||||
#: ../vnc.html:135
|
||||
msgid "Power"
|
||||
msgstr "Alimentation"
|
||||
|
||||
#: ../vnc.html:137
|
||||
msgid "Shutdown"
|
||||
msgstr "Arrêter"
|
||||
|
||||
#: ../vnc.html:138
|
||||
msgid "Reboot"
|
||||
msgstr "Redémarrer"
|
||||
|
||||
#: ../vnc.html:139
|
||||
msgid "Reset"
|
||||
msgstr "Réinitialiser"
|
||||
|
||||
#: ../vnc.html:144 ../vnc.html:150
|
||||
msgid "Clipboard"
|
||||
msgstr "Presse-papiers"
|
||||
|
||||
#: ../vnc.html:154
|
||||
msgid "Clear"
|
||||
msgstr "Effacer"
|
||||
|
||||
#: ../vnc.html:160
|
||||
msgid "Fullscreen"
|
||||
msgstr "Plein écran"
|
||||
|
||||
#: ../vnc.html:165 ../vnc.html:172
|
||||
msgid "Settings"
|
||||
msgstr "Paramètres"
|
||||
|
||||
#: ../vnc.html:175
|
||||
msgid "Shared Mode"
|
||||
msgstr "Mode partagé"
|
||||
|
||||
#: ../vnc.html:178
|
||||
msgid "View Only"
|
||||
msgstr "Afficher uniquement"
|
||||
|
||||
#: ../vnc.html:182
|
||||
msgid "Clip to Window"
|
||||
msgstr "Clip à fenêtre"
|
||||
|
||||
#: ../vnc.html:185
|
||||
msgid "Scaling Mode:"
|
||||
msgstr "Mode mise à l'échelle:"
|
||||
|
||||
#: ../vnc.html:187
|
||||
msgid "None"
|
||||
msgstr "Aucun"
|
||||
|
||||
#: ../vnc.html:188
|
||||
msgid "Local Scaling"
|
||||
msgstr "Mise à l'échelle locale"
|
||||
|
||||
#: ../vnc.html:189
|
||||
msgid "Remote Resizing"
|
||||
msgstr "Redimensionnement à distance"
|
||||
|
||||
#: ../vnc.html:194
|
||||
msgid "Advanced"
|
||||
msgstr "Avancé"
|
||||
|
||||
#: ../vnc.html:197
|
||||
msgid "Quality:"
|
||||
msgstr "Qualité:"
|
||||
|
||||
#: ../vnc.html:201
|
||||
msgid "Compression level:"
|
||||
msgstr "Niveau de compression:"
|
||||
|
||||
#: ../vnc.html:206
|
||||
msgid "Repeater ID:"
|
||||
msgstr "ID Répéteur:"
|
||||
|
||||
#: ../vnc.html:210
|
||||
msgid "WebSocket"
|
||||
msgstr "WebSocket"
|
||||
|
||||
#: ../vnc.html:213
|
||||
msgid "Encrypt"
|
||||
msgstr "Crypter"
|
||||
|
||||
#: ../vnc.html:216
|
||||
msgid "Host:"
|
||||
msgstr "Hôte:"
|
||||
|
||||
#: ../vnc.html:220
|
||||
msgid "Port:"
|
||||
msgstr "Port:"
|
||||
|
||||
#: ../vnc.html:224
|
||||
msgid "Path:"
|
||||
msgstr "Chemin:"
|
||||
|
||||
#: ../vnc.html:231
|
||||
msgid "Automatic Reconnect"
|
||||
msgstr "Reconnecter automatiquemen"
|
||||
|
||||
#: ../vnc.html:234
|
||||
msgid "Reconnect Delay (ms):"
|
||||
msgstr "Délai de reconnexion (ms):"
|
||||
|
||||
#: ../vnc.html:239
|
||||
msgid "Show Dot when No Cursor"
|
||||
msgstr "Afficher le point lorsqu'il n'y a pas de curseur"
|
||||
|
||||
#: ../vnc.html:244
|
||||
msgid "Logging:"
|
||||
msgstr "Se connecter:"
|
||||
|
||||
#: ../vnc.html:253
|
||||
msgid "Version:"
|
||||
msgstr "Version:"
|
||||
|
||||
#: ../vnc.html:261
|
||||
msgid "Disconnect"
|
||||
msgstr "Déconnecter"
|
||||
|
||||
#: ../vnc.html:280
|
||||
msgid "Connect"
|
||||
msgstr "Connecter"
|
||||
|
||||
#: ../vnc.html:290
|
||||
msgid "Username:"
|
||||
msgstr "Nom d'utilisateur:"
|
||||
|
||||
#: ../vnc.html:294
|
||||
msgid "Password:"
|
||||
msgstr "Mot de passe:"
|
||||
|
||||
#: ../vnc.html:298
|
||||
msgid "Send Credentials"
|
||||
msgstr "Envoyer les identifiants"
|
||||
|
||||
#: ../vnc.html:308
|
||||
msgid "Cancel"
|
||||
msgstr "Annuler"
|
||||
@@ -0,0 +1,324 @@
|
||||
# Japanese translations for noVNC package
|
||||
# noVNC パッケージに対する日訳
|
||||
# Copyright (C) 2019 The noVNC Authors
|
||||
# This file is distributed under the same license as the noVNC package.
|
||||
# nnn1590 <nnn1590@nnn1590.org>, 2019-2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: noVNC 1.1.0\n"
|
||||
"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
|
||||
"POT-Creation-Date: 2020-07-03 16:11+0200\n"
|
||||
"PO-Revision-Date: 2021-01-15 12:37+0900\n"
|
||||
"Last-Translator: nnn1590 <nnn1590@nnn1590.org>\n"
|
||||
"Language-Team: Japanese\n"
|
||||
"Language: ja\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"X-Generator: Poedit 2.3\n"
|
||||
|
||||
#: ../app/ui.js:394
|
||||
msgid "Connecting..."
|
||||
msgstr "接続しています..."
|
||||
|
||||
#: ../app/ui.js:401
|
||||
msgid "Disconnecting..."
|
||||
msgstr "切断しています..."
|
||||
|
||||
#: ../app/ui.js:407
|
||||
msgid "Reconnecting..."
|
||||
msgstr "再接続しています..."
|
||||
|
||||
#: ../app/ui.js:412
|
||||
msgid "Internal error"
|
||||
msgstr "内部エラー"
|
||||
|
||||
#: ../app/ui.js:1008
|
||||
msgid "Must set host"
|
||||
msgstr "ホストを設定する必要があります"
|
||||
|
||||
#: ../app/ui.js:1090
|
||||
msgid "Connected (encrypted) to "
|
||||
msgstr "接続しました (暗号化済み): "
|
||||
|
||||
#: ../app/ui.js:1092
|
||||
msgid "Connected (unencrypted) to "
|
||||
msgstr "接続しました (暗号化されていません): "
|
||||
|
||||
#: ../app/ui.js:1115
|
||||
msgid "Something went wrong, connection is closed"
|
||||
msgstr "何らかの問題で、接続が閉じられました"
|
||||
|
||||
#: ../app/ui.js:1118
|
||||
msgid "Failed to connect to server"
|
||||
msgstr "サーバーへの接続に失敗しました"
|
||||
|
||||
#: ../app/ui.js:1128
|
||||
msgid "Disconnected"
|
||||
msgstr "切断しました"
|
||||
|
||||
#: ../app/ui.js:1143
|
||||
msgid "New connection has been rejected with reason: "
|
||||
msgstr "新規接続は次の理由で拒否されました: "
|
||||
|
||||
#: ../app/ui.js:1146
|
||||
msgid "New connection has been rejected"
|
||||
msgstr "新規接続は拒否されました"
|
||||
|
||||
#: ../app/ui.js:1181
|
||||
msgid "Credentials are required"
|
||||
msgstr "資格情報が必要です"
|
||||
|
||||
#: ../vnc.html:74
|
||||
msgid "noVNC encountered an error:"
|
||||
msgstr "noVNC でエラーが発生しました:"
|
||||
|
||||
#: ../vnc.html:84
|
||||
msgid "Hide/Show the control bar"
|
||||
msgstr "コントロールバーを隠す/表示する"
|
||||
|
||||
#: ../vnc.html:91
|
||||
msgid "Drag"
|
||||
msgstr "ドラッグ"
|
||||
|
||||
#: ../vnc.html:91
|
||||
msgid "Move/Drag Viewport"
|
||||
msgstr "ビューポートを移動/ドラッグ"
|
||||
|
||||
#: ../vnc.html:97
|
||||
msgid "Keyboard"
|
||||
msgstr "キーボード"
|
||||
|
||||
#: ../vnc.html:97
|
||||
msgid "Show Keyboard"
|
||||
msgstr "キーボードを表示"
|
||||
|
||||
#: ../vnc.html:102
|
||||
msgid "Extra keys"
|
||||
msgstr "追加キー"
|
||||
|
||||
#: ../vnc.html:102
|
||||
msgid "Show Extra Keys"
|
||||
msgstr "追加キーを表示"
|
||||
|
||||
#: ../vnc.html:107
|
||||
msgid "Ctrl"
|
||||
msgstr "Ctrl"
|
||||
|
||||
#: ../vnc.html:107
|
||||
msgid "Toggle Ctrl"
|
||||
msgstr "Ctrl キーを切り替え"
|
||||
|
||||
#: ../vnc.html:110
|
||||
msgid "Alt"
|
||||
msgstr "Alt"
|
||||
|
||||
#: ../vnc.html:110
|
||||
msgid "Toggle Alt"
|
||||
msgstr "Alt キーを切り替え"
|
||||
|
||||
#: ../vnc.html:113
|
||||
msgid "Toggle Windows"
|
||||
msgstr "Windows キーを切り替え"
|
||||
|
||||
#: ../vnc.html:113
|
||||
msgid "Windows"
|
||||
msgstr "Windows"
|
||||
|
||||
#: ../vnc.html:116
|
||||
msgid "Send Tab"
|
||||
msgstr "Tab キーを送信"
|
||||
|
||||
#: ../vnc.html:116
|
||||
msgid "Tab"
|
||||
msgstr "Tab"
|
||||
|
||||
#: ../vnc.html:119
|
||||
msgid "Esc"
|
||||
msgstr "Esc"
|
||||
|
||||
#: ../vnc.html:119
|
||||
msgid "Send Escape"
|
||||
msgstr "Escape キーを送信"
|
||||
|
||||
#: ../vnc.html:122
|
||||
msgid "Ctrl+Alt+Del"
|
||||
msgstr "Ctrl+Alt+Del"
|
||||
|
||||
#: ../vnc.html:122
|
||||
msgid "Send Ctrl-Alt-Del"
|
||||
msgstr "Ctrl-Alt-Del を送信"
|
||||
|
||||
#: ../vnc.html:129
|
||||
msgid "Shutdown/Reboot"
|
||||
msgstr "シャットダウン/再起動"
|
||||
|
||||
#: ../vnc.html:129
|
||||
msgid "Shutdown/Reboot..."
|
||||
msgstr "シャットダウン/再起動..."
|
||||
|
||||
#: ../vnc.html:135
|
||||
msgid "Power"
|
||||
msgstr "電源"
|
||||
|
||||
#: ../vnc.html:137
|
||||
msgid "Shutdown"
|
||||
msgstr "シャットダウン"
|
||||
|
||||
#: ../vnc.html:138
|
||||
msgid "Reboot"
|
||||
msgstr "再起動"
|
||||
|
||||
#: ../vnc.html:139
|
||||
msgid "Reset"
|
||||
msgstr "リセット"
|
||||
|
||||
#: ../vnc.html:144 ../vnc.html:150
|
||||
msgid "Clipboard"
|
||||
msgstr "クリップボード"
|
||||
|
||||
#: ../vnc.html:154
|
||||
msgid "Clear"
|
||||
msgstr "クリア"
|
||||
|
||||
#: ../vnc.html:160
|
||||
msgid "Fullscreen"
|
||||
msgstr "全画面表示"
|
||||
|
||||
#: ../vnc.html:165 ../vnc.html:172
|
||||
msgid "Settings"
|
||||
msgstr "設定"
|
||||
|
||||
#: ../vnc.html:175
|
||||
msgid "Shared Mode"
|
||||
msgstr "共有モード"
|
||||
|
||||
#: ../vnc.html:178
|
||||
msgid "View Only"
|
||||
msgstr "表示のみ"
|
||||
|
||||
#: ../vnc.html:182
|
||||
msgid "Clip to Window"
|
||||
msgstr "ウィンドウにクリップ"
|
||||
|
||||
#: ../vnc.html:185
|
||||
msgid "Scaling Mode:"
|
||||
msgstr "スケーリングモード:"
|
||||
|
||||
#: ../vnc.html:187
|
||||
msgid "None"
|
||||
msgstr "なし"
|
||||
|
||||
#: ../vnc.html:188
|
||||
msgid "Local Scaling"
|
||||
msgstr "ローカルスケーリング"
|
||||
|
||||
#: ../vnc.html:189
|
||||
msgid "Remote Resizing"
|
||||
msgstr "リモートでリサイズ"
|
||||
|
||||
#: ../vnc.html:194
|
||||
msgid "Advanced"
|
||||
msgstr "高度"
|
||||
|
||||
#: ../vnc.html:197
|
||||
msgid "Quality:"
|
||||
msgstr "品質:"
|
||||
|
||||
#: ../vnc.html:201
|
||||
msgid "Compression level:"
|
||||
msgstr "圧縮レベル:"
|
||||
|
||||
#: ../vnc.html:206
|
||||
msgid "Repeater ID:"
|
||||
msgstr "リピーター ID:"
|
||||
|
||||
#: ../vnc.html:210
|
||||
msgid "WebSocket"
|
||||
msgstr "WebSocket"
|
||||
|
||||
#: ../vnc.html:213
|
||||
msgid "Encrypt"
|
||||
msgstr "暗号化"
|
||||
|
||||
#: ../vnc.html:216
|
||||
msgid "Host:"
|
||||
msgstr "ホスト:"
|
||||
|
||||
#: ../vnc.html:220
|
||||
msgid "Port:"
|
||||
msgstr "ポート:"
|
||||
|
||||
#: ../vnc.html:224
|
||||
msgid "Path:"
|
||||
msgstr "パス:"
|
||||
|
||||
#: ../vnc.html:231
|
||||
msgid "Automatic Reconnect"
|
||||
msgstr "自動再接続"
|
||||
|
||||
#: ../vnc.html:234
|
||||
msgid "Reconnect Delay (ms):"
|
||||
msgstr "再接続する遅延 (ミリ秒):"
|
||||
|
||||
#: ../vnc.html:239
|
||||
msgid "Show Dot when No Cursor"
|
||||
msgstr "カーソルがないときにドットを表示"
|
||||
|
||||
#: ../vnc.html:244
|
||||
msgid "Logging:"
|
||||
msgstr "ロギング:"
|
||||
|
||||
#: ../vnc.html:253
|
||||
msgid "Version:"
|
||||
msgstr "バージョン:"
|
||||
|
||||
#: ../vnc.html:261
|
||||
msgid "Disconnect"
|
||||
msgstr "切断"
|
||||
|
||||
#: ../vnc.html:280
|
||||
msgid "Connect"
|
||||
msgstr "接続"
|
||||
|
||||
#: ../vnc.html:290
|
||||
msgid "Username:"
|
||||
msgstr "ユーザー名:"
|
||||
|
||||
#: ../vnc.html:294
|
||||
msgid "Password:"
|
||||
msgstr "パスワード:"
|
||||
|
||||
#: ../vnc.html:298
|
||||
msgid "Send Credentials"
|
||||
msgstr "資格情報を送信"
|
||||
|
||||
#: ../vnc.html:308
|
||||
msgid "Cancel"
|
||||
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 "パスワードを送信"
|
||||
@@ -0,0 +1,290 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) 2018 The noVNC Authors
|
||||
# This file is distributed under the same license as the noVNC package.
|
||||
# Baw Appie <pp121324@gmail.com>, 2018.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: noVNC 1.0.0-testing.2\n"
|
||||
"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
|
||||
"POT-Creation-Date: 2018-01-31 16:29+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Baw Appie <pp121324@gmail.com>\n"
|
||||
"Language-Team: Korean\n"
|
||||
"Language: ko\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: ../app/ui.js:395
|
||||
msgid "Connecting..."
|
||||
msgstr "연결중..."
|
||||
|
||||
#: ../app/ui.js:402
|
||||
msgid "Disconnecting..."
|
||||
msgstr "연결 해제중..."
|
||||
|
||||
#: ../app/ui.js:408
|
||||
msgid "Reconnecting..."
|
||||
msgstr "재연결중..."
|
||||
|
||||
#: ../app/ui.js:413
|
||||
msgid "Internal error"
|
||||
msgstr "내부 오류"
|
||||
|
||||
#: ../app/ui.js:1002
|
||||
msgid "Must set host"
|
||||
msgstr "호스트는 설정되어야 합니다."
|
||||
|
||||
#: ../app/ui.js:1083
|
||||
msgid "Connected (encrypted) to "
|
||||
msgstr "다음과 (암호화되어) 연결되었습니다:"
|
||||
|
||||
#: ../app/ui.js:1085
|
||||
msgid "Connected (unencrypted) to "
|
||||
msgstr "다음과 (암호화 없이) 연결되었습니다:"
|
||||
|
||||
#: ../app/ui.js:1108
|
||||
msgid "Something went wrong, connection is closed"
|
||||
msgstr "무언가 잘못되었습니다, 연결이 닫혔습니다."
|
||||
|
||||
#: ../app/ui.js:1111
|
||||
msgid "Failed to connect to server"
|
||||
msgstr "서버에 연결하지 못했습니다."
|
||||
|
||||
#: ../app/ui.js:1121
|
||||
msgid "Disconnected"
|
||||
msgstr "연결이 해제되었습니다."
|
||||
|
||||
#: ../app/ui.js:1134
|
||||
msgid "New connection has been rejected with reason: "
|
||||
msgstr "새 연결이 다음 이유로 거부되었습니다:"
|
||||
|
||||
#: ../app/ui.js:1137
|
||||
msgid "New connection has been rejected"
|
||||
msgstr "새 연결이 거부되었습니다."
|
||||
|
||||
#: ../app/ui.js:1158
|
||||
msgid "Password is required"
|
||||
msgstr "비밀번호가 필요합니다."
|
||||
|
||||
#: ../vnc.html:91
|
||||
msgid "noVNC encountered an error:"
|
||||
msgstr "noVNC에 오류가 발생했습니다:"
|
||||
|
||||
#: ../vnc.html:101
|
||||
msgid "Hide/Show the control bar"
|
||||
msgstr "컨트롤 바 숨기기/보이기"
|
||||
|
||||
#: ../vnc.html:108
|
||||
msgid "Move/Drag Viewport"
|
||||
msgstr "움직이기/드래그 뷰포트"
|
||||
|
||||
#: ../vnc.html:108
|
||||
msgid "viewport drag"
|
||||
msgstr "뷰포트 드래그"
|
||||
|
||||
#: ../vnc.html:114 ../vnc.html:117 ../vnc.html:120 ../vnc.html:123
|
||||
msgid "Active Mouse Button"
|
||||
msgstr "마우스 버튼 활성화"
|
||||
|
||||
#: ../vnc.html:114
|
||||
msgid "No mousebutton"
|
||||
msgstr "마우스 버튼 없음"
|
||||
|
||||
#: ../vnc.html:117
|
||||
msgid "Left mousebutton"
|
||||
msgstr "왼쪽 마우스 버튼"
|
||||
|
||||
#: ../vnc.html:120
|
||||
msgid "Middle mousebutton"
|
||||
msgstr "중간 마우스 버튼"
|
||||
|
||||
#: ../vnc.html:123
|
||||
msgid "Right mousebutton"
|
||||
msgstr "오른쪽 마우스 버튼"
|
||||
|
||||
#: ../vnc.html:126
|
||||
msgid "Keyboard"
|
||||
msgstr "키보드"
|
||||
|
||||
#: ../vnc.html:126
|
||||
msgid "Show Keyboard"
|
||||
msgstr "키보드 보이기"
|
||||
|
||||
#: ../vnc.html:133
|
||||
msgid "Extra keys"
|
||||
msgstr "기타 키들"
|
||||
|
||||
#: ../vnc.html:133
|
||||
msgid "Show Extra Keys"
|
||||
msgstr "기타 키들 보이기"
|
||||
|
||||
#: ../vnc.html:138
|
||||
msgid "Ctrl"
|
||||
msgstr "Ctrl"
|
||||
|
||||
#: ../vnc.html:138
|
||||
msgid "Toggle Ctrl"
|
||||
msgstr "Ctrl 켜기/끄기"
|
||||
|
||||
#: ../vnc.html:141
|
||||
msgid "Alt"
|
||||
msgstr "Alt"
|
||||
|
||||
#: ../vnc.html:141
|
||||
msgid "Toggle Alt"
|
||||
msgstr "Alt 켜기/끄기"
|
||||
|
||||
#: ../vnc.html:144
|
||||
msgid "Send Tab"
|
||||
msgstr "Tab 보내기"
|
||||
|
||||
#: ../vnc.html:144
|
||||
msgid "Tab"
|
||||
msgstr "Tab"
|
||||
|
||||
#: ../vnc.html:147
|
||||
msgid "Esc"
|
||||
msgstr "Esc"
|
||||
|
||||
#: ../vnc.html:147
|
||||
msgid "Send Escape"
|
||||
msgstr "Esc 보내기"
|
||||
|
||||
#: ../vnc.html:150
|
||||
msgid "Ctrl+Alt+Del"
|
||||
msgstr "Ctrl+Alt+Del"
|
||||
|
||||
#: ../vnc.html:150
|
||||
msgid "Send Ctrl-Alt-Del"
|
||||
msgstr "Ctrl+Alt+Del 보내기"
|
||||
|
||||
#: ../vnc.html:158
|
||||
msgid "Shutdown/Reboot"
|
||||
msgstr "셧다운/리붓"
|
||||
|
||||
#: ../vnc.html:158
|
||||
msgid "Shutdown/Reboot..."
|
||||
msgstr "셧다운/리붓..."
|
||||
|
||||
#: ../vnc.html:164
|
||||
msgid "Power"
|
||||
msgstr "전원"
|
||||
|
||||
#: ../vnc.html:166
|
||||
msgid "Shutdown"
|
||||
msgstr "셧다운"
|
||||
|
||||
#: ../vnc.html:167
|
||||
msgid "Reboot"
|
||||
msgstr "리붓"
|
||||
|
||||
#: ../vnc.html:168
|
||||
msgid "Reset"
|
||||
msgstr "리셋"
|
||||
|
||||
#: ../vnc.html:173 ../vnc.html:179
|
||||
msgid "Clipboard"
|
||||
msgstr "클립보드"
|
||||
|
||||
#: ../vnc.html:183
|
||||
msgid "Clear"
|
||||
msgstr "지우기"
|
||||
|
||||
#: ../vnc.html:189
|
||||
msgid "Fullscreen"
|
||||
msgstr "전체화면"
|
||||
|
||||
#: ../vnc.html:194 ../vnc.html:201
|
||||
msgid "Settings"
|
||||
msgstr "설정"
|
||||
|
||||
#: ../vnc.html:204
|
||||
msgid "Shared Mode"
|
||||
msgstr "공유 모드"
|
||||
|
||||
#: ../vnc.html:207
|
||||
msgid "View Only"
|
||||
msgstr "보기 전용"
|
||||
|
||||
#: ../vnc.html:211
|
||||
msgid "Clip to Window"
|
||||
msgstr "창에 클립"
|
||||
|
||||
#: ../vnc.html:214
|
||||
msgid "Scaling Mode:"
|
||||
msgstr "스케일링 모드:"
|
||||
|
||||
#: ../vnc.html:216
|
||||
msgid "None"
|
||||
msgstr "없음"
|
||||
|
||||
#: ../vnc.html:217
|
||||
msgid "Local Scaling"
|
||||
msgstr "로컬 스케일링"
|
||||
|
||||
#: ../vnc.html:218
|
||||
msgid "Remote Resizing"
|
||||
msgstr "원격 크기 조절"
|
||||
|
||||
#: ../vnc.html:223
|
||||
msgid "Advanced"
|
||||
msgstr "고급"
|
||||
|
||||
#: ../vnc.html:226
|
||||
msgid "Repeater ID:"
|
||||
msgstr "중계 ID"
|
||||
|
||||
#: ../vnc.html:230
|
||||
msgid "WebSocket"
|
||||
msgstr "웹소켓"
|
||||
|
||||
#: ../vnc.html:233
|
||||
msgid "Encrypt"
|
||||
msgstr "암호화"
|
||||
|
||||
#: ../vnc.html:236
|
||||
msgid "Host:"
|
||||
msgstr "호스트:"
|
||||
|
||||
#: ../vnc.html:240
|
||||
msgid "Port:"
|
||||
msgstr "포트:"
|
||||
|
||||
#: ../vnc.html:244
|
||||
msgid "Path:"
|
||||
msgstr "위치:"
|
||||
|
||||
#: ../vnc.html:251
|
||||
msgid "Automatic Reconnect"
|
||||
msgstr "자동 재연결"
|
||||
|
||||
#: ../vnc.html:254
|
||||
msgid "Reconnect Delay (ms):"
|
||||
msgstr "재연결 지연 시간 (ms)"
|
||||
|
||||
#: ../vnc.html:260
|
||||
msgid "Logging:"
|
||||
msgstr "로깅"
|
||||
|
||||
#: ../vnc.html:272
|
||||
msgid "Disconnect"
|
||||
msgstr "연결 해제"
|
||||
|
||||
#: ../vnc.html:291
|
||||
msgid "Connect"
|
||||
msgstr "연결"
|
||||
|
||||
#: ../vnc.html:301
|
||||
msgid "Password:"
|
||||
msgstr "비밀번호:"
|
||||
|
||||
#: ../vnc.html:305
|
||||
msgid "Send Password"
|
||||
msgstr "비밀번호 전송"
|
||||
|
||||
#: ../vnc.html:315
|
||||
msgid "Cancel"
|
||||
msgstr "취소"
|
||||
@@ -1,16 +1,16 @@
|
||||
# Dutch translations for noVNC package
|
||||
# Nederlandse vertalingen voor het pakket noVNC.
|
||||
# Copyright (C) 2016 Various Authors
|
||||
# Copyright (C) 2018 The noVNC Authors
|
||||
# This file is distributed under the same license as the noVNC package.
|
||||
# Loek Janssen <loekjanssen@gmail.com>, 2016.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: noVNC 0.6.1\n"
|
||||
"Project-Id-Version: noVNC 1.1.0\n"
|
||||
"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
|
||||
"POT-Creation-Date: 2017-10-06 10:07+0200\n"
|
||||
"PO-Revision-Date: 2017-10-11 16:16+0200\n"
|
||||
"Last-Translator: Yuri van Oers <yvanoers@gmail.com>\n"
|
||||
"POT-Creation-Date: 2019-04-09 11:06+0100\n"
|
||||
"PO-Revision-Date: 2019-04-09 17:17+0100\n"
|
||||
"Last-Translator: Arend Lapere <arend.lapere@gmail.com>\n"
|
||||
"Language-Team: none\n"
|
||||
"Language: nl\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@@ -18,269 +18,301 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: ../app/ui.js:430
|
||||
#: ../app/ui.js:383
|
||||
msgid "Connecting..."
|
||||
msgstr "Verbinden..."
|
||||
|
||||
#: ../app/ui.js:438
|
||||
msgid "Connected (encrypted) to "
|
||||
msgstr "Verbonden (versleuteld) met "
|
||||
|
||||
#: ../app/ui.js:440
|
||||
msgid "Connected (unencrypted) to "
|
||||
msgstr "Verbonden (onversleuteld) met "
|
||||
|
||||
#: ../app/ui.js:446
|
||||
#: ../app/ui.js:390
|
||||
msgid "Disconnecting..."
|
||||
msgstr "Verbinding verbreken..."
|
||||
|
||||
#: ../app/ui.js:450
|
||||
msgid "Disconnected"
|
||||
msgstr "Verbinding verbroken"
|
||||
|
||||
#: ../app/ui.js:1052 ../core/rfb.js:248
|
||||
msgid "Must set host"
|
||||
msgstr "Host moeten worden ingesteld"
|
||||
|
||||
#: ../app/ui.js:1101
|
||||
#: ../app/ui.js:396
|
||||
msgid "Reconnecting..."
|
||||
msgstr "Opnieuw verbinding maken..."
|
||||
|
||||
#: ../app/ui.js:1140
|
||||
#: ../app/ui.js:401
|
||||
msgid "Internal error"
|
||||
msgstr "Interne fout"
|
||||
|
||||
#: ../app/ui.js:991
|
||||
msgid "Must set host"
|
||||
msgstr "Host moeten worden ingesteld"
|
||||
|
||||
#: ../app/ui.js:1073
|
||||
msgid "Connected (encrypted) to "
|
||||
msgstr "Verbonden (versleuteld) met "
|
||||
|
||||
#: ../app/ui.js:1075
|
||||
msgid "Connected (unencrypted) to "
|
||||
msgstr "Verbonden (onversleuteld) met "
|
||||
|
||||
#: ../app/ui.js:1098
|
||||
msgid "Something went wrong, connection is closed"
|
||||
msgstr "Er iets fout gelopen, verbinding werd verbroken"
|
||||
|
||||
#: ../app/ui.js:1101
|
||||
msgid "Failed to connect to server"
|
||||
msgstr "Verbinding maken met server is mislukt"
|
||||
|
||||
#: ../app/ui.js:1111
|
||||
msgid "Disconnected"
|
||||
msgstr "Verbinding verbroken"
|
||||
|
||||
#: ../app/ui.js:1124
|
||||
msgid "New connection has been rejected with reason: "
|
||||
msgstr "Nieuwe verbinding is geweigerd omwille van de volgende reden: "
|
||||
|
||||
#: ../app/ui.js:1127
|
||||
msgid "New connection has been rejected"
|
||||
msgstr "Nieuwe verbinding is geweigerd"
|
||||
|
||||
#: ../app/ui.js:1147
|
||||
msgid "Password is required"
|
||||
msgstr "Wachtwoord is vereist"
|
||||
|
||||
#: ../core/rfb.js:548
|
||||
msgid "Disconnect timeout"
|
||||
msgstr "Timeout tijdens verbreken van verbinding"
|
||||
|
||||
#: ../vnc.html:89
|
||||
#: ../vnc.html:80
|
||||
msgid "noVNC encountered an error:"
|
||||
msgstr "noVNC heeft een fout bemerkt:"
|
||||
|
||||
#: ../vnc.html:99
|
||||
#: ../vnc.html:90
|
||||
msgid "Hide/Show the control bar"
|
||||
msgstr "Verberg/Toon de bedieningsbalk"
|
||||
|
||||
#: ../vnc.html:106
|
||||
#: ../vnc.html:97
|
||||
msgid "Move/Drag Viewport"
|
||||
msgstr "Verplaats/Versleep Kijkvenster"
|
||||
|
||||
#: ../vnc.html:106
|
||||
#: ../vnc.html:97
|
||||
msgid "viewport drag"
|
||||
msgstr "kijkvenster slepen"
|
||||
|
||||
#: ../vnc.html:112 ../vnc.html:115 ../vnc.html:118 ../vnc.html:121
|
||||
#: ../vnc.html:103 ../vnc.html:106 ../vnc.html:109 ../vnc.html:112
|
||||
msgid "Active Mouse Button"
|
||||
msgstr "Actieve Muisknop"
|
||||
|
||||
#: ../vnc.html:112
|
||||
#: ../vnc.html:103
|
||||
msgid "No mousebutton"
|
||||
msgstr "Geen muisknop"
|
||||
|
||||
#: ../vnc.html:115
|
||||
#: ../vnc.html:106
|
||||
msgid "Left mousebutton"
|
||||
msgstr "Linker muisknop"
|
||||
|
||||
#: ../vnc.html:118
|
||||
#: ../vnc.html:109
|
||||
msgid "Middle mousebutton"
|
||||
msgstr "Middelste muisknop"
|
||||
|
||||
#: ../vnc.html:121
|
||||
#: ../vnc.html:112
|
||||
msgid "Right mousebutton"
|
||||
msgstr "Rechter muisknop"
|
||||
|
||||
#: ../vnc.html:124
|
||||
#: ../vnc.html:115
|
||||
msgid "Keyboard"
|
||||
msgstr "Toetsenbord"
|
||||
|
||||
#: ../vnc.html:124
|
||||
#: ../vnc.html:115
|
||||
msgid "Show Keyboard"
|
||||
msgstr "Toon Toetsenbord"
|
||||
|
||||
#: ../vnc.html:131
|
||||
#: ../vnc.html:121
|
||||
msgid "Extra keys"
|
||||
msgstr "Extra toetsen"
|
||||
|
||||
#: ../vnc.html:131
|
||||
#: ../vnc.html:121
|
||||
msgid "Show Extra Keys"
|
||||
msgstr "Toon Extra Toetsen"
|
||||
|
||||
#: ../vnc.html:136
|
||||
#: ../vnc.html:126
|
||||
msgid "Ctrl"
|
||||
msgstr "Ctrl"
|
||||
|
||||
#: ../vnc.html:136
|
||||
#: ../vnc.html:126
|
||||
msgid "Toggle Ctrl"
|
||||
msgstr "Ctrl aan/uitzetten"
|
||||
msgstr "Ctrl omschakelen"
|
||||
|
||||
#: ../vnc.html:139
|
||||
#: ../vnc.html:129
|
||||
msgid "Alt"
|
||||
msgstr "Alt"
|
||||
|
||||
#: ../vnc.html:139
|
||||
#: ../vnc.html:129
|
||||
msgid "Toggle Alt"
|
||||
msgstr "Alt aan/uitzetten"
|
||||
msgstr "Alt omschakelen"
|
||||
|
||||
#: ../vnc.html:142
|
||||
#: ../vnc.html:132
|
||||
msgid "Toggle Windows"
|
||||
msgstr "Windows omschakelen"
|
||||
|
||||
#: ../vnc.html:132
|
||||
msgid "Windows"
|
||||
msgstr "Windows"
|
||||
|
||||
#: ../vnc.html:135
|
||||
msgid "Send Tab"
|
||||
msgstr "Tab Sturen"
|
||||
|
||||
#: ../vnc.html:142
|
||||
#: ../vnc.html:135
|
||||
msgid "Tab"
|
||||
msgstr "Tab"
|
||||
|
||||
#: ../vnc.html:145
|
||||
#: ../vnc.html:138
|
||||
msgid "Esc"
|
||||
msgstr "Esc"
|
||||
|
||||
#: ../vnc.html:145
|
||||
#: ../vnc.html:138
|
||||
msgid "Send Escape"
|
||||
msgstr "Escape Sturen"
|
||||
|
||||
#: ../vnc.html:148
|
||||
#: ../vnc.html:141
|
||||
msgid "Ctrl+Alt+Del"
|
||||
msgstr "Ctrl-Alt-Del"
|
||||
|
||||
#: ../vnc.html:148
|
||||
#: ../vnc.html:141
|
||||
msgid "Send Ctrl-Alt-Del"
|
||||
msgstr "Ctrl-Alt-Del Sturen"
|
||||
|
||||
#: ../vnc.html:156
|
||||
#: ../vnc.html:149
|
||||
msgid "Shutdown/Reboot"
|
||||
msgstr "Uitschakelen/Herstarten"
|
||||
|
||||
#: ../vnc.html:156
|
||||
#: ../vnc.html:149
|
||||
msgid "Shutdown/Reboot..."
|
||||
msgstr "Uitschakelen/Herstarten..."
|
||||
|
||||
#: ../vnc.html:162
|
||||
#: ../vnc.html:155
|
||||
msgid "Power"
|
||||
msgstr "Systeem"
|
||||
|
||||
#: ../vnc.html:164
|
||||
#: ../vnc.html:157
|
||||
msgid "Shutdown"
|
||||
msgstr "Uitschakelen"
|
||||
|
||||
#: ../vnc.html:165
|
||||
#: ../vnc.html:158
|
||||
msgid "Reboot"
|
||||
msgstr "Herstarten"
|
||||
|
||||
#: ../vnc.html:166
|
||||
#: ../vnc.html:159
|
||||
msgid "Reset"
|
||||
msgstr "Resetten"
|
||||
|
||||
#: ../vnc.html:171 ../vnc.html:177
|
||||
#: ../vnc.html:164 ../vnc.html:170
|
||||
msgid "Clipboard"
|
||||
msgstr "Klembord"
|
||||
|
||||
#: ../vnc.html:181
|
||||
#: ../vnc.html:174
|
||||
msgid "Clear"
|
||||
msgstr "Wissen"
|
||||
|
||||
#: ../vnc.html:187
|
||||
#: ../vnc.html:180
|
||||
msgid "Fullscreen"
|
||||
msgstr "Volledig Scherm"
|
||||
|
||||
#: ../vnc.html:192 ../vnc.html:199
|
||||
#: ../vnc.html:185 ../vnc.html:192
|
||||
msgid "Settings"
|
||||
msgstr "Instellingen"
|
||||
|
||||
#: ../vnc.html:202
|
||||
#: ../vnc.html:195
|
||||
msgid "Shared Mode"
|
||||
msgstr "Gedeelde Modus"
|
||||
|
||||
#: ../vnc.html:205
|
||||
#: ../vnc.html:198
|
||||
msgid "View Only"
|
||||
msgstr "Alleen Kijken"
|
||||
|
||||
#: ../vnc.html:209
|
||||
#: ../vnc.html:202
|
||||
msgid "Clip to Window"
|
||||
msgstr "Randen buiten venster afsnijden"
|
||||
|
||||
#: ../vnc.html:212
|
||||
#: ../vnc.html:205
|
||||
msgid "Scaling Mode:"
|
||||
msgstr "Schaalmodus:"
|
||||
|
||||
#: ../vnc.html:214
|
||||
#: ../vnc.html:207
|
||||
msgid "None"
|
||||
msgstr "Geen"
|
||||
|
||||
#: ../vnc.html:215
|
||||
#: ../vnc.html:208
|
||||
msgid "Local Scaling"
|
||||
msgstr "Lokaal Schalen"
|
||||
|
||||
#: ../vnc.html:216
|
||||
msgid "Local Downscaling"
|
||||
msgstr "Lokaal Neerschalen"
|
||||
|
||||
#: ../vnc.html:217
|
||||
#: ../vnc.html:209
|
||||
msgid "Remote Resizing"
|
||||
msgstr "Op Afstand Formaat Wijzigen"
|
||||
|
||||
#: ../vnc.html:222
|
||||
#: ../vnc.html:214
|
||||
msgid "Advanced"
|
||||
msgstr "Geavanceerd"
|
||||
|
||||
#: ../vnc.html:225
|
||||
msgid "Local Cursor"
|
||||
msgstr "Lokale Cursor"
|
||||
|
||||
#: ../vnc.html:229
|
||||
#: ../vnc.html:217
|
||||
msgid "Repeater ID:"
|
||||
msgstr "Repeater ID:"
|
||||
|
||||
#: ../vnc.html:233
|
||||
#: ../vnc.html:221
|
||||
msgid "WebSocket"
|
||||
msgstr "WebSocket"
|
||||
|
||||
#: ../vnc.html:236
|
||||
#: ../vnc.html:224
|
||||
msgid "Encrypt"
|
||||
msgstr "Versleutelen"
|
||||
|
||||
#: ../vnc.html:239
|
||||
#: ../vnc.html:227
|
||||
msgid "Host:"
|
||||
msgstr "Host:"
|
||||
|
||||
#: ../vnc.html:243
|
||||
#: ../vnc.html:231
|
||||
msgid "Port:"
|
||||
msgstr "Poort:"
|
||||
|
||||
#: ../vnc.html:247
|
||||
#: ../vnc.html:235
|
||||
msgid "Path:"
|
||||
msgstr "Pad:"
|
||||
|
||||
#: ../vnc.html:254
|
||||
#: ../vnc.html:242
|
||||
msgid "Automatic Reconnect"
|
||||
msgstr "Automatisch Opnieuw Verbinden"
|
||||
|
||||
#: ../vnc.html:257
|
||||
#: ../vnc.html:245
|
||||
msgid "Reconnect Delay (ms):"
|
||||
msgstr "Vertraging voor Opnieuw Verbinden (ms):"
|
||||
|
||||
#: ../vnc.html:263
|
||||
#: ../vnc.html:250
|
||||
msgid "Show Dot when No Cursor"
|
||||
msgstr "Geef stip weer indien geen cursor"
|
||||
|
||||
#: ../vnc.html:255
|
||||
msgid "Logging:"
|
||||
msgstr "Logmeldingen:"
|
||||
|
||||
#: ../vnc.html:275
|
||||
#: ../vnc.html:267
|
||||
msgid "Disconnect"
|
||||
msgstr "Verbinding verbreken"
|
||||
|
||||
#: ../vnc.html:294
|
||||
#: ../vnc.html:286
|
||||
msgid "Connect"
|
||||
msgstr "Verbinden"
|
||||
|
||||
#: ../vnc.html:304
|
||||
#: ../vnc.html:296
|
||||
msgid "Password:"
|
||||
msgstr "Wachtwoord:"
|
||||
|
||||
#: ../vnc.html:318
|
||||
#: ../vnc.html:300
|
||||
msgid "Send Password"
|
||||
msgstr "Verzend Wachtwoord:"
|
||||
|
||||
#: ../vnc.html:310
|
||||
msgid "Cancel"
|
||||
msgstr "Annuleren"
|
||||
|
||||
#: ../vnc.html:334
|
||||
msgid "Canvas not supported."
|
||||
msgstr "Canvas wordt niet ondersteund."
|
||||
#~ msgid "Disconnect timeout"
|
||||
#~ msgstr "Timeout tijdens verbreken van verbinding"
|
||||
|
||||
#~ msgid "Local Downscaling"
|
||||
#~ msgstr "Lokaal Neerschalen"
|
||||
|
||||
#~ msgid "Local Cursor"
|
||||
#~ msgstr "Lokale Cursor"
|
||||
|
||||
#~ msgid "Canvas not supported."
|
||||
#~ msgstr "Canvas wordt niet ondersteund."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Forcing clipping mode since scrollbars aren't supported by IE in "
|
||||
|
||||
+99
-91
@@ -1,14 +1,14 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR Various Authors
|
||||
# Copyright (C) YEAR The noVNC Authors
|
||||
# This file is distributed under the same license as the noVNC package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: noVNC 1.0.0-testing.2\n"
|
||||
"Project-Id-Version: noVNC 1.3.0\n"
|
||||
"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
|
||||
"POT-Creation-Date: 2018-01-31 16:29+0100\n"
|
||||
"POT-Creation-Date: 2021-08-27 16:03+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -17,274 +17,282 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: ../app/ui.js:395
|
||||
#: ../app/ui.js:400
|
||||
msgid "Connecting..."
|
||||
msgstr ""
|
||||
|
||||
#: ../app/ui.js:402
|
||||
#: ../app/ui.js:407
|
||||
msgid "Disconnecting..."
|
||||
msgstr ""
|
||||
|
||||
#: ../app/ui.js:408
|
||||
#: ../app/ui.js:413
|
||||
msgid "Reconnecting..."
|
||||
msgstr ""
|
||||
|
||||
#: ../app/ui.js:413
|
||||
#: ../app/ui.js:418
|
||||
msgid "Internal error"
|
||||
msgstr ""
|
||||
|
||||
#: ../app/ui.js:1002
|
||||
#: ../app/ui.js:1009
|
||||
msgid "Must set host"
|
||||
msgstr ""
|
||||
|
||||
#: ../app/ui.js:1083
|
||||
#: ../app/ui.js:1091
|
||||
msgid "Connected (encrypted) to "
|
||||
msgstr ""
|
||||
|
||||
#: ../app/ui.js:1085
|
||||
#: ../app/ui.js:1093
|
||||
msgid "Connected (unencrypted) to "
|
||||
msgstr ""
|
||||
|
||||
#: ../app/ui.js:1108
|
||||
#: ../app/ui.js:1116
|
||||
msgid "Something went wrong, connection is closed"
|
||||
msgstr ""
|
||||
|
||||
#: ../app/ui.js:1111
|
||||
#: ../app/ui.js:1119
|
||||
msgid "Failed to connect to server"
|
||||
msgstr ""
|
||||
|
||||
#: ../app/ui.js:1121
|
||||
#: ../app/ui.js:1129
|
||||
msgid "Disconnected"
|
||||
msgstr ""
|
||||
|
||||
#: ../app/ui.js:1134
|
||||
#: ../app/ui.js:1144
|
||||
msgid "New connection has been rejected with reason: "
|
||||
msgstr ""
|
||||
|
||||
#: ../app/ui.js:1137
|
||||
#: ../app/ui.js:1147
|
||||
msgid "New connection has been rejected"
|
||||
msgstr ""
|
||||
|
||||
#: ../app/ui.js:1158
|
||||
msgid "Password is required"
|
||||
#: ../app/ui.js:1182
|
||||
msgid "Credentials are required"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:91
|
||||
#: ../vnc.html:61
|
||||
msgid "noVNC encountered an error:"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:101
|
||||
#: ../vnc.html:71
|
||||
msgid "Hide/Show the control bar"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:108
|
||||
#: ../vnc.html:78
|
||||
msgid "Drag"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:78
|
||||
msgid "Move/Drag Viewport"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:108
|
||||
msgid "viewport drag"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:114 ../vnc.html:117 ../vnc.html:120 ../vnc.html:123
|
||||
msgid "Active Mouse Button"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:114
|
||||
msgid "No mousebutton"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:117
|
||||
msgid "Left mousebutton"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:120
|
||||
msgid "Middle mousebutton"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:123
|
||||
msgid "Right mousebutton"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:126
|
||||
#: ../vnc.html:84
|
||||
msgid "Keyboard"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:126
|
||||
#: ../vnc.html:84
|
||||
msgid "Show Keyboard"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:133
|
||||
#: ../vnc.html:89
|
||||
msgid "Extra keys"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:133
|
||||
#: ../vnc.html:89
|
||||
msgid "Show Extra Keys"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:138
|
||||
#: ../vnc.html:94
|
||||
msgid "Ctrl"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:138
|
||||
#: ../vnc.html:94
|
||||
msgid "Toggle Ctrl"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:141
|
||||
#: ../vnc.html:97
|
||||
msgid "Alt"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:141
|
||||
#: ../vnc.html:97
|
||||
msgid "Toggle Alt"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:144
|
||||
#: ../vnc.html:100
|
||||
msgid "Toggle Windows"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:100
|
||||
msgid "Windows"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:103
|
||||
msgid "Send Tab"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:144
|
||||
#: ../vnc.html:103
|
||||
msgid "Tab"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:147
|
||||
#: ../vnc.html:106
|
||||
msgid "Esc"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:147
|
||||
#: ../vnc.html:106
|
||||
msgid "Send Escape"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:150
|
||||
#: ../vnc.html:109
|
||||
msgid "Ctrl+Alt+Del"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:150
|
||||
#: ../vnc.html:109
|
||||
msgid "Send Ctrl-Alt-Del"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:158
|
||||
#: ../vnc.html:116
|
||||
msgid "Shutdown/Reboot"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:158
|
||||
#: ../vnc.html:116
|
||||
msgid "Shutdown/Reboot..."
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:164
|
||||
#: ../vnc.html:122
|
||||
msgid "Power"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:166
|
||||
#: ../vnc.html:124
|
||||
msgid "Shutdown"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:167
|
||||
#: ../vnc.html:125
|
||||
msgid "Reboot"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:168
|
||||
#: ../vnc.html:126
|
||||
msgid "Reset"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:173 ../vnc.html:179
|
||||
#: ../vnc.html:131 ../vnc.html:137
|
||||
msgid "Clipboard"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:183
|
||||
#: ../vnc.html:141
|
||||
msgid "Clear"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:189
|
||||
#: ../vnc.html:147
|
||||
msgid "Fullscreen"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:194 ../vnc.html:201
|
||||
#: ../vnc.html:152 ../vnc.html:159
|
||||
msgid "Settings"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:204
|
||||
#: ../vnc.html:162
|
||||
msgid "Shared Mode"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:207
|
||||
#: ../vnc.html:165
|
||||
msgid "View Only"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:211
|
||||
#: ../vnc.html:169
|
||||
msgid "Clip to Window"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:214
|
||||
#: ../vnc.html:172
|
||||
msgid "Scaling Mode:"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:216
|
||||
#: ../vnc.html:174
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:217
|
||||
#: ../vnc.html:175
|
||||
msgid "Local Scaling"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:218
|
||||
#: ../vnc.html:176
|
||||
msgid "Remote Resizing"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:223
|
||||
#: ../vnc.html:181
|
||||
msgid "Advanced"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:226
|
||||
#: ../vnc.html:184
|
||||
msgid "Quality:"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:188
|
||||
msgid "Compression level:"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:193
|
||||
msgid "Repeater ID:"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:230
|
||||
#: ../vnc.html:197
|
||||
msgid "WebSocket"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:233
|
||||
#: ../vnc.html:200
|
||||
msgid "Encrypt"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:236
|
||||
#: ../vnc.html:203
|
||||
msgid "Host:"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:240
|
||||
#: ../vnc.html:207
|
||||
msgid "Port:"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:244
|
||||
#: ../vnc.html:211
|
||||
msgid "Path:"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:251
|
||||
#: ../vnc.html:218
|
||||
msgid "Automatic Reconnect"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:254
|
||||
#: ../vnc.html:221
|
||||
msgid "Reconnect Delay (ms):"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:260
|
||||
#: ../vnc.html:226
|
||||
msgid "Show Dot when No Cursor"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:231
|
||||
msgid "Logging:"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:272
|
||||
#: ../vnc.html:240
|
||||
msgid "Version:"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:248
|
||||
msgid "Disconnect"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:291
|
||||
#: ../vnc.html:267
|
||||
msgid "Connect"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:301
|
||||
#: ../vnc.html:277
|
||||
msgid "Username:"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:281
|
||||
msgid "Password:"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:305
|
||||
msgid "Send Password"
|
||||
#: ../vnc.html:285
|
||||
msgid "Send Credentials"
|
||||
msgstr ""
|
||||
|
||||
#: ../vnc.html:315
|
||||
#: ../vnc.html:295
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Polish translations for noVNC package.
|
||||
# Copyright (C) 2017 Various Authors
|
||||
# Copyright (C) 2018 The noVNC Authors
|
||||
# This file is distributed under the same license as the noVNC package.
|
||||
# Mariusz Jamro <mariusz.jamro@gmail.com>, 2017.
|
||||
#
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
/*
|
||||
* ps2js: gettext .po to noVNC .js converter
|
||||
* Copyright (C) 2016 Pierre Ossman
|
||||
* Copyright (C) 2018 The noVNC Authors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -17,27 +17,27 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
var getopt = require('node-getopt');
|
||||
var fs = require('fs');
|
||||
var po2json = require("po2json");
|
||||
const getopt = require('node-getopt');
|
||||
const fs = require('fs');
|
||||
const po2json = require("po2json");
|
||||
|
||||
opt = getopt.create([
|
||||
['h' , 'help' , 'display this help'],
|
||||
const opt = getopt.create([
|
||||
['h', 'help', 'display this help'],
|
||||
]).bindHelp().parseSystem();
|
||||
|
||||
if (opt.argv.length != 2) {
|
||||
console.error("Incorrect number of arguments given");
|
||||
process.exit(1);
|
||||
console.error("Incorrect number of arguments given");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var data = po2json.parseFileSync(opt.argv[0]);
|
||||
const data = po2json.parseFileSync(opt.argv[0]);
|
||||
|
||||
var bodyPart = Object.keys(data).filter((msgid) => msgid !== "").map((msgid) => {
|
||||
const bodyPart = Object.keys(data).filter(msgid => msgid !== "").map((msgid) => {
|
||||
if (msgid === "") return;
|
||||
var msgstr = data[msgid][1];
|
||||
const msgstr = data[msgid][1];
|
||||
return " " + JSON.stringify(msgid) + ": " + JSON.stringify(msgstr);
|
||||
}).join(",\n");
|
||||
|
||||
var output = "{\n" + bodyPart + "\n}";
|
||||
const output = "{\n" + bodyPart + "\n}";
|
||||
|
||||
fs.writeFileSync(opt.argv[1], output);
|
||||
|
||||
+299
@@ -0,0 +1,299 @@
|
||||
# Portuguese translations for noVNC package.
|
||||
# Copyright (C) 2021 The noVNC Authors
|
||||
# This file is distributed under the same license as the noVNC package.
|
||||
# <liddack@outlook.com>, 2021.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: noVNC 1.2.0\n"
|
||||
"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
|
||||
"POT-Creation-Date: 2021-03-15 21:55-0300\n"
|
||||
"PO-Revision-Date: 2021-03-15 22:09-0300\n"
|
||||
"Last-Translator: <liddack@outlook.com>\n"
|
||||
"Language-Team: Brazilian Portuguese\n"
|
||||
"Language: pt_BR\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
"X-Generator: Poedit 2.4.1\n"
|
||||
|
||||
#: ../app/ui.js:400
|
||||
msgid "Connecting..."
|
||||
msgstr "Conectando..."
|
||||
|
||||
#: ../app/ui.js:407
|
||||
msgid "Disconnecting..."
|
||||
msgstr "Desconectando..."
|
||||
|
||||
#: ../app/ui.js:413
|
||||
msgid "Reconnecting..."
|
||||
msgstr "Reconectando..."
|
||||
|
||||
#: ../app/ui.js:418
|
||||
msgid "Internal error"
|
||||
msgstr "Erro interno"
|
||||
|
||||
#: ../app/ui.js:1009
|
||||
msgid "Must set host"
|
||||
msgstr "É necessário definir o host"
|
||||
|
||||
#: ../app/ui.js:1091
|
||||
msgid "Connected (encrypted) to "
|
||||
msgstr "Conectado (com criptografia) a "
|
||||
|
||||
#: ../app/ui.js:1093
|
||||
msgid "Connected (unencrypted) to "
|
||||
msgstr "Conectado (sem criptografia) a "
|
||||
|
||||
#: ../app/ui.js:1116
|
||||
msgid "Something went wrong, connection is closed"
|
||||
msgstr "Algo deu errado. A conexão foi encerrada."
|
||||
|
||||
#: ../app/ui.js:1119
|
||||
msgid "Failed to connect to server"
|
||||
msgstr "Falha ao conectar-se ao servidor"
|
||||
|
||||
#: ../app/ui.js:1129
|
||||
msgid "Disconnected"
|
||||
msgstr "Desconectado"
|
||||
|
||||
#: ../app/ui.js:1144
|
||||
msgid "New connection has been rejected with reason: "
|
||||
msgstr "A nova conexão foi rejeitada pelo motivo: "
|
||||
|
||||
#: ../app/ui.js:1147
|
||||
msgid "New connection has been rejected"
|
||||
msgstr "A nova conexão foi rejeitada"
|
||||
|
||||
#: ../app/ui.js:1182
|
||||
msgid "Credentials are required"
|
||||
msgstr "Credenciais são obrigatórias"
|
||||
|
||||
#: ../vnc.html:61
|
||||
msgid "noVNC encountered an error:"
|
||||
msgstr "O noVNC encontrou um erro:"
|
||||
|
||||
#: ../vnc.html:71
|
||||
msgid "Hide/Show the control bar"
|
||||
msgstr "Esconder/mostrar a barra de controles"
|
||||
|
||||
#: ../vnc.html:78
|
||||
msgid "Drag"
|
||||
msgstr "Arrastar"
|
||||
|
||||
#: ../vnc.html:78
|
||||
msgid "Move/Drag Viewport"
|
||||
msgstr "Mover/arrastar a janela"
|
||||
|
||||
#: ../vnc.html:84
|
||||
msgid "Keyboard"
|
||||
msgstr "Teclado"
|
||||
|
||||
#: ../vnc.html:84
|
||||
msgid "Show Keyboard"
|
||||
msgstr "Mostrar teclado"
|
||||
|
||||
#: ../vnc.html:89
|
||||
msgid "Extra keys"
|
||||
msgstr "Teclas adicionais"
|
||||
|
||||
#: ../vnc.html:89
|
||||
msgid "Show Extra Keys"
|
||||
msgstr "Mostar teclas adicionais"
|
||||
|
||||
#: ../vnc.html:94
|
||||
msgid "Ctrl"
|
||||
msgstr "Ctrl"
|
||||
|
||||
#: ../vnc.html:94
|
||||
msgid "Toggle Ctrl"
|
||||
msgstr "Pressionar/soltar Ctrl"
|
||||
|
||||
#: ../vnc.html:97
|
||||
msgid "Alt"
|
||||
msgstr "Alt"
|
||||
|
||||
#: ../vnc.html:97
|
||||
msgid "Toggle Alt"
|
||||
msgstr "Pressionar/soltar Alt"
|
||||
|
||||
#: ../vnc.html:100
|
||||
msgid "Toggle Windows"
|
||||
msgstr "Pressionar/soltar Windows"
|
||||
|
||||
#: ../vnc.html:100
|
||||
msgid "Windows"
|
||||
msgstr "Windows"
|
||||
|
||||
#: ../vnc.html:103
|
||||
msgid "Send Tab"
|
||||
msgstr "Enviar Tab"
|
||||
|
||||
#: ../vnc.html:103
|
||||
msgid "Tab"
|
||||
msgstr "Tab"
|
||||
|
||||
#: ../vnc.html:106
|
||||
msgid "Esc"
|
||||
msgstr "Esc"
|
||||
|
||||
#: ../vnc.html:106
|
||||
msgid "Send Escape"
|
||||
msgstr "Enviar Esc"
|
||||
|
||||
#: ../vnc.html:109
|
||||
msgid "Ctrl+Alt+Del"
|
||||
msgstr "Ctrl+Alt+Del"
|
||||
|
||||
#: ../vnc.html:109
|
||||
msgid "Send Ctrl-Alt-Del"
|
||||
msgstr "Enviar Ctrl-Alt-Del"
|
||||
|
||||
#: ../vnc.html:116
|
||||
msgid "Shutdown/Reboot"
|
||||
msgstr "Desligar/reiniciar"
|
||||
|
||||
#: ../vnc.html:116
|
||||
msgid "Shutdown/Reboot..."
|
||||
msgstr "Desligar/reiniciar..."
|
||||
|
||||
#: ../vnc.html:122
|
||||
msgid "Power"
|
||||
msgstr "Ligar"
|
||||
|
||||
#: ../vnc.html:124
|
||||
msgid "Shutdown"
|
||||
msgstr "Desligar"
|
||||
|
||||
#: ../vnc.html:125
|
||||
msgid "Reboot"
|
||||
msgstr "Reiniciar"
|
||||
|
||||
#: ../vnc.html:126
|
||||
msgid "Reset"
|
||||
msgstr "Reiniciar (forçado)"
|
||||
|
||||
#: ../vnc.html:131 ../vnc.html:137
|
||||
msgid "Clipboard"
|
||||
msgstr "Área de transferência"
|
||||
|
||||
#: ../vnc.html:141
|
||||
msgid "Clear"
|
||||
msgstr "Limpar"
|
||||
|
||||
#: ../vnc.html:147
|
||||
msgid "Fullscreen"
|
||||
msgstr "Tela cheia"
|
||||
|
||||
#: ../vnc.html:152 ../vnc.html:159
|
||||
msgid "Settings"
|
||||
msgstr "Configurações"
|
||||
|
||||
#: ../vnc.html:162
|
||||
msgid "Shared Mode"
|
||||
msgstr "Modo compartilhado"
|
||||
|
||||
#: ../vnc.html:165
|
||||
msgid "View Only"
|
||||
msgstr "Apenas visualizar"
|
||||
|
||||
#: ../vnc.html:169
|
||||
msgid "Clip to Window"
|
||||
msgstr "Recortar à janela"
|
||||
|
||||
#: ../vnc.html:172
|
||||
msgid "Scaling Mode:"
|
||||
msgstr "Modo de dimensionamento:"
|
||||
|
||||
#: ../vnc.html:174
|
||||
msgid "None"
|
||||
msgstr "Nenhum"
|
||||
|
||||
#: ../vnc.html:175
|
||||
msgid "Local Scaling"
|
||||
msgstr "Local"
|
||||
|
||||
#: ../vnc.html:176
|
||||
msgid "Remote Resizing"
|
||||
msgstr "Remoto"
|
||||
|
||||
#: ../vnc.html:181
|
||||
msgid "Advanced"
|
||||
msgstr "Avançado"
|
||||
|
||||
#: ../vnc.html:184
|
||||
msgid "Quality:"
|
||||
msgstr "Qualidade:"
|
||||
|
||||
#: ../vnc.html:188
|
||||
msgid "Compression level:"
|
||||
msgstr "Nível de compressão:"
|
||||
|
||||
#: ../vnc.html:193
|
||||
msgid "Repeater ID:"
|
||||
msgstr "ID do repetidor:"
|
||||
|
||||
#: ../vnc.html:197
|
||||
msgid "WebSocket"
|
||||
msgstr "WebSocket"
|
||||
|
||||
#: ../vnc.html:200
|
||||
msgid "Encrypt"
|
||||
msgstr "Criptografar"
|
||||
|
||||
#: ../vnc.html:203
|
||||
msgid "Host:"
|
||||
msgstr "Host:"
|
||||
|
||||
#: ../vnc.html:207
|
||||
msgid "Port:"
|
||||
msgstr "Porta:"
|
||||
|
||||
#: ../vnc.html:211
|
||||
msgid "Path:"
|
||||
msgstr "Caminho:"
|
||||
|
||||
#: ../vnc.html:218
|
||||
msgid "Automatic Reconnect"
|
||||
msgstr "Reconexão automática"
|
||||
|
||||
#: ../vnc.html:221
|
||||
msgid "Reconnect Delay (ms):"
|
||||
msgstr "Atraso da reconexão (ms)"
|
||||
|
||||
#: ../vnc.html:226
|
||||
msgid "Show Dot when No Cursor"
|
||||
msgstr "Mostrar ponto quando não há cursor"
|
||||
|
||||
#: ../vnc.html:231
|
||||
msgid "Logging:"
|
||||
msgstr "Registros:"
|
||||
|
||||
#: ../vnc.html:240
|
||||
msgid "Version:"
|
||||
msgstr "Versão:"
|
||||
|
||||
#: ../vnc.html:248
|
||||
msgid "Disconnect"
|
||||
msgstr "Desconectar"
|
||||
|
||||
#: ../vnc.html:267
|
||||
msgid "Connect"
|
||||
msgstr "Conectar"
|
||||
|
||||
#: ../vnc.html:277
|
||||
msgid "Username:"
|
||||
msgstr "Nome de usuário:"
|
||||
|
||||
#: ../vnc.html:281
|
||||
msgid "Password:"
|
||||
msgstr "Senha:"
|
||||
|
||||
#: ../vnc.html:285
|
||||
msgid "Send Credentials"
|
||||
msgstr "Enviar credenciais"
|
||||
|
||||
#: ../vnc.html:295
|
||||
msgid "Cancel"
|
||||
msgstr "Cancelar"
|
||||
@@ -0,0 +1,306 @@
|
||||
# Russian translations for noVNC package
|
||||
# Русский перевод для пакета noVNC.
|
||||
# Copyright (C) 2019 Dmitriy Shweew
|
||||
# This file is distributed under the same license as the noVNC package.
|
||||
# Dmitriy Shweew <shweew@it-advisor.ru>, 2019.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: noVNC 1.1.0\n"
|
||||
"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
|
||||
"POT-Creation-Date: 2019-02-26 14:53+0400\n"
|
||||
"PO-Revision-Date: 2019-02-17 17:29+0400\n"
|
||||
"Last-Translator: Dmitriy Shweew <shweew@it-advisor.ru>\n"
|
||||
"Language-Team: Russian\n"
|
||||
"Language: ru\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
|
||||
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||
"X-Generator: Poedit 2.2.1\n"
|
||||
"X-Poedit-Flags-xgettext: --add-comments\n"
|
||||
|
||||
#: ../app/ui.js:387
|
||||
msgid "Connecting..."
|
||||
msgstr "Подключение..."
|
||||
|
||||
#: ../app/ui.js:394
|
||||
msgid "Disconnecting..."
|
||||
msgstr "Отключение..."
|
||||
|
||||
#: ../app/ui.js:400
|
||||
msgid "Reconnecting..."
|
||||
msgstr "Переподключение..."
|
||||
|
||||
#: ../app/ui.js:405
|
||||
msgid "Internal error"
|
||||
msgstr "Внутренняя ошибка"
|
||||
|
||||
#: ../app/ui.js:995
|
||||
msgid "Must set host"
|
||||
msgstr "Задайте имя сервера или IP"
|
||||
|
||||
#: ../app/ui.js:1077
|
||||
msgid "Connected (encrypted) to "
|
||||
msgstr "Подключено (с шифрованием) к "
|
||||
|
||||
#: ../app/ui.js:1079
|
||||
msgid "Connected (unencrypted) to "
|
||||
msgstr "Подключено (без шифрования) к "
|
||||
|
||||
#: ../app/ui.js:1102
|
||||
msgid "Something went wrong, connection is closed"
|
||||
msgstr "Что-то пошло не так, подключение разорвано"
|
||||
|
||||
#: ../app/ui.js:1105
|
||||
msgid "Failed to connect to server"
|
||||
msgstr "Ошибка подключения к серверу"
|
||||
|
||||
#: ../app/ui.js:1115
|
||||
msgid "Disconnected"
|
||||
msgstr "Отключено"
|
||||
|
||||
#: ../app/ui.js:1128
|
||||
msgid "New connection has been rejected with reason: "
|
||||
msgstr "Подключиться не удалось: "
|
||||
|
||||
#: ../app/ui.js:1131
|
||||
msgid "New connection has been rejected"
|
||||
msgstr "Подключиться не удалось"
|
||||
|
||||
#: ../app/ui.js:1151
|
||||
msgid "Password is required"
|
||||
msgstr "Требуется пароль"
|
||||
|
||||
#: ../vnc.html:84
|
||||
msgid "noVNC encountered an error:"
|
||||
msgstr "Ошибка noVNC: "
|
||||
|
||||
#: ../vnc.html:94
|
||||
msgid "Hide/Show the control bar"
|
||||
msgstr "Скрыть/Показать контрольную панель"
|
||||
|
||||
#: ../vnc.html:101
|
||||
msgid "Move/Drag Viewport"
|
||||
msgstr "Переместить окно"
|
||||
|
||||
#: ../vnc.html:101
|
||||
msgid "viewport drag"
|
||||
msgstr "Переместить окно"
|
||||
|
||||
#: ../vnc.html:107 ../vnc.html:110 ../vnc.html:113 ../vnc.html:116
|
||||
msgid "Active Mouse Button"
|
||||
msgstr "Активировать кнопки мыши"
|
||||
|
||||
#: ../vnc.html:107
|
||||
msgid "No mousebutton"
|
||||
msgstr "Отключить кнопки мыши"
|
||||
|
||||
#: ../vnc.html:110
|
||||
msgid "Left mousebutton"
|
||||
msgstr "Левая кнопка мыши"
|
||||
|
||||
#: ../vnc.html:113
|
||||
msgid "Middle mousebutton"
|
||||
msgstr "Средняя кнопка мыши"
|
||||
|
||||
#: ../vnc.html:116
|
||||
msgid "Right mousebutton"
|
||||
msgstr "Правая кнопка мыши"
|
||||
|
||||
#: ../vnc.html:119
|
||||
msgid "Keyboard"
|
||||
msgstr "Клавиатура"
|
||||
|
||||
#: ../vnc.html:119
|
||||
msgid "Show Keyboard"
|
||||
msgstr "Показать клавиатуру"
|
||||
|
||||
#: ../vnc.html:126
|
||||
msgid "Extra keys"
|
||||
msgstr "Доп. кнопки"
|
||||
|
||||
#: ../vnc.html:126
|
||||
msgid "Show Extra Keys"
|
||||
msgstr "Показать дополнительные кнопки"
|
||||
|
||||
#: ../vnc.html:131
|
||||
msgid "Ctrl"
|
||||
msgstr "Ctrl"
|
||||
|
||||
#: ../vnc.html:131
|
||||
msgid "Toggle Ctrl"
|
||||
msgstr "Передать нажатие Ctrl"
|
||||
|
||||
#: ../vnc.html:134
|
||||
msgid "Alt"
|
||||
msgstr "Alt"
|
||||
|
||||
#: ../vnc.html:134
|
||||
msgid "Toggle Alt"
|
||||
msgstr "Передать нажатие Alt"
|
||||
|
||||
#: ../vnc.html:137
|
||||
msgid "Toggle Windows"
|
||||
msgstr "Переключение вкладок"
|
||||
|
||||
#: ../vnc.html:137
|
||||
msgid "Windows"
|
||||
msgstr "Вкладка"
|
||||
|
||||
#: ../vnc.html:140
|
||||
msgid "Send Tab"
|
||||
msgstr "Передать нажатие Tab"
|
||||
|
||||
#: ../vnc.html:140
|
||||
msgid "Tab"
|
||||
msgstr "Tab"
|
||||
|
||||
#: ../vnc.html:143
|
||||
msgid "Esc"
|
||||
msgstr "Esc"
|
||||
|
||||
#: ../vnc.html:143
|
||||
msgid "Send Escape"
|
||||
msgstr "Передать нажатие Escape"
|
||||
|
||||
#: ../vnc.html:146
|
||||
msgid "Ctrl+Alt+Del"
|
||||
msgstr "Ctrl+Alt+Del"
|
||||
|
||||
#: ../vnc.html:146
|
||||
msgid "Send Ctrl-Alt-Del"
|
||||
msgstr "Передать нажатие Ctrl-Alt-Del"
|
||||
|
||||
#: ../vnc.html:154
|
||||
msgid "Shutdown/Reboot"
|
||||
msgstr "Выключить/Перезагрузить"
|
||||
|
||||
#: ../vnc.html:154
|
||||
msgid "Shutdown/Reboot..."
|
||||
msgstr "Выключить/Перезагрузить..."
|
||||
|
||||
#: ../vnc.html:160
|
||||
msgid "Power"
|
||||
msgstr "Питание"
|
||||
|
||||
#: ../vnc.html:162
|
||||
msgid "Shutdown"
|
||||
msgstr "Выключить"
|
||||
|
||||
#: ../vnc.html:163
|
||||
msgid "Reboot"
|
||||
msgstr "Перезагрузить"
|
||||
|
||||
#: ../vnc.html:164
|
||||
msgid "Reset"
|
||||
msgstr "Сброс"
|
||||
|
||||
#: ../vnc.html:169 ../vnc.html:175
|
||||
msgid "Clipboard"
|
||||
msgstr "Буфер обмена"
|
||||
|
||||
#: ../vnc.html:179
|
||||
msgid "Clear"
|
||||
msgstr "Очистить"
|
||||
|
||||
#: ../vnc.html:185
|
||||
msgid "Fullscreen"
|
||||
msgstr "Во весь экран"
|
||||
|
||||
#: ../vnc.html:190 ../vnc.html:197
|
||||
msgid "Settings"
|
||||
msgstr "Настройки"
|
||||
|
||||
#: ../vnc.html:200
|
||||
msgid "Shared Mode"
|
||||
msgstr "Общий режим"
|
||||
|
||||
#: ../vnc.html:203
|
||||
msgid "View Only"
|
||||
msgstr "Просмотр"
|
||||
|
||||
#: ../vnc.html:207
|
||||
msgid "Clip to Window"
|
||||
msgstr "В окно"
|
||||
|
||||
#: ../vnc.html:210
|
||||
msgid "Scaling Mode:"
|
||||
msgstr "Масштаб:"
|
||||
|
||||
#: ../vnc.html:212
|
||||
msgid "None"
|
||||
msgstr "Нет"
|
||||
|
||||
#: ../vnc.html:213
|
||||
msgid "Local Scaling"
|
||||
msgstr "Локльный масштаб"
|
||||
|
||||
#: ../vnc.html:214
|
||||
msgid "Remote Resizing"
|
||||
msgstr "Удаленный масштаб"
|
||||
|
||||
#: ../vnc.html:219
|
||||
msgid "Advanced"
|
||||
msgstr "Дополнительно"
|
||||
|
||||
#: ../vnc.html:222
|
||||
msgid "Repeater ID:"
|
||||
msgstr "Идентификатор ID:"
|
||||
|
||||
#: ../vnc.html:226
|
||||
msgid "WebSocket"
|
||||
msgstr "WebSocket"
|
||||
|
||||
#: ../vnc.html:229
|
||||
msgid "Encrypt"
|
||||
msgstr "Шифрование"
|
||||
|
||||
#: ../vnc.html:232
|
||||
msgid "Host:"
|
||||
msgstr "Сервер:"
|
||||
|
||||
#: ../vnc.html:236
|
||||
msgid "Port:"
|
||||
msgstr "Порт:"
|
||||
|
||||
#: ../vnc.html:240
|
||||
msgid "Path:"
|
||||
msgstr "Путь:"
|
||||
|
||||
#: ../vnc.html:247
|
||||
msgid "Automatic Reconnect"
|
||||
msgstr "Автоматическое переподключение"
|
||||
|
||||
#: ../vnc.html:250
|
||||
msgid "Reconnect Delay (ms):"
|
||||
msgstr "Задержка переподключения (мс):"
|
||||
|
||||
#: ../vnc.html:255
|
||||
msgid "Show Dot when No Cursor"
|
||||
msgstr "Показать точку вместо курсора"
|
||||
|
||||
#: ../vnc.html:260
|
||||
msgid "Logging:"
|
||||
msgstr "Лог:"
|
||||
|
||||
#: ../vnc.html:272
|
||||
msgid "Disconnect"
|
||||
msgstr "Отключение"
|
||||
|
||||
#: ../vnc.html:291
|
||||
msgid "Connect"
|
||||
msgstr "Подключение"
|
||||
|
||||
#: ../vnc.html:301
|
||||
msgid "Password:"
|
||||
msgstr "Пароль:"
|
||||
|
||||
#: ../vnc.html:305
|
||||
msgid "Send Password"
|
||||
msgstr "Пароль: "
|
||||
|
||||
#: ../vnc.html:315
|
||||
msgid "Cancel"
|
||||
msgstr "Выход"
|
||||
@@ -1,16 +1,16 @@
|
||||
# Swedish translations for noVNC package
|
||||
# Svenska översättningar för paket noVNC.
|
||||
# Copyright (C) 2016 Various Authors
|
||||
# Svenska översättningar för paketet noVNC.
|
||||
# Copyright (C) 2020 The noVNC Authors
|
||||
# This file is distributed under the same license as the noVNC package.
|
||||
# Samuel Mannehed <samuel@cendio.se>, 2016.
|
||||
# Samuel Mannehed <samuel@cendio.se>, 2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: noVNC 0.6.1\n"
|
||||
"Project-Id-Version: noVNC 1.3.0\n"
|
||||
"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
|
||||
"POT-Creation-Date: 2017-10-06 10:07+0200\n"
|
||||
"PO-Revision-Date: 2017-10-06 10:18+0200\n"
|
||||
"Last-Translator: Pierre Ossman <pierre@ossman.eu>\n"
|
||||
"POT-Creation-Date: 2021-08-27 16:03+0200\n"
|
||||
"PO-Revision-Date: 2021-08-27 16:18+0200\n"
|
||||
"Last-Translator: Samuel Mannehed <samuel@cendio.se>\n"
|
||||
"Language-Team: none\n"
|
||||
"Language: sv\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@@ -19,266 +19,282 @@ msgstr ""
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Poedit 2.0.3\n"
|
||||
|
||||
#: ../app/ui.js:430
|
||||
#: ../app/ui.js:400
|
||||
msgid "Connecting..."
|
||||
msgstr "Ansluter..."
|
||||
|
||||
#: ../app/ui.js:438
|
||||
msgid "Connected (encrypted) to "
|
||||
msgstr "Ansluten (krypterat) till "
|
||||
|
||||
#: ../app/ui.js:440
|
||||
msgid "Connected (unencrypted) to "
|
||||
msgstr "Ansluten (okrypterat) till "
|
||||
|
||||
#: ../app/ui.js:446
|
||||
#: ../app/ui.js:407
|
||||
msgid "Disconnecting..."
|
||||
msgstr "Kopplar ner..."
|
||||
|
||||
#: ../app/ui.js:450
|
||||
msgid "Disconnected"
|
||||
msgstr "Frånkopplad"
|
||||
|
||||
#: ../app/ui.js:1052 ../core/rfb.js:248
|
||||
msgid "Must set host"
|
||||
msgstr "Du måste specifiera en värd"
|
||||
|
||||
#: ../app/ui.js:1101
|
||||
#: ../app/ui.js:413
|
||||
msgid "Reconnecting..."
|
||||
msgstr "Återansluter..."
|
||||
|
||||
#: ../app/ui.js:1140
|
||||
msgid "Password is required"
|
||||
msgstr "Lösenord krävs"
|
||||
#: ../app/ui.js:418
|
||||
msgid "Internal error"
|
||||
msgstr "Internt fel"
|
||||
|
||||
#: ../core/rfb.js:548
|
||||
msgid "Disconnect timeout"
|
||||
msgstr "Det tog för lång tid att koppla ner"
|
||||
#: ../app/ui.js:1009
|
||||
msgid "Must set host"
|
||||
msgstr "Du måste specifiera en värd"
|
||||
|
||||
#: ../vnc.html:89
|
||||
#: ../app/ui.js:1091
|
||||
msgid "Connected (encrypted) to "
|
||||
msgstr "Ansluten (krypterat) till "
|
||||
|
||||
#: ../app/ui.js:1093
|
||||
msgid "Connected (unencrypted) to "
|
||||
msgstr "Ansluten (okrypterat) till "
|
||||
|
||||
#: ../app/ui.js:1116
|
||||
msgid "Something went wrong, connection is closed"
|
||||
msgstr "Något gick fel, anslutningen avslutades"
|
||||
|
||||
#: ../app/ui.js:1119
|
||||
msgid "Failed to connect to server"
|
||||
msgstr "Misslyckades att ansluta till servern"
|
||||
|
||||
#: ../app/ui.js:1129
|
||||
msgid "Disconnected"
|
||||
msgstr "Frånkopplad"
|
||||
|
||||
#: ../app/ui.js:1144
|
||||
msgid "New connection has been rejected with reason: "
|
||||
msgstr "Ny anslutning har blivit nekad med följande skäl: "
|
||||
|
||||
#: ../app/ui.js:1147
|
||||
msgid "New connection has been rejected"
|
||||
msgstr "Ny anslutning har blivit nekad"
|
||||
|
||||
#: ../app/ui.js:1182
|
||||
msgid "Credentials are required"
|
||||
msgstr "Användaruppgifter krävs"
|
||||
|
||||
#: ../vnc.html:61
|
||||
msgid "noVNC encountered an error:"
|
||||
msgstr "noVNC stötte på ett problem:"
|
||||
|
||||
#: ../vnc.html:99
|
||||
#: ../vnc.html:71
|
||||
msgid "Hide/Show the control bar"
|
||||
msgstr "Göm/Visa kontrollbaren"
|
||||
|
||||
#: ../vnc.html:106
|
||||
#: ../vnc.html:78
|
||||
msgid "Drag"
|
||||
msgstr "Dra"
|
||||
|
||||
#: ../vnc.html:78
|
||||
msgid "Move/Drag Viewport"
|
||||
msgstr "Flytta/Dra Vyn"
|
||||
|
||||
#: ../vnc.html:106
|
||||
msgid "viewport drag"
|
||||
msgstr "dra vy"
|
||||
|
||||
#: ../vnc.html:112 ../vnc.html:115 ../vnc.html:118 ../vnc.html:121
|
||||
msgid "Active Mouse Button"
|
||||
msgstr "Aktiv musknapp"
|
||||
|
||||
#: ../vnc.html:112
|
||||
msgid "No mousebutton"
|
||||
msgstr "Ingen musknapp"
|
||||
|
||||
#: ../vnc.html:115
|
||||
msgid "Left mousebutton"
|
||||
msgstr "Vänster musknapp"
|
||||
|
||||
#: ../vnc.html:118
|
||||
msgid "Middle mousebutton"
|
||||
msgstr "Mitten-musknapp"
|
||||
|
||||
#: ../vnc.html:121
|
||||
msgid "Right mousebutton"
|
||||
msgstr "Höger musknapp"
|
||||
|
||||
#: ../vnc.html:124
|
||||
#: ../vnc.html:84
|
||||
msgid "Keyboard"
|
||||
msgstr "Tangentbord"
|
||||
|
||||
#: ../vnc.html:124
|
||||
#: ../vnc.html:84
|
||||
msgid "Show Keyboard"
|
||||
msgstr "Visa Tangentbord"
|
||||
|
||||
#: ../vnc.html:131
|
||||
#: ../vnc.html:89
|
||||
msgid "Extra keys"
|
||||
msgstr "Extraknappar"
|
||||
|
||||
#: ../vnc.html:131
|
||||
#: ../vnc.html:89
|
||||
msgid "Show Extra Keys"
|
||||
msgstr "Visa Extraknappar"
|
||||
|
||||
#: ../vnc.html:136
|
||||
#: ../vnc.html:94
|
||||
msgid "Ctrl"
|
||||
msgstr "Ctrl"
|
||||
|
||||
#: ../vnc.html:136
|
||||
#: ../vnc.html:94
|
||||
msgid "Toggle Ctrl"
|
||||
msgstr "Växla Ctrl"
|
||||
|
||||
#: ../vnc.html:139
|
||||
#: ../vnc.html:97
|
||||
msgid "Alt"
|
||||
msgstr "Alt"
|
||||
|
||||
#: ../vnc.html:139
|
||||
#: ../vnc.html:97
|
||||
msgid "Toggle Alt"
|
||||
msgstr "Växla Alt"
|
||||
|
||||
#: ../vnc.html:142
|
||||
#: ../vnc.html:100
|
||||
msgid "Toggle Windows"
|
||||
msgstr "Växla Windows"
|
||||
|
||||
#: ../vnc.html:100
|
||||
msgid "Windows"
|
||||
msgstr "Windows"
|
||||
|
||||
#: ../vnc.html:103
|
||||
msgid "Send Tab"
|
||||
msgstr "Skicka Tab"
|
||||
|
||||
#: ../vnc.html:142
|
||||
#: ../vnc.html:103
|
||||
msgid "Tab"
|
||||
msgstr "Tab"
|
||||
|
||||
#: ../vnc.html:145
|
||||
#: ../vnc.html:106
|
||||
msgid "Esc"
|
||||
msgstr "Esc"
|
||||
|
||||
#: ../vnc.html:145
|
||||
#: ../vnc.html:106
|
||||
msgid "Send Escape"
|
||||
msgstr "Skicka Escape"
|
||||
|
||||
#: ../vnc.html:148
|
||||
#: ../vnc.html:109
|
||||
msgid "Ctrl+Alt+Del"
|
||||
msgstr "Ctrl+Alt+Del"
|
||||
|
||||
#: ../vnc.html:148
|
||||
#: ../vnc.html:109
|
||||
msgid "Send Ctrl-Alt-Del"
|
||||
msgstr "Skicka Ctrl-Alt-Del"
|
||||
|
||||
#: ../vnc.html:156
|
||||
#: ../vnc.html:116
|
||||
msgid "Shutdown/Reboot"
|
||||
msgstr "Stäng av/Boota om"
|
||||
|
||||
#: ../vnc.html:156
|
||||
#: ../vnc.html:116
|
||||
msgid "Shutdown/Reboot..."
|
||||
msgstr "Stäng av/Boota om..."
|
||||
|
||||
#: ../vnc.html:162
|
||||
#: ../vnc.html:122
|
||||
msgid "Power"
|
||||
msgstr "Ström"
|
||||
|
||||
#: ../vnc.html:164
|
||||
#: ../vnc.html:124
|
||||
msgid "Shutdown"
|
||||
msgstr "Stäng av"
|
||||
|
||||
#: ../vnc.html:165
|
||||
#: ../vnc.html:125
|
||||
msgid "Reboot"
|
||||
msgstr "Boota om"
|
||||
|
||||
#: ../vnc.html:166
|
||||
#: ../vnc.html:126
|
||||
msgid "Reset"
|
||||
msgstr "Återställ"
|
||||
|
||||
#: ../vnc.html:171 ../vnc.html:177
|
||||
#: ../vnc.html:131 ../vnc.html:137
|
||||
msgid "Clipboard"
|
||||
msgstr "Urklipp"
|
||||
|
||||
#: ../vnc.html:181
|
||||
#: ../vnc.html:141
|
||||
msgid "Clear"
|
||||
msgstr "Rensa"
|
||||
|
||||
#: ../vnc.html:187
|
||||
#: ../vnc.html:147
|
||||
msgid "Fullscreen"
|
||||
msgstr "Fullskärm"
|
||||
|
||||
#: ../vnc.html:192 ../vnc.html:199
|
||||
#: ../vnc.html:152 ../vnc.html:159
|
||||
msgid "Settings"
|
||||
msgstr "Inställningar"
|
||||
|
||||
#: ../vnc.html:202
|
||||
#: ../vnc.html:162
|
||||
msgid "Shared Mode"
|
||||
msgstr "Delat Läge"
|
||||
|
||||
#: ../vnc.html:205
|
||||
#: ../vnc.html:165
|
||||
msgid "View Only"
|
||||
msgstr "Endast Visning"
|
||||
|
||||
#: ../vnc.html:209
|
||||
#: ../vnc.html:169
|
||||
msgid "Clip to Window"
|
||||
msgstr "Begränsa till Fönster"
|
||||
|
||||
#: ../vnc.html:212
|
||||
#: ../vnc.html:172
|
||||
msgid "Scaling Mode:"
|
||||
msgstr "Skalningsläge:"
|
||||
|
||||
#: ../vnc.html:214
|
||||
#: ../vnc.html:174
|
||||
msgid "None"
|
||||
msgstr "Ingen"
|
||||
|
||||
#: ../vnc.html:215
|
||||
#: ../vnc.html:175
|
||||
msgid "Local Scaling"
|
||||
msgstr "Lokal Skalning"
|
||||
|
||||
#: ../vnc.html:216
|
||||
msgid "Local Downscaling"
|
||||
msgstr "Lokal Nedskalning"
|
||||
|
||||
#: ../vnc.html:217
|
||||
#: ../vnc.html:176
|
||||
msgid "Remote Resizing"
|
||||
msgstr "Ändra Storlek"
|
||||
|
||||
#: ../vnc.html:222
|
||||
#: ../vnc.html:181
|
||||
msgid "Advanced"
|
||||
msgstr "Avancerat"
|
||||
|
||||
#: ../vnc.html:225
|
||||
msgid "Local Cursor"
|
||||
msgstr "Lokal Muspekare"
|
||||
#: ../vnc.html:184
|
||||
msgid "Quality:"
|
||||
msgstr "Kvalitet:"
|
||||
|
||||
#: ../vnc.html:229
|
||||
#: ../vnc.html:188
|
||||
msgid "Compression level:"
|
||||
msgstr "Kompressionsnivå:"
|
||||
|
||||
#: ../vnc.html:193
|
||||
msgid "Repeater ID:"
|
||||
msgstr "Repeater-ID:"
|
||||
|
||||
#: ../vnc.html:233
|
||||
#: ../vnc.html:197
|
||||
msgid "WebSocket"
|
||||
msgstr "WebSocket"
|
||||
|
||||
#: ../vnc.html:236
|
||||
#: ../vnc.html:200
|
||||
msgid "Encrypt"
|
||||
msgstr "Kryptera"
|
||||
|
||||
#: ../vnc.html:239
|
||||
#: ../vnc.html:203
|
||||
msgid "Host:"
|
||||
msgstr "Värd:"
|
||||
|
||||
#: ../vnc.html:243
|
||||
#: ../vnc.html:207
|
||||
msgid "Port:"
|
||||
msgstr "Port:"
|
||||
|
||||
#: ../vnc.html:247
|
||||
#: ../vnc.html:211
|
||||
msgid "Path:"
|
||||
msgstr "Sökväg:"
|
||||
|
||||
#: ../vnc.html:254
|
||||
#: ../vnc.html:218
|
||||
msgid "Automatic Reconnect"
|
||||
msgstr "Automatisk Återanslutning"
|
||||
|
||||
#: ../vnc.html:257
|
||||
#: ../vnc.html:221
|
||||
msgid "Reconnect Delay (ms):"
|
||||
msgstr "Fördröjning (ms):"
|
||||
|
||||
#: ../vnc.html:263
|
||||
#: ../vnc.html:226
|
||||
msgid "Show Dot when No Cursor"
|
||||
msgstr "Visa prick när ingen muspekare finns"
|
||||
|
||||
#: ../vnc.html:231
|
||||
msgid "Logging:"
|
||||
msgstr "Loggning:"
|
||||
|
||||
#: ../vnc.html:275
|
||||
#: ../vnc.html:240
|
||||
msgid "Version:"
|
||||
msgstr "Version:"
|
||||
|
||||
#: ../vnc.html:248
|
||||
msgid "Disconnect"
|
||||
msgstr "Koppla från"
|
||||
|
||||
#: ../vnc.html:294
|
||||
#: ../vnc.html:267
|
||||
msgid "Connect"
|
||||
msgstr "Anslut"
|
||||
|
||||
#: ../vnc.html:304
|
||||
#: ../vnc.html:277
|
||||
msgid "Username:"
|
||||
msgstr "Användarnamn:"
|
||||
|
||||
#: ../vnc.html:281
|
||||
msgid "Password:"
|
||||
msgstr "Lösenord:"
|
||||
|
||||
#: ../vnc.html:318
|
||||
#: ../vnc.html:285
|
||||
msgid "Send Credentials"
|
||||
msgstr "Skicka Användaruppgifter"
|
||||
|
||||
#: ../vnc.html:295
|
||||
msgid "Cancel"
|
||||
msgstr "Avbryt"
|
||||
|
||||
#: ../vnc.html:334
|
||||
msgid "Canvas not supported."
|
||||
msgstr "Canvas stöds ej"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Turkish translations for noVNC package
|
||||
# Turkish translation for noVNC.
|
||||
# Copyright (C) 2016 Various Authors
|
||||
# Copyright (C) 2018 The noVNC Authors
|
||||
# This file is distributed under the same license as the noVNC package.
|
||||
# Ömer ÇAKMAK <farukomercakmak@gmail.com>, 2018.
|
||||
#
|
||||
|
||||
+21
-24
@@ -1,21 +1,20 @@
|
||||
#!/usr/bin/env node
|
||||
/*
|
||||
* xgettext-html: HTML gettext parser
|
||||
* Copyright (C) 2016 Pierre Ossman
|
||||
* Copyright (C) 2018 The noVNC Authors
|
||||
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||
*/
|
||||
|
||||
var getopt = require('node-getopt');
|
||||
const getopt = require('node-getopt');
|
||||
const jsdom = require("jsdom");
|
||||
const fs = require("fs");
|
||||
|
||||
var jsdom = require("jsdom");
|
||||
var fs = require("fs");
|
||||
|
||||
opt = getopt.create([
|
||||
['o' , 'output=FILE' , 'write output to specified file'],
|
||||
['h' , 'help' , 'display this help'],
|
||||
const opt = getopt.create([
|
||||
['o', 'output=FILE', 'write output to specified file'],
|
||||
['h', 'help', 'display this help'],
|
||||
]).bindHelp().parseSystem();
|
||||
|
||||
var strings = {};
|
||||
const strings = {};
|
||||
|
||||
function addString(str, location) {
|
||||
if (str.length == 0) {
|
||||
@@ -23,7 +22,7 @@ function addString(str, location) {
|
||||
}
|
||||
|
||||
if (strings[str] === undefined) {
|
||||
strings[str] = {}
|
||||
strings[str] = {};
|
||||
}
|
||||
strings[str][location] = null;
|
||||
}
|
||||
@@ -74,8 +73,8 @@ function process(elem, locator, enabled) {
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0;i < elem.childNodes.length;i++) {
|
||||
node = elem.childNodes[i];
|
||||
for (let i = 0; i < elem.childNodes.length; i++) {
|
||||
let node = elem.childNodes[i];
|
||||
if (node.nodeType === node.ELEMENT_NODE) {
|
||||
process(node, locator, enabled);
|
||||
} else if (node.nodeType === node.TEXT_NODE && enabled) {
|
||||
@@ -84,26 +83,24 @@ function process(elem, locator, enabled) {
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0;i < opt.argv.length;i++) {
|
||||
var file;
|
||||
for (let i = 0; i < opt.argv.length; i++) {
|
||||
const fn = opt.argv[i];
|
||||
const file = fs.readFileSync(fn, "utf8");
|
||||
const dom = new jsdom.JSDOM(file, { includeNodeLocations: true });
|
||||
const body = dom.window.document.body;
|
||||
|
||||
fn = opt.argv[i];
|
||||
file = fs.readFileSync(fn, "utf8");
|
||||
dom = new jsdom.JSDOM(file, { includeNodeLocations: true });
|
||||
body = dom.window.document.body;
|
||||
|
||||
locator = function (elem) {
|
||||
offset = dom.nodeLocation(elem).startOffset;
|
||||
line = file.slice(0, offset).split("\n").length;
|
||||
let locator = (elem) => {
|
||||
const offset = dom.nodeLocation(elem).startOffset;
|
||||
const line = file.slice(0, offset).split("\n").length;
|
||||
return fn + ":" + line;
|
||||
};
|
||||
|
||||
process(body, locator, true);
|
||||
}
|
||||
|
||||
var output = "";
|
||||
let output = "";
|
||||
|
||||
for (str in strings) {
|
||||
for (let str in strings) {
|
||||
output += "#:";
|
||||
for (location in strings[str]) {
|
||||
output += " " + location;
|
||||
|
||||
+284
@@ -0,0 +1,284 @@
|
||||
# Simplified Chinese translations for noVNC package.
|
||||
# Copyright (C) 2020 The noVNC Authors
|
||||
# This file is distributed under the same license as the noVNC package.
|
||||
# Peter Dave Hello <hsu@peterdavehello.org>, 2018.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: noVNC 1.1.0\n"
|
||||
"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
|
||||
"POT-Creation-Date: 2018-01-10 00:53+0800\n"
|
||||
"PO-Revision-Date: 2020-01-02 13:19+0800\n"
|
||||
"Last-Translator: CUI Wei <ghostplant@qq.com>\n"
|
||||
"Language: zh_CN\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: ../app/ui.js:395
|
||||
msgid "Connecting..."
|
||||
msgstr "连接中..."
|
||||
|
||||
#: ../app/ui.js:402
|
||||
msgid "Disconnecting..."
|
||||
msgstr "正在断开连接..."
|
||||
|
||||
#: ../app/ui.js:408
|
||||
msgid "Reconnecting..."
|
||||
msgstr "重新连接中..."
|
||||
|
||||
#: ../app/ui.js:413
|
||||
msgid "Internal error"
|
||||
msgstr "内部错误"
|
||||
|
||||
#: ../app/ui.js:1015
|
||||
msgid "Must set host"
|
||||
msgstr "请提供主机名"
|
||||
|
||||
#: ../app/ui.js:1097
|
||||
msgid "Connected (encrypted) to "
|
||||
msgstr "已连接到(加密)"
|
||||
|
||||
#: ../app/ui.js:1099
|
||||
msgid "Connected (unencrypted) to "
|
||||
msgstr "已连接到(未加密)"
|
||||
|
||||
#: ../app/ui.js:1120
|
||||
msgid "Something went wrong, connection is closed"
|
||||
msgstr "发生错误,连接已关闭"
|
||||
|
||||
#: ../app/ui.js:1123
|
||||
msgid "Failed to connect to server"
|
||||
msgstr "无法连接到服务器"
|
||||
|
||||
#: ../app/ui.js:1133
|
||||
msgid "Disconnected"
|
||||
msgstr "已断开连接"
|
||||
|
||||
#: ../app/ui.js:1146
|
||||
msgid "New connection has been rejected with reason: "
|
||||
msgstr "连接被拒绝,原因:"
|
||||
|
||||
#: ../app/ui.js:1149
|
||||
msgid "New connection has been rejected"
|
||||
msgstr "连接被拒绝"
|
||||
|
||||
#: ../app/ui.js:1170
|
||||
msgid "Password is required"
|
||||
msgstr "请提供密码"
|
||||
|
||||
#: ../vnc.html:89
|
||||
msgid "noVNC encountered an error:"
|
||||
msgstr "noVNC 遇到一个错误:"
|
||||
|
||||
#: ../vnc.html:99
|
||||
msgid "Hide/Show the control bar"
|
||||
msgstr "显示/隐藏控制栏"
|
||||
|
||||
#: ../vnc.html:106
|
||||
msgid "Move/Drag Viewport"
|
||||
msgstr "拖放显示范围"
|
||||
|
||||
#: ../vnc.html:106
|
||||
msgid "viewport drag"
|
||||
msgstr "显示范围拖放"
|
||||
|
||||
#: ../vnc.html:112 ../vnc.html:115 ../vnc.html:118 ../vnc.html:121
|
||||
msgid "Active Mouse Button"
|
||||
msgstr "启动鼠标按鍵"
|
||||
|
||||
#: ../vnc.html:112
|
||||
msgid "No mousebutton"
|
||||
msgstr "禁用鼠标按鍵"
|
||||
|
||||
#: ../vnc.html:115
|
||||
msgid "Left mousebutton"
|
||||
msgstr "鼠标左鍵"
|
||||
|
||||
#: ../vnc.html:118
|
||||
msgid "Middle mousebutton"
|
||||
msgstr "鼠标中鍵"
|
||||
|
||||
#: ../vnc.html:121
|
||||
msgid "Right mousebutton"
|
||||
msgstr "鼠标右鍵"
|
||||
|
||||
#: ../vnc.html:124
|
||||
msgid "Keyboard"
|
||||
msgstr "键盘"
|
||||
|
||||
#: ../vnc.html:124
|
||||
msgid "Show Keyboard"
|
||||
msgstr "显示键盘"
|
||||
|
||||
#: ../vnc.html:131
|
||||
msgid "Extra keys"
|
||||
msgstr "额外按键"
|
||||
|
||||
#: ../vnc.html:131
|
||||
msgid "Show Extra Keys"
|
||||
msgstr "显示额外按键"
|
||||
|
||||
#: ../vnc.html:136
|
||||
msgid "Ctrl"
|
||||
msgstr "Ctrl"
|
||||
|
||||
#: ../vnc.html:136
|
||||
msgid "Toggle Ctrl"
|
||||
msgstr "切换 Ctrl"
|
||||
|
||||
#: ../vnc.html:139
|
||||
msgid "Alt"
|
||||
msgstr "Alt"
|
||||
|
||||
#: ../vnc.html:139
|
||||
msgid "Toggle Alt"
|
||||
msgstr "切换 Alt"
|
||||
|
||||
#: ../vnc.html:142
|
||||
msgid "Send Tab"
|
||||
msgstr "发送 Tab 键"
|
||||
|
||||
#: ../vnc.html:142
|
||||
msgid "Tab"
|
||||
msgstr "Tab"
|
||||
|
||||
#: ../vnc.html:145
|
||||
msgid "Esc"
|
||||
msgstr "Esc"
|
||||
|
||||
#: ../vnc.html:145
|
||||
msgid "Send Escape"
|
||||
msgstr "发送 Escape 键"
|
||||
|
||||
#: ../vnc.html:148
|
||||
msgid "Ctrl+Alt+Del"
|
||||
msgstr "Ctrl-Alt-Del"
|
||||
|
||||
#: ../vnc.html:148
|
||||
msgid "Send Ctrl-Alt-Del"
|
||||
msgstr "发送 Ctrl-Alt-Del 键"
|
||||
|
||||
#: ../vnc.html:156
|
||||
msgid "Shutdown/Reboot"
|
||||
msgstr "关机/重新启动"
|
||||
|
||||
#: ../vnc.html:156
|
||||
msgid "Shutdown/Reboot..."
|
||||
msgstr "关机/重新启动..."
|
||||
|
||||
#: ../vnc.html:162
|
||||
msgid "Power"
|
||||
msgstr "电源"
|
||||
|
||||
#: ../vnc.html:164
|
||||
msgid "Shutdown"
|
||||
msgstr "关机"
|
||||
|
||||
#: ../vnc.html:165
|
||||
msgid "Reboot"
|
||||
msgstr "重新启动"
|
||||
|
||||
#: ../vnc.html:166
|
||||
msgid "Reset"
|
||||
msgstr "重置"
|
||||
|
||||
#: ../vnc.html:171 ../vnc.html:177
|
||||
msgid "Clipboard"
|
||||
msgstr "剪贴板"
|
||||
|
||||
#: ../vnc.html:181
|
||||
msgid "Clear"
|
||||
msgstr "清除"
|
||||
|
||||
#: ../vnc.html:187
|
||||
msgid "Fullscreen"
|
||||
msgstr "全屏"
|
||||
|
||||
#: ../vnc.html:192 ../vnc.html:199
|
||||
msgid "Settings"
|
||||
msgstr "设置"
|
||||
|
||||
#: ../vnc.html:202
|
||||
msgid "Shared Mode"
|
||||
msgstr "分享模式"
|
||||
|
||||
#: ../vnc.html:205
|
||||
msgid "View Only"
|
||||
msgstr "仅查看"
|
||||
|
||||
#: ../vnc.html:209
|
||||
msgid "Clip to Window"
|
||||
msgstr "限制/裁切窗口大小"
|
||||
|
||||
#: ../vnc.html:212
|
||||
msgid "Scaling Mode:"
|
||||
msgstr "缩放模式:"
|
||||
|
||||
#: ../vnc.html:214
|
||||
msgid "None"
|
||||
msgstr "无"
|
||||
|
||||
#: ../vnc.html:215
|
||||
msgid "Local Scaling"
|
||||
msgstr "本地缩放"
|
||||
|
||||
#: ../vnc.html:216
|
||||
msgid "Remote Resizing"
|
||||
msgstr "远程调整大小"
|
||||
|
||||
#: ../vnc.html:221
|
||||
msgid "Advanced"
|
||||
msgstr "高级"
|
||||
|
||||
#: ../vnc.html:224
|
||||
msgid "Repeater ID:"
|
||||
msgstr "中继站 ID"
|
||||
|
||||
#: ../vnc.html:228
|
||||
msgid "WebSocket"
|
||||
msgstr "WebSocket"
|
||||
|
||||
#: ../vnc.html:231
|
||||
msgid "Encrypt"
|
||||
msgstr "加密"
|
||||
|
||||
#: ../vnc.html:234
|
||||
msgid "Host:"
|
||||
msgstr "主机:"
|
||||
|
||||
#: ../vnc.html:238
|
||||
msgid "Port:"
|
||||
msgstr "端口:"
|
||||
|
||||
#: ../vnc.html:242
|
||||
msgid "Path:"
|
||||
msgstr "路径:"
|
||||
|
||||
#: ../vnc.html:249
|
||||
msgid "Automatic Reconnect"
|
||||
msgstr "自动重新连接"
|
||||
|
||||
#: ../vnc.html:252
|
||||
msgid "Reconnect Delay (ms):"
|
||||
msgstr "重新连接间隔 (ms):"
|
||||
|
||||
#: ../vnc.html:258
|
||||
msgid "Logging:"
|
||||
msgstr "日志级别:"
|
||||
|
||||
#: ../vnc.html:270
|
||||
msgid "Disconnect"
|
||||
msgstr "中断连接"
|
||||
|
||||
#: ../vnc.html:289
|
||||
msgid "Connect"
|
||||
msgstr "连接"
|
||||
|
||||
#: ../vnc.html:299
|
||||
msgid "Password:"
|
||||
msgstr "密码:"
|
||||
|
||||
#: ../vnc.html:313
|
||||
msgid "Cancel"
|
||||
msgstr "取消"
|
||||
@@ -1,5 +1,5 @@
|
||||
# Traditional Chinese translations for noVNC package.
|
||||
# Copyright (C) 2018 Various Authors
|
||||
# Copyright (C) 2018 The noVNC Authors
|
||||
# This file is distributed under the same license as the noVNC package.
|
||||
# Peter Dave Hello <hsu@peterdavehello.org>, 2018.
|
||||
#
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
snapctl restart novnc.novncsvc
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
# `snapctl get services` returns a JSON array, example:
|
||||
#{
|
||||
#"n6801": {
|
||||
# "listen": 6801,
|
||||
# "vnc": "localhost:5901"
|
||||
#},
|
||||
#"n6802": {
|
||||
# "listen": 6802,
|
||||
# "vnc": "localhost:5902"
|
||||
#}
|
||||
#}
|
||||
snapctl get services | jq -c '.[]' | while read service; do # for each service the user sepcified..
|
||||
# get the important data for the service (listen port, VNC host:port)
|
||||
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
|
||||
|
||||
# check whether those values are valid
|
||||
expr "$listen_port" : '^[0-9]\+$' > /dev/null
|
||||
listen_port_valid=$?
|
||||
if [ ! $listen_port_valid ] || [ -z "$vnc_host_port" ]; then
|
||||
# invalid values mean the service is disabled, do nothing except for printing a message (logged in /var/log/system or systemd journal)
|
||||
echo "novnc: not starting service ${service} with listen_port ${listen_port} and vnc_host_port ${vnc_host_port}"
|
||||
else
|
||||
# start (and fork with '&') the service using the specified listen port and VNC host:port
|
||||
$SNAP/novnc_proxy --listen $listen_port --vnc $vnc_host_port &
|
||||
fi
|
||||
done
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user