Add test_rdp_client for RDP tunneling testing

- Created test_rdp_client.c based on test_vnc_client.c
- Implements RDP protocol negotiation including Connection Request/Confirm
- Sends MCS Connect Initial and Client Info PDU with username
- Supports both wsssht --pipe tunneling and direct TCP connection with -p PORT
- Tests RDP connection and reports results in output
parent 599348b7
......@@ -567,6 +567,47 @@ for template in templates/*.html; do
// ${BASENAME} page HTML template
static const char *${BASENAME}_page_html __attribute__((used)) =
EOF
# Process the HTML file, escape quotes and backslashes
sed 's/\\/\\\\/g; s/"/\\"/g; s/^/"/; s/$/\\n"/' "$template" >> "$HEADER_FILE"
elif [ "$BASENAME" = "rdp" ]; then
cat > "$HEADER_FILE" << EOF
/**
* ${BASENAME} page HTML template for wssshd
*
* Copyright (C) 2024 Stefy Lanza <stefy@nexlab.net> and SexHack.me
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef ${BASENAME^^}_PAGE_H
#define ${BASENAME^^}_PAGE_H
// ${BASENAME} page HTML template
static const char *${BASENAME}_page_html =
EOF
# Use python to properly escape the HTML
python3 -c "
import sys
with open('$template', 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
lines = content.split('\n')
for line in lines:
escaped_line = line.replace('\\\\', '\\\\\\\\').replace('\\\"', '\\\\\"').replace('%c%s', '%%c%%s')
print('\"' + escaped_line + '\\\\n\"')
" >> "$HEADER_FILE"
else
cat > "$HEADER_FILE" << EOF
/**
......@@ -594,10 +635,10 @@ EOF
// ${BASENAME} page HTML template
static const char *${BASENAME}_page_html =
EOF
fi
# Process the HTML file, escape quotes and backslashes
sed 's/\\/\\\\/g; s/"/\\"/g; s/^/"/; s/$/\\n"/' "$template" >> "$HEADER_FILE"
# Process the HTML file, escape quotes and backslashes
sed 's/\\/\\\\/g; s/"/\\"/g; s/^/"/; s/$/\\n"/' "$template" >> "$HEADER_FILE"
fi
# Close the string and header
cat >> "$HEADER_FILE" << EOF
......@@ -610,4 +651,4 @@ EOF
fi
done
echo "Assets embedded successfully"
\ No newline at end of file
echo "Assets embedded successfully"
#!/bin/bash
# Script to embed web assets into C code
#
# Copyright (C) 2024 Stefy Lanza <stefy@nexlab.net> and SexHack.me
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
echo "Embedding web assets..."
# Download pako libs if not present
mkdir -p templates/novnc/vendor/pako/lib/zlib
PAKO_FILES="adler32 constants crc32 deflate inflate inffast inftrees trees zstream"
for file in $PAKO_FILES; do
if [ ! -f "templates/novnc/vendor/pako/lib/zlib/${file}.js" ]; then
echo "Downloading pako ${file}.js..."
curl -s -o "templates/novnc/vendor/pako/lib/zlib/${file}.js" "https://raw.githubusercontent.com/nodeca/pako/master/lib/zlib/${file}.js"
fi
done
# Clean up old embedded files
rm -f image_data.h favicon_data.h
# Embed logo from logos directory (created by build.sh)
if [ -f ../logos/logo-128.png ]; then
echo "Embedding logo-128.png..."
xxd -i ../logos/logo-128.png > image_data.h
# Rename the variables to match our expected names
# xxd generates names like ___logos_logo_128_png, so we need to replace the entire variable names
sed -i 's/unsigned char ___logos_logo_128_png\[\]/unsigned char image_jpg[]/g' image_data.h
sed -i 's/unsigned int ___logos_logo_128_png_len/unsigned int image_jpg_len/g' image_data.h
elif [ -f ../image.jpg ]; then
echo "Embedding image.jpg..."
xxd -i ../image.jpg | sed 's/___image_jpg/image_jpg/g' > image_data.h
else
echo "Warning: No image found, creating empty placeholder"
cat > image_data.h << 'EOF'
unsigned char image_jpg[] = {};
unsigned int image_jpg_len = 0;
EOF
fi
# Embed favicon.ico
if [ -f ../logos/favicon.ico ]; then
echo "Embedding favicon.ico..."
xxd -i ../logos/favicon.ico > favicon_data.h
# Rename the variables
sed -i 's/unsigned char ___logos_favicon_ico\[\]/unsigned char favicon_ico[]/g' favicon_data.h
sed -i 's/unsigned int ___logos_favicon_ico_len/unsigned int favicon_ico_len/g' favicon_data.h
else
echo "Warning: favicon.ico not found, creating empty placeholder"
cat > favicon_data.h << 'EOF'
unsigned char favicon_ico[] = {};
unsigned int favicon_ico_len = 0;
EOF
fi
# Embed xterm.js
if [ -f templates/xterm.js ]; then
echo "Embedding xterm.js..."
mkdir -p html_pages
HEADER_FILE="html_pages/xterm_page.h"
cat > "$HEADER_FILE" << EOF
/**
* xterm.js library for wssshd
*
* Copyright (C) 2024 Stefy Lanza <stefy@nexlab.net> and SexHack.me
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef XTERM_PAGE_H
#define XTERM_PAGE_H
// xterm.js library
const char *xterm_js =
EOF
# Process the JS file, escape quotes and backslashes
sed 's/\\/\\\\/g; s/"/\\"/g; s/^/"/; s/$/\\n"/' templates/xterm.js >> "$HEADER_FILE"
# Close the string and header
cat >> "$HEADER_FILE" << EOF
;
#endif /* XTERM_PAGE_H */
EOF
else
echo "Warning: xterm.js not found, creating empty placeholder"
mkdir -p html_pages
cat > html_pages/xterm_page.h << 'EOF'
#ifndef XTERM_PAGE_H
#define XTERM_PAGE_H
static const char *xterm_js = "";
#endif /* XTERM_PAGE_H */
EOF
fi
# Embed xterm-addon-fit.js
if [ -f templates/xterm-addon-fit.js ]; then
echo "Embedding xterm-addon-fit.js..."
mkdir -p html_pages
HEADER_FILE="html_pages/xterm_addon_page.h"
cat > "$HEADER_FILE" << EOF
/**
* xterm-addon-fit.js library for wssshd
*
* Copyright (C) 2024 Stefy Lanza <stefy@nexlab.net> and SexHack.me
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef XTERM_ADDON_PAGE_H
#define XTERM_ADDON_PAGE_H
// xterm-addon-fit.js library
const char *xterm_addon_fit_js =
EOF
# Process the JS file, escape quotes and backslashes
sed 's/\\/\\\\/g; s/"/\\"/g; s/^/"/; s/$/\\n"/' templates/xterm-addon-fit.js >> "$HEADER_FILE"
# Close the string and header
cat >> "$HEADER_FILE" << EOF
;
#endif /* XTERM_ADDON_PAGE_H */
EOF
else
echo "Warning: xterm-addon-fit.js not found, creating empty placeholder"
mkdir -p html_pages
cat > html_pages/xterm_addon_page.h << 'EOF'
#ifndef XTERM_ADDON_PAGE_H
#define XTERM_ADDON_PAGE_H
static const char *xterm_addon_fit_js = "";
#endif /* XTERM_ADDON_PAGE_H */
EOF
fi
# Embed mstsc.js
if [ -f templates/mstsc.min.js ]; then
echo "Embedding mstsc.min.js..."
mkdir -p html_pages
HEADER_FILE="html_pages/mstsc_page.h"
cat > "$HEADER_FILE" << EOF
/**
* mstsc.js library for wssshd
*
* Copyright (C) 2024 Stefy Lanza <stefy@nexlab.net> and SexHack.me
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef MSTSC_PAGE_H
#define MSTSC_PAGE_H
// mstsc.js library
const char *mstsc_js =
EOF
# Process the JS file, escape quotes and backslashes
sed 's/\\/\\\\/g; s/"/\\"/g; s/^/"/; s/$/\\n"/' templates/mstsc.min.js >> "$HEADER_FILE"
# Close the string and header
cat >> "$HEADER_FILE" << EOF
;
#endif /* MSTSC_PAGE_H */
EOF
else
echo "Warning: mstsc.min.js not found, creating empty placeholder"
mkdir -p html_pages
cat > html_pages/mstsc_page.h << 'EOF'
#ifndef MSTSC_PAGE_H
#define MSTSC_PAGE_H
static const char *mstsc_js = "";
#endif /* MSTSC_PAGE_H */
EOF
fi
# Embed RDP JS files
echo "Embedding RDP JS files..."
mkdir -p html_pages
# Generate rdp_assets.h
cat > rdp_assets.h << 'EOF'
#ifndef RDP_ASSETS_H
#define RDP_ASSETS_H
EOF
# Generate rdp_asset_map.c
cat > rdp_asset_map.c << 'EOF'
#include <string.h>
#include "rdp_assets.h"
const char *get_rdp_asset(const char *path, size_t *size) {
EOF
find templates/rdpwasm -name "*.js" | sort | while read -r file; do
if [ -f "$file" ]; then
RELPATH=$(echo "$file" | sed 's|templates/rdpwasm/||')
VARNAME=$(echo "$RELPATH" | sed 's|/|_|g; s|\.js$|_js|; s|\.|_|g')
HEADER_FILE="html_pages/rdp_${VARNAME}_page.h"
echo "Embedding $file as rdp_${VARNAME}"
# Create header with extern
cat > "$HEADER_FILE" << EOF
#ifndef RDP_${VARNAME^^}_PAGE_H
#define RDP_${VARNAME^^}_PAGE_H
extern const char *rdp_${VARNAME};
#endif /* RDP_${VARNAME^^}_PAGE_H */
EOF
# Add to rdp_assets.h
echo "#include \"html_pages/rdp_${VARNAME}_page.h\"" >> rdp_assets.h
# Add definition to rdp_asset_map.c
echo "const char *rdp_${VARNAME} =" >> rdp_asset_map.c
# Use python to properly escape
python3 -c "
import sys
with open('$file', 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
lines = content.split('\n')
for line in lines:
escaped_line = line.replace('\\\\', '\\\\\\\\').replace('\\\"', '\\\\\"')
print('\"' + escaped_line + '\\\\n\"')
" >> rdp_asset_map.c
echo ";" >> rdp_asset_map.c
# Add to rdp_asset_map.c
echo " if (strcmp(path, \"/rdpwasm/$RELPATH\") == 0) {" >> rdp_asset_map.c
echo " if (size) *size = strlen(rdp_${VARNAME});" >> rdp_asset_map.c
echo " return rdp_${VARNAME};" >> rdp_asset_map.c
echo " }" >> rdp_asset_map.c
fi
done
find templates/rdpwasm -name "*.wasm" | sort | while read -r file; do
if [ -f "$file" ]; then
RELPATH=$(echo "$file" | sed 's|templates/rdpwasm/||')
VARNAME=$(echo "$RELPATH" | sed 's|/|_|g; s|\.wasm$|_wasm|; s|\.|_|g')
HEADER_FILE="html_pages/rdp_${VARNAME}_page.h"
echo "Embedding $file as rdp_${VARNAME}"
# Create header with extern
cat > "$HEADER_FILE" << EOF
#ifndef RDP_${VARNAME^^}_PAGE_H
#define RDP_${VARNAME^^}_PAGE_H
extern const unsigned char rdp_${VARNAME}[];
extern const unsigned int rdp_${VARNAME}_len;
#endif /* RDP_${VARNAME^^}_PAGE_H */
EOF
# Add to rdp_assets.h
echo "#include \"html_pages/rdp_${VARNAME}_page.h\"" >> rdp_assets.h
# Embed binary file
xxd -i "$file" > temp_binary.h
# Rename the variables and add static
sed -i "s/templates_rdpwasm_rdp_wasm/rdp_rdp_wasm/g" temp_binary.h
sed -i "s/unsigned char rdp_rdp_wasm\[\]/static unsigned char rdp_rdp_wasm[]/g" temp_binary.h
sed -i "s/unsigned int rdp_rdp_wasm_len/static unsigned int rdp_rdp_wasm_len/g" temp_binary.h
cat temp_binary.h >> rdp_asset_map.c
rm temp_binary.h
# Add to rdp_asset_map.c
echo " if (strcmp(path, \"/rdpwasm/$RELPATH\") == 0) {" >> rdp_asset_map.c
echo " if (size) *size = rdp_${VARNAME}_len;" >> rdp_asset_map.c
echo " return (const char *)rdp_${VARNAME};" >> rdp_asset_map.c
echo " }" >> rdp_asset_map.c
fi
done
cat >> rdp_assets.h << 'EOF'
#endif /* RDP_ASSETS_H */
EOF
cat >> rdp_asset_map.c << 'EOF'
return NULL;
}
EOF
echo "RDP JS files embedded."
# Embed noVNC CSS
if [ -f templates/novnc.css ]; then
echo "Embedding novnc.css..."
mkdir -p html_pages
HEADER_FILE="html_pages/novnc_css_page.h"
cat > "$HEADER_FILE" << EOF
/**
* noVNC CSS for wssshd
*
* Copyright (C) 2024 Stefy Lanza <stefy@nexlab.net> and SexHack.me
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef NOVNC_CSS_PAGE_H
#define NOVNC_CSS_PAGE_H
// noVNC CSS
const char *novnc_css =
EOF
# Process the CSS file, escape quotes and backslashes
sed 's/\\/\\\\/g; s/"/\\"/g; s/^/"/; s/$/\\n"/' templates/novnc.css >> "$HEADER_FILE"
# Close the string and header
cat >> "$HEADER_FILE" << EOF
;
#endif /* NOVNC_CSS_PAGE_H */
EOF
else
echo "Warning: novnc.css not found, creating empty placeholder"
mkdir -p html_pages
cat > html_pages/novnc_css_page.h << 'EOF'
#ifndef NOVNC_CSS_PAGE_H
#define NOVNC_CSS_PAGE_H
static const char *novnc_css = "";
#endif /* NOVNC_CSS_PAGE_H */
EOF
fi
# Embed all noVNC JS files
echo "Embedding noVNC JS files..."
mkdir -p html_pages
# Generate novnc_assets.h
cat > novnc_assets.h << 'EOF'
#ifndef NOVNC_ASSETS_H
#define NOVNC_ASSETS_H
EOF
# Generate novnc_asset_map.c
cat > novnc_asset_map.c << 'EOF'
#include <string.h>
#include "novnc_assets.h"
const char *get_novnc_asset(const char *path) {
EOF
find templates/novnc templates/vendor -name "*.js" | sort | while read -r jsfile; do
if [ -f "$jsfile" ]; then
RELPATH=$(echo "$jsfile" | sed 's|templates/novnc/||')
RELDIR=$(dirname "$RELPATH")
if [ "$RELDIR" = "." ]; then
RELDIR=""
else
RELDIR="$RELDIR/"
fi
VARNAME=$(echo "$RELPATH" | sed 's|/|_|g; s|\.js$|_js|')
HEADER_FILE="html_pages/novnc_${VARNAME}_page.h"
echo "Embedding $jsfile as novnc_${VARNAME}"
# Create header with extern
cat > "$HEADER_FILE" << EOF
#ifndef NOVNC_${VARNAME^^}_PAGE_H
#define NOVNC_${VARNAME^^}_PAGE_H
extern const char *novnc_${VARNAME};
#endif /* NOVNC_${VARNAME^^}_PAGE_H */
EOF
# Add to novnc_assets.h
echo "#include \"html_pages/novnc_${VARNAME}_page.h\"" >> novnc_assets.h
# Add definition to novnc_asset_map.c
echo "const char *novnc_${VARNAME} =" >> novnc_asset_map.c
CONTENT=$(sed 's/\\/\\\\/g; s/"/\\"/g; s/^/"/; s/$/\\n"/' "$jsfile")
if echo "$jsfile" | grep -q "vendor/pako"; then
# Convert CommonJS to ES6 for pako files
CONTENT=$(echo "$CONTENT" | sed "s|\"const \([a-zA-Z_][a-zA-Z0-9_]*\) = require('\./\([^']*\)');\"|\"import \1 from './\2.js';\"|g")
CONTENT=$(echo "$CONTENT" | sed "s|\"const { \([^}]*\) } = require('\./constants');\"|\"import * as constants from './constants.js'; const { \1 } = constants;\"|g")
CONTENT=$(echo "$CONTENT" | sed "s|\"const { \([^}]*\) } = require('\./\([^']*\)');\"|\"import { \1 } from './\2.js';\"|g")
CONTENT=$(echo "$CONTENT" | sed "s|\"module\.exports\.\([a-zA-Z_][a-zA-Z0-9_]*\)[[:space:]]*\=[[:space:]]*\([a-zA-Z_][a-zA-Z0-9_]*\);\"|\"export { \1 };\"|g")
CONTENT=$(echo "$CONTENT" | sed "s|\"module\.exports[[:space:]]*=[[:space:]]*\([a-zA-Z_][a-zA-Z0-9_]*\);\"|\"export default \1;\"|g")
# Special for constants.js
CONTENT=$(echo "$CONTENT" | sed 's|\"module.exports = {|\"export default {|g')
# Special for deflate.js to export constants
# if echo "$jsfile" | grep -q "deflate.js"; then
# CONTENT=$(echo "$CONTENT" | sed '$a "export { Z_NO_FLUSH, Z_PARTIAL_FLUSH, Z_FULL_FLUSH, Z_FINISH, Z_BLOCK, Z_OK, Z_STREAM_END, Z_STREAM_ERROR, Z_DATA_ERROR, Z_BUF_ERROR, Z_DEFAULT_COMPRESSION, Z_FILTERED, Z_HUFFMAN_ONLY, Z_RLE, Z_FIXED, Z_DEFAULT_STRATEGY, Z_UNKNOWN, Z_DEFLATED };"')
# fi
# Special for zstream.js
if echo "$jsfile" | grep -q "zstream.js"; then
CONTENT=$(echo "$CONTENT" | sed 's|\"export { ZStream };\"|\"export default ZStream;\"|g')
fi
fi
echo "$CONTENT" | sed "s|'\\./|'/novnc/$RELDIR|g; s|\"\\./|\"/novnc/$RELDIR|g" | sed "s|'\\.\./vendor/|'/novnc/vendor/|g; s|\"\\.\./vendor/|\"/novnc/vendor/|g" >> novnc_asset_map.c
echo ";" >> novnc_asset_map.c
# Add to novnc_asset_map.c
echo " if (strcmp(path, \"/novnc/$RELPATH\") == 0) return novnc_${VARNAME};" >> novnc_asset_map.c
fi
done
cat >> novnc_assets.h << 'EOF'
#endif /* NOVNC_ASSETS_H */
EOF
cat >> novnc_asset_map.c << 'EOF'
return NULL;
}
EOF
echo "noVNC JS files embedded."
# Check if we need to process an HTML template
if [ $# -eq 1 ] && [[ "$1" == *.html ]]; then
echo "Processing HTML template: $1"
BASENAME=$(basename "$1" .html)
HEADER_FILE="html_pages/${BASENAME}_page.h"
mkdir -p html_pages
# Generate C header with HTML content
cat > "$HEADER_FILE" << EOF
/**
* ${BASENAME} page HTML template for wssshd
*
* Copyright (C) 2024 Stefy Lanza <stefy@nexlab.net> and SexHack.me
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef ${BASENAME^^}_PAGE_H
#define ${BASENAME^^}_PAGE_H
// ${BASENAME} page HTML template
EOF
# Add __attribute__((used)) for vnc_page_html to suppress unused variable warning
if [ "$BASENAME" = "vnc" ]; then
echo "static const char *${BASENAME}_page_html __attribute__((used)) =" >> "$HEADER_FILE"
else
echo "static const char *${BASENAME}_page_html =" >> "$HEADER_FILE"
fi
# Process the HTML file, escape quotes and replace {{ variables }} with %s
sed 's/\\/\\\\/g; s/"/\\"/g; s/^/"/; s/$/\\n"/' "$1" | \
sed 's/{{[^}]*}}/%s/g' >> "$HEADER_FILE"
# Close the string and header
cat >> "$HEADER_FILE" << EOF
;
#endif /* ${BASENAME^^}_PAGE_H */
EOF
echo "HTML template processed: $HEADER_FILE"
fi
# Process all HTML templates in templates/ directory
for template in templates/*.html; do
if [ -f "$template" ]; then
BASENAME=$(basename "$template" .html)
echo "Processing HTML template: $template"
HEADER_FILE="html_pages/${BASENAME}_page.h"
mkdir -p html_pages
# Generate C header with HTML content
# Add __attribute__((used)) for vnc_page_html to suppress unused variable warning
if [ "$BASENAME" = "vnc" ]; then
cat > "$HEADER_FILE" << EOF
/**
* ${BASENAME} page HTML template for wssshd
*
* Copyright (C) 2024 Stefy Lanza <stefy@nexlab.net> and SexHack.me
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef ${BASENAME^^}_PAGE_H
#define ${BASENAME^^}_PAGE_H
// ${BASENAME} page HTML template
static const char *${BASENAME}_page_html __attribute__((used)) =
EOF
# Process the HTML file, escape quotes and backslashes
sed 's/\\/\\\\/g; s/"/\\"/g; s/^/"/; s/$/\\n"/' "$template" >> "$HEADER_FILE"
elif [ "$BASENAME" = "rdp" ]; then
cat > "$HEADER_FILE" << EOF
/**
* ${BASENAME} page HTML template for wssshd
*
* Copyright (C) 2024 Stefy Lanza <stefy@nexlab.net> and SexHack.me
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef ${BASENAME^^}_PAGE_H
#define ${BASENAME^^}_PAGE_H
// ${BASENAME} page HTML template
static const char *${BASENAME}_page_html =
EOF
# Use python to properly escape the HTML
python3 -c "
import sys
with open('$template', 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
lines = content.split('\n')
for line in lines:
escaped_line = line.replace('\\\\', '\\\\\\\\').replace('\\\"', '\\\\\"').replace('%c%s', '%%c%%s')
print('\"' + escaped_line + '\\\\n\"')
" >> "$HEADER_FILE"
else
cat > "$HEADER_FILE" << EOF
/**
* ${BASENAME} page HTML template for wssshd
*
* Copyright (C) 2024 Stefy Lanza <stefy@nexlab.net> and SexHack.me
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef ${BASENAME^^}_PAGE_H
#define ${BASENAME^^}_PAGE_H
// ${BASENAME} page HTML template
static const char *${BASENAME}_page_html =
EOF
# Process the HTML file, escape quotes and backslashes
sed 's/\\/\\\\/g; s/"/\\"/g; s/^/"/; s/$/\\n"/' "$template" >> "$HEADER_FILE"
fi
# Close the string and header
cat >> "$HEADER_FILE" << EOF
;
#endif /* ${BASENAME^^}_PAGE_H */
EOF
echo "HTML template processed: $HEADER_FILE"
fi
done
echo "Assets embedded successfully"
......@@ -3479,634 +3479,15 @@ const char *novnc_input_keyboard_js =
"window.Keyboard = Keyboard;\n"
;
if (strcmp(path, "/novnc/input/keyboard.js") == 0) return novnc_input_keyboard_js;
const char *novnc_input_keysym_js =
"/* eslint-disable key-spacing */\n"
"\n"
"window.KeyTable = {\n"
" XK_VoidSymbol: 0xffffff, /* Void symbol */\n"
"\n"
" XK_BackSpace: 0xff08, /* Back space, back char */\n"
" XK_Tab: 0xff09,\n"
" XK_Linefeed: 0xff0a, /* Linefeed, LF */\n"
" XK_Clear: 0xff0b,\n"
" XK_Return: 0xff0d, /* Return, enter */\n"
" XK_Pause: 0xff13, /* Pause, hold */\n"
" XK_Scroll_Lock: 0xff14,\n"
" XK_Sys_Req: 0xff15,\n"
" XK_Escape: 0xff1b,\n"
" XK_Delete: 0xffff, /* Delete, rubout */\n"
"\n"
" /* International & multi-key character composition */\n"
"\n"
" XK_Multi_key: 0xff20, /* Multi-key character compose */\n"
" XK_Codeinput: 0xff37,\n"
" XK_SingleCandidate: 0xff3c,\n"
" XK_MultipleCandidate: 0xff3d,\n"
" XK_PreviousCandidate: 0xff3e,\n"
"\n"
" /* Japanese keyboard support */\n"
"\n"
" XK_Kanji: 0xff21, /* Kanji, Kanji convert */\n"
" XK_Muhenkan: 0xff22, /* Cancel Conversion */\n"
" XK_Henkan_Mode: 0xff23, /* Start/Stop Conversion */\n"
" XK_Henkan: 0xff23, /* Alias for Henkan_Mode */\n"
" XK_Romaji: 0xff24, /* to Romaji */\n"
" XK_Hiragana: 0xff25, /* to Hiragana */\n"
" XK_Katakana: 0xff26, /* to Katakana */\n"
" XK_Hiragana_Katakana: 0xff27, /* Hiragana/Katakana toggle */\n"
" XK_Zenkaku: 0xff28, /* to Zenkaku */\n"
" XK_Hankaku: 0xff29, /* to Hankaku */\n"
" XK_Zenkaku_Hankaku: 0xff2a, /* Zenkaku/Hankaku toggle */\n"
" XK_Touroku: 0xff2b, /* Add to Dictionary */\n"
" XK_Massyo: 0xff2c, /* Delete from Dictionary */\n"
" XK_Kana_Lock: 0xff2d, /* Kana Lock */\n"
" XK_Kana_Shift: 0xff2e, /* Kana Shift */\n"
" XK_Eisu_Shift: 0xff2f, /* Alphanumeric Shift */\n"
" XK_Eisu_toggle: 0xff30, /* Alphanumeric toggle */\n"
" XK_Kanji_Bangou: 0xff37, /* Codeinput */\n"
" XK_Zen_Koho: 0xff3d, /* Multiple/All Candidate(s) */\n"
" XK_Mae_Koho: 0xff3e, /* Previous Candidate */\n"
"\n"
" /* Cursor control & motion */\n"
"\n"
" XK_Home: 0xff50,\n"
" XK_Left: 0xff51, /* Move left, left arrow */\n"
" XK_Up: 0xff52, /* Move up, up arrow */\n"
" XK_Right: 0xff53, /* Move right, right arrow */\n"
" XK_Down: 0xff54, /* Move down, down arrow */\n"
" XK_Prior: 0xff55, /* Prior, previous */\n"
" XK_Page_Up: 0xff55,\n"
" XK_Next: 0xff56, /* Next */\n"
" XK_Page_Down: 0xff56,\n"
" XK_End: 0xff57, /* EOL */\n"
" XK_Begin: 0xff58, /* BOL */\n"
"\n"
"\n"
" /* Misc functions */\n"
"\n"
" XK_Select: 0xff60, /* Select, mark */\n"
" XK_Print: 0xff61,\n"
" XK_Execute: 0xff62, /* Execute, run, do */\n"
" XK_Insert: 0xff63, /* Insert, insert here */\n"
" XK_Undo: 0xff65,\n"
" XK_Redo: 0xff66, /* Redo, again */\n"
" XK_Menu: 0xff67,\n"
" XK_Find: 0xff68, /* Find, search */\n"
" XK_Cancel: 0xff69, /* Cancel, stop, abort, exit */\n"
" XK_Help: 0xff6a, /* Help */\n"
" XK_Break: 0xff6b,\n"
" XK_Mode_switch: 0xff7e, /* Character set switch */\n"
" XK_script_switch: 0xff7e, /* Alias for mode_switch */\n"
" XK_Num_Lock: 0xff7f,\n"
"\n"
" /* Keypad functions, keypad numbers cleverly chosen to map to ASCII */\n"
"\n"
" XK_KP_Space: 0xff80, /* Space */\n"
" XK_KP_Tab: 0xff89,\n"
" XK_KP_Enter: 0xff8d, /* Enter */\n"
" XK_KP_F1: 0xff91, /* PF1, KP_A, ... */\n"
" XK_KP_F2: 0xff92,\n"
" XK_KP_F3: 0xff93,\n"
" XK_KP_F4: 0xff94,\n"
" XK_KP_Home: 0xff95,\n"
" XK_KP_Left: 0xff96,\n"
" XK_KP_Up: 0xff97,\n"
" XK_KP_Right: 0xff98,\n"
" XK_KP_Down: 0xff99,\n"
" XK_KP_Prior: 0xff9a,\n"
" XK_KP_Page_Up: 0xff9a,\n"
" XK_KP_Next: 0xff9b,\n"
" XK_KP_Page_Down: 0xff9b,\n"
" XK_KP_End: 0xff9c,\n"
" XK_KP_Begin: 0xff9d,\n"
" XK_KP_Insert: 0xff9e,\n"
" XK_KP_Delete: 0xff9f,\n"
" XK_KP_Equal: 0xffbd, /* Equals */\n"
" XK_KP_Multiply: 0xffaa,\n"
" XK_KP_Add: 0xffab,\n"
" XK_KP_Separator: 0xffac, /* Separator, often comma */\n"
" XK_KP_Subtract: 0xffad,\n"
" XK_KP_Decimal: 0xffae,\n"
" XK_KP_Divide: 0xffaf,\n"
"\n"
" XK_KP_0: 0xffb0,\n"
" XK_KP_1: 0xffb1,\n"
" XK_KP_2: 0xffb2,\n"
" XK_KP_3: 0xffb3,\n"
" XK_KP_4: 0xffb4,\n"
" XK_KP_5: 0xffb5,\n"
" XK_KP_6: 0xffb6,\n"
" XK_KP_7: 0xffb7,\n"
" XK_KP_8: 0xffb8,\n"
" XK_KP_9: 0xffb9,\n"
"\n"
" /*\n"
" * Auxiliary functions; note the duplicate definitions for left and right\n"
" * function keys; Sun keyboards and a few other manufacturers have such\n"
" * function key groups on the left and/or right sides of the keyboard.\n"
" * We've not found a keyboard with more than 35 function keys total.\n"
" */\n"
"\n"
" XK_F1: 0xffbe,\n"
" XK_F2: 0xffbf,\n"
" XK_F3: 0xffc0,\n"
" XK_F4: 0xffc1,\n"
" XK_F5: 0xffc2,\n"
" XK_F6: 0xffc3,\n"
" XK_F7: 0xffc4,\n"
" XK_F8: 0xffc5,\n"
" XK_F9: 0xffc6,\n"
" XK_F10: 0xffc7,\n"
" XK_F11: 0xffc8,\n"
" XK_L1: 0xffc8,\n"
" XK_F12: 0xffc9,\n"
" XK_L2: 0xffc9,\n"
" XK_F13: 0xffca,\n"
" XK_L3: 0xffca,\n"
" XK_F14: 0xffcb,\n"
" XK_L4: 0xffcb,\n"
" XK_F15: 0xffcc,\n"
" XK_L5: 0xffcc,\n"
" XK_F16: 0xffcd,\n"
" XK_L6: 0xffcd,\n"
" XK_F17: 0xffce,\n"
" XK_L7: 0xffce,\n"
" XK_F18: 0xffcf,\n"
" XK_L8: 0xffcf,\n"
" XK_F19: 0xffd0,\n"
" XK_L9: 0xffd0,\n"
" XK_F20: 0xffd1,\n"
" XK_L10: 0xffd1,\n"
" XK_F21: 0xffd2,\n"
" XK_R1: 0xffd2,\n"
" XK_F22: 0xffd3,\n"
" XK_R2: 0xffd3,\n"
" XK_F23: 0xffd4,\n"
" XK_R3: 0xffd4,\n"
" XK_F24: 0xffd5,\n"
" XK_R4: 0xffd5,\n"
" XK_F25: 0xffd6,\n"
" XK_R5: 0xffd6,\n"
" XK_F26: 0xffd7,\n"
" XK_R6: 0xffd7,\n"
" XK_F27: 0xffd8,\n"
" XK_R7: 0xffd8,\n"
" XK_F28: 0xffd9,\n"
" XK_R8: 0xffd9,\n"
" XK_F29: 0xffda,\n"
" XK_R9: 0xffda,\n"
" XK_F30: 0xffdb,\n"
" XK_R10: 0xffdb,\n"
" XK_F31: 0xffdc,\n"
" XK_R11: 0xffdc,\n"
" XK_F32: 0xffdd,\n"
" XK_R12: 0xffdd,\n"
" XK_F33: 0xffde,\n"
" XK_R13: 0xffde,\n"
" XK_F34: 0xffdf,\n"
" XK_R14: 0xffdf,\n"
" XK_F35: 0xffe0,\n"
" XK_R15: 0xffe0,\n"
"\n"
" /* Modifiers */\n"
"\n"
" XK_Shift_L: 0xffe1, /* Left shift */\n"
" XK_Shift_R: 0xffe2, /* Right shift */\n"
" XK_Control_L: 0xffe3, /* Left control */\n"
" XK_Control_R: 0xffe4, /* Right control */\n"
" XK_Caps_Lock: 0xffe5, /* Caps lock */\n"
" XK_Shift_Lock: 0xffe6, /* Shift lock */\n"
"\n"
" XK_Meta_L: 0xffe7, /* Left meta */\n"
" XK_Meta_R: 0xffe8, /* Right meta */\n"
" XK_Alt_L: 0xffe9, /* Left alt */\n"
" XK_Alt_R: 0xffea, /* Right alt */\n"
" XK_Super_L: 0xffeb, /* Left super */\n"
" XK_Super_R: 0xffec, /* Right super */\n"
" XK_Hyper_L: 0xffed, /* Left hyper */\n"
" XK_Hyper_R: 0xffee, /* Right hyper */\n"
"\n"
" /*\n"
" * Keyboard (XKB) Extension function and modifier keys\n"
" * (from Appendix C of \"The X Keyboard Extension: Protocol Specification\")\n"
" * Byte 3 = 0xfe\n"
" */\n"
"\n"
" XK_ISO_Level3_Shift: 0xfe03, /* AltGr */\n"
" XK_ISO_Next_Group: 0xfe08,\n"
" XK_ISO_Prev_Group: 0xfe0a,\n"
" XK_ISO_First_Group: 0xfe0c,\n"
" XK_ISO_Last_Group: 0xfe0e,\n"
const char *novnc_input_keysymdef_js =
"/*\n"
" * Mapping from Unicode codepoints to X11/RFB keysyms\n"
" *\n"
" * This file was automatically generated from keysymdef.h\n"
" * DO NOT EDIT!\n"
" */\n"
"\n"
" /*\n"
" * Latin 1\n"
" * (ISO/IEC 8859-1: Unicode U+0020..U+00FF)\n"
" * Byte 3: 0\n"
" */\n"
"\n"
" XK_space: 0x0020, /* U+0020 SPACE */\n"
" XK_exclam: 0x0021, /* U+0021 EXCLAMATION MARK */\n"
" XK_quotedbl: 0x0022, /* U+0022 QUOTATION MARK */\n"
" XK_numbersign: 0x0023, /* U+0023 NUMBER SIGN */\n"
" XK_dollar: 0x0024, /* U+0024 DOLLAR SIGN */\n"
" XK_percent: 0x0025, /* U+0025 PERCENT SIGN */\n"
" XK_ampersand: 0x0026, /* U+0026 AMPERSAND */\n"
" XK_apostrophe: 0x0027, /* U+0027 APOSTROPHE */\n"
" XK_quoteright: 0x0027, /* deprecated */\n"
" XK_parenleft: 0x0028, /* U+0028 LEFT PARENTHESIS */\n"
" XK_parenright: 0x0029, /* U+0029 RIGHT PARENTHESIS */\n"
" XK_asterisk: 0x002a, /* U+002A ASTERISK */\n"
" XK_plus: 0x002b, /* U+002B PLUS SIGN */\n"
" XK_comma: 0x002c, /* U+002C COMMA */\n"
" XK_minus: 0x002d, /* U+002D HYPHEN-MINUS */\n"
" XK_period: 0x002e, /* U+002E FULL STOP */\n"
" XK_slash: 0x002f, /* U+002F SOLIDUS */\n"
" XK_0: 0x0030, /* U+0030 DIGIT ZERO */\n"
" XK_1: 0x0031, /* U+0031 DIGIT ONE */\n"
" XK_2: 0x0032, /* U+0032 DIGIT TWO */\n"
" XK_3: 0x0033, /* U+0033 DIGIT THREE */\n"
" XK_4: 0x0034, /* U+0034 DIGIT FOUR */\n"
" XK_5: 0x0035, /* U+0035 DIGIT FIVE */\n"
" XK_6: 0x0036, /* U+0036 DIGIT SIX */\n"
" XK_7: 0x0037, /* U+0037 DIGIT SEVEN */\n"
" XK_8: 0x0038, /* U+0038 DIGIT EIGHT */\n"
" XK_9: 0x0039, /* U+0039 DIGIT NINE */\n"
" XK_colon: 0x003a, /* U+003A COLON */\n"
" XK_semicolon: 0x003b, /* U+003B SEMICOLON */\n"
" XK_less: 0x003c, /* U+003C LESS-THAN SIGN */\n"
" XK_equal: 0x003d, /* U+003D EQUALS SIGN */\n"
" XK_greater: 0x003e, /* U+003E GREATER-THAN SIGN */\n"
" XK_question: 0x003f, /* U+003F QUESTION MARK */\n"
" XK_at: 0x0040, /* U+0040 COMMERCIAL AT */\n"
" XK_A: 0x0041, /* U+0041 LATIN CAPITAL LETTER A */\n"
" XK_B: 0x0042, /* U+0042 LATIN CAPITAL LETTER B */\n"
" XK_C: 0x0043, /* U+0043 LATIN CAPITAL LETTER C */\n"
" XK_D: 0x0044, /* U+0044 LATIN CAPITAL LETTER D */\n"
" XK_E: 0x0045, /* U+0045 LATIN CAPITAL LETTER E */\n"
" XK_F: 0x0046, /* U+0046 LATIN CAPITAL LETTER F */\n"
" XK_G: 0x0047, /* U+0047 LATIN CAPITAL LETTER G */\n"
" XK_H: 0x0048, /* U+0048 LATIN CAPITAL LETTER H */\n"
" XK_I: 0x0049, /* U+0049 LATIN CAPITAL LETTER I */\n"
" XK_J: 0x004a, /* U+004A LATIN CAPITAL LETTER J */\n"
" XK_K: 0x004b, /* U+004B LATIN CAPITAL LETTER K */\n"
" XK_L: 0x004c, /* U+004C LATIN CAPITAL LETTER L */\n"
" XK_M: 0x004d, /* U+004D LATIN CAPITAL LETTER M */\n"
" XK_N: 0x004e, /* U+004E LATIN CAPITAL LETTER N */\n"
" XK_O: 0x004f, /* U+004F LATIN CAPITAL LETTER O */\n"
" XK_P: 0x0050, /* U+0050 LATIN CAPITAL LETTER P */\n"
" XK_Q: 0x0051, /* U+0051 LATIN CAPITAL LETTER Q */\n"
" XK_R: 0x0052, /* U+0052 LATIN CAPITAL LETTER R */\n"
" XK_S: 0x0053, /* U+0053 LATIN CAPITAL LETTER S */\n"
" XK_T: 0x0054, /* U+0054 LATIN CAPITAL LETTER T */\n"
" XK_U: 0x0055, /* U+0055 LATIN CAPITAL LETTER U */\n"
" XK_V: 0x0056, /* U+0056 LATIN CAPITAL LETTER V */\n"
" XK_W: 0x0057, /* U+0057 LATIN CAPITAL LETTER W */\n"
" XK_X: 0x0058, /* U+0058 LATIN CAPITAL LETTER X */\n"
" XK_Y: 0x0059, /* U+0059 LATIN CAPITAL LETTER Y */\n"
" XK_Z: 0x005a, /* U+005A LATIN CAPITAL LETTER Z */\n"
" XK_bracketleft: 0x005b, /* U+005B LEFT SQUARE BRACKET */\n"
" XK_backslash: 0x005c, /* U+005C REVERSE SOLIDUS */\n"
" XK_bracketright: 0x005d, /* U+005D RIGHT SQUARE BRACKET */\n"
" XK_asciicircum: 0x005e, /* U+005E CIRCUMFLEX ACCENT */\n"
" XK_underscore: 0x005f, /* U+005F LOW LINE */\n"
" XK_grave: 0x0060, /* U+0060 GRAVE ACCENT */\n"
" XK_quoteleft: 0x0060, /* deprecated */\n"
" XK_a: 0x0061, /* U+0061 LATIN SMALL LETTER A */\n"
" XK_b: 0x0062, /* U+0062 LATIN SMALL LETTER B */\n"
" XK_c: 0x0063, /* U+0063 LATIN SMALL LETTER C */\n"
" XK_d: 0x0064, /* U+0064 LATIN SMALL LETTER D */\n"
" XK_e: 0x0065, /* U+0065 LATIN SMALL LETTER E */\n"
" XK_f: 0x0066, /* U+0066 LATIN SMALL LETTER F */\n"
" XK_g: 0x0067, /* U+0067 LATIN SMALL LETTER G */\n"
" XK_h: 0x0068, /* U+0068 LATIN SMALL LETTER H */\n"
" XK_i: 0x0069, /* U+0069 LATIN SMALL LETTER I */\n"
" XK_j: 0x006a, /* U+006A LATIN SMALL LETTER J */\n"
" XK_k: 0x006b, /* U+006B LATIN SMALL LETTER K */\n"
" XK_l: 0x006c, /* U+006C LATIN SMALL LETTER L */\n"
" XK_m: 0x006d, /* U+006D LATIN SMALL LETTER M */\n"
" XK_n: 0x006e, /* U+006E LATIN SMALL LETTER N */\n"
" XK_o: 0x006f, /* U+006F LATIN SMALL LETTER O */\n"
" XK_p: 0x0070, /* U+0070 LATIN SMALL LETTER P */\n"
" XK_q: 0x0071, /* U+0071 LATIN SMALL LETTER Q */\n"
" XK_r: 0x0072, /* U+0072 LATIN SMALL LETTER R */\n"
" XK_s: 0x0073, /* U+0073 LATIN SMALL LETTER S */\n"
" XK_t: 0x0074, /* U+0074 LATIN SMALL LETTER T */\n"
" XK_u: 0x0075, /* U+0075 LATIN SMALL LETTER U */\n"
" XK_v: 0x0076, /* U+0076 LATIN SMALL LETTER V */\n"
" XK_w: 0x0077, /* U+0077 LATIN SMALL LETTER W */\n"
" XK_x: 0x0078, /* U+0078 LATIN SMALL LETTER X */\n"
" XK_y: 0x0079, /* U+0079 LATIN SMALL LETTER Y */\n"
" XK_z: 0x007a, /* U+007A LATIN SMALL LETTER Z */\n"
" XK_braceleft: 0x007b, /* U+007B LEFT CURLY BRACKET */\n"
" XK_bar: 0x007c, /* U+007C VERTICAL LINE */\n"
" XK_braceright: 0x007d, /* U+007D RIGHT CURLY BRACKET */\n"
" XK_asciitilde: 0x007e, /* U+007E TILDE */\n"
"\n"
" XK_nobreakspace: 0x00a0, /* U+00A0 NO-BREAK SPACE */\n"
" XK_exclamdown: 0x00a1, /* U+00A1 INVERTED EXCLAMATION MARK */\n"
" XK_cent: 0x00a2, /* U+00A2 CENT SIGN */\n"
" XK_sterling: 0x00a3, /* U+00A3 POUND SIGN */\n"
" XK_currency: 0x00a4, /* U+00A4 CURRENCY SIGN */\n"
" XK_yen: 0x00a5, /* U+00A5 YEN SIGN */\n"
" XK_brokenbar: 0x00a6, /* U+00A6 BROKEN BAR */\n"
" XK_section: 0x00a7, /* U+00A7 SECTION SIGN */\n"
" XK_diaeresis: 0x00a8, /* U+00A8 DIAERESIS */\n"
" XK_copyright: 0x00a9, /* U+00A9 COPYRIGHT SIGN */\n"
" XK_ordfeminine: 0x00aa, /* U+00AA FEMININE ORDINAL INDICATOR */\n"
" XK_guillemotleft: 0x00ab, /* U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */\n"
" XK_notsign: 0x00ac, /* U+00AC NOT SIGN */\n"
" XK_hyphen: 0x00ad, /* U+00AD SOFT HYPHEN */\n"
" XK_registered: 0x00ae, /* U+00AE REGISTERED SIGN */\n"
" XK_macron: 0x00af, /* U+00AF MACRON */\n"
" XK_degree: 0x00b0, /* U+00B0 DEGREE SIGN */\n"
" XK_plusminus: 0x00b1, /* U+00B1 PLUS-MINUS SIGN */\n"
" XK_twosuperior: 0x00b2, /* U+00B2 SUPERSCRIPT TWO */\n"
" XK_threesuperior: 0x00b3, /* U+00B3 SUPERSCRIPT THREE */\n"
" XK_acute: 0x00b4, /* U+00B4 ACUTE ACCENT */\n"
" XK_mu: 0x00b5, /* U+00B5 MICRO SIGN */\n"
" XK_paragraph: 0x00b6, /* U+00B6 PILCROW SIGN */\n"
" XK_periodcentered: 0x00b7, /* U+00B7 MIDDLE DOT */\n"
" XK_cedilla: 0x00b8, /* U+00B8 CEDILLA */\n"
" XK_onesuperior: 0x00b9, /* U+00B9 SUPERSCRIPT ONE */\n"
" XK_masculine: 0x00ba, /* U+00BA MASCULINE ORDINAL INDICATOR */\n"
" XK_guillemotright: 0x00bb, /* U+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */\n"
" XK_onequarter: 0x00bc, /* U+00BC VULGAR FRACTION ONE QUARTER */\n"
" XK_onehalf: 0x00bd, /* U+00BD VULGAR FRACTION ONE HALF */\n"
" XK_threequarters: 0x00be, /* U+00BE VULGAR FRACTION THREE QUARTERS */\n"
" XK_questiondown: 0x00bf, /* U+00BF INVERTED QUESTION MARK */\n"
" XK_Agrave: 0x00c0, /* U+00C0 LATIN CAPITAL LETTER A WITH GRAVE */\n"
" XK_Aacute: 0x00c1, /* U+00C1 LATIN CAPITAL LETTER A WITH ACUTE */\n"
" XK_Acircumflex: 0x00c2, /* U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX */\n"
" XK_Atilde: 0x00c3, /* U+00C3 LATIN CAPITAL LETTER A WITH TILDE */\n"
" XK_Adiaeresis: 0x00c4, /* U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS */\n"
" XK_Aring: 0x00c5, /* U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE */\n"
" XK_AE: 0x00c6, /* U+00C6 LATIN CAPITAL LETTER AE */\n"
" XK_Ccedilla: 0x00c7, /* U+00C7 LATIN CAPITAL LETTER C WITH CEDILLA */\n"
" XK_Egrave: 0x00c8, /* U+00C8 LATIN CAPITAL LETTER E WITH GRAVE */\n"
" XK_Eacute: 0x00c9, /* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE */\n"
" XK_Ecircumflex: 0x00ca, /* U+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX */\n"
" XK_Ediaeresis: 0x00cb, /* U+00CB LATIN CAPITAL LETTER E WITH DIAERESIS */\n"
" XK_Igrave: 0x00cc, /* U+00CC LATIN CAPITAL LETTER I WITH GRAVE */\n"
" XK_Iacute: 0x00cd, /* U+00CD LATIN CAPITAL LETTER I WITH ACUTE */\n"
" XK_Icircumflex: 0x00ce, /* U+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX */\n"
" XK_Idiaeresis: 0x00cf, /* U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS */\n"
" XK_ETH: 0x00d0, /* U+00D0 LATIN CAPITAL LETTER ETH */\n"
" XK_Eth: 0x00d0, /* deprecated */\n"
" XK_Ntilde: 0x00d1, /* U+00D1 LATIN CAPITAL LETTER N WITH TILDE */\n"
" XK_Ograve: 0x00d2, /* U+00D2 LATIN CAPITAL LETTER O WITH GRAVE */\n"
" XK_Oacute: 0x00d3, /* U+00D3 LATIN CAPITAL LETTER O WITH ACUTE */\n"
" XK_Ocircumflex: 0x00d4, /* U+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX */\n"
" XK_Otilde: 0x00d5, /* U+00D5 LATIN CAPITAL LETTER O WITH TILDE */\n"
" XK_Odiaeresis: 0x00d6, /* U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS */\n"
" XK_multiply: 0x00d7, /* U+00D7 MULTIPLICATION SIGN */\n"
" XK_Oslash: 0x00d8, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */\n"
" XK_Ooblique: 0x00d8, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */\n"
" XK_Ugrave: 0x00d9, /* U+00D9 LATIN CAPITAL LETTER U WITH GRAVE */\n"
" XK_Uacute: 0x00da, /* U+00DA LATIN CAPITAL LETTER U WITH ACUTE */\n"
" XK_Ucircumflex: 0x00db, /* U+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX */\n"
" XK_Udiaeresis: 0x00dc, /* U+00DC LATIN CAPITAL LETTER U WITH DIAERESIS */\n"
" XK_Yacute: 0x00dd, /* U+00DD LATIN CAPITAL LETTER Y WITH ACUTE */\n"
" XK_THORN: 0x00de, /* U+00DE LATIN CAPITAL LETTER THORN */\n"
" XK_Thorn: 0x00de, /* deprecated */\n"
" XK_ssharp: 0x00df, /* U+00DF LATIN SMALL LETTER SHARP S */\n"
" XK_agrave: 0x00e0, /* U+00E0 LATIN SMALL LETTER A WITH GRAVE */\n"
" XK_aacute: 0x00e1, /* U+00E1 LATIN SMALL LETTER A WITH ACUTE */\n"
" XK_acircumflex: 0x00e2, /* U+00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX */\n"
" XK_atilde: 0x00e3, /* U+00E3 LATIN SMALL LETTER A WITH TILDE */\n"
" XK_adiaeresis: 0x00e4, /* U+00E4 LATIN SMALL LETTER A WITH DIAERESIS */\n"
" XK_aring: 0x00e5, /* U+00E5 LATIN SMALL LETTER A WITH RING ABOVE */\n"
" XK_ae: 0x00e6, /* U+00E6 LATIN SMALL LETTER AE */\n"
" XK_ccedilla: 0x00e7, /* U+00E7 LATIN SMALL LETTER C WITH CEDILLA */\n"
" XK_egrave: 0x00e8, /* U+00E8 LATIN SMALL LETTER E WITH GRAVE */\n"
" XK_eacute: 0x00e9, /* U+00E9 LATIN SMALL LETTER E WITH ACUTE */\n"
" XK_ecircumflex: 0x00ea, /* U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX */\n"
" XK_ediaeresis: 0x00eb, /* U+00EB LATIN SMALL LETTER E WITH DIAERESIS */\n"
" XK_igrave: 0x00ec, /* U+00EC LATIN SMALL LETTER I WITH GRAVE */\n"
" XK_iacute: 0x00ed, /* U+00ED LATIN SMALL LETTER I WITH ACUTE */\n"
" XK_icircumflex: 0x00ee, /* U+00EE LATIN SMALL LETTER I WITH CIRCUMFLEX */\n"
" XK_idiaeresis: 0x00ef, /* U+00EF LATIN SMALL LETTER I WITH DIAERESIS */\n"
" XK_eth: 0x00f0, /* U+00F0 LATIN SMALL LETTER ETH */\n"
" XK_ntilde: 0x00f1, /* U+00F1 LATIN SMALL LETTER N WITH TILDE */\n"
" XK_ograve: 0x00f2, /* U+00F2 LATIN SMALL LETTER O WITH GRAVE */\n"
" XK_oacute: 0x00f3, /* U+00F3 LATIN SMALL LETTER O WITH ACUTE */\n"
" XK_ocircumflex: 0x00f4, /* U+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX */\n"
" XK_otilde: 0x00f5, /* U+00F5 LATIN SMALL LETTER O WITH TILDE */\n"
" XK_odiaeresis: 0x00f6, /* U+00F6 LATIN SMALL LETTER O WITH DIAERESIS */\n"
" XK_division: 0x00f7, /* U+00F7 DIVISION SIGN */\n"
" XK_oslash: 0x00f8, /* U+00F8 LATIN SMALL LETTER O WITH STROKE */\n"
" XK_ooblique: 0x00f8, /* U+00F8 LATIN SMALL LETTER O WITH STROKE */\n"
" XK_ugrave: 0x00f9, /* U+00F9 LATIN SMALL LETTER U WITH GRAVE */\n"
" XK_uacute: 0x00fa, /* U+00FA LATIN SMALL LETTER U WITH ACUTE */\n"
" XK_ucircumflex: 0x00fb, /* U+00FB LATIN SMALL LETTER U WITH CIRCUMFLEX */\n"
" XK_udiaeresis: 0x00fc, /* U+00FC LATIN SMALL LETTER U WITH DIAERESIS */\n"
" XK_yacute: 0x00fd, /* U+00FD LATIN SMALL LETTER Y WITH ACUTE */\n"
" XK_thorn: 0x00fe, /* U+00FE LATIN SMALL LETTER THORN */\n"
" XK_ydiaeresis: 0x00ff, /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS */\n"
"\n"
" /*\n"
" * Korean\n"
" * Byte 3 = 0x0e\n"
" */\n"
"\n"
" XK_Hangul: 0xff31, /* Hangul start/stop(toggle) */\n"
" XK_Hangul_Hanja: 0xff34, /* Start Hangul->Hanja Conversion */\n"
" XK_Hangul_Jeonja: 0xff38, /* Jeonja mode */\n"
"\n"
" /*\n"
" * XFree86 vendor specific keysyms.\n"
" *\n"
" * The XFree86 keysym range is 0x10080001 - 0x1008FFFF.\n"
" */\n"
"\n"
" XF86XK_ModeLock: 0x1008FF01,\n"
" XF86XK_MonBrightnessUp: 0x1008FF02,\n"
" XF86XK_MonBrightnessDown: 0x1008FF03,\n"
" XF86XK_KbdLightOnOff: 0x1008FF04,\n"
" XF86XK_KbdBrightnessUp: 0x1008FF05,\n"
" XF86XK_KbdBrightnessDown: 0x1008FF06,\n"
" XF86XK_Standby: 0x1008FF10,\n"
" XF86XK_AudioLowerVolume: 0x1008FF11,\n"
" XF86XK_AudioMute: 0x1008FF12,\n"
" XF86XK_AudioRaiseVolume: 0x1008FF13,\n"
" XF86XK_AudioPlay: 0x1008FF14,\n"
" XF86XK_AudioStop: 0x1008FF15,\n"
" XF86XK_AudioPrev: 0x1008FF16,\n"
" XF86XK_AudioNext: 0x1008FF17,\n"
" XF86XK_HomePage: 0x1008FF18,\n"
" XF86XK_Mail: 0x1008FF19,\n"
" XF86XK_Start: 0x1008FF1A,\n"
" XF86XK_Search: 0x1008FF1B,\n"
" XF86XK_AudioRecord: 0x1008FF1C,\n"
" XF86XK_Calculator: 0x1008FF1D,\n"
" XF86XK_Memo: 0x1008FF1E,\n"
" XF86XK_ToDoList: 0x1008FF1F,\n"
" XF86XK_Calendar: 0x1008FF20,\n"
" XF86XK_PowerDown: 0x1008FF21,\n"
" XF86XK_ContrastAdjust: 0x1008FF22,\n"
" XF86XK_RockerUp: 0x1008FF23,\n"
" XF86XK_RockerDown: 0x1008FF24,\n"
" XF86XK_RockerEnter: 0x1008FF25,\n"
" XF86XK_Back: 0x1008FF26,\n"
" XF86XK_Forward: 0x1008FF27,\n"
" XF86XK_Stop: 0x1008FF28,\n"
" XF86XK_Refresh: 0x1008FF29,\n"
" XF86XK_PowerOff: 0x1008FF2A,\n"
" XF86XK_WakeUp: 0x1008FF2B,\n"
" XF86XK_Eject: 0x1008FF2C,\n"
" XF86XK_ScreenSaver: 0x1008FF2D,\n"
" XF86XK_WWW: 0x1008FF2E,\n"
" XF86XK_Sleep: 0x1008FF2F,\n"
" XF86XK_Favorites: 0x1008FF30,\n"
" XF86XK_AudioPause: 0x1008FF31,\n"
" XF86XK_AudioMedia: 0x1008FF32,\n"
" XF86XK_MyComputer: 0x1008FF33,\n"
" XF86XK_VendorHome: 0x1008FF34,\n"
" XF86XK_LightBulb: 0x1008FF35,\n"
" XF86XK_Shop: 0x1008FF36,\n"
" XF86XK_History: 0x1008FF37,\n"
" XF86XK_OpenURL: 0x1008FF38,\n"
" XF86XK_AddFavorite: 0x1008FF39,\n"
" XF86XK_HotLinks: 0x1008FF3A,\n"
" XF86XK_BrightnessAdjust: 0x1008FF3B,\n"
" XF86XK_Finance: 0x1008FF3C,\n"
" XF86XK_Community: 0x1008FF3D,\n"
" XF86XK_AudioRewind: 0x1008FF3E,\n"
" XF86XK_BackForward: 0x1008FF3F,\n"
" XF86XK_Launch0: 0x1008FF40,\n"
" XF86XK_Launch1: 0x1008FF41,\n"
" XF86XK_Launch2: 0x1008FF42,\n"
" XF86XK_Launch3: 0x1008FF43,\n"
" XF86XK_Launch4: 0x1008FF44,\n"
" XF86XK_Launch5: 0x1008FF45,\n"
" XF86XK_Launch6: 0x1008FF46,\n"
" XF86XK_Launch7: 0x1008FF47,\n"
" XF86XK_Launch8: 0x1008FF48,\n"
" XF86XK_Launch9: 0x1008FF49,\n"
" XF86XK_LaunchA: 0x1008FF4A,\n"
" XF86XK_LaunchB: 0x1008FF4B,\n"
" XF86XK_LaunchC: 0x1008FF4C,\n"
" XF86XK_LaunchD: 0x1008FF4D,\n"
" XF86XK_LaunchE: 0x1008FF4E,\n"
" XF86XK_LaunchF: 0x1008FF4F,\n"
" XF86XK_ApplicationLeft: 0x1008FF50,\n"
" XF86XK_ApplicationRight: 0x1008FF51,\n"
" XF86XK_Book: 0x1008FF52,\n"
" XF86XK_CD: 0x1008FF53,\n"
" XF86XK_Calculater: 0x1008FF54,\n"
" XF86XK_Clear: 0x1008FF55,\n"
" XF86XK_Close: 0x1008FF56,\n"
" XF86XK_Copy: 0x1008FF57,\n"
" XF86XK_Cut: 0x1008FF58,\n"
" XF86XK_Display: 0x1008FF59,\n"
" XF86XK_DOS: 0x1008FF5A,\n"
" XF86XK_Documents: 0x1008FF5B,\n"
" XF86XK_Excel: 0x1008FF5C,\n"
" XF86XK_Explorer: 0x1008FF5D,\n"
" XF86XK_Game: 0x1008FF5E,\n"
" XF86XK_Go: 0x1008FF5F,\n"
" XF86XK_iTouch: 0x1008FF60,\n"
" XF86XK_LogOff: 0x1008FF61,\n"
" XF86XK_Market: 0x1008FF62,\n"
" XF86XK_Meeting: 0x1008FF63,\n"
" XF86XK_MenuKB: 0x1008FF65,\n"
" XF86XK_MenuPB: 0x1008FF66,\n"
" XF86XK_MySites: 0x1008FF67,\n"
" XF86XK_New: 0x1008FF68,\n"
" XF86XK_News: 0x1008FF69,\n"
" XF86XK_OfficeHome: 0x1008FF6A,\n"
" XF86XK_Open: 0x1008FF6B,\n"
" XF86XK_Option: 0x1008FF6C,\n"
" XF86XK_Paste: 0x1008FF6D,\n"
" XF86XK_Phone: 0x1008FF6E,\n"
" XF86XK_Q: 0x1008FF70,\n"
" XF86XK_Reply: 0x1008FF72,\n"
" XF86XK_Reload: 0x1008FF73,\n"
" XF86XK_RotateWindows: 0x1008FF74,\n"
" XF86XK_RotationPB: 0x1008FF75,\n"
" XF86XK_RotationKB: 0x1008FF76,\n"
" XF86XK_Save: 0x1008FF77,\n"
" XF86XK_ScrollUp: 0x1008FF78,\n"
" XF86XK_ScrollDown: 0x1008FF79,\n"
" XF86XK_ScrollClick: 0x1008FF7A,\n"
" XF86XK_Send: 0x1008FF7B,\n"
" XF86XK_Spell: 0x1008FF7C,\n"
" XF86XK_SplitScreen: 0x1008FF7D,\n"
" XF86XK_Support: 0x1008FF7E,\n"
" XF86XK_TaskPane: 0x1008FF7F,\n"
" XF86XK_Terminal: 0x1008FF80,\n"
" XF86XK_Tools: 0x1008FF81,\n"
" XF86XK_Travel: 0x1008FF82,\n"
" XF86XK_UserPB: 0x1008FF84,\n"
" XF86XK_User1KB: 0x1008FF85,\n"
" XF86XK_User2KB: 0x1008FF86,\n"
" XF86XK_Video: 0x1008FF87,\n"
" XF86XK_WheelButton: 0x1008FF88,\n"
" XF86XK_Word: 0x1008FF89,\n"
" XF86XK_Xfer: 0x1008FF8A,\n"
" XF86XK_ZoomIn: 0x1008FF8B,\n"
" XF86XK_ZoomOut: 0x1008FF8C,\n"
" XF86XK_Away: 0x1008FF8D,\n"
" XF86XK_Messenger: 0x1008FF8E,\n"
" XF86XK_WebCam: 0x1008FF8F,\n"
" XF86XK_MailForward: 0x1008FF90,\n"
" XF86XK_Pictures: 0x1008FF91,\n"
" XF86XK_Music: 0x1008FF92,\n"
" XF86XK_Battery: 0x1008FF93,\n"
" XF86XK_Bluetooth: 0x1008FF94,\n"
" XF86XK_WLAN: 0x1008FF95,\n"
" XF86XK_UWB: 0x1008FF96,\n"
" XF86XK_AudioForward: 0x1008FF97,\n"
" XF86XK_AudioRepeat: 0x1008FF98,\n"
" XF86XK_AudioRandomPlay: 0x1008FF99,\n"
" XF86XK_Subtitle: 0x1008FF9A,\n"
" XF86XK_AudioCycleTrack: 0x1008FF9B,\n"
" XF86XK_CycleAngle: 0x1008FF9C,\n"
" XF86XK_FrameBack: 0x1008FF9D,\n"
" XF86XK_FrameForward: 0x1008FF9E,\n"
" XF86XK_Time: 0x1008FF9F,\n"
" XF86XK_Select: 0x1008FFA0,\n"
" XF86XK_View: 0x1008FFA1,\n"
" XF86XK_TopMenu: 0x1008FFA2,\n"
" XF86XK_Red: 0x1008FFA3,\n"
" XF86XK_Green: 0x1008FFA4,\n"
" XF86XK_Yellow: 0x1008FFA5,\n"
" XF86XK_Blue: 0x1008FFA6,\n"
" XF86XK_Suspend: 0x1008FFA7,\n"
" XF86XK_Hibernate: 0x1008FFA8,\n"
" XF86XK_TouchpadToggle: 0x1008FFA9,\n"
" XF86XK_TouchpadOn: 0x1008FFB0,\n"
" XF86XK_TouchpadOff: 0x1008FFB1,\n"
" XF86XK_AudioMicMute: 0x1008FFB2,\n"
" XF86XK_Switch_VT_1: 0x1008FE01,\n"
" XF86XK_Switch_VT_2: 0x1008FE02,\n"
" XF86XK_Switch_VT_3: 0x1008FE03,\n"
" XF86XK_Switch_VT_4: 0x1008FE04,\n"
" XF86XK_Switch_VT_5: 0x1008FE05,\n"
" XF86XK_Switch_VT_6: 0x1008FE06,\n"
" XF86XK_Switch_VT_7: 0x1008FE07,\n"
" XF86XK_Switch_VT_8: 0x1008FE08,\n"
" XF86XK_Switch_VT_9: 0x1008FE09,\n"
" XF86XK_Switch_VT_10: 0x1008FE0A,\n"
" XF86XK_Switch_VT_11: 0x1008FE0B,\n"
" XF86XK_Switch_VT_12: 0x1008FE0C,\n"
" XF86XK_Ungrab: 0x1008FE20,\n"
" XF86XK_ClearGrab: 0x1008FE21,\n"
" XF86XK_Next_VMode: 0x1008FE22,\n"
" XF86XK_Prev_VMode: 0x1008FE23,\n"
" XF86XK_LogWindowTree: 0x1008FE24,\n"
" XF86XK_LogGrabInfo: 0x1008FE25,\n"
"};\n"
;
if (strcmp(path, "/novnc/input/keysym.js") == 0) return novnc_input_keysym_js;
const char *novnc_input_keysymdef_js =
"/*\n"
" * Mapping from Unicode codepoints to X11/RFB keysyms\n"
" *\n"
" * This file was automatically generated from keysymdef.h\n"
" * DO NOT EDIT!\n"
" */\n"
"\n"
"/* Functions at the bottom */\n"
"/* Functions at the bottom */\n"
"\n"
"const codepoints = {\n"
" 0x0100: 0x03c0, // XK_Amacron\n"
......@@ -4770,29 +4151,648 @@ const char *novnc_input_keysymdef_js =
" 0x30fc: 0x04b0, // XK_prolongedsound\n"
"};\n"
"\n"
"window.lookup = function(u) {\n"
" // Latin-1 is one-to-one mapping\n"
" if ((u >= 0x20) && (u <= 0xff)) {\n"
" return u;\n"
" }\n"
"window.lookup = function(u) {\n"
" // Latin-1 is one-to-one mapping\n"
" if ((u >= 0x20) && (u <= 0xff)) {\n"
" return u;\n"
" }\n"
"\n"
" // Lookup table (fairly random)\n"
" const keysym = codepoints[u];\n"
" if (keysym !== undefined) {\n"
" return keysym;\n"
" }\n"
"\n"
" // General mapping as final fallback\n"
" return 0x01000000 | u;\n"
"};\n"
"window.codepoints = codepoints;\n"
"\n"
"// Create keysyms object for compatibility with util.js\n"
"window.keysyms = {\n"
" lookup: window.lookup\n"
"};\n"
;
if (strcmp(path, "/novnc/input/keysymdef.js") == 0) return novnc_input_keysymdef_js;
const char *novnc_input_keysym_js =
"/* eslint-disable key-spacing */\n"
"\n"
"window.KeyTable = {\n"
" XK_VoidSymbol: 0xffffff, /* Void symbol */\n"
"\n"
" XK_BackSpace: 0xff08, /* Back space, back char */\n"
" XK_Tab: 0xff09,\n"
" XK_Linefeed: 0xff0a, /* Linefeed, LF */\n"
" XK_Clear: 0xff0b,\n"
" XK_Return: 0xff0d, /* Return, enter */\n"
" XK_Pause: 0xff13, /* Pause, hold */\n"
" XK_Scroll_Lock: 0xff14,\n"
" XK_Sys_Req: 0xff15,\n"
" XK_Escape: 0xff1b,\n"
" XK_Delete: 0xffff, /* Delete, rubout */\n"
"\n"
" /* International & multi-key character composition */\n"
"\n"
" XK_Multi_key: 0xff20, /* Multi-key character compose */\n"
" XK_Codeinput: 0xff37,\n"
" XK_SingleCandidate: 0xff3c,\n"
" XK_MultipleCandidate: 0xff3d,\n"
" XK_PreviousCandidate: 0xff3e,\n"
"\n"
" /* Japanese keyboard support */\n"
"\n"
" XK_Kanji: 0xff21, /* Kanji, Kanji convert */\n"
" XK_Muhenkan: 0xff22, /* Cancel Conversion */\n"
" XK_Henkan_Mode: 0xff23, /* Start/Stop Conversion */\n"
" XK_Henkan: 0xff23, /* Alias for Henkan_Mode */\n"
" XK_Romaji: 0xff24, /* to Romaji */\n"
" XK_Hiragana: 0xff25, /* to Hiragana */\n"
" XK_Katakana: 0xff26, /* to Katakana */\n"
" XK_Hiragana_Katakana: 0xff27, /* Hiragana/Katakana toggle */\n"
" XK_Zenkaku: 0xff28, /* to Zenkaku */\n"
" XK_Hankaku: 0xff29, /* to Hankaku */\n"
" XK_Zenkaku_Hankaku: 0xff2a, /* Zenkaku/Hankaku toggle */\n"
" XK_Touroku: 0xff2b, /* Add to Dictionary */\n"
" XK_Massyo: 0xff2c, /* Delete from Dictionary */\n"
" XK_Kana_Lock: 0xff2d, /* Kana Lock */\n"
" XK_Kana_Shift: 0xff2e, /* Kana Shift */\n"
" XK_Eisu_Shift: 0xff2f, /* Alphanumeric Shift */\n"
" XK_Eisu_toggle: 0xff30, /* Alphanumeric toggle */\n"
" XK_Kanji_Bangou: 0xff37, /* Codeinput */\n"
" XK_Zen_Koho: 0xff3d, /* Multiple/All Candidate(s) */\n"
" XK_Mae_Koho: 0xff3e, /* Previous Candidate */\n"
"\n"
" /* Cursor control & motion */\n"
"\n"
" XK_Home: 0xff50,\n"
" XK_Left: 0xff51, /* Move left, left arrow */\n"
" XK_Up: 0xff52, /* Move up, up arrow */\n"
" XK_Right: 0xff53, /* Move right, right arrow */\n"
" XK_Down: 0xff54, /* Move down, down arrow */\n"
" XK_Prior: 0xff55, /* Prior, previous */\n"
" XK_Page_Up: 0xff55,\n"
" XK_Next: 0xff56, /* Next */\n"
" XK_Page_Down: 0xff56,\n"
" XK_End: 0xff57, /* EOL */\n"
" XK_Begin: 0xff58, /* BOL */\n"
"\n"
"\n"
" /* Misc functions */\n"
"\n"
" XK_Select: 0xff60, /* Select, mark */\n"
" XK_Print: 0xff61,\n"
" XK_Execute: 0xff62, /* Execute, run, do */\n"
" XK_Insert: 0xff63, /* Insert, insert here */\n"
" XK_Undo: 0xff65,\n"
" XK_Redo: 0xff66, /* Redo, again */\n"
" XK_Menu: 0xff67,\n"
" XK_Find: 0xff68, /* Find, search */\n"
" XK_Cancel: 0xff69, /* Cancel, stop, abort, exit */\n"
" XK_Help: 0xff6a, /* Help */\n"
" XK_Break: 0xff6b,\n"
" XK_Mode_switch: 0xff7e, /* Character set switch */\n"
" XK_script_switch: 0xff7e, /* Alias for mode_switch */\n"
" XK_Num_Lock: 0xff7f,\n"
"\n"
" /* Keypad functions, keypad numbers cleverly chosen to map to ASCII */\n"
"\n"
" XK_KP_Space: 0xff80, /* Space */\n"
" XK_KP_Tab: 0xff89,\n"
" XK_KP_Enter: 0xff8d, /* Enter */\n"
" XK_KP_F1: 0xff91, /* PF1, KP_A, ... */\n"
" XK_KP_F2: 0xff92,\n"
" XK_KP_F3: 0xff93,\n"
" XK_KP_F4: 0xff94,\n"
" XK_KP_Home: 0xff95,\n"
" XK_KP_Left: 0xff96,\n"
" XK_KP_Up: 0xff97,\n"
" XK_KP_Right: 0xff98,\n"
" XK_KP_Down: 0xff99,\n"
" XK_KP_Prior: 0xff9a,\n"
" XK_KP_Page_Up: 0xff9a,\n"
" XK_KP_Next: 0xff9b,\n"
" XK_KP_Page_Down: 0xff9b,\n"
" XK_KP_End: 0xff9c,\n"
" XK_KP_Begin: 0xff9d,\n"
" XK_KP_Insert: 0xff9e,\n"
" XK_KP_Delete: 0xff9f,\n"
" XK_KP_Equal: 0xffbd, /* Equals */\n"
" XK_KP_Multiply: 0xffaa,\n"
" XK_KP_Add: 0xffab,\n"
" XK_KP_Separator: 0xffac, /* Separator, often comma */\n"
" XK_KP_Subtract: 0xffad,\n"
" XK_KP_Decimal: 0xffae,\n"
" XK_KP_Divide: 0xffaf,\n"
"\n"
" XK_KP_0: 0xffb0,\n"
" XK_KP_1: 0xffb1,\n"
" XK_KP_2: 0xffb2,\n"
" XK_KP_3: 0xffb3,\n"
" XK_KP_4: 0xffb4,\n"
" XK_KP_5: 0xffb5,\n"
" XK_KP_6: 0xffb6,\n"
" XK_KP_7: 0xffb7,\n"
" XK_KP_8: 0xffb8,\n"
" XK_KP_9: 0xffb9,\n"
"\n"
" /*\n"
" * Auxiliary functions; note the duplicate definitions for left and right\n"
" * function keys; Sun keyboards and a few other manufacturers have such\n"
" * function key groups on the left and/or right sides of the keyboard.\n"
" * We've not found a keyboard with more than 35 function keys total.\n"
" */\n"
"\n"
" XK_F1: 0xffbe,\n"
" XK_F2: 0xffbf,\n"
" XK_F3: 0xffc0,\n"
" XK_F4: 0xffc1,\n"
" XK_F5: 0xffc2,\n"
" XK_F6: 0xffc3,\n"
" XK_F7: 0xffc4,\n"
" XK_F8: 0xffc5,\n"
" XK_F9: 0xffc6,\n"
" XK_F10: 0xffc7,\n"
" XK_F11: 0xffc8,\n"
" XK_L1: 0xffc8,\n"
" XK_F12: 0xffc9,\n"
" XK_L2: 0xffc9,\n"
" XK_F13: 0xffca,\n"
" XK_L3: 0xffca,\n"
" XK_F14: 0xffcb,\n"
" XK_L4: 0xffcb,\n"
" XK_F15: 0xffcc,\n"
" XK_L5: 0xffcc,\n"
" XK_F16: 0xffcd,\n"
" XK_L6: 0xffcd,\n"
" XK_F17: 0xffce,\n"
" XK_L7: 0xffce,\n"
" XK_F18: 0xffcf,\n"
" XK_L8: 0xffcf,\n"
" XK_F19: 0xffd0,\n"
" XK_L9: 0xffd0,\n"
" XK_F20: 0xffd1,\n"
" XK_L10: 0xffd1,\n"
" XK_F21: 0xffd2,\n"
" XK_R1: 0xffd2,\n"
" XK_F22: 0xffd3,\n"
" XK_R2: 0xffd3,\n"
" XK_F23: 0xffd4,\n"
" XK_R3: 0xffd4,\n"
" XK_F24: 0xffd5,\n"
" XK_R4: 0xffd5,\n"
" XK_F25: 0xffd6,\n"
" XK_R5: 0xffd6,\n"
" XK_F26: 0xffd7,\n"
" XK_R6: 0xffd7,\n"
" XK_F27: 0xffd8,\n"
" XK_R7: 0xffd8,\n"
" XK_F28: 0xffd9,\n"
" XK_R8: 0xffd9,\n"
" XK_F29: 0xffda,\n"
" XK_R9: 0xffda,\n"
" XK_F30: 0xffdb,\n"
" XK_R10: 0xffdb,\n"
" XK_F31: 0xffdc,\n"
" XK_R11: 0xffdc,\n"
" XK_F32: 0xffdd,\n"
" XK_R12: 0xffdd,\n"
" XK_F33: 0xffde,\n"
" XK_R13: 0xffde,\n"
" XK_F34: 0xffdf,\n"
" XK_R14: 0xffdf,\n"
" XK_F35: 0xffe0,\n"
" XK_R15: 0xffe0,\n"
"\n"
" /* Modifiers */\n"
"\n"
" XK_Shift_L: 0xffe1, /* Left shift */\n"
" XK_Shift_R: 0xffe2, /* Right shift */\n"
" XK_Control_L: 0xffe3, /* Left control */\n"
" XK_Control_R: 0xffe4, /* Right control */\n"
" XK_Caps_Lock: 0xffe5, /* Caps lock */\n"
" XK_Shift_Lock: 0xffe6, /* Shift lock */\n"
"\n"
" XK_Meta_L: 0xffe7, /* Left meta */\n"
" XK_Meta_R: 0xffe8, /* Right meta */\n"
" XK_Alt_L: 0xffe9, /* Left alt */\n"
" XK_Alt_R: 0xffea, /* Right alt */\n"
" XK_Super_L: 0xffeb, /* Left super */\n"
" XK_Super_R: 0xffec, /* Right super */\n"
" XK_Hyper_L: 0xffed, /* Left hyper */\n"
" XK_Hyper_R: 0xffee, /* Right hyper */\n"
"\n"
" /*\n"
" * Keyboard (XKB) Extension function and modifier keys\n"
" * (from Appendix C of \"The X Keyboard Extension: Protocol Specification\")\n"
" * Byte 3 = 0xfe\n"
" */\n"
"\n"
" XK_ISO_Level3_Shift: 0xfe03, /* AltGr */\n"
" XK_ISO_Next_Group: 0xfe08,\n"
" XK_ISO_Prev_Group: 0xfe0a,\n"
" XK_ISO_First_Group: 0xfe0c,\n"
" XK_ISO_Last_Group: 0xfe0e,\n"
"\n"
" /*\n"
" * Latin 1\n"
" * (ISO/IEC 8859-1: Unicode U+0020..U+00FF)\n"
" * Byte 3: 0\n"
" */\n"
"\n"
" XK_space: 0x0020, /* U+0020 SPACE */\n"
" XK_exclam: 0x0021, /* U+0021 EXCLAMATION MARK */\n"
" XK_quotedbl: 0x0022, /* U+0022 QUOTATION MARK */\n"
" XK_numbersign: 0x0023, /* U+0023 NUMBER SIGN */\n"
" XK_dollar: 0x0024, /* U+0024 DOLLAR SIGN */\n"
" XK_percent: 0x0025, /* U+0025 PERCENT SIGN */\n"
" XK_ampersand: 0x0026, /* U+0026 AMPERSAND */\n"
" XK_apostrophe: 0x0027, /* U+0027 APOSTROPHE */\n"
" XK_quoteright: 0x0027, /* deprecated */\n"
" XK_parenleft: 0x0028, /* U+0028 LEFT PARENTHESIS */\n"
" XK_parenright: 0x0029, /* U+0029 RIGHT PARENTHESIS */\n"
" XK_asterisk: 0x002a, /* U+002A ASTERISK */\n"
" XK_plus: 0x002b, /* U+002B PLUS SIGN */\n"
" XK_comma: 0x002c, /* U+002C COMMA */\n"
" XK_minus: 0x002d, /* U+002D HYPHEN-MINUS */\n"
" XK_period: 0x002e, /* U+002E FULL STOP */\n"
" XK_slash: 0x002f, /* U+002F SOLIDUS */\n"
" XK_0: 0x0030, /* U+0030 DIGIT ZERO */\n"
" XK_1: 0x0031, /* U+0031 DIGIT ONE */\n"
" XK_2: 0x0032, /* U+0032 DIGIT TWO */\n"
" XK_3: 0x0033, /* U+0033 DIGIT THREE */\n"
" XK_4: 0x0034, /* U+0034 DIGIT FOUR */\n"
" XK_5: 0x0035, /* U+0035 DIGIT FIVE */\n"
" XK_6: 0x0036, /* U+0036 DIGIT SIX */\n"
" XK_7: 0x0037, /* U+0037 DIGIT SEVEN */\n"
" XK_8: 0x0038, /* U+0038 DIGIT EIGHT */\n"
" XK_9: 0x0039, /* U+0039 DIGIT NINE */\n"
" XK_colon: 0x003a, /* U+003A COLON */\n"
" XK_semicolon: 0x003b, /* U+003B SEMICOLON */\n"
" XK_less: 0x003c, /* U+003C LESS-THAN SIGN */\n"
" XK_equal: 0x003d, /* U+003D EQUALS SIGN */\n"
" XK_greater: 0x003e, /* U+003E GREATER-THAN SIGN */\n"
" XK_question: 0x003f, /* U+003F QUESTION MARK */\n"
" XK_at: 0x0040, /* U+0040 COMMERCIAL AT */\n"
" XK_A: 0x0041, /* U+0041 LATIN CAPITAL LETTER A */\n"
" XK_B: 0x0042, /* U+0042 LATIN CAPITAL LETTER B */\n"
" XK_C: 0x0043, /* U+0043 LATIN CAPITAL LETTER C */\n"
" XK_D: 0x0044, /* U+0044 LATIN CAPITAL LETTER D */\n"
" XK_E: 0x0045, /* U+0045 LATIN CAPITAL LETTER E */\n"
" XK_F: 0x0046, /* U+0046 LATIN CAPITAL LETTER F */\n"
" XK_G: 0x0047, /* U+0047 LATIN CAPITAL LETTER G */\n"
" XK_H: 0x0048, /* U+0048 LATIN CAPITAL LETTER H */\n"
" XK_I: 0x0049, /* U+0049 LATIN CAPITAL LETTER I */\n"
" XK_J: 0x004a, /* U+004A LATIN CAPITAL LETTER J */\n"
" XK_K: 0x004b, /* U+004B LATIN CAPITAL LETTER K */\n"
" XK_L: 0x004c, /* U+004C LATIN CAPITAL LETTER L */\n"
" XK_M: 0x004d, /* U+004D LATIN CAPITAL LETTER M */\n"
" XK_N: 0x004e, /* U+004E LATIN CAPITAL LETTER N */\n"
" XK_O: 0x004f, /* U+004F LATIN CAPITAL LETTER O */\n"
" XK_P: 0x0050, /* U+0050 LATIN CAPITAL LETTER P */\n"
" XK_Q: 0x0051, /* U+0051 LATIN CAPITAL LETTER Q */\n"
" XK_R: 0x0052, /* U+0052 LATIN CAPITAL LETTER R */\n"
" XK_S: 0x0053, /* U+0053 LATIN CAPITAL LETTER S */\n"
" XK_T: 0x0054, /* U+0054 LATIN CAPITAL LETTER T */\n"
" XK_U: 0x0055, /* U+0055 LATIN CAPITAL LETTER U */\n"
" XK_V: 0x0056, /* U+0056 LATIN CAPITAL LETTER V */\n"
" XK_W: 0x0057, /* U+0057 LATIN CAPITAL LETTER W */\n"
" XK_X: 0x0058, /* U+0058 LATIN CAPITAL LETTER X */\n"
" XK_Y: 0x0059, /* U+0059 LATIN CAPITAL LETTER Y */\n"
" XK_Z: 0x005a, /* U+005A LATIN CAPITAL LETTER Z */\n"
" XK_bracketleft: 0x005b, /* U+005B LEFT SQUARE BRACKET */\n"
" XK_backslash: 0x005c, /* U+005C REVERSE SOLIDUS */\n"
" XK_bracketright: 0x005d, /* U+005D RIGHT SQUARE BRACKET */\n"
" XK_asciicircum: 0x005e, /* U+005E CIRCUMFLEX ACCENT */\n"
" XK_underscore: 0x005f, /* U+005F LOW LINE */\n"
" XK_grave: 0x0060, /* U+0060 GRAVE ACCENT */\n"
" XK_quoteleft: 0x0060, /* deprecated */\n"
" XK_a: 0x0061, /* U+0061 LATIN SMALL LETTER A */\n"
" XK_b: 0x0062, /* U+0062 LATIN SMALL LETTER B */\n"
" XK_c: 0x0063, /* U+0063 LATIN SMALL LETTER C */\n"
" XK_d: 0x0064, /* U+0064 LATIN SMALL LETTER D */\n"
" XK_e: 0x0065, /* U+0065 LATIN SMALL LETTER E */\n"
" XK_f: 0x0066, /* U+0066 LATIN SMALL LETTER F */\n"
" XK_g: 0x0067, /* U+0067 LATIN SMALL LETTER G */\n"
" XK_h: 0x0068, /* U+0068 LATIN SMALL LETTER H */\n"
" XK_i: 0x0069, /* U+0069 LATIN SMALL LETTER I */\n"
" XK_j: 0x006a, /* U+006A LATIN SMALL LETTER J */\n"
" XK_k: 0x006b, /* U+006B LATIN SMALL LETTER K */\n"
" XK_l: 0x006c, /* U+006C LATIN SMALL LETTER L */\n"
" XK_m: 0x006d, /* U+006D LATIN SMALL LETTER M */\n"
" XK_n: 0x006e, /* U+006E LATIN SMALL LETTER N */\n"
" XK_o: 0x006f, /* U+006F LATIN SMALL LETTER O */\n"
" XK_p: 0x0070, /* U+0070 LATIN SMALL LETTER P */\n"
" XK_q: 0x0071, /* U+0071 LATIN SMALL LETTER Q */\n"
" XK_r: 0x0072, /* U+0072 LATIN SMALL LETTER R */\n"
" XK_s: 0x0073, /* U+0073 LATIN SMALL LETTER S */\n"
" XK_t: 0x0074, /* U+0074 LATIN SMALL LETTER T */\n"
" XK_u: 0x0075, /* U+0075 LATIN SMALL LETTER U */\n"
" XK_v: 0x0076, /* U+0076 LATIN SMALL LETTER V */\n"
" XK_w: 0x0077, /* U+0077 LATIN SMALL LETTER W */\n"
" XK_x: 0x0078, /* U+0078 LATIN SMALL LETTER X */\n"
" XK_y: 0x0079, /* U+0079 LATIN SMALL LETTER Y */\n"
" XK_z: 0x007a, /* U+007A LATIN SMALL LETTER Z */\n"
" XK_braceleft: 0x007b, /* U+007B LEFT CURLY BRACKET */\n"
" XK_bar: 0x007c, /* U+007C VERTICAL LINE */\n"
" XK_braceright: 0x007d, /* U+007D RIGHT CURLY BRACKET */\n"
" XK_asciitilde: 0x007e, /* U+007E TILDE */\n"
"\n"
" XK_nobreakspace: 0x00a0, /* U+00A0 NO-BREAK SPACE */\n"
" XK_exclamdown: 0x00a1, /* U+00A1 INVERTED EXCLAMATION MARK */\n"
" XK_cent: 0x00a2, /* U+00A2 CENT SIGN */\n"
" XK_sterling: 0x00a3, /* U+00A3 POUND SIGN */\n"
" XK_currency: 0x00a4, /* U+00A4 CURRENCY SIGN */\n"
" XK_yen: 0x00a5, /* U+00A5 YEN SIGN */\n"
" XK_brokenbar: 0x00a6, /* U+00A6 BROKEN BAR */\n"
" XK_section: 0x00a7, /* U+00A7 SECTION SIGN */\n"
" XK_diaeresis: 0x00a8, /* U+00A8 DIAERESIS */\n"
" XK_copyright: 0x00a9, /* U+00A9 COPYRIGHT SIGN */\n"
" XK_ordfeminine: 0x00aa, /* U+00AA FEMININE ORDINAL INDICATOR */\n"
" XK_guillemotleft: 0x00ab, /* U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */\n"
" XK_notsign: 0x00ac, /* U+00AC NOT SIGN */\n"
" XK_hyphen: 0x00ad, /* U+00AD SOFT HYPHEN */\n"
" XK_registered: 0x00ae, /* U+00AE REGISTERED SIGN */\n"
" XK_macron: 0x00af, /* U+00AF MACRON */\n"
" XK_degree: 0x00b0, /* U+00B0 DEGREE SIGN */\n"
" XK_plusminus: 0x00b1, /* U+00B1 PLUS-MINUS SIGN */\n"
" XK_twosuperior: 0x00b2, /* U+00B2 SUPERSCRIPT TWO */\n"
" XK_threesuperior: 0x00b3, /* U+00B3 SUPERSCRIPT THREE */\n"
" XK_acute: 0x00b4, /* U+00B4 ACUTE ACCENT */\n"
" XK_mu: 0x00b5, /* U+00B5 MICRO SIGN */\n"
" XK_paragraph: 0x00b6, /* U+00B6 PILCROW SIGN */\n"
" XK_periodcentered: 0x00b7, /* U+00B7 MIDDLE DOT */\n"
" XK_cedilla: 0x00b8, /* U+00B8 CEDILLA */\n"
" XK_onesuperior: 0x00b9, /* U+00B9 SUPERSCRIPT ONE */\n"
" XK_masculine: 0x00ba, /* U+00BA MASCULINE ORDINAL INDICATOR */\n"
" XK_guillemotright: 0x00bb, /* U+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */\n"
" XK_onequarter: 0x00bc, /* U+00BC VULGAR FRACTION ONE QUARTER */\n"
" XK_onehalf: 0x00bd, /* U+00BD VULGAR FRACTION ONE HALF */\n"
" XK_threequarters: 0x00be, /* U+00BE VULGAR FRACTION THREE QUARTERS */\n"
" XK_questiondown: 0x00bf, /* U+00BF INVERTED QUESTION MARK */\n"
" XK_Agrave: 0x00c0, /* U+00C0 LATIN CAPITAL LETTER A WITH GRAVE */\n"
" XK_Aacute: 0x00c1, /* U+00C1 LATIN CAPITAL LETTER A WITH ACUTE */\n"
" XK_Acircumflex: 0x00c2, /* U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX */\n"
" XK_Atilde: 0x00c3, /* U+00C3 LATIN CAPITAL LETTER A WITH TILDE */\n"
" XK_Adiaeresis: 0x00c4, /* U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS */\n"
" XK_Aring: 0x00c5, /* U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE */\n"
" XK_AE: 0x00c6, /* U+00C6 LATIN CAPITAL LETTER AE */\n"
" XK_Ccedilla: 0x00c7, /* U+00C7 LATIN CAPITAL LETTER C WITH CEDILLA */\n"
" XK_Egrave: 0x00c8, /* U+00C8 LATIN CAPITAL LETTER E WITH GRAVE */\n"
" XK_Eacute: 0x00c9, /* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE */\n"
" XK_Ecircumflex: 0x00ca, /* U+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX */\n"
" XK_Ediaeresis: 0x00cb, /* U+00CB LATIN CAPITAL LETTER E WITH DIAERESIS */\n"
" XK_Igrave: 0x00cc, /* U+00CC LATIN CAPITAL LETTER I WITH GRAVE */\n"
" XK_Iacute: 0x00cd, /* U+00CD LATIN CAPITAL LETTER I WITH ACUTE */\n"
" XK_Icircumflex: 0x00ce, /* U+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX */\n"
" XK_Idiaeresis: 0x00cf, /* U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS */\n"
" XK_ETH: 0x00d0, /* U+00D0 LATIN CAPITAL LETTER ETH */\n"
" XK_Eth: 0x00d0, /* deprecated */\n"
" XK_Ntilde: 0x00d1, /* U+00D1 LATIN CAPITAL LETTER N WITH TILDE */\n"
" XK_Ograve: 0x00d2, /* U+00D2 LATIN CAPITAL LETTER O WITH GRAVE */\n"
" XK_Oacute: 0x00d3, /* U+00D3 LATIN CAPITAL LETTER O WITH ACUTE */\n"
" XK_Ocircumflex: 0x00d4, /* U+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX */\n"
" XK_Otilde: 0x00d5, /* U+00D5 LATIN CAPITAL LETTER O WITH TILDE */\n"
" XK_Odiaeresis: 0x00d6, /* U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS */\n"
" XK_multiply: 0x00d7, /* U+00D7 MULTIPLICATION SIGN */\n"
" XK_Oslash: 0x00d8, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */\n"
" XK_Ooblique: 0x00d8, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */\n"
" XK_Ugrave: 0x00d9, /* U+00D9 LATIN CAPITAL LETTER U WITH GRAVE */\n"
" XK_Uacute: 0x00da, /* U+00DA LATIN CAPITAL LETTER U WITH ACUTE */\n"
" XK_Ucircumflex: 0x00db, /* U+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX */\n"
" XK_Udiaeresis: 0x00dc, /* U+00DC LATIN CAPITAL LETTER U WITH DIAERESIS */\n"
" XK_Yacute: 0x00dd, /* U+00DD LATIN CAPITAL LETTER Y WITH ACUTE */\n"
" XK_THORN: 0x00de, /* U+00DE LATIN CAPITAL LETTER THORN */\n"
" XK_Thorn: 0x00de, /* deprecated */\n"
" XK_ssharp: 0x00df, /* U+00DF LATIN SMALL LETTER SHARP S */\n"
" XK_agrave: 0x00e0, /* U+00E0 LATIN SMALL LETTER A WITH GRAVE */\n"
" XK_aacute: 0x00e1, /* U+00E1 LATIN SMALL LETTER A WITH ACUTE */\n"
" XK_acircumflex: 0x00e2, /* U+00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX */\n"
" XK_atilde: 0x00e3, /* U+00E3 LATIN SMALL LETTER A WITH TILDE */\n"
" XK_adiaeresis: 0x00e4, /* U+00E4 LATIN SMALL LETTER A WITH DIAERESIS */\n"
" XK_aring: 0x00e5, /* U+00E5 LATIN SMALL LETTER A WITH RING ABOVE */\n"
" XK_ae: 0x00e6, /* U+00E6 LATIN SMALL LETTER AE */\n"
" XK_ccedilla: 0x00e7, /* U+00E7 LATIN SMALL LETTER C WITH CEDILLA */\n"
" XK_egrave: 0x00e8, /* U+00E8 LATIN SMALL LETTER E WITH GRAVE */\n"
" XK_eacute: 0x00e9, /* U+00E9 LATIN SMALL LETTER E WITH ACUTE */\n"
" XK_ecircumflex: 0x00ea, /* U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX */\n"
" XK_ediaeresis: 0x00eb, /* U+00EB LATIN SMALL LETTER E WITH DIAERESIS */\n"
" XK_igrave: 0x00ec, /* U+00EC LATIN SMALL LETTER I WITH GRAVE */\n"
" XK_iacute: 0x00ed, /* U+00ED LATIN SMALL LETTER I WITH ACUTE */\n"
" XK_icircumflex: 0x00ee, /* U+00EE LATIN SMALL LETTER I WITH CIRCUMFLEX */\n"
" XK_idiaeresis: 0x00ef, /* U+00EF LATIN SMALL LETTER I WITH DIAERESIS */\n"
" XK_eth: 0x00f0, /* U+00F0 LATIN SMALL LETTER ETH */\n"
" XK_ntilde: 0x00f1, /* U+00F1 LATIN SMALL LETTER N WITH TILDE */\n"
" XK_ograve: 0x00f2, /* U+00F2 LATIN SMALL LETTER O WITH GRAVE */\n"
" XK_oacute: 0x00f3, /* U+00F3 LATIN SMALL LETTER O WITH ACUTE */\n"
" XK_ocircumflex: 0x00f4, /* U+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX */\n"
" XK_otilde: 0x00f5, /* U+00F5 LATIN SMALL LETTER O WITH TILDE */\n"
" XK_odiaeresis: 0x00f6, /* U+00F6 LATIN SMALL LETTER O WITH DIAERESIS */\n"
" XK_division: 0x00f7, /* U+00F7 DIVISION SIGN */\n"
" XK_oslash: 0x00f8, /* U+00F8 LATIN SMALL LETTER O WITH STROKE */\n"
" XK_ooblique: 0x00f8, /* U+00F8 LATIN SMALL LETTER O WITH STROKE */\n"
" XK_ugrave: 0x00f9, /* U+00F9 LATIN SMALL LETTER U WITH GRAVE */\n"
" XK_uacute: 0x00fa, /* U+00FA LATIN SMALL LETTER U WITH ACUTE */\n"
" XK_ucircumflex: 0x00fb, /* U+00FB LATIN SMALL LETTER U WITH CIRCUMFLEX */\n"
" XK_udiaeresis: 0x00fc, /* U+00FC LATIN SMALL LETTER U WITH DIAERESIS */\n"
" XK_yacute: 0x00fd, /* U+00FD LATIN SMALL LETTER Y WITH ACUTE */\n"
" XK_thorn: 0x00fe, /* U+00FE LATIN SMALL LETTER THORN */\n"
" XK_ydiaeresis: 0x00ff, /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS */\n"
"\n"
" /*\n"
" * Korean\n"
" * Byte 3 = 0x0e\n"
" */\n"
"\n"
" // Lookup table (fairly random)\n"
" const keysym = codepoints[u];\n"
" if (keysym !== undefined) {\n"
" return keysym;\n"
" }\n"
" XK_Hangul: 0xff31, /* Hangul start/stop(toggle) */\n"
" XK_Hangul_Hanja: 0xff34, /* Start Hangul->Hanja Conversion */\n"
" XK_Hangul_Jeonja: 0xff38, /* Jeonja mode */\n"
"\n"
" // General mapping as final fallback\n"
" return 0x01000000 | u;\n"
"};\n"
"window.codepoints = codepoints;\n"
" /*\n"
" * XFree86 vendor specific keysyms.\n"
" *\n"
" * The XFree86 keysym range is 0x10080001 - 0x1008FFFF.\n"
" */\n"
"\n"
"// Create keysyms object for compatibility with util.js\n"
"window.keysyms = {\n"
" lookup: window.lookup\n"
" XF86XK_ModeLock: 0x1008FF01,\n"
" XF86XK_MonBrightnessUp: 0x1008FF02,\n"
" XF86XK_MonBrightnessDown: 0x1008FF03,\n"
" XF86XK_KbdLightOnOff: 0x1008FF04,\n"
" XF86XK_KbdBrightnessUp: 0x1008FF05,\n"
" XF86XK_KbdBrightnessDown: 0x1008FF06,\n"
" XF86XK_Standby: 0x1008FF10,\n"
" XF86XK_AudioLowerVolume: 0x1008FF11,\n"
" XF86XK_AudioMute: 0x1008FF12,\n"
" XF86XK_AudioRaiseVolume: 0x1008FF13,\n"
" XF86XK_AudioPlay: 0x1008FF14,\n"
" XF86XK_AudioStop: 0x1008FF15,\n"
" XF86XK_AudioPrev: 0x1008FF16,\n"
" XF86XK_AudioNext: 0x1008FF17,\n"
" XF86XK_HomePage: 0x1008FF18,\n"
" XF86XK_Mail: 0x1008FF19,\n"
" XF86XK_Start: 0x1008FF1A,\n"
" XF86XK_Search: 0x1008FF1B,\n"
" XF86XK_AudioRecord: 0x1008FF1C,\n"
" XF86XK_Calculator: 0x1008FF1D,\n"
" XF86XK_Memo: 0x1008FF1E,\n"
" XF86XK_ToDoList: 0x1008FF1F,\n"
" XF86XK_Calendar: 0x1008FF20,\n"
" XF86XK_PowerDown: 0x1008FF21,\n"
" XF86XK_ContrastAdjust: 0x1008FF22,\n"
" XF86XK_RockerUp: 0x1008FF23,\n"
" XF86XK_RockerDown: 0x1008FF24,\n"
" XF86XK_RockerEnter: 0x1008FF25,\n"
" XF86XK_Back: 0x1008FF26,\n"
" XF86XK_Forward: 0x1008FF27,\n"
" XF86XK_Stop: 0x1008FF28,\n"
" XF86XK_Refresh: 0x1008FF29,\n"
" XF86XK_PowerOff: 0x1008FF2A,\n"
" XF86XK_WakeUp: 0x1008FF2B,\n"
" XF86XK_Eject: 0x1008FF2C,\n"
" XF86XK_ScreenSaver: 0x1008FF2D,\n"
" XF86XK_WWW: 0x1008FF2E,\n"
" XF86XK_Sleep: 0x1008FF2F,\n"
" XF86XK_Favorites: 0x1008FF30,\n"
" XF86XK_AudioPause: 0x1008FF31,\n"
" XF86XK_AudioMedia: 0x1008FF32,\n"
" XF86XK_MyComputer: 0x1008FF33,\n"
" XF86XK_VendorHome: 0x1008FF34,\n"
" XF86XK_LightBulb: 0x1008FF35,\n"
" XF86XK_Shop: 0x1008FF36,\n"
" XF86XK_History: 0x1008FF37,\n"
" XF86XK_OpenURL: 0x1008FF38,\n"
" XF86XK_AddFavorite: 0x1008FF39,\n"
" XF86XK_HotLinks: 0x1008FF3A,\n"
" XF86XK_BrightnessAdjust: 0x1008FF3B,\n"
" XF86XK_Finance: 0x1008FF3C,\n"
" XF86XK_Community: 0x1008FF3D,\n"
" XF86XK_AudioRewind: 0x1008FF3E,\n"
" XF86XK_BackForward: 0x1008FF3F,\n"
" XF86XK_Launch0: 0x1008FF40,\n"
" XF86XK_Launch1: 0x1008FF41,\n"
" XF86XK_Launch2: 0x1008FF42,\n"
" XF86XK_Launch3: 0x1008FF43,\n"
" XF86XK_Launch4: 0x1008FF44,\n"
" XF86XK_Launch5: 0x1008FF45,\n"
" XF86XK_Launch6: 0x1008FF46,\n"
" XF86XK_Launch7: 0x1008FF47,\n"
" XF86XK_Launch8: 0x1008FF48,\n"
" XF86XK_Launch9: 0x1008FF49,\n"
" XF86XK_LaunchA: 0x1008FF4A,\n"
" XF86XK_LaunchB: 0x1008FF4B,\n"
" XF86XK_LaunchC: 0x1008FF4C,\n"
" XF86XK_LaunchD: 0x1008FF4D,\n"
" XF86XK_LaunchE: 0x1008FF4E,\n"
" XF86XK_LaunchF: 0x1008FF4F,\n"
" XF86XK_ApplicationLeft: 0x1008FF50,\n"
" XF86XK_ApplicationRight: 0x1008FF51,\n"
" XF86XK_Book: 0x1008FF52,\n"
" XF86XK_CD: 0x1008FF53,\n"
" XF86XK_Calculater: 0x1008FF54,\n"
" XF86XK_Clear: 0x1008FF55,\n"
" XF86XK_Close: 0x1008FF56,\n"
" XF86XK_Copy: 0x1008FF57,\n"
" XF86XK_Cut: 0x1008FF58,\n"
" XF86XK_Display: 0x1008FF59,\n"
" XF86XK_DOS: 0x1008FF5A,\n"
" XF86XK_Documents: 0x1008FF5B,\n"
" XF86XK_Excel: 0x1008FF5C,\n"
" XF86XK_Explorer: 0x1008FF5D,\n"
" XF86XK_Game: 0x1008FF5E,\n"
" XF86XK_Go: 0x1008FF5F,\n"
" XF86XK_iTouch: 0x1008FF60,\n"
" XF86XK_LogOff: 0x1008FF61,\n"
" XF86XK_Market: 0x1008FF62,\n"
" XF86XK_Meeting: 0x1008FF63,\n"
" XF86XK_MenuKB: 0x1008FF65,\n"
" XF86XK_MenuPB: 0x1008FF66,\n"
" XF86XK_MySites: 0x1008FF67,\n"
" XF86XK_New: 0x1008FF68,\n"
" XF86XK_News: 0x1008FF69,\n"
" XF86XK_OfficeHome: 0x1008FF6A,\n"
" XF86XK_Open: 0x1008FF6B,\n"
" XF86XK_Option: 0x1008FF6C,\n"
" XF86XK_Paste: 0x1008FF6D,\n"
" XF86XK_Phone: 0x1008FF6E,\n"
" XF86XK_Q: 0x1008FF70,\n"
" XF86XK_Reply: 0x1008FF72,\n"
" XF86XK_Reload: 0x1008FF73,\n"
" XF86XK_RotateWindows: 0x1008FF74,\n"
" XF86XK_RotationPB: 0x1008FF75,\n"
" XF86XK_RotationKB: 0x1008FF76,\n"
" XF86XK_Save: 0x1008FF77,\n"
" XF86XK_ScrollUp: 0x1008FF78,\n"
" XF86XK_ScrollDown: 0x1008FF79,\n"
" XF86XK_ScrollClick: 0x1008FF7A,\n"
" XF86XK_Send: 0x1008FF7B,\n"
" XF86XK_Spell: 0x1008FF7C,\n"
" XF86XK_SplitScreen: 0x1008FF7D,\n"
" XF86XK_Support: 0x1008FF7E,\n"
" XF86XK_TaskPane: 0x1008FF7F,\n"
" XF86XK_Terminal: 0x1008FF80,\n"
" XF86XK_Tools: 0x1008FF81,\n"
" XF86XK_Travel: 0x1008FF82,\n"
" XF86XK_UserPB: 0x1008FF84,\n"
" XF86XK_User1KB: 0x1008FF85,\n"
" XF86XK_User2KB: 0x1008FF86,\n"
" XF86XK_Video: 0x1008FF87,\n"
" XF86XK_WheelButton: 0x1008FF88,\n"
" XF86XK_Word: 0x1008FF89,\n"
" XF86XK_Xfer: 0x1008FF8A,\n"
" XF86XK_ZoomIn: 0x1008FF8B,\n"
" XF86XK_ZoomOut: 0x1008FF8C,\n"
" XF86XK_Away: 0x1008FF8D,\n"
" XF86XK_Messenger: 0x1008FF8E,\n"
" XF86XK_WebCam: 0x1008FF8F,\n"
" XF86XK_MailForward: 0x1008FF90,\n"
" XF86XK_Pictures: 0x1008FF91,\n"
" XF86XK_Music: 0x1008FF92,\n"
" XF86XK_Battery: 0x1008FF93,\n"
" XF86XK_Bluetooth: 0x1008FF94,\n"
" XF86XK_WLAN: 0x1008FF95,\n"
" XF86XK_UWB: 0x1008FF96,\n"
" XF86XK_AudioForward: 0x1008FF97,\n"
" XF86XK_AudioRepeat: 0x1008FF98,\n"
" XF86XK_AudioRandomPlay: 0x1008FF99,\n"
" XF86XK_Subtitle: 0x1008FF9A,\n"
" XF86XK_AudioCycleTrack: 0x1008FF9B,\n"
" XF86XK_CycleAngle: 0x1008FF9C,\n"
" XF86XK_FrameBack: 0x1008FF9D,\n"
" XF86XK_FrameForward: 0x1008FF9E,\n"
" XF86XK_Time: 0x1008FF9F,\n"
" XF86XK_Select: 0x1008FFA0,\n"
" XF86XK_View: 0x1008FFA1,\n"
" XF86XK_TopMenu: 0x1008FFA2,\n"
" XF86XK_Red: 0x1008FFA3,\n"
" XF86XK_Green: 0x1008FFA4,\n"
" XF86XK_Yellow: 0x1008FFA5,\n"
" XF86XK_Blue: 0x1008FFA6,\n"
" XF86XK_Suspend: 0x1008FFA7,\n"
" XF86XK_Hibernate: 0x1008FFA8,\n"
" XF86XK_TouchpadToggle: 0x1008FFA9,\n"
" XF86XK_TouchpadOn: 0x1008FFB0,\n"
" XF86XK_TouchpadOff: 0x1008FFB1,\n"
" XF86XK_AudioMicMute: 0x1008FFB2,\n"
" XF86XK_Switch_VT_1: 0x1008FE01,\n"
" XF86XK_Switch_VT_2: 0x1008FE02,\n"
" XF86XK_Switch_VT_3: 0x1008FE03,\n"
" XF86XK_Switch_VT_4: 0x1008FE04,\n"
" XF86XK_Switch_VT_5: 0x1008FE05,\n"
" XF86XK_Switch_VT_6: 0x1008FE06,\n"
" XF86XK_Switch_VT_7: 0x1008FE07,\n"
" XF86XK_Switch_VT_8: 0x1008FE08,\n"
" XF86XK_Switch_VT_9: 0x1008FE09,\n"
" XF86XK_Switch_VT_10: 0x1008FE0A,\n"
" XF86XK_Switch_VT_11: 0x1008FE0B,\n"
" XF86XK_Switch_VT_12: 0x1008FE0C,\n"
" XF86XK_Ungrab: 0x1008FE20,\n"
" XF86XK_ClearGrab: 0x1008FE21,\n"
" XF86XK_Next_VMode: 0x1008FE22,\n"
" XF86XK_Prev_VMode: 0x1008FE23,\n"
" XF86XK_LogWindowTree: 0x1008FE24,\n"
" XF86XK_LogGrabInfo: 0x1008FE25,\n"
"};\n"
;
if (strcmp(path, "/novnc/input/keysymdef.js") == 0) return novnc_input_keysymdef_js;
if (strcmp(path, "/novnc/input/keysym.js") == 0) return novnc_input_keysym_js;
const char *novnc_input_util_js =
"\n"
"// Get 'KeyboardEvent.code', handling legacy browsers\n"
......
......@@ -18,8 +18,8 @@
#include "html_pages/novnc_input_fixedkeys_js_page.h"
#include "html_pages/novnc_input_gesturehandler_js_page.h"
#include "html_pages/novnc_input_keyboard_js_page.h"
#include "html_pages/novnc_input_keysym_js_page.h"
#include "html_pages/novnc_input_keysymdef_js_page.h"
#include "html_pages/novnc_input_keysym_js_page.h"
#include "html_pages/novnc_input_util_js_page.h"
#include "html_pages/novnc_input_vkeys_js_page.h"
#include "html_pages/novnc_input_xtscancodes_js_page.h"
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -3,8 +3,8 @@
#include "html_pages/rdp_clipboard_js_page.h"
#include "html_pages/rdp_mstsc_js_page.h"
#include "html_pages/rdp_out_stream_js_page.h"
#include "html_pages/rdp_rdp_wasm_js_page.h"
#include "html_pages/rdp_rdp_graphics_js_page.h"
#include "html_pages/rdp_rdp_wasm_js_page.h"
#include "html_pages/rdp_reversed_layouts_js_page.h"
#include "html_pages/rdp_scancodes_js_page.h"
#include "html_pages/rdp_rdp_wasm_page.h"
......
......@@ -7,12 +7,13 @@
<link rel="icon" href="/favicon.ico" type="image/x-icon">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="/rdpwasm/rdp.wasm.js"></script>
<script src="/rdpwasm/clipboard.js"></script>
<script src="/rdpwasm/out_stream.js"></script>
<script src="/rdpwasm/rdp_graphics.js"></script>
<script src="/rdpwasm/reversed_layouts.js"></script>
<script src="/rdpwasm/scancodes.js"></script>
<script src="/rdpwasm/reversed_layouts.js"></script>
<script src="/rdpwasm/rdp_graphics.js"></script>
<script src="/rdpwasm/out_stream.js"></script>
<script src="/rdpwasm/clipboard.js"></script>
<style>
.navbar-brand {
font-weight: bold;
......@@ -307,10 +308,7 @@
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
console.log('RDP page script starting...');
// init kbdlayout_input
let defaultLayoutId;
try {
......@@ -321,7 +319,7 @@ try {
const layout = layouts[i];
const displayName = layout.displayName;
const opt = document.createElement('option');
opt.textContent = `${layout.localeName} 0x${layout.klid.toString(16).padStart(5, '0')} (${displayName})`;
opt.textContent = layout.localeName + ' 0x' + layout.klid.toString(16).padStart(5, '0') + ' (' + displayName + ')';
opt.value = i;
if (displayName === 'United States - English') {
opt.selected = true;
......@@ -329,7 +327,6 @@ try {
}
// Since we don't have kbdlayout_input in this simplified version, we'll use default
}
console.log('Keyboard layouts initialized, defaultLayoutId:', defaultLayoutId);
} catch (error) {
console.error('Error initializing keyboard layouts:', error);
defaultLayoutId = 0; // fallback
......@@ -339,16 +336,13 @@ let kbdInputLayoutEvent = () => {};
let _Module = null;
console.log('Starting WebAssembly module loading...');
if (typeof WallixModule === 'undefined') {
console.error('WallixModule is not defined - rdp.wasm.js may not have loaded');
} else {
WallixModule({
// INITIAL_MEMORY: 16777216, // 16**6
// INITIAL_MEMORY: 268435456, // 16**7
}).then((Module) => {
console.log('WebAssembly module loaded successfully');
}).then((Module) => {
_Module = Module;
// optional
......@@ -370,33 +364,19 @@ if (typeof WallixModule === 'undefined') {
MouseFlags = _Module.MouseFlags;
InputFlags = _Module.InputFlags;
console.log('WebAssembly constants set:', { RdpClient: !!RdpClient, MouseFlags: !!MouseFlags, InputFlags: !!InputFlags });
}).catch((e) => {
}).catch((e) => {
console.error('Failed to load WebAssembly module:', e);
showNotification('Failed to load RDP WebAssembly module', 'danger');
});
});
}
console.log('After WallixModule setup');
// Constants will be set after module loads
let RdpClient, ClipboardChannel, MouseFlags, InputFlags;
// Define constants that will be available after module loads
const KeyAcquire = 0;
const KeyRelease = 0x80;
const SyncFlags = {
ShiftLeft: 0x01,
ShiftRight: 0x02,
ControlLeft: 0x04,
ControlRight: 0x08,
AltLeft: 0x10,
AltRight: 0x20,
OSLeft: 0x40,
OSRight: 0x80,
NumLock: 0x100,
CapsLock: 0x200,
KanaLock: 0x400,
ScrollLock: 0x800
};
// Constants are defined in scancodes.js
console.log('After constants');
function MultiSelectToInt(e, constants)
{
......@@ -559,7 +539,7 @@ class EmulatedKeyboard extends Keyboard
}
compositeKeyEvent(evt, text) {
if (!this._preprocessKeyEvent(evt, flag)) return;
if (!this._preprocessKeyEvent(evt, KeyAcquire)) return;
const scancodes = this._keymap.toScancodesAndFlags(text, text, KeyAcquire);
if (scancodes) {
......@@ -645,6 +625,7 @@ class UnicodeKeyboard extends Keyboard
}
}
}
console.log('After classes');
let rdpclient = null;
let socket = null;
......@@ -789,47 +770,28 @@ const maximizeBtn = document.querySelector('.maximize-btn');
const minimizeBtn = document.querySelector('.minimize-btn');
const zoomBtn = document.getElementById('zoomBtn');
console.log('DOM elements found:', {
connectBtn: !!connectBtn,
disconnectBtn: !!disconnectBtn,
cancelConnectBtn: !!cancelConnectBtn,
startRdpBtn: !!startRdpBtn,
closeBtn: !!closeBtn,
maximizeBtn: !!maximizeBtn,
minimizeBtn: !!minimizeBtn,
zoomBtn: !!zoomBtn
});
if (connectBtn) {
connectBtn.addEventListener('click', function(e) {
console.log('Connect button clicked');
showRdpConfig();
});
console.log('Connect button listener attached');
}
if (disconnectBtn) {
disconnectBtn.addEventListener('click', function(e) {
console.log('Disconnect button clicked');
disconnect();
});
console.log('Disconnect button listener attached');
}
if (cancelConnectBtn) {
cancelConnectBtn.addEventListener('click', function(e) {
console.log('Cancel connect button clicked');
cancelConnect();
});
console.log('Cancel connect button listener attached');
}
if (startRdpBtn) {
startRdpBtn.addEventListener('click', function(e) {
console.log('Start RDP button clicked');
startRdpConnection();
});
console.log('Start RDP button listener attached');
}
// Window control buttons
......@@ -865,8 +827,6 @@ if (zoomBtn) {
console.log('Zoom button listener attached');
}
console.log('Event listeners attachment completed');
// Input event handlers
let ecanvas = document.getElementById('canvas');
let ecanvasFocus = document.getElementById('canvasFocus');
......@@ -939,7 +899,6 @@ function toggleZoom() {
}
function showRdpConfig() {
console.log('showRdpConfig called, connected:', connected);
if (connected) return;
// Show the RDP configuration modal
......@@ -948,7 +907,6 @@ function showRdpConfig() {
}
function startRdpConnection() {
console.log('startRdpConnection called');
// Hide the modal
const modal = bootstrap.Modal.getInstance(document.getElementById('rdpConfigModal'));
modal.hide();
......@@ -1199,4 +1157,4 @@ function cancelConnect() {
}
</script>
</body>
</html>
\ No newline at end of file
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RDP - %s</title>
<link rel="icon" href="/favicon.ico" type="image/x-icon">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<script src="/rdpwasm/rdp.wasm.js"></script>
<script src="/rdpwasm/scancodes.js"></script>
<script src="/rdpwasm/reversed_layouts.js"></script>
<script src="/rdpwasm/rdp_graphics.js"></script>
<script src="/rdpwasm/out_stream.js"></script>
<script src="/rdpwasm/clipboard.js"></script>
<style>
.navbar-brand {
font-weight: bold;
}
.rdp-container {
background-color: #1e1e1e;
color: #f8f8f2;
border-radius: 8px;
height: calc(100vh - 200px);
min-height: 400px;
overflow: hidden;
position: relative;
}
.rdp-container.full-size {
overflow: auto;
max-height: none;
height: auto;
}
.rdp-container.full-size #canvas {
min-width: fit-content;
min-height: fit-content;
}
/* GNOME-like window decorations */
.rdp-window {
border: 1px solid #ccc;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 10px rgba(0,0,0,0.2);
}
.window-titlebar {
background: linear-gradient(to bottom, #f0f0f0, #e0e0e0);
border-bottom: 1px solid #ccc;
padding: 4px 8px;
display: flex;
justify-content: space-between;
align-items: center;
height: 32px;
}
.window-title {
font-weight: bold;
color: #333;
font-size: 14px;
}
.window-controls {
display: flex;
align-items: center;
gap: 4px;
}
.window-btn {
width: 24px;
height: 24px;
border: none;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
font-weight: bold;
cursor: pointer;
transition: all 0.2s;
}
.window-btn:hover {
transform: scale(1.1);
}
.close-btn {
background: #ff605c;
color: white;
}
.close-btn:hover {
background: #ff403c;
}
.maximize-btn {
background: #28ca42;
color: white;
}
.maximize-btn:hover {
background: #24b83a;
}
.minimize-btn {
background: #ffbd44;
color: white;
display: none; /* Hidden by default, shown in fullscreen */
}
.minimize-btn:hover {
background: #ffad2c;
}
.zoom-btn {
background: #17a2b8;
color: white;
}
.zoom-btn:hover {
background: #138496;
}
.zoom-btn.active {
background: #007bff;
}
.zoom-btn.active:hover {
background: #0056b3;
}
.window-content {
background: #1e1e1e;
padding: 8px;
}
/* Fullscreen styles */
.rdp-window.fullscreen {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
border: none;
border-radius: 0;
z-index: 9999;
}
.rdp-window.fullscreen .rdp-container {
height: calc(100vh - 40px) !important;
min-height: calc(100vh - 40px) !important;
}
.rdp-window.fullscreen .minimize-btn {
display: flex;
}
#canvas {
width: 100%;
height: 100%;
}
#canvasFocus {
width: 0px;
height: 0px;
position: absolute;
z-index: -10;
padding: 0;
margin: 0;
}
</style>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container">
<a class="navbar-brand" href="/">
<i class="fas fa-desktop"></i> WSSSHD control panel</a>
<div class="navbar-nav ms-auto">
<span class="navbar-text me-3">RDP Session - %s</span>
<a class="nav-link" href="/logout">Logout</a>
</div></div></nav>
<div id="notification-area" class="position-fixed top-0 end-0 p-3" style="z-index: 1050;"></div>
<!-- RDP Configuration Modal -->
<div class="modal fade" id="rdpConfigModal" tabindex="-1" aria-labelledby="rdpConfigModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="rdpConfigModalLabel">RDP Connection Configuration</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="rdpConfigForm">
<div class="row">
<div class="col-md-6">
<fieldset class="border p-3 mb-3">
<legend class="w-auto">Authentication</legend>
<div class="mb-3">
<label for="rdpUsername" class="form-label">Username</label>
<input type="text" class="form-control" id="rdpUsername" placeholder="Username">
</div>
<div class="mb-3">
<label for="rdpPassword" class="form-label">Password</label>
<input type="password" class="form-control" id="rdpPassword" placeholder="Password">
</div>
<div class="mb-3">
<label for="rdpDomain" class="form-label">Domain</label>
<input type="text" class="form-control" id="rdpDomain" placeholder="Domain (optional)">
</div>
</fieldset>
</div>
<div class="col-md-6">
<fieldset class="border p-3 mb-3">
<legend class="w-auto">Display</legend>
<div class="mb-3">
<label for="rdpWidth" class="form-label">Width</label>
<input type="number" class="form-control" id="rdpWidth" value="1024" min="640" max="4096">
</div>
<div class="mb-3">
<label for="rdpHeight" class="form-label">Height</label>
<input type="number" class="form-control" id="rdpHeight" value="768" min="480" max="2160">
</div>
<div class="mb-3">
<label for="rdpBpp" class="form-label">Color Depth (BPP)</label>
<select class="form-select" id="rdpBpp">
<option value="8">8-bit</option>
<option value="15">15-bit</option>
<option value="16" selected>16-bit</option>
<option value="24">24-bit</option>
<option value="32">32-bit</option>
</select>
</div>
<div class="mb-3">
<label for="rdpGraphicsImpl" class="form-label">Graphics Implementation</label>
<select class="form-select" id="rdpGraphicsImpl">
<option value="2d" selected>Canvas 2D</option>
<option value="webgl">WebGL</option>
<option value="webgl2">WebGL2</option>
</select>
</div>
</fieldset>
</div>
</div>
<div class="row">
<div class="col-md-6">
<fieldset class="border p-3 mb-3">
<legend class="w-auto">Keyboard</legend>
<div class="mb-3">
<label for="rdpKeyboardMethod" class="form-label">Keyboard Method</label>
<select class="form-select" id="rdpKeyboardMethod">
<option value="codeToScancode" selected>KeyboardEvent.code → Scancode</option>
<option value="emulateScancode">KeyboardEvent.key → Scancode or Unicode</option>
<option value="unicode">KeyboardEvent.key → Unicode</option>
</select>
</div>
<div class="mb-3">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="rdpAltGrCtrlAlt" checked>
<label class="form-check-label" for="rdpAltGrCtrlAlt">
Ctrl + Alt = AltGr
</label>
</div>
</div>
</fieldset>
</div>
<div class="col-md-6">
<fieldset class="border p-3 mb-3">
<legend class="w-auto">Advanced</legend>
<div class="mb-3">
<label for="rdpVerbosity" class="form-label">Verbosity Level</label>
<input type="number" class="form-control" id="rdpVerbosity" value="0" min="0">
</div>
<div class="mb-3">
<label for="rdpJsonConfig" class="form-label">JSON Configuration (Advanced)</label>
<textarea class="form-control" id="rdpJsonConfig" rows="3" placeholder='{"key": "value"}'></textarea>
</div>
</fieldset>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id="startRdpBtn">Start RDP Session</button>
</div>
</div>
</div>
</div>
<div class="container mt-4">
<div class="row">
<div class="col-12">
<div class="rdp-window">
<div class="window-titlebar">
<div class="window-title">
<i class="fas fa-desktop"></i> RDP Session - %s
</div>
<div class="window-controls">
<button id="connectBtn" class="btn btn-success btn-sm me-1" style="height: 24px; font-size: 12px; padding: 0 8px;">
<i class="fas fa-play"></i> Connect
</button>
<button id="disconnectBtn" class="btn btn-danger btn-sm me-1" disabled style="height: 24px; font-size: 12px; padding: 0 8px;">
<i class="fas fa-stop"></i> Disconnect
</button>
<button class="window-btn zoom-btn" title="Toggle Zoom (Scale/Fit)" id="zoomBtn">
<i class="fas fa-search-plus"></i>
</button>
<button class="window-btn minimize-btn" title="Exit Fullscreen">_</button>
<button class="window-btn maximize-btn" title="Fullscreen"><span class="maximize-icon"></span></button>
<button class="window-btn close-btn" title="Disconnect">×</button>
</div>
</div>
<div class="window-content">
<div id="rdp" class="rdp-container w-100">
<canvas id="canvas" width="1024" height="768"></canvas><input id="canvasFocus" type="text"/>
<div id="rdp_status" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; color: #f8f8f2;">Click Connect to start RDP session</div>
<div id="rdp_loading" style="display: none; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; color: #f8f8f2;">
<div class="spinner-border text-primary mb-2" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<div>Connecting to RDP server...</div>
<button id="cancelConnectBtn" class="btn btn-outline-danger btn-sm mt-2" style="display: none;">
<i class="fas fa-times"></i> Cancel
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// init kbdlayout_input
let defaultLayoutId;
try {
if (typeof layouts === 'undefined') {
throw new Error('layouts is not defined - reversed_layouts.js may not have loaded');
}
for (let i = 0; i < layouts.length; ++i) {
const layout = layouts[i];
const displayName = layout.displayName;
const opt = document.createElement('option');
opt.textContent = layout.localeName + ' 0x' + layout.klid.toString(16).padStart(5, '0') + ' (' + displayName + ')';
opt.value = i;
if (displayName === 'United States - English') {
opt.selected = true;
defaultLayoutId = i;
}
// Since we don't have kbdlayout_input in this simplified version, we'll use default
}
} catch (error) {
console.error('Error initializing keyboard layouts:', error);
defaultLayoutId = 0; // fallback
}
let kbdInputLayoutEvent = () => {};
let _Module = null;
if (typeof WallixModule === 'undefined') {
console.error('WallixModule is not defined - rdp.wasm.js may not have loaded');
} else {
WallixModule({
// INITIAL_MEMORY: 16777216, // 16**6
// INITIAL_MEMORY: 268435456, // 16**7
}).then((Module) => {
_Module = Module;
// optional
const LogLevel = Module.LogLevel;
Module.log = function(priority, msg) {
const logger = (priority === LogLevel.Info) ? console.log
: (priority === LogLevel.Warning) ? console.warn
: (priority === LogLevel.Error) ? console.error
: (priority === LogLevel.Debug) ? (s) => {
console.debug("%c%s", 'color:yellow', s)
}
: console.info;
logger(msg);
};
// Set constants now that module is loaded
RdpClient = _Module.RdpClient;
ClipboardChannel = _Module.ClipboardChannel;
MouseFlags = _Module.MouseFlags;
InputFlags = _Module.InputFlags;
}).catch((e) => {
console.error('Failed to load WebAssembly module:', e);
showNotification('Failed to load RDP WebAssembly module', 'danger');
});
console.log('After WallixModule setup');
// Constants will be set after module loads
let RdpClient, ClipboardChannel, MouseFlags, InputFlags;
// Define constants that will be available after module loads
const KeyAcquire = 0;
const KeyRelease = 0x80;
const SyncFlags = {
ShiftLeft: 0x01,
ShiftRight: 0x02,
ControlLeft: 0x04,
ControlRight: 0x08,
AltLeft: 0x10,
AltRight: 0x20,
OSLeft: 0x40,
OSRight: 0x80,
NumLock: 0x100,
CapsLock: 0x200,
KanaLock: 0x400,
ScrollLock: 0x800
};
console.log('After constants');
function MultiSelectToInt(e, constants)
{
let flags = 0;
for (let i = 0; i < e.length; i++) {
if (e.options[i].selected) {
flags |= constants[e.options[i].value] || 0;
}
}
return flags;
}
const gdImplTable = {
'2d':newRdpGraphics2D,
webgl:newRdpGraphicsGL,
webgl2:newRdpGraphicsGL2,
};
class Keyboard
{
// driver = class {
// sendScancodes(scancodes:Array[Number], evt:KeyEvent);
// syncKbdLocks(syncFlags:Number)
// }
constructor(keymap, driver) {
this._driver = driver;
this._keymap = keymap;
this._syncState = 0;
// on window, when left + right shift are pressed, onkeyup is only triggered for the last one
this._shiftDown = 0;
}
copyInternalStateFrom(other) {
this._syncState = other._syncState;
this._shiftDown = other._shiftDown;
this._keymap = other._keymap;
}
activeModsSync() {
this._syncState = 1;
}
keyup(evt) {
if (!this._syncState && evt.key === 'Shift') {
this._shiftDown &= ~this._codeToShiftMod(evt.code);
// shift is released but one of the sides is still considered pressed
if (this._shiftDown && !evt.getModifierState('Shift')) {
const scancodes = [];
if (this._shiftDown & SyncFlags.ShiftRight) {
scancodes.push(ScancodeByMod.ShiftRight | KeyRelease);
}
if (this._shiftDown & SyncFlags.ShiftLeft) {
scancodes.push(ScancodeByMod.ShiftLeft | KeyRelease);
}
this._shiftDown = 0;
this._driver.sendScancodes(scancodes, evt);
return;
}
}
this._keyEvent(evt, KeyRelease);
}
keydown(evt) {
if (!this._syncState && evt.key === 'Shift') {
this._shiftDown |= this._codeToShiftMod(evt.code);
}
this._keyEvent(evt, KeyAcquire);
}
_keyEvent(evt, flag) {
if (!this._preprocessKeyEvent(evt, flag)) return;
// numpad
if (evt.location === KeyboardEvent.DOM_KEY_LOCATION_NUMPAD) {
const scancode = numpadCodeToScancode(evt.code);
this._driver.sendScancodes([scancode | flag], evt);
return;
}
const scancodes = codeToScancodes(evt.key, flag) || codeToScancodes(evt.code, flag);
if (scancodes) {
this._driver.sendScancodes(scancodes, evt);
}
}
/// \return false when key processing should stop
_preprocessKeyEvent(evt, flag) {
if (!this._syncState) return true;
let syncFlags = 0;
// locks
if (evt.getModifierState("NumLock")) syncFlags |= SyncFlags.NumLock;
if (evt.getModifierState("CapsLock")) syncFlags |= SyncFlags.CapsLock;
if (evt.getModifierState("KanaLock")) syncFlags |= SyncFlags.KanaLock;
if (evt.getModifierState("ScrollLock")) syncFlags |= SyncFlags.ScrollLock;
// locks are always properly synchronized and only need to be sent once
if (this._syncState === 1) {
this._driver.syncKbdLocks(syncFlags);
this._syncState = 2;
}
if (evt.altKey) syncFlags |= SyncFlags.AltLeft;
if (evt.getModifierState("AltGraph")) syncFlags |= SyncFlags.AltRight;
// ambiguously mods
let leftOrRight = 0;
if (evt.metaKey) leftOrRight |= (evt.code === 'OSRight' && flag === KeyAcquire) ? SyncFlags.OSRight : SyncFlags.OSLeft;
if (evt.ctrlKey) leftOrRight |= (evt.code === 'ControlRight' && flag === KeyAcquire) ? SyncFlags.ControlRight : SyncFlags.ControlLeft;
if (evt.shiftKey) leftOrRight |= (evt.code === 'ShiftRight' && flag === KeyAcquire) ? SyncFlags.ShiftRight : SyncFlags.ShiftLeft;
syncFlags |= leftOrRight;
this._driver.sendScancodes(scancodesForSynchronizedMods(syncFlags), evt);
this._keymap.sync(syncFlags);
this._shiftDown = leftOrRight & (SyncFlags.ShiftRight | SyncFlags.ShiftLeft);
// mods are unambiguously synchronized
if (!leftOrRight) {
this._syncState = 0;
}
switch (evt.code) {
// mods are already processed, no need to continue
case "OSLeft":
case "OSRight":
case "ShiftLeft":
case "ShiftRight":
case "ControlLeft":
case "ControlRight":
return false;
}
return true;
}
_codeToShiftMod(code) {
if (code === 'ShiftRight') return SyncFlags.ShiftRight;
if (code === 'ShiftLeft') return SyncFlags.ShiftLeft;
return 0;
}
}
class EmulatedKeyboard extends Keyboard
{
// driver = class {
// sendUnicode(unicode:String, flag:Number, evt:KeyEvent)
// sendScancodes(scancodes:Array[Number], evt:KeyEvent);
// syncKbdLocks(syncFlags:Number)
// }
constructor(keymap, driver) {
super(keymap, driver)
this._hasUnicodeSupport = false;
}
setUnicodeSupport(enable) {
this._hasUnicodeSupport = enable;
}
compositeKeyEvent(evt, text) {
if (!this._preprocessKeyEvent(evt, KeyAcquire)) return;
const scancodes = this._keymap.toScancodesAndFlags(text, text, KeyAcquire);
if (scancodes) {
this._driver.sendScancodes(this._unstatedScancodes(scancodes), evt);
}
else if (this._hasUnicodeSupport) {
this._driver.sendUnicode(text, KeyAcquire, evt);
this._driver.sendUnicode(text, KeyRelease, evt);
}
}
// release pressed keys and press released keys
_unstatedScancodes(scancodes) {
const set = new Set();
for (const scancode of scancodes) {
if (scancode & KeyRelease)
set.delete(scancode & ~KeyRelease);
else
set.add(scancode);
}
const len = scancodes.length;
for (let i = 0; i < len; ++i) {
const scancode = scancodes[i];
if (!(scancode & KeyRelease) && set.has(scancode)) {
scancodes.push(scancode & KeyRelease);
}
}
return scancodes;
}
_keyEvent(evt, flag) {
if (!this._preprocessKeyEvent(evt, flag)) return;
if (isComposing(evt)) {
return;
}
// numpad
if (evt.location === KeyboardEvent.DOM_KEY_LOCATION_NUMPAD) {
const scancode = numpadCodeToScancode(evt.code);
this._driver.sendScancodes([scancode | flag], evt);
return;
}
const scancodes = this._keymap.toScancodesAndFlags(evt.key, evt.code, flag);
if (scancodes) {
this._driver.sendScancodes(scancodes, evt);
}
else if (this._hasUnicodeSupport) {
this._driver.sendUnicode(evt.key, flag, evt);
}
}
}
class UnicodeKeyboard extends Keyboard
{
// driver = class {
// sendUnicode(unicode:String, flag:Number, evt:KeyEvent)
// sendScancodes(scancodes:Array[Number], evt:KeyEvent);
// syncKbdLocks(syncFlags:Number)
// }
constructor(keymap, driver) {
super(keymap, driver)
}
_keyEvent(evt, flag) {
if (!this._preprocessKeyEvent(evt, flag)) return;
if (isComposing(evt)) {
return;
}
if (evt.key.length === 1 || evt.key.charCodeAt(0) > 127) {
this._driver.sendUnicode(evt.key, flag, evt);
}
else {
const scancodes = codeToScancodes(evt.key, flag) || codeToScancodes(evt.code, flag);
if (scancodes) {
this._driver.sendScancodes(scancodes, evt);
}
}
}
}
console.log('After classes');
let rdpclient = null;
let socket = null;
let connected = false;
let hWheelSupport = false;
let MouseXSupport = false;
const sendData = function() {
if (socket && socket.readyState === WebSocket.OPEN && rdpclient) {
const out = rdpclient.getOutputData();
if (out.length) {
socket.send(out);
rdpclient.resetOutputData();
}
}
};
const sendScancodes = function(scancodes, evt) {
if (scancodes) {
evt.preventDefault();
evt.stopImmediatePropagation();
for (let i = 0; i < scancodes.length; ++i) {
const scancode = scancodes[i];
console.log('Scancode: send', scancode, '0x'+scancode.toString(16));
rdpclient.writeScancodeEvent(scancode);
}
sendData();
}
else {
console.warn('Scancode: unknown keycode', evt.key, evt.code)
}
}
const sendUnicode = function(unicode, flag, evt) {
const scancode = keycodeToSingleScancode(unicode); // actionLayout[unicode];
if (scancode) {
sendScancodes([scancode | flag], evt)
}
else {
evt.preventDefault();
evt.stopImmediatePropagation();
for (let i = 0; i < unicode.length; ++i) {
const code = unicode.charCodeAt(i);
console.log('Unicode: send', code, `(0x${code.toString(16)})`, 'flag:', flag, `(0x${flag.toString(16)})`);
rdpclient.writeUnicodeEvent(code, flag);
}
sendData();
}
}
const isComposing = function(evt) {
switch (evt.key) {
case 'Control':
case 'Shift':
case 'Alt':
case 'AltGraph':
case 'NumLock':
case 'ScrollLock':
case 'CapsLock':
case 'OS':
return false;
case 'Dead':
case 'Compose':
case 'Process':
// case 'Unidentified':
return true;
}
return evt.isComposing;
};
const currentLayout = function() {
const kbdLayoutId = defaultLayoutId; // since we don't have input, use default
const layout = layouts[kbdLayoutId];
return layout;
}
const keyboardDriver = {
sendUnicode,
sendScancodes,
syncKbdLocks: function(syncFlags) {
rdpclient.syncKbdLocks(syncFlags);
},
};
const keymap = new ReversedKeymap(currentLayout());
const scancodeKeyboard = new Keyboard(keymap, keyboardDriver);
const emulatedKeyboard = new EmulatedKeyboard(keymap, keyboardDriver);
const unicodeKeyboard = new UnicodeKeyboard(keymap, keyboardDriver);
let keyboardForEvent = scancodeKeyboard;
const onKeyUp = (evt) => { keyboardForEvent.keyup(evt); };
const onKeyDown = (evt) => { keyboardForEvent.keydown(evt); };
function sendMouseEvent(evt, flags)
{
evt.preventDefault();
evt.stopImmediatePropagation();
rdpclient.writeMouseEvent(evt.offsetX, evt.offsetY, flags);
sendData();
}
function sendMouseButton(evt, flag)
{
switch (evt.button) {
case 0: return sendMouseEvent(evt, flag | MouseFlags.LeftButton);
case 1: return sendMouseEvent(evt, flag | MouseFlags.MiddleButton);
case 2: return sendMouseEvent(evt, flag | MouseFlags.RightButton);
case 3: if (MouseXSupport) return sendMouseEvent(evt, flag | MouseFlags.Button4); break;
case 4: if (MouseXSupport) return sendMouseEvent(evt, flag | MouseFlags.Button5); break;
}
}
const onMouseMove = (evt) => sendMouseEvent(evt, MouseFlags.Move);
const onMouseDown = (evt) => sendMouseButton(evt, MouseFlags.Down);
const onMouseUp = (evt) => sendMouseButton(evt, MouseFlags.Up);
const onMouseWheel = (evt) => {
if (evt.deltaY) {
const delta = (evt.deltaY < 0)
? MouseFlags.WheelRotationMask
: MouseFlags.WheelNegative;
sendMouseEvent(evt, MouseFlags.VerticalWheel | delta);
}
else if (evt.deltaX && hWheelSupport) {
const delta = (evt.deltaX < 0)
? MouseFlags.WheelRotationMask
: MouseFlags.WheelNegative;
sendMouseEvent(evt, MouseFlags.HorizontalWheel | delta);
}
};
console.log('Attaching event listeners...');
// Check if elements exist
const connectBtn = document.getElementById('connectBtn');
const disconnectBtn = document.getElementById('disconnectBtn');
const cancelConnectBtn = document.getElementById('cancelConnectBtn');
const startRdpBtn = document.getElementById('startRdpBtn');
const closeBtn = document.querySelector('.close-btn');
const maximizeBtn = document.querySelector('.maximize-btn');
const minimizeBtn = document.querySelector('.minimize-btn');
const zoomBtn = document.getElementById('zoomBtn');
if (connectBtn) {
connectBtn.addEventListener('click', function(e) {
showRdpConfig();
});
}
if (disconnectBtn) {
disconnectBtn.addEventListener('click', function(e) {
disconnect();
});
}
if (cancelConnectBtn) {
cancelConnectBtn.addEventListener('click', function(e) {
cancelConnect();
});
}
// Window control buttons
if (closeBtn) {
closeBtn.addEventListener('click', function(e) {
console.log('Close button clicked');
disconnect();
});
console.log('Close button listener attached');
}
if (maximizeBtn) {
maximizeBtn.addEventListener('click', function(e) {
console.log('Maximize button clicked');
toggleFullscreen();
});
console.log('Maximize button listener attached');
}
if (minimizeBtn) {
minimizeBtn.addEventListener('click', function(e) {
console.log('Minimize button clicked');
toggleFullscreen();
});
console.log('Minimize button listener attached');
}
if (zoomBtn) {
zoomBtn.addEventListener('click', function(e) {
console.log('Zoom button clicked');
toggleZoom();
});
console.log('Zoom button listener attached');
}
// Input event handlers
let ecanvas = document.getElementById('canvas');
let ecanvasFocus = document.getElementById('canvasFocus');
function showNotification(message, type = 'info') {
const notificationArea = document.getElementById('notification-area');
const notification = document.createElement('div');
notification.className = `alert alert-${type} alert-dismissible fade show`;
notification.innerHTML = `${message}<button type="button" class="btn-close" data-bs-dismiss="alert"></button>`;
notificationArea.appendChild(notification);
setTimeout(() => {
if (notification.parentNode) {
notification.remove();
}
}, 5000);
}
function toggleFullscreen() {
const rdpWindow = document.querySelector('.rdp-window');
const maximizeBtn = document.querySelector('.maximize-btn');
const maximizeIcon = maximizeBtn.querySelector('.maximize-icon');
if (rdpWindow.classList.contains('fullscreen')) {
// Exit fullscreen
rdpWindow.classList.remove('fullscreen');
maximizeIcon.textContent = '□';
maximizeBtn.title = 'Fullscreen';
} else {
// Enter fullscreen
rdpWindow.classList.add('fullscreen');
maximizeIcon.textContent = '▭'; // Restore icon
maximizeBtn.title = 'Exit Fullscreen';
}
}
function toggleZoom() {
if (!rdpclient || !connected) return;
const zoomBtn = document.getElementById('zoomBtn');
const zoomIcon = zoomBtn.querySelector('i');
const rdpContainer = document.getElementById('rdp');
if (zoomBtn.classList.contains('active')) {
// Switch to scaled view (fit to window)
zoomBtn.classList.remove('active');
zoomBtn.title = 'Toggle Zoom (Scale/Fit)';
zoomIcon.className = 'fas fa-search-plus';
rdpContainer.classList.remove('full-size');
// Enable scaling, disable clipping
if (rdpclient.scaleViewport !== undefined) {
rdpclient.scaleViewport = true;
}
showNotification('Switched to scaled view (fit to window)', 'info');
} else {
// Switch to full-size view with scrollbars
zoomBtn.classList.add('active');
zoomBtn.title = 'Toggle Zoom (Actual Size)';
zoomIcon.className = 'fas fa-search-minus';
rdpContainer.classList.add('full-size');
// Disable scaling, enable clipping
if (rdpclient.scaleViewport !== undefined) {
rdpclient.scaleViewport = false;
}
showNotification('Switched to actual size view with scrollbars', 'info');
}
}
function showRdpConfig() {
if (connected) return;
// Show the RDP configuration modal
const modal = new bootstrap.Modal(document.getElementById('rdpConfigModal'));
modal.show();
}
function startRdpConnection() {
// Hide the modal
const modal = bootstrap.Modal.getInstance(document.getElementById('rdpConfigModal'));
modal.hide();
// Start the actual connection
connect();
}
function connect() {
console.log('connect called, connected:', connected);
if (connected) return;
// Check if WebAssembly module is loaded
if (!_Module) {
console.log('WebAssembly module not loaded yet');
showNotification('WebAssembly module not loaded yet. Please wait.', 'warning');
return;
}
// Hide the status text and show loading message
document.getElementById('rdp_status').style.display = 'none';
document.getElementById('rdp_loading').style.display = 'block';
document.getElementById('cancelConnectBtn').style.display = 'inline-block';
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsUrl = wsProtocol + '//' + window.location.host + '/rdp/%s/ws';
try {
socket = new WebSocket(wsUrl);
socket.binaryType = 'arraybuffer';
socket.onopen = () => {
console.info('Graphics implementation: ' + document.getElementById('rdpGraphicsImpl').value);
const gd = gdImplTable[document.getElementById('rdpGraphicsImpl').value](ecanvas, _Module);
gd.drawRect(0, 0, gd.width, gd.height, 0);
// Get form values
const config = {
width: parseInt(document.getElementById('rdpWidth').value) || 1024,
height: parseInt(document.getElementById('rdpHeight').value) || 768,
username: document.getElementById('rdpUsername').value || '',
password: document.getElementById('rdpPassword').value || '',
domain: document.getElementById('rdpDomain').value || '',
bpp: parseInt(document.getElementById('rdpBpp').value) || 32,
verbosity: parseInt(document.getElementById('rdpVerbosity').value) || 0,
keylayout: currentLayout().klid,
};
// Add JSON config if provided
const jsonConfig = document.getElementById('rdpJsonConfig').value.trim();
if (jsonConfig) {
try {
const extraConfig = JSON.parse(jsonConfig);
Object.assign(config, extraConfig);
} catch (e) {
console.warn('Invalid JSON config, ignoring:', e);
}
}
console.table(config);
rdpclient = new RdpClient(gd, config);
window.rdpclient = rdpclient;
window.sendData = sendData;
socket.onmessage = function(event) {
rdpclient.processInputData(event.data);
sendData();
};
rdpclient.writeFirstPacket();
sendData();
connected = true;
document.getElementById('connectBtn').disabled = true;
document.getElementById('disconnectBtn').disabled = false;
// Hide loading message
document.getElementById('rdp_loading').style.display = 'none';
showNotification('RDP session connected', 'success');
// Set up input handling
updateInput();
};
socket.onclose = () => {
connected = false;
document.getElementById('connectBtn').disabled = false;
document.getElementById('disconnectBtn').disabled = true;
// Reset UI to initial state
document.getElementById('rdp_status').style.display = 'block';
document.getElementById('rdp_loading').style.display = 'none';
document.getElementById('cancelConnectBtn').style.display = 'none';
showNotification('RDP session disconnected', 'info');
canvasStopEvents();
rdpclient = null;
socket = null;
};
socket.onerror = (e) => {
console.error('RDP WebSocket error:', e);
showNotification('RDP connection error', 'danger');
};
} catch (e) {
console.error('Failed to create RDP client:', e);
showNotification('Failed to connect RDP: ' + e.message, 'danger');
}
}
function updateInput()
{
if (!rdpclient) return;
const inputFlags = rdpclient.getInputFlags();
const keyboardLayout = rdpclient.getKeyboardLayout();
console.log(`keyboardLayout: 0x${keyboardLayout.toString(16)}`);
console.group(`inputFlags: 0x${inputFlags.toString(16)}`);
for (const k in InputFlags) {
console.log(`${k}: ${(inputFlags & InputFlags[k]) ? 1 : 0} (0x${InputFlags[k].toString(16)})`);
}
console.groupEnd();
hWheelSupport = Boolean(inputFlags & InputFlags.HorizontalWheel);
MouseXSupport = Boolean(inputFlags & InputFlags.MouseX);
updateKbdInput(inputFlags);
kbdInputLayoutEvent = () => {
if (!rdpclient) return;
updateKbdInput(inputFlags);
}
canvasStopEvents();
canvasStartEvents();
}
function updateKbdInput(inputFlags)
{
const kbdMethodId = document.getElementById('rdpKeyboardMethod').selectedIndex;
const altGrIsCtrlAndAlt = document.getElementById('rdpAltGrCtrlAlt').checked;
const kbdMethod = document.getElementById('rdpKeyboardMethod')[kbdMethodId].value;
const hasUnicode = !!(inputFlags & InputFlags.Unicode);
const layout = currentLayout();
console.group('keyboard');
console.log(`unicode support: ${hasUnicode}`);
console.log(`method: (${kbdMethodId}) ${kbdMethod}`);
console.log(`layout: (0x${layout.klid.toString(16)}) ${layout.displayName}`);
console.log(`AltGr = Ctrl + Alt: ${altGrIsCtrlAndAlt}`);
console.groupEnd();
keymap.altGrIsCtrlAndAlt = altGrIsCtrlAndAlt;
keymap.layout = layout;
emulatedKeyboard.setUnicodeSupport(hasUnicode);
const newKeyboardForEvent = (kbdMethod === 'emulateScancode') ? emulatedKeyboard
: (kbdMethod === 'unicode') ? unicodeKeyboard
: scancodeKeyboard;
newKeyboardForEvent.copyInternalStateFrom(keyboardForEvent);
keyboardForEvent = newKeyboardForEvent;
keyboardForEvent.activeModsSync();
}
function canvasStartEvents()
{
ecanvas.addEventListener('mousemove', onMouseMove);
ecanvas.addEventListener('mousedown', onMouseDown);
ecanvas.addEventListener('mouseup', onMouseUp);
ecanvas.addEventListener('wheel', onMouseWheel);
ecanvasFocus.addEventListener('keydown', onKeyDown);
ecanvasFocus.addEventListener('keyup', onKeyUp);
canvasEnableFocus();
}
function canvasStopEvents()
{
ecanvas.removeEventListener('mousemove', onMouseMove);
ecanvas.removeEventListener('mousedown', onMouseDown);
ecanvas.removeEventListener('mouseup', onMouseUp);
ecanvas.removeEventListener('wheel', onMouseWheel);
ecanvasFocus.removeEventListener('keydown', onKeyDown);
ecanvasFocus.removeEventListener('keyup', onKeyUp);
}
function canvasFocus(evt)
{
console.log('focus');
ecanvasFocus.addEventListener('keydown', onKeyDown);
ecanvasFocus.addEventListener('keyup', onKeyUp);
ecanvas.onclick = (e) => {
e.preventDefault();
e.stopImmediatePropagation();
};
keyboardForEvent.activeModsSync();
}
function canvasEnableFocus()
{
// preventScroll don't work with firefox
ecanvasFocus.focus({preventScroll: true});
}
function canvasBlur()
{
console.log('blur');
ecanvasFocus.removeEventListener('keydown', onKeyDown);
ecanvasFocus.removeEventListener('keyup', onKeyUp);
ecanvas.onclick = canvasEnableFocus;
}
ecanvasFocus.onblur = canvasBlur;
ecanvasFocus.onfocus = canvasFocus;
function disconnect() {
if (socket) {
socket.close();
socket = null;
}
if (rdpclient) {
rdpclient = null;
}
connected = false;
document.getElementById('connectBtn').disabled = false;
document.getElementById('disconnectBtn').disabled = true;
// Reset UI to initial state
document.getElementById('rdp_status').style.display = 'block';
document.getElementById('rdp_loading').style.display = 'none';
document.getElementById('cancelConnectBtn').style.display = 'none';
canvasStopEvents();
location.reload();
}
function cancelConnect() {
if (socket) {
socket.close();
socket = null;
}
if (rdpclient) {
rdpclient = null;
}
connected = false;
document.getElementById('connectBtn').disabled = false;
document.getElementById('disconnectBtn').disabled = true;
// Reset UI to initial state
document.getElementById('rdp_status').style.display = 'block';
document.getElementById('rdp_loading').style.display = 'none';
document.getElementById('cancelConnectBtn').style.display = 'none';
showNotification('RDP connection cancelled', 'warning');
}
</script>
</body>
</html>
\ No newline at end of file
......@@ -19,7 +19,3 @@ else if (typeof define === 'function' && define['amd'])
define([], function() { return WallixModule; });
else if (typeof exports === 'object')
exports["WallixModule"] = WallixModule;
else {
window.WallixModule = WallixModule;
window.Module = WallixModule;
}
......@@ -1417,7 +1417,7 @@ const newRdpGraphics = function(canvasElement, module, ropError) {
return ctx ? createCtx(ctx, newRdpPointer(canvasElement, module)) : undefined;
};
if (typeof module !== 'undefined' && module.exports) {
try {
module.exports.newRdpGraphics2D = newRdpGraphics2D;
module.exports.newRdpGraphicsGL = newRdpGraphicsGL;
module.exports.newRdpGraphicsGL2 = newRdpGraphicsGL2;
......@@ -1426,13 +1426,7 @@ if (typeof module !== 'undefined' && module.exports) {
module.exports.newRdpGL = newRdpGL;
module.exports.newRdpGL2 = newRdpGL2;
module.exports.newRdpPointer = newRdpPointer;
} else {
window.newRdpGraphics2D = newRdpGraphics2D;
window.newRdpGraphicsGL = newRdpGraphicsGL;
window.newRdpGraphicsGL2 = newRdpGraphicsGL2;
window.newRdpGraphics = newRdpGraphics;
window.newRdpCanvas = newRdpCanvas;
window.newRdpGL = newRdpGL;
window.newRdpGL2 = newRdpGL2;
window.newRdpPointer = newRdpPointer;
}
catch (e) {
// module not found
}
......@@ -2441,9 +2441,9 @@ static int handle_request(int client_fd, const http_request_t *req) {
return 0;
}
// Generate RDP HTML with client_id
char html[65536];
char html[262144];
int len = snprintf(html, sizeof(html), rdp_page_html,
client_id, client_id, client_id, client_id, client_id);
client_id, client_id, client_id, client_id);
// No CSP header for RDP pages to avoid blocking WebAssembly
send_response(client_fd, 200, "OK", "text/html", html, len, NULL, NULL);
} else {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment