提交qiming-noVNC
1
.gitignore
vendored
@@ -9,6 +9,7 @@
|
|||||||
!/qiming-claude-code-acp-ts/
|
!/qiming-claude-code-acp-ts/
|
||||||
!/qiming-dev-inject/
|
!/qiming-dev-inject/
|
||||||
!/qiming-mcp-proxy/
|
!/qiming-mcp-proxy/
|
||||||
|
!/qiming-noVNC/
|
||||||
!/qimingclaw/
|
!/qimingclaw/
|
||||||
!/qimingcode/
|
!/qimingcode/
|
||||||
|
|
||||||
|
|||||||
1
qiming-noVNC/.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
app/vendor/opus-decoder.min.js -text
|
||||||
34
qiming-noVNC/.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -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.
|
||||||
5
qiming-noVNC/.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -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
|
||||||
17
qiming-noVNC/.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -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.
|
||||||
97
qiming-noVNC/.github/workflows/deploy.yml
vendored
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
name: Publish
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
npm:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- run: |
|
||||||
|
GITREV=$(git rev-parse --short HEAD)
|
||||||
|
echo $GITREV
|
||||||
|
sed -i "s/^\(.*\"version\".*\)\"\([^\"]\+\)\"\(.*\)\$/\1\"\2-g$GITREV\"\3/" package.json
|
||||||
|
if: github.event_name != 'release'
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
# Needs to be explicitly specified for auth to work
|
||||||
|
registry-url: 'https://registry.npmjs.org'
|
||||||
|
- run: npm install
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: npm
|
||||||
|
path: lib
|
||||||
|
- run: npm publish --access public
|
||||||
|
env:
|
||||||
|
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
||||||
|
if: |
|
||||||
|
github.repository == 'novnc/noVNC' &&
|
||||||
|
github.event_name == 'release' &&
|
||||||
|
!github.event.release.prerelease
|
||||||
|
- run: npm publish --access public --tag beta
|
||||||
|
env:
|
||||||
|
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
||||||
|
if: |
|
||||||
|
github.repository == 'novnc/noVNC' &&
|
||||||
|
github.event_name == 'release' &&
|
||||||
|
github.event.release.prerelease
|
||||||
|
- run: npm publish --access public --tag dev
|
||||||
|
env:
|
||||||
|
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
||||||
|
if: |
|
||||||
|
github.repository == 'novnc/noVNC' &&
|
||||||
|
github.event_name == 'push' &&
|
||||||
|
github.event.ref == 'refs/heads/master'
|
||||||
|
snap:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- run: |
|
||||||
|
GITREV=$(git rev-parse --short HEAD)
|
||||||
|
echo $GITREV
|
||||||
|
sed -i "s/^\(.*\"version\".*\)\"\([^\"]\+\)\"\(.*\)\$/\1\"\2-g$GITREV\"\3/" package.json
|
||||||
|
if: github.event_name != 'release'
|
||||||
|
- run: |
|
||||||
|
VERSION=$(grep '"version"' package.json | cut -d '"' -f 4)
|
||||||
|
echo $VERSION
|
||||||
|
sed -i "s/^version:.*/version: '$VERSION'/" snap/snapcraft.yaml
|
||||||
|
- uses: snapcore/action-build@v1
|
||||||
|
id: snapcraft
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: snap
|
||||||
|
path: ${{ steps.snapcraft.outputs.snap }}
|
||||||
|
- uses: snapcore/action-publish@v1
|
||||||
|
with:
|
||||||
|
snap: ${{ steps.snapcraft.outputs.snap }}
|
||||||
|
release: stable
|
||||||
|
env:
|
||||||
|
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_LOGIN }}
|
||||||
|
if: |
|
||||||
|
github.repository == 'novnc/noVNC' &&
|
||||||
|
github.event_name == 'release' &&
|
||||||
|
!github.event.release.prerelease
|
||||||
|
- uses: snapcore/action-publish@v1
|
||||||
|
with:
|
||||||
|
snap: ${{ steps.snapcraft.outputs.snap }}
|
||||||
|
release: beta
|
||||||
|
env:
|
||||||
|
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_LOGIN }}
|
||||||
|
if: |
|
||||||
|
github.repository == 'novnc/noVNC' &&
|
||||||
|
github.event_name == 'release' &&
|
||||||
|
github.event.release.prerelease
|
||||||
|
- uses: snapcore/action-publish@v1
|
||||||
|
with:
|
||||||
|
snap: ${{ steps.snapcraft.outputs.snap }}
|
||||||
|
release: edge
|
||||||
|
env:
|
||||||
|
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_LOGIN }}
|
||||||
|
if: |
|
||||||
|
github.repository == 'novnc/noVNC' &&
|
||||||
|
github.event_name == 'push' &&
|
||||||
|
github.event.ref == 'refs/heads/master'
|
||||||
19
qiming-noVNC/.github/workflows/lint.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
name: Lint
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
eslint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
- run: npm update
|
||||||
|
- run: npm run lint
|
||||||
|
html:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
- run: npm update
|
||||||
|
- run: git ls-tree --name-only -r HEAD | grep -E "[.](html|css)$" | xargs ./utils/validate
|
||||||
28
qiming-noVNC/.github/workflows/test.yml
vendored
Normal file
@@ -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@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
- run: npm update
|
||||||
|
- run: npm run test
|
||||||
|
env:
|
||||||
|
TEST_BROWSER_NAME: ${{ matrix.browser }}
|
||||||
15
qiming-noVNC/.github/workflows/translate.yml
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
name: Translate
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
translate:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
- run: npm update
|
||||||
|
- run: sudo apt-get install gettext
|
||||||
|
- run: make -C po update-pot
|
||||||
|
- run: make -C po update-po
|
||||||
|
- run: make -C po update-js
|
||||||
14
qiming-noVNC/.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
*.pyc
|
||||||
|
*.o
|
||||||
|
tests/data_*.js
|
||||||
|
utils/rebind.so
|
||||||
|
utils/websockify
|
||||||
|
/node_modules
|
||||||
|
/build
|
||||||
|
/lib
|
||||||
|
recordings
|
||||||
|
*.swp
|
||||||
|
*~
|
||||||
|
noVNC-*.tgz
|
||||||
|
.DS_Store
|
||||||
|
test-page/
|
||||||
0
qiming-noVNC/.gitmodules
vendored
Normal file
13
qiming-noVNC/AUTHORS
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
maintainers:
|
||||||
|
- Samuel Mannehed for Cendio AB (@samhed)
|
||||||
|
- Pierre Ossman for Cendio AB (@CendioOssman)
|
||||||
|
maintainersEmeritus:
|
||||||
|
- Joel Martin (@kanaka)
|
||||||
|
- Solly Ross (@directxman12)
|
||||||
|
- @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.
|
||||||
62
qiming-noVNC/LICENSE.txt
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
noVNC is Copyright (C) 2022 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
|
||||||
|
Javascript code necessary for full noVNC operation. This includes (but
|
||||||
|
is not limited to):
|
||||||
|
|
||||||
|
core/**/*.js
|
||||||
|
app/*.js
|
||||||
|
test/playback.js
|
||||||
|
|
||||||
|
The HTML, CSS, font and images files that included with the noVNC
|
||||||
|
source distibution (or repository) are not considered part of the
|
||||||
|
noVNC core library and are licensed under more permissive licenses.
|
||||||
|
The intent is to allow easy integration of noVNC into existing web
|
||||||
|
sites and web applications.
|
||||||
|
|
||||||
|
The HTML, CSS, font and image files are licensed as follows:
|
||||||
|
|
||||||
|
*.html : 2-Clause BSD license
|
||||||
|
|
||||||
|
app/styles/*.css : 2-Clause BSD license
|
||||||
|
|
||||||
|
app/styles/Orbitron* : SIL Open Font License 1.1
|
||||||
|
(Copyright 2009 Matt McInerney)
|
||||||
|
|
||||||
|
app/images/ : Creative Commons Attribution-ShareAlike
|
||||||
|
http://creativecommons.org/licenses/by-sa/3.0/
|
||||||
|
|
||||||
|
Some portions of noVNC are copyright to their individual authors.
|
||||||
|
Please refer to the individual source files and/or to the noVNC commit
|
||||||
|
history: https://github.com/novnc/noVNC/commits/master
|
||||||
|
|
||||||
|
The are several files and projects that have been incorporated into
|
||||||
|
the noVNC core library. Here is a list of those files and the original
|
||||||
|
licenses (all MPL 2.0 compatible):
|
||||||
|
|
||||||
|
core/base64.js : MPL 2.0
|
||||||
|
|
||||||
|
core/des.js : Various BSD style licenses
|
||||||
|
|
||||||
|
vendor/pako/ : 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.
|
||||||
|
|
||||||
|
The following license texts are included:
|
||||||
|
|
||||||
|
docs/LICENSE.MPL-2.0
|
||||||
|
docs/LICENSE.OFL-1.1
|
||||||
|
docs/LICENSE.BSD-3-Clause (New BSD)
|
||||||
|
docs/LICENSE.BSD-2-Clause (Simplified BSD / FreeBSD)
|
||||||
|
vendor/pako/LICENSE (MIT)
|
||||||
|
|
||||||
|
Or alternatively the license texts may be found here:
|
||||||
|
|
||||||
|
http://www.mozilla.org/MPL/2.0/
|
||||||
|
http://scripts.sil.org/OFL
|
||||||
|
http://en.wikipedia.org/wiki/BSD_licenses
|
||||||
|
https://opensource.org/licenses/MIT
|
||||||
73
qiming-noVNC/LOCAL_DEV.md
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# 本地开发指南
|
||||||
|
|
||||||
|
> ⚠️ **注意**: 本文档及 `scripts/` 目录下的脚本仅用于**开发调试**,不影响原始业务逻辑。
|
||||||
|
|
||||||
|
## 启动开发服务器
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
# 或
|
||||||
|
pnpm dev
|
||||||
|
```
|
||||||
|
|
||||||
|
服务器将在 `http://localhost:8080` 启动。
|
||||||
|
|
||||||
|
## 启动虚拟桌面服务
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 使用 npm 运行(推荐)
|
||||||
|
npm run start:desktop
|
||||||
|
|
||||||
|
# 或直接运行脚本
|
||||||
|
./scripts/start_desktop.sh
|
||||||
|
|
||||||
|
# 自定义提示词
|
||||||
|
npm run start:desktop -- "你好,帮我完成一个任务"
|
||||||
|
|
||||||
|
# 自定义配置
|
||||||
|
API_HOST=192.168.1.34 API_PORT=8086 USER_ID=my_user npm run start:desktop
|
||||||
|
```
|
||||||
|
|
||||||
|
## 测试地址
|
||||||
|
|
||||||
|
### 连接到内网 VNC 服务器
|
||||||
|
|
||||||
|
```
|
||||||
|
http://localhost:8080/vnc.html?host=192.168.1.34&port=8088&path=computer/vnc/user_123/666/websockify&encrypt=0&resize=scale&autoconnect=true
|
||||||
|
```
|
||||||
|
|
||||||
|
### URL 参数说明
|
||||||
|
|
||||||
|
| 参数 | 说明 | 示例值 |
|
||||||
|
|------|------|--------|
|
||||||
|
| `host` | VNC WebSocket 服务器地址 | `192.168.1.34` |
|
||||||
|
| `port` | WebSocket 端口 | `8088` |
|
||||||
|
| `path` | WebSocket 路径 | `computer/vnc/user_123/666/websockify` |
|
||||||
|
| `encrypt` | 是否加密 (0=ws://, 1=wss://) | `0` |
|
||||||
|
| `resize` | 缩放模式 (`off`, `scale`, `remote`) | `scale` |
|
||||||
|
| `autoconnect` | 是否自动连接 | `true` |
|
||||||
|
|
||||||
|
### 完整 WebSocket 地址
|
||||||
|
|
||||||
|
上述配置对应的 WebSocket 连接地址为:
|
||||||
|
|
||||||
|
```
|
||||||
|
ws://192.168.1.34:8088/computer/vnc/user_123/666/websockify
|
||||||
|
```
|
||||||
|
|
||||||
|
## 配置默认值
|
||||||
|
|
||||||
|
可以通过修改 `defaults.json` 来设置默认连接参数:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"host": "192.168.1.34",
|
||||||
|
"port": 8088,
|
||||||
|
"path": "computer/vnc/user_123/666/websockify",
|
||||||
|
"encrypt": false,
|
||||||
|
"resize": "scale",
|
||||||
|
"autoconnect": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> **注意**: URL 参数会覆盖 `defaults.json` 中的配置。
|
||||||
228
qiming-noVNC/README.md
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
## noVNC: HTML VNC client library and application
|
||||||
|
|
||||||
|
[](https://github.com/novnc/noVNC/actions?query=workflow%3ATest)
|
||||||
|
[](https://github.com/novnc/noVNC/actions?query=workflow%3ALint)
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
noVNC is both a HTML VNC client JavaScript library and an application built on
|
||||||
|
top of that library. noVNC runs well in any modern browser including mobile
|
||||||
|
browsers (iOS and Android).
|
||||||
|
|
||||||
|
Many companies, projects and products have integrated noVNC including
|
||||||
|
[OpenStack](http://www.openstack.org),
|
||||||
|
[OpenNebula](http://opennebula.org/),
|
||||||
|
[LibVNCServer](http://libvncserver.sourceforge.net), and
|
||||||
|
[ThinLinc](https://cendio.com/thinlinc). See
|
||||||
|
[the Projects and companies wiki page](https://github.com/novnc/noVNC/wiki/Projects-and-companies-using-noVNC)
|
||||||
|
for a more complete list with additional info and links.
|
||||||
|
|
||||||
|
### Table of contents
|
||||||
|
|
||||||
|
- [News/help/contact](#newshelpcontact)
|
||||||
|
- [Features](#features)
|
||||||
|
- [Screenshots](#screenshots)
|
||||||
|
- [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)
|
||||||
|
|
||||||
|
### News/help/contact
|
||||||
|
|
||||||
|
The project website is found at [novnc.com](http://novnc.com).
|
||||||
|
|
||||||
|
If you are a noVNC developer/integrator/user (or want to be) please join the
|
||||||
|
[noVNC discussion group](https://groups.google.com/forum/?fromgroups#!forum/novnc).
|
||||||
|
|
||||||
|
Bugs and feature requests can be submitted via
|
||||||
|
[github issues](https://github.com/novnc/noVNC/issues). If you have questions
|
||||||
|
about using noVNC then please first use the
|
||||||
|
[discussion group](https://groups.google.com/forum/?fromgroups#!forum/novnc).
|
||||||
|
We also have a [wiki](https://github.com/novnc/noVNC/wiki/) with lots of
|
||||||
|
helpful information.
|
||||||
|
|
||||||
|
If you are looking for a place to start contributing to noVNC, a good place to
|
||||||
|
start would be the issues that are marked as
|
||||||
|
["patchwelcome"](https://github.com/novnc/noVNC/issues?labels=patchwelcome).
|
||||||
|
Please check our
|
||||||
|
[contribution guide](https://github.com/novnc/noVNC/wiki/Contributing) though.
|
||||||
|
|
||||||
|
If you want to show appreciation for noVNC you could donate to a great non-
|
||||||
|
profits such as:
|
||||||
|
[Compassion International](http://www.compassion.com/),
|
||||||
|
[SIL](http://www.sil.org),
|
||||||
|
[Habitat for Humanity](http://www.habitat.org),
|
||||||
|
[Electronic Frontier Foundation](https://www.eff.org/),
|
||||||
|
[Against Malaria Foundation](http://www.againstmalaria.com/),
|
||||||
|
[Nothing But Nets](http://www.nothingbutnets.net/), etc.
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Supports all modern browsers including mobile (iOS, Android)
|
||||||
|
* Supported authentication methods: none, classical VNC, RealVNC's
|
||||||
|
RSA-AES, Tight, VeNCrypt Plain, XVP, Apple's Diffie-Hellman,
|
||||||
|
UltraVNC's MSLogonII
|
||||||
|
* Supported VNC encodings: raw, copyrect, rre, hextile, tight, tightPNG,
|
||||||
|
ZRLE, JPEG, Zlib, H.264
|
||||||
|
* Supports scaling, clipping and resizing the desktop
|
||||||
|
* Supports back & forward mouse buttons
|
||||||
|
* Local cursor rendering
|
||||||
|
* Clipboard copy/paste with full Unicode support
|
||||||
|
* 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
|
||||||
|
|
||||||
|
### Screenshots
|
||||||
|
|
||||||
|
Running in Firefox before and after connecting:
|
||||||
|
|
||||||
|
<img src="http://novnc.com/img/noVNC-1-login.png" width=400>
|
||||||
|
<img src="http://novnc.com/img/noVNC-3-connected.png" width=400>
|
||||||
|
|
||||||
|
See more screenshots
|
||||||
|
[here](http://novnc.com/screenshots.html).
|
||||||
|
|
||||||
|
|
||||||
|
### Browser requirements
|
||||||
|
|
||||||
|
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 89, Firefox 89, Safari 15, Opera 75, Edge 89
|
||||||
|
|
||||||
|
|
||||||
|
### Server requirements
|
||||||
|
|
||||||
|
noVNC follows the standard VNC protocol, but unlike other VNC clients it does
|
||||||
|
require WebSockets support. Many servers include support (e.g.
|
||||||
|
[x11vnc/libvncserver](http://libvncserver.sourceforge.net/),
|
||||||
|
[QEMU](http://www.qemu.org/), and
|
||||||
|
[MobileVNC](http://www.smartlab.at/mobilevnc/)), but for the others you need to
|
||||||
|
use a WebSockets to TCP socket proxy. noVNC has a sister project
|
||||||
|
[websockify](https://github.com/novnc/websockify) that provides a simple such
|
||||||
|
proxy.
|
||||||
|
|
||||||
|
|
||||||
|
### Quick start
|
||||||
|
|
||||||
|
* 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/novnc_proxy --vnc localhost:5901`
|
||||||
|
|
||||||
|
* If you don't need to expose the web server to public internet, you can
|
||||||
|
bind to localhost:
|
||||||
|
|
||||||
|
`./utils/novnc_proxy --vnc localhost:5901 --listen localhost:6081`
|
||||||
|
|
||||||
|
* Point your browser to the cut-and-paste URL that is output by the `novnc_proxy`
|
||||||
|
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 from snap directly
|
||||||
|
|
||||||
|
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`
|
||||||
|
|
||||||
|
If you want to use certificate files, due to standard snap confinement restrictions you need to have them in the /home/\<user\>/snap/novnc/current/ directory. If your username is jsmith an example command would be:
|
||||||
|
|
||||||
|
`novnc --listen 8443 --cert ~jsmith/snap/novnc/current/self.crt --key ~jsmith/snap/novnc/current/self.key --vnc ubuntu.example.com:5901`
|
||||||
|
|
||||||
|
#### Running noVNC from snap 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 running 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
|
||||||
|
|
||||||
|
Please see our other documents for how to integrate noVNC in your own software,
|
||||||
|
or deploying the noVNC application in production environments:
|
||||||
|
|
||||||
|
* [Embedding](docs/EMBEDDING.md) - For the noVNC application
|
||||||
|
* [Library](docs/LIBRARY.md) - For the noVNC JavaScript library
|
||||||
|
|
||||||
|
|
||||||
|
### 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:
|
||||||
|
* [Samuel Mannehed](https://github.com/samhed) (Cendio)
|
||||||
|
* [Pierre Ossman](https://github.com/CendioOssman) (Cendio)
|
||||||
|
|
||||||
|
* Previous core contributors:
|
||||||
|
* [Joel Martin](https://github.com/kanaka) (Project founder)
|
||||||
|
* [Solly Ross](https://github.com/DirectXMan12) (Red Hat / OpenStack)
|
||||||
|
|
||||||
|
* Notable contributions:
|
||||||
|
* UI and icons : Pierre Ossman, Chris Gordon
|
||||||
|
* Original logo : Michael Sersen
|
||||||
|
* tight encoding : Michael Tinglof (Mercuri.ca)
|
||||||
|
* RealVNC RSA AES authentication : USTC Vlab Team
|
||||||
|
|
||||||
|
* Included libraries:
|
||||||
|
* base64 : Martijn Pieters (Digital Creations 2), Samuel Sieb (sieb.net)
|
||||||
|
* DES : Dave Zimmerman (Widget Workshop), Jef Poskanzer (ACME Labs)
|
||||||
|
* Pako : Vitaly Puzrin (https://github.com/nodeca/pako)
|
||||||
|
|
||||||
|
Do you want to be on this list? Check out our
|
||||||
|
[contribution guide](https://github.com/novnc/noVNC/wiki/Contributing) and
|
||||||
|
start hacking!
|
||||||
392
qiming-noVNC/app/audio.js
Normal file
@@ -0,0 +1,392 @@
|
|||||||
|
/*
|
||||||
|
* noVNC: HTML5 VNC client
|
||||||
|
* Audio streaming module for remote desktop audio playback
|
||||||
|
*
|
||||||
|
* 音频流模块 - 用于播放远程桌面的音频输出
|
||||||
|
*
|
||||||
|
* 功能:
|
||||||
|
* - 通过 WebSocket 接收 Opus 编码的音频数据
|
||||||
|
* - 使用 Web Audio API 解码并播放音频
|
||||||
|
* - 支持音量控制和连接状态管理
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as Log from '../core/util/logging.js';
|
||||||
|
|
||||||
|
// 音频管理器类
|
||||||
|
class AudioManager {
|
||||||
|
constructor() {
|
||||||
|
// WebSocket 连接
|
||||||
|
this.ws = null;
|
||||||
|
this.connected = false;
|
||||||
|
|
||||||
|
// Web Audio API 组件
|
||||||
|
this.audioContext = null;
|
||||||
|
this.gainNode = null;
|
||||||
|
this.decoder = null;
|
||||||
|
|
||||||
|
// 播放调度
|
||||||
|
this.nextPlayTime = 0;
|
||||||
|
|
||||||
|
// 配置
|
||||||
|
this.volume = 0.8; // 默认音量 80%
|
||||||
|
this.sampleRate = 48000;
|
||||||
|
this.channels = 2;
|
||||||
|
|
||||||
|
// 重试配置
|
||||||
|
this.maxRetries = 5; // 最大重试次数
|
||||||
|
this.retryCount = 0; // 当前重试次数
|
||||||
|
this.retryDelay = 2000; // 重试间隔 (ms)
|
||||||
|
this.retryTimer = null; // 重试定时器
|
||||||
|
this.lastWsUrl = null; // 上次连接的URL(用于重试)
|
||||||
|
this.autoRetryEnabled = true; // 是否启用自动重试
|
||||||
|
|
||||||
|
// 回调函数
|
||||||
|
this.onStatusChange = null;
|
||||||
|
this.onMaxRetriesReached = null; // 达到最大重试次数的回调
|
||||||
|
|
||||||
|
// OpusDecoder 加载状态
|
||||||
|
this.opusDecoderReady = false;
|
||||||
|
this._checkOpusDecoder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查 OpusDecoder 是否已加载
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_checkOpusDecoder() {
|
||||||
|
// opus-decoder 库使用 UMD 模式,导出为 window["opus-decoder"].OpusDecoder
|
||||||
|
const opusDecoderLib = window["opus-decoder"];
|
||||||
|
if (opusDecoderLib && opusDecoderLib.OpusDecoder) {
|
||||||
|
window.OpusDecoder = opusDecoderLib.OpusDecoder;
|
||||||
|
this.opusDecoderReady = true;
|
||||||
|
Log.Info('[Audio] OpusDecoder 加载成功');
|
||||||
|
} else {
|
||||||
|
Log.Warn('[Audio] OpusDecoder 未加载,音频功能可能无法使用');
|
||||||
|
this.opusDecoderReady = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建音频 WebSocket URL
|
||||||
|
* @param {string} baseUrl - 基础 URL (如 http://127.0.0.1:8088)
|
||||||
|
* @param {string} projectId - 项目 ID
|
||||||
|
* @param {string} userId - 用户 ID (可选,调试模式使用)
|
||||||
|
* @param {boolean} debugMode - 是否调试模式
|
||||||
|
* @returns {string} WebSocket URL
|
||||||
|
*/
|
||||||
|
buildWsUrl(baseUrl, projectId, userId = null, debugMode = false) {
|
||||||
|
// 将 http/https 转换为 ws/wss
|
||||||
|
const wsUrl = baseUrl
|
||||||
|
.replace(/^http/, 'ws')
|
||||||
|
.replace(/\/+$/, '');
|
||||||
|
|
||||||
|
// 调试模式:包含 user_id
|
||||||
|
// 正式模式:不包含 user_id
|
||||||
|
if (debugMode && userId) {
|
||||||
|
return `ws://192.168.1.34:8088/computer/audio/${userId}/${projectId}/ws`;
|
||||||
|
} else {
|
||||||
|
return `${wsUrl}/computer/audio/${projectId}/ws`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 连接音频流
|
||||||
|
* @param {string} wsUrl - WebSocket URL
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async connect(wsUrl) {
|
||||||
|
if (this.connected) {
|
||||||
|
Log.Warn('[Audio] 已经连接,请先断开');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查 OpusDecoder
|
||||||
|
if (!this.opusDecoderReady) {
|
||||||
|
this._checkOpusDecoder();
|
||||||
|
if (!this.opusDecoderReady) {
|
||||||
|
Log.Error('[Audio] OpusDecoder 未加载,无法启动音频');
|
||||||
|
this._updateStatus('error', 'OpusDecoder 未加载');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this._updateStatus('connecting', '音频连接中...');
|
||||||
|
Log.Info('[Audio] 连接音频流: ' + wsUrl);
|
||||||
|
|
||||||
|
// 初始化 Web Audio API
|
||||||
|
await this._initAudioContext();
|
||||||
|
|
||||||
|
// 保存URL用于重试
|
||||||
|
this.lastWsUrl = wsUrl;
|
||||||
|
|
||||||
|
// 连接 WebSocket
|
||||||
|
this.ws = new WebSocket(wsUrl);
|
||||||
|
this.ws.binaryType = 'arraybuffer';
|
||||||
|
|
||||||
|
this.ws.onopen = () => {
|
||||||
|
Log.Info('[Audio] WebSocket 已连接');
|
||||||
|
this.connected = true;
|
||||||
|
this.retryCount = 0; // 连接成功,重置重试计数
|
||||||
|
this._updateStatus('connected', '音频已连接');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.ws.onmessage = async (event) => {
|
||||||
|
try {
|
||||||
|
const data = new Uint8Array(event.data);
|
||||||
|
// 检查协议头 (0x01 表示 Opus 音频)
|
||||||
|
if (data[0] === 0x01) {
|
||||||
|
const opusData = data.slice(1);
|
||||||
|
await this._playAudioChunk(opusData);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
Log.Error('[Audio] 处理音频数据失败: ' + err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.ws.onerror = (err) => {
|
||||||
|
Log.Error('[Audio] WebSocket 错误: ' + err);
|
||||||
|
this._updateStatus('error', '音频连接错误');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.ws.onclose = () => {
|
||||||
|
Log.Info('[Audio] WebSocket 已关闭');
|
||||||
|
this.connected = false;
|
||||||
|
this._cleanup();
|
||||||
|
|
||||||
|
// 自动重试逻辑
|
||||||
|
if (this.autoRetryEnabled && this.retryCount < this.maxRetries) {
|
||||||
|
this.retryCount++;
|
||||||
|
Log.Info('[Audio] 将在 ' + (this.retryDelay / 1000) + ' 秒后重试 (' + this.retryCount + '/' + this.maxRetries + ')');
|
||||||
|
this._updateStatus('connecting', '重试中 (' + this.retryCount + '/' + this.maxRetries + ')');
|
||||||
|
|
||||||
|
this.retryTimer = setTimeout(() => {
|
||||||
|
if (this.lastWsUrl && this.autoRetryEnabled) {
|
||||||
|
this.connect(this.lastWsUrl);
|
||||||
|
}
|
||||||
|
}, this.retryDelay);
|
||||||
|
} else if (this.retryCount >= this.maxRetries) {
|
||||||
|
Log.Warn('[Audio] 已达到最大重试次数 (' + this.maxRetries + ')');
|
||||||
|
this._updateStatus('error', '连接失败,请手动重试');
|
||||||
|
if (this.onMaxRetriesReached) {
|
||||||
|
this.onMaxRetriesReached();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._updateStatus('disconnected', '音频已断开');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
Log.Error('[Audio] 连接失败: ' + err);
|
||||||
|
this._updateStatus('error', '音频启动失败');
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 断开音频流
|
||||||
|
*/
|
||||||
|
disconnect() {
|
||||||
|
// 禁用自动重试
|
||||||
|
this.autoRetryEnabled = false;
|
||||||
|
|
||||||
|
// 清除重试定时器
|
||||||
|
if (this.retryTimer) {
|
||||||
|
clearTimeout(this.retryTimer);
|
||||||
|
this.retryTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.ws) {
|
||||||
|
this.ws.close();
|
||||||
|
this.ws = null;
|
||||||
|
}
|
||||||
|
this.connected = false;
|
||||||
|
this.retryCount = 0;
|
||||||
|
this._cleanup();
|
||||||
|
this._updateStatus('disconnected', '音频已停止');
|
||||||
|
Log.Info('[Audio] 音频流已断开');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置音量
|
||||||
|
* @param {number} volume - 音量值 (0-1)
|
||||||
|
*/
|
||||||
|
setVolume(volume) {
|
||||||
|
this.volume = Math.max(0, Math.min(1, volume));
|
||||||
|
if (this.gainNode) {
|
||||||
|
this.gainNode.gain.value = this.volume;
|
||||||
|
}
|
||||||
|
Log.Debug('[Audio] 音量设置为: ' + Math.round(this.volume * 100) + '%');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前音量
|
||||||
|
* @returns {number} 音量值 (0-1)
|
||||||
|
*/
|
||||||
|
getVolume() {
|
||||||
|
return this.volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化 Web Audio API
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
async _initAudioContext() {
|
||||||
|
if (!this.audioContext) {
|
||||||
|
this.audioContext = new (window.AudioContext || window.webkitAudioContext)({
|
||||||
|
sampleRate: this.sampleRate,
|
||||||
|
latencyHint: 'interactive'
|
||||||
|
});
|
||||||
|
|
||||||
|
this.gainNode = this.audioContext.createGain();
|
||||||
|
this.gainNode.gain.value = this.volume;
|
||||||
|
this.gainNode.connect(this.audioContext.destination);
|
||||||
|
|
||||||
|
this.nextPlayTime = this.audioContext.currentTime + 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 恢复 AudioContext(浏览器安全策略)
|
||||||
|
if (this.audioContext.state === 'suspended') {
|
||||||
|
try {
|
||||||
|
await this.audioContext.resume();
|
||||||
|
Log.Info('[Audio] AudioContext 已恢复');
|
||||||
|
} catch (e) {
|
||||||
|
Log.Warn('[Audio] AudioContext 自动恢复失败,等待用户交互: ' + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 尝试恢复 AudioContext
|
||||||
|
*/
|
||||||
|
async resume() {
|
||||||
|
if (this.audioContext && this.audioContext.state === 'suspended') {
|
||||||
|
try {
|
||||||
|
await this.audioContext.resume();
|
||||||
|
Log.Info('[Audio] AudioContext 已恢复');
|
||||||
|
} catch (e) {
|
||||||
|
Log.Error('[Audio] 恢复失败: ' + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 播放音频数据块
|
||||||
|
* @param {Uint8Array} opusData - Opus 编码的音频数据
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
async _playAudioChunk(opusData) {
|
||||||
|
try {
|
||||||
|
// 初始化或复用 Opus 解码器
|
||||||
|
if (!this.decoder) {
|
||||||
|
Log.Debug('[Audio] 初始化 OpusDecoder...');
|
||||||
|
this.decoder = new window.OpusDecoder({
|
||||||
|
sampleRate: this.sampleRate,
|
||||||
|
channels: this.channels
|
||||||
|
});
|
||||||
|
await this.decoder.ready;
|
||||||
|
Log.Debug('[Audio] OpusDecoder 初始化完成');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解码 Opus 数据
|
||||||
|
const decoded = this.decoder.decodeFrame(opusData);
|
||||||
|
const channels = decoded.channelData;
|
||||||
|
const samplesDecoded = decoded.samplesDecoded;
|
||||||
|
|
||||||
|
if (!channels || channels.length < 2) {
|
||||||
|
Log.Warn('[Audio] 输出声道数据无效');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const leftChannelData = channels[0];
|
||||||
|
const rightChannelData = channels[1];
|
||||||
|
|
||||||
|
// 创建 AudioBuffer
|
||||||
|
const audioBuffer = this.audioContext.createBuffer(
|
||||||
|
2, samplesDecoded, this.sampleRate
|
||||||
|
);
|
||||||
|
|
||||||
|
// 填充声道数据
|
||||||
|
audioBuffer.getChannelData(0).set(leftChannelData);
|
||||||
|
audioBuffer.getChannelData(1).set(rightChannelData);
|
||||||
|
|
||||||
|
// 调度播放
|
||||||
|
const source = this.audioContext.createBufferSource();
|
||||||
|
source.buffer = audioBuffer;
|
||||||
|
source.connect(this.gainNode);
|
||||||
|
|
||||||
|
// 计算播放时间
|
||||||
|
const currentTime = this.audioContext.currentTime;
|
||||||
|
if (this.nextPlayTime < currentTime) {
|
||||||
|
this.nextPlayTime = currentTime + 0.05; // 50ms 缓冲
|
||||||
|
}
|
||||||
|
|
||||||
|
source.start(this.nextPlayTime);
|
||||||
|
|
||||||
|
// 计算下一个播放时间点
|
||||||
|
const duration = samplesDecoded / this.sampleRate;
|
||||||
|
this.nextPlayTime += duration;
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
Log.Error('[Audio] 解码或播放失败: ' + err);
|
||||||
|
// 解码失败时重置解码器
|
||||||
|
if (this.decoder) {
|
||||||
|
try {
|
||||||
|
this.decoder.free();
|
||||||
|
} catch (e) {
|
||||||
|
// 忽略释放错误
|
||||||
|
}
|
||||||
|
this.decoder = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理资源
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_cleanup() {
|
||||||
|
// 重置播放调度
|
||||||
|
this.nextPlayTime = 0;
|
||||||
|
|
||||||
|
// 释放解码器
|
||||||
|
if (this.decoder) {
|
||||||
|
try {
|
||||||
|
this.decoder.free();
|
||||||
|
} catch (e) {
|
||||||
|
// 忽略释放错误
|
||||||
|
}
|
||||||
|
this.decoder = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新状态并触发回调
|
||||||
|
* @param {string} status - 状态 (connecting/connected/disconnected/error)
|
||||||
|
* @param {string} message - 状态消息
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_updateStatus(status, message) {
|
||||||
|
if (this.onStatusChange) {
|
||||||
|
this.onStatusChange(status, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 销毁音频管理器
|
||||||
|
*/
|
||||||
|
destroy() {
|
||||||
|
this.disconnect();
|
||||||
|
if (this.audioContext) {
|
||||||
|
this.audioContext.close();
|
||||||
|
this.audioContext = null;
|
||||||
|
}
|
||||||
|
this.gainNode = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出单例
|
||||||
|
const audioManager = new AudioManager();
|
||||||
|
export default audioManager;
|
||||||
|
|
||||||
252
qiming-noVNC/app/clipboard.js
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
/*
|
||||||
|
* noVNC: HTML5 VNC client
|
||||||
|
* Clipboard management module
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as Log from '../core/util/logging.js';
|
||||||
|
import { l10n } from './localization.js';
|
||||||
|
|
||||||
|
const _ = l10n.get.bind(l10n);
|
||||||
|
|
||||||
|
class ClipboardManager {
|
||||||
|
constructor() {
|
||||||
|
this.rfb = null;
|
||||||
|
this.autoSync = false;
|
||||||
|
this.permissionGranted = false;
|
||||||
|
this.lastLocalText = null;
|
||||||
|
this.syncFocusHandler = null;
|
||||||
|
|
||||||
|
// Callbacks for UI updates
|
||||||
|
this.onStatusChange = null; // (status, message) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
setRFB(rfb) {
|
||||||
|
this.rfb = rfb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize clipboard state based on permissions
|
||||||
|
* 根据权限状态初始化剪贴板自动同步
|
||||||
|
*
|
||||||
|
* 注意:默认开启自动同步,因为:
|
||||||
|
* 1. 这是更好的用户体验
|
||||||
|
* 2. Clipboard API 在用户手势(如点击、焦点切换)时才会真正读取
|
||||||
|
* 3. 如果权限被拒绝,会在实际操作时处理
|
||||||
|
*/
|
||||||
|
async init() {
|
||||||
|
Log.Info('[Clipboard] Initializing...');
|
||||||
|
|
||||||
|
// 检查 Clipboard API 是否可用
|
||||||
|
if (!navigator.clipboard) {
|
||||||
|
Log.Warn('[Clipboard] Clipboard API not supported');
|
||||||
|
this._updateStatus('error', _('Clipboard API not supported'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试查询权限状态(某些浏览器可能不支持)
|
||||||
|
let permissionState = 'unknown';
|
||||||
|
|
||||||
|
if (navigator.permissions && navigator.permissions.query) {
|
||||||
|
try {
|
||||||
|
// 注意:某些浏览器不支持 "clipboard-read" 权限查询
|
||||||
|
const result = await navigator.permissions.query({ name: "clipboard-read" });
|
||||||
|
permissionState = result.state;
|
||||||
|
Log.Info('[Clipboard] Permission query result: ' + permissionState);
|
||||||
|
} catch (err) {
|
||||||
|
// 权限查询不支持(如 Firefox),这是正常的
|
||||||
|
Log.Debug('[Clipboard] Permission query not supported: ' + err.message);
|
||||||
|
permissionState = 'unknown';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据权限状态决定行为
|
||||||
|
if (permissionState === 'denied') {
|
||||||
|
// 权限明确被拒绝
|
||||||
|
Log.Info('[Clipboard] Permission denied, disabling auto sync');
|
||||||
|
this.autoSync = false;
|
||||||
|
this._updateStatus('inactive', '');
|
||||||
|
} else {
|
||||||
|
// granted / prompt / unknown 都默认开启
|
||||||
|
// 实际权限检查会在用户手势时进行
|
||||||
|
Log.Info('[Clipboard] Enabling auto sync (permission: ' + permissionState + ')');
|
||||||
|
this.autoSync = true;
|
||||||
|
this._startSync(false); // 不立即执行,等待用户手势
|
||||||
|
this._updateStatus('active', _('Auto sync enabled'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle auto-sync state
|
||||||
|
* @param {boolean} enable
|
||||||
|
* @returns {Promise<boolean>} resulting state
|
||||||
|
*/
|
||||||
|
async toggleAutoSync(enable) {
|
||||||
|
if (enable) {
|
||||||
|
const hasPermission = await this._requestPermission();
|
||||||
|
if (!hasPermission) {
|
||||||
|
this._updateStatus('error', _('Clipboard permission denied'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.autoSync = true;
|
||||||
|
this._startSync();
|
||||||
|
this._updateStatus('active', _('Auto sync enabled'));
|
||||||
|
Log.Info('[Clipboard] Auto sync enabled');
|
||||||
|
} else {
|
||||||
|
this.autoSync = false;
|
||||||
|
this._stopSync();
|
||||||
|
this._updateStatus('inactive', '');
|
||||||
|
Log.Info('[Clipboard] Auto sync disabled');
|
||||||
|
}
|
||||||
|
return this.autoSync;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive text from remote and sync to local if enabled
|
||||||
|
* @param {string} text
|
||||||
|
*/
|
||||||
|
handleRemoteText(text) {
|
||||||
|
if (this.autoSync) {
|
||||||
|
this.writeLocal(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read from local clipboard manually
|
||||||
|
*/
|
||||||
|
async readLocal() {
|
||||||
|
try {
|
||||||
|
if (!navigator.clipboard || !navigator.clipboard.readText) {
|
||||||
|
this._updateStatus('error', _('Clipboard API not supported'));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const text = await navigator.clipboard.readText();
|
||||||
|
this.lastLocalText = text;
|
||||||
|
Log.Debug('[Clipboard] Read from local: ' + text.substr(0, 40) + '...');
|
||||||
|
|
||||||
|
this._updateStatus('success', _('Read from local clipboard'));
|
||||||
|
this._resetStatus();
|
||||||
|
|
||||||
|
return text;
|
||||||
|
} catch (err) {
|
||||||
|
Log.Warn('[Clipboard] Failed to read local: ' + err.message);
|
||||||
|
this._updateStatus('error', _('Failed to read clipboard'));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write to local clipboard
|
||||||
|
* @param {string} text
|
||||||
|
*/
|
||||||
|
async writeLocal(text) {
|
||||||
|
try {
|
||||||
|
if (!navigator.clipboard || !navigator.clipboard.writeText) {
|
||||||
|
this._updateStatus('error', _('Clipboard API not supported'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await navigator.clipboard.writeText(text);
|
||||||
|
this.lastLocalText = text;
|
||||||
|
Log.Debug('[Clipboard] Wrote to local: ' + text.substr(0, 40) + '...');
|
||||||
|
|
||||||
|
this._updateStatus('success', _('Copied to local clipboard'));
|
||||||
|
this._resetStatus();
|
||||||
|
} catch (err) {
|
||||||
|
Log.Warn('[Clipboard] Failed to write local: ' + err.message);
|
||||||
|
this._updateStatus('error', _('Failed to write clipboard'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send text to remote
|
||||||
|
* @param {string} text
|
||||||
|
*/
|
||||||
|
sendToRemote(text) {
|
||||||
|
if (this.rfb) {
|
||||||
|
this.rfb.clipboardPasteFrom(text);
|
||||||
|
Log.Debug('[Clipboard] Sent to remote: ' + text.substr(0, 40) + '...');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private methods
|
||||||
|
|
||||||
|
async _requestPermission() {
|
||||||
|
try {
|
||||||
|
if (navigator.clipboard && navigator.clipboard.readText) {
|
||||||
|
await navigator.clipboard.readText();
|
||||||
|
this.permissionGranted = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch (err) {
|
||||||
|
if (err.name === 'NotAllowedError') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Other errors (like empty clipboard) usually mean we have permission
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_startSync(runImmediately = true) {
|
||||||
|
this.syncFocusHandler = async () => {
|
||||||
|
if (!this.autoSync || !this.rfb) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Focus event is a user gesture, so readText should work/prompt
|
||||||
|
const text = await navigator.clipboard.readText();
|
||||||
|
if (text && text !== this.lastLocalText) {
|
||||||
|
this.lastLocalText = text;
|
||||||
|
this.sendToRemote(text);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// If it fails (e.g. denied), we might want to turn off autoSync?
|
||||||
|
// For now, just log and maybe show status
|
||||||
|
Log.Warn('[Clipboard] Auto-sync read failed: ' + err);
|
||||||
|
if (err.name === 'NotAllowedError') {
|
||||||
|
this._updateStatus('error', _('Clipboard permission denied'));
|
||||||
|
this.autoSync = false; // Disable if denied
|
||||||
|
// We might want to notify UI to uncheck box
|
||||||
|
// But we don't have a direct way to sync back to checkbox unless we use callback
|
||||||
|
// Current arch: init sets checkbox. toggle sets checkbox.
|
||||||
|
// If we change state here, checkbox might desync.
|
||||||
|
// We can use onStatusChange to signal "error"? Or add onStateChange?
|
||||||
|
// For now, keep simple.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('focus', this.syncFocusHandler);
|
||||||
|
if (runImmediately) {
|
||||||
|
this.syncFocusHandler(); // Initial sync
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_stopSync() {
|
||||||
|
if (this.syncFocusHandler) {
|
||||||
|
window.removeEventListener('focus', this.syncFocusHandler);
|
||||||
|
this.syncFocusHandler = null;
|
||||||
|
}
|
||||||
|
this.lastLocalText = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateStatus(status, message) {
|
||||||
|
if (this.onStatusChange) {
|
||||||
|
this.onStatusChange(status, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_resetStatus() {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this.autoSync) {
|
||||||
|
this._updateStatus('active', _('Auto sync enabled'));
|
||||||
|
} else {
|
||||||
|
this._updateStatus('inactive', '');
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const clipboardManager = new ClipboardManager();
|
||||||
|
export default clipboardManager;
|
||||||
79
qiming-noVNC/app/error-handler.js
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Fallback for all uncought errors
|
||||||
|
function handleError(event, err) {
|
||||||
|
try {
|
||||||
|
const msg = document.getElementById('noVNC_fallback_errormsg');
|
||||||
|
|
||||||
|
// Work around Firefox bug:
|
||||||
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1685038
|
||||||
|
if (event.message === "ResizeObserver loop completed with undelivered notifications.") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only show the initial error
|
||||||
|
if (msg.hasChildNodes()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let div = document.createElement("div");
|
||||||
|
div.classList.add('noVNC_message');
|
||||||
|
div.appendChild(document.createTextNode(event.message));
|
||||||
|
msg.appendChild(div);
|
||||||
|
|
||||||
|
if (event.filename) {
|
||||||
|
div = document.createElement("div");
|
||||||
|
div.className = 'noVNC_location';
|
||||||
|
let text = event.filename;
|
||||||
|
if (event.lineno !== undefined) {
|
||||||
|
text += ":" + event.lineno;
|
||||||
|
if (event.colno !== undefined) {
|
||||||
|
text += ":" + event.colno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div.appendChild(document.createTextNode(text));
|
||||||
|
msg.appendChild(div);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err && err.stack) {
|
||||||
|
div = document.createElement("div");
|
||||||
|
div.className = 'noVNC_stack';
|
||||||
|
div.appendChild(document.createTextNode(err.stack));
|
||||||
|
msg.appendChild(div);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('noVNC_fallback_error')
|
||||||
|
.classList.add("noVNC_open");
|
||||||
|
|
||||||
|
} catch (exc) {
|
||||||
|
document.write("noVNC encountered an error.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to disable keyboard interaction, best effort
|
||||||
|
try {
|
||||||
|
// Remove focus from the currently focused element in order to
|
||||||
|
// prevent keyboard interaction from continuing
|
||||||
|
if (document.activeElement) { document.activeElement.blur(); }
|
||||||
|
|
||||||
|
// Don't let any element be focusable when showing the error
|
||||||
|
let keyboardFocusable = 'a[href], button, input, textarea, select, details, [tabindex]';
|
||||||
|
document.querySelectorAll(keyboardFocusable).forEach((elem) => {
|
||||||
|
elem.setAttribute("tabindex", "-1");
|
||||||
|
});
|
||||||
|
} catch (exc) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't return true since this would prevent the error
|
||||||
|
// from being printed to the browser console.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('error', evt => handleError(evt, evt.error));
|
||||||
|
window.addEventListener('unhandledrejection', evt => handleError(evt.reason, evt.reason));
|
||||||
92
qiming-noVNC/app/images/alt.svg
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
<?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="alt.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="18.205425"
|
||||||
|
inkscape:cy="17.531398"
|
||||||
|
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)">
|
||||||
|
<g
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:48px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'Sans Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
id="text5290">
|
||||||
|
<path
|
||||||
|
d="m 9.9560547,1042.3329 -2.9394531,0 -0.4638672,1.3281 -1.8896485,0 2.7001953,-7.29 2.241211,0 2.7001958,7.29 -1.889649,0 -0.4589843,-1.3281 z m -2.4707031,-1.3526 1.9970703,0 -0.9960938,-2.9003 -1.0009765,2.9003 z"
|
||||||
|
style="font-size:10px;fill:#ffffff;fill-opacity:1"
|
||||||
|
id="path5340" />
|
||||||
|
<path
|
||||||
|
d="m 13.188477,1036.0634 1.748046,0 0,7.5976 -1.748046,0 0,-7.5976 z"
|
||||||
|
style="font-size:10px;fill:#ffffff;fill-opacity:1"
|
||||||
|
id="path5342" />
|
||||||
|
<path
|
||||||
|
d="m 18.535156,1036.6395 0,1.5528 1.801758,0 0,1.25 -1.801758,0 0,2.3193 q 0,0.3809 0.151367,0.5176 0.151368,0.1318 0.600586,0.1318 l 0.898438,0 0,1.25 -1.499024,0 q -1.035156,0 -1.469726,-0.4297 -0.429688,-0.4345 -0.429688,-1.4697 l 0,-2.3193 -0.86914,0 0,-1.25 0.86914,0 0,-1.5528 1.748047,0 z"
|
||||||
|
style="font-size:10px;fill:#ffffff;fill-opacity:1"
|
||||||
|
id="path5344" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.5 KiB |
BIN
qiming-noVNC/app/images/audio-muted.png
Normal file
|
After Width: | Height: | Size: 367 B |
5
qiming-noVNC/app/images/audio-muted.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 25 25" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon>
|
||||||
|
<line x1="18" y1="8" x2="14" y2="16"></line>
|
||||||
|
<line x1="14" y1="8" x2="18" y2="16"></line>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 343 B |
BIN
qiming-noVNC/app/images/audio-on.png
Normal file
|
After Width: | Height: | Size: 553 B |
5
qiming-noVNC/app/images/audio-on.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 25 25" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon>
|
||||||
|
<path d="M19.07 4.93a10 10 0 0 1 0 14.14"></path>
|
||||||
|
<path d="M15.54 8.46a5 5 0 0 1 0 7.07"></path>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 350 B |
6
qiming-noVNC/app/images/audio.svg
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 25 25" fill="none" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon>
|
||||||
|
<path d="M19.07 4.93a10 10 0 0 1 0 14.14"></path>
|
||||||
|
<path d="M15.54 8.46a5 5 0 0 1 0 7.07"></path>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 351 B |
BIN
qiming-noVNC/app/images/bg.jpg
Normal file
|
After Width: | Height: | Size: 368 KiB |
106
qiming-noVNC/app/images/clipboard.svg
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
<?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="clipboard.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="1"
|
||||||
|
inkscape:cx="15.366606"
|
||||||
|
inkscape:cy="16.42981"
|
||||||
|
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="opacity:1;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="M 9,6 6,6 C 5.4459889,6 5,6.4459889 5,7 l 0,13 c 0,0.554011 0.4459889,1 1,1 l 13,0 c 0.554011,0 1,-0.445989 1,-1 L 20,7 C 20,6.4459889 19.554011,6 19,6 l -3,0"
|
||||||
|
transform="translate(0,1027.3622)"
|
||||||
|
id="rect6083"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cssssssssc" />
|
||||||
|
<rect
|
||||||
|
style="opacity:1;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
id="rect6085"
|
||||||
|
width="7"
|
||||||
|
height="4"
|
||||||
|
x="9"
|
||||||
|
y="1031.3622"
|
||||||
|
ry="1.00002" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.50196081"
|
||||||
|
d="m 8.5071212,1038.8622 7.9999998,0"
|
||||||
|
id="path6087"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.50196081"
|
||||||
|
d="m 8.5071212,1041.8622 3.9999998,0"
|
||||||
|
id="path6089"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.50196081"
|
||||||
|
d="m 8.5071212,1044.8622 5.9999998,0"
|
||||||
|
id="path6091"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.9 KiB |
96
qiming-noVNC/app/images/connect.svg
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
<?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="connect.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="1"
|
||||||
|
inkscape:cx="37.14834"
|
||||||
|
inkscape:cy="1.9525926"
|
||||||
|
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: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)">
|
||||||
|
<g
|
||||||
|
id="g5103"
|
||||||
|
transform="matrix(0.70710678,-0.70710678,0.70710678,0.70710678,-729.15757,315.8823)">
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cssssc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="rect5096"
|
||||||
|
d="m 11,1040.3622 -5,0 c -1.108,0 -2,-0.892 -2,-2 l 0,-4 c 0,-1.108 0.892,-2 2,-2 l 5,0"
|
||||||
|
style="opacity:1;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="m 14,1032.3622 5,0 c 1.108,0 2,0.892 2,2 l 0,4 c 0,1.108 -0.892,2 -2,2 l -5,0"
|
||||||
|
id="path5099"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cssssc" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path5101"
|
||||||
|
d="m 9,1036.3622 7,0"
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.3 KiB |
96
qiming-noVNC/app/images/ctrl.svg
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
<?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="ctrl.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="18.205425"
|
||||||
|
inkscape:cy="17.531398"
|
||||||
|
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)">
|
||||||
|
<g
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:48px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'Sans Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
id="text5290">
|
||||||
|
<path
|
||||||
|
d="m 9.1210938,1043.1898 q -0.5175782,0.2686 -1.0791016,0.4053 -0.5615235,0.1367 -1.171875,0.1367 -1.8212891,0 -2.8857422,-1.0156 -1.0644531,-1.0205 -1.0644531,-2.7637 0,-1.748 1.0644531,-2.7637 1.0644531,-1.0205 2.8857422,-1.0205 0.6103515,0 1.171875,0.1368 0.5615234,0.1367 1.0791016,0.4052 l 0,1.5088 q -0.522461,-0.3564 -1.0302735,-0.5224 -0.5078125,-0.1661 -1.0693359,-0.1661 -1.0058594,0 -1.5820313,0.6446 -0.5761719,0.6445 -0.5761719,1.7773 0,1.1279 0.5761719,1.7725 0.5761719,0.6445 1.5820313,0.6445 0.5615234,0 1.0693359,-0.166 0.5078125,-0.166 1.0302735,-0.5225 l 0,1.5088 z"
|
||||||
|
style="font-size:10px;fill:#ffffff;fill-opacity:1"
|
||||||
|
id="path5370" />
|
||||||
|
<path
|
||||||
|
d="m 12.514648,1036.5687 0,1.5528 1.801758,0 0,1.25 -1.801758,0 0,2.3193 q 0,0.3809 0.151368,0.5176 0.151367,0.1318 0.600586,0.1318 l 0.898437,0 0,1.25 -1.499023,0 q -1.035157,0 -1.469727,-0.4297 -0.429687,-0.4345 -0.429687,-1.4697 l 0,-2.3193 -0.8691411,0 0,-1.25 0.8691411,0 0,-1.5528 1.748046,0 z"
|
||||||
|
style="font-size:10px;fill:#ffffff;fill-opacity:1"
|
||||||
|
id="path5372" />
|
||||||
|
<path
|
||||||
|
d="m 19.453125,1039.6107 q -0.229492,-0.1074 -0.458984,-0.1562 -0.22461,-0.054 -0.454102,-0.054 -0.673828,0 -1.040039,0.4345 -0.361328,0.4297 -0.361328,1.2354 l 0,2.5195 -1.748047,0 0,-5.4687 1.748047,0 0,0.8984 q 0.336914,-0.5371 0.771484,-0.7813 0.439453,-0.249 1.049805,-0.249 0.08789,0 0.19043,0.01 0.102539,0 0.297851,0.029 l 0.0049,1.582 z"
|
||||||
|
style="font-size:10px;fill:#ffffff;fill-opacity:1"
|
||||||
|
id="path5374" />
|
||||||
|
<path
|
||||||
|
d="m 20.332031,1035.9926 1.748047,0 0,7.5976 -1.748047,0 0,-7.5976 z"
|
||||||
|
style="font-size:10px;fill:#ffffff;fill-opacity:1"
|
||||||
|
id="path5376" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.3 KiB |
100
qiming-noVNC/app/images/ctrlaltdel.svg
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
<?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="ctrlaltdel.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="8"
|
||||||
|
inkscape:cx="11.135667"
|
||||||
|
inkscape:cy="16.407428"
|
||||||
|
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)">
|
||||||
|
<rect
|
||||||
|
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
id="rect5253"
|
||||||
|
width="5"
|
||||||
|
height="5.0000172"
|
||||||
|
x="16"
|
||||||
|
y="1031.3622"
|
||||||
|
ry="1.0000174" />
|
||||||
|
<rect
|
||||||
|
y="1043.3622"
|
||||||
|
x="4"
|
||||||
|
height="5.0000172"
|
||||||
|
width="5"
|
||||||
|
id="rect5255"
|
||||||
|
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
ry="1.0000174" />
|
||||||
|
<rect
|
||||||
|
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
id="rect5257"
|
||||||
|
width="5"
|
||||||
|
height="5.0000172"
|
||||||
|
x="13"
|
||||||
|
y="1043.3622"
|
||||||
|
ry="1.0000174" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.2 KiB |
94
qiming-noVNC/app/images/disconnect.svg
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
<?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="disconnect.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="25.05707"
|
||||||
|
inkscape:cy="11.594858"
|
||||||
|
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="false">
|
||||||
|
<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)">
|
||||||
|
<g
|
||||||
|
id="g5171"
|
||||||
|
transform="translate(-24.062499,-6.15775e-4)">
|
||||||
|
<path
|
||||||
|
id="path5110"
|
||||||
|
transform="translate(0,1027.3622)"
|
||||||
|
d="m 39.744141,3.4960938 c -0.769923,0 -1.539607,0.2915468 -2.121094,0.8730468 l -2.566406,2.5664063 1.414062,1.4140625 2.566406,-2.5664063 c 0.403974,-0.404 1.010089,-0.404 1.414063,0 l 2.828125,2.828125 c 0.40398,0.4039 0.403907,1.0101621 0,1.4140629 l -2.566406,2.566406 1.414062,1.414062 2.566406,-2.566406 c 1.163041,-1.1629 1.162968,-3.0791874 0,-4.2421874 L 41.865234,4.3691406 C 41.283747,3.7876406 40.514063,3.4960937 39.744141,3.4960938 Z M 39.017578,9.015625 a 1.0001,1.0001 0 0 0 -0.6875,0.3027344 l -0.445312,0.4453125 1.414062,1.4140621 0.445313,-0.445312 A 1.0001,1.0001 0 0 0 39.017578,9.015625 Z m -6.363281,0.7070312 a 1.0001,1.0001 0 0 0 -0.6875,0.3027348 L 28.431641,13.5625 c -1.163042,1.163 -1.16297,3.079187 0,4.242188 l 2.828125,2.828124 c 1.162974,1.163101 3.079213,1.163101 4.242187,0 l 3.535156,-3.535156 a 1.0001,1.0001 0 1 0 -1.414062,-1.414062 l -3.535156,3.535156 c -0.403974,0.404 -1.010089,0.404 -1.414063,0 l -2.828125,-2.828125 c -0.403981,-0.404 -0.403908,-1.010162 0,-1.414063 l 3.535156,-3.537109 A 1.0001,1.0001 0 0 0 32.654297,9.7226562 Z m 3.109375,2.1621098 -2.382813,2.384765 a 1.0001,1.0001 0 1 0 1.414063,1.414063 l 2.382812,-2.384766 -1.414062,-1.414062 z"
|
||||||
|
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"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<rect
|
||||||
|
transform="matrix(0.70710678,-0.70710678,0.70710678,0.70710678,0,0)"
|
||||||
|
y="752.29541"
|
||||||
|
x="-712.31262"
|
||||||
|
height="18.000017"
|
||||||
|
width="3"
|
||||||
|
id="rect5116"
|
||||||
|
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.9 KiB |
76
qiming-noVNC/app/images/drag.svg
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<?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="drag.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="22.627417"
|
||||||
|
inkscape:cx="9.8789407"
|
||||||
|
inkscape:cy="9.5008608"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
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="false"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1136"
|
||||||
|
inkscape:window-x="1920"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="1">
|
||||||
|
<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="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="m 7.039733,1049.3037 c -0.4309106,-0.1233 -0.7932634,-0.4631 -0.9705434,-0.9103 -0.04922,-0.1241 -0.057118,-0.2988 -0.071321,-1.5771 l -0.015972,-1.4375 -0.328125,-0.082 c -0.7668138,-0.1927 -1.1897046,-0.4275 -1.7031253,-0.9457 -0.4586773,-0.4629 -0.6804297,-0.8433 -0.867034,-1.4875 -0.067215,-0.232 -0.068001,-0.2642 -0.078682,-3.2188 -0.012078,-3.341 -0.020337,-3.2012 0.2099452,-3.5555 0.2246623,-0.3458 0.5798271,-0.5892 0.9667343,-0.6626 0.092506,-0.017 0.531898,-0.032 0.9764271,-0.032 l 0.8082347,0 1.157e-4,1.336 c 1.125e-4,1.2779 0.00281,1.3403 0.062214,1.4378 0.091785,0.1505 0.2357707,0.226 0.4314082,0.2261 0.285389,2e-4 0.454884,-0.1352 0.5058962,-0.4042 0.019355,-0.102 0.031616,-0.982 0.031616,-2.269 0,-1.9756 0.00357,-2.1138 0.059205,-2.2926 0.1645475,-0.5287 0.6307616,-0.9246 1.19078,-1.0113 0.8000572,-0.1238 1.5711277,0.4446 1.6860387,1.2429 0.01732,0.1203 0.03177,0.8248 0.03211,1.5657 6.19e-4,1.3449 7.22e-4,1.347 0.07093,1.4499 0.108355,0.1587 0.255268,0.2248 0.46917,0.2108 0.204069,-0.013 0.316116,-0.08 0.413642,-0.2453 0.06028,-0.1024 0.06307,-0.1778 0.07862,-2.1218 0.01462,-1.8283 0.02124,-2.0285 0.07121,-2.1549 0.260673,-0.659 0.934894,-1.0527 1.621129,-0.9465 0.640523,0.099 1.152269,0.6104 1.243187,1.2421 0.01827,0.1269 0.03175,0.9943 0.03211,2.0657 l 6.19e-4,1.8469 0.07031,0.103 c 0.108355,0.1587 0.255267,0.2248 0.46917,0.2108 0.204069,-0.013 0.316115,-0.08 0.413642,-0.2453 0.05951,-0.1011 0.06329,-0.1786 0.07907,-1.6218 0.01469,-1.3438 0.02277,-1.5314 0.07121,-1.6549 0.257975,-0.6576 0.934425,-1.0527 1.620676,-0.9465 0.640522,0.099 1.152269,0.6104 1.243186,1.2421 0.0186,0.1292 0.03179,1.0759 0.03222,2.3125 7.15e-4,2.0335 0.0025,2.0966 0.06283,2.1956 0.09178,0.1505 0.235771,0.226 0.431409,0.2261 0.285388,2e-4 0.454884,-0.1352 0.505897,-0.4042 0.01874,-0.099 0.03161,-0.8192 0.03161,-1.769 0,-1.4848 0.0043,-1.6163 0.0592,-1.7926 0.164548,-0.5287 0.630762,-0.9246 1.19078,-1.0113 0.800057,-0.1238 1.571128,0.4446 1.686039,1.2429 0.04318,0.2999 0.04372,9.1764 5.78e-4,9.4531 -0.04431,0.2841 -0.217814,0.6241 -0.420069,0.8232 -0.320102,0.315 -0.63307,0.4268 -1.194973,0.4268 l -0.35281,0 -2.51e-4,1.2734 c -1.25e-4,0.7046 -0.01439,1.3642 -0.03191,1.4766 -0.06665,0.4274 -0.372966,0.8704 -0.740031,1.0702 -0.349999,0.1905 0.01748,0.18 -6.242199,0.1776 -5.3622439,0 -5.7320152,-0.01 -5.9121592,-0.057 l 1.4e-5,0 z"
|
||||||
|
id="path4379"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.6 KiB |
81
qiming-noVNC/app/images/error.svg
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
<?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="error.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="1"
|
||||||
|
inkscape:cx="14.00357"
|
||||||
|
inkscape:cy="12.443398"
|
||||||
|
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 />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-1027.3622)">
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="M 7 3 C 4.7839905 3 3 4.7839905 3 7 L 3 18 C 3 20.21601 4.7839905 22 7 22 L 18 22 C 20.21601 22 22 20.21601 22 18 L 22 7 C 22 4.7839905 20.21601 3 18 3 L 7 3 z M 7.6992188 6 A 1.6916875 1.6924297 0 0 1 8.9121094 6.5117188 L 12.5 10.101562 L 16.087891 6.5117188 A 1.6916875 1.6924297 0 0 1 17.251953 6 A 1.6916875 1.6924297 0 0 1 18.480469 8.90625 L 14.892578 12.496094 L 18.480469 16.085938 A 1.6916875 1.6924297 0 1 1 16.087891 18.478516 L 12.5 14.888672 L 8.9121094 18.478516 A 1.6916875 1.6924297 0 1 1 6.5214844 16.085938 L 10.109375 12.496094 L 6.5214844 8.90625 A 1.6916875 1.6924297 0 0 1 7.6992188 6 z "
|
||||||
|
transform="translate(0,1027.3622)"
|
||||||
|
id="rect4135" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.0 KiB |
92
qiming-noVNC/app/images/esc.svg
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
<?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="esc.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="18.205425"
|
||||||
|
inkscape:cy="17.531398"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="text5290"
|
||||||
|
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)">
|
||||||
|
<g
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:48px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'Sans Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
id="text5290">
|
||||||
|
<path
|
||||||
|
d="m 3.9331055,1036.1464 5.0732422,0 0,1.4209 -3.1933594,0 0,1.3574 3.0029297,0 0,1.4209 -3.0029297,0 0,1.6699 3.3007812,0 0,1.4209 -5.180664,0 0,-7.29 z"
|
||||||
|
style="font-size:10px;fill:#ffffff;fill-opacity:1"
|
||||||
|
id="path5314" />
|
||||||
|
<path
|
||||||
|
d="m 14.963379,1038.1385 0,1.3282 q -0.561524,-0.2344 -1.083984,-0.3516 -0.522461,-0.1172 -0.986329,-0.1172 -0.498046,0 -0.742187,0.127 -0.239258,0.122 -0.239258,0.3808 0,0.21 0.180664,0.3223 0.185547,0.1123 0.65918,0.166 l 0.307617,0.044 q 1.342773,0.1709 1.806641,0.5615 0.463867,0.3906 0.463867,1.2256 0,0.874 -0.644531,1.3134 -0.644532,0.4395 -1.923829,0.4395 -0.541992,0 -1.123046,-0.088 -0.576172,-0.083 -1.186524,-0.2539 l 0,-1.3281 q 0.522461,0.2539 1.069336,0.3808 0.551758,0.127 1.118164,0.127 0.512695,0 0.771485,-0.1416 0.258789,-0.1416 0.258789,-0.4199 0,-0.2344 -0.180664,-0.3467 -0.175782,-0.1172 -0.708008,-0.1807 l -0.307617,-0.039 q -1.166993,-0.1465 -1.635743,-0.542 -0.46875,-0.3955 -0.46875,-1.2012 0,-0.8691 0.595703,-1.2891 0.595704,-0.4199 1.826172,-0.4199 0.483399,0 1.015625,0.073 0.532227,0.073 1.157227,0.2294 z"
|
||||||
|
style="font-size:10px;fill:#ffffff;fill-opacity:1"
|
||||||
|
id="path5316" />
|
||||||
|
<path
|
||||||
|
d="m 21.066895,1038.1385 0,1.4258 q -0.356446,-0.2441 -0.717774,-0.3613 -0.356445,-0.1172 -0.742187,-0.1172 -0.732422,0 -1.142579,0.4297 -0.405273,0.4248 -0.405273,1.1914 0,0.7666 0.405273,1.1963 0.410157,0.4248 1.142579,0.4248 0.410156,0 0.776367,-0.1221 0.371094,-0.122 0.683594,-0.3613 l 0,1.4307 q -0.410157,0.1513 -0.834961,0.2246 -0.419922,0.078 -0.844727,0.078 -1.479492,0 -2.314453,-0.7568 -0.834961,-0.7618 -0.834961,-2.1143 0,-1.3525 0.834961,-2.1094 0.834961,-0.7617 2.314453,-0.7617 0.429688,0 0.844727,0.078 0.419921,0.073 0.834961,0.2246 z"
|
||||||
|
style="font-size:10px;fill:#ffffff;fill-opacity:1"
|
||||||
|
id="path5318" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.4 KiB |
69
qiming-noVNC/app/images/expander.svg
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
<?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="9"
|
||||||
|
height="10"
|
||||||
|
viewBox="0 0 9 10"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="expander.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="45.254834"
|
||||||
|
inkscape:cx="9.8737281"
|
||||||
|
inkscape:cy="6.4583132"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:snap-object-midpoints="false"
|
||||||
|
inkscape:object-nodes="true"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1136"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="1">
|
||||||
|
<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,-1042.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:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:4;stroke-linecap:butt;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 2.0800781,1042.3633 A 2.0002,2.0002 0 0 0 0,1044.3613 l 0,6 a 2.0002,2.0002 0 0 0 3.0292969,1.7168 l 5,-3 a 2.0002,2.0002 0 0 0 0,-3.4316 l -5,-3 a 2.0002,2.0002 0 0 0 -0.9492188,-0.2832 z"
|
||||||
|
id="path4138"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.0 KiB |
93
qiming-noVNC/app/images/fullscreen.svg
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
<?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="fullscreen.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="1"
|
||||||
|
inkscape:cx="16.400723"
|
||||||
|
inkscape:cy="15.083758"
|
||||||
|
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="false"
|
||||||
|
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="false">
|
||||||
|
<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)">
|
||||||
|
<rect
|
||||||
|
style="opacity:1;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
id="rect5006"
|
||||||
|
width="17"
|
||||||
|
height="17.000017"
|
||||||
|
x="4"
|
||||||
|
y="1031.3622"
|
||||||
|
ry="3.0000174" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
|
||||||
|
d="m 7.5,1044.8622 4,0 -1.5,-1.5 1.5,-1.5 -1,-1 -1.5,1.5 -1.5,-1.5 0,4 z"
|
||||||
|
id="path5017"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path5025"
|
||||||
|
d="m 17.5,1034.8622 -4,0 1.5,1.5 -1.5,1.5 1,1 1.5,-1.5 1.5,1.5 0,-4 z"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.1 KiB |
82
qiming-noVNC/app/images/handle.svg
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<?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="5"
|
||||||
|
height="6"
|
||||||
|
viewBox="0 0 5 6"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="handle.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="32"
|
||||||
|
inkscape:cx="1.3551778"
|
||||||
|
inkscape:cy="8.7800329"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
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="false"
|
||||||
|
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,-1046.3622)">
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 4.0000803,1049.3622 -3,-2 0,4 z"
|
||||||
|
id="path4247"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.5 KiB |
172
qiming-noVNC/app/images/handle_bg.svg
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
<?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="15"
|
||||||
|
height="50"
|
||||||
|
viewBox="0 0 15 50"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="handle_bg.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="-10.001409"
|
||||||
|
inkscape:cy="24.512566"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
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="false"
|
||||||
|
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,-1002.3622)">
|
||||||
|
<rect
|
||||||
|
style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
id="rect4249"
|
||||||
|
width="1"
|
||||||
|
height="1.0000174"
|
||||||
|
x="9.5"
|
||||||
|
y="1008.8622"
|
||||||
|
ry="1.7382812e-05" />
|
||||||
|
<rect
|
||||||
|
ry="1.7382812e-05"
|
||||||
|
y="1013.8622"
|
||||||
|
x="9.5"
|
||||||
|
height="1.0000174"
|
||||||
|
width="1"
|
||||||
|
id="rect4255"
|
||||||
|
style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||||
|
<rect
|
||||||
|
ry="1.7382812e-05"
|
||||||
|
y="1008.8622"
|
||||||
|
x="4.5"
|
||||||
|
height="1.0000174"
|
||||||
|
width="1"
|
||||||
|
id="rect4261"
|
||||||
|
style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||||
|
<rect
|
||||||
|
style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
id="rect4263"
|
||||||
|
width="1"
|
||||||
|
height="1.0000174"
|
||||||
|
x="4.5"
|
||||||
|
y="1013.8622"
|
||||||
|
ry="1.7382812e-05" />
|
||||||
|
<rect
|
||||||
|
ry="1.7382812e-05"
|
||||||
|
y="1039.8622"
|
||||||
|
x="9.5"
|
||||||
|
height="1.0000174"
|
||||||
|
width="1"
|
||||||
|
id="rect4265"
|
||||||
|
style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||||
|
<rect
|
||||||
|
style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
id="rect4267"
|
||||||
|
width="1"
|
||||||
|
height="1.0000174"
|
||||||
|
x="9.5"
|
||||||
|
y="1044.8622"
|
||||||
|
ry="1.7382812e-05" />
|
||||||
|
<rect
|
||||||
|
style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
id="rect4269"
|
||||||
|
width="1"
|
||||||
|
height="1.0000174"
|
||||||
|
x="4.5"
|
||||||
|
y="1039.8622"
|
||||||
|
ry="1.7382812e-05" />
|
||||||
|
<rect
|
||||||
|
ry="1.7382812e-05"
|
||||||
|
y="1044.8622"
|
||||||
|
x="4.5"
|
||||||
|
height="1.0000174"
|
||||||
|
width="1"
|
||||||
|
id="rect4271"
|
||||||
|
style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||||
|
<rect
|
||||||
|
style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
id="rect4273"
|
||||||
|
width="1"
|
||||||
|
height="1.0000174"
|
||||||
|
x="9.5"
|
||||||
|
y="1018.8622"
|
||||||
|
ry="1.7382812e-05" />
|
||||||
|
<rect
|
||||||
|
ry="1.7382812e-05"
|
||||||
|
y="1018.8622"
|
||||||
|
x="4.5"
|
||||||
|
height="1.0000174"
|
||||||
|
width="1"
|
||||||
|
id="rect4275"
|
||||||
|
style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||||
|
<rect
|
||||||
|
style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
id="rect4277"
|
||||||
|
width="1"
|
||||||
|
height="1.0000174"
|
||||||
|
x="9.5"
|
||||||
|
y="1034.8622"
|
||||||
|
ry="1.7382812e-05" />
|
||||||
|
<rect
|
||||||
|
ry="1.7382812e-05"
|
||||||
|
y="1034.8622"
|
||||||
|
x="4.5"
|
||||||
|
height="1.0000174"
|
||||||
|
width="1"
|
||||||
|
id="rect4279"
|
||||||
|
style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 6.2 KiB |
42
qiming-noVNC/app/images/icons/Makefile
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
BROWSER_SIZES := 16 24 32 48 64
|
||||||
|
#ANDROID_SIZES := 72 96 144 192
|
||||||
|
# FIXME: The ICO is limited to 8 icons due to a Chrome bug:
|
||||||
|
# https://bugs.chromium.org/p/chromium/issues/detail?id=1381393
|
||||||
|
ANDROID_SIZES := 96 144 192
|
||||||
|
WEB_ICON_SIZES := $(BROWSER_SIZES) $(ANDROID_SIZES)
|
||||||
|
|
||||||
|
#IOS_1X_SIZES := 20 29 40 76 # No such devices exist anymore
|
||||||
|
IOS_2X_SIZES := 40 58 80 120 152 167
|
||||||
|
IOS_3X_SIZES := 60 87 120 180
|
||||||
|
ALL_IOS_SIZES := $(IOS_1X_SIZES) $(IOS_2X_SIZES) $(IOS_3X_SIZES)
|
||||||
|
|
||||||
|
ALL_ICONS := \
|
||||||
|
$(ALL_IOS_SIZES:%=novnc-ios-%.png) \
|
||||||
|
novnc.ico
|
||||||
|
|
||||||
|
all: $(ALL_ICONS)
|
||||||
|
|
||||||
|
# Our testing shows that the ICO file need to be sorted in largest to
|
||||||
|
# smallest to get the apporpriate behviour
|
||||||
|
WEB_ICON_SIZES_REVERSE := $(shell echo $(WEB_ICON_SIZES) | tr ' ' '\n' | sort -nr | tr '\n' ' ')
|
||||||
|
WEB_BASE_ICONS := $(WEB_ICON_SIZES_REVERSE:%=novnc-%.png)
|
||||||
|
.INTERMEDIATE: $(WEB_BASE_ICONS)
|
||||||
|
|
||||||
|
novnc.ico: $(WEB_BASE_ICONS)
|
||||||
|
convert $(WEB_BASE_ICONS) "$@"
|
||||||
|
|
||||||
|
# General conversion
|
||||||
|
novnc-%.png: novnc-icon.svg
|
||||||
|
convert -depth 8 -background transparent \
|
||||||
|
-size $*x$* "$(lastword $^)" "$@"
|
||||||
|
|
||||||
|
# iOS icons use their own SVG
|
||||||
|
novnc-ios-%.png: novnc-ios-icon.svg
|
||||||
|
convert -depth 8 -background transparent \
|
||||||
|
-size $*x$* "$(lastword $^)" "$@"
|
||||||
|
|
||||||
|
# The smallest sizes are generated using a different SVG
|
||||||
|
novnc-16.png novnc-24.png novnc-32.png: novnc-icon-sm.svg
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.png
|
||||||
BIN
qiming-noVNC/app/images/icons/fav.ico
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
163
qiming-noVNC/app/images/icons/novnc-icon-sm.svg
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
<?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="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="novnc-icon-sm.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="45.254834"
|
||||||
|
inkscape:cx="9.722703"
|
||||||
|
inkscape:cy="5.5311896"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
inkscape:object-nodes="true"
|
||||||
|
inkscape:snap-smooth-nodes="true"
|
||||||
|
inkscape:snap-midpoints="true"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1136"
|
||||||
|
inkscape:window-x="1920"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="1">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4169" />
|
||||||
|
</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,-1036.3621)">
|
||||||
|
<rect
|
||||||
|
style="opacity:1;fill:#494949;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
id="rect4167"
|
||||||
|
width="16"
|
||||||
|
height="15.999992"
|
||||||
|
x="0"
|
||||||
|
y="1036.3622"
|
||||||
|
ry="2.6666584" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#313131;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="M 2.6666667,1036.3621 C 1.1893373,1036.3621 0,1037.5515 0,1039.0288 l 0,10.6666 c 0,1.4774 1.1893373,2.6667 2.6666667,2.6667 l 4,0 C 11.837333,1052.3621 16,1046.7128 16,1039.6955 l 0,-0.6667 c 0,-1.4773 -1.189337,-2.6667 -2.666667,-2.6667 l -10.6666663,0 z"
|
||||||
|
id="rect4173"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<g
|
||||||
|
id="g4381">
|
||||||
|
<g
|
||||||
|
transform="translate(0.25,0.25)"
|
||||||
|
style="fill:#000000;fill-opacity:1"
|
||||||
|
id="g4365">
|
||||||
|
<g
|
||||||
|
style="fill:#000000;fill-opacity:1"
|
||||||
|
id="g4367">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4369"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 4.3289754,1039.3621 c 0.1846149,0 0.3419956,0.071 0.4716623,0.2121 C 4.933546,1039.7121 5,1039.8793 5,1040.0759 l 0,3.2862 -1,0 0,-2.964 c 0,-0.024 -0.011592,-0.036 -0.034038,-0.036 l -1.931924,0 C 2.011349,1040.3621 2,1040.3741 2,1040.3981 l 0,2.964 -1,0 0,-4 z"
|
||||||
|
sodipodi:nodetypes="scsccsssscccs" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4371"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 6.6710244,1039.3621 2.6579513,0 c 0.184775,0 0.3419957,0.071 0.471662,0.2121 C 9.933546,1039.7121 10,1039.8793 10,1040.0759 l 0,2.5724 c 0,0.1966 -0.066454,0.3655 -0.1993623,0.5069 -0.1296663,0.1379 -0.286887,0.2069 -0.471662,0.2069 l -2.6579513,0 c -0.184775,0 -0.3436164,-0.069 -0.4765247,-0.2069 C 6.0648334,1043.0138 6,1042.8449 6,1042.6483 l 0,-2.5724 c 0,-0.1966 0.064833,-0.3638 0.1944997,-0.5017 0.1329083,-0.1414 0.2917497,-0.2121 0.4765247,-0.2121 z m 2.2949386,1 -1.931926,0 C 7.011344,1040.3621 7,1040.3741 7,1040.3981 l 0,1.928 c 0,0.024 0.011347,0.036 0.034037,0.036 l 1.931926,0 c 0.02269,0 0.034037,-0.012 0.034037,-0.036 l 0,-1.928 c 0,-0.024 -0.011347,-0.036 -0.034037,-0.036 z"
|
||||||
|
sodipodi:nodetypes="sscsscsscsscssssssssss" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
style="fill:#000000;fill-opacity:1"
|
||||||
|
id="g4373">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4375"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 3,1047.1121 1,-2.75 1,0 -1.5,4 -1,0 -1.5,-4 1,0 z"
|
||||||
|
sodipodi:nodetypes="cccccccc" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4377"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 9,1046.8621 0,-2.5 1,0 0,4 -1,0 -2,-2.5 0,2.5 -1,0 0,-4 1,0 z"
|
||||||
|
sodipodi:nodetypes="ccccccccccc" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4379"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 15,1045.3621 -2.96596,0 c -0.02269,0 -0.03404,0.012 -0.03404,0.036 l 0,1.928 c 0,0.024 0.01135,0.036 0.03404,0.036 l 2.96596,0 0,1 -3.324113,0 c -0.188017,0 -0.348479,-0.068 -0.481388,-0.2037 C 11.064833,1048.0192 11,1047.8511 11,1047.6542 l 0,-2.5842 c 0,-0.1969 0.06483,-0.3633 0.194499,-0.4991 0.132909,-0.1392 0.293371,-0.2088 0.481388,-0.2088 l 3.324113,0 z"
|
||||||
|
sodipodi:nodetypes="cssssccscsscscc" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g4356">
|
||||||
|
<g
|
||||||
|
id="g4347">
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="scsccsssscccs"
|
||||||
|
d="m 4.3289754,1039.3621 c 0.1846149,0 0.3419956,0.071 0.4716623,0.2121 C 4.933546,1039.7121 5,1039.8793 5,1040.0759 l 0,3.2862 -1,0 0,-2.964 c 0,-0.024 -0.011592,-0.036 -0.034038,-0.036 l -1.931924,0 c -0.022689,0 -0.034038,0.012 -0.034038,0.036 l 0,2.964 -1,0 0,-4 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#008000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
id="path4143"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="sscsscsscsscssssssssss"
|
||||||
|
d="m 6.6710244,1039.3621 2.6579513,0 c 0.184775,0 0.3419957,0.071 0.471662,0.2121 C 9.933546,1039.7121 10,1039.8793 10,1040.0759 l 0,2.5724 c 0,0.1966 -0.066454,0.3655 -0.1993623,0.5069 -0.1296663,0.1379 -0.286887,0.2069 -0.471662,0.2069 l -2.6579513,0 c -0.184775,0 -0.3436164,-0.069 -0.4765247,-0.2069 C 6.0648334,1043.0138 6,1042.8449 6,1042.6483 l 0,-2.5724 c 0,-0.1966 0.064833,-0.3638 0.1944997,-0.5017 0.1329083,-0.1414 0.2917497,-0.2121 0.4765247,-0.2121 z m 2.2949386,1 -1.931926,0 C 7.011344,1040.3621 7,1040.3741 7,1040.3981 l 0,1.928 c 0,0.024 0.011347,0.036 0.034037,0.036 l 1.931926,0 c 0.02269,0 0.034037,-0.012 0.034037,-0.036 l 0,-1.928 c 0,-0.024 -0.011347,-0.036 -0.034037,-0.036 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#008000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
id="path4145"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g4351">
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cccccccc"
|
||||||
|
d="m 3,1047.1121 1,-2.75 1,0 -1.5,4 -1,0 -1.5,-4 1,0 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
id="path4147"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccccccccc"
|
||||||
|
d="m 9,1046.8621 0,-2.5 1,0 0,4 -1,0 -2,-2.5 0,2.5 -1,0 0,-4 1,0 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
id="path4149"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cssssccscsscscc"
|
||||||
|
d="m 15,1045.3621 -2.96596,0 c -0.02269,0 -0.03404,0.012 -0.03404,0.036 l 0,1.928 c 0,0.024 0.01135,0.036 0.03404,0.036 l 2.96596,0 0,1 -3.324113,0 c -0.188017,0 -0.348479,-0.068 -0.481388,-0.2037 C 11.064833,1048.0192 11,1047.8511 11,1047.6542 l 0,-2.5842 c 0,-0.1969 0.06483,-0.3633 0.194499,-0.4991 0.132909,-0.1392 0.293371,-0.2088 0.481388,-0.2088 l 3.324113,0 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
id="path4151"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 11 KiB |
163
qiming-noVNC/app/images/icons/novnc-icon.svg
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
<?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="48"
|
||||||
|
height="48"
|
||||||
|
viewBox="0 0 48 48.000001"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="novnc-icon.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="11.313708"
|
||||||
|
inkscape:cx="27.187245"
|
||||||
|
inkscape:cy="17.700974"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
inkscape:object-nodes="true"
|
||||||
|
inkscape:snap-smooth-nodes="true"
|
||||||
|
inkscape:snap-midpoints="true"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1136"
|
||||||
|
inkscape:window-x="1920"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="1">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4169" />
|
||||||
|
</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 />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-1004.3621)">
|
||||||
|
<rect
|
||||||
|
style="opacity:1;fill:#494949;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
id="rect4167"
|
||||||
|
width="48"
|
||||||
|
height="48"
|
||||||
|
x="0"
|
||||||
|
y="1004.3621"
|
||||||
|
ry="7.9999785" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#313131;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="m 8,1004.3621 c -4.4319881,0 -8,3.568 -8,8 l 0,32 c 0,4.432 3.5680119,8 8,8 l 12,0 c 15.512,0 28,-16.948 28,-38 l 0,-2 c 0,-4.432 -3.568012,-8 -8,-8 l -32,0 z"
|
||||||
|
id="rect4173"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<g
|
||||||
|
id="g4300"
|
||||||
|
style="fill:#000000;fill-opacity:1;stroke:none"
|
||||||
|
transform="translate(0.5,0.5)">
|
||||||
|
<g
|
||||||
|
id="g4302"
|
||||||
|
style="fill:#000000;fill-opacity:1;stroke:none">
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="scsccsssscccs"
|
||||||
|
d="m 11.986926,1016.3621 c 0.554325,0 1.025987,0.2121 1.414987,0.6362 0.398725,0.4138 0.600909,0.9155 0.598087,1.5052 l 0,6.8586 -2,0 0,-6.8914 c 0,-0.072 -0.03404,-0.1086 -0.102113,-0.1086 l -4.7957745,0 C 7.0340375,1018.3621 7,1018.3983 7,1018.4707 l 0,6.8914 -2,0 0,-9 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
id="path4304"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="sscsscsscsscssssssssss"
|
||||||
|
d="m 17.013073,1016.3621 4.973854,0 c 0.554325,0 1.025987,0.2121 1.414986,0.6362 0.398725,0.4138 0.598087,0.9155 0.598087,1.5052 l 0,4.7172 c 0,0.5897 -0.199362,1.0966 -0.598087,1.5207 -0.388999,0.4138 -0.860661,0.6207 -1.414986,0.6207 l -4.973854,0 c -0.554325,0 -1.030849,-0.2069 -1.429574,-0.6207 C 15.1945,1024.3173 15,1023.8104 15,1023.2207 l 0,-4.7172 c 0,-0.5897 0.1945,-1.0914 0.583499,-1.5052 0.398725,-0.4241 0.875249,-0.6362 1.429574,-0.6362 z m 4.884815,2 -4.795776,0 c -0.06808,0 -0.102112,0.036 -0.102112,0.1086 l 0,4.7828 c 0,0.072 0.03404,0.1086 0.102112,0.1086 l 4.795776,0 c 0.06807,0 0.102112,-0.036 0.102112,-0.1086 l 0,-4.7828 c 0,-0.072 -0.03404,-0.1086 -0.102112,-0.1086 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
id="path4306"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g4308"
|
||||||
|
style="fill:#000000;fill-opacity:1;stroke:none">
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cccccccc"
|
||||||
|
d="m 12,1036.9177 4.768114,-8.5556 2.231886,0 -6,11 -2,0 -6,-11 2.2318854,0 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
id="path4310"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccccccccc"
|
||||||
|
d="m 29,1036.3621 0,-8 2,0 0,11 -2,0 -7,-8 0,8 -2,0 0,-11 2,0 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
id="path4312"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cssssccscsscscc"
|
||||||
|
d="m 43,1030.3621 -8.897887,0 c -0.06808,0 -0.102113,0.036 -0.102113,0.1069 l 0,6.7862 c 0,0.071 0.03404,0.1069 0.102113,0.1069 l 8.897887,0 0,2 -8.972339,0 c -0.56405,0 -1.045437,-0.2037 -1.444162,-0.6111 C 32.1945,1038.3334 32,1037.8292 32,1037.2385 l 0,-6.7528 c 0,-0.5907 0.1945,-1.0898 0.583499,-1.4972 0.398725,-0.4176 0.880112,-0.6264 1.444162,-0.6264 l 8.972339,0 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
id="path4314"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g4291"
|
||||||
|
style="stroke:none">
|
||||||
|
<g
|
||||||
|
id="g4282"
|
||||||
|
style="stroke:none">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4143"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#008000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 11.986926,1016.3621 c 0.554325,0 1.025987,0.2121 1.414987,0.6362 0.398725,0.4138 0.600909,0.9155 0.598087,1.5052 l 0,6.8586 -2,0 0,-6.8914 c 0,-0.072 -0.03404,-0.1086 -0.102113,-0.1086 l -4.7957745,0 C 7.0340375,1018.3621 7,1018.3983 7,1018.4707 l 0,6.8914 -2,0 0,-9 z"
|
||||||
|
sodipodi:nodetypes="scsccsssscccs" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4145"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#008000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 17.013073,1016.3621 4.973854,0 c 0.554325,0 1.025987,0.2121 1.414986,0.6362 0.398725,0.4138 0.598087,0.9155 0.598087,1.5052 l 0,4.7172 c 0,0.5897 -0.199362,1.0966 -0.598087,1.5207 -0.388999,0.4138 -0.860661,0.6207 -1.414986,0.6207 l -4.973854,0 c -0.554325,0 -1.030849,-0.2069 -1.429574,-0.6207 C 15.1945,1024.3173 15,1023.8104 15,1023.2207 l 0,-4.7172 c 0,-0.5897 0.1945,-1.0914 0.583499,-1.5052 0.398725,-0.4241 0.875249,-0.6362 1.429574,-0.6362 z m 4.884815,2 -4.795776,0 c -0.06808,0 -0.102112,0.036 -0.102112,0.1086 l 0,4.7828 c 0,0.072 0.03404,0.1086 0.102112,0.1086 l 4.795776,0 c 0.06807,0 0.102112,-0.036 0.102112,-0.1086 l 0,-4.7828 c 0,-0.072 -0.03404,-0.1086 -0.102112,-0.1086 z"
|
||||||
|
sodipodi:nodetypes="sscsscsscsscssssssssss" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g4286"
|
||||||
|
style="stroke:none">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4147"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 12,1036.9177 4.768114,-8.5556 2.231886,0 -6,11 -2,0 -6,-11 2.2318854,0 z"
|
||||||
|
sodipodi:nodetypes="cccccccc" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4149"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 29,1036.3621 0,-8 2,0 0,11 -2,0 -7,-8 0,8 -2,0 0,-11 2,0 z"
|
||||||
|
sodipodi:nodetypes="ccccccccccc" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4151"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 43,1030.3621 -8.897887,0 c -0.06808,0 -0.102113,0.036 -0.102113,0.1069 l 0,6.7862 c 0,0.071 0.03404,0.1069 0.102113,0.1069 l 8.897887,0 0,2 -8.972339,0 c -0.56405,0 -1.045437,-0.2037 -1.444162,-0.6111 C 32.1945,1038.3334 32,1037.8292 32,1037.2385 l 0,-6.7528 c 0,-0.5907 0.1945,-1.0898 0.583499,-1.4972 0.398725,-0.4176 0.880112,-0.6264 1.444162,-0.6264 l 8.972339,0 z"
|
||||||
|
sodipodi:nodetypes="cssssccscsscscc" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 11 KiB |
BIN
qiming-noVNC/app/images/icons/novnc-ios-120.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
qiming-noVNC/app/images/icons/novnc-ios-152.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
qiming-noVNC/app/images/icons/novnc-ios-167.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
qiming-noVNC/app/images/icons/novnc-ios-180.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
qiming-noVNC/app/images/icons/novnc-ios-40.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
qiming-noVNC/app/images/icons/novnc-ios-58.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
qiming-noVNC/app/images/icons/novnc-ios-60.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
qiming-noVNC/app/images/icons/novnc-ios-80.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
qiming-noVNC/app/images/icons/novnc-ios-87.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
183
qiming-noVNC/app/images/icons/novnc-ios-icon.svg
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="48"
|
||||||
|
height="48"
|
||||||
|
viewBox="0 0 48 48.000001"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
||||||
|
sodipodi:docname="novnc-ios-icon.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="11.313708"
|
||||||
|
inkscape:cx="27.356195"
|
||||||
|
inkscape:cy="17.810253"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
inkscape:object-nodes="true"
|
||||||
|
inkscape:snap-smooth-nodes="true"
|
||||||
|
inkscape:snap-midpoints="true"
|
||||||
|
inkscape:window-width="2560"
|
||||||
|
inkscape:window-height="1371"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid4169" />
|
||||||
|
</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" />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-1004.3621)">
|
||||||
|
<rect
|
||||||
|
style="opacity:1;fill:#494949;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
id="rect4167"
|
||||||
|
width="48"
|
||||||
|
height="48"
|
||||||
|
x="0"
|
||||||
|
y="1004.3621"
|
||||||
|
inkscape:label="background" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#313131;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="m 0,1004.3621 v 48 h 20 c 15.512,0 28,-16.948 28,-38 v -10 z"
|
||||||
|
id="rect4173"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccccc"
|
||||||
|
inkscape:label="darker_grey_plate" />
|
||||||
|
<g
|
||||||
|
id="g4300"
|
||||||
|
style="display:inline;fill:#000000;fill-opacity:1;stroke:none"
|
||||||
|
transform="translate(0.5,0.5)"
|
||||||
|
inkscape:label="shadows">
|
||||||
|
<g
|
||||||
|
id="g4302"
|
||||||
|
style="fill:#000000;fill-opacity:1;stroke:none"
|
||||||
|
inkscape:label="no">
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="scsccsssscccs"
|
||||||
|
d="m 11.986926,1016.3621 c 0.554325,0 1.025987,0.2121 1.414987,0.6362 0.398725,0.4138 0.600909,0.9155 0.598087,1.5052 v 6.8586 h -2 v -6.8914 c 0,-0.072 -0.03404,-0.1086 -0.102113,-0.1086 H 7.1021125 C 7.0340375,1018.3621 7,1018.3983 7,1018.4707 v 6.8914 H 5 v -9 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
id="path4304"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:label="n" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="sscsscsscsscssssssssss"
|
||||||
|
d="m 17.013073,1016.3621 h 4.973854 c 0.554325,0 1.025987,0.2121 1.414986,0.6362 0.398725,0.4138 0.598087,0.9155 0.598087,1.5052 v 4.7172 c 0,0.5897 -0.199362,1.0966 -0.598087,1.5207 -0.388999,0.4138 -0.860661,0.6207 -1.414986,0.6207 h -4.973854 c -0.554325,0 -1.030849,-0.2069 -1.429574,-0.6207 C 15.1945,1024.3173 15,1023.8104 15,1023.2207 v -4.7172 c 0,-0.5897 0.1945,-1.0914 0.583499,-1.5052 0.398725,-0.4241 0.875249,-0.6362 1.429574,-0.6362 z m 4.884815,2 h -4.795776 c -0.06808,0 -0.102112,0.036 -0.102112,0.1086 v 4.7828 c 0,0.072 0.03404,0.1086 0.102112,0.1086 h 4.795776 c 0.06807,0 0.102112,-0.036 0.102112,-0.1086 v -4.7828 c 0,-0.072 -0.03404,-0.1086 -0.102112,-0.1086 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
id="path4306"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:label="o" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g4308"
|
||||||
|
style="fill:#000000;fill-opacity:1;stroke:none"
|
||||||
|
inkscape:label="VNC">
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cccccccc"
|
||||||
|
d="m 12,1036.9177 4.768114,-8.5556 H 19 l -6,11 h -2 l -6,-11 h 2.2318854 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
id="path4310"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:label="V" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="ccccccccccc"
|
||||||
|
d="m 29,1036.3621 v -8 h 2 v 11 h -2 l -7,-8 v 8 h -2 v -11 h 2 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
id="path4312"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:label="N" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cssssccscsscscc"
|
||||||
|
d="m 43,1030.3621 h -8.897887 c -0.06808,0 -0.102113,0.036 -0.102113,0.1069 v 6.7862 c 0,0.071 0.03404,0.1069 0.102113,0.1069 H 43 v 2 h -8.972339 c -0.56405,0 -1.045437,-0.2037 -1.444162,-0.6111 C 32.1945,1038.3334 32,1037.8292 32,1037.2385 v -6.7528 c 0,-0.5907 0.1945,-1.0898 0.583499,-1.4972 0.398725,-0.4176 0.880112,-0.6264 1.444162,-0.6264 H 43 Z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
id="path4314"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:label="C" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g4291"
|
||||||
|
style="stroke:none"
|
||||||
|
inkscape:label="noVNC">
|
||||||
|
<g
|
||||||
|
id="g4282"
|
||||||
|
style="stroke:none"
|
||||||
|
inkscape:label="no">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4143"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#008000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 11.986926,1016.3621 c 0.554325,0 1.025987,0.2121 1.414987,0.6362 0.398725,0.4138 0.600909,0.9155 0.598087,1.5052 l 0,6.8586 -2,0 0,-6.8914 c 0,-0.072 -0.03404,-0.1086 -0.102113,-0.1086 l -4.7957745,0 C 7.0340375,1018.3621 7,1018.3983 7,1018.4707 l 0,6.8914 -2,0 0,-9 z"
|
||||||
|
sodipodi:nodetypes="scsccsssscccs"
|
||||||
|
inkscape:label="n" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4145"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#008000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 17.013073,1016.3621 4.973854,0 c 0.554325,0 1.025987,0.2121 1.414986,0.6362 0.398725,0.4138 0.598087,0.9155 0.598087,1.5052 l 0,4.7172 c 0,0.5897 -0.199362,1.0966 -0.598087,1.5207 -0.388999,0.4138 -0.860661,0.6207 -1.414986,0.6207 l -4.973854,0 c -0.554325,0 -1.030849,-0.2069 -1.429574,-0.6207 C 15.1945,1024.3173 15,1023.8104 15,1023.2207 l 0,-4.7172 c 0,-0.5897 0.1945,-1.0914 0.583499,-1.5052 0.398725,-0.4241 0.875249,-0.6362 1.429574,-0.6362 z m 4.884815,2 -4.795776,0 c -0.06808,0 -0.102112,0.036 -0.102112,0.1086 l 0,4.7828 c 0,0.072 0.03404,0.1086 0.102112,0.1086 l 4.795776,0 c 0.06807,0 0.102112,-0.036 0.102112,-0.1086 l 0,-4.7828 c 0,-0.072 -0.03404,-0.1086 -0.102112,-0.1086 z"
|
||||||
|
sodipodi:nodetypes="sscsscsscsscssssssssss"
|
||||||
|
inkscape:label="o" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g4286"
|
||||||
|
style="stroke:none"
|
||||||
|
inkscape:label="VNC">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4147"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 12,1036.9177 4.768114,-8.5556 2.231886,0 -6,11 -2,0 -6,-11 2.2318854,0 z"
|
||||||
|
sodipodi:nodetypes="cccccccc"
|
||||||
|
inkscape:label="V" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4149"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 29,1036.3621 0,-8 2,0 0,11 -2,0 -7,-8 0,8 -2,0 0,-11 2,0 z"
|
||||||
|
sodipodi:nodetypes="ccccccccccc"
|
||||||
|
inkscape:label="N" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4151"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:Orbitron;-inkscape-font-specification:'Orbitron Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 43,1030.3621 -8.897887,0 c -0.06808,0 -0.102113,0.036 -0.102113,0.1069 l 0,6.7862 c 0,0.071 0.03404,0.1069 0.102113,0.1069 l 8.897887,0 0,2 -8.972339,0 c -0.56405,0 -1.045437,-0.2037 -1.444162,-0.6111 C 32.1945,1038.3334 32,1037.8292 32,1037.2385 l 0,-6.7528 c 0,-0.5907 0.1945,-1.0898 0.583499,-1.4972 0.398725,-0.4176 0.880112,-0.6264 1.444162,-0.6264 l 8.972339,0 z"
|
||||||
|
sodipodi:nodetypes="cssssccscsscscc"
|
||||||
|
inkscape:label="C" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 12 KiB |
9
qiming-noVNC/app/images/ime.svg
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M12 19V5"></path>
|
||||||
|
<path d="M5 12H2"></path>
|
||||||
|
<path d="M22 12h-3"></path>
|
||||||
|
<path d="M6 8h12"></path>
|
||||||
|
<path d="M8 16h8"></path>
|
||||||
|
<rect x="4" y="3" width="16" height="18" rx="2"></rect>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 368 B |
81
qiming-noVNC/app/images/info.svg
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
<?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="info.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="1"
|
||||||
|
inkscape:cx="15.720838"
|
||||||
|
inkscape:cy="8.9111233"
|
||||||
|
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="false"
|
||||||
|
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 />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-1027.3622)">
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="M 12.5 3 A 9.5 9.4999914 0 0 0 3 12.5 A 9.5 9.4999914 0 0 0 12.5 22 A 9.5 9.4999914 0 0 0 22 12.5 A 9.5 9.4999914 0 0 0 12.5 3 z M 12.5 5 A 1.5 1.5000087 0 0 1 14 6.5 A 1.5 1.5000087 0 0 1 12.5 8 A 1.5 1.5000087 0 0 1 11 6.5 A 1.5 1.5000087 0 0 1 12.5 5 z M 10.521484 8.9785156 L 12.521484 8.9785156 A 1.50015 1.50015 0 0 1 14.021484 10.478516 L 14.021484 15.972656 A 1.50015 1.50015 0 0 1 14.498047 18.894531 C 14.498047 18.894531 13.74301 19.228309 12.789062 18.912109 C 12.312092 18.754109 11.776235 18.366625 11.458984 17.828125 C 11.141734 17.289525 11.021484 16.668469 11.021484 15.980469 L 11.021484 11.980469 L 10.521484 11.980469 A 1.50015 1.50015 0 1 1 10.521484 8.9804688 L 10.521484 8.9785156 z "
|
||||||
|
transform="translate(0,1027.3622)"
|
||||||
|
id="path4136" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.1 KiB |
88
qiming-noVNC/app/images/keyboard.svg
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<?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="keyboard.svg"
|
||||||
|
inkscape:export-filename="/home/ossman/devel/noVNC/images/keyboard.png"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-ydpi="90">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#717171"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="1"
|
||||||
|
inkscape:cx="31.285341"
|
||||||
|
inkscape:cy="8.8028469"
|
||||||
|
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:snap-bbox-midpoints="false"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1136"
|
||||||
|
inkscape:window-x="1920"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:object-paths="true"
|
||||||
|
inkscape:snap-intersection-paths="true"
|
||||||
|
inkscape:object-nodes="true"
|
||||||
|
inkscape:snap-midpoints="true"
|
||||||
|
inkscape:snap-smooth-nodes="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 />
|
||||||
|
</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:1;stroke-linecap:butt;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 7,3 C 4.8012876,3 3,4.8013 3,7 3,11.166667 3,15.333333 3,19.5 3,20.8764 4.1236413,22 5.5,22 l 14,0 C 20.876358,22 22,20.8764 22,19.5 22,15.333333 22,11.166667 22,7 22,4.8013 20.198712,3 18,3 Z m 0,2 11,0 c 1.125307,0 2,0.8747 2,2 L 20,12 5,12 5,7 C 5,5.8747 5.8746931,5 7,5 Z M 6.5,14 C 6.777,14 7,14.223 7,14.5 7,14.777 6.777,15 6.5,15 6.223,15 6,14.777 6,14.5 6,14.223 6.223,14 6.5,14 Z m 2,0 C 8.777,14 9,14.223 9,14.5 9,14.777 8.777,15 8.5,15 8.223,15 8,14.777 8,14.5 8,14.223 8.223,14 8.5,14 Z m 2,0 C 10.777,14 11,14.223 11,14.5 11,14.777 10.777,15 10.5,15 10.223,15 10,14.777 10,14.5 10,14.223 10.223,14 10.5,14 Z m 2,0 C 12.777,14 13,14.223 13,14.5 13,14.777 12.777,15 12.5,15 12.223,15 12,14.777 12,14.5 12,14.223 12.223,14 12.5,14 Z m 2,0 C 14.777,14 15,14.223 15,14.5 15,14.777 14.777,15 14.5,15 14.223,15 14,14.777 14,14.5 14,14.223 14.223,14 14.5,14 Z m 2,0 C 16.777,14 17,14.223 17,14.5 17,14.777 16.777,15 16.5,15 16.223,15 16,14.777 16,14.5 16,14.223 16.223,14 16.5,14 Z m 2,0 C 18.777,14 19,14.223 19,14.5 19,14.777 18.777,15 18.5,15 18.223,15 18,14.777 18,14.5 18,14.223 18.223,14 18.5,14 Z m -13,2 C 5.777,16 6,16.223 6,16.5 6,16.777 5.777,17 5.5,17 5.223,17 5,16.777 5,16.5 5,16.223 5.223,16 5.5,16 Z m 2,0 C 7.777,16 8,16.223 8,16.5 8,16.777 7.777,17 7.5,17 7.223,17 7,16.777 7,16.5 7,16.223 7.223,16 7.5,16 Z m 2,0 C 9.777,16 10,16.223 10,16.5 10,16.777 9.777,17 9.5,17 9.223,17 9,16.777 9,16.5 9,16.223 9.223,16 9.5,16 Z m 2,0 C 11.777,16 12,16.223 12,16.5 12,16.777 11.777,17 11.5,17 11.223,17 11,16.777 11,16.5 11,16.223 11.223,16 11.5,16 Z m 2,0 C 13.777,16 14,16.223 14,16.5 14,16.777 13.777,17 13.5,17 13.223,17 13,16.777 13,16.5 13,16.223 13.223,16 13.5,16 Z m 2,0 C 15.777,16 16,16.223 16,16.5 16,16.777 15.777,17 15.5,17 15.223,17 15,16.777 15,16.5 15,16.223 15.223,16 15.5,16 Z m 2,0 C 17.777,16 18,16.223 18,16.5 18,16.777 17.777,17 17.5,17 17.223,17 17,16.777 17,16.5 17,16.223 17.223,16 17.5,16 Z m 2,0 C 19.777,16 20,16.223 20,16.5 20,16.777 19.777,17 19.5,17 19.223,17 19,16.777 19,16.5 19,16.223 19.223,16 19.5,16 Z M 6,18 c 0.554,0 1,0.446 1,1 0,0.554 -0.446,1 -1,1 -0.554,0 -1,-0.446 -1,-1 0,-0.554 0.446,-1 1,-1 z m 2.8261719,0 7.3476561,0 C 16.631643,18 17,18.368372 17,18.826172 l 0,0.347656 C 17,19.631628 16.631643,20 16.173828,20 L 8.8261719,20 C 8.3683573,20 8,19.631628 8,19.173828 L 8,18.826172 C 8,18.368372 8.3683573,18 8.8261719,18 Z m 10.1113281,0 0.125,0 C 19.581551,18 20,18.4184 20,18.9375 l 0,0.125 C 20,19.5816 19.581551,20 19.0625,20 l -0.125,0 C 18.418449,20 18,19.5816 18,19.0625 l 0,-0.125 C 18,18.4184 18.418449,18 18.9375,18 Z"
|
||||||
|
transform="translate(0,1027.3622)"
|
||||||
|
id="rect4160"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="sccssccsssssccssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
|
||||||
|
d="m 12.499929,1033.8622 -2,2 1.500071,0 0,2 1,0 0,-2 1.499929,0 z"
|
||||||
|
id="path4150"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccccccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 6.3 KiB |
87
qiming-noVNC/app/images/power.svg
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<?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="power.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="1"
|
||||||
|
inkscape:cx="9.3159849"
|
||||||
|
inkscape:cy="13.436208"
|
||||||
|
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 9 6.8183594 C 6.3418164 8.1213032 4.5 10.849161 4.5 14 C 4.5 18.4065 8.0935666 22 12.5 22 C 16.906433 22 20.5 18.4065 20.5 14 C 20.5 10.849161 18.658184 8.1213032 16 6.8183594 L 16 9.125 C 17.514327 10.211757 18.5 11.984508 18.5 14 C 18.5 17.3256 15.825553 20 12.5 20 C 9.1744469 20 6.5 17.3256 6.5 14 C 6.5 11.984508 7.4856727 10.211757 9 9.125 L 9 6.8183594 z "
|
||||||
|
transform="translate(0,1027.3622)"
|
||||||
|
id="path6140" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 12.5,1031.8836 0,6.4786"
|
||||||
|
id="path6142"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.9 KiB |
76
qiming-noVNC/app/images/settings.svg
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<?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="settings.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="22.627417"
|
||||||
|
inkscape:cx="14.69683"
|
||||||
|
inkscape:cy="8.8039511"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
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="false"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1136"
|
||||||
|
inkscape:window-x="1920"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="1">
|
||||||
|
<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="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="M 11 3 L 11 5.1601562 A 7.5 7.5 0 0 0 8.3671875 6.2460938 L 6.84375 4.7226562 L 4.7226562 6.84375 L 6.2480469 8.3691406 A 7.5 7.5 0 0 0 5.1523438 11 L 3 11 L 3 14 L 5.1601562 14 A 7.5 7.5 0 0 0 6.2460938 16.632812 L 4.7226562 18.15625 L 6.84375 20.277344 L 8.3691406 18.751953 A 7.5 7.5 0 0 0 11 19.847656 L 11 22 L 14 22 L 14 19.839844 A 7.5 7.5 0 0 0 16.632812 18.753906 L 18.15625 20.277344 L 20.277344 18.15625 L 18.751953 16.630859 A 7.5 7.5 0 0 0 19.847656 14 L 22 14 L 22 11 L 19.839844 11 A 7.5 7.5 0 0 0 18.753906 8.3671875 L 20.277344 6.84375 L 18.15625 4.7226562 L 16.630859 6.2480469 A 7.5 7.5 0 0 0 14 5.1523438 L 14 3 L 11 3 z M 12.5 10 A 2.5 2.5 0 0 1 15 12.5 A 2.5 2.5 0 0 1 12.5 15 A 2.5 2.5 0 0 1 10 12.5 A 2.5 2.5 0 0 1 12.5 10 z "
|
||||||
|
transform="translate(0,1027.3622)"
|
||||||
|
id="rect4967" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.0 KiB |
86
qiming-noVNC/app/images/tab.svg
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
<?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="tab.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="11.67335"
|
||||||
|
inkscape:cy="17.881696"
|
||||||
|
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="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
d="m 3,1031.3622 0,8 2,0 0,-4 0,-4 -2,0 z m 2,4 4,4 0,-3 13,0 0,-2 -13,0 0,-3 -4,4 z"
|
||||||
|
id="rect5194"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
id="path5211"
|
||||||
|
d="m 22,1048.3622 0,-8 -2,0 0,4 0,4 2,0 z m -2,-4 -4,-4 0,3 -13,0 0,2 13,0 0,3 4,-4 z"
|
||||||
|
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.9 KiB |
90
qiming-noVNC/app/images/toggleextrakeys.svg
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<?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="extrakeys.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="1"
|
||||||
|
inkscape:cx="15.234555"
|
||||||
|
inkscape:cy="9.9710826"
|
||||||
|
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="false"
|
||||||
|
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="false">
|
||||||
|
<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:miter;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,1031.3622 c -2.1987124,0 -4,1.8013 -4,4 l 0,8.9996 c 0,2.1987 1.8012876,4 4,4 l 9,0 c 2.198712,0 4,-1.8013 4,-4 l 0,-8.9996 c 0,-2.1987 -1.801288,-4 -4,-4 z m 0,2 9,0 c 1.125307,0 2,0.8747 2,2 l 0,7.0005 c 0,1.1253 -0.874693,2 -2,2 l -9,0 c -1.1253069,0 -2,-0.8747 -2,-2 l 0,-7.0005 c 0,-1.1253 0.8746931,-2 2,-2 z"
|
||||||
|
id="rect5006"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ssssssssssssssssss" />
|
||||||
|
<g
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:10px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'Sans Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
id="text4167"
|
||||||
|
transform="matrix(0.96021948,0,0,0.96021948,0.18921715,41.80659)">
|
||||||
|
<path
|
||||||
|
d="m 14.292969,1040.6791 -2.939453,0 -0.463868,1.3281 -1.889648,0 2.700195,-7.29 2.241211,0 2.700196,7.29 -1.889649,0 -0.458984,-1.3281 z m -2.470703,-1.3526 1.99707,0 -0.996094,-2.9004 -1.000976,2.9004 z"
|
||||||
|
id="path4172"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.3 KiB |
81
qiming-noVNC/app/images/warning.svg
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
<?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="warning.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="1"
|
||||||
|
inkscape:cx="16.457343"
|
||||||
|
inkscape:cy="12.179552"
|
||||||
|
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="false"
|
||||||
|
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:evenodd;stroke:none;stroke-width:4;stroke-linecap:butt;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.513672 3.0019531 C 11.751609 2.9919531 11.052563 3.4242687 10.710938 4.1054688 L 3.2109375 19.105469 C 2.5461937 20.435369 3.5132277 21.9999 5 22 L 20 22 C 21.486772 21.9999 22.453806 20.435369 21.789062 19.105469 L 14.289062 4.1054688 C 13.951849 3.4330688 13.265888 3.0066531 12.513672 3.0019531 z M 12.478516 6.9804688 A 1.50015 1.50015 0 0 1 14 8.5 L 14 14.5 A 1.50015 1.50015 0 1 1 11 14.5 L 11 8.5 A 1.50015 1.50015 0 0 1 12.478516 6.9804688 z M 12.5 17 A 1.5 1.5 0 0 1 14 18.5 A 1.5 1.5 0 0 1 12.5 20 A 1.5 1.5 0 0 1 11 18.5 A 1.5 1.5 0 0 1 12.5 17 z "
|
||||||
|
transform="translate(0,1027.3622)"
|
||||||
|
id="path4208" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.8 KiB |
65
qiming-noVNC/app/images/windows.svg
Normal file
@@ -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 |
296
qiming-noVNC/app/ime.js
Normal file
@@ -0,0 +1,296 @@
|
|||||||
|
/*
|
||||||
|
* noVNC: HTML5 VNC client
|
||||||
|
* IME (Input Method Editor) passthrough module
|
||||||
|
*
|
||||||
|
* 输入法透传模块 - 用于将本地输入法的输入传送到远程桌面
|
||||||
|
*
|
||||||
|
* 功能:
|
||||||
|
* - 通过 WebSocket 连接 IME 服务
|
||||||
|
* - 监听输入法事件(compositionend)
|
||||||
|
* - 将输入的文本发送到远程桌面
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as Log from '../core/util/logging.js';
|
||||||
|
|
||||||
|
// 输入法管理器类
|
||||||
|
class IMEManager {
|
||||||
|
constructor() {
|
||||||
|
// WebSocket 连接
|
||||||
|
this.ws = null;
|
||||||
|
this.connected = false;
|
||||||
|
|
||||||
|
// 隐藏输入框元素
|
||||||
|
this.inputElement = null;
|
||||||
|
|
||||||
|
// 回调函数
|
||||||
|
this.onStatusChange = null;
|
||||||
|
|
||||||
|
// 绑定事件处理函数(用于移除监听器)
|
||||||
|
this._boundCompositionEnd = this._handleCompositionEnd.bind(this);
|
||||||
|
this._boundInput = this._handleInput.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建 IME WebSocket URL
|
||||||
|
* @param {string} baseUrl - 基础 URL (如 http://127.0.0.1:8088)
|
||||||
|
* @param {string} projectId - 项目 ID
|
||||||
|
* @param {string} userId - 用户 ID (可选,调试模式使用)
|
||||||
|
* @param {boolean} debugMode - 是否调试模式
|
||||||
|
* @returns {string} WebSocket URL
|
||||||
|
*/
|
||||||
|
buildWsUrl(baseUrl, projectId, userId = null, debugMode = false) {
|
||||||
|
// 将 http/https 转换为 ws/wss
|
||||||
|
const wsUrl = baseUrl
|
||||||
|
.replace(/^http/, 'ws')
|
||||||
|
.replace(/\/+$/, '');
|
||||||
|
|
||||||
|
// 调试模式:包含 user_id
|
||||||
|
// 正式模式:不包含 user_id
|
||||||
|
if (debugMode && userId) {
|
||||||
|
return `ws://192.168.1.34:8088/computer/ime/${userId}/${projectId}/connect`;
|
||||||
|
} else {
|
||||||
|
return `${wsUrl}/computer/ime/${projectId}/connect`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 连接 IME 服务
|
||||||
|
* @param {string} wsUrl - WebSocket URL
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
async connect(wsUrl) {
|
||||||
|
if (this.connected) {
|
||||||
|
Log.Warn('[IME] 已经连接,请先断开');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this._updateStatus('connecting', 'IME 连接中...');
|
||||||
|
Log.Info('[IME] 连接 IME 服务: ' + wsUrl);
|
||||||
|
|
||||||
|
// 创建隐藏输入框
|
||||||
|
this._createInputElement();
|
||||||
|
|
||||||
|
// 连接 WebSocket
|
||||||
|
this.ws = new WebSocket(wsUrl);
|
||||||
|
|
||||||
|
this.ws.onopen = () => {
|
||||||
|
Log.Info('[IME] WebSocket 已连接');
|
||||||
|
this.connected = true;
|
||||||
|
this._updateStatus('connected', 'IME 已连接');
|
||||||
|
|
||||||
|
// 启用输入监听
|
||||||
|
this._enableInputListeners();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.ws.onmessage = (event) => {
|
||||||
|
try {
|
||||||
|
const response = JSON.parse(event.data);
|
||||||
|
if (response.status === 'ok') {
|
||||||
|
Log.Debug('[IME] 文本发送成功');
|
||||||
|
} else {
|
||||||
|
Log.Warn('[IME] 服务器响应: ' + response.message);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
Log.Error('[IME] 响应解析失败: ' + err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.ws.onerror = (err) => {
|
||||||
|
Log.Error('[IME] WebSocket 错误: ' + err);
|
||||||
|
this._updateStatus('error', 'IME 连接错误');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.ws.onclose = () => {
|
||||||
|
Log.Info('[IME] WebSocket 已关闭');
|
||||||
|
this.connected = false;
|
||||||
|
this._updateStatus('disconnected', 'IME 已断开');
|
||||||
|
this._disableInputListeners();
|
||||||
|
};
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
Log.Error('[IME] 连接失败: ' + err);
|
||||||
|
this._updateStatus('error', 'IME 启动失败');
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 断开 IME 服务
|
||||||
|
*/
|
||||||
|
disconnect() {
|
||||||
|
if (this.ws) {
|
||||||
|
this.ws.close();
|
||||||
|
this.ws = null;
|
||||||
|
}
|
||||||
|
this.connected = false;
|
||||||
|
this._disableInputListeners();
|
||||||
|
this._updateStatus('disconnected', 'IME 已停止');
|
||||||
|
Log.Info('[IME] IME 服务已断开');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送文本到远程桌面
|
||||||
|
* @param {string} text - 要发送的文本
|
||||||
|
*/
|
||||||
|
sendText(text) {
|
||||||
|
if (!this.connected || !this.ws) {
|
||||||
|
Log.Warn('[IME] 未连接,无法发送文本');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!text || text.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const message = JSON.stringify({
|
||||||
|
type: 'text',
|
||||||
|
text: text,
|
||||||
|
method: 'xdotool' // 使用 xdotool 输入方法
|
||||||
|
});
|
||||||
|
|
||||||
|
this.ws.send(message);
|
||||||
|
Log.Debug('[IME] 发送文本: ' + text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 激活输入(聚焦到隐藏输入框)
|
||||||
|
* 当用户点击 VNC 画面时调用
|
||||||
|
*/
|
||||||
|
activateInput() {
|
||||||
|
if (this.inputElement && this.connected) {
|
||||||
|
this.inputElement.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建隐藏输入框
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_createInputElement() {
|
||||||
|
if (this.inputElement) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建隐藏的输入框,用于捕获输入法事件
|
||||||
|
this.inputElement = document.createElement('input');
|
||||||
|
this.inputElement.type = 'text';
|
||||||
|
this.inputElement.id = 'noVNC_ime_input';
|
||||||
|
this.inputElement.autocomplete = 'off';
|
||||||
|
this.inputElement.autocapitalize = 'off';
|
||||||
|
this.inputElement.spellcheck = false;
|
||||||
|
|
||||||
|
// 设置样式 - 隐藏但可聚焦
|
||||||
|
this.inputElement.style.cssText = `
|
||||||
|
position: fixed;
|
||||||
|
top: -9999px;
|
||||||
|
left: -9999px;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
document.body.appendChild(this.inputElement);
|
||||||
|
Log.Debug('[IME] 隐藏输入框已创建');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启用输入监听器
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_enableInputListeners() {
|
||||||
|
if (!this.inputElement) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听输入法完成事件(如选择中文候选词)
|
||||||
|
this.inputElement.addEventListener('compositionend', this._boundCompositionEnd);
|
||||||
|
|
||||||
|
// 监听直接输入事件(非输入法输入)
|
||||||
|
this.inputElement.addEventListener('input', this._boundInput);
|
||||||
|
|
||||||
|
Log.Debug('[IME] 输入监听器已启用');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 禁用输入监听器
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_disableInputListeners() {
|
||||||
|
if (!this.inputElement) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.inputElement.removeEventListener('compositionend', this._boundCompositionEnd);
|
||||||
|
this.inputElement.removeEventListener('input', this._boundInput);
|
||||||
|
|
||||||
|
Log.Debug('[IME] 输入监听器已禁用');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理输入法完成事件
|
||||||
|
* @param {CompositionEvent} event
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_handleCompositionEnd(event) {
|
||||||
|
const text = event.data;
|
||||||
|
if (text && text.length > 0) {
|
||||||
|
Log.Debug('[IME] 输入法完成: ' + text);
|
||||||
|
this.sendText(text);
|
||||||
|
|
||||||
|
// 清空输入框
|
||||||
|
if (this.inputElement) {
|
||||||
|
this.inputElement.value = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理直接输入事件
|
||||||
|
* @param {InputEvent} event
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_handleInput(event) {
|
||||||
|
// 如果正在进行输入法输入,忽略
|
||||||
|
if (event.isComposing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const text = event.target.value;
|
||||||
|
if (text && text.length > 0) {
|
||||||
|
Log.Debug('[IME] 直接输入: ' + text);
|
||||||
|
this.sendText(text);
|
||||||
|
event.target.value = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新状态并触发回调
|
||||||
|
* @param {string} status - 状态 (connecting/connected/disconnected/error)
|
||||||
|
* @param {string} message - 状态消息
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_updateStatus(status, message) {
|
||||||
|
if (this.onStatusChange) {
|
||||||
|
this.onStatusChange(status, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 销毁 IME 管理器
|
||||||
|
*/
|
||||||
|
destroy() {
|
||||||
|
this.disconnect();
|
||||||
|
|
||||||
|
if (this.inputElement && this.inputElement.parentNode) {
|
||||||
|
this.inputElement.parentNode.removeChild(this.inputElement);
|
||||||
|
this.inputElement = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出单例
|
||||||
|
const imeManager = new IMEManager();
|
||||||
|
export default imeManager;
|
||||||
|
|
||||||
1
qiming-noVNC/app/locale/README
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DO NOT MODIFY THE FILES IN THIS FOLDER, THEY ARE AUTOMATICALLY GENERATED FROM THE PO-FILES.
|
||||||
71
qiming-noVNC/app/locale/cs.json
Normal file
@@ -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"
|
||||||
|
}
|
||||||
74
qiming-noVNC/app/locale/de.json
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
{
|
||||||
|
"Connecting...": "Verbinden...",
|
||||||
|
"Disconnecting...": "Verbindung trennen...",
|
||||||
|
"Reconnecting...": "Verbindung wiederherstellen...",
|
||||||
|
"Internal error": "Interner Fehler",
|
||||||
|
"Must set host": "Richten Sie den Server ein",
|
||||||
|
"Connected (encrypted) to ": "Verbunden mit (verschlüsselt) ",
|
||||||
|
"Connected (unencrypted) to ": "Verbunden mit (unverschlüsselt) ",
|
||||||
|
"Something went wrong, connection is closed": "Etwas lief schief, Verbindung wurde getrennt",
|
||||||
|
"Disconnected": "Verbindung zum Server getrennt",
|
||||||
|
"New connection has been rejected with reason: ": "Verbindung wurde aus folgendem Grund abgelehnt: ",
|
||||||
|
"New connection has been rejected": "Verbindung wurde abgelehnt",
|
||||||
|
"Password is required": "Passwort ist erforderlich",
|
||||||
|
"noVNC encountered an error:": "Ein Fehler ist aufgetreten:",
|
||||||
|
"Hide/Show the control bar": "Kontrollleiste verstecken/anzeigen",
|
||||||
|
"Move/Drag viewport": "Ansichtsfenster verschieben/ziehen",
|
||||||
|
"viewport drag": "Ansichtsfenster ziehen",
|
||||||
|
"Active Mouse Button": "Aktive Maustaste",
|
||||||
|
"No mousebutton": "Keine Maustaste",
|
||||||
|
"Left mousebutton": "Linke Maustaste",
|
||||||
|
"Middle mousebutton": "Mittlere Maustaste",
|
||||||
|
"Right mousebutton": "Rechte Maustaste",
|
||||||
|
"Keyboard": "Tastatur",
|
||||||
|
"Show keyboard": "Tastatur anzeigen",
|
||||||
|
"Extra keys": "Zusatztasten",
|
||||||
|
"Show extra keys": "Zusatztasten anzeigen",
|
||||||
|
"Ctrl": "Strg",
|
||||||
|
"Toggle Ctrl": "Strg umschalten",
|
||||||
|
"Alt": "Alt",
|
||||||
|
"Toggle Alt": "Alt umschalten",
|
||||||
|
"Send Tab": "Tab senden",
|
||||||
|
"Tab": "Tab",
|
||||||
|
"Esc": "Esc",
|
||||||
|
"Send Escape": "Escape senden",
|
||||||
|
"Ctrl+Alt+Del": "Strg+Alt+Entf",
|
||||||
|
"Send Ctrl-Alt-Del": "Strg+Alt+Entf senden",
|
||||||
|
"Shutdown/Reboot": "Herunterfahren/Neustarten",
|
||||||
|
"Shutdown/Reboot...": "Herunterfahren/Neustarten...",
|
||||||
|
"Power": "Energie",
|
||||||
|
"Shutdown": "Herunterfahren",
|
||||||
|
"Reboot": "Neustarten",
|
||||||
|
"Reset": "Zurücksetzen",
|
||||||
|
"Clipboard": "Zwischenablage",
|
||||||
|
"Clear": "Löschen",
|
||||||
|
"Fullscreen": "Vollbild",
|
||||||
|
"Settings": "Einstellungen",
|
||||||
|
"Shared mode": "Geteilter Modus",
|
||||||
|
"View only": "Nur betrachten",
|
||||||
|
"Clip to window": "Auf Fenster begrenzen",
|
||||||
|
"Scaling mode:": "Skalierungsmodus:",
|
||||||
|
"None": "Keiner",
|
||||||
|
"Local scaling": "Lokales skalieren",
|
||||||
|
"Remote resizing": "Serverseitiges skalieren",
|
||||||
|
"Advanced": "Erweitert",
|
||||||
|
"Repeater ID:": "Repeater ID:",
|
||||||
|
"WebSocket": "WebSocket",
|
||||||
|
"Encrypt": "Verschlüsselt",
|
||||||
|
"Host:": "Server:",
|
||||||
|
"Port:": "Port:",
|
||||||
|
"Path:": "Pfad:",
|
||||||
|
"Automatic reconnect": "Automatisch wiederverbinden",
|
||||||
|
"Reconnect delay (ms):": "Wiederverbindungsverzögerung (ms):",
|
||||||
|
"Logging:": "Protokollierung:",
|
||||||
|
"Disconnect": "Verbindung trennen",
|
||||||
|
"Connect": "Verbinden",
|
||||||
|
"Password:": "Passwort:",
|
||||||
|
"Cancel": "Abbrechen",
|
||||||
|
"Canvas not supported.": "Canvas nicht unterstützt.",
|
||||||
|
"Disconnect timeout": "Zeitüberschreitung beim Trennen",
|
||||||
|
"Local Downscaling": "Lokales herunterskalieren",
|
||||||
|
"Local Cursor": "Lokaler Mauszeiger",
|
||||||
|
"Forcing clipping mode since scrollbars aren't supported by IE in fullscreen": "'Clipping-Modus' aktiviert, Scrollbalken in 'IE-Vollbildmodus' werden nicht unterstützt",
|
||||||
|
"True Color": "True Color"
|
||||||
|
}
|
||||||
100
qiming-noVNC/app/locale/el.json
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
{
|
||||||
|
"HTTPS is required for full functionality": "Το HTTPS είναι απαιτούμενο για πλήρη λειτουργικότητα",
|
||||||
|
"Connecting...": "Συνδέεται...",
|
||||||
|
"Disconnecting...": "Aποσυνδέεται...",
|
||||||
|
"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": "Παράθυρα",
|
||||||
|
"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": "Πρόχειρο",
|
||||||
|
"Edit clipboard content in the textarea below.": "Επεξεργαστείτε το περιεχόμενο του πρόχειρου στην περιοχή κειμένου παρακάτω.",
|
||||||
|
"Full Screen": "Πλήρης Οθόνη",
|
||||||
|
"Settings": "Ρυθμίσεις",
|
||||||
|
"Shared Mode": "Κοινόχρηστη Λειτουργία",
|
||||||
|
"View Only": "Μόνο Θέαση",
|
||||||
|
"Clip to Window": "Αποκοπή στο όριο του Παράθυρου",
|
||||||
|
"Scaling Mode:": "Λειτουργία Κλιμάκωσης:",
|
||||||
|
"None": "Καμία",
|
||||||
|
"Local Scaling": "Τοπική Κλιμάκωση",
|
||||||
|
"Remote Resizing": "Απομακρυσμένη Αλλαγή μεγέθους",
|
||||||
|
"Advanced": "Για προχωρημένους",
|
||||||
|
"Quality:": "Ποιότητα:",
|
||||||
|
"Compression level:": "Επίπεδο συμπίεσης:",
|
||||||
|
"Repeater ID:": "Repeater ID:",
|
||||||
|
"WebSocket": "WebSocket",
|
||||||
|
"Encrypt": "Κρυπτογράφηση",
|
||||||
|
"Host:": "Όνομα διακομιστή:",
|
||||||
|
"Port:": "Πόρτα διακομιστή:",
|
||||||
|
"Path:": "Διαδρομή:",
|
||||||
|
"Automatic Reconnect": "Αυτόματη επανασύνδεση",
|
||||||
|
"Reconnect Delay (ms):": "Καθυστέρηση επανασύνδεσης (ms):",
|
||||||
|
"Show Dot when No Cursor": "Εμφάνιση Τελείας όταν δεν υπάρχει Δρομέας",
|
||||||
|
"Logging:": "Καταγραφή:",
|
||||||
|
"Version:": "Έκδοση:",
|
||||||
|
"Disconnect": "Αποσύνδεση",
|
||||||
|
"Connect": "Σύνδεση",
|
||||||
|
"Server identity": "Ταυτότητα Διακομιστή",
|
||||||
|
"The server has provided the following identifying information:": "Ο διακομιστής παρείχε την ακόλουθη πληροφορία ταυτοποίησης:",
|
||||||
|
"Fingerprint:": "Δακτυλικό αποτύπωμα:",
|
||||||
|
"Please verify that the information is correct and press \"Approve\". Otherwise press \"Reject\".": "Παρακαλώ επαληθεύσετε ότι η πληροφορία είναι σωστή και πιέστε \"Αποδοχή\". Αλλιώς πιέστε \"Απόρριψη\".",
|
||||||
|
"Approve": "Αποδοχή",
|
||||||
|
"Reject": "Απόρριψη",
|
||||||
|
"Credentials": "Διαπιστευτήρια",
|
||||||
|
"Username:": "Κωδικός Χρήστη:",
|
||||||
|
"Password:": "Κωδικός Πρόσβασης:",
|
||||||
|
"Send Credentials": "Αποστολή Διαπιστευτηρίων",
|
||||||
|
"Cancel": "Ακύρωση",
|
||||||
|
"Password is required": "Απαιτείται ο κωδικός πρόσβασης",
|
||||||
|
"viewport drag": "σύρσιμο θεατού πεδίου",
|
||||||
|
"Active Mouse Button": "Ενεργό Πλήκτρο Ποντικιού",
|
||||||
|
"No mousebutton": "Χωρίς Πλήκτρο Ποντικιού",
|
||||||
|
"Left mousebutton": "Αριστερό Πλήκτρο Ποντικιού",
|
||||||
|
"Middle mousebutton": "Μεσαίο Πλήκτρο Ποντικιού",
|
||||||
|
"Right mousebutton": "Δεξί Πλήκτρο Ποντικιού",
|
||||||
|
"Clear": "Καθάρισμα",
|
||||||
|
"Canvas not supported.": "Δεν υποστηρίζεται το στοιχείο Canvas",
|
||||||
|
"Disconnect timeout": "Παρέλευση χρονικού ορίου αποσύνδεσης",
|
||||||
|
"Local Downscaling": "Τοπική Συρρίκνωση",
|
||||||
|
"Local Cursor": "Τοπικός Δρομέας",
|
||||||
|
"Forcing clipping mode since scrollbars aren't supported by IE in fullscreen": "Εφαρμογή λειτουργίας αποκοπής αφού δεν υποστηρίζονται οι λωρίδες κύλισης σε πλήρη οθόνη στον IE",
|
||||||
|
"True Color": "Πραγματικά Χρώματα",
|
||||||
|
"Style:": "Στυλ:",
|
||||||
|
"default": "προεπιλεγμένο",
|
||||||
|
"Apply": "Εφαρμογή",
|
||||||
|
"Connection": "Σύνδεση",
|
||||||
|
"Token:": "Διακριτικό:",
|
||||||
|
"Send Password": "Αποστολή Κωδικού Πρόσβασης"
|
||||||
|
}
|
||||||
68
qiming-noVNC/app/locale/es.json
Normal file
@@ -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": "Se debe configurar el host",
|
||||||
|
"Reconnecting...": "Reconectando...",
|
||||||
|
"Password is required": "La 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",
|
||||||
|
"Encrypt": "Encriptar",
|
||||||
|
"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",
|
||||||
|
"Host:": "Host:",
|
||||||
|
"Port:": "Puerto:",
|
||||||
|
"Path:": "Ruta:",
|
||||||
|
"Automatic reconnect": "Reconexión automática",
|
||||||
|
"Reconnect delay (ms):": "Retraso en la reconexión (ms):",
|
||||||
|
"Logging:": "Registrando:",
|
||||||
|
"Disconnect": "Desconectar",
|
||||||
|
"Connect": "Conectar",
|
||||||
|
"Password:": "Contraseña:",
|
||||||
|
"Cancel": "Cancelar",
|
||||||
|
"Canvas not supported.": "Canvas no soportado."
|
||||||
|
}
|
||||||
82
qiming-noVNC/app/locale/fr.json
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
{
|
||||||
|
"Running without HTTPS is not recommended, crashes or other issues are likely.": "Lancer sans HTTPS n'est pas recommandé, crashs ou autres problèmes en vue.",
|
||||||
|
"Connecting...": "En cours de connexion...",
|
||||||
|
"Disconnecting...": "Déconnexion en cours...",
|
||||||
|
"Reconnecting...": "Reconnexion en cours...",
|
||||||
|
"Internal error": "Erreur interne",
|
||||||
|
"Failed to connect to server: ": "Échec de connexion au serveur ",
|
||||||
|
"Connected (encrypted) to ": "Connecté (chiffré) à ",
|
||||||
|
"Connected (unencrypted) to ": "Connecté (non chiffré) à ",
|
||||||
|
"Something went wrong, connection is closed": "Quelque chose s'est mal passé, la connexion a été fermée",
|
||||||
|
"Failed to connect to server": "Échec de connexion au serveur",
|
||||||
|
"Disconnected": "Déconnecté",
|
||||||
|
"New connection has been rejected with reason: ": "Une nouvelle connexion a été rejetée avec motif : ",
|
||||||
|
"New connection has been rejected": "Une nouvelle connexion a été rejetée",
|
||||||
|
"Credentials are required": "Les identifiants sont requis",
|
||||||
|
"noVNC encountered an error:": "noVNC a rencontré une erreur :",
|
||||||
|
"Hide/Show the control bar": "Masquer/Afficher la barre de contrôle",
|
||||||
|
"Drag": "Faire glisser",
|
||||||
|
"Move/Drag viewport": "Déplacer la fenêtre de visualisation",
|
||||||
|
"Keyboard": "Clavier",
|
||||||
|
"Show keyboard": "Afficher le clavier",
|
||||||
|
"Extra keys": "Touches supplémentaires",
|
||||||
|
"Show extra keys": "Afficher les touches supplémentaires",
|
||||||
|
"Ctrl": "Ctrl",
|
||||||
|
"Toggle Ctrl": "Basculer Ctrl",
|
||||||
|
"Alt": "Alt",
|
||||||
|
"Toggle Alt": "Basculer Alt",
|
||||||
|
"Toggle Windows": "Basculer Windows",
|
||||||
|
"Windows": "Fenêtre",
|
||||||
|
"Send Tab": "Envoyer Tab",
|
||||||
|
"Tab": "Tabulation",
|
||||||
|
"Esc": "Esc",
|
||||||
|
"Send Escape": "Envoyer Escape",
|
||||||
|
"Ctrl+Alt+Del": "Ctrl+Alt+Del",
|
||||||
|
"Send Ctrl-Alt-Del": "Envoyer Ctrl-Alt-Del",
|
||||||
|
"Shutdown/Reboot": "Arrêter/Redémarrer",
|
||||||
|
"Shutdown/Reboot...": "Arrêter/Redémarrer...",
|
||||||
|
"Power": "Alimentation",
|
||||||
|
"Shutdown": "Arrêter",
|
||||||
|
"Reboot": "Redémarrer",
|
||||||
|
"Reset": "Réinitialiser",
|
||||||
|
"Clipboard": "Presse-papiers",
|
||||||
|
"Edit clipboard content in the textarea below.": "Editer le contenu du presse-papier dans la zone ci-dessous.",
|
||||||
|
"Full screen": "Plein écran",
|
||||||
|
"Settings": "Paramètres",
|
||||||
|
"Shared mode": "Mode partagé",
|
||||||
|
"View only": "Afficher uniquement",
|
||||||
|
"Clip to window": "Ajuster à la fenêtre",
|
||||||
|
"Scaling mode:": "Mode mise à l'échelle :",
|
||||||
|
"None": "Aucun",
|
||||||
|
"Local scaling": "Mise à l'échelle locale",
|
||||||
|
"Remote resizing": "Redimensionnement à distance",
|
||||||
|
"Advanced": "Avancé",
|
||||||
|
"Quality:": "Qualité :",
|
||||||
|
"Compression level:": "Niveau de compression :",
|
||||||
|
"Repeater ID:": "ID Répéteur :",
|
||||||
|
"WebSocket": "WebSocket",
|
||||||
|
"Encrypt": "Chiffrer",
|
||||||
|
"Host:": "Hôte :",
|
||||||
|
"Port:": "Port :",
|
||||||
|
"Path:": "Chemin :",
|
||||||
|
"Automatic reconnect": "Reconnecter automatiquement",
|
||||||
|
"Reconnect delay (ms):": "Délai de reconnexion (ms) :",
|
||||||
|
"Show dot when no cursor": "Afficher le point lorsqu'il n'y a pas de curseur",
|
||||||
|
"Logging:": "Se connecter :",
|
||||||
|
"Version:": "Version :",
|
||||||
|
"Disconnect": "Déconnecter",
|
||||||
|
"Connect": "Connecter",
|
||||||
|
"Server identity": "Identité du serveur",
|
||||||
|
"The server has provided the following identifying information:": "Le serveur a fourni l'identification suivante :",
|
||||||
|
"Fingerprint:": "Empreinte digitale :",
|
||||||
|
"Please verify that the information is correct and press \"Approve\". Otherwise press \"Reject\".": "SVP, verifiez que l'information est correcte et pressez \"Accepter\". Sinon pressez \"Refuser\".",
|
||||||
|
"Approve": "Accepter",
|
||||||
|
"Reject": "Refuser",
|
||||||
|
"Credentials": "Envoyer les identifiants",
|
||||||
|
"Username:": "Nom d'utilisateur :",
|
||||||
|
"Password:": "Mot de passe :",
|
||||||
|
"Send credentials": "Envoyer les identifiants",
|
||||||
|
"Cancel": "Annuler",
|
||||||
|
"Must set host": "Doit définir l'hôte",
|
||||||
|
"Clear": "Effacer"
|
||||||
|
}
|
||||||
68
qiming-noVNC/app/locale/it.json
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
{
|
||||||
|
"Connecting...": "Connessione in corso...",
|
||||||
|
"Disconnecting...": "Disconnessione...",
|
||||||
|
"Reconnecting...": "Riconnessione...",
|
||||||
|
"Internal error": "Errore interno",
|
||||||
|
"Must set host": "Devi impostare l'host",
|
||||||
|
"Connected (encrypted) to ": "Connesso (crittografato) a ",
|
||||||
|
"Connected (unencrypted) to ": "Connesso (non crittografato) a",
|
||||||
|
"Something went wrong, connection is closed": "Qualcosa è andato storto, la connessione è stata chiusa",
|
||||||
|
"Failed to connect to server": "Impossibile connettersi al server",
|
||||||
|
"Disconnected": "Disconnesso",
|
||||||
|
"New connection has been rejected with reason: ": "La nuova connessione è stata rifiutata con motivo: ",
|
||||||
|
"New connection has been rejected": "La nuova connessione è stata rifiutata",
|
||||||
|
"Credentials are required": "Le credenziali sono obbligatorie",
|
||||||
|
"noVNC encountered an error:": "noVNC ha riscontrato un errore:",
|
||||||
|
"Hide/Show the control bar": "Nascondi/Mostra la barra di controllo",
|
||||||
|
"Keyboard": "Tastiera",
|
||||||
|
"Show keyboard": "Mostra tastiera",
|
||||||
|
"Extra keys": "Tasti Aggiuntivi",
|
||||||
|
"Show Extra Keys": "Mostra Tasti Aggiuntivi",
|
||||||
|
"Ctrl": "Ctrl",
|
||||||
|
"Toggle Ctrl": "Tieni premuto Ctrl",
|
||||||
|
"Alt": "Alt",
|
||||||
|
"Toggle Alt": "Tieni premuto Alt",
|
||||||
|
"Toggle Windows": "Tieni premuto Windows",
|
||||||
|
"Windows": "Windows",
|
||||||
|
"Send Tab": "Invia Tab",
|
||||||
|
"Tab": "Tab",
|
||||||
|
"Esc": "Esc",
|
||||||
|
"Send Escape": "Invia Esc",
|
||||||
|
"Ctrl+Alt+Del": "Ctrl+Alt+Canc",
|
||||||
|
"Send Ctrl-Alt-Del": "Invia Ctrl-Alt-Canc",
|
||||||
|
"Shutdown/Reboot": "Spegnimento/Riavvio",
|
||||||
|
"Shutdown/Reboot...": "Spegnimento/Riavvio...",
|
||||||
|
"Power": "Alimentazione",
|
||||||
|
"Shutdown": "Spegnimento",
|
||||||
|
"Reboot": "Riavvio",
|
||||||
|
"Reset": "Reset",
|
||||||
|
"Clipboard": "Clipboard",
|
||||||
|
"Clear": "Pulisci",
|
||||||
|
"Fullscreen": "Schermo intero",
|
||||||
|
"Settings": "Impostazioni",
|
||||||
|
"Shared mode": "Modalità condivisa",
|
||||||
|
"View Only": "Sola Visualizzazione",
|
||||||
|
"Scaling mode:": "Modalità di ridimensionamento:",
|
||||||
|
"None": "Nessuna",
|
||||||
|
"Local Scaling": "Ridimensionamento Locale",
|
||||||
|
"Remote Resizing": "Ridimensionamento Remoto",
|
||||||
|
"Advanced": "Avanzate",
|
||||||
|
"Quality:": "Qualità:",
|
||||||
|
"Compression level:": "Livello Compressione:",
|
||||||
|
"Repeater ID:": "ID Ripetitore:",
|
||||||
|
"WebSocket": "WebSocket",
|
||||||
|
"Encrypt": "Crittografa",
|
||||||
|
"Host:": "Host:",
|
||||||
|
"Port:": "Porta:",
|
||||||
|
"Path:": "Percorso:",
|
||||||
|
"Automatic Reconnect": "Riconnessione Automatica",
|
||||||
|
"Reconnect Delay (ms):": "Ritardo Riconnessione (ms):",
|
||||||
|
"Show Dot when No Cursor": "Mostra Punto quando Nessun Cursore",
|
||||||
|
"Version:": "Versione:",
|
||||||
|
"Disconnect": "Disconnetti",
|
||||||
|
"Connect": "Connetti",
|
||||||
|
"Username:": "Utente:",
|
||||||
|
"Password:": "Password:",
|
||||||
|
"Send Credentials": "Invia Credenziale",
|
||||||
|
"Cancel": "Annulla"
|
||||||
|
}
|
||||||
81
qiming-noVNC/app/locale/ja.json
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
{
|
||||||
|
"Running without HTTPS is not recommended, crashes or other issues are likely.": "HTTPS接続なしで実行することは推奨されません。クラッシュしたりその他の問題が発生したりする可能性があります。",
|
||||||
|
"Connecting...": "接続しています...",
|
||||||
|
"Disconnecting...": "切断しています...",
|
||||||
|
"Reconnecting...": "再接続しています...",
|
||||||
|
"Internal error": "内部エラー",
|
||||||
|
"Must set host": "ホストを設定する必要があります",
|
||||||
|
"Failed to connect to server: ": "サーバーへの接続に失敗しました: ",
|
||||||
|
"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": "クリップボード",
|
||||||
|
"Edit clipboard content in the textarea below.": "以下の入力欄からクリップボードの内容を編集できます。",
|
||||||
|
"Full screen": "全画面表示",
|
||||||
|
"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": "接続",
|
||||||
|
"Server identity": "サーバーの識別情報",
|
||||||
|
"The server has provided the following identifying information:": "サーバーは以下の識別情報を提供しています:",
|
||||||
|
"Fingerprint:": "フィンガープリント:",
|
||||||
|
"Please verify that the information is correct and press \"Approve\". Otherwise press \"Reject\".": "この情報が正しい場合は「承認」を、そうでない場合は「拒否」を押してください。",
|
||||||
|
"Approve": "承認",
|
||||||
|
"Reject": "拒否",
|
||||||
|
"Credentials": "資格情報",
|
||||||
|
"Username:": "ユーザー名:",
|
||||||
|
"Password:": "パスワード:",
|
||||||
|
"Send credentials": "資格情報を送信",
|
||||||
|
"Cancel": "キャンセル"
|
||||||
|
}
|
||||||
70
qiming-noVNC/app/locale/ko.json
Normal file
@@ -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": "취소"
|
||||||
|
}
|
||||||
95
qiming-noVNC/app/locale/nl.json
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
{
|
||||||
|
"Running without HTTPS is not recommended, crashes or other issues are likely.": "Het is niet aan te raden om zonder HTTPS te werken, crashes of andere problemen zijn dan waarschijnlijk.",
|
||||||
|
"Connecting...": "Aan het verbinden…",
|
||||||
|
"Disconnecting...": "Bezig om verbinding te verbreken...",
|
||||||
|
"Reconnecting...": "Opnieuw verbinding maken...",
|
||||||
|
"Internal error": "Interne fout",
|
||||||
|
"Failed to connect to server: ": "Verbinding maken met server is mislukt",
|
||||||
|
"Connected (encrypted) to ": "Verbonden (versleuteld) met ",
|
||||||
|
"Connected (unencrypted) to ": "Verbonden (onversleuteld) met ",
|
||||||
|
"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",
|
||||||
|
"New connection has been rejected with reason: ": "Nieuwe verbinding is geweigerd met de volgende reden: ",
|
||||||
|
"New connection has been rejected": "Nieuwe verbinding is geweigerd",
|
||||||
|
"Credentials are required": "Inloggegevens zijn nodig",
|
||||||
|
"noVNC encountered an error:": "noVNC heeft een fout bemerkt:",
|
||||||
|
"Hide/Show the control bar": "Verberg/Toon de bedieningsbalk",
|
||||||
|
"Drag": "Sleep",
|
||||||
|
"Move/Drag viewport": "Verplaats/Versleep Kijkvenster",
|
||||||
|
"Keyboard": "Toetsenbord",
|
||||||
|
"Show keyboard": "Toon Toetsenbord",
|
||||||
|
"Extra keys": "Extra toetsen",
|
||||||
|
"Show extra keys": "Toon Extra Toetsen",
|
||||||
|
"Ctrl": "Ctrl",
|
||||||
|
"Toggle Ctrl": "Ctrl omschakelen",
|
||||||
|
"Alt": "Alt",
|
||||||
|
"Toggle Alt": "Alt omschakelen",
|
||||||
|
"Toggle Windows": "Vensters omschakelen",
|
||||||
|
"Windows": "Vensters",
|
||||||
|
"Send Tab": "Tab Sturen",
|
||||||
|
"Tab": "Tab",
|
||||||
|
"Esc": "Esc",
|
||||||
|
"Send Escape": "Escape Sturen",
|
||||||
|
"Ctrl+Alt+Del": "Ctrl-Alt-Del",
|
||||||
|
"Send Ctrl-Alt-Del": "Ctrl-Alt-Del Sturen",
|
||||||
|
"Shutdown/Reboot": "Uitschakelen/Herstarten",
|
||||||
|
"Shutdown/Reboot...": "Uitschakelen/Herstarten...",
|
||||||
|
"Power": "Systeem",
|
||||||
|
"Shutdown": "Uitschakelen",
|
||||||
|
"Reboot": "Herstarten",
|
||||||
|
"Reset": "Resetten",
|
||||||
|
"Clipboard": "Klembord",
|
||||||
|
"Edit clipboard content in the textarea below.": "Edit de inhoud van het klembord in het tekstveld hieronder",
|
||||||
|
"Full screen": "Volledig Scherm",
|
||||||
|
"Settings": "Instellingen",
|
||||||
|
"Shared mode": "Gedeelde Modus",
|
||||||
|
"View only": "Alleen Kijken",
|
||||||
|
"Clip to window": "Randen buiten venster afsnijden",
|
||||||
|
"Scaling mode:": "Schaalmodus:",
|
||||||
|
"None": "Geen",
|
||||||
|
"Local scaling": "Lokaal Schalen",
|
||||||
|
"Remote resizing": "Op Afstand Formaat Wijzigen",
|
||||||
|
"Advanced": "Geavanceerd",
|
||||||
|
"Quality:": "Kwaliteit:",
|
||||||
|
"Compression level:": "Compressieniveau:",
|
||||||
|
"Repeater ID:": "Repeater ID:",
|
||||||
|
"WebSocket": "WebSocket",
|
||||||
|
"Encrypt": "Versleutelen",
|
||||||
|
"Host:": "Host:",
|
||||||
|
"Port:": "Poort:",
|
||||||
|
"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:",
|
||||||
|
"Version:": "Versie:",
|
||||||
|
"Disconnect": "Verbinding verbreken",
|
||||||
|
"Connect": "Verbinden",
|
||||||
|
"Server identity": "Serveridentiteit",
|
||||||
|
"The server has provided the following identifying information:": "De server geeft de volgende identificerende informatie:",
|
||||||
|
"Fingerprint:": "Vingerafdruk:",
|
||||||
|
"Please verify that the information is correct and press \"Approve\". Otherwise press \"Reject\".": "Verifieer dat de informatie is correct en druk “OK”. Druk anders op “Afwijzen”.",
|
||||||
|
"Approve": "OK",
|
||||||
|
"Reject": "Afwijzen",
|
||||||
|
"Credentials": "Inloggegevens",
|
||||||
|
"Username:": "Gebruikersnaam:",
|
||||||
|
"Password:": "Wachtwoord:",
|
||||||
|
"Send credentials": "Stuur inloggegevens",
|
||||||
|
"Cancel": "Annuleren",
|
||||||
|
"Must set host": "Host moeten worden ingesteld",
|
||||||
|
"Password is required": "Wachtwoord is vereist",
|
||||||
|
"viewport drag": "kijkvenster slepen",
|
||||||
|
"Active Mouse Button": "Actieve Muisknop",
|
||||||
|
"No mousebutton": "Geen muisknop",
|
||||||
|
"Left mousebutton": "Linker muisknop",
|
||||||
|
"Middle mousebutton": "Middelste muisknop",
|
||||||
|
"Right mousebutton": "Rechter muisknop",
|
||||||
|
"Clear": "Wissen",
|
||||||
|
"Send Password": "Verzend Wachtwoord:",
|
||||||
|
"Disconnect timeout": "Timeout tijdens verbreken van verbinding",
|
||||||
|
"Local Downscaling": "Lokaal Neerschalen",
|
||||||
|
"Local Cursor": "Lokale Cursor",
|
||||||
|
"Canvas not supported.": "Canvas wordt niet ondersteund.",
|
||||||
|
"Forcing clipping mode since scrollbars aren't supported by IE in fullscreen": "''Clipping mode' ingeschakeld, omdat schuifbalken in volledige-scherm-modus in IE niet worden ondersteund"
|
||||||
|
}
|
||||||
80
qiming-noVNC/app/locale/pl.json
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
{
|
||||||
|
"Connecting...": "Łączenie...",
|
||||||
|
"Disconnecting...": "Rozłączanie...",
|
||||||
|
"Reconnecting...": "Łączenie...",
|
||||||
|
"Internal error": "Błąd wewnętrzny",
|
||||||
|
"Must set host": "Host i port są wymagane",
|
||||||
|
"Connected (encrypted) to ": "Połączenie (szyfrowane) z ",
|
||||||
|
"Connected (unencrypted) to ": "Połączenie (nieszyfrowane) z ",
|
||||||
|
"Something went wrong, connection is closed": "Coś poszło źle, połączenie zostało zamknięte",
|
||||||
|
"Disconnected": "Rozłączony",
|
||||||
|
"New connection has been rejected with reason: ": "Nowe połączenie zostało odrzucone z powodu: ",
|
||||||
|
"New connection has been rejected": "Nowe połączenie zostało odrzucone",
|
||||||
|
"Password is required": "Hasło jest wymagane",
|
||||||
|
"noVNC encountered an error:": "noVNC napotkało błąd:",
|
||||||
|
"Hide/Show the control bar": "Pokaż/Ukryj pasek ustawień",
|
||||||
|
"Move/Drag Viewport": "Ruszaj/Przeciągaj Viewport",
|
||||||
|
"viewport drag": "przeciągnij viewport",
|
||||||
|
"Active Mouse Button": "Aktywny Przycisk Myszy",
|
||||||
|
"No mousebutton": "Brak przycisku myszy",
|
||||||
|
"Left mousebutton": "Lewy przycisk myszy",
|
||||||
|
"Middle mousebutton": "Środkowy przycisk myszy",
|
||||||
|
"Right mousebutton": "Prawy przycisk myszy",
|
||||||
|
"Keyboard": "Klawiatura",
|
||||||
|
"Show keyboard": "Pokaż klawiaturę",
|
||||||
|
"Extra keys": "Przyciski dodatkowe",
|
||||||
|
"Show extra keys": "Pokaż przyciski dodatkowe",
|
||||||
|
"Ctrl": "Ctrl",
|
||||||
|
"Toggle Ctrl": "Przełącz Ctrl",
|
||||||
|
"Alt": "Alt",
|
||||||
|
"Toggle Alt": "Przełącz Alt",
|
||||||
|
"Send Tab": "Wyślij Tab",
|
||||||
|
"Tab": "Tab",
|
||||||
|
"Esc": "Esc",
|
||||||
|
"Send Escape": "Wyślij Escape",
|
||||||
|
"Ctrl+Alt+Del": "Ctrl+Alt+Del",
|
||||||
|
"Send Ctrl-Alt-Del": "Wyślij Ctrl-Alt-Del",
|
||||||
|
"Shutdown/Reboot": "Wyłącz/Uruchom ponownie",
|
||||||
|
"Shutdown/Reboot...": "Wyłącz/Uruchom ponownie...",
|
||||||
|
"Power": "Włączony",
|
||||||
|
"Shutdown": "Wyłącz",
|
||||||
|
"Reboot": "Uruchom ponownie",
|
||||||
|
"Reset": "Resetuj",
|
||||||
|
"Clipboard": "Schowek",
|
||||||
|
"Clear": "Wyczyść",
|
||||||
|
"Fullscreen": "Pełny ekran",
|
||||||
|
"Settings": "Ustawienia",
|
||||||
|
"Shared Mode": "Tryb Współdzielenia",
|
||||||
|
"View Only": "Tylko Podgląd",
|
||||||
|
"Clip to Window": "Przytnij do Okna",
|
||||||
|
"Scaling Mode:": "Tryb Skalowania:",
|
||||||
|
"None": "Brak",
|
||||||
|
"Local scaling": "Skalowanie lokalne",
|
||||||
|
"Remote resizing": "Skalowanie zdalne",
|
||||||
|
"Advanced": "Zaawansowane",
|
||||||
|
"Repeater ID:": "ID Repeatera:",
|
||||||
|
"WebSocket": "WebSocket",
|
||||||
|
"Encrypt": "Szyfrowanie",
|
||||||
|
"Host:": "Host:",
|
||||||
|
"Port:": "Port:",
|
||||||
|
"Path:": "Ścieżka:",
|
||||||
|
"Automatic reconnect": "Automatycznie wznawiaj połączenie",
|
||||||
|
"Reconnect delay (ms):": "Opóźnienie wznawiania (ms):",
|
||||||
|
"Logging:": "Poziom logowania:",
|
||||||
|
"Disconnect": "Rozłącz",
|
||||||
|
"Connect": "Połącz",
|
||||||
|
"Password:": "Hasło:",
|
||||||
|
"Cancel": "Anuluj",
|
||||||
|
"Canvas not supported.": "Element Canvas nie jest wspierany.",
|
||||||
|
"Disconnect timeout": "Timeout rozłączenia",
|
||||||
|
"Local Downscaling": "Downscaling lokalny",
|
||||||
|
"Local Cursor": "Lokalny kursor",
|
||||||
|
"Forcing clipping mode since scrollbars aren't supported by IE in fullscreen": "Wymuszam clipping mode ponieważ paski przewijania nie są wspierane przez IE w trybie pełnoekranowym",
|
||||||
|
"True Color": "True Color",
|
||||||
|
"Style:": "Styl:",
|
||||||
|
"default": "domyślny",
|
||||||
|
"Apply": "Zapisz",
|
||||||
|
"Connection": "Połączenie",
|
||||||
|
"Token:": "Token:",
|
||||||
|
"Send Password": "Wyślij Hasło"
|
||||||
|
}
|
||||||
72
qiming-noVNC/app/locale/pt_BR.json
Normal file
@@ -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"
|
||||||
|
}
|
||||||
72
qiming-noVNC/app/locale/ru.json
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
{
|
||||||
|
"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": "Новое соединение отклонено",
|
||||||
|
"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": "Вкладка",
|
||||||
|
"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": "Выход"
|
||||||
|
}
|
||||||
83
qiming-noVNC/app/locale/sv.json
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
{
|
||||||
|
"Running without HTTPS is not recommended, crashes or other issues are likely.": "Det är ej rekommenderat att köra utan HTTPS, krascher och andra problem är troliga.",
|
||||||
|
"Connecting...": "Ansluter...",
|
||||||
|
"Disconnecting...": "Kopplar ner...",
|
||||||
|
"Reconnecting...": "Återansluter...",
|
||||||
|
"Internal error": "Internt fel",
|
||||||
|
"Failed to connect to server: ": "Misslyckades att ansluta till servern: ",
|
||||||
|
"Connected (encrypted) to ": "Ansluten (krypterat) till ",
|
||||||
|
"Connected (unencrypted) to ": "Ansluten (okrypterat) till ",
|
||||||
|
"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",
|
||||||
|
"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",
|
||||||
|
"Keyboard": "Tangentbord",
|
||||||
|
"Show keyboard": "Visa tangentbord",
|
||||||
|
"Extra keys": "Extraknappar",
|
||||||
|
"Show extra keys": "Visa extraknappar",
|
||||||
|
"Ctrl": "Ctrl",
|
||||||
|
"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",
|
||||||
|
"Send Escape": "Skicka Escape",
|
||||||
|
"Ctrl+Alt+Del": "Ctrl+Alt+Del",
|
||||||
|
"Send Ctrl-Alt-Del": "Skicka Ctrl-Alt-Del",
|
||||||
|
"Shutdown/Reboot": "Stäng av/Boota om",
|
||||||
|
"Shutdown/Reboot...": "Stäng av/Boota om...",
|
||||||
|
"Power": "Ström",
|
||||||
|
"Shutdown": "Stäng av",
|
||||||
|
"Reboot": "Boota om",
|
||||||
|
"Reset": "Återställ",
|
||||||
|
"Clipboard": "Urklipp",
|
||||||
|
"Edit clipboard content in the textarea below.": "Redigera urklippets innehåll i fältet nedan.",
|
||||||
|
"Full screen": "Fullskärm",
|
||||||
|
"Settings": "Inställningar",
|
||||||
|
"Shared mode": "Delat läge",
|
||||||
|
"View only": "Endast visning",
|
||||||
|
"Clip to window": "Begränsa till fönster",
|
||||||
|
"Scaling mode:": "Skalningsläge:",
|
||||||
|
"None": "Ingen",
|
||||||
|
"Local scaling": "Lokal skalning",
|
||||||
|
"Remote resizing": "Ändra storlek",
|
||||||
|
"Advanced": "Avancerat",
|
||||||
|
"Quality:": "Kvalitet:",
|
||||||
|
"Compression level:": "Kompressionsnivå:",
|
||||||
|
"Repeater ID:": "Repeater-ID:",
|
||||||
|
"WebSocket": "WebSocket",
|
||||||
|
"Encrypt": "Kryptera",
|
||||||
|
"Host:": "Värd:",
|
||||||
|
"Port:": "Port:",
|
||||||
|
"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",
|
||||||
|
"Server identity": "Server-identitet",
|
||||||
|
"The server has provided the following identifying information:": "Servern har gett följande identifierande information:",
|
||||||
|
"Fingerprint:": "Fingeravtryck:",
|
||||||
|
"Please verify that the information is correct and press \"Approve\". Otherwise press \"Reject\".": "Kontrollera att informationen är korrekt och tryck sedan \"Godkänn\". Tryck annars \"Neka\".",
|
||||||
|
"Approve": "Godkänn",
|
||||||
|
"Reject": "Neka",
|
||||||
|
"Credentials": "Användaruppgifter",
|
||||||
|
"Username:": "Användarnamn:",
|
||||||
|
"Password:": "Lösenord:",
|
||||||
|
"Send credentials": "Skicka användaruppgifter",
|
||||||
|
"Cancel": "Avbryt",
|
||||||
|
"Must set host": "Du måste specifiera en värd",
|
||||||
|
"HTTPS is required for full functionality": "HTTPS krävs för full funktionalitet",
|
||||||
|
"Clear": "Rensa"
|
||||||
|
}
|
||||||
69
qiming-noVNC/app/locale/tr.json
Normal file
@@ -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."
|
||||||
|
}
|
||||||
107
qiming-noVNC/app/locale/zh_CN.json
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
{
|
||||||
|
"Running without HTTPS is not recommended, crashes or other issues are likely.": "不建议在没有 HTTPS 的情况下运行,可能会出现崩溃或出现其他问题。",
|
||||||
|
"Connecting...": "连接中...",
|
||||||
|
"Disconnecting...": "正在断开连接...",
|
||||||
|
"Reconnecting...": "重新连接中...",
|
||||||
|
"Internal error": "内部错误",
|
||||||
|
"Must set host": "必须设置主机",
|
||||||
|
"Failed to connect to server: ": "无法连接到智能体电脑:",
|
||||||
|
"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": "窗口",
|
||||||
|
"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": "剪贴板",
|
||||||
|
"Auto sync clipboard": "自动同步剪贴板",
|
||||||
|
"Auto sync enabled": "自动同步已开启",
|
||||||
|
"Clipboard permission denied": "剪贴板权限被拒绝",
|
||||||
|
"Clipboard API not supported": "浏览器不支持剪贴板 API",
|
||||||
|
"Read from local clipboard": "已读取本地剪贴板",
|
||||||
|
"Copied to local clipboard": "已复制到本地剪贴板",
|
||||||
|
"Failed to read clipboard": "读取剪贴板失败",
|
||||||
|
"Failed to write clipboard": "写入剪贴板失败",
|
||||||
|
"Read Local": "读取本地",
|
||||||
|
"Send Remote": "发送远程",
|
||||||
|
"Copy Local": "复制本地",
|
||||||
|
"Read from local clipboard": "从本地剪贴板读取",
|
||||||
|
"Send to remote clipboard": "发送到远程剪贴板",
|
||||||
|
"Copy to local clipboard": "复制到本地剪贴板",
|
||||||
|
"Edit clipboard content in the textarea below.": "在下面的文本区域中编辑剪贴板内容。",
|
||||||
|
"Full screen": "全屏",
|
||||||
|
"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):": "重新连接间隔 (ms):",
|
||||||
|
"Show dot when no cursor": "无光标时显示点",
|
||||||
|
"Logging:": "日志级别:",
|
||||||
|
"Version:": "版本:",
|
||||||
|
"Disconnect": "断开连接",
|
||||||
|
"Connect": "连接",
|
||||||
|
"Server identity": "智能体电脑身份",
|
||||||
|
"The server has provided the following identifying information:": "智能体电脑提供了以下识别信息:",
|
||||||
|
"Fingerprint:": "指纹:",
|
||||||
|
"Please verify that the information is correct and press \"Approve\". Otherwise press \"Reject\".": "请核实信息是否正确,并按 “同意”,否则按 “拒绝”。",
|
||||||
|
"Approve": "同意",
|
||||||
|
"Reject": "拒绝",
|
||||||
|
"Credentials": "凭证",
|
||||||
|
"Username:": "用户名:",
|
||||||
|
"Password:": "密码:",
|
||||||
|
"Send credentials": "发送凭证",
|
||||||
|
"Cancel": "取消",
|
||||||
|
"Password is required": "请提供密码",
|
||||||
|
"Disconnect timeout": "超时断开",
|
||||||
|
"viewport drag": "窗口拖动",
|
||||||
|
"Active Mouse Button": "启动鼠标按键",
|
||||||
|
"No mousebutton": "禁用鼠标按键",
|
||||||
|
"Left mousebutton": "鼠标左键",
|
||||||
|
"Middle mousebutton": "鼠标中键",
|
||||||
|
"Right mousebutton": "鼠标右键",
|
||||||
|
"Clear": "清除",
|
||||||
|
"Local Downscaling": "降低本地尺寸",
|
||||||
|
"Local Cursor": "本地光标",
|
||||||
|
"Canvas not supported.": "不支持 Canvas。"
|
||||||
|
}
|
||||||
69
qiming-noVNC/app/locale/zh_TW.json
Normal file
@@ -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": "取消"
|
||||||
|
}
|
||||||
206
qiming-noVNC/app/localization.js
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
/*
|
||||||
|
* noVNC: HTML5 VNC client
|
||||||
|
* Copyright (C) 2018 The noVNC authors
|
||||||
|
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||||
|
*
|
||||||
|
* See README.md for usage and integration instructions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Localization utilities
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class Localizer {
|
||||||
|
constructor() {
|
||||||
|
// Currently configured language
|
||||||
|
this.language = 'en';
|
||||||
|
|
||||||
|
// Current dictionary of translations
|
||||||
|
this._dictionary = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure suitable language based on user preferences
|
||||||
|
async setup(supportedLanguages, baseURL) {
|
||||||
|
this.language = 'en'; // Default: US English
|
||||||
|
this._dictionary = undefined;
|
||||||
|
|
||||||
|
this._setupLanguage(supportedLanguages);
|
||||||
|
await this._setupDictionary(baseURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
_setupLanguage(supportedLanguages) {
|
||||||
|
/*
|
||||||
|
* 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 (let i = 0;i < userLanguages.length;i++) {
|
||||||
|
const userLang = userLanguages[i]
|
||||||
|
.toLowerCase()
|
||||||
|
.replace("_", "-")
|
||||||
|
.split("-");
|
||||||
|
|
||||||
|
// First pass: perfect match
|
||||||
|
for (let j = 0; j < supportedLanguages.length; j++) {
|
||||||
|
const supLang = supportedLanguages[j]
|
||||||
|
.toLowerCase()
|
||||||
|
.replace("_", "-")
|
||||||
|
.split("-");
|
||||||
|
|
||||||
|
if (userLang[0] !== supLang[0]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (userLang[1] !== supLang[1]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.language = supportedLanguages[j];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second pass: English fallback
|
||||||
|
if (userLang[0] === 'en') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Third pass pass: other fallback
|
||||||
|
for (let j = 0;j < supportedLanguages.length;j++) {
|
||||||
|
const supLang = supportedLanguages[j]
|
||||||
|
.toLowerCase()
|
||||||
|
.replace("_", "-")
|
||||||
|
.split("-");
|
||||||
|
|
||||||
|
if (userLang[0] !== supLang[0]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (supLang[1] !== undefined) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.language = supportedLanguages[j];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async _setupDictionary(baseURL) {
|
||||||
|
if (baseURL) {
|
||||||
|
if (!baseURL.endsWith("/")) {
|
||||||
|
baseURL = baseURL + "/";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
baseURL = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.language === "en") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let response = await fetch(baseURL + this.language + ".json");
|
||||||
|
if (!response.ok) {
|
||||||
|
throw Error("" + response.status + " " + response.statusText);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._dictionary = await response.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve localised text
|
||||||
|
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() {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
function process(elem, enabled) {
|
||||||
|
function isAnyOf(searchElement, items) {
|
||||||
|
return items.indexOf(searchElement) !== -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function translateString(str) {
|
||||||
|
// We assume surrounding whitespace, and whitespace around line
|
||||||
|
// breaks is just for source formatting
|
||||||
|
str = str.split("\n").map(s => s.trim()).join(" ").trim();
|
||||||
|
return self.get(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
function translateAttribute(elem, attr) {
|
||||||
|
const str = translateString(elem.getAttribute(attr));
|
||||||
|
elem.setAttribute(attr, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
function translateTextNode(node) {
|
||||||
|
const str = translateString(node.data);
|
||||||
|
node.data = str;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elem.hasAttribute("translate")) {
|
||||||
|
if (isAnyOf(elem.getAttribute("translate"), ["", "yes"])) {
|
||||||
|
enabled = true;
|
||||||
|
} else if (isAnyOf(elem.getAttribute("translate"), ["no"])) {
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enabled) {
|
||||||
|
if (elem.hasAttribute("abbr") &&
|
||||||
|
elem.tagName === "TH") {
|
||||||
|
translateAttribute(elem, "abbr");
|
||||||
|
}
|
||||||
|
if (elem.hasAttribute("alt") &&
|
||||||
|
isAnyOf(elem.tagName, ["AREA", "IMG", "INPUT"])) {
|
||||||
|
translateAttribute(elem, "alt");
|
||||||
|
}
|
||||||
|
if (elem.hasAttribute("download") &&
|
||||||
|
isAnyOf(elem.tagName, ["A", "AREA"])) {
|
||||||
|
translateAttribute(elem, "download");
|
||||||
|
}
|
||||||
|
if (elem.hasAttribute("label") &&
|
||||||
|
isAnyOf(elem.tagName, ["MENUITEM", "MENU", "OPTGROUP",
|
||||||
|
"OPTION", "TRACK"])) {
|
||||||
|
translateAttribute(elem, "label");
|
||||||
|
}
|
||||||
|
// FIXME: Should update "lang"
|
||||||
|
if (elem.hasAttribute("placeholder") &&
|
||||||
|
isAnyOf(elem.tagName, ["INPUT", "TEXTAREA"])) {
|
||||||
|
translateAttribute(elem, "placeholder");
|
||||||
|
}
|
||||||
|
if (elem.hasAttribute("title")) {
|
||||||
|
translateAttribute(elem, "title");
|
||||||
|
}
|
||||||
|
if (elem.hasAttribute("value") &&
|
||||||
|
elem.tagName === "INPUT" &&
|
||||||
|
isAnyOf(elem.getAttribute("type"), ["reset", "button", "submit"])) {
|
||||||
|
translateAttribute(elem, "value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
translateTextNode(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
process(document.body, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const l10n = new Localizer();
|
||||||
|
export default l10n.get.bind(l10n);
|
||||||
4
qiming-noVNC/app/sounds/CREDITS
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
bell
|
||||||
|
Copyright: Dr. Richard Boulanger et al
|
||||||
|
URL: http://www.archive.org/details/Berklee44v12
|
||||||
|
License: CC-BY Attribution 3.0 Unported
|
||||||
BIN
qiming-noVNC/app/sounds/bell.mp3
Normal file
BIN
qiming-noVNC/app/sounds/bell.oga
Normal file
BIN
qiming-noVNC/app/styles/Orbitron700.ttf
Normal file
BIN
qiming-noVNC/app/styles/Orbitron700.woff
Normal file
1296
qiming-noVNC/app/styles/base.css
Normal file
30
qiming-noVNC/app/styles/constants.css
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* noVNC general CSS constant variables
|
||||||
|
* Copyright (C) 2025 The noVNC authors
|
||||||
|
* noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
|
||||||
|
* This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ---------- COLORS ----------- */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--novnc-grey: rgb(128, 128, 128);
|
||||||
|
--novnc-lightgrey: rgb(192, 192, 192);
|
||||||
|
--novnc-darkgrey: rgb(92, 92, 92);
|
||||||
|
|
||||||
|
/* Transparent to make button colors adapt to the background */
|
||||||
|
--novnc-buttongrey: rgba(192, 192, 192, 0.5);
|
||||||
|
|
||||||
|
--novnc-blue: rgb(110, 132, 163);
|
||||||
|
--novnc-lightblue: rgb(74, 144, 217);
|
||||||
|
--novnc-darkblue: rgb(83, 99, 122);
|
||||||
|
|
||||||
|
--novnc-green: rgb(0, 128, 0);
|
||||||
|
--novnc-yellow: rgb(255, 255, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------ MISC PROPERTIES ------ */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--input-xpadding: 1em;
|
||||||
|
}
|
||||||
628
qiming-noVNC/app/styles/input.css
Normal file
@@ -0,0 +1,628 @@
|
|||||||
|
/*
|
||||||
|
* noVNC general input element CSS
|
||||||
|
* Copyright (C) 2025 The noVNC authors
|
||||||
|
* noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
|
||||||
|
* This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ------- SHARED BETWEEN INPUT ELEMENTS -------- */
|
||||||
|
|
||||||
|
input,
|
||||||
|
textarea,
|
||||||
|
button,
|
||||||
|
select,
|
||||||
|
input::file-selector-button {
|
||||||
|
padding: 0.5em var(--input-xpadding);
|
||||||
|
border-radius: 6px;
|
||||||
|
appearance: none;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
|
/* Respect standard font settings */
|
||||||
|
font: inherit;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
input:disabled,
|
||||||
|
textarea:disabled,
|
||||||
|
button:disabled,
|
||||||
|
select:disabled,
|
||||||
|
label[disabled] {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus-visible,
|
||||||
|
textarea:focus-visible,
|
||||||
|
button:focus-visible,
|
||||||
|
select:focus-visible,
|
||||||
|
input:focus-visible::file-selector-button {
|
||||||
|
outline: 2px solid var(--novnc-lightblue);
|
||||||
|
outline-offset: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------- TEXT INPUT -------- */
|
||||||
|
|
||||||
|
input:not([type]),
|
||||||
|
input[type=date],
|
||||||
|
input[type=datetime-local],
|
||||||
|
input[type=email],
|
||||||
|
input[type=month],
|
||||||
|
input[type=number],
|
||||||
|
input[type=password],
|
||||||
|
input[type=search],
|
||||||
|
input[type=tel],
|
||||||
|
input[type=text],
|
||||||
|
input[type=time],
|
||||||
|
input[type=url],
|
||||||
|
input[type=week],
|
||||||
|
textarea {
|
||||||
|
border: 1px solid var(--novnc-lightgrey);
|
||||||
|
/* Account for borders on text inputs, buttons dont have borders */
|
||||||
|
padding: calc(0.5em - 1px) var(--input-xpadding);
|
||||||
|
}
|
||||||
|
input:not([type]):focus-visible,
|
||||||
|
input[type=date]:focus-visible,
|
||||||
|
input[type=datetime-local]:focus-visible,
|
||||||
|
input[type=email]:focus-visible,
|
||||||
|
input[type=month]:focus-visible,
|
||||||
|
input[type=number]:focus-visible,
|
||||||
|
input[type=password]:focus-visible,
|
||||||
|
input[type=search]:focus-visible,
|
||||||
|
input[type=tel]:focus-visible,
|
||||||
|
input[type=text]:focus-visible,
|
||||||
|
input[type=time]:focus-visible,
|
||||||
|
input[type=url]:focus-visible,
|
||||||
|
input[type=week]:focus-visible,
|
||||||
|
textarea:focus-visible {
|
||||||
|
outline-offset: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
margin: unset; /* Remove Firefox's built in margin */
|
||||||
|
/* Prevent layout from shifting when scrollbars show */
|
||||||
|
scrollbar-gutter: stable;
|
||||||
|
/* Make textareas show at minimum one line. This does not work when
|
||||||
|
using box-sizing border-box, in which case, vertical padding and
|
||||||
|
border width needs to be taken into account. */
|
||||||
|
min-height: 1lh;
|
||||||
|
vertical-align: baseline; /* Firefox gives "text-bottom" by default */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------- NUMBER PICKERS ------- */
|
||||||
|
|
||||||
|
/* We can't style the number spinner buttons:
|
||||||
|
https://github.com/w3c/csswg-drafts/issues/8777 */
|
||||||
|
input[type=number]::-webkit-inner-spin-button,
|
||||||
|
input[type=number]::-webkit-outer-spin-button {
|
||||||
|
/* Get rid of increase/decrease buttons in WebKit */
|
||||||
|
appearance: none;
|
||||||
|
}
|
||||||
|
input[type=number] {
|
||||||
|
/* Get rid of increase/decrease buttons in Firefox */
|
||||||
|
appearance: textfield;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------- BUTTON ACTIVATIONS -------- */
|
||||||
|
|
||||||
|
/* A color overlay that depends on the activation level. The level can then be
|
||||||
|
set for different states on an element, for example hover and click on a
|
||||||
|
<button>. */
|
||||||
|
input, button, select, option,
|
||||||
|
input::file-selector-button,
|
||||||
|
.button-activations {
|
||||||
|
--button-activation-level: 0;
|
||||||
|
/* Note that CSS variables aren't functions, beware when inheriting */
|
||||||
|
--button-activation-alpha: calc(0.08 * var(--button-activation-level));
|
||||||
|
/* FIXME: We want the image() function instead of the linear-gradient()
|
||||||
|
function below. But it's not supported in the browsers yet. */
|
||||||
|
--button-activation-overlay:
|
||||||
|
linear-gradient(rgba(0, 0, 0, var(--button-activation-alpha))
|
||||||
|
100%, transparent);
|
||||||
|
--button-activation-overlay-light:
|
||||||
|
linear-gradient(rgba(255, 255, 255, calc(0.23 * var(--button-activation-level)))
|
||||||
|
100%, transparent);
|
||||||
|
}
|
||||||
|
.button-activations {
|
||||||
|
background-image: var(--button-activation-overlay);
|
||||||
|
|
||||||
|
/* Disable Chrome's touch tap highlight to avoid conflicts with overlay */
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
}
|
||||||
|
/* When we want the light overlay on activations instead.
|
||||||
|
This is best used on elements with darker backgrounds. */
|
||||||
|
.button-activations.light-overlay {
|
||||||
|
background-image: var(--button-activation-overlay-light);
|
||||||
|
/* Can't use the normal blend mode since that gives washed out colors. */
|
||||||
|
/* FIXME: For elements with these activation overlays we'd like only
|
||||||
|
the luminosity to change. The proprty "background-blend-mode" set
|
||||||
|
to "luminosity" sounds good, but it doesn't work as intended,
|
||||||
|
see: https://bugzilla.mozilla.org/show_bug.cgi?id=1806417 */
|
||||||
|
background-blend-mode: overlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:hover, button:hover, select:hover, option:hover,
|
||||||
|
input::file-selector-button:hover,
|
||||||
|
.button-activations:hover {
|
||||||
|
--button-activation-level: 1;
|
||||||
|
}
|
||||||
|
/* Unfortunately we have to disable the :hover effect on touch devices,
|
||||||
|
otherwise the style lingers after tapping the button. */
|
||||||
|
@media (any-pointer: coarse) {
|
||||||
|
input:hover, button:hover, select:hover, option:hover,
|
||||||
|
input::file-selector-button:hover,
|
||||||
|
.button-activations:hover {
|
||||||
|
--button-activation-level: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input:active, button:active, select:active, option:active,
|
||||||
|
input::file-selector-button:active,
|
||||||
|
.button-activations:active {
|
||||||
|
--button-activation-level: 2;
|
||||||
|
}
|
||||||
|
input:disabled, button:disabled, select:disabled, select:disabled option,
|
||||||
|
input:disabled::file-selector-button,
|
||||||
|
.button-activations:disabled {
|
||||||
|
--button-activation-level: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------- BUTTONS -------- */
|
||||||
|
|
||||||
|
input[type=button],
|
||||||
|
input[type=color],
|
||||||
|
input[type=image],
|
||||||
|
input[type=reset],
|
||||||
|
input[type=submit],
|
||||||
|
input::file-selector-button,
|
||||||
|
button,
|
||||||
|
select {
|
||||||
|
min-width: 8em;
|
||||||
|
border: none;
|
||||||
|
color: black;
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: var(--novnc-buttongrey);
|
||||||
|
background-image: var(--button-activation-overlay);
|
||||||
|
cursor: pointer;
|
||||||
|
/* Disable Chrome's touch tap highlight */
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
}
|
||||||
|
input[type=button]:disabled,
|
||||||
|
input[type=color]:disabled,
|
||||||
|
input[type=image]:disabled,
|
||||||
|
input[type=reset]:disabled,
|
||||||
|
input[type=submit]:disabled,
|
||||||
|
input:disabled::file-selector-button,
|
||||||
|
button:disabled,
|
||||||
|
select:disabled {
|
||||||
|
/* See Firefox bug:
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1798304 */
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=button],
|
||||||
|
input[type=color],
|
||||||
|
input[type=reset],
|
||||||
|
input[type=submit] {
|
||||||
|
/* Workaround for text-overflow bugs in Firefox and Chromium:
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1800077
|
||||||
|
https://bugs.chromium.org/p/chromium/issues/detail?id=1383144 */
|
||||||
|
overflow: clip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------- COLOR PICKERS ------- */
|
||||||
|
|
||||||
|
input[type=color] {
|
||||||
|
min-width: unset;
|
||||||
|
box-sizing: content-box;
|
||||||
|
width: 1.4em;
|
||||||
|
height: 1.4em;
|
||||||
|
}
|
||||||
|
input[type=color]::-webkit-color-swatch-wrapper {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
/* -webkit-color-swatch & -moz-color-swatch cant be in a selector list:
|
||||||
|
https://bugs.chromium.org/p/chromium/issues/detail?id=1154623 */
|
||||||
|
input[type=color]::-webkit-color-swatch {
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
input[type=color]::-moz-color-swatch {
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- SHARED BETWEEN CHECKBOXES, RADIOBUTTONS AND THE TOGGLE CLASS -- */
|
||||||
|
|
||||||
|
input[type=radio],
|
||||||
|
input[type=checkbox] {
|
||||||
|
display: inline-flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background-color: var(--novnc-buttongrey);
|
||||||
|
background-image: var(--button-activation-overlay);
|
||||||
|
/* Disable Chrome's touch tap highlight to avoid conflicts with overlay */
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
width: 16px;
|
||||||
|
--checkradio-height: 16px;
|
||||||
|
height: var(--checkradio-height);
|
||||||
|
padding: 0;
|
||||||
|
margin: 0 6px 0 0;
|
||||||
|
/* Don't have transitions for outline in order to be consistent
|
||||||
|
with other elements */
|
||||||
|
transition: all 0.2s, outline-color 0s, outline-offset 0s;
|
||||||
|
|
||||||
|
/* A transparent outline in order to work around a graphical clipping issue
|
||||||
|
in WebKit. See bug: https://bugs.webkit.org/show_bug.cgi?id=256003 */
|
||||||
|
outline: 1px solid transparent;
|
||||||
|
position: relative; /* Since ::before & ::after are absolute positioned */
|
||||||
|
|
||||||
|
/* We want to align with the middle of capital letters, this requires
|
||||||
|
a workaround. The default behavior is to align the bottom of the element
|
||||||
|
on top of the text baseline, this is too far up.
|
||||||
|
We want to push the element down half the difference in height between
|
||||||
|
it and a capital X. In our font, the height of a capital "X" is 0.698em.
|
||||||
|
*/
|
||||||
|
vertical-align: calc(0px - (var(--checkradio-height) - 0.698em) / 2);
|
||||||
|
/* FIXME: Could write 1cap instead of 0.698em, but it's only supported in
|
||||||
|
Firefox as of 2023 */
|
||||||
|
/* FIXME: We probably want to use round() here, see bug 8148 */
|
||||||
|
}
|
||||||
|
input[type=radio]:focus-visible,
|
||||||
|
input[type=checkbox]:focus-visible {
|
||||||
|
outline-color: var(--novnc-lightblue);
|
||||||
|
}
|
||||||
|
input[type=checkbox]::before,
|
||||||
|
input[type=checkbox]:not(.toggle)::after,
|
||||||
|
input[type=radio]::before,
|
||||||
|
input[type=radio]::after {
|
||||||
|
content: "";
|
||||||
|
display: block; /* width & height doesn't work on inline elements */
|
||||||
|
transition: inherit;
|
||||||
|
/* Let's prevent the pseudo-elements from taking up layout space so that
|
||||||
|
the ::before and ::after pseudo-elements can be in the same place. This
|
||||||
|
is also required for vertical-align: baseline to work like we want it to
|
||||||
|
on radio/checkboxes. If the pseudo-elements take up layout space, the
|
||||||
|
baseline of text inside them will be used instead. */
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
input[type=checkbox]:not(.toggle)::after,
|
||||||
|
input[type=radio]::after {
|
||||||
|
width: 10px;
|
||||||
|
height: 2px;
|
||||||
|
background-color: transparent;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------- CHECKBOXES ------- */
|
||||||
|
|
||||||
|
input[type=checkbox]:not(.toggle) {
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
input[type=checkbox]:not(.toggle):checked,
|
||||||
|
input[type=checkbox]:not(.toggle):indeterminate {
|
||||||
|
background-color: var(--novnc-blue);
|
||||||
|
background-image: var(--button-activation-overlay-light);
|
||||||
|
background-blend-mode: overlay;
|
||||||
|
}
|
||||||
|
input[type=checkbox]:not(.toggle)::before {
|
||||||
|
width: 25%;
|
||||||
|
height: 55%;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: transparent;
|
||||||
|
border-width: 0 2px 2px 0;
|
||||||
|
border-radius: 1px;
|
||||||
|
transform: translateY(-1px) rotate(35deg);
|
||||||
|
}
|
||||||
|
input[type=checkbox]:not(.toggle):checked::before {
|
||||||
|
border-color: white;
|
||||||
|
}
|
||||||
|
input[type=checkbox]:not(.toggle):indeterminate::after {
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------- RADIO BUTTONS ------- */
|
||||||
|
|
||||||
|
input[type=radio] {
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 1px solid transparent; /* To ensure a smooth transition */
|
||||||
|
}
|
||||||
|
input[type=radio]:checked {
|
||||||
|
border: 4px solid var(--novnc-blue);
|
||||||
|
background-color: white;
|
||||||
|
/* button-activation-overlay should be removed from the radio
|
||||||
|
element to not interfere with button-activation-overlay-light
|
||||||
|
that is set on the ::before element. */
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
input[type=radio]::before {
|
||||||
|
width: inherit;
|
||||||
|
height: inherit;
|
||||||
|
border-radius: inherit;
|
||||||
|
/* We can achieve the highlight overlay effect on border colors by
|
||||||
|
setting button-activation-overlay-light on an element that stays
|
||||||
|
on top (z-axis) of the element with a border. */
|
||||||
|
background-image: var(--button-activation-overlay-light);
|
||||||
|
mix-blend-mode: overlay;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
input[type=radio]:checked::before {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
input[type=radio]:indeterminate::after {
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------- TOGGLE SWITCHES ------- */
|
||||||
|
|
||||||
|
/* These are meant to be used instead of checkboxes in some cases. If all of
|
||||||
|
the following critera are true you should use a toggle switch:
|
||||||
|
|
||||||
|
* The choice is a simple ON/OFF or ENABLE/DISABLE
|
||||||
|
* The choice doesn't give the feeling of "I agree" or "I confirm"
|
||||||
|
* There are not multiple related & grouped options
|
||||||
|
*/
|
||||||
|
|
||||||
|
input[type=checkbox].toggle {
|
||||||
|
display: inline-block;
|
||||||
|
--checkradio-height: 18px; /* Height value used in calc, see above */
|
||||||
|
width: 31px;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
border-radius: 9px;
|
||||||
|
}
|
||||||
|
input[type=checkbox].toggle:disabled {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
input[type=checkbox].toggle:indeterminate {
|
||||||
|
background-color: var(--novnc-buttongrey);
|
||||||
|
background-image: var(--button-activation-overlay);
|
||||||
|
}
|
||||||
|
input[type=checkbox].toggle:checked {
|
||||||
|
background-color: var(--novnc-blue);
|
||||||
|
background-image: var(--button-activation-overlay-light);
|
||||||
|
background-blend-mode: overlay;
|
||||||
|
}
|
||||||
|
input[type=checkbox].toggle::before {
|
||||||
|
--circle-diameter: 10px;
|
||||||
|
--circle-offset: 4px;
|
||||||
|
width: var(--circle-diameter);
|
||||||
|
height: var(--circle-diameter);
|
||||||
|
top: var(--circle-offset);
|
||||||
|
left: var(--circle-offset);
|
||||||
|
background: white;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
input[type=checkbox].toggle:checked::before {
|
||||||
|
left: calc(100% - var(--circle-offset) - var(--circle-diameter));
|
||||||
|
}
|
||||||
|
input[type=checkbox].toggle:indeterminate::before {
|
||||||
|
left: calc(50% - var(--circle-diameter) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------- RANGE SLIDERS ------- */
|
||||||
|
|
||||||
|
input[type=range] {
|
||||||
|
border: unset;
|
||||||
|
border-radius: 8px;
|
||||||
|
height: 15px;
|
||||||
|
padding: 0;
|
||||||
|
background: transparent;
|
||||||
|
/* Needed to get properly rounded corners on -moz-range-progress
|
||||||
|
when the thumb is all the way to the right. Without overflow
|
||||||
|
hidden, the pointy edges of the progress track shows to the
|
||||||
|
right of the thumb. */
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
@supports selector(::-webkit-slider-thumb) {
|
||||||
|
input[type=range] {
|
||||||
|
/* Needs a fixed width to match clip-path */
|
||||||
|
width: 125px;
|
||||||
|
/* overflow: hidden is not ideal for hiding the left part of the box
|
||||||
|
shadow of -webkit-slider-thumb since it doesn't match the smaller
|
||||||
|
border-radius of the progress track. The below clip-path has two
|
||||||
|
circular sides to make the ends of the track have correctly rounded
|
||||||
|
corners. The clip path shape looks something like this:
|
||||||
|
|
||||||
|
+-------------------------------+
|
||||||
|
/---| |---\
|
||||||
|
| |
|
||||||
|
\---| |---/
|
||||||
|
+-------------------------------+
|
||||||
|
|
||||||
|
The larger middle part of the clip path is made to have room for the
|
||||||
|
thumb. By using margins on the track, we prevent the thumb from
|
||||||
|
touching the ends of the track.
|
||||||
|
*/
|
||||||
|
clip-path: path(' \
|
||||||
|
M 4.5 3 \
|
||||||
|
L 4.5 0 \
|
||||||
|
L 120.5 0 \
|
||||||
|
L 120.5 3 \
|
||||||
|
A 1 1 0 0 1 120.5 12 \
|
||||||
|
L 120.5 15 \
|
||||||
|
L 4.5 15 \
|
||||||
|
L 4.5 12 \
|
||||||
|
A 1 1 0 0 1 4.5 3 \
|
||||||
|
');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input[type=range]:hover {
|
||||||
|
cursor: grab;
|
||||||
|
}
|
||||||
|
input[type=range]:active {
|
||||||
|
cursor: grabbing;
|
||||||
|
}
|
||||||
|
input[type=range]:disabled {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
input[type=range]:focus-visible {
|
||||||
|
clip-path: none; /* Otherwise it hides the outline */
|
||||||
|
}
|
||||||
|
/* -webkit-slider.. & -moz-range.. cant be in selector lists:
|
||||||
|
https://bugs.chromium.org/p/chromium/issues/detail?id=1154623 */
|
||||||
|
input[type=range]::-webkit-slider-runnable-track {
|
||||||
|
background-color: var(--novnc-buttongrey);
|
||||||
|
height: 7px;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin: 0 3px;
|
||||||
|
}
|
||||||
|
input[type=range]::-moz-range-track {
|
||||||
|
background-color: var(--novnc-buttongrey);
|
||||||
|
height: 7px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
input[type=range]::-moz-range-progress {
|
||||||
|
background-color: var(--novnc-blue);
|
||||||
|
height: 9px;
|
||||||
|
/* Needs rounded corners only on the left side. Otherwise the rounding of
|
||||||
|
the progress track starts before the thumb, when the thumb is close to
|
||||||
|
the left edge. */
|
||||||
|
border-radius: 5px 0 0 5px;
|
||||||
|
}
|
||||||
|
input[type=range]::-webkit-slider-thumb {
|
||||||
|
appearance: none;
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: white;
|
||||||
|
background-image: var(--button-activation-overlay);
|
||||||
|
/* Disable Chrome's touch tap highlight to avoid conflicts with overlay */
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
border: 3px solid var(--novnc-blue);
|
||||||
|
margin-top: -4px; /* (track height / 2) - (thumb height /2) */
|
||||||
|
|
||||||
|
/* Since there is no way to style the left part of the range track in
|
||||||
|
webkit, we add a large shadow (1000px wide) to the left of the thumb and
|
||||||
|
then crop it with a clip-path shaped like this:
|
||||||
|
___
|
||||||
|
+-------------------/ \
|
||||||
|
| progress |Thumb|
|
||||||
|
+-------------------\ ___ /
|
||||||
|
|
||||||
|
The large left part of the shadow is clipped by another clip-path on on
|
||||||
|
the main range input element. */
|
||||||
|
/* FIXME: We can remove the box shadow workaround when this is standardized:
|
||||||
|
https://github.com/w3c/csswg-drafts/issues/4410 */
|
||||||
|
|
||||||
|
box-shadow: calc(-100vw - 8px) 0 0 100vw var(--novnc-blue);
|
||||||
|
clip-path: path(' \
|
||||||
|
M -1000 3 \
|
||||||
|
L 3 3 \
|
||||||
|
L 15 7.5 \
|
||||||
|
A 1 1 0 0 1 0 7.5 \
|
||||||
|
A 1 1 0 0 1 15 7.5 \
|
||||||
|
L 3 12 \
|
||||||
|
L -1000 12 Z \
|
||||||
|
');
|
||||||
|
}
|
||||||
|
input[type=range]::-moz-range-thumb {
|
||||||
|
appearance: none;
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: white;
|
||||||
|
background-image: var(--button-activation-overlay);
|
||||||
|
border: 3px solid var(--novnc-blue);
|
||||||
|
margin-top: -7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------- FILE CHOOSERS ------- */
|
||||||
|
|
||||||
|
input[type=file] {
|
||||||
|
background-image: none;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
input::file-selector-button {
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
input[type=file]:focus-visible {
|
||||||
|
outline: none; /* We outline the button instead of the entire element */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------- SELECT BUTTONS ------- */
|
||||||
|
|
||||||
|
select {
|
||||||
|
--select-arrow: url('data:image/svg+xml;utf8, \
|
||||||
|
<svg width="11" height="6" version="1.1" viewBox="0 0 11 6" \
|
||||||
|
xmlns="http://www.w3.org/2000/svg"> \
|
||||||
|
<path d="m10.5.5-5 5-5-5" fill="none" \
|
||||||
|
stroke="black" stroke-width="1.5" \
|
||||||
|
stroke-linecap="round" stroke-linejoin="round"/> \
|
||||||
|
</svg>');
|
||||||
|
|
||||||
|
/* FIXME: A bug in Firefox, requires a workaround for the background:
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1810958 */
|
||||||
|
/* The dropdown list will show the select element's background above and
|
||||||
|
below the options in Firefox. We want the entire dropdown to be white. */
|
||||||
|
background-color: white;
|
||||||
|
/* However, we don't want the select element to actually show a white
|
||||||
|
background, so let's place a gradient above it with the color we want. */
|
||||||
|
--grey-background: linear-gradient(var(--novnc-buttongrey) 100%,
|
||||||
|
transparent);
|
||||||
|
background-image:
|
||||||
|
var(--select-arrow),
|
||||||
|
var(--button-activation-overlay),
|
||||||
|
var(--grey-background);
|
||||||
|
background-position: calc(100% - var(--input-xpadding)), left top, left top;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
padding-right: calc(2*var(--input-xpadding) + 11px);
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
/* FIXME: :active isn't set when the <select> is opened in Firefox:
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1805406 */
|
||||||
|
select:active {
|
||||||
|
/* Rotated arrow */
|
||||||
|
background-image: url('data:image/svg+xml;utf8, \
|
||||||
|
<svg width="11" height="6" version="1.1" viewBox="0 0 11 6" \
|
||||||
|
xmlns="http://www.w3.org/2000/svg" transform="rotate(180)"> \
|
||||||
|
<path d="m10.5.5-5 5-5-5" fill="none" \
|
||||||
|
stroke="black" stroke-width="1.5" \
|
||||||
|
stroke-linecap="round" stroke-linejoin="round"/> \
|
||||||
|
</svg>'),
|
||||||
|
var(--button-activation-overlay),
|
||||||
|
var(--grey-background);
|
||||||
|
}
|
||||||
|
select:disabled {
|
||||||
|
background-image:
|
||||||
|
var(--select-arrow),
|
||||||
|
var(--grey-background);
|
||||||
|
}
|
||||||
|
/* Note that styling for <option> doesn't work in all browsers
|
||||||
|
since its often drawn directly by the OS. We are generally very
|
||||||
|
limited in what we can change here. */
|
||||||
|
option {
|
||||||
|
/* Prevent Chrome from inheriting background-color from the <select> */
|
||||||
|
background-color: white;
|
||||||
|
color: black;
|
||||||
|
font-weight: normal;
|
||||||
|
background-image: var(--button-activation-overlay);
|
||||||
|
}
|
||||||
|
option:checked {
|
||||||
|
background-color: var(--novnc-lightgrey);
|
||||||
|
}
|
||||||
|
/* Change the look when the <select> isn't used as a dropdown. When "size"
|
||||||
|
or "multiple" are set, these elements behaves more like lists. */
|
||||||
|
select[size]:not([size="1"]), select[multiple] {
|
||||||
|
background-color: white;
|
||||||
|
background-image: unset; /* Don't show the arrow and other gradients */
|
||||||
|
border: 1px solid var(--novnc-lightgrey);
|
||||||
|
padding: 0;
|
||||||
|
font-weight: normal; /* Without this, options get bold font in WebKit. */
|
||||||
|
|
||||||
|
/* As an exception to the "list"-look, multi-selects in Chrome on Android,
|
||||||
|
and Safari on iOS, are unfortunately designed to be shown as a single
|
||||||
|
line. We can mitigate this inconsistency by at least fixing the height
|
||||||
|
here. By setting a min-height that matches other input elements, it
|
||||||
|
doesn't look too much out of place:
|
||||||
|
(1px border * 2) + (6.5px padding * 2) + 24px line-height = 39px */
|
||||||
|
min-height: 39px;
|
||||||
|
}
|
||||||
|
select[size]:not([size="1"]):focus-visible,
|
||||||
|
select[multiple]:focus-visible {
|
||||||
|
/* Text input style focus-visible highlight */
|
||||||
|
outline-offset: -1px;
|
||||||
|
}
|
||||||
|
select[size]:not([size="1"]) option, select[multiple] option {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
padding: 4px var(--input-xpadding);
|
||||||
|
}
|
||||||
2371
qiming-noVNC/app/ui.js
Normal file
194
qiming-noVNC/app/vendor/opus-decoder.min.js
vendored
Normal file
250
qiming-noVNC/app/webutil.js
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
/*
|
||||||
|
* 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 '../core/util/logging.js';
|
||||||
|
|
||||||
|
// init log level reading the logging HTTP param
|
||||||
|
export function initLogging(level) {
|
||||||
|
"use strict";
|
||||||
|
if (typeof level !== "undefined") {
|
||||||
|
Log.initLogging(level);
|
||||||
|
} else {
|
||||||
|
const param = document.location.href.match(/logging=([A-Za-z0-9._-]*)/);
|
||||||
|
Log.initLogging(param || undefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a query string variable
|
||||||
|
// 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=secretvalue
|
||||||
|
//
|
||||||
|
// Even mixing public and non public parameters will work:
|
||||||
|
// https://www.example.com?nonsecretparam=example.com#password=secretvalue
|
||||||
|
export function getQueryVar(name, defVal) {
|
||||||
|
"use strict";
|
||||||
|
const re = new RegExp('.*[?&]' + name + '=([^&#]*)'),
|
||||||
|
match = document.location.href.match(re);
|
||||||
|
if (typeof defVal === 'undefined') { defVal = null; }
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
return decodeURIComponent(match[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return defVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a hash fragment variable
|
||||||
|
export function getHashVar(name, defVal) {
|
||||||
|
"use strict";
|
||||||
|
const re = new RegExp('.*[&#]' + name + '=([^&]*)'),
|
||||||
|
match = document.location.hash.match(re);
|
||||||
|
if (typeof defVal === 'undefined') { defVal = null; }
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
return decodeURIComponent(match[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return defVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a variable from the fragment or the query string
|
||||||
|
// Fragment takes precedence
|
||||||
|
export function getConfigVar(name, defVal) {
|
||||||
|
"use strict";
|
||||||
|
const val = getHashVar(name);
|
||||||
|
|
||||||
|
if (val === null) {
|
||||||
|
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) {
|
||||||
|
"use strict";
|
||||||
|
let date, expires;
|
||||||
|
if (days) {
|
||||||
|
date = new Date();
|
||||||
|
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||||
|
expires = "; expires=" + date.toGMTString();
|
||||||
|
} else {
|
||||||
|
expires = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
let secure;
|
||||||
|
if (document.location.protocol === "https:") {
|
||||||
|
secure = "; secure";
|
||||||
|
} else {
|
||||||
|
secure = "";
|
||||||
|
}
|
||||||
|
document.cookie = name + "=" + value + expires + "; path=/" + secure;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function readCookie(name, defaultValue) {
|
||||||
|
"use strict";
|
||||||
|
const nameEQ = name + "=";
|
||||||
|
const ca = document.cookie.split(';');
|
||||||
|
|
||||||
|
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) {
|
||||||
|
"use strict";
|
||||||
|
createCookie(name, "", -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setting handling.
|
||||||
|
*/
|
||||||
|
|
||||||
|
let settings = {};
|
||||||
|
|
||||||
|
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) {
|
||||||
|
"use strict";
|
||||||
|
if (settings[name] === value) return;
|
||||||
|
settings[name] = value;
|
||||||
|
if (window.chrome && window.chrome.storage) {
|
||||||
|
window.chrome.storage.sync.set(settings);
|
||||||
|
} else {
|
||||||
|
localStorageSet(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function readSetting(name, defaultValue) {
|
||||||
|
"use strict";
|
||||||
|
let value;
|
||||||
|
if ((name in settings) || (window.chrome && window.chrome.storage)) {
|
||||||
|
value = settings[name];
|
||||||
|
} else {
|
||||||
|
value = localStorageGet(name);
|
||||||
|
settings[name] = value;
|
||||||
|
}
|
||||||
|
if (typeof value === "undefined") {
|
||||||
|
value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value === null && typeof defaultValue !== "undefined") {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
} else {
|
||||||
|
localStorageRemove(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let loggedMsgs = [];
|
||||||
|
function logOnce(msg, level = "warn") {
|
||||||
|
if (!loggedMsgs.includes(msg)) {
|
||||||
|
switch (level) {
|
||||||
|
case "error":
|
||||||
|
Log.Error(msg);
|
||||||
|
break;
|
||||||
|
case "warn":
|
||||||
|
Log.Warn(msg);
|
||||||
|
break;
|
||||||
|
case "debug":
|
||||||
|
Log.Debug(msg);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.Info(msg);
|
||||||
|
}
|
||||||
|
loggedMsgs.push(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let cookiesMsg = "Couldn't access noVNC settings, are cookies disabled?";
|
||||||
|
|
||||||
|
function localStorageGet(name) {
|
||||||
|
let r;
|
||||||
|
try {
|
||||||
|
r = localStorage.getItem(name);
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof DOMException) {
|
||||||
|
logOnce(cookiesMsg);
|
||||||
|
logOnce("'localStorage.getItem(" + name + ")' failed: " + e,
|
||||||
|
"debug");
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
function localStorageSet(name, value) {
|
||||||
|
try {
|
||||||
|
localStorage.setItem(name, value);
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof DOMException) {
|
||||||
|
logOnce(cookiesMsg);
|
||||||
|
logOnce("'localStorage.setItem(" + name + "," + value +
|
||||||
|
")' failed: " + e, "debug");
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function localStorageRemove(name) {
|
||||||
|
try {
|
||||||
|
localStorage.removeItem(name);
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof DOMException) {
|
||||||
|
logOnce(cookiesMsg);
|
||||||
|
logOnce("'localStorage.removeItem(" + name + ")' failed: " + e,
|
||||||
|
"debug");
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
104
qiming-noVNC/core/base64.js
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
// From: http://hg.mozilla.org/mozilla-central/raw-file/ec10630b1a54/js/src/devtools/jint/sunspider/string-base64.js
|
||||||
|
|
||||||
|
import * as Log from './util/logging.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
/* Convert data (an array of integers) to a Base64 string. */
|
||||||
|
toBase64Table: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split(''),
|
||||||
|
base64Pad: '=',
|
||||||
|
|
||||||
|
encode(data) {
|
||||||
|
"use strict";
|
||||||
|
let result = '';
|
||||||
|
const length = data.length;
|
||||||
|
const lengthpad = (length % 3);
|
||||||
|
// Convert every three bytes to 4 ascii characters.
|
||||||
|
|
||||||
|
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.
|
||||||
|
const j = length - lengthpad;
|
||||||
|
if (lengthpad === 2) {
|
||||||
|
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) {
|
||||||
|
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 */
|
||||||
|
/* 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,
|
||||||
|
52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1,
|
||||||
|
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
|
||||||
|
15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
|
||||||
|
-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(data, offset = 0) {
|
||||||
|
let dataLength = data.indexOf('=') - offset;
|
||||||
|
if (dataLength < 0) { dataLength = data.length - offset; }
|
||||||
|
|
||||||
|
/* Every four characters is 3 resulting numbers */
|
||||||
|
const resultLength = (dataLength >> 2) * 3 + Math.floor((dataLength % 4) / 1.5);
|
||||||
|
const result = new Array(resultLength);
|
||||||
|
|
||||||
|
// Convert one by one.
|
||||||
|
|
||||||
|
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);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect data into leftdata, update bitcount
|
||||||
|
leftdata = (leftdata << 6) | c;
|
||||||
|
leftbits += 6;
|
||||||
|
|
||||||
|
// If we have 8 or more bits, append 8 bits to the result
|
||||||
|
if (leftbits >= 8) {
|
||||||
|
leftbits -= 8;
|
||||||
|
// Append if not padding.
|
||||||
|
if (!padding) {
|
||||||
|
result[idx++] = (leftdata >> leftbits) & 0xff;
|
||||||
|
}
|
||||||
|
leftdata &= (1 << leftbits) - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are any bits left, the base64 string was corrupted
|
||||||
|
if (leftbits) {
|
||||||
|
const err = new Error('Corrupted base64 string');
|
||||||
|
err.name = 'Base64-Error';
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}; /* End of Base64 namespace */
|
||||||
178
qiming-noVNC/core/crypto/aes.js
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
export class AESECBCipher {
|
||||||
|
constructor() {
|
||||||
|
this._key = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
get algorithm() {
|
||||||
|
return { name: "AES-ECB" };
|
||||||
|
}
|
||||||
|
|
||||||
|
static async importKey(key, _algorithm, extractable, keyUsages) {
|
||||||
|
const cipher = new AESECBCipher;
|
||||||
|
await cipher._importKey(key, extractable, keyUsages);
|
||||||
|
return cipher;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _importKey(key, extractable, keyUsages) {
|
||||||
|
this._key = await window.crypto.subtle.importKey(
|
||||||
|
"raw", key, {name: "AES-CBC"}, extractable, keyUsages);
|
||||||
|
}
|
||||||
|
|
||||||
|
async encrypt(_algorithm, plaintext) {
|
||||||
|
const x = new Uint8Array(plaintext);
|
||||||
|
if (x.length % 16 !== 0 || this._key === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const n = x.length / 16;
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
const y = new Uint8Array(await window.crypto.subtle.encrypt({
|
||||||
|
name: "AES-CBC",
|
||||||
|
iv: new Uint8Array(16),
|
||||||
|
}, this._key, x.slice(i * 16, i * 16 + 16))).slice(0, 16);
|
||||||
|
x.set(y, i * 16);
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AESEAXCipher {
|
||||||
|
constructor() {
|
||||||
|
this._rawKey = null;
|
||||||
|
this._ctrKey = null;
|
||||||
|
this._cbcKey = null;
|
||||||
|
this._zeroBlock = new Uint8Array(16);
|
||||||
|
this._prefixBlock0 = this._zeroBlock;
|
||||||
|
this._prefixBlock1 = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
|
||||||
|
this._prefixBlock2 = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
get algorithm() {
|
||||||
|
return { name: "AES-EAX" };
|
||||||
|
}
|
||||||
|
|
||||||
|
async _encryptBlock(block) {
|
||||||
|
const encrypted = await window.crypto.subtle.encrypt({
|
||||||
|
name: "AES-CBC",
|
||||||
|
iv: this._zeroBlock,
|
||||||
|
}, this._cbcKey, block);
|
||||||
|
return new Uint8Array(encrypted).slice(0, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
async _initCMAC() {
|
||||||
|
const k1 = await this._encryptBlock(this._zeroBlock);
|
||||||
|
const k2 = new Uint8Array(16);
|
||||||
|
const v = k1[0] >>> 6;
|
||||||
|
for (let i = 0; i < 15; i++) {
|
||||||
|
k2[i] = (k1[i + 1] >> 6) | (k1[i] << 2);
|
||||||
|
k1[i] = (k1[i + 1] >> 7) | (k1[i] << 1);
|
||||||
|
}
|
||||||
|
const lut = [0x0, 0x87, 0x0e, 0x89];
|
||||||
|
k2[14] ^= v >>> 1;
|
||||||
|
k2[15] = (k1[15] << 2) ^ lut[v];
|
||||||
|
k1[15] = (k1[15] << 1) ^ lut[v >> 1];
|
||||||
|
this._k1 = k1;
|
||||||
|
this._k2 = k2;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _encryptCTR(data, counter) {
|
||||||
|
const encrypted = await window.crypto.subtle.encrypt({
|
||||||
|
name: "AES-CTR",
|
||||||
|
counter: counter,
|
||||||
|
length: 128
|
||||||
|
}, this._ctrKey, data);
|
||||||
|
return new Uint8Array(encrypted);
|
||||||
|
}
|
||||||
|
|
||||||
|
async _decryptCTR(data, counter) {
|
||||||
|
const decrypted = await window.crypto.subtle.decrypt({
|
||||||
|
name: "AES-CTR",
|
||||||
|
counter: counter,
|
||||||
|
length: 128
|
||||||
|
}, this._ctrKey, data);
|
||||||
|
return new Uint8Array(decrypted);
|
||||||
|
}
|
||||||
|
|
||||||
|
async _computeCMAC(data, prefixBlock) {
|
||||||
|
if (prefixBlock.length !== 16) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const n = Math.floor(data.length / 16);
|
||||||
|
const m = Math.ceil(data.length / 16);
|
||||||
|
const r = data.length - n * 16;
|
||||||
|
const cbcData = new Uint8Array((m + 1) * 16);
|
||||||
|
cbcData.set(prefixBlock);
|
||||||
|
cbcData.set(data, 16);
|
||||||
|
if (r === 0) {
|
||||||
|
for (let i = 0; i < 16; i++) {
|
||||||
|
cbcData[n * 16 + i] ^= this._k1[i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cbcData[(n + 1) * 16 + r] = 0x80;
|
||||||
|
for (let i = 0; i < 16; i++) {
|
||||||
|
cbcData[(n + 1) * 16 + i] ^= this._k2[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let cbcEncrypted = await window.crypto.subtle.encrypt({
|
||||||
|
name: "AES-CBC",
|
||||||
|
iv: this._zeroBlock,
|
||||||
|
}, this._cbcKey, cbcData);
|
||||||
|
|
||||||
|
cbcEncrypted = new Uint8Array(cbcEncrypted);
|
||||||
|
const mac = cbcEncrypted.slice(cbcEncrypted.length - 32, cbcEncrypted.length - 16);
|
||||||
|
return mac;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async importKey(key, _algorithm, _extractable, _keyUsages) {
|
||||||
|
const cipher = new AESEAXCipher;
|
||||||
|
await cipher._importKey(key);
|
||||||
|
return cipher;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _importKey(key) {
|
||||||
|
this._rawKey = key;
|
||||||
|
this._ctrKey = await window.crypto.subtle.importKey(
|
||||||
|
"raw", key, {name: "AES-CTR"}, false, ["encrypt", "decrypt"]);
|
||||||
|
this._cbcKey = await window.crypto.subtle.importKey(
|
||||||
|
"raw", key, {name: "AES-CBC"}, false, ["encrypt"]);
|
||||||
|
await this._initCMAC();
|
||||||
|
}
|
||||||
|
|
||||||
|
async encrypt(algorithm, message) {
|
||||||
|
const ad = algorithm.additionalData;
|
||||||
|
const nonce = algorithm.iv;
|
||||||
|
const nCMAC = await this._computeCMAC(nonce, this._prefixBlock0);
|
||||||
|
const encrypted = await this._encryptCTR(message, nCMAC);
|
||||||
|
const adCMAC = await this._computeCMAC(ad, this._prefixBlock1);
|
||||||
|
const mac = await this._computeCMAC(encrypted, this._prefixBlock2);
|
||||||
|
for (let i = 0; i < 16; i++) {
|
||||||
|
mac[i] ^= nCMAC[i] ^ adCMAC[i];
|
||||||
|
}
|
||||||
|
const res = new Uint8Array(16 + encrypted.length);
|
||||||
|
res.set(encrypted);
|
||||||
|
res.set(mac, encrypted.length);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
async decrypt(algorithm, data) {
|
||||||
|
const encrypted = data.slice(0, data.length - 16);
|
||||||
|
const ad = algorithm.additionalData;
|
||||||
|
const nonce = algorithm.iv;
|
||||||
|
const mac = data.slice(data.length - 16);
|
||||||
|
const nCMAC = await this._computeCMAC(nonce, this._prefixBlock0);
|
||||||
|
const adCMAC = await this._computeCMAC(ad, this._prefixBlock1);
|
||||||
|
const computedMac = await this._computeCMAC(encrypted, this._prefixBlock2);
|
||||||
|
for (let i = 0; i < 16; i++) {
|
||||||
|
computedMac[i] ^= nCMAC[i] ^ adCMAC[i];
|
||||||
|
}
|
||||||
|
if (computedMac.length !== mac.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < mac.length; i++) {
|
||||||
|
if (computedMac[i] !== mac[i]) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const res = await this._decryptCTR(encrypted, nCMAC);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
34
qiming-noVNC/core/crypto/bigint.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
export function modPow(b, e, m) {
|
||||||
|
let r = 1n;
|
||||||
|
b = b % m;
|
||||||
|
while (e > 0n) {
|
||||||
|
if ((e & 1n) === 1n) {
|
||||||
|
r = (r * b) % m;
|
||||||
|
}
|
||||||
|
e = e >> 1n;
|
||||||
|
b = (b * b) % m;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bigIntToU8Array(bigint, padLength=0) {
|
||||||
|
let hex = bigint.toString(16);
|
||||||
|
if (padLength === 0) {
|
||||||
|
padLength = Math.ceil(hex.length / 2);
|
||||||
|
}
|
||||||
|
hex = hex.padStart(padLength * 2, '0');
|
||||||
|
const length = hex.length / 2;
|
||||||
|
const arr = new Uint8Array(length);
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
arr[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function u8ArrayToBigInt(arr) {
|
||||||
|
let hex = '0x';
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
hex += arr[i].toString(16).padStart(2, '0');
|
||||||
|
}
|
||||||
|
return BigInt(hex);
|
||||||
|
}
|
||||||
90
qiming-noVNC/core/crypto/crypto.js
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
import { AESECBCipher, AESEAXCipher } from "./aes.js";
|
||||||
|
import { DESCBCCipher, DESECBCipher } from "./des.js";
|
||||||
|
import { RSACipher } from "./rsa.js";
|
||||||
|
import { DHCipher } from "./dh.js";
|
||||||
|
import { MD5 } from "./md5.js";
|
||||||
|
|
||||||
|
// A single interface for the cryptographic algorithms not supported by SubtleCrypto.
|
||||||
|
// Both synchronous and asynchronous implmentations are allowed.
|
||||||
|
class LegacyCrypto {
|
||||||
|
constructor() {
|
||||||
|
this._algorithms = {
|
||||||
|
"AES-ECB": AESECBCipher,
|
||||||
|
"AES-EAX": AESEAXCipher,
|
||||||
|
"DES-ECB": DESECBCipher,
|
||||||
|
"DES-CBC": DESCBCCipher,
|
||||||
|
"RSA-PKCS1-v1_5": RSACipher,
|
||||||
|
"DH": DHCipher,
|
||||||
|
"MD5": MD5,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
encrypt(algorithm, key, data) {
|
||||||
|
if (key.algorithm.name !== algorithm.name) {
|
||||||
|
throw new Error("algorithm does not match");
|
||||||
|
}
|
||||||
|
if (typeof key.encrypt !== "function") {
|
||||||
|
throw new Error("key does not support encryption");
|
||||||
|
}
|
||||||
|
return key.encrypt(algorithm, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypt(algorithm, key, data) {
|
||||||
|
if (key.algorithm.name !== algorithm.name) {
|
||||||
|
throw new Error("algorithm does not match");
|
||||||
|
}
|
||||||
|
if (typeof key.decrypt !== "function") {
|
||||||
|
throw new Error("key does not support encryption");
|
||||||
|
}
|
||||||
|
return key.decrypt(algorithm, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
importKey(format, keyData, algorithm, extractable, keyUsages) {
|
||||||
|
if (format !== "raw") {
|
||||||
|
throw new Error("key format is not supported");
|
||||||
|
}
|
||||||
|
const alg = this._algorithms[algorithm.name];
|
||||||
|
if (typeof alg === "undefined" || typeof alg.importKey !== "function") {
|
||||||
|
throw new Error("algorithm is not supported");
|
||||||
|
}
|
||||||
|
return alg.importKey(keyData, algorithm, extractable, keyUsages);
|
||||||
|
}
|
||||||
|
|
||||||
|
generateKey(algorithm, extractable, keyUsages) {
|
||||||
|
const alg = this._algorithms[algorithm.name];
|
||||||
|
if (typeof alg === "undefined" || typeof alg.generateKey !== "function") {
|
||||||
|
throw new Error("algorithm is not supported");
|
||||||
|
}
|
||||||
|
return alg.generateKey(algorithm, extractable, keyUsages);
|
||||||
|
}
|
||||||
|
|
||||||
|
exportKey(format, key) {
|
||||||
|
if (format !== "raw") {
|
||||||
|
throw new Error("key format is not supported");
|
||||||
|
}
|
||||||
|
if (typeof key.exportKey !== "function") {
|
||||||
|
throw new Error("key does not support exportKey");
|
||||||
|
}
|
||||||
|
return key.exportKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
digest(algorithm, data) {
|
||||||
|
const alg = this._algorithms[algorithm];
|
||||||
|
if (typeof alg !== "function") {
|
||||||
|
throw new Error("algorithm is not supported");
|
||||||
|
}
|
||||||
|
return alg(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
deriveBits(algorithm, key, length) {
|
||||||
|
if (key.algorithm.name !== algorithm.name) {
|
||||||
|
throw new Error("algorithm does not match");
|
||||||
|
}
|
||||||
|
if (typeof key.deriveBits !== "function") {
|
||||||
|
throw new Error("key does not support deriveBits");
|
||||||
|
}
|
||||||
|
return key.deriveBits(algorithm, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new LegacyCrypto;
|
||||||
330
qiming-noVNC/core/crypto/des.js
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
/*
|
||||||
|
* Ported from Flashlight VNC ActionScript implementation:
|
||||||
|
* http://www.wizhelp.com/flashlight-vnc/
|
||||||
|
*
|
||||||
|
* Full attribution follows:
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* This DES class has been extracted from package Acme.Crypto for use in VNC.
|
||||||
|
* The unnecessary odd parity code has been removed.
|
||||||
|
*
|
||||||
|
* These changes are:
|
||||||
|
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
|
||||||
|
* DesCipher - the DES encryption method
|
||||||
|
*
|
||||||
|
* The meat of this code is by Dave Zimmerman <dzimm@widget.com>, and is:
|
||||||
|
*
|
||||||
|
* Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software
|
||||||
|
* and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and
|
||||||
|
* without fee is hereby granted, provided that this copyright notice is kept
|
||||||
|
* intact.
|
||||||
|
*
|
||||||
|
* WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY
|
||||||
|
* OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||||
|
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE LIABLE
|
||||||
|
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
|
||||||
|
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
|
||||||
|
* CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
|
||||||
|
* PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
|
||||||
|
* NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
|
||||||
|
* SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
|
||||||
|
* SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
|
||||||
|
* PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). WIDGET WORKSHOP
|
||||||
|
* SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
|
||||||
|
* HIGH RISK ACTIVITIES.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* The rest is:
|
||||||
|
*
|
||||||
|
* Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* Visit the ACME Labs Java page for up-to-date versions of this and other
|
||||||
|
* fine Java utilities: http://www.acme.com/java/
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable comma-spacing */
|
||||||
|
|
||||||
|
// 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];
|
||||||
|
|
||||||
|
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];
|
||||||
|
|
||||||
|
/* eslint-enable comma-spacing */
|
||||||
|
|
||||||
|
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
|
||||||
|
const m = l & 0x7;
|
||||||
|
pc1m[j] = ((password[l >>> 3] & (1<<m)) !== 0) ? 1: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < 16; ++i) {
|
||||||
|
const m = i << 1;
|
||||||
|
const n = m + 1;
|
||||||
|
kn[m] = kn[n] = 0;
|
||||||
|
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 (let j = 0; j < 24; ++j) {
|
||||||
|
if (pcr[PC2[j]] !== 0) {
|
||||||
|
kn[m] |= 1 << (23 - j);
|
||||||
|
}
|
||||||
|
if (pcr[PC2[j + 24]] !== 0) {
|
||||||
|
kn[n] |= 1 << (23 - j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cookey
|
||||||
|
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;
|
||||||
|
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
|
||||||
|
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++];
|
||||||
|
r = b[i++]<<24 | b[i++]<<16 | b[i++]<<8 | b[i++];
|
||||||
|
|
||||||
|
x = ((l >>> 4) ^ r) & 0x0f0f0f0f;
|
||||||
|
r ^= x;
|
||||||
|
l ^= (x << 4);
|
||||||
|
x = ((l >>> 16) ^ r) & 0x0000ffff;
|
||||||
|
r ^= x;
|
||||||
|
l ^= (x << 16);
|
||||||
|
x = ((r >>> 2) ^ l) & 0x33333333;
|
||||||
|
l ^= x;
|
||||||
|
r ^= (x << 2);
|
||||||
|
x = ((r >>> 8) ^ l) & 0x00ff00ff;
|
||||||
|
l ^= x;
|
||||||
|
r ^= (x << 8);
|
||||||
|
r = (r << 1) | ((r >>> 31) & 1);
|
||||||
|
x = (l ^ r) & 0xaaaaaaaa;
|
||||||
|
l ^= x;
|
||||||
|
r ^= x;
|
||||||
|
l = (l << 1) | ((l >>> 31) & 1);
|
||||||
|
|
||||||
|
for (let i = 0, keysi = 0; i < 8; ++i) {
|
||||||
|
x = (r << 28) | (r >>> 4);
|
||||||
|
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 ^ 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 ^= this.keys[keysi++];
|
||||||
|
fval = SP7[x & 0x3f];
|
||||||
|
fval |= SP5[(x >>> 8) & 0x3f];
|
||||||
|
fval |= SP3[(x >>> 16) & 0x3f];
|
||||||
|
fval |= SP1[(x >>> 24) & 0x3f];
|
||||||
|
x = l ^ this.keys[keysi++];
|
||||||
|
fval |= SP8[x & 0x0000003f];
|
||||||
|
fval |= SP6[(x >>> 8) & 0x3f];
|
||||||
|
fval |= SP4[(x >>> 16) & 0x3f];
|
||||||
|
fval |= SP2[(x >>> 24) & 0x3f];
|
||||||
|
r ^= fval;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = (r << 31) | (r >>> 1);
|
||||||
|
x = (l ^ r) & 0xaaaaaaaa;
|
||||||
|
l ^= x;
|
||||||
|
r ^= x;
|
||||||
|
l = (l << 31) | (l >>> 1);
|
||||||
|
x = ((l >>> 8) ^ r) & 0x00ff00ff;
|
||||||
|
r ^= x;
|
||||||
|
l ^= (x << 8);
|
||||||
|
x = ((l >>> 2) ^ r) & 0x33333333;
|
||||||
|
r ^= x;
|
||||||
|
l ^= (x << 2);
|
||||||
|
x = ((r >>> 16) ^ l) & 0x0000ffff;
|
||||||
|
l ^= x;
|
||||||
|
r ^= (x << 16);
|
||||||
|
x = ((r >>> 4) ^ l) & 0x0f0f0f0f;
|
||||||
|
l ^= x;
|
||||||
|
r ^= (x << 4);
|
||||||
|
|
||||||
|
// Spread ints to bytes
|
||||||
|
x = [r, l];
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
b[i] = (x[i>>>2] >>> (8 * (3 - (i % 4)))) % 256;
|
||||||
|
if (b[i] < 0) { b[i] += 256; } // unsigned
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DESECBCipher {
|
||||||
|
constructor() {
|
||||||
|
this._cipher = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
get algorithm() {
|
||||||
|
return { name: "DES-ECB" };
|
||||||
|
}
|
||||||
|
|
||||||
|
static importKey(key, _algorithm, _extractable, _keyUsages) {
|
||||||
|
const cipher = new DESECBCipher;
|
||||||
|
cipher._importKey(key);
|
||||||
|
return cipher;
|
||||||
|
}
|
||||||
|
|
||||||
|
_importKey(key, _extractable, _keyUsages) {
|
||||||
|
this._cipher = new DES(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
encrypt(_algorithm, plaintext) {
|
||||||
|
const x = new Uint8Array(plaintext);
|
||||||
|
if (x.length % 8 !== 0 || this._cipher === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const n = x.length / 8;
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
x.set(this._cipher.enc8(x.slice(i * 8, i * 8 + 8)), i * 8);
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DESCBCCipher {
|
||||||
|
constructor() {
|
||||||
|
this._cipher = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
get algorithm() {
|
||||||
|
return { name: "DES-CBC" };
|
||||||
|
}
|
||||||
|
|
||||||
|
static importKey(key, _algorithm, _extractable, _keyUsages) {
|
||||||
|
const cipher = new DESCBCCipher;
|
||||||
|
cipher._importKey(key);
|
||||||
|
return cipher;
|
||||||
|
}
|
||||||
|
|
||||||
|
_importKey(key) {
|
||||||
|
this._cipher = new DES(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
encrypt(algorithm, plaintext) {
|
||||||
|
const x = new Uint8Array(plaintext);
|
||||||
|
let y = new Uint8Array(algorithm.iv);
|
||||||
|
if (x.length % 8 !== 0 || this._cipher === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const n = x.length / 8;
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
for (let j = 0; j < 8; j++) {
|
||||||
|
y[j] ^= plaintext[i * 8 + j];
|
||||||
|
}
|
||||||
|
y = this._cipher.enc8(y);
|
||||||
|
x.set(y, i * 8);
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
}
|
||||||
55
qiming-noVNC/core/crypto/dh.js
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import { modPow, bigIntToU8Array, u8ArrayToBigInt } from "./bigint.js";
|
||||||
|
|
||||||
|
class DHPublicKey {
|
||||||
|
constructor(key) {
|
||||||
|
this._key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
get algorithm() {
|
||||||
|
return { name: "DH" };
|
||||||
|
}
|
||||||
|
|
||||||
|
exportKey() {
|
||||||
|
return this._key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DHCipher {
|
||||||
|
constructor() {
|
||||||
|
this._g = null;
|
||||||
|
this._p = null;
|
||||||
|
this._gBigInt = null;
|
||||||
|
this._pBigInt = null;
|
||||||
|
this._privateKey = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
get algorithm() {
|
||||||
|
return { name: "DH" };
|
||||||
|
}
|
||||||
|
|
||||||
|
static generateKey(algorithm, _extractable) {
|
||||||
|
const cipher = new DHCipher;
|
||||||
|
cipher._generateKey(algorithm);
|
||||||
|
return { privateKey: cipher, publicKey: new DHPublicKey(cipher._publicKey) };
|
||||||
|
}
|
||||||
|
|
||||||
|
_generateKey(algorithm) {
|
||||||
|
const g = algorithm.g;
|
||||||
|
const p = algorithm.p;
|
||||||
|
this._keyBytes = p.length;
|
||||||
|
this._gBigInt = u8ArrayToBigInt(g);
|
||||||
|
this._pBigInt = u8ArrayToBigInt(p);
|
||||||
|
this._privateKey = window.crypto.getRandomValues(new Uint8Array(this._keyBytes));
|
||||||
|
this._privateKeyBigInt = u8ArrayToBigInt(this._privateKey);
|
||||||
|
this._publicKey = bigIntToU8Array(modPow(
|
||||||
|
this._gBigInt, this._privateKeyBigInt, this._pBigInt), this._keyBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
deriveBits(algorithm, length) {
|
||||||
|
const bytes = Math.ceil(length / 8);
|
||||||
|
const pkey = new Uint8Array(algorithm.public);
|
||||||
|
const len = bytes > this._keyBytes ? bytes : this._keyBytes;
|
||||||
|
const secret = modPow(u8ArrayToBigInt(pkey), this._privateKeyBigInt, this._pBigInt);
|
||||||
|
return bigIntToU8Array(secret, len).slice(0, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
82
qiming-noVNC/core/crypto/md5.js
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* noVNC: HTML5 VNC client
|
||||||
|
* Copyright (C) 2021 The noVNC authors
|
||||||
|
* Licensed under MPL 2.0 (see LICENSE.txt)
|
||||||
|
*
|
||||||
|
* See README.md for usage and integration instructions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Performs MD5 hashing on an array of bytes, returns an array of bytes
|
||||||
|
*/
|
||||||
|
|
||||||
|
export async function MD5(d) {
|
||||||
|
let s = "";
|
||||||
|
for (let i = 0; i < d.length; i++) {
|
||||||
|
s += String.fromCharCode(d[i]);
|
||||||
|
}
|
||||||
|
return M(V(Y(X(s), 8 * s.length)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function M(d) {
|
||||||
|
let f = new Uint8Array(d.length);
|
||||||
|
for (let i=0;i<d.length;i++) {
|
||||||
|
f[i] = d.charCodeAt(i);
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
function X(d) {
|
||||||
|
let r = Array(d.length >> 2);
|
||||||
|
for (let m = 0; m < r.length; m++) r[m] = 0;
|
||||||
|
for (let m = 0; m < 8 * d.length; m += 8) r[m >> 5] |= (255 & d.charCodeAt(m / 8)) << m % 32;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
function V(d) {
|
||||||
|
let r = "";
|
||||||
|
for (let m = 0; m < 32 * d.length; m += 8) r += String.fromCharCode(d[m >> 5] >>> m % 32 & 255);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Y(d, g) {
|
||||||
|
d[g >> 5] |= 128 << g % 32, d[14 + (g + 64 >>> 9 << 4)] = g;
|
||||||
|
let m = 1732584193, f = -271733879, r = -1732584194, i = 271733878;
|
||||||
|
for (let n = 0; n < d.length; n += 16) {
|
||||||
|
let h = m,
|
||||||
|
t = f,
|
||||||
|
g = r,
|
||||||
|
e = i;
|
||||||
|
f = ii(f = ii(f = ii(f = ii(f = hh(f = hh(f = hh(f = hh(f = gg(f = gg(f = gg(f = gg(f = ff(f = ff(f = ff(f = ff(f, r = ff(r, i = ff(i, m = ff(m, f, r, i, d[n + 0], 7, -680876936), f, r, d[n + 1], 12, -389564586), m, f, d[n + 2], 17, 606105819), i, m, d[n + 3], 22, -1044525330), r = ff(r, i = ff(i, m = ff(m, f, r, i, d[n + 4], 7, -176418897), f, r, d[n + 5], 12, 1200080426), m, f, d[n + 6], 17, -1473231341), i, m, d[n + 7], 22, -45705983), r = ff(r, i = ff(i, m = ff(m, f, r, i, d[n + 8], 7, 1770035416), f, r, d[n + 9], 12, -1958414417), m, f, d[n + 10], 17, -42063), i, m, d[n + 11], 22, -1990404162), r = ff(r, i = ff(i, m = ff(m, f, r, i, d[n + 12], 7, 1804603682), f, r, d[n + 13], 12, -40341101), m, f, d[n + 14], 17, -1502002290), i, m, d[n + 15], 22, 1236535329), r = gg(r, i = gg(i, m = gg(m, f, r, i, d[n + 1], 5, -165796510), f, r, d[n + 6], 9, -1069501632), m, f, d[n + 11], 14, 643717713), i, m, d[n + 0], 20, -373897302), r = gg(r, i = gg(i, m = gg(m, f, r, i, d[n + 5], 5, -701558691), f, r, d[n + 10], 9, 38016083), m, f, d[n + 15], 14, -660478335), i, m, d[n + 4], 20, -405537848), r = gg(r, i = gg(i, m = gg(m, f, r, i, d[n + 9], 5, 568446438), f, r, d[n + 14], 9, -1019803690), m, f, d[n + 3], 14, -187363961), i, m, d[n + 8], 20, 1163531501), r = gg(r, i = gg(i, m = gg(m, f, r, i, d[n + 13], 5, -1444681467), f, r, d[n + 2], 9, -51403784), m, f, d[n + 7], 14, 1735328473), i, m, d[n + 12], 20, -1926607734), r = hh(r, i = hh(i, m = hh(m, f, r, i, d[n + 5], 4, -378558), f, r, d[n + 8], 11, -2022574463), m, f, d[n + 11], 16, 1839030562), i, m, d[n + 14], 23, -35309556), r = hh(r, i = hh(i, m = hh(m, f, r, i, d[n + 1], 4, -1530992060), f, r, d[n + 4], 11, 1272893353), m, f, d[n + 7], 16, -155497632), i, m, d[n + 10], 23, -1094730640), r = hh(r, i = hh(i, m = hh(m, f, r, i, d[n + 13], 4, 681279174), f, r, d[n + 0], 11, -358537222), m, f, d[n + 3], 16, -722521979), i, m, d[n + 6], 23, 76029189), r = hh(r, i = hh(i, m = hh(m, f, r, i, d[n + 9], 4, -640364487), f, r, d[n + 12], 11, -421815835), m, f, d[n + 15], 16, 530742520), i, m, d[n + 2], 23, -995338651), r = ii(r, i = ii(i, m = ii(m, f, r, i, d[n + 0], 6, -198630844), f, r, d[n + 7], 10, 1126891415), m, f, d[n + 14], 15, -1416354905), i, m, d[n + 5], 21, -57434055), r = ii(r, i = ii(i, m = ii(m, f, r, i, d[n + 12], 6, 1700485571), f, r, d[n + 3], 10, -1894986606), m, f, d[n + 10], 15, -1051523), i, m, d[n + 1], 21, -2054922799), r = ii(r, i = ii(i, m = ii(m, f, r, i, d[n + 8], 6, 1873313359), f, r, d[n + 15], 10, -30611744), m, f, d[n + 6], 15, -1560198380), i, m, d[n + 13], 21, 1309151649), r = ii(r, i = ii(i, m = ii(m, f, r, i, d[n + 4], 6, -145523070), f, r, d[n + 11], 10, -1120210379), m, f, d[n + 2], 15, 718787259), i, m, d[n + 9], 21, -343485551), m = add(m, h), f = add(f, t), r = add(r, g), i = add(i, e);
|
||||||
|
}
|
||||||
|
return Array(m, f, r, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cmn(d, g, m, f, r, i) {
|
||||||
|
return add(rol(add(add(g, d), add(f, i)), r), m);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ff(d, g, m, f, r, i, n) {
|
||||||
|
return cmn(g & m | ~g & f, d, g, r, i, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
function gg(d, g, m, f, r, i, n) {
|
||||||
|
return cmn(g & f | m & ~f, d, g, r, i, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hh(d, g, m, f, r, i, n) {
|
||||||
|
return cmn(g ^ m ^ f, d, g, r, i, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ii(d, g, m, f, r, i, n) {
|
||||||
|
return cmn(m ^ (g | ~f), d, g, r, i, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
function add(d, g) {
|
||||||
|
let m = (65535 & d) + (65535 & g);
|
||||||
|
return (d >> 16) + (g >> 16) + (m >> 16) << 16 | 65535 & m;
|
||||||
|
}
|
||||||
|
|
||||||
|
function rol(d, g) {
|
||||||
|
return d << g | d >>> 32 - g;
|
||||||
|
}
|
||||||
132
qiming-noVNC/core/crypto/rsa.js
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
import Base64 from "../base64.js";
|
||||||
|
import { modPow, bigIntToU8Array, u8ArrayToBigInt } from "./bigint.js";
|
||||||
|
|
||||||
|
export class RSACipher {
|
||||||
|
constructor() {
|
||||||
|
this._keyLength = 0;
|
||||||
|
this._keyBytes = 0;
|
||||||
|
this._n = null;
|
||||||
|
this._e = null;
|
||||||
|
this._d = null;
|
||||||
|
this._nBigInt = null;
|
||||||
|
this._eBigInt = null;
|
||||||
|
this._dBigInt = null;
|
||||||
|
this._extractable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
get algorithm() {
|
||||||
|
return { name: "RSA-PKCS1-v1_5" };
|
||||||
|
}
|
||||||
|
|
||||||
|
_base64urlDecode(data) {
|
||||||
|
data = data.replace(/-/g, "+").replace(/_/g, "/");
|
||||||
|
data = data.padEnd(Math.ceil(data.length / 4) * 4, "=");
|
||||||
|
return Base64.decode(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
_padArray(arr, length) {
|
||||||
|
const res = new Uint8Array(length);
|
||||||
|
res.set(arr, length - arr.length);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async generateKey(algorithm, extractable, _keyUsages) {
|
||||||
|
const cipher = new RSACipher;
|
||||||
|
await cipher._generateKey(algorithm, extractable);
|
||||||
|
return { privateKey: cipher };
|
||||||
|
}
|
||||||
|
|
||||||
|
async _generateKey(algorithm, extractable) {
|
||||||
|
this._keyLength = algorithm.modulusLength;
|
||||||
|
this._keyBytes = Math.ceil(this._keyLength / 8);
|
||||||
|
const key = await window.crypto.subtle.generateKey(
|
||||||
|
{
|
||||||
|
name: "RSA-OAEP",
|
||||||
|
modulusLength: algorithm.modulusLength,
|
||||||
|
publicExponent: algorithm.publicExponent,
|
||||||
|
hash: {name: "SHA-256"},
|
||||||
|
},
|
||||||
|
true, ["encrypt", "decrypt"]);
|
||||||
|
const privateKey = await window.crypto.subtle.exportKey("jwk", key.privateKey);
|
||||||
|
this._n = this._padArray(this._base64urlDecode(privateKey.n), this._keyBytes);
|
||||||
|
this._nBigInt = u8ArrayToBigInt(this._n);
|
||||||
|
this._e = this._padArray(this._base64urlDecode(privateKey.e), this._keyBytes);
|
||||||
|
this._eBigInt = u8ArrayToBigInt(this._e);
|
||||||
|
this._d = this._padArray(this._base64urlDecode(privateKey.d), this._keyBytes);
|
||||||
|
this._dBigInt = u8ArrayToBigInt(this._d);
|
||||||
|
this._extractable = extractable;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async importKey(key, _algorithm, extractable, keyUsages) {
|
||||||
|
if (keyUsages.length !== 1 || keyUsages[0] !== "encrypt") {
|
||||||
|
throw new Error("only support importing RSA public key");
|
||||||
|
}
|
||||||
|
const cipher = new RSACipher;
|
||||||
|
await cipher._importKey(key, extractable);
|
||||||
|
return cipher;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _importKey(key, extractable) {
|
||||||
|
const n = key.n;
|
||||||
|
const e = key.e;
|
||||||
|
if (n.length !== e.length) {
|
||||||
|
throw new Error("the sizes of modulus and public exponent do not match");
|
||||||
|
}
|
||||||
|
this._keyBytes = n.length;
|
||||||
|
this._keyLength = this._keyBytes * 8;
|
||||||
|
this._n = new Uint8Array(this._keyBytes);
|
||||||
|
this._e = new Uint8Array(this._keyBytes);
|
||||||
|
this._n.set(n);
|
||||||
|
this._e.set(e);
|
||||||
|
this._nBigInt = u8ArrayToBigInt(this._n);
|
||||||
|
this._eBigInt = u8ArrayToBigInt(this._e);
|
||||||
|
this._extractable = extractable;
|
||||||
|
}
|
||||||
|
|
||||||
|
async encrypt(_algorithm, message) {
|
||||||
|
if (message.length > this._keyBytes - 11) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const ps = new Uint8Array(this._keyBytes - message.length - 3);
|
||||||
|
window.crypto.getRandomValues(ps);
|
||||||
|
for (let i = 0; i < ps.length; i++) {
|
||||||
|
ps[i] = Math.floor(ps[i] * 254 / 255 + 1);
|
||||||
|
}
|
||||||
|
const em = new Uint8Array(this._keyBytes);
|
||||||
|
em[1] = 0x02;
|
||||||
|
em.set(ps, 2);
|
||||||
|
em.set(message, ps.length + 3);
|
||||||
|
const emBigInt = u8ArrayToBigInt(em);
|
||||||
|
const c = modPow(emBigInt, this._eBigInt, this._nBigInt);
|
||||||
|
return bigIntToU8Array(c, this._keyBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
async decrypt(_algorithm, message) {
|
||||||
|
if (message.length !== this._keyBytes) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const msgBigInt = u8ArrayToBigInt(message);
|
||||||
|
const emBigInt = modPow(msgBigInt, this._dBigInt, this._nBigInt);
|
||||||
|
const em = bigIntToU8Array(emBigInt, this._keyBytes);
|
||||||
|
if (em[0] !== 0x00 || em[1] !== 0x02) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
let i = 2;
|
||||||
|
for (; i < em.length; i++) {
|
||||||
|
if (em[i] === 0x00) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i === em.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return em.slice(i + 1, em.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
async exportKey() {
|
||||||
|
if (!this._extractable) {
|
||||||
|
throw new Error("key is not extractable");
|
||||||
|
}
|
||||||
|
return { n: this._n, e: this._e, d: this._d };
|
||||||
|
}
|
||||||
|
}
|
||||||
27
qiming-noVNC/core/decoders/copyrect.js
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
321
qiming-noVNC/core/decoders/h264.js
Normal file
@@ -0,0 +1,321 @@
|
|||||||
|
/*
|
||||||
|
* noVNC: HTML5 VNC client
|
||||||
|
* Copyright (C) 2024 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 class H264Parser {
|
||||||
|
constructor(data) {
|
||||||
|
this._data = data;
|
||||||
|
this._index = 0;
|
||||||
|
this.profileIdc = null;
|
||||||
|
this.constraintSet = null;
|
||||||
|
this.levelIdc = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_getStartSequenceLen(index) {
|
||||||
|
let data = this._data;
|
||||||
|
if (data[index + 0] == 0 && data[index + 1] == 0 && data[index + 2] == 0 && data[index + 3] == 1) {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
if (data[index + 0] == 0 && data[index + 1] == 0 && data[index + 2] == 1) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_indexOfNextNalUnit(index) {
|
||||||
|
let data = this._data;
|
||||||
|
for (let i = index; i < data.length; ++i) {
|
||||||
|
if (this._getStartSequenceLen(i) != 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_parseSps(index) {
|
||||||
|
this.profileIdc = this._data[index];
|
||||||
|
this.constraintSet = this._data[index + 1];
|
||||||
|
this.levelIdc = this._data[index + 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
_parseNalUnit(index) {
|
||||||
|
const firstByte = this._data[index];
|
||||||
|
if (firstByte & 0x80) {
|
||||||
|
throw new Error('H264 parsing sanity check failed, forbidden zero bit is set');
|
||||||
|
}
|
||||||
|
const unitType = firstByte & 0x1f;
|
||||||
|
|
||||||
|
switch (unitType) {
|
||||||
|
case 1: // coded slice, non-idr
|
||||||
|
return { slice: true };
|
||||||
|
case 5: // coded slice, idr
|
||||||
|
return { slice: true, key: true };
|
||||||
|
case 6: // sei
|
||||||
|
return {};
|
||||||
|
case 7: // sps
|
||||||
|
this._parseSps(index + 1);
|
||||||
|
return {};
|
||||||
|
case 8: // pps
|
||||||
|
return {};
|
||||||
|
default:
|
||||||
|
Log.Warn("Unhandled unit type: ", unitType);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
parse() {
|
||||||
|
const startIndex = this._index;
|
||||||
|
let isKey = false;
|
||||||
|
|
||||||
|
while (this._index < this._data.length) {
|
||||||
|
const startSequenceLen = this._getStartSequenceLen(this._index);
|
||||||
|
if (startSequenceLen == 0) {
|
||||||
|
throw new Error('Invalid start sequence in bit stream');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { slice, key } = this._parseNalUnit(this._index + startSequenceLen);
|
||||||
|
|
||||||
|
let nextIndex = this._indexOfNextNalUnit(this._index + startSequenceLen);
|
||||||
|
if (nextIndex == -1) {
|
||||||
|
this._index = this._data.length;
|
||||||
|
} else {
|
||||||
|
this._index = nextIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key) {
|
||||||
|
isKey = true;
|
||||||
|
}
|
||||||
|
if (slice) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startIndex === this._index) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
frame: this._data.subarray(startIndex, this._index),
|
||||||
|
key: isKey,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class H264Context {
|
||||||
|
constructor(width, height) {
|
||||||
|
this.lastUsed = 0;
|
||||||
|
this._width = width;
|
||||||
|
this._height = height;
|
||||||
|
this._profileIdc = null;
|
||||||
|
this._constraintSet = null;
|
||||||
|
this._levelIdc = null;
|
||||||
|
this._decoder = null;
|
||||||
|
this._pendingFrames = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleFrame(frame) {
|
||||||
|
let pending = this._pendingFrames.shift();
|
||||||
|
if (pending === undefined) {
|
||||||
|
throw new Error("Pending frame queue empty when receiving frame from decoder");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pending.timestamp != frame.timestamp) {
|
||||||
|
throw new Error("Video frame timestamp mismatch. Expected " +
|
||||||
|
frame.timestamp + " but but got " + pending.timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
pending.frame = frame;
|
||||||
|
pending.ready = true;
|
||||||
|
pending.resolve();
|
||||||
|
|
||||||
|
if (!pending.keep) {
|
||||||
|
frame.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleError(e) {
|
||||||
|
throw new Error("Failed to decode frame: " + e.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
_configureDecoder(profileIdc, constraintSet, levelIdc) {
|
||||||
|
if (this._decoder === null || this._decoder.state === 'closed') {
|
||||||
|
this._decoder = new VideoDecoder({
|
||||||
|
output: frame => this._handleFrame(frame),
|
||||||
|
error: e => this._handleError(e),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const codec = 'avc1.' +
|
||||||
|
profileIdc.toString(16).padStart(2, '0') +
|
||||||
|
constraintSet.toString(16).padStart(2, '0') +
|
||||||
|
levelIdc.toString(16).padStart(2, '0');
|
||||||
|
this._decoder.configure({
|
||||||
|
codec: codec,
|
||||||
|
codedWidth: this._width,
|
||||||
|
codedHeight: this._height,
|
||||||
|
optimizeForLatency: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_preparePendingFrame(timestamp) {
|
||||||
|
let pending = {
|
||||||
|
timestamp: timestamp,
|
||||||
|
promise: null,
|
||||||
|
resolve: null,
|
||||||
|
frame: null,
|
||||||
|
ready: false,
|
||||||
|
keep: false,
|
||||||
|
};
|
||||||
|
pending.promise = new Promise((resolve) => {
|
||||||
|
pending.resolve = resolve;
|
||||||
|
});
|
||||||
|
this._pendingFrames.push(pending);
|
||||||
|
|
||||||
|
return pending;
|
||||||
|
}
|
||||||
|
|
||||||
|
decode(payload) {
|
||||||
|
let parser = new H264Parser(payload);
|
||||||
|
let result = null;
|
||||||
|
|
||||||
|
// Ideally, this timestamp should come from the server, but we'll just
|
||||||
|
// approximate it instead.
|
||||||
|
let timestamp = Math.round(window.performance.now() * 1e3);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
let encodedFrame = parser.parse();
|
||||||
|
if (encodedFrame === null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser.profileIdc !== null) {
|
||||||
|
self._profileIdc = parser.profileIdc;
|
||||||
|
self._constraintSet = parser.constraintSet;
|
||||||
|
self._levelIdc = parser.levelIdc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._decoder === null || this._decoder.state !== 'configured') {
|
||||||
|
if (!encodedFrame.key) {
|
||||||
|
Log.Warn("Missing key frame. Can't decode until one arrives");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (self._profileIdc === null) {
|
||||||
|
Log.Warn('Cannot config decoder. Have not received SPS and PPS yet.');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
this._configureDecoder(self._profileIdc, self._constraintSet,
|
||||||
|
self._levelIdc);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = this._preparePendingFrame(timestamp);
|
||||||
|
|
||||||
|
const chunk = new EncodedVideoChunk({
|
||||||
|
timestamp: timestamp,
|
||||||
|
type: encodedFrame.key ? 'key' : 'delta',
|
||||||
|
data: encodedFrame.frame,
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
this._decoder.decode(chunk);
|
||||||
|
} catch (e) {
|
||||||
|
Log.Warn("Failed to decode:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We only keep last frame of each payload
|
||||||
|
if (result !== null) {
|
||||||
|
result.keep = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class H264Decoder {
|
||||||
|
constructor() {
|
||||||
|
this._tick = 0;
|
||||||
|
this._contexts = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
_contextId(x, y, width, height) {
|
||||||
|
return [x, y, width, height].join(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
_findOldestContextId() {
|
||||||
|
let oldestTick = Number.MAX_VALUE;
|
||||||
|
let oldestKey = undefined;
|
||||||
|
for (const [key, value] of Object.entries(this._contexts)) {
|
||||||
|
if (value.lastUsed < oldestTick) {
|
||||||
|
oldestTick = value.lastUsed;
|
||||||
|
oldestKey = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return oldestKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
_createContext(x, y, width, height) {
|
||||||
|
const maxContexts = 64;
|
||||||
|
if (Object.keys(this._contexts).length >= maxContexts) {
|
||||||
|
let oldestContextId = this._findOldestContextId();
|
||||||
|
delete this._contexts[oldestContextId];
|
||||||
|
}
|
||||||
|
let context = new H264Context(width, height);
|
||||||
|
this._contexts[this._contextId(x, y, width, height)] = context;
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
_getContext(x, y, width, height) {
|
||||||
|
let context = this._contexts[this._contextId(x, y, width, height)];
|
||||||
|
return context !== undefined ? context : this._createContext(x, y, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
_resetContext(x, y, width, height) {
|
||||||
|
delete this._contexts[this._contextId(x, y, width, height)];
|
||||||
|
}
|
||||||
|
|
||||||
|
_resetAllContexts() {
|
||||||
|
this._contexts = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
decodeRect(x, y, width, height, sock, display, depth) {
|
||||||
|
const resetContextFlag = 1;
|
||||||
|
const resetAllContextsFlag = 2;
|
||||||
|
|
||||||
|
if (sock.rQwait("h264 header", 8)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const length = sock.rQshift32();
|
||||||
|
const flags = sock.rQshift32();
|
||||||
|
|
||||||
|
if (sock.rQwait("h264 payload", length, 8)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & resetAllContextsFlag) {
|
||||||
|
this._resetAllContexts();
|
||||||
|
} else if (flags & resetContextFlag) {
|
||||||
|
this._resetContext(x, y, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
let context = this._getContext(x, y, width, height);
|
||||||
|
context.lastUsed = this._tick++;
|
||||||
|
|
||||||
|
if (length !== 0) {
|
||||||
|
let payload = sock.rQshiftBytes(length, false);
|
||||||
|
let frame = context.decode(payload);
|
||||||
|
if (frame !== null) {
|
||||||
|
display.videoFrame(x, y, width, height, frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||