[WIP]: Spice protocol support.
This commit is contained in:
parent
5dbf4820ab
commit
c75a1fe008
@ -37,6 +37,7 @@ DIST_SUBDIRS = \
|
||||
src/pulse \
|
||||
src/protocols/kubernetes \
|
||||
src/protocols/rdp \
|
||||
src/protocols/spice \
|
||||
src/protocols/ssh \
|
||||
src/protocols/telnet \
|
||||
src/protocols/vnc
|
||||
@ -65,6 +66,10 @@ if ENABLE_RDP
|
||||
SUBDIRS += src/protocols/rdp
|
||||
endif
|
||||
|
||||
if ENABLE_SPICE
|
||||
SUBDIRS += src/protocols/spice
|
||||
endif
|
||||
|
||||
if ENABLE_SSH
|
||||
SUBDIRS += src/protocols/ssh
|
||||
endif
|
||||
|
24
configure.ac
24
configure.ac
@ -634,6 +634,27 @@ then
|
||||
|
||||
fi
|
||||
|
||||
#
|
||||
# spice-glib
|
||||
#
|
||||
|
||||
have_spice_glib=disabled
|
||||
AC_ARG_WITH([spice],
|
||||
[AS_HELP_STRING([--with-spice],
|
||||
[support SPICE @<:@default=check@:>@])],
|
||||
[],
|
||||
[with_spice=check])
|
||||
|
||||
if test "x$with_spice" != "xno"
|
||||
then
|
||||
have_spice_glib=yes
|
||||
PKG_CHECK_MODULES([GLIB2], [glib-2.0],, [have_spice_glib=no])
|
||||
PKG_CHECK_MODULES([SPICE], [spice-client-glib-2.0],, [have_spice_glib=no])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL([ENABLE_SPICE], [test "x${have_spice_glib}" = "xyes"])
|
||||
AC_SUBST(SPICE_LIBS)
|
||||
|
||||
|
||||
#
|
||||
# FreeRDP 2 (libfreerdp2, libfreerdp-client2, and libwinpr2)
|
||||
@ -1188,6 +1209,7 @@ AC_CONFIG_FILES([Makefile
|
||||
src/protocols/kubernetes/tests/Makefile
|
||||
src/protocols/rdp/Makefile
|
||||
src/protocols/rdp/tests/Makefile
|
||||
src/protocols/spice/Makefile
|
||||
src/protocols/ssh/Makefile
|
||||
src/protocols/telnet/Makefile
|
||||
src/protocols/vnc/Makefile])
|
||||
@ -1199,6 +1221,7 @@ AC_OUTPUT
|
||||
|
||||
AM_COND_IF([ENABLE_KUBERNETES], [build_kubernetes=yes], [build_kubernetes=no])
|
||||
AM_COND_IF([ENABLE_RDP], [build_rdp=yes], [build_rdp=no])
|
||||
AM_COND_IF([ENABLE_SPICE], [build_spice=yes], [build_spice=no])
|
||||
AM_COND_IF([ENABLE_SSH], [build_ssh=yes], [build_ssh=no])
|
||||
AM_COND_IF([ENABLE_TELNET], [build_telnet=yes], [build_telnet=no])
|
||||
AM_COND_IF([ENABLE_VNC], [build_vnc=yes], [build_vnc=no])
|
||||
@ -1260,6 +1283,7 @@ $PACKAGE_NAME version $PACKAGE_VERSION
|
||||
|
||||
Kubernetes .... ${build_kubernetes}
|
||||
RDP ........... ${build_rdp}
|
||||
SPICE ......... ${build_spice}
|
||||
SSH ........... ${build_ssh}
|
||||
Telnet ........ ${build_telnet}
|
||||
VNC ........... ${build_vnc}
|
||||
|
133
src/protocols/spice/Makefile.am
Normal file
133
src/protocols/spice/Makefile.am
Normal file
@ -0,0 +1,133 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# NOTE: Parts of this file (Makefile.am) are automatically transcluded verbatim
|
||||
# into Makefile.in. Though the build system (GNU Autotools) automatically adds
|
||||
# its own license boilerplate to the generated Makefile.in, that boilerplate
|
||||
# does not apply to the transcluded portions of Makefile.am which are licensed
|
||||
# to you by the ASF under the Apache License, Version 2.0, as described above.
|
||||
#
|
||||
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
lib_LTLIBRARIES = libguac-client-spice.la
|
||||
|
||||
nodist_libguac_client_spice_la_SOURCES = \
|
||||
_generated_keymaps.c
|
||||
|
||||
libguac_client_spice_la_SOURCES = \
|
||||
argv.c \
|
||||
auth.c \
|
||||
channels/audio.c \
|
||||
channels/clipboard.c \
|
||||
channels/cursor.c \
|
||||
channels/display.c \
|
||||
channels/file.c \
|
||||
client.c \
|
||||
decompose.c \
|
||||
input.c \
|
||||
keyboard.c \
|
||||
keymap.c \
|
||||
log.c \
|
||||
settings.c \
|
||||
spice.c \
|
||||
user.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
argv.h \
|
||||
auth.h \
|
||||
channels/audio.h \
|
||||
channels/clipboard.h \
|
||||
channels/cursor.h \
|
||||
channels/display.h \
|
||||
channels/file.h \
|
||||
client.h \
|
||||
decompose.h \
|
||||
input.h \
|
||||
keyboard.h \
|
||||
keymap.h \
|
||||
log.h \
|
||||
settings.h \
|
||||
spice.h \
|
||||
user.h
|
||||
|
||||
libguac_client_spice_la_CFLAGS = \
|
||||
-Werror -Wall -pedantic -Iinclude \
|
||||
@COMMON_INCLUDE@ \
|
||||
@COMMON_SSH_INCLUDE@ \
|
||||
@LIBGUAC_INCLUDE@ \
|
||||
@GLIB2_CFLAGS@ \
|
||||
@SPICE_CFLAGS@
|
||||
|
||||
libguac_client_spice_la_LDFLAGS = \
|
||||
-version-info 0:0:0 \
|
||||
@CAIRO_LIBS@ \
|
||||
@GLIB2_LIBS@ \
|
||||
@SPICE_LIBS@
|
||||
|
||||
libguac_client_spice_la_LIBADD = \
|
||||
@COMMON_LTLIB@ \
|
||||
@LIBGUAC_LTLIB@
|
||||
|
||||
# Optional SFTP support
|
||||
if ENABLE_COMMON_SSH
|
||||
libguac_client_spice_la_SOURCES += sftp.c
|
||||
noinst_HEADERS += sftp.h
|
||||
libguac_client_spice_la_LIBADD += @COMMON_SSH_LTLIB@
|
||||
endif
|
||||
|
||||
#
|
||||
# Autogenerated keymaps and channel wrapper functions
|
||||
#
|
||||
|
||||
CLEANFILES = \
|
||||
_generated_keymaps.c
|
||||
|
||||
BUILT_SOURCES = \
|
||||
_generated_keymaps.c
|
||||
|
||||
spice_keymaps = \
|
||||
$(srcdir)/keymaps/base.keymap \
|
||||
$(srcdir)/keymaps/failsafe.keymap \
|
||||
$(srcdir)/keymaps/de_de_qwertz.keymap \
|
||||
$(srcdir)/keymaps/de_ch_qwertz.keymap \
|
||||
$(srcdir)/keymaps/en_gb_qwerty.keymap \
|
||||
$(srcdir)/keymaps/en_us_qwerty.keymap \
|
||||
$(srcdir)/keymaps/es_es_qwerty.keymap \
|
||||
$(srcdir)/keymaps/es_latam_qwerty.keymap \
|
||||
$(srcdir)/keymaps/fr_be_azerty.keymap \
|
||||
$(srcdir)/keymaps/fr_ca_qwerty.keymap \
|
||||
$(srcdir)/keymaps/fr_ch_qwertz.keymap \
|
||||
$(srcdir)/keymaps/fr_fr_azerty.keymap \
|
||||
$(srcdir)/keymaps/hu_hu_qwertz.keymap \
|
||||
$(srcdir)/keymaps/it_it_qwerty.keymap \
|
||||
$(srcdir)/keymaps/ja_jp_qwerty.keymap \
|
||||
$(srcdir)/keymaps/no_no_qwerty.keymap \
|
||||
$(srcdir)/keymaps/pl_pl_qwerty.keymap \
|
||||
$(srcdir)/keymaps/pt_br_qwerty.keymap \
|
||||
$(srcdir)/keymaps/sv_se_qwerty.keymap \
|
||||
$(srcdir)/keymaps/da_dk_qwerty.keymap \
|
||||
$(srcdir)/keymaps/tr_tr_qwerty.keymap
|
||||
|
||||
_generated_keymaps.c: $(spice_keymaps) $(srcdir)/keymaps/generate.pl
|
||||
$(AM_V_GEN) $(srcdir)/keymaps/generate.pl $(spice_keymaps)
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(spice_keymaps) \
|
||||
keymaps/generate.pl
|
53
src/protocols/spice/argv.c
Normal file
53
src/protocols/spice/argv.c
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "argv.h"
|
||||
#include "spice.h"
|
||||
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int guac_spice_argv_callback(guac_user* user, const char* mimetype,
|
||||
const char* name, const char* value, void* data) {
|
||||
|
||||
guac_client* client = user->client;
|
||||
guac_spice_client* spice_client = (guac_spice_client*) client->data;
|
||||
guac_spice_settings* settings = spice_client->settings;
|
||||
|
||||
/* Update username */
|
||||
if (strcmp(name, GUAC_SPICE_ARGV_USERNAME) == 0) {
|
||||
free(settings->username);
|
||||
settings->username = strdup(value);
|
||||
}
|
||||
|
||||
/* Update password */
|
||||
else if (strcmp(name, GUAC_SPICE_ARGV_PASSWORD) == 0) {
|
||||
free(settings->password);
|
||||
settings->password = strdup(value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
47
src/protocols/spice/argv.h
Normal file
47
src/protocols/spice/argv.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_SPICE_ARGV_H
|
||||
#define GUAC_SPICE_ARGV_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/argv.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* Handles a received argument value from a Guacamole "argv" instruction,
|
||||
* updating the given connection parameter.
|
||||
*/
|
||||
guac_argv_callback guac_spice_argv_callback;
|
||||
|
||||
/**
|
||||
* The name of the parameter Guacamole will use to specify/update the username
|
||||
* for the SPICE connection.
|
||||
*/
|
||||
#define GUAC_SPICE_ARGV_USERNAME "username"
|
||||
|
||||
/**
|
||||
* The name of the parameter Guacamole will use to specify/update the password
|
||||
* for the SPICE connection.
|
||||
*/
|
||||
#define GUAC_SPICE_ARGV_PASSWORD "password"
|
||||
|
||||
#endif /* GUAC_SPICE_ARGV_H */
|
||||
|
71
src/protocols/spice/auth.c
Normal file
71
src/protocols/spice/auth.c
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "argv.h"
|
||||
#include "auth.h"
|
||||
#include "spice.h"
|
||||
|
||||
#include <guacamole/argv.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/string.h>
|
||||
|
||||
#include <glib-unix.h>
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
|
||||
gboolean guac_spice_get_credentials(guac_client* client) {
|
||||
|
||||
guac_spice_client* spice_client = ((guac_spice_client*) client->data);
|
||||
guac_spice_settings* settings = spice_client->settings;
|
||||
|
||||
char* params[3] = {NULL};
|
||||
int i = 0;
|
||||
|
||||
/* Check if username is not provided. */
|
||||
if (settings->username == NULL) {
|
||||
guac_argv_register(GUAC_SPICE_ARGV_USERNAME, guac_spice_argv_callback, NULL, 0);
|
||||
params[i] = GUAC_SPICE_ARGV_USERNAME;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Check if password is not provided. */
|
||||
if (settings->password == NULL) {
|
||||
guac_argv_register(GUAC_SPICE_ARGV_PASSWORD, guac_spice_argv_callback, NULL, 0);
|
||||
params[i] = GUAC_SPICE_ARGV_PASSWORD;
|
||||
i++;
|
||||
}
|
||||
|
||||
params[i] = NULL;
|
||||
|
||||
/* If we have empty parameters, request them and await response. */
|
||||
if (i > 0) {
|
||||
guac_client_owner_send_required(client, (const char**) params);
|
||||
guac_argv_await((const char**) params);
|
||||
return true;
|
||||
}
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||
"Unable to retrieve any credentials from the user.");
|
||||
return false;
|
||||
|
||||
}
|
46
src/protocols/spice/auth.h
Normal file
46
src/protocols/spice/auth.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_SPICE_AUTH_H
|
||||
#define GUAC_SPICE_AUTH_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
|
||||
#include <glib-unix.h>
|
||||
|
||||
/**
|
||||
* Handler invoked when an authentication error is received from the SPICE
|
||||
* server, which retrieves the credentials from the Guacamole Client accessing
|
||||
* the connection, if those credentials have not been explicitly set in the
|
||||
* configuration. Returns TRUE if credentials are successfully retrieved, or
|
||||
* FALSE otherwise.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client that is attempting to connect to the SPICE server and
|
||||
* that will be asked for the credentials.
|
||||
*
|
||||
* @return
|
||||
* TRUE if the credentials are retrieved from the users; otherwise FALSE.
|
||||
*/
|
||||
gboolean guac_spice_get_credentials(guac_client* client);
|
||||
|
||||
#endif /* GUAC_SPICE_AUTH_H */
|
||||
|
68
src/protocols/spice/channels/audio.c
Normal file
68
src/protocols/spice/channels/audio.c
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "audio.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
|
||||
void guac_spice_client_audio_playback_data_handler(
|
||||
SpicePlaybackChannel* channel, gpointer data, gint size,
|
||||
guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Calling audio playback data handler.");
|
||||
|
||||
}
|
||||
|
||||
void guac_spice_client_audio_playback_delay_handler(
|
||||
SpicePlaybackChannel* channel, guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Calling audio playback delay handler.");
|
||||
|
||||
}
|
||||
|
||||
void guac_spice_client_audio_playback_start_handler(
|
||||
SpicePlaybackChannel* channel, gint format, gint channels, gint rate,
|
||||
guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Calling audio playback start handler.");
|
||||
|
||||
}
|
||||
|
||||
void guac_spice_client_audio_playback_stop_handler(
|
||||
SpicePlaybackChannel* channel, guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Calling audio playback stop handler.");
|
||||
|
||||
}
|
||||
|
||||
void guac_spice_client_audio_record_start_handler(SpiceRecordChannel* channel,
|
||||
gint format, gint channels, gint rate, guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Calling audio record start handler.");
|
||||
|
||||
}
|
||||
|
||||
void guac_spice_client_audio_record_stop_handler(SpiceRecordChannel* channel,
|
||||
guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Calling audio record stop handler.");
|
||||
|
||||
}
|
133
src/protocols/spice/channels/audio.h
Normal file
133
src/protocols/spice/channels/audio.h
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_SPICE_AUDIO_H
|
||||
#define GUAC_SPICE_AUDIO_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
|
||||
#include <spice-client-glib-2.0/spice-client.h>
|
||||
|
||||
/**
|
||||
* A callback function invoked with the SPICE client receives audio playback
|
||||
* data from the SPICE server.
|
||||
*
|
||||
* @param channel
|
||||
* The SpicePlaybackChannel on which the data was sent.
|
||||
*
|
||||
* @param data
|
||||
* The audio data.
|
||||
*
|
||||
* @param size
|
||||
* The number of bytes of data sent.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client associated with this event.
|
||||
*/
|
||||
void guac_spice_client_audio_playback_data_handler(
|
||||
SpicePlaybackChannel* channel, gpointer data, gint size,
|
||||
guac_client* client);
|
||||
|
||||
/**
|
||||
* A callback function invoked when the SPICE server requests the audio playback
|
||||
* delay value from the client.
|
||||
*
|
||||
* @param channel
|
||||
* The SpicePlaybackChannel channel on which this event occurred.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client associated with this event.
|
||||
*/
|
||||
void guac_spice_client_audio_playback_delay_handler(
|
||||
SpicePlaybackChannel* channel, guac_client* client);
|
||||
|
||||
/**
|
||||
* A callback function invoked by the client when the SPICE server sends a
|
||||
* signal indicating that it is starting an audio transmission.
|
||||
*
|
||||
* @param channel
|
||||
* The SpicePlaybackChannel on which this event occurred.
|
||||
*
|
||||
* @param format
|
||||
* The SPICE_AUDIO_FMT value of the format of the audio data.
|
||||
*
|
||||
* @param channels
|
||||
* The number of channels of audio data present.
|
||||
*
|
||||
* @param rate
|
||||
* The audio sampling rate at which the data will be sent.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client associated with this event.
|
||||
*/
|
||||
void guac_spice_client_audio_playback_start_handler(
|
||||
SpicePlaybackChannel* channel, gint format, gint channels, gint rate,
|
||||
guac_client* client);
|
||||
|
||||
/**
|
||||
* The callback function invoked by the client when the SPICE server sends
|
||||
* an event indicating that audio playback will cease.
|
||||
*
|
||||
* @param channel
|
||||
* The SpicePlaybackChannel on which the recording is being halted.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client associated with this event.
|
||||
*/
|
||||
void guac_spice_client_audio_playback_stop_handler(
|
||||
SpicePlaybackChannel* channel, guac_client* client);
|
||||
|
||||
/**
|
||||
* The callback function invoked by the client when the SPICE server requests
|
||||
* that the client begin recording audio data to send to the server.
|
||||
*
|
||||
* @param channel
|
||||
* The SpiceRecordChannel on which the record event is being requested.
|
||||
*
|
||||
* @param format
|
||||
* The SPICE_AUDIO_FMT value representing the required recording format.
|
||||
*
|
||||
* @param channels
|
||||
* The number of audio channels that should be recorded.
|
||||
*
|
||||
* @param rate
|
||||
* The rate at which the recording should take place.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client associated with this event.
|
||||
*/
|
||||
void guac_spice_client_audio_record_start_handler(SpiceRecordChannel* channel,
|
||||
gint format, gint channels, gint rate, guac_client* client);
|
||||
|
||||
/**
|
||||
* The callback function invoked by the client when the SPICE server sends
|
||||
* an event requesting that recording be stopped.
|
||||
*
|
||||
* @param channel
|
||||
* The channel associated with the event.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client associated with the event.
|
||||
*/
|
||||
void guac_spice_client_audio_record_stop_handler(SpiceRecordChannel* channel,
|
||||
guac_client* client);
|
||||
#endif /* GUAC_SPICE_AUDIO_H */
|
||||
|
145
src/protocols/spice/channels/clipboard.c
Normal file
145
src/protocols/spice/channels/clipboard.c
Normal file
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "client.h"
|
||||
#include "clipboard.h"
|
||||
#include "common/clipboard.h"
|
||||
#include "common/iconv.h"
|
||||
#include "spice.h"
|
||||
#include "spice-constants.h"
|
||||
#include "user.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/stream.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
#include <spice-1/spice/vd_agent.h>
|
||||
|
||||
int guac_spice_set_clipboard_encoding(guac_client* client,
|
||||
const char* name) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Setting clipboard encoding.");
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int guac_spice_clipboard_handler(guac_user* user, guac_stream* stream,
|
||||
char* mimetype) {
|
||||
|
||||
guac_client_log(user->client, GUAC_LOG_DEBUG, "Calling SPICE clipboard handler.");
|
||||
guac_spice_client* spice_client = (guac_spice_client*) user->client->data;
|
||||
guac_common_clipboard_reset(spice_client->clipboard, mimetype);
|
||||
|
||||
/* Set handlers for clipboard stream */
|
||||
stream->blob_handler = guac_spice_clipboard_blob_handler;
|
||||
stream->end_handler = guac_spice_clipboard_end_handler;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int guac_spice_clipboard_blob_handler(guac_user* user, guac_stream* stream,
|
||||
void* data, int length) {
|
||||
|
||||
guac_client_log(user->client, GUAC_LOG_DEBUG, "Calling SPICE clipboard BLOB handler.");
|
||||
|
||||
/* Append new data */
|
||||
guac_spice_client* spice_client = (guac_spice_client*) user->client->data;
|
||||
guac_common_clipboard_append(spice_client->clipboard, (char*) data, length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int guac_spice_clipboard_end_handler(guac_user* user, guac_stream* stream) {
|
||||
|
||||
guac_client_log(user->client, GUAC_LOG_DEBUG, "Calling SPICE clipboard end handler.");
|
||||
|
||||
guac_spice_client* spice_client = (guac_spice_client*) user->client->data;
|
||||
const char* input = spice_client->clipboard->buffer;
|
||||
|
||||
/* Send via VNC only if finished connecting */
|
||||
if (spice_client->main_channel != NULL)
|
||||
spice_main_channel_clipboard_selection_notify(spice_client->main_channel,
|
||||
VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD,
|
||||
VD_AGENT_CLIPBOARD_UTF8_TEXT,
|
||||
(const unsigned char*) input,
|
||||
spice_client->clipboard->length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void guac_spice_clipboard_selection_handler(SpiceMainChannel channel,
|
||||
guint selection, guint type, gpointer data, guint size,
|
||||
guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Notifying client of clipboard data"
|
||||
" available from the guest.");
|
||||
|
||||
guac_spice_client* spice_client = (guac_spice_client*) client->data;
|
||||
|
||||
switch (type) {
|
||||
case VD_AGENT_CLIPBOARD_UTF8_TEXT:
|
||||
guac_common_clipboard_append(spice_client->clipboard, (char *) data, size);
|
||||
break;
|
||||
|
||||
default:
|
||||
guac_client_log(client, GUAC_LOG_WARNING, "Guacamole currently does"
|
||||
" not support clipboard data other than plain text.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void guac_spice_clipboard_selection_grab_handler(SpiceMainChannel channel,
|
||||
guint selection, gpointer types, guint ntypes, guint extra, guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Notifying client of clipboard grab"
|
||||
" in the guest.");
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Arg: channel: 0x%08x", channel);
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Arg: selection: 0x%08x", selection);
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Arg: types: 0x%08x", types);
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Arg: ntypes: 0x%08x", ntypes);
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Arg: extra: 0x%08x", extra);
|
||||
|
||||
}
|
||||
|
||||
void guac_spice_clipboard_selection_release_handler(SpiceMainChannel channel,
|
||||
guint selection, guint extra, guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Notifying client of clipboard"
|
||||
" release in the guest.");
|
||||
|
||||
}
|
||||
|
||||
void guac_spice_clipboard_selection_request_handler(SpiceMainChannel channel,
|
||||
guint selection, guint types, guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Requesting clipboard data from"
|
||||
" the client.");
|
||||
|
||||
guac_spice_client* spice_client = (guac_spice_client*) client->data;
|
||||
const char* input = spice_client->clipboard->buffer;
|
||||
|
||||
spice_main_channel_clipboard_selection_notify(spice_client->main_channel,
|
||||
VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD,
|
||||
VD_AGENT_CLIPBOARD_UTF8_TEXT,
|
||||
(const unsigned char*) input,
|
||||
spice_client->clipboard->length);
|
||||
|
||||
}
|
150
src/protocols/spice/channels/clipboard.h
Normal file
150
src/protocols/spice/channels/clipboard.h
Normal file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_SPICE_CLIPBOARD_H
|
||||
#define GUAC_SPICE_CLIPBOARD_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
#include <spice-client-glib-2.0/spice-client.h>
|
||||
|
||||
/**
|
||||
* Sets the encoding of clipboard data exchanged with the SPICE server to the
|
||||
* encoding having the given name. If the name is NULL, or is invalid, the
|
||||
* standard ISO8859-1 encoding will be used.
|
||||
*
|
||||
* @param client
|
||||
* The client to set the clipboard encoding of.
|
||||
*
|
||||
* @param name
|
||||
* The name of the encoding to use for all clipboard data. Valid values
|
||||
* are: "ISO8859-1", "UTF-8", "UTF-16", "CP1252", or NULL.
|
||||
*
|
||||
* @return
|
||||
* Zero if the chosen encoding is standard for SPICE, or non-zero if the
|
||||
* SPICE standard is being violated.
|
||||
*/
|
||||
int guac_spice_set_clipboard_encoding(guac_client* client,
|
||||
const char* name);
|
||||
|
||||
/**
|
||||
* Handler for inbound clipboard data from Guacamole users.
|
||||
*/
|
||||
guac_user_clipboard_handler guac_spice_clipboard_handler;
|
||||
|
||||
/**
|
||||
* Handler for stream data related to clipboard.
|
||||
*/
|
||||
guac_user_blob_handler guac_spice_clipboard_blob_handler;
|
||||
|
||||
/**
|
||||
* Handler for end-of-stream related to clipboard.
|
||||
*/
|
||||
guac_user_end_handler guac_spice_clipboard_end_handler;
|
||||
|
||||
/**
|
||||
* A handler that will be registered with the SPICE client to handle clipboard
|
||||
* data sent from the SPICE server to the client.
|
||||
*
|
||||
* @param channel
|
||||
* The main SPICE channel on which this event was fired.
|
||||
*
|
||||
* @param selection
|
||||
* The clipboard on which the selection occurred.
|
||||
*
|
||||
* @param type
|
||||
* The type of the data that is on the clipboard.
|
||||
*
|
||||
* @param data
|
||||
* A pointer to the location containing the data that is on the clipboard.
|
||||
*
|
||||
* @param size
|
||||
* The amount of data in bytes.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client associated with this event handler, passed when the
|
||||
* handler was registered.
|
||||
*/
|
||||
void guac_spice_clipboard_selection_handler(SpiceMainChannel channel,
|
||||
guint selection, guint type, gpointer data, guint size,
|
||||
guac_client* client);
|
||||
|
||||
/**
|
||||
* A handler that will be registered with the SPICE client to handle clipboard
|
||||
* events where the guest (vdagent) within the SPICE server notifies the client
|
||||
* that data is available on the clipboard.
|
||||
*
|
||||
* @param channel
|
||||
* The main SpiceChannel on which this event is fired.
|
||||
*
|
||||
* @param selection
|
||||
* The SPICE clipboard from which the event is fired.
|
||||
*
|
||||
* @param types
|
||||
* The type of data being sent by the agent.
|
||||
*
|
||||
* @param ntypes
|
||||
* The number of data types represented.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client that was passed in when the callback was registered.
|
||||
*/
|
||||
void guac_spice_clipboard_selection_grab_handler(SpiceMainChannel channel,
|
||||
guint selection, gpointer types, guint ntypes, guint other, guac_client* client);
|
||||
|
||||
/**
|
||||
* A handler that will be called by the SPICE client when the SPICE server
|
||||
* is done with the clipboard and releases control of it.
|
||||
*
|
||||
* @param chennl
|
||||
* The main SPICE channel on which this event is fired.
|
||||
*
|
||||
* @param selection
|
||||
* The SPICE server clipboard releasing control.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client that was registered with the callback.
|
||||
*/
|
||||
void guac_spice_clipboard_selection_release_handler(SpiceMainChannel channel,
|
||||
guint selection, guint other, guac_client* client);
|
||||
|
||||
/**
|
||||
* A handler that will be called by the SPICE client when the SPICE server
|
||||
* would like to check and receive the contents of the client's clipboard.
|
||||
*
|
||||
* @param channel
|
||||
* The main SPICE channel on which this event is fired.
|
||||
*
|
||||
* @param selection
|
||||
* The SPICE server clipboard that is requesting data.
|
||||
*
|
||||
* @param types
|
||||
* The type of data to be sent to the SPICE server.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client object that was registered with the callback.
|
||||
*/
|
||||
void guac_spice_clipboard_selection_request_handler(SpiceMainChannel channel,
|
||||
guint selection, guint types, guac_client* client);
|
||||
|
||||
#endif /* GUAC_SPICE_CLIPBOARD_H */
|
||||
|
80
src/protocols/spice/channels/cursor.c
Normal file
80
src/protocols/spice/channels/cursor.c
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "common/cursor.h"
|
||||
#include "common/display.h"
|
||||
#include "common/surface.h"
|
||||
#include "spice.h"
|
||||
#include "spice-constants.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/layer.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <spice-client-glib-2.0/spice-client.h>
|
||||
|
||||
/* Define cairo_format_stride_for_width() if missing */
|
||||
#ifndef HAVE_CAIRO_FORMAT_STRIDE_FOR_WIDTH
|
||||
#define cairo_format_stride_for_width(format, width) (width*4)
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <syslog.h>
|
||||
|
||||
void guac_spice_cursor_hide(SpiceChannel* channel, guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "Cursor hide signal received.");
|
||||
|
||||
guac_spice_client* spice_client = (guac_spice_client*) client->data;
|
||||
guac_common_cursor_set_blank(spice_client->display->cursor);
|
||||
}
|
||||
|
||||
void guac_spice_cursor_move(SpiceChannel* channel, int x, int y,
|
||||
guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "Cursor move signal received.");
|
||||
|
||||
guac_spice_client* spice_client = (guac_spice_client*) client->data;
|
||||
guac_common_cursor_update(spice_client->display->cursor, client->__owner, x, y, spice_client->display->cursor->button_mask);
|
||||
}
|
||||
|
||||
void guac_spice_cursor_reset(SpiceChannel* channel, guac_client* client) {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Cursor reset signal received, not yet implemented");
|
||||
}
|
||||
|
||||
void guac_spice_cursor_set(SpiceChannel* channel, int width, int height,
|
||||
int x, int y, gpointer* rgba, guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "Cursor set signal received.");
|
||||
|
||||
guac_spice_client* spice_client = (guac_spice_client*) client->data;
|
||||
int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
|
||||
|
||||
/* Update stored cursor information */
|
||||
guac_common_cursor_set_argb(spice_client->display->cursor, x, y,
|
||||
(const unsigned char*) rgba, width, height, stride);
|
||||
|
||||
}
|
101
src/protocols/spice/channels/cursor.h
Normal file
101
src/protocols/spice/channels/cursor.h
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_SPICE_CURSOR_H
|
||||
#define GUAC_SPICE_CURSOR_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <spice-client-glib-2.0/spice-client.h>
|
||||
|
||||
/**
|
||||
* The callback function that is executed when the cursor hide signal is received
|
||||
* from the SPICE server.
|
||||
*
|
||||
* @param channel
|
||||
* The channel which received the cursor hide event.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client associated with this session.
|
||||
*/
|
||||
void guac_spice_cursor_hide(SpiceCursorChannel* channel, guac_client* client);
|
||||
|
||||
/**
|
||||
* The callback function that is executed when the cursor move signal is
|
||||
* received from the server.
|
||||
*
|
||||
* @param channel
|
||||
* The channel that received the cursor move event.
|
||||
*
|
||||
* @param x
|
||||
* The x position of the cursor.
|
||||
*
|
||||
* @param y
|
||||
* The y position of the cursor.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client associated with this SPICE session.
|
||||
*/
|
||||
void guac_spice_cursor_move(SpiceCursorChannel* channel, int x, int y,
|
||||
guac_client* client);
|
||||
|
||||
/**
|
||||
* The callback function that is executed in response to the cursor reset
|
||||
* signal, resetting the cursor to the default context.
|
||||
*
|
||||
* @param channel
|
||||
* The channel that received the cursor reset signal.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client associated with this SPICE session.
|
||||
*/
|
||||
void guac_spice_cursor_reset(SpiceCursorChannel* channel, guac_client* client);
|
||||
|
||||
/**
|
||||
* The callback function that is executed in response to receiving the cursor
|
||||
* set signal from the SPICE server, which sets the width, height, and image
|
||||
* of the cursor, and the x and y coordinates of the cursor hotspot.
|
||||
*
|
||||
* @param channel
|
||||
* The channel that received the cursor set signal.
|
||||
*
|
||||
* @param width
|
||||
* The width of the cursor image.
|
||||
*
|
||||
* @param height
|
||||
* The height of the cursor image.
|
||||
*
|
||||
* @param x
|
||||
* The x coordinate of the cursor hotspot.
|
||||
*
|
||||
* @param y
|
||||
* The y coordinate of the cursor hotspot.
|
||||
*
|
||||
* @param rgba
|
||||
* A pointer to the memory region containing the image data for the cursor,
|
||||
* or NULL if the default cursor image should be used.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client associated with this SPICE session.
|
||||
*/
|
||||
void guac_spice_cursor_set(SpiceCursorChannel* channel, int width, int height,
|
||||
int x, int y, gpointer* rgba, guac_client* client);
|
||||
|
||||
#endif /* GUAC_SPICE_CURSOR_H */
|
||||
|
170
src/protocols/spice/channels/display.c
Normal file
170
src/protocols/spice/channels/display.c
Normal file
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "common/display.h"
|
||||
#include "common/iconv.h"
|
||||
#include "common/surface.h"
|
||||
#include "spice.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/layer.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <spice-client-glib-2.0/spice-client.h>
|
||||
|
||||
/* Define cairo_format_stride_for_width() if missing */
|
||||
#ifndef HAVE_CAIRO_FORMAT_STRIDE_FOR_WIDTH
|
||||
#define cairo_format_stride_for_width(format, width) (width*4)
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <syslog.h>
|
||||
|
||||
void guac_spice_client_display_update(SpiceChannel* channel, int x,
|
||||
int y, int w, int h, guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Received request to update Spice display: %d, %d, %d, %d", x, y, w, h);
|
||||
guac_spice_client* spice_client = (guac_spice_client*) client->data;
|
||||
|
||||
/* Retrieve the primary display buffer */
|
||||
SpiceDisplayPrimary primary;
|
||||
if (spice_display_channel_get_primary(channel, 0, &primary)) {
|
||||
|
||||
/* Create cairo surface from decoded buffer */
|
||||
cairo_surface_t* surface = cairo_image_surface_create_for_data(
|
||||
primary.data,
|
||||
CAIRO_FORMAT_RGB24,
|
||||
primary.width,
|
||||
primary.height,
|
||||
primary.stride);
|
||||
|
||||
/* A region smaller than the entire display should be updated. */
|
||||
if ((x > 0 || y > 0 ) && (w < primary.width || h < primary.height)) {
|
||||
|
||||
cairo_surface_t* updateArea = cairo_surface_create_similar_image(surface, CAIRO_FORMAT_RGB24, w, h);
|
||||
cairo_t* updateContext = cairo_create(updateArea);
|
||||
cairo_set_operator(updateContext, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_set_source_surface(updateContext, surface, 0 - x, 0 - y);
|
||||
cairo_rectangle(updateContext, 0, 0, w, h);
|
||||
cairo_fill(updateContext);
|
||||
guac_common_surface_draw(spice_client->display->default_surface, x, y, updateArea);
|
||||
cairo_surface_destroy(updateArea);
|
||||
|
||||
}
|
||||
|
||||
/* The entire display should be updated. */
|
||||
else {
|
||||
guac_common_surface_draw(spice_client->display->default_surface,
|
||||
0, 0, surface);
|
||||
}
|
||||
|
||||
/* Free surfaces */
|
||||
cairo_surface_destroy(surface);
|
||||
}
|
||||
|
||||
/* Flush surface and mark end of frame. */
|
||||
guac_common_surface_flush(spice_client->display->default_surface);
|
||||
guac_client_end_frame(client);
|
||||
guac_socket_flush(client->socket);
|
||||
}
|
||||
|
||||
void guac_spice_client_display_gl_draw(SpiceChannel* channel, int x,
|
||||
int y, int w, int h, guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Received gl draw request.");
|
||||
|
||||
guac_spice_client* spice_client = (guac_spice_client*) client->data;
|
||||
|
||||
/* Copy specified rectangle within default layer */
|
||||
guac_common_surface_copy(spice_client->display->default_surface,
|
||||
x, y, w, h,
|
||||
spice_client->display->default_surface, x, y);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void guac_spice_client_display_mark(SpiceChannel* channel, gint mark,
|
||||
guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Received signal to mark display.");
|
||||
|
||||
int channelId;
|
||||
|
||||
g_object_get(channel, "channel-id", &channelId, NULL);
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Channel %i marked as available.", channelId);
|
||||
|
||||
}
|
||||
|
||||
void guac_spice_client_display_primary_create(SpiceChannel* channel,
|
||||
gint format, gint width, gint height, gint stride, gint shmid,
|
||||
gpointer imgdata, guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Received request to create primary display.");
|
||||
|
||||
guac_spice_client* spice_client = (guac_spice_client*) client->data;
|
||||
spice_client->display = guac_common_display_alloc(client,
|
||||
width, height);
|
||||
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "Creating Cairo image surface.");
|
||||
cairo_surface_t* surface = cairo_image_surface_create_for_data(imgdata, CAIRO_FORMAT_RGB24,
|
||||
width, height, stride);
|
||||
|
||||
/* Draw directly to default layer */
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "Drawing to the default surface.");
|
||||
guac_common_surface_draw(spice_client->display->default_surface,
|
||||
0, 0, surface);
|
||||
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "Flushing the default surface.");
|
||||
guac_common_surface_flush(spice_client->display->default_surface);
|
||||
|
||||
guac_client_end_frame(client);
|
||||
guac_socket_flush(client->socket);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void guac_spice_client_display_primary_destroy(SpiceChannel* channel,
|
||||
guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Received request to destroy the primary display.");
|
||||
|
||||
guac_spice_client* spice_client = (guac_spice_client*) client->data;
|
||||
guac_common_display_free(spice_client->display);
|
||||
|
||||
}
|
||||
|
||||
void* guac_spice_client_streaming_handler(SpiceChannel* channel,
|
||||
gboolean streaming_mode, guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Received call to streaming handler.");
|
||||
|
||||
guac_spice_client* spice_client = (guac_spice_client*) client->data;
|
||||
return spice_client->display;
|
||||
|
||||
}
|
||||
|
||||
|
182
src/protocols/spice/channels/display.h
Normal file
182
src/protocols/spice/channels/display.h
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_SPICE_DISPLAY_H
|
||||
#define GUAC_SPICE_DISPLAY_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <spice-client-glib-2.0/spice-client.h>
|
||||
|
||||
/**
|
||||
* Callback invoked by the SPICE library when it receives a new binary image
|
||||
* data from the SPICE server. The image itself will be stored in the designated
|
||||
* sub-rectangle of client->framebuffer.
|
||||
*
|
||||
* @param channel
|
||||
* The SpiceDisplayChannel that received the update event.
|
||||
*
|
||||
* @param x
|
||||
* The X coordinate of the upper-left corner of the destination rectangle
|
||||
* in which the image should be drawn, in pixels.
|
||||
*
|
||||
* @param y
|
||||
* The Y coordinate of the upper-left corner of the destination rectangle
|
||||
* in which the image should be drawn, in pixels.
|
||||
*
|
||||
* @param w
|
||||
* The width of the image, in pixels.
|
||||
*
|
||||
* @param h
|
||||
* The height of the image, in pixels.
|
||||
*
|
||||
* @param guac_client
|
||||
* The guac_client associated with the event.
|
||||
*/
|
||||
void guac_spice_client_display_update(SpiceDisplayChannel* channel, int x,
|
||||
int y, int w, int h, guac_client* client);
|
||||
|
||||
/**
|
||||
* The callback function invoked when the RED_DISPLAY_MARK command is received
|
||||
* from the SPICE server and the display should be exposed.
|
||||
*
|
||||
* @param channel
|
||||
* The SpiceDisplayChannel on which the event was received.
|
||||
*
|
||||
* @param mark
|
||||
* Non-zero when the display mark has been received.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client associated with this channel and event.
|
||||
*/
|
||||
void guac_spice_client_display_mark(SpiceDisplayChannel* channel, gint mark,
|
||||
guac_client* client);
|
||||
|
||||
/**
|
||||
* The callback function invoked when primary display buffer data is sent from
|
||||
* the SPICE server to the client.
|
||||
*
|
||||
* @param channel
|
||||
* The SpiceDisplayChannel on which this event was received.
|
||||
*
|
||||
* @param format
|
||||
* The SPICE format of the received data.
|
||||
*
|
||||
* @param width
|
||||
* The total width of the display.
|
||||
*
|
||||
* @param height
|
||||
* The total height of the display.
|
||||
*
|
||||
* @param stride
|
||||
* The buffer width padding.
|
||||
*
|
||||
* @param shmid
|
||||
* The identifier of the shared memory segment associated with the data, or
|
||||
* -1 if shared memory is not in use.
|
||||
*
|
||||
* @param imgdata
|
||||
* A pointer to the buffer containing the surface data.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client associated with this channel/event.
|
||||
*/
|
||||
void guac_spice_client_display_primary_create(SpiceDisplayChannel* channel,
|
||||
gint format, gint width, gint height, gint stride, gint shmid,
|
||||
gpointer imgdata, guac_client* client);
|
||||
|
||||
/**
|
||||
* The callback function invoked by the client when the primary surface is
|
||||
* destroyed and should no longer be accessed.
|
||||
*
|
||||
* @param channel
|
||||
* The SpiceDisplayChannel on which the primary surface destroy event was
|
||||
* received.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client associated with this channel/event.
|
||||
*/
|
||||
void guac_spice_client_display_primary_destroy(SpiceDisplayChannel* channel,
|
||||
guac_client* client);
|
||||
|
||||
/**
|
||||
* Callback function that is invoked when a channel specifies that a display
|
||||
* is marked as active and should be exposed.
|
||||
*
|
||||
* @param channel
|
||||
* The channel on which the mark was received.
|
||||
*
|
||||
* @param marked
|
||||
* TRUE if the display should be marked; otherwise false.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client associated with the channel/event.
|
||||
*/
|
||||
void guac_spice_client_display_mark(SpiceDisplayChannel* channel,
|
||||
gboolean marked, guac_client* client);
|
||||
|
||||
/**
|
||||
* Callback invoked by the SPICE client when it receives a CopyRect message.
|
||||
* CopyRect specified a rectangle of source data within the display and a
|
||||
* set of X/Y coordinates to which that rectangle should be copied.
|
||||
*
|
||||
* @param channel
|
||||
* The SpiceDisplayChannel that received the gl_draw event.
|
||||
*
|
||||
* @param x
|
||||
* The X coordinate of the upper-left corner of the source rectangle
|
||||
* from which the image data should be copied, in pixels.
|
||||
*
|
||||
* @param y
|
||||
* The Y coordinate of the upper-left corner of the source rectangle
|
||||
* from which the image data should be copied, in pixels.
|
||||
*
|
||||
* @param w
|
||||
* The width of the source and destination rectangles, in pixels.
|
||||
*
|
||||
* @param h
|
||||
* The height of the source and destination rectangles, in pixels.
|
||||
*
|
||||
* @param guac_client
|
||||
* The guac_client associated with this gl_draw event.
|
||||
*/
|
||||
void guac_spice_client_display_gl_draw(SpiceDisplayChannel* channel, int x,
|
||||
int y, int w, int h, guac_client* client);
|
||||
|
||||
/**
|
||||
* The callback function invoked by the client when it receives a request to
|
||||
* change streaming mode.
|
||||
*
|
||||
* @param channel
|
||||
* The SpiceDisplayChannel that received the streaming mode change request.
|
||||
*
|
||||
* @param streaming_mode
|
||||
* TRUE if the display channel should be in streaming mode; otherwise FALSE.
|
||||
*
|
||||
* @param guac_client
|
||||
* The guac_client associated with this event.
|
||||
*
|
||||
* @return
|
||||
* A pointer to the display.
|
||||
*/
|
||||
void* guac_spice_client_streaming_handler(SpiceDisplayChannel* channel,
|
||||
gboolean streaming_mode, guac_client* client);
|
||||
|
||||
#endif /* GUAC_SPICE_DISPLAY_H */
|
||||
|
33
src/protocols/spice/channels/file.c
Normal file
33
src/protocols/spice/channels/file.c
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "file.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
|
||||
void guac_spice_client_file_transfer_handler(SpiceMainChannel* main_channel,
|
||||
SpiceFileTransferTask* task, guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "File transfer handler.");
|
||||
|
||||
}
|
||||
|
||||
#include "file.h"
|
47
src/protocols/spice/channels/file.h
Normal file
47
src/protocols/spice/channels/file.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GUAC_SPICE_FILE_H
|
||||
#define GUAC_SPICE_FILE_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
|
||||
#include <spice-client-glib-2.0/spice-client.h>
|
||||
|
||||
/**
|
||||
* A handler that is called when the SPICE client receives notification of
|
||||
* a new file transfer task.
|
||||
*
|
||||
* @param main_channel
|
||||
* The main channel associated with the SPICE session.
|
||||
*
|
||||
* @param task
|
||||
* The file transfer task that triggered this function call.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client object associated with this session.
|
||||
*/
|
||||
void guac_spice_client_file_transfer_handler(SpiceMainChannel* main_channel,
|
||||
SpiceFileTransferTask* task, guac_client* client);
|
||||
|
||||
#endif /* GUAC_SPICE_FILE_H */
|
||||
|
375
src/protocols/spice/client.c
Normal file
375
src/protocols/spice/client.c
Normal file
@ -0,0 +1,375 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "auth.h"
|
||||
#include "client.h"
|
||||
#include "channels/audio.h"
|
||||
#include "channels/clipboard.h"
|
||||
#include "channels/cursor.h"
|
||||
#include "channels/display.h"
|
||||
#include "channels/file.h"
|
||||
#include "input.h"
|
||||
#include "keyboard.h"
|
||||
#include "user.h"
|
||||
#include "spice.h"
|
||||
#include "spice-constants.h"
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
#include "common-ssh/sftp.h"
|
||||
#include "common-ssh/ssh.h"
|
||||
#include "common-ssh/user.h"
|
||||
#endif
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/recording.h>
|
||||
|
||||
#include <glib/gmain.h>
|
||||
#include <pthread.h>
|
||||
#include <spice-client-glib-2.0/spice-client.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Handle events for the main SPICE channel, taking the appropriate action
|
||||
* for known events, and logging warnings for unknowns and non-fatal events.
|
||||
*
|
||||
* @param channel
|
||||
* The channel for which to handle events.
|
||||
*
|
||||
* @param event
|
||||
* The event that is being handled.
|
||||
*
|
||||
* @param client
|
||||
* The guacamole_client associated with this event.
|
||||
*/
|
||||
static void guac_spice_client_main_channel_handler(SpiceChannel *channel,
|
||||
SpiceChannelEvent event, guac_client* client) {
|
||||
|
||||
guac_spice_client* spice_client = (guac_spice_client*) client->data;
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Received new main channel event: %u", event);
|
||||
|
||||
/* Handle the various possible SPICE events. */
|
||||
switch (event) {
|
||||
|
||||
/* Channel has been closed, so we abort the connection. */
|
||||
case SPICE_CHANNEL_CLOSED:
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||
"Disconnected from SPICE server.");
|
||||
break;
|
||||
|
||||
/* Channel has been opened - log it and do nothing else. */
|
||||
case SPICE_CHANNEL_OPENED:
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Channel opened.");
|
||||
break;
|
||||
|
||||
/* Error authenticating, log a warning and prompt user. */
|
||||
case SPICE_CHANNEL_ERROR_AUTH:
|
||||
guac_client_log(client, GUAC_LOG_WARNING,
|
||||
"Channel authentication failed.");
|
||||
|
||||
/* Trigger a credential prompt. */
|
||||
if (guac_spice_get_credentials(client)
|
||||
&& spice_session_connect(spice_client->spice_session))
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Session connection started.");
|
||||
|
||||
else
|
||||
guac_client_abort(client,
|
||||
GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED,
|
||||
"Failed to get credentials to connect to server.");
|
||||
|
||||
break;
|
||||
|
||||
/* TLS error, abort the connection with a warning. */
|
||||
case SPICE_CHANNEL_ERROR_TLS:
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||
"TLS failure connecting to SPICE server.");
|
||||
break;
|
||||
|
||||
/* I/O error, abort the connection with a warning. */
|
||||
case SPICE_CHANNEL_ERROR_IO:
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||
"IO error communicating with SPICE server.");
|
||||
break;
|
||||
|
||||
/* SPICE link error, abort the connection with a warning. */
|
||||
case SPICE_CHANNEL_ERROR_LINK:
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||
"Link error communicating with SPICE server.");
|
||||
break;
|
||||
|
||||
/* Connect error, abort the connection with a warning. */
|
||||
case SPICE_CHANNEL_ERROR_CONNECT:
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||
"Connection error communicating with SPICe server.");
|
||||
break;
|
||||
|
||||
/* Some other unknown event - log it and move on. */
|
||||
default:
|
||||
guac_client_log(client, GUAC_LOG_WARNING,
|
||||
"Unknown event received on channel.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int guac_client_init(guac_client* client) {
|
||||
|
||||
/* Set client args */
|
||||
client->args = GUAC_SPICE_CLIENT_ARGS;
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Initializing SPICE client.");
|
||||
|
||||
/* Alloc client data */
|
||||
guac_spice_client* spice_client = calloc(1, sizeof(guac_spice_client));
|
||||
client->data = spice_client;
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Initializing clipboard.");
|
||||
|
||||
/* Init clipboard */
|
||||
spice_client->clipboard =
|
||||
guac_common_clipboard_alloc(GUAC_SPICE_CLIPBOARD_MAX_LENGTH);
|
||||
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Setting up user handlers.");
|
||||
|
||||
/* Set handlers */
|
||||
client->join_handler = guac_spice_user_join_handler;
|
||||
client->leave_handler = guac_spice_user_leave_handler;
|
||||
client->free_handler = guac_spice_client_free_handler;
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Setting up mutex locks.");
|
||||
|
||||
/* Recursive attribute for locks */
|
||||
pthread_mutexattr_init(&(spice_client->attributes));
|
||||
pthread_mutexattr_settype(&(spice_client->attributes),
|
||||
PTHREAD_MUTEX_RECURSIVE);
|
||||
|
||||
/* Init required locks */
|
||||
pthread_rwlock_init(&(spice_client->lock), NULL);
|
||||
pthread_mutex_init(&(spice_client->message_lock), &(spice_client->attributes));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int guac_spice_client_free_handler(guac_client* client) {
|
||||
|
||||
guac_spice_client* spice_client = (guac_spice_client*) client->data;
|
||||
guac_spice_settings* settings = spice_client->settings;
|
||||
|
||||
/* Clean up SPICE client*/
|
||||
SpiceSession* spice_session = spice_client->spice_session;
|
||||
if (spice_session != NULL) {
|
||||
|
||||
/* Wait for client thread to finish */
|
||||
pthread_join(spice_client->client_thread, NULL);
|
||||
|
||||
/* Disconnect the session, destroying data */
|
||||
spice_session_disconnect(spice_session);
|
||||
|
||||
/* Free up the glib main loop. */
|
||||
g_main_loop_unref(spice_client->spice_mainloop);
|
||||
|
||||
}
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
/* Free SFTP filesystem, if loaded */
|
||||
if (spice_client->sftp_filesystem)
|
||||
guac_common_ssh_destroy_sftp_filesystem(spice_client->sftp_filesystem);
|
||||
|
||||
/* Free SFTP session */
|
||||
if (spice_client->sftp_session)
|
||||
guac_common_ssh_destroy_session(spice_client->sftp_session);
|
||||
|
||||
/* Free SFTP user */
|
||||
if (spice_client->sftp_user)
|
||||
guac_common_ssh_destroy_user(spice_client->sftp_user);
|
||||
|
||||
guac_common_ssh_uninit();
|
||||
#endif
|
||||
|
||||
/* Clean up recording, if in progress */
|
||||
if (spice_client->recording != NULL)
|
||||
guac_recording_free(spice_client->recording);
|
||||
|
||||
/* Free clipboard */
|
||||
if (spice_client->clipboard != NULL)
|
||||
guac_common_clipboard_free(spice_client->clipboard);
|
||||
|
||||
/* Free display */
|
||||
if (spice_client->display != NULL)
|
||||
guac_common_display_free(spice_client->display);
|
||||
|
||||
/* Free SPICE keyboard state */
|
||||
guac_spice_keyboard_free(spice_client->keyboard);
|
||||
spice_client->keyboard = NULL;
|
||||
|
||||
/* Free parsed settings */
|
||||
if (settings != NULL)
|
||||
guac_spice_settings_free(settings);
|
||||
|
||||
pthread_rwlock_destroy(&(spice_client->lock));
|
||||
pthread_mutex_destroy(&(spice_client->message_lock));
|
||||
|
||||
/* Free generic data struct */
|
||||
free(client->data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void guac_spice_client_channel_handler(SpiceSession *spice_session,
|
||||
SpiceChannel *channel, guac_client* client) {
|
||||
|
||||
guac_spice_client* spice_client = (guac_spice_client*) client->data;
|
||||
guac_spice_settings* settings = spice_client->settings;
|
||||
int id;
|
||||
|
||||
/* Get the channel ID. */
|
||||
g_object_get(channel, SPICE_PROPERTY_CHANNEL_ID, &id, NULL);
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "New channel created: %i", id);
|
||||
|
||||
/* Check if this is the main channel and register handlers. */
|
||||
if (SPICE_IS_MAIN_CHANNEL(channel)) {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Setting up main channel.");
|
||||
spice_client->main_channel = SPICE_MAIN_CHANNEL(channel);
|
||||
|
||||
/* Register the main channel event handler and return. */
|
||||
g_signal_connect(channel, SPICE_SIGNAL_CHANNEL_EVENT,
|
||||
G_CALLBACK(guac_spice_client_main_channel_handler), client);
|
||||
|
||||
/* Register clipboard handlers. */
|
||||
g_signal_connect(channel, SPICE_SIGNAL_MAIN_CLIPBOARD_SELECTION,
|
||||
G_CALLBACK(guac_spice_clipboard_selection_handler), client);
|
||||
g_signal_connect(channel, SPICE_SIGNAL_MAIN_CLIPBOARD_SELECTION_GRAB,
|
||||
G_CALLBACK(guac_spice_clipboard_selection_grab_handler), client);
|
||||
g_signal_connect(channel, SPICE_SIGNAL_MAIN_CLIPBOARD_SELECTION_RELEASE,
|
||||
G_CALLBACK(guac_spice_clipboard_selection_release_handler), client);
|
||||
g_signal_connect(channel, SPICE_SIGNAL_MAIN_CLIPBOARD_SELECTION_REQUEST,
|
||||
G_CALLBACK(guac_spice_clipboard_selection_request_handler), client);
|
||||
|
||||
/* Update the main display with our size. */
|
||||
if (client->__owner != NULL)
|
||||
spice_main_channel_update_display(spice_client->main_channel,
|
||||
GUAC_SPICE_DEFAULT_DISPLAY_ID,
|
||||
0,
|
||||
0,
|
||||
client->__owner->info.optimal_width,
|
||||
client->__owner->info.optimal_height, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if this is the display channel and register display handlers. */
|
||||
if (SPICE_IS_DISPLAY_CHANNEL(channel) && id == 0) {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Setting up display channel.");
|
||||
int width, height;
|
||||
SpiceDisplayPrimary primary;
|
||||
g_object_get(channel, "width", &width, "height", &height, NULL);
|
||||
spice_client->spice_display = SPICE_DISPLAY_CHANNEL(channel);
|
||||
spice_client->display = guac_common_display_alloc(client, width, height);
|
||||
|
||||
/* Register callbacks fr the various display signals. */
|
||||
g_signal_connect(channel, SPICE_SIGNAL_DISPLAY_INVALIDATE,
|
||||
G_CALLBACK(guac_spice_client_display_update), client);
|
||||
g_signal_connect(channel, SPICE_SIGNAL_DISPLAY_MARK,
|
||||
G_CALLBACK(guac_spice_client_display_mark), client);
|
||||
g_signal_connect(channel, SPICE_SIGNAL_DISPLAY_PRIMARY_CREATE,
|
||||
G_CALLBACK(guac_spice_client_display_primary_create), client);
|
||||
g_signal_connect(channel, SPICE_SIGNAL_DISPLAY_PRIMARY_DESTROY,
|
||||
G_CALLBACK(guac_spice_client_display_primary_destroy), client);
|
||||
g_signal_connect(channel, SPICE_SIGNAL_GL_DRAW,
|
||||
G_CALLBACK(guac_spice_client_display_gl_draw), client);
|
||||
g_signal_connect(channel, SPICE_SIGNAL_STREAMING_MODE,
|
||||
G_CALLBACK(guac_spice_client_streaming_handler), client);
|
||||
|
||||
/* Attempt to get the primary display, and set it up. */
|
||||
if (spice_display_channel_get_primary(channel, 0, &primary)) {
|
||||
guac_spice_client_display_primary_create(
|
||||
spice_client->spice_display, primary.format,
|
||||
primary.width, primary.height, primary.stride,
|
||||
primary.shmid, primary.data, client);
|
||||
guac_spice_client_display_mark(spice_client->spice_display,
|
||||
primary.marked, client);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Check for audio playback channel and set up the channel. */
|
||||
if (SPICE_IS_PLAYBACK_CHANNEL(channel) && settings->audio_enabled) {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Setting up audio playback channel.");
|
||||
spice_client->playback_channel = SPICE_PLAYBACK_CHANNEL(channel);
|
||||
g_signal_connect(channel, SPICE_SIGNAL_PLAYBACK_DATA,
|
||||
G_CALLBACK(guac_spice_client_audio_playback_data_handler), client);
|
||||
g_signal_connect(channel, SPICE_SIGNAL_PLAYBACK_GET_DELAY,
|
||||
G_CALLBACK(guac_spice_client_audio_playback_delay_handler), client);
|
||||
g_signal_connect(channel, SPICE_SIGNAL_PLAYBACK_START,
|
||||
G_CALLBACK(guac_spice_client_audio_playback_start_handler), client);
|
||||
g_signal_connect(channel, SPICE_SIGNAL_PLAYBACK_STOP,
|
||||
G_CALLBACK(guac_spice_client_audio_playback_stop_handler), client);
|
||||
}
|
||||
|
||||
/* Check for audio recording channel and set up the channel. */
|
||||
if (SPICE_IS_RECORD_CHANNEL(channel) && settings->audio_enabled) {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Setting up audio record channel.");
|
||||
spice_client->record_channel = SPICE_RECORD_CHANNEL(channel);
|
||||
g_signal_connect(channel, SPICE_SIGNAL_RECORD_START,
|
||||
G_CALLBACK(guac_spice_client_audio_record_start_handler), client);
|
||||
g_signal_connect(channel, SPICE_SIGNAL_RECORD_STOP,
|
||||
G_CALLBACK(guac_spice_client_audio_record_stop_handler), client);
|
||||
}
|
||||
|
||||
/* Check for cursor channel and set it up. */
|
||||
if (SPICE_IS_CURSOR_CHANNEL(channel)) {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Setting up cursor channel.");
|
||||
spice_client->cursor_channel = SPICE_CURSOR_CHANNEL(channel);
|
||||
g_signal_connect(channel, SPICE_SIGNAL_CURSOR_HIDE,
|
||||
G_CALLBACK(guac_spice_cursor_hide), client);
|
||||
g_signal_connect(channel, SPICE_SIGNAL_CURSOR_MOVE,
|
||||
G_CALLBACK(guac_spice_cursor_move), client);
|
||||
g_signal_connect(channel, SPICE_SIGNAL_CURSOR_RESET,
|
||||
G_CALLBACK(guac_spice_cursor_reset), client);
|
||||
g_signal_connect(channel, SPICE_SIGNAL_CURSOR_SET,
|
||||
G_CALLBACK(guac_spice_cursor_set), client);
|
||||
}
|
||||
|
||||
/* Check if this is an inputs channel and set it up. */
|
||||
if (SPICE_IS_INPUTS_CHANNEL(channel)) {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Setting up inputs channel.");
|
||||
spice_client->inputs_channel = SPICE_INPUTS_CHANNEL(channel);
|
||||
|
||||
/* Register callback that sets keyboard modifiers */
|
||||
g_signal_connect(channel, SPICE_SIGNAL_INPUTS_MODIFIERS,
|
||||
G_CALLBACK(guac_spice_keyboard_set_indicators), client);
|
||||
}
|
||||
|
||||
/* File transfer channel */
|
||||
if (SPICE_IS_WEBDAV_CHANNEL(channel)) {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Setting up webdav channel.");
|
||||
if (settings->file_transfer
|
||||
&& settings->file_directory != NULL
|
||||
&& strcmp(settings->file_directory, "") != 0) {
|
||||
}
|
||||
}
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Calling spice_channel_connect for channel %d.", id);
|
||||
if (!spice_channel_connect(channel))
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||
"Unable to connect the channel.");
|
||||
|
||||
}
|
73
src/protocols/spice/client.h
Normal file
73
src/protocols/spice/client.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GUAC_SPICE_CLIENT_H
|
||||
#define GUAC_SPICE_CLIENT_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
|
||||
#include <spice-client-glib-2.0/spice-client.h>
|
||||
|
||||
/**
|
||||
* The maximum duration of a frame in milliseconds.
|
||||
*/
|
||||
#define GUAC_SPICE_FRAME_DURATION 40
|
||||
|
||||
/**
|
||||
* The amount of time to allow per message read within a frame, in
|
||||
* milliseconds. If the server is silent for at least this amount of time, the
|
||||
* frame will be considered finished.
|
||||
*/
|
||||
#define GUAC_SPICE_FRAME_TIMEOUT 0
|
||||
|
||||
/**
|
||||
* The amount of time to wait for a new message from the SPICE server when
|
||||
* beginning a new frame. This value must be kept reasonably small such that
|
||||
* a slow SPICE server will not prevent external events from being handled (such
|
||||
* as the stop signal from guac_client_stop()), but large enough that the
|
||||
* message handling loop does not eat up CPU spinning.
|
||||
*/
|
||||
#define GUAC_SPICE_FRAME_START_TIMEOUT 1000000
|
||||
|
||||
/**
|
||||
* The number of milliseconds to wait between connection attempts.
|
||||
*/
|
||||
#define GUAC_SPICE_CONNECT_INTERVAL 1000
|
||||
|
||||
/**
|
||||
* The maximum number of bytes to allow within the clipboard.
|
||||
*/
|
||||
#define GUAC_SPICE_CLIPBOARD_MAX_LENGTH 262144
|
||||
|
||||
/**
|
||||
* Handler which frees all data associated with the guac_client.
|
||||
*/
|
||||
guac_client_free_handler guac_spice_client_free_handler;
|
||||
|
||||
/**
|
||||
* Handler for new channel events.
|
||||
*/
|
||||
void guac_spice_client_channel_handler(SpiceSession *spice_session,
|
||||
SpiceChannel *channel, guac_client* client);
|
||||
|
||||
#endif /* GUAC_SPICE_CLIENT_H */
|
||||
|
176
src/protocols/spice/decompose.c
Normal file
176
src/protocols/spice/decompose.c
Normal file
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "keyboard.h"
|
||||
|
||||
/**
|
||||
* The X11 keysym for the dead key which types a grave (`).
|
||||
*/
|
||||
#define DEAD_GRAVE 0xFE50
|
||||
|
||||
/**
|
||||
* The X11 keysym for the dead key which types an acute (´). Note that this is
|
||||
* NOT equivalent to an apostrophe or single quote.
|
||||
*/
|
||||
#define DEAD_ACUTE 0xFE51
|
||||
|
||||
/**
|
||||
* The X11 keysym for the dead key which types a circumflex/caret (^).
|
||||
*/
|
||||
#define DEAD_CIRCUMFLEX 0xFE52
|
||||
|
||||
/**
|
||||
* The X11 keysym for the dead key which types a tilde (~).
|
||||
*/
|
||||
#define DEAD_TILDE 0xFE53
|
||||
|
||||
/**
|
||||
* The X11 keysym for the dead key which types a dieresis/umlaut (¨).
|
||||
*/
|
||||
#define DEAD_DIERESIS 0xFE57
|
||||
|
||||
/**
|
||||
* The X11 keysym for the dead key which types an abovering (˚). Note that this
|
||||
* is NOT equivalent to the degree symbol.
|
||||
*/
|
||||
#define DEAD_ABOVERING 0xFE58
|
||||
|
||||
/**
|
||||
* The decomposed form of a key that can be typed using two keypresses: a dead
|
||||
* key followed by a base key. For example, on a keyboard which lacks a single
|
||||
* dedicated key for doing the same, "ó" would be typed using the dead acute
|
||||
* key followed by the "o" key. The dead key and base key are pressed and
|
||||
* released in sequence; they are not held down.
|
||||
*/
|
||||
typedef struct guac_spice_decomposed_key {
|
||||
|
||||
/**
|
||||
* The keysym of the dead key which must first be pressed and released to
|
||||
* begin typing the desired character. The dead key defines the diacritic
|
||||
* which will be applied to the character typed by the base key.
|
||||
*/
|
||||
int dead_keysym;
|
||||
|
||||
/**
|
||||
* The keysym of the base key which must be pressed and released to finish
|
||||
* typing the desired character. The base key defines the normal form of
|
||||
* the character (the form which lacks any diacritic) to which the
|
||||
* diacritic defined by the previously-pressed dead key will be applied.
|
||||
*/
|
||||
int base_keysym;
|
||||
|
||||
} guac_spice_decomposed_key;
|
||||
|
||||
/**
|
||||
* A lookup table of all known decomposed forms of various keysyms. Keysyms map
|
||||
* directly to entries within this table. A keysym which has no entry within
|
||||
* this table does not have a defined decomposed form (or at least does not
|
||||
* have a decomposed form relevant to SPICE).
|
||||
*/
|
||||
guac_spice_decomposed_key guac_spice_decomposed_keys[256] = {
|
||||
|
||||
/* ^ */ [0x005E] = { DEAD_CIRCUMFLEX, ' ' },
|
||||
/* ` */ [0x0060] = { DEAD_GRAVE, ' ' },
|
||||
/* ~ */ [0x007E] = { DEAD_TILDE, ' ' },
|
||||
/* ¨ */ [0x00A8] = { DEAD_DIERESIS, ' ' },
|
||||
/* ´ */ [0x00B4] = { DEAD_ACUTE, ' ' },
|
||||
/* À */ [0x00C0] = { DEAD_GRAVE, 'A' },
|
||||
/* Á */ [0x00C1] = { DEAD_ACUTE, 'A' },
|
||||
/* Â */ [0x00C2] = { DEAD_CIRCUMFLEX, 'A' },
|
||||
/* Ã */ [0x00C3] = { DEAD_TILDE, 'A' },
|
||||
/* Ä */ [0x00C4] = { DEAD_DIERESIS, 'A' },
|
||||
/* Å */ [0x00C5] = { DEAD_ABOVERING, 'A' },
|
||||
/* È */ [0x00C8] = { DEAD_GRAVE, 'E' },
|
||||
/* É */ [0x00C9] = { DEAD_ACUTE, 'E' },
|
||||
/* Ê */ [0x00CA] = { DEAD_CIRCUMFLEX, 'E' },
|
||||
/* Ë */ [0x00CB] = { DEAD_DIERESIS, 'E' },
|
||||
/* Ì */ [0x00CC] = { DEAD_GRAVE, 'I' },
|
||||
/* Í */ [0x00CD] = { DEAD_ACUTE, 'I' },
|
||||
/* Î */ [0x00CE] = { DEAD_CIRCUMFLEX, 'I' },
|
||||
/* Ï */ [0x00CF] = { DEAD_DIERESIS, 'I' },
|
||||
/* Ñ */ [0x00D1] = { DEAD_TILDE, 'N' },
|
||||
/* Ò */ [0x00D2] = { DEAD_GRAVE, 'O' },
|
||||
/* Ó */ [0x00D3] = { DEAD_ACUTE, 'O' },
|
||||
/* Ô */ [0x00D4] = { DEAD_CIRCUMFLEX, 'O' },
|
||||
/* Õ */ [0x00D5] = { DEAD_TILDE, 'O' },
|
||||
/* Ö */ [0x00D6] = { DEAD_DIERESIS, 'O' },
|
||||
/* Ù */ [0x00D9] = { DEAD_GRAVE, 'U' },
|
||||
/* Ú */ [0x00DA] = { DEAD_ACUTE, 'U' },
|
||||
/* Û */ [0x00DB] = { DEAD_CIRCUMFLEX, 'U' },
|
||||
/* Ü */ [0x00DC] = { DEAD_DIERESIS, 'U' },
|
||||
/* Ý */ [0x00DD] = { DEAD_ACUTE, 'Y' },
|
||||
/* à */ [0x00E0] = { DEAD_GRAVE, 'a' },
|
||||
/* á */ [0x00E1] = { DEAD_ACUTE, 'a' },
|
||||
/* â */ [0x00E2] = { DEAD_CIRCUMFLEX, 'a' },
|
||||
/* ã */ [0x00E3] = { DEAD_TILDE, 'a' },
|
||||
/* ä */ [0x00E4] = { DEAD_DIERESIS, 'a' },
|
||||
/* å */ [0x00E5] = { DEAD_ABOVERING, 'a' },
|
||||
/* è */ [0x00E8] = { DEAD_GRAVE, 'e' },
|
||||
/* é */ [0x00E9] = { DEAD_ACUTE, 'e' },
|
||||
/* ê */ [0x00EA] = { DEAD_CIRCUMFLEX, 'e' },
|
||||
/* ë */ [0x00EB] = { DEAD_DIERESIS, 'e' },
|
||||
/* ì */ [0x00EC] = { DEAD_GRAVE, 'i' },
|
||||
/* í */ [0x00ED] = { DEAD_ACUTE, 'i' },
|
||||
/* î */ [0x00EE] = { DEAD_CIRCUMFLEX, 'i' },
|
||||
/* ï */ [0x00EF] = { DEAD_DIERESIS, 'i' },
|
||||
/* ñ */ [0x00F1] = { DEAD_TILDE, 'n' },
|
||||
/* ò */ [0x00F2] = { DEAD_GRAVE, 'o' },
|
||||
/* ó */ [0x00F3] = { DEAD_ACUTE, 'o' },
|
||||
/* ô */ [0x00F4] = { DEAD_CIRCUMFLEX, 'o' },
|
||||
/* õ */ [0x00F5] = { DEAD_TILDE, 'o' },
|
||||
/* ö */ [0x00F6] = { DEAD_DIERESIS, 'o' },
|
||||
/* ù */ [0x00F9] = { DEAD_GRAVE, 'u' },
|
||||
/* ú */ [0x00FA] = { DEAD_ACUTE, 'u' },
|
||||
/* û */ [0x00FB] = { DEAD_CIRCUMFLEX, 'u' },
|
||||
/* ü */ [0x00FC] = { DEAD_DIERESIS, 'u' },
|
||||
/* ý */ [0x00FD] = { DEAD_ACUTE, 'y' },
|
||||
/* ÿ */ [0x00FF] = { DEAD_DIERESIS, 'y' }
|
||||
|
||||
};
|
||||
|
||||
int guac_spice_decompose_keysym(guac_spice_keyboard* keyboard, int keysym) {
|
||||
|
||||
/* Verify keysym is within range of lookup table */
|
||||
if (keysym < 0x00 || keysym > 0xFF)
|
||||
return 1;
|
||||
|
||||
/* Verify keysym is actually defined within lookup table */
|
||||
guac_spice_decomposed_key* key = &guac_spice_decomposed_keys[keysym];
|
||||
if (!key->dead_keysym)
|
||||
return 1;
|
||||
|
||||
/* Cannot type using decomposed keys if those keys are not defined within
|
||||
* the current layout */
|
||||
if (!guac_spice_keyboard_is_defined(keyboard, key->dead_keysym)
|
||||
|| !guac_spice_keyboard_is_defined(keyboard, key->base_keysym))
|
||||
return 1;
|
||||
|
||||
/* Press dead key */
|
||||
guac_spice_keyboard_update_keysym(keyboard, key->dead_keysym, 1, GUAC_SPICE_KEY_SOURCE_SYNTHETIC);
|
||||
guac_spice_keyboard_update_keysym(keyboard, key->dead_keysym, 0, GUAC_SPICE_KEY_SOURCE_SYNTHETIC);
|
||||
|
||||
/* Press base key */
|
||||
guac_spice_keyboard_update_keysym(keyboard, key->base_keysym, 1, GUAC_SPICE_KEY_SOURCE_SYNTHETIC);
|
||||
guac_spice_keyboard_update_keysym(keyboard, key->base_keysym, 0, GUAC_SPICE_KEY_SOURCE_SYNTHETIC);
|
||||
|
||||
/* Decomposed key successfully typed */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
50
src/protocols/spice/decompose.h
Normal file
50
src/protocols/spice/decompose.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_SPICE_DECOMPOSE_H
|
||||
#define GUAC_SPICE_DECOMPOSE_H
|
||||
|
||||
#include "config.h"
|
||||
#include "keyboard.h"
|
||||
|
||||
/**
|
||||
* Attempts to type the given keysym by decomposing the associated character
|
||||
* into the dead key and base key pair which would be used to type that
|
||||
* character on a keyboard which lacks the necessary dedicated key. The key
|
||||
* events for the dead key and base key are sent only if the keyboard layout of
|
||||
* the given keyboard defines those keys.
|
||||
*
|
||||
* For example, the keysym for "ò" (0x00F2) would decompose into a dead grave
|
||||
* (`) and the base key "o". May it rest in peace.
|
||||
*
|
||||
* @param keyboard
|
||||
* The guac_spice_keyboard associated with the current SPICE session.
|
||||
*
|
||||
* @param keysym
|
||||
* The keysym being pressed.
|
||||
*
|
||||
* @return
|
||||
* Zero if the keysym was successfully decomposed and sent to the SPICE
|
||||
* server as a pair of key events (the dead key and base key), non-zero
|
||||
* otherwise.
|
||||
*/
|
||||
int guac_spice_decompose_keysym(guac_spice_keyboard* keyboard, int keysym);
|
||||
|
||||
#endif
|
||||
|
154
src/protocols/spice/input.c
Normal file
154
src/protocols/spice/input.c
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "common/cursor.h"
|
||||
#include "common/display.h"
|
||||
#include "spice.h"
|
||||
#include "spice-constants.h"
|
||||
|
||||
#include <guacamole/recording.h>
|
||||
#include <guacamole/user.h>
|
||||
#include <spice-client-glib-2.0/spice-client.h>
|
||||
|
||||
int guac_spice_user_mouse_handler(guac_user* user, int x, int y, int mask) {
|
||||
|
||||
guac_client* client = user->client;
|
||||
guac_spice_client* spice_client = (guac_spice_client*) client->data;
|
||||
|
||||
/* Store the old button mask. */
|
||||
int curr_button_mask = spice_client->display->cursor->button_mask;
|
||||
|
||||
guac_user_log(user, GUAC_LOG_TRACE, "Handling mouse event: %d, %d, 0x%08x", x, y, mask);
|
||||
|
||||
/* Update current mouse location/state */
|
||||
guac_common_cursor_update(spice_client->display->cursor, user, x, y, mask);
|
||||
|
||||
/* Report mouse position and button state within recording. */
|
||||
if (spice_client->recording != NULL)
|
||||
guac_recording_report_mouse(spice_client->recording, x, y, mask);
|
||||
|
||||
/* Send SPICE event only if finished connecting */
|
||||
if (spice_client->inputs_channel != NULL) {
|
||||
spice_inputs_channel_position(spice_client->inputs_channel, x, y, GUAC_SPICE_DEFAULT_DISPLAY_ID, mask);
|
||||
|
||||
/* Button state has changed, so we need to evaluate which buttons changed. */
|
||||
if (curr_button_mask != mask) {
|
||||
|
||||
/* Left click. */
|
||||
if (curr_button_mask ^ GUAC_CLIENT_MOUSE_LEFT && mask & GUAC_CLIENT_MOUSE_LEFT) {
|
||||
guac_user_log(user, GUAC_LOG_TRACE, "Left click!");
|
||||
spice_inputs_channel_button_press(spice_client->inputs_channel, SPICE_MOUSE_BUTTON_LEFT, mask);
|
||||
}
|
||||
|
||||
/* Left release. */
|
||||
if (curr_button_mask & GUAC_CLIENT_MOUSE_LEFT && mask ^ GUAC_CLIENT_MOUSE_LEFT) {
|
||||
guac_user_log(user, GUAC_LOG_TRACE, "Left release!");
|
||||
spice_inputs_channel_button_release(spice_client->inputs_channel, SPICE_MOUSE_BUTTON_LEFT, mask);
|
||||
}
|
||||
|
||||
/* Middle click. */
|
||||
if (curr_button_mask ^ GUAC_CLIENT_MOUSE_MIDDLE && mask & GUAC_CLIENT_MOUSE_MIDDLE) {
|
||||
guac_user_log(user, GUAC_LOG_TRACE, "Middle click!");
|
||||
spice_inputs_channel_button_press(spice_client->inputs_channel, SPICE_MOUSE_BUTTON_MIDDLE, mask);
|
||||
}
|
||||
|
||||
/* Middle release. */
|
||||
if (curr_button_mask & GUAC_CLIENT_MOUSE_MIDDLE && mask ^ GUAC_CLIENT_MOUSE_MIDDLE) {
|
||||
guac_user_log(user, GUAC_LOG_TRACE, "Middle release!");
|
||||
spice_inputs_channel_button_release(spice_client->inputs_channel, SPICE_MOUSE_BUTTON_MIDDLE, mask);
|
||||
}
|
||||
|
||||
/* Right click. */
|
||||
if (curr_button_mask ^ GUAC_CLIENT_MOUSE_RIGHT && mask & GUAC_CLIENT_MOUSE_RIGHT) {
|
||||
guac_user_log(user, GUAC_LOG_TRACE, "Right click!");
|
||||
spice_inputs_channel_button_press(spice_client->inputs_channel, SPICE_MOUSE_BUTTON_RIGHT, mask);
|
||||
}
|
||||
|
||||
/* Right release. */
|
||||
if (curr_button_mask & GUAC_CLIENT_MOUSE_RIGHT && mask ^ GUAC_CLIENT_MOUSE_RIGHT) {
|
||||
guac_user_log(user, GUAC_LOG_TRACE, "Right release!");
|
||||
spice_inputs_channel_button_release(spice_client->inputs_channel, SPICE_MOUSE_BUTTON_RIGHT, mask);
|
||||
}
|
||||
|
||||
/* Scroll up. */
|
||||
if (curr_button_mask ^ GUAC_CLIENT_MOUSE_SCROLL_UP && mask & GUAC_CLIENT_MOUSE_SCROLL_UP) {
|
||||
guac_user_log(user, GUAC_LOG_TRACE, "Scroll up!");
|
||||
spice_inputs_channel_button_press(spice_client->inputs_channel, SPICE_MOUSE_BUTTON_UP, mask);
|
||||
}
|
||||
|
||||
/* Scroll up stop. */
|
||||
if (curr_button_mask & GUAC_CLIENT_MOUSE_SCROLL_UP && mask ^ GUAC_CLIENT_MOUSE_SCROLL_UP) {
|
||||
guac_user_log(user, GUAC_LOG_TRACE, "Scroll up stop!");
|
||||
spice_inputs_channel_button_release(spice_client->inputs_channel, SPICE_MOUSE_BUTTON_UP, mask);
|
||||
}
|
||||
|
||||
/* Scroll down. */
|
||||
if (curr_button_mask ^ GUAC_CLIENT_MOUSE_SCROLL_DOWN && mask & GUAC_CLIENT_MOUSE_SCROLL_DOWN) {
|
||||
guac_user_log(user, GUAC_LOG_TRACE, "Scroll down!");
|
||||
spice_inputs_channel_button_press(spice_client->inputs_channel, SPICE_MOUSE_BUTTON_DOWN, mask);
|
||||
}
|
||||
|
||||
/* Scroll down stop. */
|
||||
if (curr_button_mask & GUAC_CLIENT_MOUSE_SCROLL_DOWN && mask ^ GUAC_CLIENT_MOUSE_SCROLL_DOWN) {
|
||||
guac_user_log(user, GUAC_LOG_TRACE, "Scroll down stop!");
|
||||
spice_inputs_channel_button_release(spice_client->inputs_channel, SPICE_MOUSE_BUTTON_DOWN, mask);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int guac_spice_user_key_handler(guac_user* user, int keysym, int pressed) {
|
||||
|
||||
guac_spice_client* spice_client = (guac_spice_client*) user->client->data;
|
||||
int retval = 0;
|
||||
|
||||
pthread_rwlock_rdlock(&(spice_client->lock));
|
||||
|
||||
guac_user_log(user, GUAC_LOG_TRACE, "Handling keypress: 0x%08x", keysym);
|
||||
|
||||
/* Report key state within recording */
|
||||
if (spice_client->recording != NULL)
|
||||
guac_recording_report_key(spice_client->recording,
|
||||
keysym, pressed);
|
||||
|
||||
/* Skip if keyboard not yet ready */
|
||||
if (spice_client->inputs_channel == NULL || spice_client->keyboard == NULL)
|
||||
goto complete;
|
||||
|
||||
/* Update keysym state */
|
||||
retval = guac_spice_keyboard_update_keysym(spice_client->keyboard,
|
||||
keysym, pressed, GUAC_SPICE_KEY_SOURCE_CLIENT);
|
||||
|
||||
complete:
|
||||
pthread_rwlock_unlock(&(spice_client->lock));
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void guac_spice_mouse_mode_update(SpiceChannel* channel, guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Updating mouse mode, not implemented.");
|
||||
|
||||
}
|
50
src/protocols/spice/input.h
Normal file
50
src/protocols/spice/input.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GUAC_SPICE_INPUT_H
|
||||
#define GUAC_SPICE_INPUT_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* Handler for Guacamole user mouse events.
|
||||
*/
|
||||
guac_user_mouse_handler guac_spice_user_mouse_handler;
|
||||
|
||||
/**
|
||||
* Handler for Guacamole user key events.
|
||||
*/
|
||||
guac_user_key_handler guac_spice_user_key_handler;
|
||||
|
||||
/**
|
||||
* A callback that is invoked when the SPICE server updates the mouse mode.
|
||||
*
|
||||
* @param channel
|
||||
* The channel on which the update occurred.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client instance associated with this session.
|
||||
*/
|
||||
void guac_spice_mouse_mode_update(SpiceChannel* channel, guac_client* client);
|
||||
|
||||
#endif /* GUAC_SPICE_INPUT_H */
|
||||
|
652
src/protocols/spice/keyboard.c
Normal file
652
src/protocols/spice/keyboard.c
Normal file
@ -0,0 +1,652 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "decompose.h"
|
||||
#include "keyboard.h"
|
||||
#include "keymap.h"
|
||||
#include "spice.h"
|
||||
#include "spice-constants.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* Translates the given keysym into the corresponding lock flag, as would be
|
||||
* required by the SPICE synchronize event. If the given keysym does not
|
||||
* represent a lock key, zero is returned.
|
||||
*
|
||||
* @param keysym
|
||||
* The keysym to translate into a SPICE lock flag.
|
||||
*
|
||||
* @return
|
||||
* The SPICE lock flag which corresponds to the given keysym, or zero if the
|
||||
* given keysym does not represent a lock key.
|
||||
*/
|
||||
static int guac_spice_keyboard_lock_flag(int keysym) {
|
||||
|
||||
/* Translate keysym into corresponding lock flag */
|
||||
switch (keysym) {
|
||||
|
||||
/* Scroll lock */
|
||||
case GUAC_SPICE_KEYSYM_SCROLL_LOCK:
|
||||
return SPICE_INPUTS_SCROLL_LOCK;
|
||||
|
||||
/* Num lock */
|
||||
case GUAC_SPICE_KEYSYM_NUM_LOCK:
|
||||
return SPICE_INPUTS_NUM_LOCK;
|
||||
|
||||
/* Caps lock */
|
||||
case GUAC_SPICE_KEYSYM_CAPS_LOCK:
|
||||
return SPICE_INPUTS_CAPS_LOCK;
|
||||
|
||||
}
|
||||
|
||||
/* Not a lock key */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Immediately sends an SPICE key event having the given scancode and flags.
|
||||
*
|
||||
* @param spice_client
|
||||
* The SPICE client instance associated with the SPICE session along which the
|
||||
* key event should be sent.
|
||||
*
|
||||
* @param scancode
|
||||
* The scancode of the key to press or release via the SPICE key event.
|
||||
*
|
||||
* @param flags
|
||||
* Any SPICE-specific flags required for the provided scancode to have the
|
||||
* intended meaning, such as KBD_FLAGS_EXTENDED. The possible flags and
|
||||
* their meanings are dictated by SPICE. KBD_FLAGS_DOWN and KBD_FLAGS_UP
|
||||
* need not be specified here - they will automatically be added depending
|
||||
* on the value specified for the pressed parameter.
|
||||
*
|
||||
* @param pressed
|
||||
* Non-zero if the key is being pressed, zero if the key is being released.
|
||||
*/
|
||||
static void guac_spice_send_key_event(guac_spice_client* spice_client,
|
||||
int scancode, int flags, int pressed) {
|
||||
|
||||
/* Send actual key press or release */
|
||||
pthread_mutex_lock(&(spice_client->message_lock));
|
||||
if (pressed)
|
||||
spice_inputs_channel_key_press(spice_client->inputs_channel, scancode);
|
||||
else
|
||||
spice_inputs_channel_key_release(spice_client->inputs_channel, scancode);
|
||||
pthread_mutex_unlock(&(spice_client->message_lock));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Immediately sends an SPICE synchonize event having the given flags. An SPICE
|
||||
* synchronize event sets the state of remote lock keys absolutely, where a
|
||||
* lock key will be active only if its corresponding flag is set in the event.
|
||||
*
|
||||
* @param spice_client
|
||||
* The SPICE client instance associated with the SPICE session along which the
|
||||
* synchronize event should be sent.
|
||||
*
|
||||
* @param modifiers
|
||||
* Bitwise OR of the flags representing the lock keys which should be set,
|
||||
* if any, as dictated by the SPICE protocol. If no flags are set, then no
|
||||
* lock keys will be active.
|
||||
*/
|
||||
static void guac_spice_send_synchronize_event(guac_spice_client* spice_client,
|
||||
unsigned int modifiers) {
|
||||
|
||||
/* Skip if inputs channel is not connected */
|
||||
if (spice_client->inputs_channel == NULL)
|
||||
return;
|
||||
|
||||
/* Synchronize lock key states */
|
||||
pthread_mutex_lock(&(spice_client->message_lock));
|
||||
spice_inputs_channel_set_key_locks(spice_client->inputs_channel, modifiers);
|
||||
pthread_mutex_unlock(&(spice_client->message_lock));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a keyboard instance and X11 keysym, returns a pointer to the
|
||||
* keys_by_keysym entry that represents the key having that keysym within the
|
||||
* keyboard, regardless of whether the key is currently defined. If no such key
|
||||
* can exist (the keysym cannot be mapped or is out of range), NULL is
|
||||
* returned.
|
||||
*
|
||||
* @param keyboard
|
||||
* The guac_spice_keyboard associated with the current SPICE session.
|
||||
*
|
||||
* @param keysym
|
||||
* The keysym of the key to lookup within the given keyboard.
|
||||
*
|
||||
* @return
|
||||
* A pointer to the keys_by_keysym entry which represents or can represent
|
||||
* the key having the given keysym, or NULL if no such keysym can be
|
||||
* defined within a guac_spice_keyboard structure.
|
||||
*/
|
||||
static guac_spice_key** guac_spice_keyboard_map_key(guac_spice_keyboard* keyboard,
|
||||
int keysym) {
|
||||
|
||||
int index;
|
||||
|
||||
/* Map keysyms between 0x0000 and 0xFFFF directly */
|
||||
if (keysym >= 0x0000 && keysym <= 0xFFFF)
|
||||
index = keysym;
|
||||
|
||||
/* Map all Unicode keysyms from U+0000 to U+FFFF */
|
||||
else if (keysym >= 0x1000000 && keysym <= 0x100FFFF)
|
||||
index = 0x10000 + (keysym & 0xFFFF);
|
||||
|
||||
/* All other keysyms are unmapped */
|
||||
else
|
||||
return NULL;
|
||||
|
||||
/* Corresponding key mapping (defined or not) has been located */
|
||||
return &(keyboard->keys_by_keysym[index]);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bits that are set within the given integer (the number
|
||||
* of 1s in the binary expansion of the given integer).
|
||||
*
|
||||
* @param value
|
||||
* The integer to read.
|
||||
*
|
||||
* @return
|
||||
* The number of bits that are set within the given integer.
|
||||
*/
|
||||
static int guac_spice_count_bits(unsigned int value) {
|
||||
|
||||
int bits = 0;
|
||||
|
||||
while (value) {
|
||||
bits += value & 1;
|
||||
value >>= 1;
|
||||
}
|
||||
|
||||
return bits;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an estimated cost for sending the necessary SPICE events to type the
|
||||
* key described by the given guac_spice_keysym_desc, given the current lock and
|
||||
* modifier state of the keyboard. A higher cost value indicates that a greater
|
||||
* number of events are expected to be required.
|
||||
*
|
||||
* Lower-cost approaches should be preferred when multiple alternatives exist
|
||||
* for typing a particular key, as the lower cost implies fewer additional key
|
||||
* events required to produce the expected behavior. For example, if Caps Lock
|
||||
* is enabled, typing an uppercase "A" by pressing the "A" key has a lower cost
|
||||
* than disabling Caps Lock and pressing Shift+A.
|
||||
*
|
||||
* @param keyboard
|
||||
* The guac_spice_keyboard associated with the current SPICE session.
|
||||
*
|
||||
* @param def
|
||||
* The guac_spice_keysym_desc that describes the key being pressed, as well
|
||||
* as any requirements that must be satisfied for the key to be interpreted
|
||||
* as expected.
|
||||
*
|
||||
* @return
|
||||
* An arbitrary integer value which indicates the overall estimated
|
||||
* complexity of typing the given key.
|
||||
*/
|
||||
static int guac_spice_keyboard_get_cost(guac_spice_keyboard* keyboard,
|
||||
const guac_spice_keysym_desc* def) {
|
||||
|
||||
unsigned int modifiers = guac_spice_keyboard_get_modifier_flags(keyboard);
|
||||
|
||||
/* Each change to any key requires one event, by definition */
|
||||
int cost = 1;
|
||||
|
||||
/* Each change to a lock requires roughly two key events */
|
||||
unsigned int update_locks = (def->set_modifiers & ~keyboard->modifiers) | (def->clear_modifiers & keyboard->modifiers);
|
||||
cost += guac_spice_count_bits(update_locks) * 2;
|
||||
|
||||
/* Each change to a modifier requires one key event */
|
||||
unsigned int update_modifiers = (def->clear_modifiers & modifiers) | (def->set_modifiers & ~modifiers);
|
||||
cost += guac_spice_count_bits(update_modifiers);
|
||||
|
||||
return cost;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pointer to the guac_spice_key structure representing the
|
||||
* definition(s) and state of the key having the given keysym. If no such key
|
||||
* is defined within the keyboard layout of the SPICE server, NULL is returned.
|
||||
*
|
||||
* @param keyboard
|
||||
* The guac_spice_keyboard associated with the current SPICE session.
|
||||
*
|
||||
* @param keysym
|
||||
* The keysym of the key to lookup within the given keyboard.
|
||||
*
|
||||
* @return
|
||||
* A pointer to the guac_spice_key structure representing the definition(s)
|
||||
* and state of the key having the given keysym, or NULL if no such key is
|
||||
* defined within the keyboard layout of the SPICE server.
|
||||
*/
|
||||
static guac_spice_key* guac_spice_keyboard_get_key(guac_spice_keyboard* keyboard,
|
||||
int keysym) {
|
||||
|
||||
/* Verify that the key is actually defined */
|
||||
guac_spice_key** key_by_keysym = guac_spice_keyboard_map_key(keyboard, keysym);
|
||||
if (key_by_keysym == NULL)
|
||||
return NULL;
|
||||
|
||||
return *key_by_keysym;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a key which may have multiple possible definitions, returns the
|
||||
* definition that currently has the lowest cost, taking into account the
|
||||
* current keyboard lock and modifier states.
|
||||
*
|
||||
* @param keyboard
|
||||
* The guac_spice_keyboard associated with the current SPICE session.
|
||||
*
|
||||
* @param key
|
||||
* The key whose lowest-cost possible definition should be retrieved.
|
||||
*
|
||||
* @return
|
||||
* A pointer to the guac_spice_keysym_desc which defines the current
|
||||
* lowest-cost method of typing the given key.
|
||||
*/
|
||||
static const guac_spice_keysym_desc* guac_spice_keyboard_get_definition(guac_spice_keyboard* keyboard,
|
||||
guac_spice_key* key) {
|
||||
|
||||
/* Consistently map the same entry so long as the key is held */
|
||||
if (key->pressed != NULL)
|
||||
return key->pressed;
|
||||
|
||||
/* Calculate cost of first definition of key (there must always be at least
|
||||
* one definition) */
|
||||
const guac_spice_keysym_desc* best_def = key->definitions[0];
|
||||
int best_cost = guac_spice_keyboard_get_cost(keyboard, best_def);
|
||||
|
||||
/* If further definitions exist, choose the definition with the lowest
|
||||
* overall cost */
|
||||
for (int i = 1; i < key->num_definitions; i++) {
|
||||
|
||||
const guac_spice_keysym_desc* def = key->definitions[i];
|
||||
int cost = guac_spice_keyboard_get_cost(keyboard, def);
|
||||
|
||||
if (cost < best_cost) {
|
||||
best_def = def;
|
||||
best_cost = cost;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return best_def;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the keysym/scancode mapping described by the given guac_spice_keysym_desc
|
||||
* to the internal mapping of the keyboard. If insufficient space remains for
|
||||
* additional keysyms, or the given keysym has already reached the maximum
|
||||
* number of possible definitions, the mapping is ignored and the failure is
|
||||
* logged.
|
||||
*
|
||||
* @param keyboard
|
||||
* The guac_spice_keyboard associated with the current SPICE session.
|
||||
*
|
||||
* @param mapping
|
||||
* The keysym/scancode mapping that should be added to the given keyboard.
|
||||
*/
|
||||
static void guac_spice_keyboard_add_mapping(guac_spice_keyboard* keyboard,
|
||||
const guac_spice_keysym_desc* mapping) {
|
||||
|
||||
/* Locate corresponding keysym-to-key translation entry within keyboard
|
||||
* structure */
|
||||
guac_spice_key** key_by_keysym = guac_spice_keyboard_map_key(keyboard, mapping->keysym);
|
||||
if (key_by_keysym == NULL) {
|
||||
guac_client_log(keyboard->client, GUAC_LOG_DEBUG, "Ignoring unmappable keysym 0x%X", mapping->keysym);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If not yet pointing to a key, point keysym-to-key translation entry at
|
||||
* next available storage */
|
||||
if (*key_by_keysym == NULL) {
|
||||
|
||||
if (keyboard->num_keys == GUAC_SPICE_KEYBOARD_MAX_KEYSYMS) {
|
||||
guac_client_log(keyboard->client, GUAC_LOG_DEBUG, "Key definition "
|
||||
"for keysym 0x%X dropped: Keymap exceeds maximum "
|
||||
"supported number of keysyms",
|
||||
mapping->keysym);
|
||||
return;
|
||||
}
|
||||
|
||||
*key_by_keysym = &keyboard->keys[keyboard->num_keys++];
|
||||
|
||||
}
|
||||
|
||||
guac_spice_key* key = *key_by_keysym;
|
||||
|
||||
/* Add new definition only if sufficient space remains */
|
||||
if (key->num_definitions == GUAC_SPICE_KEY_MAX_DEFINITIONS) {
|
||||
guac_client_log(keyboard->client, GUAC_LOG_DEBUG, "Key definition "
|
||||
"for keysym 0x%X dropped: Maximum number of possible "
|
||||
"definitions has been reached for this keysym",
|
||||
mapping->keysym);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Store new possible definition of key */
|
||||
key->definitions[key->num_definitions++] = mapping;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all keysym/scancode mappings declared within the given keymap and its
|
||||
* parent keymap, if any. These mappings are stored within the given
|
||||
* guac_spice_keyboard structure for future use in translating keysyms to the
|
||||
* scancodes required by SPICE key events.
|
||||
*
|
||||
* @param keyboard
|
||||
* The guac_spice_keyboard which should be initialized with the
|
||||
* keysym/scancode mapping defined in the given keymap.
|
||||
*
|
||||
* @param keymap
|
||||
* The keymap to use to populate the given client's keysym/scancode
|
||||
* mapping.
|
||||
*/
|
||||
static void guac_spice_keyboard_load_keymap(guac_spice_keyboard* keyboard,
|
||||
const guac_spice_keymap* keymap) {
|
||||
|
||||
/* If parent exists, load parent first */
|
||||
if (keymap->parent != NULL)
|
||||
guac_spice_keyboard_load_keymap(keyboard, keymap->parent);
|
||||
|
||||
/* Log load */
|
||||
guac_client_log(keyboard->client, GUAC_LOG_INFO,
|
||||
"Loading keymap \"%s\"", keymap->name);
|
||||
|
||||
/* Copy mapping into keymap */
|
||||
const guac_spice_keysym_desc* mapping = keymap->mapping;
|
||||
while (mapping->keysym != 0) {
|
||||
guac_spice_keyboard_add_mapping(keyboard, mapping++);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
guac_spice_keyboard* guac_spice_keyboard_alloc(guac_client* client,
|
||||
const guac_spice_keymap* keymap) {
|
||||
|
||||
guac_spice_keyboard* keyboard = calloc(1, sizeof(guac_spice_keyboard));
|
||||
keyboard->client = client;
|
||||
|
||||
/* Load keymap into keyboard */
|
||||
guac_spice_keyboard_load_keymap(keyboard, keymap);
|
||||
|
||||
return keyboard;
|
||||
|
||||
}
|
||||
|
||||
void guac_spice_keyboard_free(guac_spice_keyboard* keyboard) {
|
||||
free(keyboard);
|
||||
}
|
||||
|
||||
int guac_spice_keyboard_is_defined(guac_spice_keyboard* keyboard, int keysym) {
|
||||
|
||||
/* Return whether the mapping actually exists */
|
||||
return guac_spice_keyboard_get_key(keyboard, keysym) != NULL;
|
||||
|
||||
}
|
||||
|
||||
int guac_spice_keyboard_is_pressed(guac_spice_keyboard* keyboard, int keysym) {
|
||||
|
||||
guac_spice_key* key = guac_spice_keyboard_get_key(keyboard, keysym);
|
||||
return key != NULL && key->pressed != NULL;
|
||||
|
||||
}
|
||||
|
||||
unsigned int guac_spice_keyboard_get_modifier_flags(guac_spice_keyboard* keyboard) {
|
||||
|
||||
unsigned int modifier_flags = 0;
|
||||
|
||||
/* Shift */
|
||||
if (guac_spice_keyboard_is_pressed(keyboard, GUAC_SPICE_KEYSYM_LSHIFT)
|
||||
|| guac_spice_keyboard_is_pressed(keyboard, GUAC_SPICE_KEYSYM_RSHIFT))
|
||||
modifier_flags |= GUAC_SPICE_KEYMAP_MODIFIER_SHIFT;
|
||||
|
||||
/* Dedicated AltGr key */
|
||||
if (guac_spice_keyboard_is_pressed(keyboard, GUAC_SPICE_KEYSYM_RALT)
|
||||
|| guac_spice_keyboard_is_pressed(keyboard, GUAC_SPICE_KEYSYM_ALTGR))
|
||||
modifier_flags |= GUAC_SPICE_KEYMAP_MODIFIER_ALTGR;
|
||||
|
||||
/* AltGr via Ctrl+Alt */
|
||||
if (guac_spice_keyboard_is_pressed(keyboard, GUAC_SPICE_KEYSYM_LALT)
|
||||
&& (guac_spice_keyboard_is_pressed(keyboard, GUAC_SPICE_KEYSYM_RCTRL)
|
||||
|| guac_spice_keyboard_is_pressed(keyboard, GUAC_SPICE_KEYSYM_LCTRL)))
|
||||
modifier_flags |= GUAC_SPICE_KEYMAP_MODIFIER_ALTGR;
|
||||
|
||||
return modifier_flags;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Presses/releases the requested key by sending one or more SPICE key events, as
|
||||
* defined within the keymap defining that key.
|
||||
*
|
||||
* @param keyboard
|
||||
* The guac_spice_keyboard associated with the current SPICE session.
|
||||
*
|
||||
* @param key
|
||||
* The guac_spice_keysym_desc of the key being pressed or released, as
|
||||
* retrieved from the relevant keymap.
|
||||
*
|
||||
* @param pressed
|
||||
* Zero if the key is being released, non-zero otherwise.
|
||||
*
|
||||
* @return
|
||||
* Zero if the key was successfully pressed/released, non-zero if the key
|
||||
* cannot be sent using SPICE key events.
|
||||
*/
|
||||
static const guac_spice_keysym_desc* guac_spice_keyboard_send_defined_key(guac_spice_keyboard* keyboard,
|
||||
guac_spice_key* key, int pressed) {
|
||||
|
||||
guac_client* client = keyboard->client;
|
||||
guac_spice_client* spice_client = (guac_spice_client*) client->data;
|
||||
|
||||
const guac_spice_keysym_desc* keysym_desc = guac_spice_keyboard_get_definition(keyboard, key);
|
||||
if (keysym_desc->scancode == 0)
|
||||
return NULL;
|
||||
|
||||
/* Update state of required locks and modifiers only when key is just
|
||||
* now being pressed */
|
||||
if (pressed) {
|
||||
guac_spice_keyboard_update_locks(keyboard,
|
||||
keysym_desc->set_locks,
|
||||
keysym_desc->clear_locks);
|
||||
|
||||
guac_spice_keyboard_update_modifiers(keyboard,
|
||||
keysym_desc->set_modifiers,
|
||||
keysym_desc->clear_modifiers);
|
||||
}
|
||||
|
||||
/* Fire actual key event for target key */
|
||||
guac_client_log(client, GUAC_LOG_TRACE, "Firing scancode event: %08x", keysym_desc->scancode);
|
||||
guac_spice_send_key_event(spice_client, keysym_desc->scancode,
|
||||
keysym_desc->flags, pressed);
|
||||
|
||||
return keysym_desc;
|
||||
|
||||
}
|
||||
|
||||
void guac_spice_keyboard_update_locks(guac_spice_keyboard* keyboard,
|
||||
unsigned int set_modifiers, unsigned int clear_modifiers) {
|
||||
|
||||
guac_client* client = keyboard->client;
|
||||
guac_spice_client* spice_client = (guac_spice_client*) client->data;
|
||||
|
||||
/* Calculate updated lock flags */
|
||||
unsigned int modifiers = (keyboard->modifiers | set_modifiers) & ~clear_modifiers;
|
||||
|
||||
/* Synchronize remote side only if lock flags have changed */
|
||||
if (modifiers != keyboard->modifiers) {
|
||||
guac_spice_send_synchronize_event(spice_client, modifiers);
|
||||
keyboard->modifiers = modifiers;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void guac_spice_keyboard_update_modifiers(guac_spice_keyboard* keyboard,
|
||||
unsigned int set_flags, unsigned int clear_flags) {
|
||||
|
||||
unsigned int modifier_flags = guac_spice_keyboard_get_modifier_flags(keyboard);
|
||||
|
||||
/* Only clear modifiers that are set */
|
||||
clear_flags &= modifier_flags;
|
||||
|
||||
/* Only set modifiers that are currently cleared */
|
||||
set_flags &= ~modifier_flags;
|
||||
|
||||
/* Press/release Shift as needed */
|
||||
if (set_flags & GUAC_SPICE_KEYMAP_MODIFIER_SHIFT) {
|
||||
guac_spice_keyboard_update_keysym(keyboard, GUAC_SPICE_KEYSYM_LSHIFT, 1, GUAC_SPICE_KEY_SOURCE_SYNTHETIC);
|
||||
}
|
||||
else if (clear_flags & GUAC_SPICE_KEYMAP_MODIFIER_SHIFT) {
|
||||
guac_spice_keyboard_update_keysym(keyboard, GUAC_SPICE_KEYSYM_LSHIFT, 0, GUAC_SPICE_KEY_SOURCE_SYNTHETIC);
|
||||
guac_spice_keyboard_update_keysym(keyboard, GUAC_SPICE_KEYSYM_RSHIFT, 0, GUAC_SPICE_KEY_SOURCE_SYNTHETIC);
|
||||
}
|
||||
|
||||
/* Press/release AltGr as needed */
|
||||
if (set_flags & GUAC_SPICE_KEYMAP_MODIFIER_ALTGR) {
|
||||
guac_spice_keyboard_update_keysym(keyboard, GUAC_SPICE_KEYSYM_ALTGR, 1, GUAC_SPICE_KEY_SOURCE_SYNTHETIC);
|
||||
}
|
||||
else if (clear_flags & GUAC_SPICE_KEYMAP_MODIFIER_ALTGR) {
|
||||
guac_spice_keyboard_update_keysym(keyboard, GUAC_SPICE_KEYSYM_ALTGR, 0, GUAC_SPICE_KEY_SOURCE_SYNTHETIC);
|
||||
guac_spice_keyboard_update_keysym(keyboard, GUAC_SPICE_KEYSYM_LALT, 0, GUAC_SPICE_KEY_SOURCE_SYNTHETIC);
|
||||
guac_spice_keyboard_update_keysym(keyboard, GUAC_SPICE_KEYSYM_RALT, 0, GUAC_SPICE_KEY_SOURCE_SYNTHETIC);
|
||||
guac_spice_keyboard_update_keysym(keyboard, GUAC_SPICE_KEYSYM_LCTRL, 0, GUAC_SPICE_KEY_SOURCE_SYNTHETIC);
|
||||
guac_spice_keyboard_update_keysym(keyboard, GUAC_SPICE_KEYSYM_RCTRL, 0, GUAC_SPICE_KEY_SOURCE_SYNTHETIC);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int guac_spice_keyboard_update_keysym(guac_spice_keyboard* keyboard,
|
||||
int keysym, int pressed, guac_spice_key_source source) {
|
||||
|
||||
/* Synchronize lock keys states, if this has not yet been done */
|
||||
if (!keyboard->synchronized) {
|
||||
|
||||
guac_client* client = keyboard->client;
|
||||
guac_spice_client* spice_client = (guac_spice_client*) client->data;
|
||||
|
||||
/* Synchronize remote lock key states with local state */
|
||||
guac_spice_send_synchronize_event(spice_client, keyboard->modifiers);
|
||||
keyboard->synchronized = 1;
|
||||
|
||||
}
|
||||
|
||||
guac_spice_key* key = guac_spice_keyboard_get_key(keyboard, keysym);
|
||||
|
||||
/* Update tracking of client-side keyboard state but only for keys which
|
||||
* are tracked server-side, as well (to ensure that the key count remains
|
||||
* correct, even if a user sends extra unbalanced or excessive press and
|
||||
* release events) */
|
||||
if (source == GUAC_SPICE_KEY_SOURCE_CLIENT && key != NULL) {
|
||||
if (pressed && !key->user_pressed) {
|
||||
keyboard->user_pressed_keys++;
|
||||
key->user_pressed = 1;
|
||||
}
|
||||
else if (!pressed && key->user_pressed) {
|
||||
keyboard->user_pressed_keys--;
|
||||
key->user_pressed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Send events and update server-side lock state only if server-side key
|
||||
* state is changing (or if server-side state of this key is untracked) */
|
||||
if (key == NULL || (pressed && key->pressed == NULL) || (!pressed && key->pressed != NULL)) {
|
||||
|
||||
/* Toggle locks on keydown */
|
||||
if (pressed)
|
||||
keyboard->modifiers ^= guac_spice_keyboard_lock_flag(keysym);
|
||||
|
||||
/* If key is known, update state and attempt to send using normal SPICE key
|
||||
* events */
|
||||
const guac_spice_keysym_desc* definition = NULL;
|
||||
if (key != NULL) {
|
||||
definition = guac_spice_keyboard_send_defined_key(keyboard, key, pressed);
|
||||
key->pressed = pressed ? definition : NULL;
|
||||
}
|
||||
|
||||
/* Fall back to dead keys or Unicode events if otherwise undefined inside
|
||||
* current keymap (note that we only handle "pressed" here, as neither
|
||||
* Unicode events nor dead keys can have a pressed/released state) */
|
||||
if (definition == NULL && pressed) {
|
||||
guac_client_log(keyboard->client, GUAC_LOG_WARNING,
|
||||
"Undefined key will not be sent: %d", keysym);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Reset SPICE server keyboard state (releasing any automatically
|
||||
* pressed keys) once all keys have been released on the client
|
||||
* side */
|
||||
if (source == GUAC_SPICE_KEY_SOURCE_CLIENT && keyboard->user_pressed_keys == 0)
|
||||
guac_spice_keyboard_reset(keyboard);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void guac_spice_keyboard_reset(guac_spice_keyboard* keyboard) {
|
||||
|
||||
/* Release all pressed keys */
|
||||
for (int i = 0; i < keyboard->num_keys; i++) {
|
||||
guac_spice_key* key = &keyboard->keys[i];
|
||||
if (key->pressed != NULL)
|
||||
guac_spice_keyboard_update_keysym(keyboard, key->pressed->keysym, 0,
|
||||
GUAC_SPICE_KEY_SOURCE_SYNTHETIC);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void guac_spice_keyboard_set_indicators(SpiceChannel* channel, guac_client* client) {
|
||||
|
||||
guac_spice_client* spice_client = (guac_spice_client*) client->data;
|
||||
|
||||
pthread_rwlock_rdlock(&(spice_client->lock));
|
||||
|
||||
/* Skip if keyboard not yet ready */
|
||||
guac_spice_keyboard* keyboard = spice_client->keyboard;
|
||||
if (keyboard == NULL)
|
||||
goto complete;
|
||||
|
||||
unsigned int modifiers;
|
||||
g_object_get(channel, SPICE_PROPERTY_KEY_MODIFIERS, &modifiers, NULL);
|
||||
|
||||
/* Update with received locks */
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Received updated keyboard lock flags from SPICE server: 0x%X", modifiers);
|
||||
keyboard->modifiers = modifiers;
|
||||
|
||||
complete:
|
||||
pthread_rwlock_unlock(&(spice_client->lock));
|
||||
|
||||
}
|
323
src/protocols/spice/keyboard.h
Normal file
323
src/protocols/spice/keyboard.h
Normal file
@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_SPICE_KEYBOARD_H
|
||||
#define GUAC_SPICE_KEYBOARD_H
|
||||
|
||||
#include "keymap.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <spice-client-glib-2.0/spice-client.h>
|
||||
|
||||
/**
|
||||
* The maximum number of distinct keysyms that any particular keyboard may support.
|
||||
*/
|
||||
#define GUAC_SPICE_KEYBOARD_MAX_KEYSYMS 1024
|
||||
|
||||
/**
|
||||
* The maximum number of unique modifier variations that any particular keysym
|
||||
* may define. For example, on a US English keyboard, an uppercase "A" may be
|
||||
* typed by pressing Shift+A with Caps Lock unset, or by pressing A with Caps
|
||||
* Lock set (two variations).
|
||||
*/
|
||||
#define GUAC_SPICE_KEY_MAX_DEFINITIONS 4
|
||||
|
||||
/**
|
||||
* All possible sources of SPICE key events tracked by guac_spice_keyboard.
|
||||
*/
|
||||
typedef enum guac_spice_key_source {
|
||||
|
||||
/**
|
||||
* The key event was received directly from the Guacamole client via a
|
||||
* "key" instruction.
|
||||
*/
|
||||
GUAC_SPICE_KEY_SOURCE_CLIENT = 0,
|
||||
|
||||
/**
|
||||
* The key event is being synthesized internally within the SPICE support.
|
||||
*/
|
||||
GUAC_SPICE_KEY_SOURCE_SYNTHETIC = 1
|
||||
|
||||
} guac_spice_key_source;
|
||||
|
||||
/**
|
||||
* A representation of a single key within the overall local keyboard,
|
||||
* including the definition of that key within the SPICE server's keymap and
|
||||
* whether the key is currently pressed locally.
|
||||
*/
|
||||
typedef struct guac_spice_key {
|
||||
|
||||
/**
|
||||
* All definitions of this key within the SPICE server's keymap (keyboard
|
||||
* layout). Each definition describes which scancode corresponds to this
|
||||
* key from the perspective of the SPICE server, as well as which other
|
||||
* scancodes must be pressed/released for this key to have the desired
|
||||
* meaning.
|
||||
*/
|
||||
const guac_spice_keysym_desc* definitions[GUAC_SPICE_KEY_MAX_DEFINITIONS];
|
||||
|
||||
/**
|
||||
* The number of definitions within the definitions array. If this key does
|
||||
* not exist within the SPICE server's keymap, this will be 0.
|
||||
*/
|
||||
int num_definitions;
|
||||
|
||||
/**
|
||||
* The definition of this key that is currently pressed. If this key is not
|
||||
* currently pressed, this will be NULL.
|
||||
*/
|
||||
const guac_spice_keysym_desc* pressed;
|
||||
|
||||
/**
|
||||
* Whether this key is currently pressed by the user, and is included among
|
||||
* the total tracked by user_pressed_keys within guac_spice_keyboard.
|
||||
*/
|
||||
int user_pressed;
|
||||
|
||||
} guac_spice_key;
|
||||
|
||||
/**
|
||||
* The current keyboard state of an SPICE session.
|
||||
*/
|
||||
typedef struct guac_spice_keyboard {
|
||||
|
||||
/**
|
||||
* The guac_client associated with the SPICE session whose keyboard state is
|
||||
* being managed by this guac_spice_keyboard.
|
||||
*/
|
||||
guac_client* client;
|
||||
|
||||
/**
|
||||
* The local state of all known lock keys, as a bitwise OR of all SPICE lock
|
||||
* key flags. Legal flags are KBD_SYNC_SCROLL_LOCK, KBD_SYNC_NUM_LOCK,
|
||||
* KBD_SYNC_CAPS_LOCK, and KBD_SYNC_KANA_LOCK.
|
||||
*/
|
||||
int modifiers;
|
||||
|
||||
/**
|
||||
* Whether the states of remote lock keys (Caps lock, Num lock, etc.) have
|
||||
* been synchronized with local lock key states.
|
||||
*/
|
||||
int synchronized;
|
||||
|
||||
/**
|
||||
* The number of keys stored within the keys array.
|
||||
*/
|
||||
unsigned int num_keys;
|
||||
|
||||
/**
|
||||
* The local state of all keys, as well as the necessary information to
|
||||
* translate received keysyms into scancodes or sequences of scancodes for
|
||||
* SPICE. The state of each key is updated based on received Guacamole key
|
||||
* events, while the information describing the behavior and scancode
|
||||
* mapping of each key is populated based on an associated keymap.
|
||||
*
|
||||
* Keys within this array are in arbitrary order.
|
||||
*/
|
||||
guac_spice_key keys[GUAC_SPICE_KEYBOARD_MAX_KEYSYMS];
|
||||
|
||||
/**
|
||||
* Lookup table into the overall keys array, locating the guac_spice_key
|
||||
* associated with any particular keysym. If a keysym has no corresponding
|
||||
* guac_spice_key within the keys array, its entry within this lookuptable
|
||||
* will be NULL.
|
||||
*
|
||||
* The index of the key for a given keysym is determined based on a
|
||||
* simple transformation of the keysym itself. Keysyms between 0x0000 and
|
||||
* 0xFFFF inclusive are mapped to 0x00000 through 0x0FFFF, while keysyms
|
||||
* between 0x1000000 and 0x100FFFF inclusive (keysyms which are derived
|
||||
* from Unicode) are mapped to 0x10000 through 0x1FFFF.
|
||||
*/
|
||||
guac_spice_key* keys_by_keysym[0x20000];
|
||||
|
||||
/**
|
||||
* The total number of keys that the user of the connection is currently
|
||||
* holding down. This value indicates only the client-side keyboard state.
|
||||
* It DOES NOT indicate the number of keys currently pressed within the SPICE
|
||||
* server.
|
||||
*/
|
||||
int user_pressed_keys;
|
||||
|
||||
} guac_spice_keyboard;
|
||||
|
||||
/**
|
||||
* Allocates a new guac_spice_keyboard which manages the keyboard state of the
|
||||
* SPICE session associated with the given guac_client. Keyboard events will be
|
||||
* dynamically translated from keysym to SPICE scancode according to the
|
||||
* provided keymap. The returned guac_spice_keyboard must eventually be freed
|
||||
* with guac_spice_keyboard_free().
|
||||
*
|
||||
* @param client
|
||||
* The guac_client associated with the SPICE session whose keyboard state is
|
||||
* to be managed by the newly-allocated guac_spice_keyboard.
|
||||
*
|
||||
* @param keymap
|
||||
* The keymap which should be used to translate keyboard events.
|
||||
*
|
||||
* @return
|
||||
* A newly-allocated guac_spice_keyboard which manages the keyboard state
|
||||
* for the SPICE session associated given guac_client.
|
||||
*/
|
||||
guac_spice_keyboard* guac_spice_keyboard_alloc(guac_client* client,
|
||||
const guac_spice_keymap* keymap);
|
||||
|
||||
/**
|
||||
* Frees all memory allocated for the given guac_spice_keyboard. The
|
||||
* guac_spice_keyboard must have been previously allocated via
|
||||
* guac_spice_keyboard_alloc().
|
||||
*
|
||||
* @param keyboard
|
||||
* The guac_spice_keyboard instance which should be freed.
|
||||
*/
|
||||
void guac_spice_keyboard_free(guac_spice_keyboard* keyboard);
|
||||
|
||||
/**
|
||||
* Returns whether the given keysym is defined for the keyboard layout
|
||||
* associated with the given keyboard.
|
||||
*
|
||||
* @param keyboard
|
||||
* The guac_spice_keyboard instance to check.
|
||||
*
|
||||
* @param keysym
|
||||
* The keysym of the key being checked against the keyboard layout of the
|
||||
* given keyboard.
|
||||
*
|
||||
* @return
|
||||
* Non-zero if the key is explicitly defined within the keyboard layout of
|
||||
* the given keyboard, zero otherwise.
|
||||
*/
|
||||
int guac_spice_keyboard_is_defined(guac_spice_keyboard* keyboard, int keysym);
|
||||
|
||||
/**
|
||||
* Returns whether the key having the given keysym is currently pressed.
|
||||
*
|
||||
* @param keyboard
|
||||
* The guac_spice_keyboard instance to check.
|
||||
*
|
||||
* @param keysym
|
||||
* The keysym of the key being checked.
|
||||
*
|
||||
* @return
|
||||
* Non-zero if the key is currently pressed, zero otherwise.
|
||||
*/
|
||||
int guac_spice_keyboard_is_pressed(guac_spice_keyboard* keyboard, int keysym);
|
||||
|
||||
/**
|
||||
* Returns the local state of all known modifier keys, as a bitwise OR of the
|
||||
* modifier flags used by the keymaps. Alternative methods of producing the
|
||||
* effect of certain modifiers, such as holding Ctrl+Alt for AltGr when a
|
||||
* dedicated AltGr key is unavailable, are taken into account.
|
||||
*
|
||||
* @see GUAC_SPICE_KEYMAP_MODIFIER_SHIFT
|
||||
* @see GUAC_SPICE_KEYMAP_MODIFIER_ALTGR
|
||||
*
|
||||
* @param keyboard
|
||||
* The guac_spice_keyboard associated with the current SPICE session.
|
||||
*
|
||||
* @return
|
||||
* The local state of all known modifier keys.
|
||||
*/
|
||||
unsigned int guac_spice_keyboard_get_modifier_flags(guac_spice_keyboard* keyboard);
|
||||
|
||||
/**
|
||||
* Updates the local state of the lock keys (such as Caps lock or Num lock),
|
||||
* synchronizing the remote state of those keys if it is expected to differ.
|
||||
*
|
||||
* @param keyboard
|
||||
* The guac_spice_keyboard associated with the current SPICE session.
|
||||
*
|
||||
* @param set_modifiers
|
||||
* The lock key flags which should be set. Legal flags are
|
||||
* KBD_SYNC_SCROLL_LOCK, KBD_SYNC_NUM_LOCK, KBD_SYNC_CAPS_LOCK, and
|
||||
* KBD_SYNC_KANA_LOCK.
|
||||
*
|
||||
* @param clear_modifiers
|
||||
* The lock key flags which should be cleared. Legal flags are
|
||||
* KBD_SYNC_SCROLL_LOCK, KBD_SYNC_NUM_LOCK, KBD_SYNC_CAPS_LOCK, and
|
||||
* KBD_SYNC_KANA_LOCK.
|
||||
*/
|
||||
void guac_spice_keyboard_update_locks(guac_spice_keyboard* keyboard,
|
||||
unsigned int set_modifiers, unsigned int clear_modifiers);
|
||||
|
||||
/**
|
||||
* Updates the local state of the modifier keys (such as Shift or AltGr),
|
||||
* synchronizing the remote state of those keys if it is expected to differ.
|
||||
* Valid modifier flags are defined by keymap.h.
|
||||
*
|
||||
* @see GUAC_SPICE_KEYMAP_MODIFIER_SHIFT
|
||||
* @see GUAC_SPICE_KEYMAP_MODIFIER_ALTGR
|
||||
*
|
||||
* @param keyboard
|
||||
* The guac_spice_keyboard associated with the current SPICE session.
|
||||
*
|
||||
* @param set_modifiers
|
||||
* The modifier key flags which should be set.
|
||||
*
|
||||
* @param clear_modifiers
|
||||
* The modifier key flags which should be cleared.
|
||||
*/
|
||||
void guac_spice_keyboard_update_modifiers(guac_spice_keyboard* keyboard,
|
||||
unsigned int set_modifiers, unsigned int clear_modifiers);
|
||||
|
||||
/**
|
||||
* Updates the local state of the given keysym, sending the key events required
|
||||
* to replicate that state remotely (on the SPICE server). The key events sent
|
||||
* will depend on the current keymap.
|
||||
*
|
||||
* @param keyboard
|
||||
* The guac_spice_keyboard associated with the current SPICE session.
|
||||
*
|
||||
* @param keysym
|
||||
* The keysym being pressed or released.
|
||||
*
|
||||
* @param pressed
|
||||
* Zero if the keysym is being released, non-zero otherwise.
|
||||
*
|
||||
* @param source
|
||||
* The source of the key event represented by this call to
|
||||
* guac_spice_keyboard_update_keysym().
|
||||
*
|
||||
* @return
|
||||
* Zero if the keys were successfully sent, non-zero otherwise.
|
||||
*/
|
||||
int guac_spice_keyboard_update_keysym(guac_spice_keyboard* keyboard,
|
||||
int keysym, int pressed, guac_spice_key_source source);
|
||||
|
||||
/**
|
||||
* Releases all currently pressed keys, sending key release events to the SPICE
|
||||
* server as necessary. Lock states (Caps Lock, etc.) are not affected.
|
||||
*
|
||||
* @param keyboard
|
||||
* The guac_spice_keyboard associated with the current SPICE session.
|
||||
*/
|
||||
void guac_spice_keyboard_reset(guac_spice_keyboard* keyboard);
|
||||
|
||||
/**
|
||||
* Callback which is invoked when the SPICE server reports changes to keyboard
|
||||
* lock status using a Server Set Keyboard Indicators PDU.
|
||||
*
|
||||
* @param channel
|
||||
* The spiceContext associated with the current SPICE session.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client object associated with the callback.
|
||||
*/
|
||||
void guac_spice_keyboard_set_indicators(SpiceChannel* channel, guac_client* client);
|
||||
|
||||
#endif
|
41
src/protocols/spice/keymap.c
Normal file
41
src/protocols/spice/keymap.c
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "keymap.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
const guac_spice_keymap* guac_spice_keymap_find(const char* name) {
|
||||
|
||||
/* For each keymap */
|
||||
const guac_spice_keymap** current = GUAC_SPICE_KEYMAPS;
|
||||
while (*current != NULL) {
|
||||
|
||||
/* If name matches, done */
|
||||
if (strcmp((*current)->name, name) == 0)
|
||||
return *current;
|
||||
|
||||
current++;
|
||||
}
|
||||
|
||||
/* Failure */
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
202
src/protocols/spice/keymap.h
Normal file
202
src/protocols/spice/keymap.h
Normal file
@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_SPICE_KEYMAP_H
|
||||
#define GUAC_SPICE_KEYMAP_H
|
||||
|
||||
/**
|
||||
* The X11 keysym for Num Lock.
|
||||
*/
|
||||
#define GUAC_SPICE_KEYSYM_NUM_LOCK 0xFF7F
|
||||
|
||||
/**
|
||||
* The X11 keysym for Scroll Lock.
|
||||
*/
|
||||
#define GUAC_SPICE_KEYSYM_SCROLL_LOCK 0xFF14
|
||||
|
||||
/**
|
||||
* The X11 keysym for Caps Lock.
|
||||
*/
|
||||
#define GUAC_SPICE_KEYSYM_CAPS_LOCK 0xFFE5
|
||||
|
||||
/**
|
||||
* The X11 keysym for Kana Lock.
|
||||
*/
|
||||
#define GUAC_SPICE_KEYSYM_KANA_LOCK 0xFF2D
|
||||
|
||||
/**
|
||||
* The X11 keysym for Left Shift.
|
||||
*/
|
||||
#define GUAC_SPICE_KEYSYM_LSHIFT 0xFFE1
|
||||
|
||||
/**
|
||||
* The X11 keysym for Right Shift.
|
||||
*/
|
||||
#define GUAC_SPICE_KEYSYM_RSHIFT 0xFFE2
|
||||
|
||||
/**
|
||||
* The X11 keysym for Left Ctrl.
|
||||
*/
|
||||
#define GUAC_SPICE_KEYSYM_LCTRL 0xFFE3
|
||||
|
||||
/**
|
||||
* The X11 keysym for Right Ctrl.
|
||||
*/
|
||||
#define GUAC_SPICE_KEYSYM_RCTRL 0xFFE4
|
||||
|
||||
/**
|
||||
* The X11 keysym for Left Alt.
|
||||
*/
|
||||
#define GUAC_SPICE_KEYSYM_LALT 0xFFE9
|
||||
|
||||
/**
|
||||
* The X11 keysym for Right Alt.
|
||||
*/
|
||||
#define GUAC_SPICE_KEYSYM_RALT 0xFFEA
|
||||
|
||||
/**
|
||||
* The X11 keysym for AltGr.
|
||||
*/
|
||||
#define GUAC_SPICE_KEYSYM_ALTGR 0xFE03
|
||||
|
||||
/**
|
||||
* Bitwise flag value representing the Shift modifier.
|
||||
*/
|
||||
#define GUAC_SPICE_KEYMAP_MODIFIER_SHIFT 1
|
||||
|
||||
/**
|
||||
* Bitwise flag value representing the AltGr modifier.
|
||||
*/
|
||||
#define GUAC_SPICE_KEYMAP_MODIFIER_ALTGR 2
|
||||
|
||||
/**
|
||||
* Represents a keysym-to-scancode mapping for SPICE, with extra information
|
||||
* about the state of prerequisite keysyms.
|
||||
*/
|
||||
typedef struct guac_spice_keysym_desc {
|
||||
|
||||
/**
|
||||
* The keysym being mapped.
|
||||
*/
|
||||
int keysym;
|
||||
|
||||
/**
|
||||
* The scancode this keysym maps to.
|
||||
*/
|
||||
int scancode;
|
||||
|
||||
/**
|
||||
* Required SPICE-specific flags that must be sent along with the scancode.
|
||||
*/
|
||||
int flags;
|
||||
|
||||
/**
|
||||
* Bitwise-OR of the flags of any modifiers that must be active for the
|
||||
* associated scancode to be interpreted as this keysym.
|
||||
*
|
||||
* If the associated keysym is pressed, and any of these modifiers are not
|
||||
* currently active, Guacamole's SPICE support must send additional events
|
||||
* to activate these modifiers prior to sending the scancode for this
|
||||
* keysym.
|
||||
*
|
||||
* @see GUAC_SPICE_KEYMAP_MODIFIER_SHIFT
|
||||
* @see GUAC_SPICE_KEYMAP_MODIFIER_ALTGR
|
||||
*/
|
||||
const unsigned int set_modifiers;
|
||||
|
||||
/**
|
||||
* Bitwise-OR of the flags of any modifiers that must NOT be active for the
|
||||
* associated scancode to be interpreted as this keysym.
|
||||
*
|
||||
* If the associated keysym is pressed, and any of these modifiers are
|
||||
* currently active, Guacamole's SPICE support must send additional events
|
||||
* to deactivate these modifiers prior to sending the scancode for this
|
||||
* keysym.
|
||||
*
|
||||
* @see GUAC_SPICE_KEYMAP_MODIFIER_SHIFT
|
||||
* @see GUAC_SPICE_KEYMAP_MODIFIER_ALTGR
|
||||
*/
|
||||
const unsigned int clear_modifiers;
|
||||
|
||||
/**
|
||||
* Bitwise OR of the flags of all lock keys (ie: Caps lock, Num lock, etc.)
|
||||
* which must be active for this keysym to be properly typed. Legal flags
|
||||
* are KBD_SYNC_SCROLL_LOCK, KBD_SYNC_NUM_LOCK, KBD_SYNC_CAPS_LOCK, and
|
||||
* KBD_SYNC_KANA_LOCK.
|
||||
*/
|
||||
const unsigned int set_locks;
|
||||
|
||||
/**
|
||||
* Bitwise OR of the flags of all lock keys (ie: Caps lock, Num lock, etc.)
|
||||
* which must be inactive for this keysym to be properly typed. Legal flags
|
||||
* are KBD_SYNC_SCROLL_LOCK, KBD_SYNC_NUM_LOCK, KBD_SYNC_CAPS_LOCK, and
|
||||
* KBD_SYNC_KANA_LOCK.
|
||||
*/
|
||||
const unsigned int clear_locks;
|
||||
|
||||
} guac_spice_keysym_desc;
|
||||
|
||||
/**
|
||||
* Hierarchical keysym mapping
|
||||
*/
|
||||
typedef struct guac_spice_keymap guac_spice_keymap;
|
||||
struct guac_spice_keymap {
|
||||
|
||||
/**
|
||||
* The parent mapping this map will inherit its initial mapping from.
|
||||
* Any other mapping information will add to or override the mapping
|
||||
* inherited from the parent.
|
||||
*/
|
||||
const guac_spice_keymap* parent;
|
||||
|
||||
/**
|
||||
* Descriptive name of this keymap
|
||||
*/
|
||||
const char* name;
|
||||
|
||||
/**
|
||||
* Null-terminated array of scancode mappings.
|
||||
*/
|
||||
const guac_spice_keysym_desc* mapping;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* The name of the default keymap, which MUST exist.
|
||||
*/
|
||||
#define GUAC_SPICE_DEFAULT_KEYMAP "en-us-qwerty"
|
||||
|
||||
/**
|
||||
* NULL-terminated array of all keymaps.
|
||||
*/
|
||||
extern const guac_spice_keymap* GUAC_SPICE_KEYMAPS[];
|
||||
|
||||
/**
|
||||
* Return the keymap having the given name, if any, or NULL otherwise.
|
||||
*
|
||||
* @param name
|
||||
* The name of the keymap to find.
|
||||
*
|
||||
* @return
|
||||
* The keymap having the given name, or NULL if no such keymap exists.
|
||||
*/
|
||||
const guac_spice_keymap* guac_spice_keymap_find(const char* name);
|
||||
|
||||
#endif
|
||||
|
93
src/protocols/spice/keymaps/base.keymap
Normal file
93
src/protocols/spice/keymaps/base.keymap
Normal file
@ -0,0 +1,93 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
name "base"
|
||||
|
||||
# Typeable characters
|
||||
map 0x39 ~ " " # Space
|
||||
map 0x0F ~ 0xff09 # Tab
|
||||
|
||||
# Control characters
|
||||
map 0x0E ~ 0xff08 # BackSpace
|
||||
map 0x1C ~ 0xff0d # Return
|
||||
map 0x01 ~ 0xff1b # Escape
|
||||
map +ext 0x52 ~ 0xff63 # Insert
|
||||
map +ext 0x53 ~ 0xffff # Delete
|
||||
map +ext 0x47 ~ 0xff50 # Home
|
||||
map +ext 0x4F ~ 0xff57 # End
|
||||
map +ext 0x4B ~ 0xff51 # Left
|
||||
map +ext 0x48 ~ 0xff52 # Up
|
||||
map +ext 0x4D ~ 0xff53 # Right
|
||||
map +ext 0x50 ~ 0xff54 # Down
|
||||
map +ext 0x49 ~ 0xff55 # Page_Up
|
||||
map +ext 0x51 ~ 0xff56 # Page_Down
|
||||
map +ext 0x37 ~ 0xff61 # Print Screen
|
||||
|
||||
# Locks
|
||||
map 0x45 ~ 0xff7f # Num_Lock
|
||||
map 0x46 ~ 0xff14 # Scroll_Lock
|
||||
map 0x3A ~ 0xffe5 # Caps_Lock
|
||||
|
||||
# Keypad numerals
|
||||
map -shift +num 0x52 ~ 0xffb0 # KP_0
|
||||
map -shift +num 0x4F ~ 0xffb1 # KP_1
|
||||
map -shift +num 0x50 ~ 0xffb2 # KP_2
|
||||
map -shift +num 0x51 ~ 0xffb3 # KP_3
|
||||
map -shift +num 0x4B ~ 0xffb4 # KP_4
|
||||
map -shift +num 0x4C ~ 0xffb5 # KP_5
|
||||
map -shift +num 0x4D ~ 0xffb6 # KP_6
|
||||
map -shift +num 0x47 ~ 0xffb7 # KP_7
|
||||
map -shift +num 0x48 ~ 0xffb8 # KP_8
|
||||
map -shift +num 0x49 ~ 0xffb9 # KP_9
|
||||
|
||||
# Keypad operators
|
||||
map 0x37 ~ 0xffaa # KP_multiply
|
||||
map 0x4e ~ 0xffab # KP_add
|
||||
map 0x4a ~ 0xffad # KP_subtract
|
||||
map 0x53 ~ 0xffae # KP_decimal
|
||||
map +ext 0x35 ~ 0xffaf # KP_divide
|
||||
|
||||
# F keys
|
||||
map 0x3B ~ 0xffbe # F1
|
||||
map 0x3C ~ 0xffbf # F2
|
||||
map 0x3D ~ 0xffc0 # F3
|
||||
map 0x3E ~ 0xffc1 # F4
|
||||
map 0x3F ~ 0xffc2 # F5
|
||||
map 0x40 ~ 0xffc3 # F6
|
||||
map 0x41 ~ 0xffc4 # F7
|
||||
map 0x42 ~ 0xffc5 # F8
|
||||
map 0x43 ~ 0xffc6 # F9
|
||||
map 0x44 ~ 0xffc7 # F10
|
||||
map 0x57 ~ 0xffc8 # F11
|
||||
map 0x58 ~ 0xffc9 # F12
|
||||
|
||||
# Modifiers
|
||||
map 0x2A ~ 0xffe1 # Shift_L
|
||||
map 0x36 ~ 0xffe2 # Shift_R
|
||||
map 0x1D ~ 0xffe3 # Control_L
|
||||
map +ext 0x1D ~ 0xffe4 # Control_R
|
||||
map 0x38 ~ 0xffe9 # Alt_L
|
||||
map +ext 0x38 ~ 0xffea # Alt_R
|
||||
map +ext 0x38 ~ 0xfe03 # AltGr
|
||||
map +ext 0x5B ~ 0xffe7 # Meta_L
|
||||
map +ext 0x5C ~ 0xffe8 # Meta_R
|
||||
map +ext 0x5B ~ 0xffeb # Super_L
|
||||
map +ext 0x5C ~ 0xffec # Super_R
|
||||
map +ext 0x5D ~ 0xff67 # Menu
|
||||
|
73
src/protocols/spice/keymaps/da_dk_qwerty.keymap
Normal file
73
src/protocols/spice/keymaps/da_dk_qwerty.keymap
Normal file
@ -0,0 +1,73 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
parent "base"
|
||||
name "da-dk-qwerty"
|
||||
|
||||
#
|
||||
# Basic keys
|
||||
#
|
||||
|
||||
map -caps -altgr -shift 0x29 0x02..0x0C ~ "§1234567890+"
|
||||
map -caps -altgr -shift 0x10..0x1A ~ "qwertyuiopå"
|
||||
map -caps -altgr -shift 0x1E..0x28 0x2B ~ "asdfghjklæø'"
|
||||
map -caps -altgr -shift 0x56 0x2C..0x35 ~ "<zxcvbnm,.-"
|
||||
|
||||
map -caps -altgr +shift 0x29 0x02..0x0C ~ "½!"#¤%&/()=?"
|
||||
map -caps -altgr +shift 0x10..0x1A ~ "QWERTYUIOPÅ"
|
||||
map -caps -altgr +shift 0x1E..0x28 0x2B ~ "ASDFGHJKLÆØ*"
|
||||
map -caps -altgr +shift 0x56 0x2C..0x35 ~ ">ZXCVBNM;:_"
|
||||
|
||||
map +caps -altgr -shift 0x29 0x02..0x0C ~ "§1234567890+"
|
||||
map +caps -altgr -shift 0x10..0x1A ~ "QWERTYUIOPÅ"
|
||||
map +caps -altgr -shift 0x1E..0x28 0x2B ~ "ASDFGHJKLÆØ'"
|
||||
map +caps -altgr -shift 0x56 0x2C..0x35 ~ "<ZXCVBNM,.-"
|
||||
|
||||
map +caps -altgr +shift 0x29 0x02..0x0C ~ "½!"#¤%&/()=?"
|
||||
map +caps -altgr +shift 0x10..0x1A ~ "qwertyuiopå"
|
||||
map +caps -altgr +shift 0x1E..0x28 0x2B ~ "asdfghjklæø*"
|
||||
map +caps -altgr +shift 0x56 0x2C..0x35 ~ ">zxcvbnm;:_"
|
||||
|
||||
#
|
||||
# Keys requiring AltGr
|
||||
#
|
||||
|
||||
map +altgr -shift 0x03 ~ "@"
|
||||
map +altgr -shift 0x04 ~ "£"
|
||||
map +altgr -shift 0x05 ~ "$"
|
||||
map +altgr -shift 0x08 ~ "{"
|
||||
map +altgr -shift 0x09 ~ "["
|
||||
map +altgr -shift 0x0A ~ "]"
|
||||
map +altgr -shift 0x0B ~ "}"
|
||||
map +altgr -shift 0x56 ~ "\"
|
||||
|
||||
map +altgr -shift 0x12 ~ "€"
|
||||
|
||||
map +altgr -shift 0x0D ~ "|"
|
||||
map +altgr -shift 0x32 ~ "µ"
|
||||
|
||||
#
|
||||
# Dead keys
|
||||
#
|
||||
|
||||
map -altgr -shift 0x0D ~ 0xFE51 # Dead acute
|
||||
map -altgr +shift 0x0D ~ 0xFE50 # Dead grave
|
||||
map -altgr -shift 0x1B ~ 0xFE57 # Dead umlaut
|
||||
map -altgr +shift 0x1B ~ 0xFE52 # Dead circumflex
|
||||
map +altgr -shift 0x1B ~ 0xFE53 # Dead tilde
|
67
src/protocols/spice/keymaps/de_ch_qwertz.keymap
Normal file
67
src/protocols/spice/keymaps/de_ch_qwertz.keymap
Normal file
@ -0,0 +1,67 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
parent "base"
|
||||
name "de-ch-qwertz"
|
||||
|
||||
#
|
||||
# Basic keys
|
||||
#
|
||||
|
||||
map -caps -altgr -shift 0x29 0x02..0x0C ~ "§1234567890'"
|
||||
map -caps -altgr -shift 0x10..0x1A ~ "qwertzuiopü"
|
||||
map -caps -altgr -shift 0x1E..0x28 0x2B ~ "asdfghjklöä$"
|
||||
map -caps -altgr -shift 0x56 0x2C..0x35 ~ "<yxcvbnm,.-"
|
||||
|
||||
map -caps -altgr +shift 0x29 0x02..0x0C ~ "°+"*ç%&/()=?"
|
||||
map -caps -altgr +shift 0x10..0x1B ~ "QWERTZUIOPè!"
|
||||
map -caps -altgr +shift 0x1E..0x28 0x2B ~ "ASDFGHJKLéà£"
|
||||
map -caps -altgr +shift 0x56 0x2C..0x35 ~ ">YXCVBNM;:_"
|
||||
|
||||
map +caps -altgr -shift 0x29 0x02..0x0C ~ "§1234567890'"
|
||||
map +caps -altgr -shift 0x10..0x1A ~ "QWERTZUIOPÜ"
|
||||
map +caps -altgr -shift 0x1E..0x28 0x2B ~ "ASDFGHJKLÖÄ$"
|
||||
map +caps -altgr -shift 0x56 0x2C..0x35 ~ "<YXCVBNM,.-"
|
||||
|
||||
map +caps -altgr +shift 0x29 0x02..0x0C ~ "°+"*ç%&/()=?"
|
||||
map +caps -altgr +shift 0x10..0x1B ~ "qwertzuiopÈ!"
|
||||
map +caps -altgr +shift 0x1E..0x28 0x2B ~ "asdfghjklÉÀ£"
|
||||
map +caps -altgr +shift 0x56 0x2C..0x35 ~ ">yxcvbnm;:_"
|
||||
|
||||
#
|
||||
# Keys requiring AltGr
|
||||
#
|
||||
|
||||
map +altgr -shift 0x02..0x04 ~ "¦@#"
|
||||
map +altgr -shift 0x07..0x09 ~ "¬|¢"
|
||||
map +altgr -shift 0x1A..0x1B ~ "[]"
|
||||
map +altgr -shift 0x28 ~ "{"
|
||||
map +altgr -shift 0x2B ~ "}"
|
||||
map +altgr -shift 0x56 ~ "\"
|
||||
map +altgr -shift 0x12 ~ "€"
|
||||
|
||||
#
|
||||
# Dead keys
|
||||
#
|
||||
|
||||
map +altgr -shift 0x0C ~ 0xFE51 # Dead acute
|
||||
map -altgr -shift 0x0D ~ 0xFE52 # Dead circumflex
|
||||
map -altgr +shift 0x0D ~ 0xFE50 # Dead grave
|
||||
map +altgr -shift 0x0D ~ 0xFE53 # Dead tilde
|
||||
map -altgr -shift 0x1B ~ 0xFE57 # Dead umlaut
|
74
src/protocols/spice/keymaps/de_de_qwertz.keymap
Normal file
74
src/protocols/spice/keymaps/de_de_qwertz.keymap
Normal file
@ -0,0 +1,74 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
parent "base"
|
||||
name "de-de-qwertz"
|
||||
|
||||
#
|
||||
# Basic keys
|
||||
#
|
||||
|
||||
map -caps -altgr -shift 0x02..0x0C ~ "1234567890ß"
|
||||
map -caps -altgr -shift 0x10..0x1B ~ "qwertzuiopü+"
|
||||
map -caps -altgr -shift 0x1E..0x28 0x2B ~ "asdfghjklöä#"
|
||||
map -caps -altgr -shift 0x56 0x2C..0x35 ~ "<yxcvbnm,.-"
|
||||
|
||||
map -caps -altgr +shift 0x29 0x02..0x0C ~ "°!"§$%&/()=?"
|
||||
map -caps -altgr +shift 0x10..0x1B ~ "QWERTZUIOPÜ*"
|
||||
map -caps -altgr +shift 0x1E..0x28 0x2B ~ "ASDFGHJKLÖÄ'"
|
||||
map -caps -altgr +shift 0x56 0x2C..0x35 ~ ">YXCVBNM;:_"
|
||||
|
||||
map +caps -altgr -shift 0x02..0x0C ~ "!"§$%&/()=?"
|
||||
map +caps -altgr -shift 0x10..0x1B ~ "QWERTZUIOPÜ*"
|
||||
map +caps -altgr -shift 0x1E..0x28 0x2B ~ "ASDFGHJKLÖÄ'"
|
||||
map +caps -altgr -shift 0x56 0x2C..0x35 ~ "<YXCVBNM;:-"
|
||||
|
||||
map +caps -altgr +shift 0x29 0x02..0x0C ~ "°1234567890ß"
|
||||
map +caps -altgr +shift 0x10..0x1B ~ "qwertzuiopü+"
|
||||
map +caps -altgr +shift 0x1E..0x28 0x2B ~ "asdfghjklöä#"
|
||||
map +caps -altgr +shift 0x56 0x2C..0x35 ~ ">yxcvbnm,._"
|
||||
|
||||
#
|
||||
# Keys requiring AltGr
|
||||
#
|
||||
|
||||
map +altgr -shift 0x03 ~ "²"
|
||||
map +altgr -shift 0x04 ~ "³"
|
||||
map +altgr -shift 0x08 ~ "{"
|
||||
map +altgr -shift 0x09 ~ "["
|
||||
map +altgr -shift 0x0A ~ "]"
|
||||
map +altgr -shift 0x0B ~ "}"
|
||||
map +altgr -shift 0x0C ~ "\"
|
||||
|
||||
map +altgr -shift 0x10 ~ "@"
|
||||
map +altgr -shift 0x12 ~ "€"
|
||||
map +altgr -shift 0x1B ~ "~"
|
||||
|
||||
map +altgr -shift 0x56 ~ "|"
|
||||
map +altgr -shift 0x32 ~ "µ"
|
||||
|
||||
#
|
||||
# Dead keys
|
||||
#
|
||||
|
||||
map -altgr +shift 0x0D ~ 0xFE50 # Dead grave
|
||||
map -altgr -shift 0x0D ~ 0xFE51 # Dead acute
|
||||
map -altgr -shift 0x29 ~ 0xFE52 # Dead circumflex
|
||||
map +altgr -shift 0x0C ~ 0xFE53 # Dead tilde
|
||||
|
79
src/protocols/spice/keymaps/en_gb_qwerty.keymap
Normal file
79
src/protocols/spice/keymaps/en_gb_qwerty.keymap
Normal file
@ -0,0 +1,79 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
parent "base"
|
||||
name "en-gb-qwerty"
|
||||
|
||||
#
|
||||
# Basic keys
|
||||
#
|
||||
|
||||
map -caps -altgr -shift 0x29 0x02..0x0D ~ "`1234567890-="
|
||||
map -caps -altgr -shift 0x10..0x1B ~ "qwertyuiop[]"
|
||||
map -caps -altgr -shift 0x1E..0x28 0x2B ~ "asdfghjkl;'#"
|
||||
map -caps -altgr -shift 0x56 0x2C..0x35 ~ "\zxcvbnm,./"
|
||||
|
||||
map -caps -altgr +shift 0x29 0x02..0x0D ~ "¬!"£$%^&*()_+"
|
||||
map -caps -altgr +shift 0x10..0x1B ~ "QWERTYUIOP{}"
|
||||
map -caps -altgr +shift 0x1E..0x28 0x2B ~ "ASDFGHJKL:@~"
|
||||
map -caps -altgr +shift 0x56 0x2C..0x35 ~ "|ZXCVBNM<>?"
|
||||
|
||||
map +caps -altgr -shift 0x29 0x02..0x0D ~ "`1234567890-="
|
||||
map +caps -altgr -shift 0x10..0x1B ~ "QWERTYUIOP[]"
|
||||
map +caps -altgr -shift 0x1E..0x28 0x2B ~ "ASDFGHJKL;'#"
|
||||
map +caps -altgr -shift 0x56 0x2C..0x35 ~ "\ZXCVBNM,./"
|
||||
|
||||
map +caps -altgr +shift 0x29 0x02..0x0D ~ "¬!"£$%^&*()_+"
|
||||
map +caps -altgr +shift 0x10..0x1B ~ "qwertyuiop{}"
|
||||
map +caps -altgr +shift 0x1E..0x28 0x2B ~ "asdfghjkl:@~"
|
||||
map +caps -altgr +shift 0x56 0x2C..0x35 ~ "|zxcvbnm<>?"
|
||||
|
||||
#
|
||||
# Keys requiring AltGr (some of which are affected by Caps Lock)
|
||||
#
|
||||
|
||||
map +altgr -shift 0x29 ~ "¦"
|
||||
map +altgr -shift 0x05 ~ "€"
|
||||
|
||||
map -caps +altgr -shift 0x12 ~ "é"
|
||||
map -caps +altgr +shift 0x12 ~ "É"
|
||||
map -caps +altgr -shift 0x16 ~ "ú"
|
||||
map -caps +altgr +shift 0x16 ~ "Ú"
|
||||
map -caps +altgr -shift 0x17 ~ "í"
|
||||
map -caps +altgr +shift 0x17 ~ "Í"
|
||||
map -caps +altgr -shift 0x18 ~ "ó"
|
||||
map -caps +altgr +shift 0x18 ~ "Ó"
|
||||
map -caps +altgr -shift 0x1E ~ "á"
|
||||
map -caps +altgr +shift 0x1E ~ "Á"
|
||||
map -caps +altgr -shift 0x2E ~ "ç"
|
||||
map -caps +altgr +shift 0x2E ~ "Ç"
|
||||
|
||||
map +caps +altgr +shift 0x12 ~ "é"
|
||||
map +caps +altgr -shift 0x12 ~ "É"
|
||||
map +caps +altgr +shift 0x16 ~ "ú"
|
||||
map +caps +altgr -shift 0x16 ~ "Ú"
|
||||
map +caps +altgr +shift 0x17 ~ "í"
|
||||
map +caps +altgr -shift 0x17 ~ "Í"
|
||||
map +caps +altgr +shift 0x18 ~ "ó"
|
||||
map +caps +altgr -shift 0x18 ~ "Ó"
|
||||
map +caps +altgr +shift 0x1E ~ "á"
|
||||
map +caps +altgr -shift 0x1E ~ "Á"
|
||||
map +caps +altgr +shift 0x2E ~ "ç"
|
||||
map +caps +altgr -shift 0x2E ~ "Ç"
|
||||
|
42
src/protocols/spice/keymaps/en_us_qwerty.keymap
Normal file
42
src/protocols/spice/keymaps/en_us_qwerty.keymap
Normal file
@ -0,0 +1,42 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
parent "base"
|
||||
name "en-us-qwerty"
|
||||
|
||||
map -caps -shift 0x29 0x02..0x0D ~ "`1234567890-="
|
||||
map -caps -shift 0x10..0x1B 0x2B ~ "qwertyuiop[]\"
|
||||
map -caps -shift 0x1E..0x28 ~ "asdfghjkl;'"
|
||||
map -caps -shift 0x2C..0x35 ~ "zxcvbnm,./"
|
||||
|
||||
map -caps +shift 0x29 0x02..0x0D ~ "~!@#$%^&*()_+"
|
||||
map -caps +shift 0x10..0x1B 0x2B ~ "QWERTYUIOP{}|"
|
||||
map -caps +shift 0x1E..0x28 ~ "ASDFGHJKL:""
|
||||
map -caps +shift 0x2C..0x35 ~ "ZXCVBNM<>?"
|
||||
|
||||
map +caps -shift 0x29 0x02..0x0D ~ "`1234567890-="
|
||||
map +caps -shift 0x10..0x1B 0x2B ~ "QWERTYUIOP[]\"
|
||||
map +caps -shift 0x1E..0x28 ~ "ASDFGHJKL;'"
|
||||
map +caps -shift 0x2C..0x35 ~ "ZXCVBNM,./"
|
||||
|
||||
map +caps +shift 0x29 0x02..0x0D ~ "~!@#$%^&*()_+"
|
||||
map +caps +shift 0x10..0x1B 0x2B ~ "qwertyuiop{}|"
|
||||
map +caps +shift 0x1E..0x28 ~ "asdfghjkl:""
|
||||
map +caps +shift 0x2C..0x35 ~ "zxcvbnm<>?"
|
||||
|
63
src/protocols/spice/keymaps/es_es_qwerty.keymap
Normal file
63
src/protocols/spice/keymaps/es_es_qwerty.keymap
Normal file
@ -0,0 +1,63 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
parent "base"
|
||||
name "es-es-qwerty"
|
||||
|
||||
#
|
||||
# Basic keys
|
||||
#
|
||||
|
||||
map -caps -altgr -shift 0x29 0x02..0x0D ~ "º1234567890'¡"
|
||||
map -caps -altgr -shift 0x10..0x19 0x1B ~ "qwertyuiop+"
|
||||
map -caps -altgr -shift 0x1E..0x27 0x2B ~ "asdfghjklñç"
|
||||
map -caps -altgr -shift 0x56 0x2C..0x35 ~ "<zxcvbnm,.-"
|
||||
|
||||
map -caps -altgr +shift 0x29 0x02..0x0D ~ "ª!"·$%&/()=?¿"
|
||||
map -caps -altgr +shift 0x10..0x19 0x1B ~ "QWERTYUIOP*"
|
||||
map -caps -altgr +shift 0x1E..0x27 0x2B ~ "ASDFGHJKLÑÇ"
|
||||
map -caps -altgr +shift 0x56 0x2C..0x35 ~ ">ZXCVBNM;:_"
|
||||
|
||||
map +caps -altgr -shift 0x29 0x02..0x0D ~ "º1234567890'¡"
|
||||
map +caps -altgr -shift 0x10..0x19 0x1B ~ "QWERTYUIOP+"
|
||||
map +caps -altgr -shift 0x1E..0x27 0x2B ~ "ASDFGHJKLÑÇ"
|
||||
map +caps -altgr -shift 0x56 0x2C..0x35 ~ "<ZXCVBNM,.-"
|
||||
|
||||
map +caps -altgr +shift 0x29 0x02..0x0D ~ "ª!"·$%&/()=?¿"
|
||||
map +caps -altgr +shift 0x10..0x19 0x1B ~ "qwertyuiop*"
|
||||
map +caps -altgr +shift 0x1E..0x27 0x2B ~ "asdfghjklñç"
|
||||
map +caps -altgr +shift 0x56 0x2C..0x35 ~ ">zxcvbnm;:_"
|
||||
|
||||
#
|
||||
# Keys requiring AltGr
|
||||
#
|
||||
|
||||
map +altgr -shift 0x29 0x02..0x04 0x07 ~ "\|@#¬"
|
||||
map +altgr -shift 0x12 0x1A 0x1B ~ "€[]"
|
||||
map +altgr -shift 0x28 0x2B ~ "{}"
|
||||
|
||||
#
|
||||
# Dead keys
|
||||
#
|
||||
|
||||
map -altgr -shift 0x1A ~ 0xFE50 # Dead grave
|
||||
map -altgr -shift 0x28 ~ 0xFE51 # Dead acute
|
||||
map -altgr +shift 0x1A ~ 0xFE52 # Dead circumflex
|
||||
map +altgr -shift 0x05 ~ 0xFE53 # Dead tilde
|
||||
map -altgr +shift 0x28 ~ 0xFE57 # Dead diaeresis (umlaut)
|
63
src/protocols/spice/keymaps/es_latam_qwerty.keymap
Normal file
63
src/protocols/spice/keymaps/es_latam_qwerty.keymap
Normal file
@ -0,0 +1,63 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
parent "base"
|
||||
name "es-latam-qwerty"
|
||||
|
||||
#
|
||||
# Basic keys
|
||||
#
|
||||
|
||||
map -caps -altgr -shift 0x29 0x02..0x0D ~ "|1234567890'¿"
|
||||
map -caps -altgr -shift 0x10..0x19 0x1B ~ "qwertyuiop+"
|
||||
map -caps -altgr -shift 0x1E..0x28 0x2B ~ "asdfghjklñ{}"
|
||||
map -caps -altgr -shift 0x56 0x2C..0x35 ~ "<zxcvbnm,.-"
|
||||
|
||||
map -caps -altgr +shift 0x29 0x02..0x0D ~ "º!"#$%&/()=?¡"
|
||||
map -caps -altgr +shift 0x10..0x19 0x1B ~ "QWERTYUIOP*"
|
||||
map -caps -altgr +shift 0x1E..0x28 0x2B ~ "ASDFGHJKLÑ[]"
|
||||
map -caps -altgr +shift 0x56 0x2C..0x35 ~ ">ZXCVBNM;:_"
|
||||
|
||||
map +caps -altgr -shift 0x29 0x02..0x0D ~ "|1234567890'¿"
|
||||
map +caps -altgr -shift 0x10..0x19 0x1B ~ "QWERTYUIOP+"
|
||||
map +caps -altgr -shift 0x1E..0x28 0x2B ~ "ASDFGHJKLÑ{}"
|
||||
map +caps -altgr -shift 0x56 0x2C..0x35 ~ "<ZXCVBNM,.-"
|
||||
|
||||
map +caps -altgr +shift 0x29 0x02..0x0D ~ "º!"#$%&/()=?¡"
|
||||
map +caps -altgr +shift 0x10..0x19 0x1B ~ "qwertyuiop*"
|
||||
map +caps -altgr +shift 0x1E..0x28 0x2B ~ "asdfghjklñ[]"
|
||||
map +caps -altgr +shift 0x56 0x2C..0x35 ~ ">zxcvbnm;:_"
|
||||
|
||||
#
|
||||
# Keys requiring AltGr
|
||||
#
|
||||
|
||||
map +altgr -shift 0x29 0x0C ~ "¬\"
|
||||
map +altgr -shift 0x10 ~ "€"
|
||||
map +altgr -shift 0x28 ~ "^"
|
||||
|
||||
#
|
||||
# Dead keys
|
||||
#
|
||||
|
||||
map +altgr -shift 0x2B ~ 0xFE50 # Dead grave
|
||||
map -altgr -shift 0x1A ~ 0xFE51 # Dead acute
|
||||
map -altgr +shift 0x1A ~ 0xFE57 # Dead diaeresis (umlaut)
|
||||
map +altgr -shift 0x1B ~ 0xFE53 # Dead tilde
|
||||
|
22
src/protocols/spice/keymaps/failsafe.keymap
Normal file
22
src/protocols/spice/keymaps/failsafe.keymap
Normal file
@ -0,0 +1,22 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
parent "base"
|
||||
name "failsafe"
|
||||
|
76
src/protocols/spice/keymaps/fr_be_azerty.keymap
Normal file
76
src/protocols/spice/keymaps/fr_be_azerty.keymap
Normal file
@ -0,0 +1,76 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
parent "base"
|
||||
name "fr-be-azerty"
|
||||
|
||||
#
|
||||
# Basic keys
|
||||
#
|
||||
|
||||
map -caps -altgr -shift 0x29 0x02..0x0D ~ "²&é"'(§è!çà)-"
|
||||
map -caps -altgr -shift 0x10..0x19 0x1B ~ "azertyuiop$"
|
||||
map -caps -altgr -shift 0x1E..0x28 0x2B ~ "qsdfghjklmùµ"
|
||||
map -caps -altgr -shift 0x56 0x2C..0x35 ~ "<wxcvbn,;:="
|
||||
|
||||
map -caps -altgr +shift 0x29 0x02..0x0D ~ "³1234567890°_"
|
||||
map -caps -altgr +shift 0x10..0x19 0x1B ~ "AZERTYUIOP£"
|
||||
map -caps -altgr +shift 0x1E..0x28 0x2B ~ "QSDFGHJKLM%£"
|
||||
map -caps -altgr +shift 0x56 0x2C..0x35 ~ ">WXCVBN?./+"
|
||||
|
||||
map +caps -altgr -shift 0x29 0x02..0x0D ~ "²1234567890°_"
|
||||
map +caps -altgr -shift 0x10..0x19 0x1B ~ "AZERTYUIOP£"
|
||||
map +caps -altgr -shift 0x1E..0x28 0x2B ~ "QSDFGHJKLM%£"
|
||||
map +caps -altgr -shift 0x56 0x2C..0x35 ~ "<WXCVBN?./+"
|
||||
|
||||
map +caps -altgr +shift 0x29 0x02..0x0D ~ "³&é"'(§è!çà)-"
|
||||
map +caps -altgr +shift 0x10..0x19 0x1B ~ "azertyuiop$"
|
||||
map +caps -altgr +shift 0x1E..0x28 0x2B ~ "qsdfghjklmùµ"
|
||||
map +caps -altgr +shift 0x56 0x2C..0x35 ~ ">wxcvbn,;:="
|
||||
|
||||
#
|
||||
# Keys requiring AltGr (unaffected by Caps Lock, but Shift must not be pressed)
|
||||
#
|
||||
|
||||
map +altgr -shift 0x02..0x04 ~ "|@#"
|
||||
map +altgr -shift 0x0A..0x0B ~ "{}"
|
||||
map +altgr -shift 0x1A..0x1B ~ "[]"
|
||||
|
||||
map +altgr -shift 0x12 ~ "€"
|
||||
map +altgr -shift 0x56 ~ "\"
|
||||
map +altgr -shift 0x07 ~ "^"
|
||||
|
||||
#
|
||||
# Dead keys requiring AltGr (unaffected by Caps Lock or Shift)
|
||||
#
|
||||
|
||||
map +altgr 0x35 ~ 0xFE53 # Dead tilde
|
||||
map +altgr 0x28 ~ 0xFE51 # Dead acute
|
||||
map +altgr 0x2B ~ 0xFE50 # Dead grave
|
||||
|
||||
#
|
||||
# Dead keys (affected by Caps Lock and Shift)
|
||||
#
|
||||
|
||||
map -caps -altgr -shift 0x1A ~ 0xFE52 # Dead circumflex
|
||||
map -caps -altgr +shift 0x1A ~ 0xFE57 # Dead umlaut
|
||||
|
||||
map +caps -altgr -shift 0x1A ~ 0xFE57 # Dead umlaut
|
||||
map +caps -altgr +shift 0x1A ~ 0xFE52 # Dead circumflex
|
||||
|
54
src/protocols/spice/keymaps/fr_ca_qwerty.keymap
Normal file
54
src/protocols/spice/keymaps/fr_ca_qwerty.keymap
Normal file
@ -0,0 +1,54 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
parent "base"
|
||||
name "fr-ca-qwerty"
|
||||
|
||||
#
|
||||
# Basic keys
|
||||
#
|
||||
|
||||
map -altgr -shift 0x29 0x02..0x0D ~ "#1234567890-="
|
||||
map -altgr -shift 0x10..0x1B 0x2B ~ "qwertyuiop^¸<"
|
||||
map -altgr -shift 0x1E..0x28 ~ "asdfghjkl;`"
|
||||
map -altgr -shift 0x2C..0x35 ~ "zxcvbnm,.é"
|
||||
|
||||
map -altgr +shift 0x29 0x02..0x0D ~ "|!"/$%?&*()_+"
|
||||
map -altgr +shift 0x10..0x1B 0x2B ~ "QWERTYUIOP^¨>"
|
||||
map -altgr +shift 0x1E..0x28 ~ "ASDFGHJKL:`"
|
||||
map -altgr +shift 0x2C..0x35 ~ "ZXCVBNM'.É"
|
||||
|
||||
#
|
||||
# Keys requiring AltGr
|
||||
#
|
||||
|
||||
map +altgr -shift 0x29 0x02..0x0D ~ "\±@£¢¤¬¦²³¼½¾"
|
||||
map +altgr -shift 0x18..0x1B 0x2B ~ "§¶[]}"
|
||||
map +altgr -shift 0x27..0x28 ~ "~{"
|
||||
map +altgr -shift 0x32..0x33 0x35 ~ "µ¯´"
|
||||
|
||||
#
|
||||
# Combined accents
|
||||
#
|
||||
|
||||
map -altgr -shift 0x1A ~ 0x0302 # COMBINING CIRCUMFLEX ACCENT
|
||||
map -altgr -shift 0x1B ~ 0x0327 # COMBINING CEDILLA
|
||||
map -altgr +shift 0x1B ~ 0x0308 # COMBINING DIAERESIS
|
||||
map -altgr -shift 0x28 ~ 0x0300 # COMBINING GRAVE ACCENT
|
||||
map +altgr -shift 0x35 ~ 0x0301 # COMBINING ACUTE ACCENT
|
68
src/protocols/spice/keymaps/fr_ch_qwertz.keymap
Normal file
68
src/protocols/spice/keymaps/fr_ch_qwertz.keymap
Normal file
@ -0,0 +1,68 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
parent "base"
|
||||
name "fr-ch-qwertz"
|
||||
|
||||
#
|
||||
# Basic keys
|
||||
#
|
||||
|
||||
map -caps -altgr -shift 0x29 0x02..0x0C ~ "§1234567890'"
|
||||
map -caps -altgr -shift 0x10..0x1A ~ "qwertzuiopè"
|
||||
map -caps -altgr -shift 0x1E..0x28 0x2B ~ "asdfghjkléà$"
|
||||
map -caps -altgr -shift 0x56 0x2C..0x35 ~ "<yxcvbnm,.-"
|
||||
|
||||
map -caps -altgr +shift 0x29 0x02..0x0C ~ "°+"*ç%&/()=?"
|
||||
map -caps -altgr +shift 0x10..0x1B ~ "QWERTZUIOPü!"
|
||||
map -caps -altgr +shift 0x1E..0x28 0x2B ~ "ASDFGHJKLöä£"
|
||||
map -caps -altgr +shift 0x56 0x2C..0x35 ~ ">YXCVBNM;:_"
|
||||
|
||||
map +caps -altgr -shift 0x29 0x02..0x0C ~ "§1234567890'"
|
||||
map +caps -altgr -shift 0x10..0x1A ~ "QWERTZUIOPè"
|
||||
map +caps -altgr -shift 0x1E..0x28 0x2B ~ "ASDFGHJKLéà$"
|
||||
map +caps -altgr -shift 0x56 0x2C..0x35 ~ "<YXCVBNM,.-"
|
||||
|
||||
map +caps -altgr +shift 0x29 0x02..0x0C ~ "°+"*ç%&/()=?"
|
||||
map +caps -altgr +shift 0x10..0x1B ~ "qwertzuiopü!"
|
||||
map +caps -altgr +shift 0x1E..0x28 0x2B ~ "asdfghjklöä£"
|
||||
map +caps -altgr +shift 0x56 0x2C..0x35 ~ ">yxcvbnm;:_"
|
||||
|
||||
#
|
||||
# Keys requiring AltGr
|
||||
#
|
||||
|
||||
map +altgr -shift 0x02..0x04 ~ "¦@#"
|
||||
map +altgr -shift 0x07..0x09 ~ "¬|¢"
|
||||
map +altgr -shift 0x1A 0x1B ~ "[]"
|
||||
map +altgr -shift 0x28 0x2B ~ "{}"
|
||||
map +altgr -shift 0x56 ~ "\"
|
||||
|
||||
map +altgr -shift 0x12 ~ "€"
|
||||
|
||||
#
|
||||
# Dead keys
|
||||
#
|
||||
|
||||
map -altgr -shift 0x1B ~ 0xFE57 # Dead umlaut
|
||||
map +altgr -shift 0x0C ~ 0xFE51 # Dead acute
|
||||
map -altgr -shift 0x0D ~ 0xFE52 # Dead circumflex
|
||||
map -altgr +shift 0x0D ~ 0xFE50 # Dead grave
|
||||
map +altgr -shift 0x0D ~ 0xFE53 # Dead tilde
|
||||
|
65
src/protocols/spice/keymaps/fr_fr_azerty.keymap
Normal file
65
src/protocols/spice/keymaps/fr_fr_azerty.keymap
Normal file
@ -0,0 +1,65 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
parent "base"
|
||||
name "fr-fr-azerty"
|
||||
|
||||
#
|
||||
# Basic keys
|
||||
#
|
||||
|
||||
map -caps -altgr -shift 0x29 0x02..0x0D ~ "²&é"'(-è_çà)="
|
||||
map -caps -altgr -shift 0x10..0x19 0x1B ~ "azertyuiop$"
|
||||
map -caps -altgr -shift 0x1E..0x28 0x2B ~ "qsdfghjklmù*"
|
||||
map -caps -altgr -shift 0x56 0x2C..0x35 ~ "<wxcvbn,;:!"
|
||||
|
||||
map -caps -altgr +shift 0x02..0x0D ~ "1234567890°+"
|
||||
map -caps -altgr +shift 0x10..0x19 0x1B ~ "AZERTYUIOP£"
|
||||
map -caps -altgr +shift 0x1E..0x28 0x2B ~ "QSDFGHJKLM%µ"
|
||||
map -caps -altgr +shift 0x56 0x2C..0x35 ~ ">WXCVBN?./§"
|
||||
|
||||
map +caps -altgr -shift 0x29 0x02..0x0D ~ "²1234567890°+"
|
||||
map +caps -altgr -shift 0x10..0x19 0x1B ~ "AZERTYUIOP£"
|
||||
map +caps -altgr -shift 0x1E..0x28 0x2B ~ "QSDFGHJKLM%µ"
|
||||
map +caps -altgr -shift 0x56 0x2C..0x35 ~ "<WXCVBN?./§"
|
||||
|
||||
map +caps -altgr +shift 0x02..0x0D ~ "&é"'(-è_çà)="
|
||||
map +caps -altgr +shift 0x10..0x19 0x1B ~ "azertyuiop$"
|
||||
map +caps -altgr +shift 0x1E..0x28 0x2B ~ "qsdfghjklmù*"
|
||||
map +caps -altgr +shift 0x56 0x2C..0x35 ~ ">wxcvbn,;:!"
|
||||
|
||||
#
|
||||
# Keys requiring AltGr (unaffected by Caps Lock, but Shift must not be pressed)
|
||||
#
|
||||
|
||||
map +altgr -shift 0x03..0x0D ~ "~#{[|`\^@]}"
|
||||
|
||||
map +altgr -shift 0x12 ~ "€"
|
||||
map +altgr -shift 0x1B ~ "¤"
|
||||
|
||||
#
|
||||
# Dead keys (affected by Caps Lock and Shift)
|
||||
#
|
||||
|
||||
map -caps -altgr -shift 0x1A ~ 0xFE52 # Dead circumflex
|
||||
map -caps -altgr +shift 0x1A ~ 0xFE57 # Dead umlaut
|
||||
|
||||
map +caps -altgr -shift 0x1A ~ 0xFE57 # Dead umlaut
|
||||
map +caps -altgr +shift 0x1A ~ 0xFE52 # Dead circumflex
|
||||
|
253
src/protocols/spice/keymaps/generate.pl
Executable file
253
src/protocols/spice/keymaps/generate.pl
Executable file
@ -0,0 +1,253 @@
|
||||
#!/usr/bin/env perl
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
#
|
||||
# generate.pl
|
||||
#
|
||||
# Parse .keymap files, producing corresponding .c files that can be included
|
||||
# into the Spice plugin source.
|
||||
#
|
||||
|
||||
# We need at least Perl 5.8 for Unicode's sake
|
||||
use 5.008;
|
||||
|
||||
sub keymap_symbol {
|
||||
my $name = shift;
|
||||
$name =~ s/-/_/g;
|
||||
return 'guac_spice_keymap_' . $name;
|
||||
}
|
||||
|
||||
#
|
||||
# _generated_keymaps.c
|
||||
#
|
||||
|
||||
my @keymaps = ();
|
||||
|
||||
open OUTPUT, ">", "_generated_keymaps.c";
|
||||
print OUTPUT
|
||||
'#include "config.h"' . "\n"
|
||||
. '#include "keymap.h"' . "\n"
|
||||
. "\n"
|
||||
. '#include <stddef.h>' . "\n"
|
||||
. '#include <spice-client-glib-2.0/spice-client.h>' . "\n"
|
||||
. "\n";
|
||||
|
||||
for my $filename (@ARGV) {
|
||||
|
||||
my $content = "";
|
||||
my $parent = "";
|
||||
my $layout_name = "";
|
||||
|
||||
# Parse file
|
||||
open INPUT, '<', "$filename";
|
||||
binmode INPUT, ":encoding(utf8)";
|
||||
while (<INPUT>) {
|
||||
|
||||
chomp;
|
||||
|
||||
# Comments
|
||||
if (m/^\s*#/) {}
|
||||
|
||||
# Name
|
||||
elsif ((my $name) = m/^\s*name\s+"(.*)"\s*(?:#.*)?$/) {
|
||||
$layout_name = $name;
|
||||
}
|
||||
|
||||
# Parent map
|
||||
elsif ((my $name) = m/^\s*parent\s+"(.*)"\s*(?:#.*)?$/) {
|
||||
$parent = keymap_symbol($name);
|
||||
}
|
||||
|
||||
# Map
|
||||
elsif ((my $range, my $onto) =
|
||||
m/^\s*map\s+([^~]*)\s+~\s+(".*"|0x[0-9A-Fa-f]+)\s*(?:#.*)?$/) {
|
||||
|
||||
my @keysyms = ();
|
||||
my @scancodes = ();
|
||||
|
||||
my $ext_flags = 0;
|
||||
my $set_shift = 0;
|
||||
my $set_altgr = 0;
|
||||
my $set_caps = 0;
|
||||
my $set_num = 0;
|
||||
|
||||
my $clear_shift = 0;
|
||||
my $clear_altgr = 0;
|
||||
my $clear_caps = 0;
|
||||
my $clear_num = 0;
|
||||
|
||||
# Parse ranges and options
|
||||
foreach $_ (split(/\s+/, $range)) {
|
||||
|
||||
# Set option/modifier
|
||||
if ((my $opt) = m/^\+([a-z]+)$/) {
|
||||
if ($opt eq "shift") { $set_shift = 1; }
|
||||
elsif ($opt eq "altgr") { $set_altgr = 1; }
|
||||
elsif ($opt eq "caps") { $set_caps = 1; }
|
||||
elsif ($opt eq "num") { $set_num = 1; }
|
||||
elsif ($opt eq "ext") { $ext_flags = 1; }
|
||||
else {
|
||||
die "$filename: $.: ERROR: "
|
||||
. "Invalid set option\n";
|
||||
}
|
||||
}
|
||||
|
||||
# Clear option/modifier
|
||||
elsif ((my $opt) = m/^-([a-z]+)$/) {
|
||||
if ($opt eq "shift") { $clear_shift = 1; }
|
||||
elsif ($opt eq "altgr") { $clear_altgr = 1; }
|
||||
elsif ($opt eq "caps") { $clear_caps = 1; }
|
||||
elsif ($opt eq "num") { $clear_num = 1; }
|
||||
else {
|
||||
die "$filename: $.: ERROR: "
|
||||
. "Invalid clear option\n";
|
||||
}
|
||||
}
|
||||
|
||||
# Single scancode
|
||||
elsif ((my $scancode) = m/^(0x[0-9A-Fa-f]+)$/) {
|
||||
$scancodes[++$#scancodes] = hex($scancode);
|
||||
}
|
||||
|
||||
# Range of scancodes
|
||||
elsif ((my $start, my $end) =
|
||||
m/^(0x[0-9A-Fa-f]+)\.\.(0x[0-9A-Fa-f]+)$/) {
|
||||
for (my $i=hex($start); $i<=hex($end); $i++) {
|
||||
$scancodes[++$#scancodes] = $i;
|
||||
}
|
||||
}
|
||||
|
||||
# Invalid token
|
||||
else {
|
||||
die "$filename: $.: ERROR: "
|
||||
. "Invalid token\n";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# Parse onto
|
||||
if ($onto =~ m/^0x/) {
|
||||
$keysyms[0] = hex($onto);
|
||||
}
|
||||
else {
|
||||
foreach my $char (split('',
|
||||
substr($onto, 1, length($onto)-2))) {
|
||||
my $codepoint = ord($char);
|
||||
if ($codepoint >= 0x0100) {
|
||||
$keysyms[++$#keysyms] = 0x01000000 | $codepoint;
|
||||
}
|
||||
else {
|
||||
$keysyms[++$#keysyms] = $codepoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Check mapping
|
||||
if ($#keysyms != $#scancodes) {
|
||||
die "$filename: $.: ERROR: "
|
||||
. "Keysym and scancode range lengths differ\n";
|
||||
}
|
||||
|
||||
# Write keysym/scancode pairs
|
||||
for (my $i=0; $i<=$#keysyms; $i++) {
|
||||
|
||||
$content .= " {"
|
||||
. " .keysym = " . $keysyms[$i] . ","
|
||||
. " .scancode = " . $scancodes[$i];
|
||||
|
||||
# Modifiers that must be active
|
||||
$content .= ", .set_modifiers = 0";
|
||||
$content .= " | GUAC_SPICE_KEYMAP_MODIFIER_SHIFT" if $set_shift;
|
||||
$content .= " | GUAC_SPICE_KEYMAP_MODIFIER_ALTGR" if $set_altgr;
|
||||
|
||||
# Modifiers that must be inactive
|
||||
$content .= ", .clear_modifiers = 0";
|
||||
$content .= " | GUAC_SPICE_KEYMAP_MODIFIER_SHIFT" if $clear_shift;
|
||||
$content .= " | GUAC_SPICE_KEYMAP_MODIFIER_ALTGR" if $clear_altgr;
|
||||
|
||||
# Locks that must be set
|
||||
$content .= ", .set_locks = 0";
|
||||
$content .= " | SPICE_INPUTS_NUM_LOCK" if $set_num;
|
||||
$content .= " | SPICE_INPUTS_CAPS_LOCK" if $set_caps;
|
||||
|
||||
# Locks that must NOT be set
|
||||
$content .= ", .clear_locks = 0";
|
||||
$content .= " | SPICE_INPUTS_NUM_LOCK" if $clear_num;
|
||||
$content .= " | SPICE_INPUTS_CAPS_LOCK" if $clear_caps;
|
||||
|
||||
$content .= " },\n";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# Invalid token
|
||||
elsif (m/\S/) {
|
||||
die "$filename: $.: ERROR: "
|
||||
. "Invalid token\n";
|
||||
}
|
||||
|
||||
}
|
||||
close INPUT;
|
||||
|
||||
# Header
|
||||
my $sym = keymap_symbol($layout_name);
|
||||
print OUTPUT
|
||||
"\n"
|
||||
. '/* Autogenerated from ' . $filename . ' */' . "\n"
|
||||
. 'static guac_spice_keysym_desc __' . $sym . '[] = {' . "\n"
|
||||
. $content
|
||||
. ' {0}' . "\n"
|
||||
. '};' . "\n";
|
||||
|
||||
# Desc header
|
||||
print OUTPUT "\n"
|
||||
. 'static const guac_spice_keymap ' . $sym . ' = { ' . "\n";
|
||||
|
||||
# Layout name
|
||||
print OUTPUT " .name = \"$layout_name\",\n";
|
||||
|
||||
# Parent layout (if any)
|
||||
if ($parent) {
|
||||
print OUTPUT " .parent = &$parent,\n";
|
||||
}
|
||||
|
||||
# Desc footer
|
||||
print OUTPUT
|
||||
' .mapping = __' . $sym . "\n"
|
||||
. '};' . "\n";
|
||||
|
||||
$keymaps[++$#keymaps] = $sym;
|
||||
print STDERR "Added: $layout_name\n";
|
||||
|
||||
}
|
||||
|
||||
print OUTPUT "\n"
|
||||
. 'const guac_spice_keymap* GUAC_SPICE_KEYMAPS[] = {' . "\n";
|
||||
|
||||
foreach my $keymap (@keymaps) {
|
||||
print OUTPUT " &$keymap,\n";
|
||||
}
|
||||
print OUTPUT
|
||||
' NULL' . "\n"
|
||||
. '};' . "\n";
|
||||
|
||||
close OUTPUT;
|
||||
|
108
src/protocols/spice/keymaps/hu_hu_qwertz.keymap
Normal file
108
src/protocols/spice/keymaps/hu_hu_qwertz.keymap
Normal file
@ -0,0 +1,108 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
parent "base"
|
||||
name "hu-hu-qwertz"
|
||||
|
||||
#
|
||||
# Basic keys
|
||||
#
|
||||
|
||||
map -caps -altgr -shift 0x29 0x02..0x0D ~ "0123456789öüó"
|
||||
map -caps -altgr -shift 0x10..0x1B ~ "qwertzuıopőú"
|
||||
map -caps -altgr -shift 0x1E..0x28 0x2B ~ "asdfghjkléáű"
|
||||
map -caps -altgr -shift 0x56 0x2C..0x35 ~ "íyxcvbnm,.-"
|
||||
|
||||
map -caps -altgr +shift 0x29 0x02..0x0D ~ "§'"+!%/=()ÖÜÓ"
|
||||
map -caps -altgr +shift 0x10..0x1B ~ "QWERTZUIOPŐÚ"
|
||||
map -caps -altgr +shift 0x1E..0x28 0x2B ~ "ASDFGHJKLÉÁŰ"
|
||||
map -caps -altgr +shift 0x56 0x2C..0x35 ~ "ÍYXCVBNM?:_"
|
||||
|
||||
map +caps -altgr -shift 0x29 0x02..0x0D ~ "0123456789ÖÜÓ"
|
||||
map +caps -altgr -shift 0x10..0x1B ~ "QWERTZUIOPŐÚ"
|
||||
map +caps -altgr -shift 0x1E..0x28 0x2B ~ "ASDFGHJKLÉÁŰ"
|
||||
map +caps -altgr -shift 0x56 0x2C..0x35 ~ "ÍYXCVBNM,.-"
|
||||
|
||||
map +caps -altgr +shift 0x29 0x02..0x0D ~ "§'"+!%/=()öüó"
|
||||
map +caps -altgr +shift 0x10..0x1B ~ "qwertzuiopőú"
|
||||
map +caps -altgr +shift 0x1E..0x28 0x2B ~ "asdfghjkléáű"
|
||||
map +caps -altgr +shift 0x56 0x2C..0x35 ~ "íyxcvbnm?:_"
|
||||
|
||||
#
|
||||
# Keys requiring AltGr
|
||||
#
|
||||
|
||||
map +altgr -shift 0x02 ~ "~"
|
||||
map +altgr -shift 0x08 ~ "`"
|
||||
|
||||
map +altgr -shift 0x10 ~ "\"
|
||||
map +altgr -shift 0x11 ~ "|"
|
||||
map +altgr -shift 0x12 ~ "Ä"
|
||||
map +altgr -shift 0x16 ~ "€"
|
||||
map +altgr -shift 0x17 ~ "Í"
|
||||
map +altgr -shift 0x1A ~ "÷"
|
||||
map +altgr -shift 0x1B ~ "×"
|
||||
|
||||
map +altgr -shift 0x1E ~ "ä"
|
||||
map +altgr -shift 0x1F ~ "đ"
|
||||
map +altgr -shift 0x20 ~ "Đ"
|
||||
map +altgr -shift 0x21 ~ "["
|
||||
map +altgr -shift 0x22 ~ "]"
|
||||
map +altgr -shift 0x24 ~ "í"
|
||||
map +altgr -shift 0x25 ~ "ł"
|
||||
map +altgr -shift 0x26 ~ "Ł"
|
||||
map +altgr -shift 0x27 ~ "$"
|
||||
map +altgr -shift 0x28 ~ "ß"
|
||||
map +altgr -shift 0x2B ~ "¤"
|
||||
|
||||
map +altgr -shift 0x56 ~ "<"
|
||||
map +altgr -shift 0x2C ~ ">"
|
||||
map +altgr -shift 0x2D ~ "#"
|
||||
map +altgr -shift 0x2E ~ "&"
|
||||
map +altgr -shift 0x2F ~ "@"
|
||||
map +altgr -shift 0x30 ~ "{"
|
||||
map +altgr -shift 0x31 ~ "}"
|
||||
map +altgr -shift 0x32 ~ "<"
|
||||
map +altgr -shift 0x33 ~ ";"
|
||||
map +altgr -shift 0x34 ~ ">"
|
||||
map +altgr -shift 0x35 ~ "*"
|
||||
|
||||
|
||||
#
|
||||
# Keys requiring AltGr & Shift
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# Dead keys
|
||||
#
|
||||
|
||||
map +altgr -shift 0x03 ~ 0xFE5A # Dead caron
|
||||
map +altgr -shift 0x04 ~ 0xFE52 # Dead circumflex
|
||||
map +altgr -shift 0x05 ~ 0xFE55 # Dead breve
|
||||
map +altgr -shift 0x06 ~ 0xFE58 # Dead abovering
|
||||
map +altgr -shift 0x07 ~ 0xFE5C # Dead ogonek
|
||||
map +altgr -shift 0x09 ~ 0xFE56 # Dead abovedot
|
||||
map +altgr -shift 0x0A ~ 0xFE51 # Dead acute
|
||||
map +altgr -shift 0x0B ~ 0xFE59 # Dead doubleacute
|
||||
map +altgr -shift 0x0C ~ 0xFE57 # Dead diaeresis
|
||||
map +altgr -shift 0x0D ~ 0xFE5B # Dead cedilla
|
||||
|
||||
|
||||
# END
|
59
src/protocols/spice/keymaps/it_it_qwerty.keymap
Normal file
59
src/protocols/spice/keymaps/it_it_qwerty.keymap
Normal file
@ -0,0 +1,59 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
parent "base"
|
||||
name "it-it-qwerty"
|
||||
|
||||
#
|
||||
# Basic keys
|
||||
#
|
||||
|
||||
map -caps -altgr -shift 0x29 0x02..0x0D ~ "\1234567890'ì"
|
||||
map -caps -altgr -shift 0x10..0x1B ~ "qwertyuiopè+"
|
||||
map -caps -altgr -shift 0x1E..0x28 0x2B ~ "asdfghjklòàù"
|
||||
map -caps -altgr -shift 0x56 0x2C..0x35 ~ "<zxcvbnm,.-"
|
||||
|
||||
map -caps -altgr +shift 0x29 0x02..0x0D ~ "|!"£$%&/()=?^"
|
||||
map -caps -altgr +shift 0x10..0x1B ~ "QWERTYUIOPé*"
|
||||
map -caps -altgr +shift 0x1E..0x28 0x2B ~ "ASDFGHJKLç°§"
|
||||
map -caps -altgr +shift 0x56 0x2C..0x35 ~ ">ZXCVBNM;:_"
|
||||
|
||||
map +caps -altgr -shift 0x29 0x02..0x0D ~ "\1234567890'ì"
|
||||
map +caps -altgr -shift 0x10..0x1B ~ "QWERTYUIOPè+"
|
||||
map +caps -altgr -shift 0x1E..0x28 0x2B ~ "ASDFGHJKLòàù"
|
||||
map +caps -altgr -shift 0x56 0x2C..0x35 ~ "<ZXCVBNM,.-"
|
||||
|
||||
map +caps -altgr +shift 0x29 0x02..0x0D ~ "|!"£$%&/()=?^"
|
||||
map +caps -altgr +shift 0x10..0x1B ~ "qwertyuiopé*"
|
||||
map +caps -altgr +shift 0x1E..0x28 0x2B ~ "asdfghjklç°§"
|
||||
map +caps -altgr +shift 0x56 0x2C..0x35 ~ ">zxcvbnm;:_"
|
||||
|
||||
#
|
||||
# Keys requiring AltGr
|
||||
#
|
||||
|
||||
map +altgr -shift 0x12 ~ "€"
|
||||
map +altgr -shift 0x1A ~ "["
|
||||
map +altgr -shift 0x1B ~ "]"
|
||||
map +altgr -shift 0x27 ~ "@"
|
||||
map +altgr -shift 0x28 ~ "#"
|
||||
|
||||
map +altgr +shift 0x1A ~ "{"
|
||||
map +altgr +shift 0x1B ~ "}"
|
||||
|
35
src/protocols/spice/keymaps/ja_jp_qwerty.keymap
Normal file
35
src/protocols/spice/keymaps/ja_jp_qwerty.keymap
Normal file
@ -0,0 +1,35 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
parent "base"
|
||||
name "ja-jp-qwerty"
|
||||
|
||||
map -shift 0x02..0x0D 0x7D ~ "1234567890-^\"
|
||||
map -shift 0x10..0x1B ~ "qwertyuiop@["
|
||||
map -shift 0x1E..0x28 0x2B ~ "asdfghjkl;:]"
|
||||
map -shift 0x2C..0x35 0x73 ~ "zxcvbnm,./\"
|
||||
|
||||
map +shift 0x02..0x0A 0x0C 0x0D 0x7D ~ "!"#$%&'()=~|"
|
||||
map +shift 0x10..0x1B ~ "QWERTYUIOP`{"
|
||||
map +shift 0x1E..0x28 0x2B ~ "ASDFGHJKL+*}"
|
||||
map +shift 0x2C..0x35 0x73 ~ "ZXCVBNM<>?_"
|
||||
|
||||
map -shift 0x29 ~ 0xFF28
|
||||
map -shift 0x29 ~ 0xFF2A
|
||||
map +shift 0x29 ~ 0xFF29
|
75
src/protocols/spice/keymaps/no_no_qwerty.keymap
Normal file
75
src/protocols/spice/keymaps/no_no_qwerty.keymap
Normal file
@ -0,0 +1,75 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
parent "base"
|
||||
name "no-no-qwerty"
|
||||
|
||||
#
|
||||
# Basic keys
|
||||
#
|
||||
|
||||
map -caps -altgr -shift 0x29 0x02..0x0C ~ "|1234567890+"
|
||||
map -caps -altgr -shift 0x10..0x1A ~ "qwertyuiopå"
|
||||
map -caps -altgr -shift 0x1E..0x28 0x2B ~ "asdfghjkløæ'"
|
||||
map -caps -altgr -shift 0x56 0x2C..0x35 ~ "<zxcvbnm,.-"
|
||||
|
||||
map -caps -altgr +shift 0x29 0x02..0x0C ~ "|!"#¤%&/()=?"
|
||||
map -caps -altgr +shift 0x10..0x1A ~ "QWERTYUIOPÅ"
|
||||
map -caps -altgr +shift 0x1E..0x28 0x2B ~ "ASDFGHJKLØÆ*"
|
||||
map -caps -altgr +shift 0x56 0x2C..0x35 ~ ">ZXCVBNM;:_"
|
||||
|
||||
map +caps -altgr -shift 0x29 0x02..0x0C ~ "|1234567890+"
|
||||
map +caps -altgr -shift 0x10..0x1A ~ "QWERTYUIOPÅ"
|
||||
map +caps -altgr -shift 0x1E..0x28 0x2B ~ "ASDFGHJKLØÆ'"
|
||||
map +caps -altgr -shift 0x56 0x2C..0x35 ~ "<ZXCVBNM,.-"
|
||||
|
||||
map +caps -altgr +shift 0x29 0x02..0x0C ~ "|!"#¤%&/()=?"
|
||||
map +caps -altgr +shift 0x10..0x1A ~ "qwertyuiopå"
|
||||
map +caps -altgr +shift 0x1E..0x28 0x2B ~ "asdfghjkløæ*"
|
||||
map +caps -altgr +shift 0x56 0x2C..0x35 ~ ">zxcvbnm;:_"
|
||||
|
||||
map -altgr -shift 0x0D ~ "\"
|
||||
|
||||
#
|
||||
# Keys requiring AltGr
|
||||
#
|
||||
|
||||
map +altgr -shift 0x03 ~ "@"
|
||||
map +altgr -shift 0x04 ~ "£"
|
||||
map +altgr -shift 0x05 ~ "$"
|
||||
map +altgr -shift 0x08 ~ "{"
|
||||
map +altgr -shift 0x09 ~ "["
|
||||
map +altgr -shift 0x0A ~ "]"
|
||||
map +altgr -shift 0x0B ~ "}"
|
||||
map +altgr -shift 0x56 ~ "\"
|
||||
|
||||
map +altgr -shift 0x12 ~ "€"
|
||||
|
||||
map +altgr -shift 0x0D ~ "|"
|
||||
map +altgr -shift 0x32 ~ "µ"
|
||||
|
||||
#
|
||||
# Dead keys
|
||||
#
|
||||
|
||||
map +altgr -shift 0x0D ~ 0xFE51 # Dead acute
|
||||
map -altgr +shift 0x0D ~ 0xFE50 # Dead grave
|
||||
map -altgr -shift 0x1B ~ 0xFE57 # Dead umlaut
|
||||
map -altgr +shift 0x1B ~ 0xFE52 # Dead circumflex
|
||||
map +altgr -shift 0x1B ~ 0xFE53 # Dead tilde
|
63
src/protocols/spice/keymaps/pl_pl_qwerty.keymap
Normal file
63
src/protocols/spice/keymaps/pl_pl_qwerty.keymap
Normal file
@ -0,0 +1,63 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
parent "base"
|
||||
name "pl-pl-qwerty"
|
||||
|
||||
map -caps -shift 0x29 0x02..0x0D ~ "`1234567890-="
|
||||
map -caps -shift 0x10..0x1B 0x2B ~ "qwertyuiop[]\"
|
||||
map -caps -shift 0x1E..0x28 ~ "asdfghjkl;'"
|
||||
map -caps -shift 0x2C..0x35 ~ "zxcvbnm,./"
|
||||
|
||||
map -caps +shift 0x29 0x02..0x0D ~ "~!@#$%^&*()_+"
|
||||
map -caps +shift 0x10..0x1B 0x2B ~ "QWERTYUIOP{}|"
|
||||
map -caps +shift 0x1E..0x28 ~ "ASDFGHJKL:""
|
||||
map -caps +shift 0x2C..0x35 ~ "ZXCVBNM<>?"
|
||||
|
||||
map +caps -shift 0x29 0x02..0x0D ~ "`1234567890-="
|
||||
map +caps -shift 0x10..0x1B 0x2B ~ "QWERTYUIOP[]\"
|
||||
map +caps -shift 0x1E..0x28 ~ "ASDFGHJKL;'"
|
||||
map +caps -shift 0x2C..0x35 ~ "ZXCVBNM,./"
|
||||
|
||||
map +caps +shift 0x29 0x02..0x0D ~ "~!@#$%^&*()_+"
|
||||
map +caps +shift 0x10..0x1B 0x2B ~ "qwertyuiop{}|"
|
||||
map +caps +shift 0x1E..0x28 ~ "asdfghjkl:""
|
||||
map +caps +shift 0x2C..0x35 ~ "zxcvbnm<>?"
|
||||
|
||||
#
|
||||
# Keys requiring AltGr
|
||||
#
|
||||
|
||||
map +altgr -shift 0x16 ~ "€"
|
||||
|
||||
map -caps -shift +altgr 0x12 0x18 ~ "ęó"
|
||||
map -caps -shift +altgr 0x1E 0x1F 0x26 ~ "ąśł"
|
||||
map -caps -shift +altgr 0x2C 0x2D 0x2E 0x31 ~ "żźćń"
|
||||
|
||||
map -caps +shift +altgr 0x12 0x18 ~ "ĘÓ"
|
||||
map -caps +shift +altgr 0x1E 0x1F 0x26 ~ "ĄŚŁ"
|
||||
map -caps +shift +altgr 0x2C 0x2D 0x2E 0x31 ~ "ŻŹĆŃ"
|
||||
|
||||
map +caps -shift +altgr 0x12 0x18 ~ "ĘÓ"
|
||||
map +caps -shift +altgr 0x1E 0x1F 0x26 ~ "ĄŚŁ"
|
||||
map +caps -shift +altgr 0x2C 0x2D 0x2E 0x31 ~ "ŻŹĆŃ"
|
||||
|
||||
map +caps +shift +altgr 0x12 0x18 ~ "ęó"
|
||||
map +caps +shift +altgr 0x1E 0x1F 0x26 ~ "ąśł"
|
||||
map +caps +shift +altgr 0x2C 0x2D 0x2E 0x31 ~ "żźćń"
|
66
src/protocols/spice/keymaps/pt_br_qwerty.keymap
Normal file
66
src/protocols/spice/keymaps/pt_br_qwerty.keymap
Normal file
@ -0,0 +1,66 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
parent "base"
|
||||
name "pt-br-qwerty"
|
||||
|
||||
#
|
||||
# Basic keys
|
||||
#
|
||||
|
||||
map -caps -altgr -shift 0x29 0x02..0x0D ~ "'1234567890-="
|
||||
map -caps -altgr -shift 0x10..0x19 0x1B ~ "qwertyuiop["
|
||||
map -caps -altgr -shift 0x1E..0x27 0x2B ~ "asdfghjklç]"
|
||||
map -caps -altgr -shift 0x56 0x2C..0x35 0x73 ~ "\zxcvbnm,.;/"
|
||||
|
||||
map -caps -altgr +shift 0x29 0x02..0x06 0x08..0x0D ~ ""!@#$%&*()_+"
|
||||
map -caps -altgr +shift 0x10..0x19 0x1B ~ "QWERTYUIOP{"
|
||||
map -caps -altgr +shift 0x1E..0x27 0x2B ~ "ASDFGHJKLÇ}"
|
||||
map -caps -altgr +shift 0x56 0x2C..0x35 0x73 ~ "|ZXCVBNM<>:?"
|
||||
|
||||
map +caps -altgr -shift 0x29 0x02..0x0D ~ "'1234567890-="
|
||||
map +caps -altgr -shift 0x10..0x19 0x1B ~ "QWERTYUIOP["
|
||||
map +caps -altgr -shift 0x1E..0x27 0x2B ~ "ASDFGHJKLÇ]"
|
||||
map +caps -altgr -shift 0x56 0x2C..0x35 0x73 ~ "\ZXCVBNM,.;/"
|
||||
|
||||
map +caps -altgr +shift 0x29 0x02..0x06 0x08..0x0D ~ ""!@#$%&*()_+"
|
||||
map +caps -altgr +shift 0x10..0x19 0x1B ~ "qwertyuiop{"
|
||||
map +caps -altgr +shift 0x1E..0x27 0x2B ~ "asdfghjklç}"
|
||||
map +caps -altgr +shift 0x56 0x2C..0x35 0x73 ~ "|zxcvbnm<>:?"
|
||||
|
||||
#
|
||||
# Keys requiring AltGr
|
||||
#
|
||||
|
||||
map +altgr -shift 0x02..0x07 0x0D ~ "¹²³£¢¬§"
|
||||
map +altgr -shift 0x10..0x11 ~ "/?"
|
||||
map +altgr -shift 0x12 ~ "°"
|
||||
map +altgr -shift 0x1B ~ "ª"
|
||||
map +altgr -shift 0x2B ~ "º"
|
||||
map +altgr -shift 0x2E ~ "₢"
|
||||
|
||||
#
|
||||
# Dead keys
|
||||
#
|
||||
|
||||
map -altgr +shift 0x07 ~ 0xFE57 # Dead diaeresis (umlaut)
|
||||
map -altgr +shift 0x1A ~ 0xFE50 # Dead grave
|
||||
map -altgr -shift 0x1A ~ 0xFE51 # Dead acute
|
||||
map -altgr +shift 0x28 ~ 0xFE52 # Dead circumflex
|
||||
map -altgr -shift 0x28 ~ 0xFE53 # Dead tilde
|
74
src/protocols/spice/keymaps/sv_se_qwerty.keymap
Normal file
74
src/protocols/spice/keymaps/sv_se_qwerty.keymap
Normal file
@ -0,0 +1,74 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
parent "base"
|
||||
name "sv-se-qwerty"
|
||||
|
||||
#
|
||||
# Basic keys
|
||||
#
|
||||
|
||||
map -caps -altgr -shift 0x29 0x02..0x0C ~ "§1234567890+"
|
||||
map -caps -altgr -shift 0x10..0x1A ~ "qwertyuiopå"
|
||||
map -caps -altgr -shift 0x1E..0x28 0x2B ~ "asdfghjklöä'"
|
||||
map -caps -altgr -shift 0x56 0x2C..0x35 ~ "<zxcvbnm,.-"
|
||||
|
||||
map -caps -altgr +shift 0x29 0x02..0x0C ~ "½!"#¤%&/()=?"
|
||||
map -caps -altgr +shift 0x10..0x1A ~ "QWERTYUIOPÅ"
|
||||
map -caps -altgr +shift 0x1E..0x28 0x2B ~ "ASDFGHJKLÖÄ*"
|
||||
map -caps -altgr +shift 0x56 0x2C..0x35 ~ ">ZXCVBNM;:_"
|
||||
|
||||
map +caps -altgr -shift 0x29 0x02..0x0C ~ "§1234567890+"
|
||||
map +caps -altgr -shift 0x10..0x1A ~ "QWERTYUIOPÅ"
|
||||
map +caps -altgr -shift 0x1E..0x28 0x2B ~ "ASDFGHJKLÖÄ'"
|
||||
map +caps -altgr -shift 0x56 0x2C..0x35 ~ "<ZXCVBNM,.-"
|
||||
|
||||
map +caps -altgr +shift 0x29 0x02..0x0C ~ "½!"#¤%&/()=?"
|
||||
map +caps -altgr +shift 0x10..0x1A ~ "qwertyuiopå"
|
||||
map +caps -altgr +shift 0x1E..0x28 0x2B ~ "asdfghjklöä*"
|
||||
map +caps -altgr +shift 0x56 0x2C..0x35 ~ ">zxcvbnm;:_"
|
||||
|
||||
#
|
||||
# Keys requiring AltGr
|
||||
#
|
||||
|
||||
map +altgr -shift 0x03 ~ "@"
|
||||
map +altgr -shift 0x04 ~ "£"
|
||||
map +altgr -shift 0x05 ~ "$"
|
||||
map +altgr -shift 0x08 ~ "{"
|
||||
map +altgr -shift 0x09 ~ "["
|
||||
map +altgr -shift 0x0A ~ "]"
|
||||
map +altgr -shift 0x0B ~ "}"
|
||||
map +altgr -shift 0x0C ~ "\"
|
||||
|
||||
map +altgr -shift 0x12 ~ "€"
|
||||
|
||||
map +altgr -shift 0x56 ~ "|"
|
||||
map +altgr -shift 0x32 ~ "µ"
|
||||
|
||||
#
|
||||
# Dead keys
|
||||
#
|
||||
|
||||
map -altgr -shift 0x0D ~ 0xFE51 # Dead acute
|
||||
map -altgr +shift 0x0D ~ 0xFE50 # Dead grave
|
||||
map -altgr -shift 0x1B ~ 0xFE57 # Dead umlaut
|
||||
map -altgr +shift 0x1B ~ 0xFE52 # Dead circumflex
|
||||
map +altgr -shift 0x1B ~ 0xFE53 # Dead tilde
|
||||
|
92
src/protocols/spice/keymaps/tr_tr_qwerty.keymap
Normal file
92
src/protocols/spice/keymaps/tr_tr_qwerty.keymap
Normal file
@ -0,0 +1,92 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
parent "base"
|
||||
name "tr-tr-qwerty"
|
||||
|
||||
#
|
||||
# Basic keys
|
||||
#
|
||||
|
||||
map -caps -altgr -shift 0x29 0x02..0x0D ~ ""1234567890*-"
|
||||
map -caps -altgr -shift 0x10..0x1B ~ "qwertyuıopğü"
|
||||
map -caps -altgr -shift 0x1E..0x28 0x2B ~ "asdfghjklşi,"
|
||||
map -caps -altgr -shift 0x56 0x2C..0x35 ~ "<zxcvbnmöç."
|
||||
|
||||
map -caps -altgr +shift 0x29 0x02..0x03 ~ "é!'"
|
||||
map -caps -altgr +shift 0x05..0x0D ~ "+%&/()=?_"
|
||||
map -caps -altgr +shift 0x10..0x1B ~ "QWERTYUIOPĞÜ"
|
||||
map -caps -altgr +shift 0x1E..0x28 0x2B ~ "ASDFGHJKLŞİ;"
|
||||
map -caps -altgr +shift 0x56 0x2C..0x35 ~ ">ZXCVBNMÖÇ:"
|
||||
|
||||
map +caps -altgr -shift 0x29 0x02..0x0D ~ ""1234567890*-"
|
||||
map +caps -altgr -shift 0x10..0x1B ~ "QWERTYUIOPĞÜ"
|
||||
map +caps -altgr -shift 0x1E..0x28 0x2B ~ "ASDFGHJKLŞİ,"
|
||||
map +caps -altgr -shift 0x56 0x2C..0x35 ~ "<ZXCVBNMÖÇ."
|
||||
|
||||
map +caps -altgr +shift 0x29 0x02..0x03 ~ "é!'"
|
||||
map +caps -altgr +shift 0x05..0x0D ~ "+%&/()=?_"
|
||||
map +caps -altgr +shift 0x10..0x1B ~ "qwertyuıopğü"
|
||||
map +caps -altgr +shift 0x1E..0x28 0x2B ~ "asdfghjklşi;"
|
||||
map +caps -altgr +shift 0x56 0x2C..0x35 ~ ">zxcvbnmöç:"
|
||||
|
||||
#
|
||||
# Keys requiring AltGr
|
||||
#
|
||||
|
||||
map +altgr -shift 0x29 0x02..0x06 ~ "<>£#$½"
|
||||
map +altgr -shift 0x08..0x0D ~ "{[]}\|"
|
||||
|
||||
map +altgr -shift 0x10 ~ "@"
|
||||
map +altgr -shift 0x12 ~ "€"
|
||||
map +altgr -shift 0x14 ~ "₺"
|
||||
map +altgr -shift 0x1F ~ "ß"
|
||||
|
||||
map +altgr -shift 0x56 ~ "|"
|
||||
|
||||
|
||||
#
|
||||
# Keys requiring AltGr and vary by Shift and Caps Lock
|
||||
#
|
||||
|
||||
map -caps +altgr -shift 0x17 ~ "i"
|
||||
map -caps +altgr -shift 0x1E ~ "æ"
|
||||
|
||||
map -caps +altgr +shift 0x17 ~ "İ"
|
||||
map -caps +altgr +shift 0x1E ~ "Æ"
|
||||
|
||||
map +caps +altgr -shift 0x17 ~ "İ"
|
||||
map +caps +altgr -shift 0x1E ~ "Æ"
|
||||
|
||||
map +caps +altgr +shift 0x1E ~ "æ"
|
||||
map +caps +altgr +shift 0x17 ~ "i"
|
||||
|
||||
#
|
||||
# Dead keys
|
||||
#
|
||||
|
||||
map -altgr +shift 0x04 ~ 0xFE52 # Dead circumflex
|
||||
|
||||
map +altgr -shift 0x1A ~ 0xFE57 # Dead diaeresis (umlaut)
|
||||
map +altgr -shift 0x1B ~ 0xFE53 # Dead tilde
|
||||
|
||||
map +altgr -shift 0x27 ~ 0xFE51 # Dead acute
|
||||
map +altgr -shift 0x2B ~ 0xFE50 # Dead grave
|
||||
|
||||
# END
|
67
src/protocols/spice/log.c
Normal file
67
src/protocols/spice/log.c
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "common/iconv.h"
|
||||
#include "common/surface.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/layer.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <spice-client-glib-2.0/spice-client.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <syslog.h>
|
||||
|
||||
void guac_spice_client_log_info(const char* format, ...) {
|
||||
|
||||
char message[2048];
|
||||
|
||||
/* Copy log message into buffer */
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsnprintf(message, sizeof(message), format, args);
|
||||
va_end(args);
|
||||
|
||||
/* Log to syslog */
|
||||
syslog(LOG_INFO, "%s", message);
|
||||
|
||||
}
|
||||
|
||||
void guac_spice_client_log_error(const char* format, ...) {
|
||||
|
||||
char message[2048];
|
||||
|
||||
/* Copy log message into buffer */
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsnprintf(message, sizeof(message), format, args);
|
||||
va_end(args);
|
||||
|
||||
/* Log to syslog */
|
||||
syslog(LOG_ERR, "%s", message);
|
||||
|
||||
}
|
||||
|
67
src/protocols/spice/log.h
Normal file
67
src/protocols/spice/log.h
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_SPICE_LOG_H
|
||||
#define GUAC_SPICE_LOG_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "common/iconv.h"
|
||||
#include "common/surface.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/layer.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <spice-client-glib-2.0/spice-client.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <syslog.h>
|
||||
|
||||
/**
|
||||
* Callback invoked by SPICE when an informational message needs to be
|
||||
* logged.
|
||||
*
|
||||
* @param format
|
||||
* A printf-style format string to log.
|
||||
*
|
||||
* @param ...
|
||||
* The values to use when filling the conversion specifiers within the
|
||||
* format string.
|
||||
*/
|
||||
void guac_spice_client_log_info(const char* format, ...);
|
||||
|
||||
/**
|
||||
* Callback invoked by SPICE when an error message needs to be logged.
|
||||
*
|
||||
* @param format
|
||||
* A printf-style format string to log.
|
||||
*
|
||||
* @param ...
|
||||
* The values to use when filling the conversion specifiers within the
|
||||
* format string.
|
||||
*/
|
||||
void guac_spice_client_log_error(const char* format, ...);
|
||||
|
||||
#endif /* GUAC_SPICE_LOG_H */
|
||||
|
628
src/protocols/spice/settings.c
Normal file
628
src/protocols/spice/settings.c
Normal file
@ -0,0 +1,628 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "argv.h"
|
||||
#include "client.h"
|
||||
#include "common/defaults.h"
|
||||
#include "settings.h"
|
||||
#include "spice-defaults.h"
|
||||
#include "spice-constants.h"
|
||||
|
||||
#include <guacamole/user.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <spice-client-glib-2.0/spice-client.h>
|
||||
|
||||
/* Client plugin arguments */
|
||||
const char* GUAC_SPICE_CLIENT_ARGS[] = {
|
||||
"hostname",
|
||||
"port",
|
||||
"tls",
|
||||
"tls-verify",
|
||||
"ca",
|
||||
"ca-file",
|
||||
"pubkey",
|
||||
"proxy",
|
||||
"read-only",
|
||||
"encodings",
|
||||
GUAC_SPICE_ARGV_USERNAME,
|
||||
GUAC_SPICE_ARGV_PASSWORD,
|
||||
"swap-red-blue",
|
||||
"color-depth",
|
||||
"cursor",
|
||||
"autoretry",
|
||||
"clipboard-encoding",
|
||||
|
||||
"enable-audio",
|
||||
"file-transfer",
|
||||
"file-directory",
|
||||
"file-transfer-ro",
|
||||
"server-layout",
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
"enable-sftp",
|
||||
"sftp-hostname",
|
||||
"sftp-host-key",
|
||||
"sftp-port",
|
||||
"sftp-username",
|
||||
"sftp-password",
|
||||
"sftp-private-key",
|
||||
"sftp-passphrase",
|
||||
"sftp-directory",
|
||||
"sftp-root-directory",
|
||||
"sftp-server-alive-interval",
|
||||
"sftp-disable-download",
|
||||
"sftp-disable-upload",
|
||||
#endif
|
||||
|
||||
"recording-path",
|
||||
"recording-name",
|
||||
"recording-exclude-output",
|
||||
"recording-exclude-mouse",
|
||||
"recording-include-keys",
|
||||
"create-recording-path",
|
||||
"disable-copy",
|
||||
"disable-paste",
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
enum SPICE_ARGS_IDX {
|
||||
|
||||
/**
|
||||
* The hostname of the SPICE server (or repeater) to connect to.
|
||||
*/
|
||||
IDX_HOSTNAME,
|
||||
|
||||
/**
|
||||
* The port of the SPICE server (or repeater) to connect to.
|
||||
*/
|
||||
IDX_PORT,
|
||||
|
||||
/**
|
||||
* Whether or not the connection to the SPICE server should be made via
|
||||
* TLS.
|
||||
*/
|
||||
IDX_TLS,
|
||||
|
||||
/**
|
||||
* The verification mode that should be used to validate TLS connections
|
||||
* to the SPICE server.
|
||||
*/
|
||||
IDX_TLS_VERIFY,
|
||||
|
||||
/**
|
||||
* One or more Base64-encoded certificates that will be used for TLS
|
||||
* verification.
|
||||
*/
|
||||
IDX_CA,
|
||||
|
||||
/**
|
||||
* A path to a file containing one or more certificates that will be used
|
||||
* when validating TLS connections.
|
||||
*/
|
||||
IDX_CA_FILE,
|
||||
|
||||
/**
|
||||
* The public key of the host for TLS verification.
|
||||
*/
|
||||
IDX_PUBKEY,
|
||||
|
||||
/**
|
||||
* The proxy server to connect through when connecting to the SPICE server.
|
||||
*/
|
||||
IDX_PROXY,
|
||||
|
||||
/**
|
||||
* "true" if this connection should be read-only (user input should be
|
||||
* dropped), "false" or blank otherwise.
|
||||
*/
|
||||
IDX_READ_ONLY,
|
||||
|
||||
/**
|
||||
* Space-separated list of encodings to use within the SPICE session. If not
|
||||
* specified, this will be:
|
||||
*
|
||||
* "zrle ultra copyrect hextile zlib corre rre raw".
|
||||
*/
|
||||
IDX_ENCODINGS,
|
||||
|
||||
/**
|
||||
* The username to send to the SPICE server if authentication is requested.
|
||||
*/
|
||||
IDX_USERNAME,
|
||||
|
||||
/**
|
||||
* The password to send to the SPICE server if authentication is requested.
|
||||
*/
|
||||
IDX_PASSWORD,
|
||||
|
||||
/**
|
||||
* "true" if the red and blue components of each color should be swapped,
|
||||
* "false" or blank otherwise. This is mainly used for SPICE servers that do
|
||||
* not properly handle colors.
|
||||
*/
|
||||
IDX_SWAP_RED_BLUE,
|
||||
|
||||
/**
|
||||
* The color depth to request, in bits.
|
||||
*/
|
||||
IDX_COLOR_DEPTH,
|
||||
|
||||
/**
|
||||
* "remote" if the cursor should be rendered on the server instead of the
|
||||
* client. All other values will default to local rendering.
|
||||
*/
|
||||
IDX_CURSOR,
|
||||
|
||||
/**
|
||||
* The number of connection attempts to make before giving up. By default,
|
||||
* this will be 0.
|
||||
*/
|
||||
IDX_AUTORETRY,
|
||||
|
||||
/**
|
||||
* The encoding to use for clipboard data sent to the SPICE server if we are
|
||||
* going to be deviating from the standard (which mandates ISO 8829-1).
|
||||
* Valid values are "ISO8829-1" (the only legal value with respect to the
|
||||
* SPICE standard), "UTF-8", "UTF-16", and "CP2252".
|
||||
*/
|
||||
IDX_CLIPBOARD_ENCODING,
|
||||
|
||||
/**
|
||||
* "true" if audio should be enabled, "false" or blank otherwise.
|
||||
*/
|
||||
IDX_ENABLE_AUDIO,
|
||||
|
||||
/**
|
||||
* "true" if file transfer should be enabled, "false" or blank otherwise.
|
||||
*/
|
||||
IDX_FILE_TRANSFER,
|
||||
|
||||
/**
|
||||
* The absolute path to the directory that should be shared from the system
|
||||
* running guacd to the spice server.
|
||||
*/
|
||||
IDX_FILE_DIRECTORY,
|
||||
|
||||
/**
|
||||
* Whether or not the shared directory should be read-only to the SPICE
|
||||
* server.
|
||||
*/
|
||||
IDX_FILE_TRANSFER_RO,
|
||||
|
||||
/**
|
||||
* The name of the keymap chosen as the layout of the server. Legal names
|
||||
* are defined within the *.keymap files in the "keymaps" directory of the
|
||||
* source for Guacamole's SPICE support.
|
||||
*/
|
||||
IDX_SERVER_LAYOUT,
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
/**
|
||||
* "true" if SFTP should be enabled for the SPICE connection, "false" or
|
||||
* blank otherwise.
|
||||
*/
|
||||
IDX_ENABLE_SFTP,
|
||||
|
||||
/**
|
||||
* The hostname of the SSH server to connect to for SFTP. If blank, the
|
||||
* hostname of the SPICE server will be used.
|
||||
*/
|
||||
IDX_SFTP_HOSTNAME,
|
||||
|
||||
/**
|
||||
* The public SSH host key to identify the SFTP server.
|
||||
*/
|
||||
IDX_SFTP_HOST_KEY,
|
||||
|
||||
/**
|
||||
* The port of the SSH server to connect to for SFTP. If blank, the default
|
||||
* SSH port of "22" will be used.
|
||||
*/
|
||||
IDX_SFTP_PORT,
|
||||
|
||||
/**
|
||||
* The username to provide when authenticating with the SSH server for
|
||||
* SFTP.
|
||||
*/
|
||||
IDX_SFTP_USERNAME,
|
||||
|
||||
/**
|
||||
* The password to provide when authenticating with the SSH server for
|
||||
* SFTP (if not using a private key).
|
||||
*/
|
||||
IDX_SFTP_PASSWORD,
|
||||
|
||||
/**
|
||||
* The base64-encoded private key to use when authenticating with the SSH
|
||||
* server for SFTP (if not using a password).
|
||||
*/
|
||||
IDX_SFTP_PRIVATE_KEY,
|
||||
|
||||
/**
|
||||
* The passphrase to use to decrypt the provided base64-encoded private
|
||||
* key.
|
||||
*/
|
||||
IDX_SFTP_PASSPHRASE,
|
||||
|
||||
/**
|
||||
* The default location for file uploads within the SSH server. This will
|
||||
* apply only to uploads which do not use the filesystem guac_object (where
|
||||
* the destination directory is otherwise ambiguous).
|
||||
*/
|
||||
IDX_SFTP_DIRECTORY,
|
||||
|
||||
/**
|
||||
* The path of the directory within the SSH server to expose as a
|
||||
* filesystem guac_object. If omitted, "/" will be used by default.
|
||||
*/
|
||||
IDX_SFTP_ROOT_DIRECTORY,
|
||||
|
||||
/**
|
||||
* The interval at which SSH keepalive messages are sent to the server for
|
||||
* SFTP connections. The default is 0 (disabling keepalives), and a value
|
||||
* of 1 is automatically incremented to 2 by libssh2 to avoid busy loop corner
|
||||
* cases.
|
||||
*/
|
||||
IDX_SFTP_SERVER_ALIVE_INTERVAL,
|
||||
|
||||
/**
|
||||
* If set to "true", file downloads over SFTP will be blocked. If set to
|
||||
* "false" or not set, file downloads will be allowed.
|
||||
*/
|
||||
IDX_SFTP_DISABLE_DOWNLOAD,
|
||||
|
||||
/**
|
||||
* If set to "true", file uploads over SFTP will be blocked. If set to
|
||||
* "false" or not set, file uploads will be allowed.
|
||||
*/
|
||||
IDX_SFTP_DISABLE_UPLOAD,
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The full absolute path to the directory in which screen recordings
|
||||
* should be written.
|
||||
*/
|
||||
IDX_RECORDING_PATH,
|
||||
|
||||
/**
|
||||
* The name that should be given to screen recordings which are written in
|
||||
* the given path.
|
||||
*/
|
||||
IDX_RECORDING_NAME,
|
||||
|
||||
/**
|
||||
* Whether output which is broadcast to each connected client (graphics,
|
||||
* streams, etc.) should NOT be included in the session recording. Output
|
||||
* is included by default, as it is necessary for any recording which must
|
||||
* later be viewable as video.
|
||||
*/
|
||||
IDX_RECORDING_EXCLUDE_OUTPUT,
|
||||
|
||||
/**
|
||||
* Whether changes to mouse state, such as position and buttons pressed or
|
||||
* released, should NOT be included in the session recording. Mouse state
|
||||
* is included by default, as it is necessary for the mouse cursor to be
|
||||
* rendered in any resulting video.
|
||||
*/
|
||||
IDX_RECORDING_EXCLUDE_MOUSE,
|
||||
|
||||
/**
|
||||
* Whether keys pressed and released should be included in the session
|
||||
* recording. Key events are NOT included by default within the recording,
|
||||
* as doing so has privacy and security implications. Including key events
|
||||
* may be necessary in certain auditing contexts, but should only be done
|
||||
* with caution. Key events can easily contain sensitive information, such
|
||||
* as passwords, credit card numbers, etc.
|
||||
*/
|
||||
IDX_RECORDING_INCLUDE_KEYS,
|
||||
|
||||
/**
|
||||
* Whether the specified screen recording path should automatically be
|
||||
* created if it does not yet exist.
|
||||
*/
|
||||
IDX_CREATE_RECORDING_PATH,
|
||||
|
||||
/**
|
||||
* Whether outbound clipboard access should be blocked. If set to "true",
|
||||
* it will not be possible to copy data from the remote desktop to the
|
||||
* client using the clipboard. By default, clipboard access is not blocked.
|
||||
*/
|
||||
IDX_DISABLE_COPY,
|
||||
|
||||
/**
|
||||
* Whether inbound clipboard access should be blocked. If set to "true", it
|
||||
* will not be possible to paste data from the client to the remote desktop
|
||||
* using the clipboard. By default, clipboard access is not blocked.
|
||||
*/
|
||||
IDX_DISABLE_PASTE,
|
||||
|
||||
SPICE_ARGS_COUNT
|
||||
};
|
||||
|
||||
guac_spice_settings* guac_spice_parse_args(guac_user* user,
|
||||
int argc, const char** argv) {
|
||||
|
||||
/* Validate arg count */
|
||||
if (argc != SPICE_ARGS_COUNT) {
|
||||
guac_user_log(user, GUAC_LOG_WARNING, "Incorrect number of connection "
|
||||
"parameters provided: expected %i, got %i.",
|
||||
SPICE_ARGS_COUNT, argc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
guac_spice_settings* settings = calloc(1, sizeof(guac_spice_settings));
|
||||
|
||||
settings->hostname =
|
||||
guac_user_parse_args_string(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_HOSTNAME, SPICE_DEFAULT_HOST);
|
||||
|
||||
settings->port =
|
||||
guac_user_parse_args_string(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_PORT, SPICE_DEFAULT_PORT);
|
||||
|
||||
settings->tls =
|
||||
guac_user_parse_args_boolean(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_TLS, false);
|
||||
|
||||
char* verify_mode = guac_user_parse_args_string(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_TLS_VERIFY, NULL);
|
||||
|
||||
if (verify_mode != NULL) {
|
||||
if (strcmp(verify_mode, GUAC_SPICE_PARAMETER_TLS_VERIFY_PUBKEY) == 0)
|
||||
settings->tls_verify = SPICE_SESSION_VERIFY_PUBKEY;
|
||||
else if (strcmp(verify_mode, GUAC_SPICE_PARAMETER_TLS_VERIFY_SUBJECT) == 0)
|
||||
settings->tls_verify = SPICE_SESSION_VERIFY_SUBJECT;
|
||||
}
|
||||
|
||||
else {
|
||||
settings->tls_verify = SPICE_SESSION_VERIFY_HOSTNAME;
|
||||
}
|
||||
|
||||
free(verify_mode);
|
||||
|
||||
settings->ca =
|
||||
guac_user_parse_args_string(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_CA, NULL);
|
||||
|
||||
settings->ca_file =
|
||||
guac_user_parse_args_string(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_CA_FILE, NULL);
|
||||
|
||||
settings->pubkey =
|
||||
guac_user_parse_args_string(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_PUBKEY, NULL);
|
||||
|
||||
settings->proxy =
|
||||
guac_user_parse_args_string(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_PROXY, NULL);
|
||||
|
||||
settings->username =
|
||||
guac_user_parse_args_string(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_USERNAME, NULL);
|
||||
|
||||
settings->password =
|
||||
guac_user_parse_args_string(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_PASSWORD, NULL);
|
||||
|
||||
/* Read-only mode */
|
||||
settings->read_only =
|
||||
guac_user_parse_args_boolean(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_READ_ONLY, false);
|
||||
|
||||
/* Parse color depth */
|
||||
settings->color_depth =
|
||||
guac_user_parse_args_int(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_COLOR_DEPTH, 0);
|
||||
|
||||
/* Set encodings if specified */
|
||||
settings->encodings =
|
||||
guac_user_parse_args_string(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_ENCODINGS,
|
||||
SPICE_DEFAULT_ENCODINGS);
|
||||
|
||||
/* Parse autoretry */
|
||||
settings->retries =
|
||||
guac_user_parse_args_int(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_AUTORETRY, 0);
|
||||
|
||||
/* Audio enable/disable */
|
||||
settings->audio_enabled =
|
||||
guac_user_parse_args_boolean(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_ENABLE_AUDIO, false);
|
||||
|
||||
/* File transfer enable/disable */
|
||||
settings->file_transfer =
|
||||
guac_user_parse_args_boolean(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_FILE_TRANSFER, false);
|
||||
|
||||
/* The directory on the guacd server to share */
|
||||
settings->file_directory =
|
||||
guac_user_parse_args_string(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_FILE_DIRECTORY, NULL);
|
||||
|
||||
/* Whether or not the share should be read-only. */
|
||||
settings->file_transfer_ro =
|
||||
guac_user_parse_args_boolean(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_FILE_TRANSFER_RO, false);
|
||||
|
||||
/* Pick keymap based on argument */
|
||||
settings->server_layout = NULL;
|
||||
if (argv[IDX_SERVER_LAYOUT][0] != '\0')
|
||||
settings->server_layout =
|
||||
guac_spice_keymap_find(argv[IDX_SERVER_LAYOUT]);
|
||||
|
||||
/* If no keymap requested, use default */
|
||||
if (settings->server_layout == NULL)
|
||||
settings->server_layout = guac_spice_keymap_find(GUAC_SPICE_DEFAULT_KEYMAP);
|
||||
|
||||
/* Set clipboard encoding if specified */
|
||||
settings->clipboard_encoding =
|
||||
guac_user_parse_args_string(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_CLIPBOARD_ENCODING, NULL);
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
/* SFTP enable/disable */
|
||||
settings->enable_sftp =
|
||||
guac_user_parse_args_boolean(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_ENABLE_SFTP, false);
|
||||
|
||||
/* Hostname for SFTP connection */
|
||||
settings->sftp_hostname =
|
||||
guac_user_parse_args_string(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_SFTP_HOSTNAME, settings->hostname);
|
||||
|
||||
/* The public SSH host key. */
|
||||
settings->sftp_host_key =
|
||||
guac_user_parse_args_string(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_SFTP_HOST_KEY, NULL);
|
||||
|
||||
/* Port for SFTP connection */
|
||||
settings->sftp_port =
|
||||
guac_user_parse_args_string(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_SFTP_PORT, SPICE_DEFAULT_SFTP_PORT);
|
||||
|
||||
/* Username for SSH/SFTP authentication */
|
||||
settings->sftp_username =
|
||||
guac_user_parse_args_string(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_SFTP_USERNAME, "");
|
||||
|
||||
/* Password for SFTP (if not using private key) */
|
||||
settings->sftp_password =
|
||||
guac_user_parse_args_string(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_SFTP_PASSWORD, "");
|
||||
|
||||
/* Private key for SFTP (if not using password) */
|
||||
settings->sftp_private_key =
|
||||
guac_user_parse_args_string(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_SFTP_PRIVATE_KEY, NULL);
|
||||
|
||||
/* Passphrase for decrypting the SFTP private key (if applicable */
|
||||
settings->sftp_passphrase =
|
||||
guac_user_parse_args_string(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_SFTP_PASSPHRASE, "");
|
||||
|
||||
/* Default upload directory */
|
||||
settings->sftp_directory =
|
||||
guac_user_parse_args_string(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_SFTP_DIRECTORY, NULL);
|
||||
|
||||
/* SFTP root directory */
|
||||
settings->sftp_root_directory =
|
||||
guac_user_parse_args_string(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_SFTP_ROOT_DIRECTORY, SPICE_DEFAULT_SFTP_ROOT);
|
||||
|
||||
/* Default keepalive value */
|
||||
settings->sftp_server_alive_interval =
|
||||
guac_user_parse_args_int(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_SFTP_SERVER_ALIVE_INTERVAL, 0);
|
||||
|
||||
settings->sftp_disable_download =
|
||||
guac_user_parse_args_boolean(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_SFTP_DISABLE_DOWNLOAD, false);
|
||||
|
||||
settings->sftp_disable_upload =
|
||||
guac_user_parse_args_boolean(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_SFTP_DISABLE_UPLOAD, false);
|
||||
#endif
|
||||
|
||||
/* Read recording path */
|
||||
settings->recording_path =
|
||||
guac_user_parse_args_string(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_RECORDING_PATH, NULL);
|
||||
|
||||
/* Read recording name */
|
||||
settings->recording_name =
|
||||
guac_user_parse_args_string(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_RECORDING_NAME, GUAC_SPICE_DEFAULT_RECORDING_NAME);
|
||||
|
||||
/* Parse output exclusion flag */
|
||||
settings->recording_exclude_output =
|
||||
guac_user_parse_args_boolean(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_RECORDING_EXCLUDE_OUTPUT, false);
|
||||
|
||||
/* Parse mouse exclusion flag */
|
||||
settings->recording_exclude_mouse =
|
||||
guac_user_parse_args_boolean(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_RECORDING_EXCLUDE_MOUSE, false);
|
||||
|
||||
/* Parse key event inclusion flag */
|
||||
settings->recording_include_keys =
|
||||
guac_user_parse_args_boolean(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_RECORDING_INCLUDE_KEYS, false);
|
||||
|
||||
/* Parse path creation flag */
|
||||
settings->create_recording_path =
|
||||
guac_user_parse_args_boolean(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_CREATE_RECORDING_PATH, false);
|
||||
|
||||
/* Parse clipboard copy disable flag */
|
||||
settings->disable_copy =
|
||||
guac_user_parse_args_boolean(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_DISABLE_COPY, false);
|
||||
|
||||
/* Parse clipboard paste disable flag */
|
||||
settings->disable_paste =
|
||||
guac_user_parse_args_boolean(user, GUAC_SPICE_CLIENT_ARGS, argv,
|
||||
IDX_DISABLE_PASTE, false);
|
||||
|
||||
return settings;
|
||||
|
||||
}
|
||||
|
||||
void guac_spice_settings_free(guac_spice_settings* settings) {
|
||||
|
||||
/* Free settings strings */
|
||||
free(settings->clipboard_encoding);
|
||||
free(settings->encodings);
|
||||
free(settings->hostname);
|
||||
free(settings->password);
|
||||
free(settings->recording_name);
|
||||
free(settings->recording_path);
|
||||
free(settings->username);
|
||||
|
||||
#ifdef ENABLE_SPICE_REPEATER
|
||||
/* Free SPICE repeater settings */
|
||||
free(settings->dest_host);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
/* Free SFTP settings */
|
||||
free(settings->sftp_directory);
|
||||
free(settings->sftp_root_directory);
|
||||
free(settings->sftp_host_key);
|
||||
free(settings->sftp_hostname);
|
||||
free(settings->sftp_passphrase);
|
||||
free(settings->sftp_password);
|
||||
free(settings->sftp_port);
|
||||
free(settings->sftp_private_key);
|
||||
free(settings->sftp_username);
|
||||
#endif
|
||||
|
||||
/* Free settings structure */
|
||||
free(settings);
|
||||
|
||||
}
|
||||
|
323
src/protocols/spice/settings.h
Normal file
323
src/protocols/spice/settings.h
Normal file
@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GUAC_SPICE_SETTINGS_H
|
||||
#define GUAC_SPICE_SETTINGS_H
|
||||
|
||||
#include "config.h"
|
||||
#include "keymap.h"
|
||||
|
||||
#include <spice-client-glib-2.0/spice-client.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* The filename to use for the screen recording, if not specified.
|
||||
*/
|
||||
#define GUAC_SPICE_DEFAULT_RECORDING_NAME "recording"
|
||||
|
||||
/**
|
||||
* SPICE-specific client data.
|
||||
*/
|
||||
typedef struct guac_spice_settings {
|
||||
|
||||
/**
|
||||
* The hostname of the SPICE server (or repeater) to connect to.
|
||||
*/
|
||||
char* hostname;
|
||||
|
||||
/**
|
||||
* The port of the SPICE server (or repeater) to connect to.
|
||||
*/
|
||||
char* port;
|
||||
|
||||
/**
|
||||
* Whether or not TLS should be used to connect to the SPICE server.
|
||||
*/
|
||||
bool tls;
|
||||
|
||||
/**
|
||||
* The type of TLS validation that should be done for encrypted connections
|
||||
* to SPICE servers.
|
||||
*/
|
||||
SpiceSessionVerify tls_verify;
|
||||
|
||||
/**
|
||||
* One or more Base64-encoded certificates to use to validate TLS
|
||||
* connections to the SPICE server.
|
||||
*/
|
||||
char* ca;
|
||||
|
||||
/**
|
||||
* A path to a file containing one more certificates that will be used to
|
||||
* validate TLS connections.
|
||||
*/
|
||||
char* ca_file;
|
||||
|
||||
/**
|
||||
* The public key of the SPICE server for TLS verification.
|
||||
*/
|
||||
char* pubkey;
|
||||
|
||||
/**
|
||||
* SPICE supports connecting to remote servers via a proxy server. You can
|
||||
* specify the proxy server to use in this property.
|
||||
*/
|
||||
char* proxy;
|
||||
|
||||
/**
|
||||
* The username given in the arguments.
|
||||
*/
|
||||
char* username;
|
||||
|
||||
/**
|
||||
* The password given in the arguments.
|
||||
*/
|
||||
char* password;
|
||||
|
||||
/**
|
||||
* Space-separated list of encodings to use within the SPICE session.
|
||||
*/
|
||||
char* encodings;
|
||||
|
||||
/**
|
||||
* The color depth to request, in bits.
|
||||
*/
|
||||
int color_depth;
|
||||
|
||||
/**
|
||||
* Whether this connection is read-only, and user input should be dropped.
|
||||
*/
|
||||
bool read_only;
|
||||
|
||||
/**
|
||||
* Whether audio is enabled.
|
||||
*/
|
||||
bool audio_enabled;
|
||||
|
||||
/**
|
||||
* If file transfer capability should be enabled.
|
||||
*/
|
||||
bool file_transfer;
|
||||
|
||||
/**
|
||||
* The directory on the server where guacd is running that should be
|
||||
* shared.
|
||||
*/
|
||||
char* file_directory;
|
||||
|
||||
/**
|
||||
* If file transfer capability should be limited to read-only.
|
||||
*/
|
||||
bool file_transfer_ro;
|
||||
|
||||
/**
|
||||
* The keymap chosen as the layout of the server.
|
||||
*/
|
||||
const guac_spice_keymap* server_layout;
|
||||
|
||||
/**
|
||||
* The number of connection attempts to make before giving up.
|
||||
*/
|
||||
int retries;
|
||||
|
||||
/**
|
||||
* The encoding to use for clipboard data sent to the SPICE server, or NULL
|
||||
* to use the encoding required by the SPICE standard.
|
||||
*/
|
||||
char* clipboard_encoding;
|
||||
|
||||
/**
|
||||
* Whether outbound clipboard access should be blocked. If set, it will not
|
||||
* be possible to copy data from the remote desktop to the client using the
|
||||
* clipboard.
|
||||
*/
|
||||
bool disable_copy;
|
||||
|
||||
/**
|
||||
* Whether inbound clipboard access should be blocked. If set, it will not
|
||||
* be possible to paste data from the client to the remote desktop using
|
||||
* the clipboard.
|
||||
*/
|
||||
bool disable_paste;
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
/**
|
||||
* Whether SFTP should be enabled for the SPICE connection.
|
||||
*/
|
||||
bool enable_sftp;
|
||||
|
||||
/**
|
||||
* The hostname of the SSH server to connect to for SFTP.
|
||||
*/
|
||||
char* sftp_hostname;
|
||||
|
||||
/**
|
||||
* The public SSH host key.
|
||||
*/
|
||||
char* sftp_host_key;
|
||||
|
||||
/**
|
||||
* The port of the SSH server to connect to for SFTP.
|
||||
*/
|
||||
char* sftp_port;
|
||||
|
||||
/**
|
||||
* The username to provide when authenticating with the SSH server for
|
||||
* SFTP.
|
||||
*/
|
||||
char* sftp_username;
|
||||
|
||||
/**
|
||||
* The password to provide when authenticating with the SSH server for
|
||||
* SFTP (if not using a private key).
|
||||
*/
|
||||
char* sftp_password;
|
||||
|
||||
/**
|
||||
* The base64-encoded private key to use when authenticating with the SSH
|
||||
* server for SFTP (if not using a password).
|
||||
*/
|
||||
char* sftp_private_key;
|
||||
|
||||
/**
|
||||
* The passphrase to use to decrypt the provided base64-encoded private
|
||||
* key.
|
||||
*/
|
||||
char* sftp_passphrase;
|
||||
|
||||
/**
|
||||
* The default location for file uploads within the SSH server. This will
|
||||
* apply only to uploads which do not use the filesystem guac_object (where
|
||||
* the destination directory is otherwise ambiguous).
|
||||
*/
|
||||
char* sftp_directory;
|
||||
|
||||
/**
|
||||
* The path of the directory within the SSH server to expose as a
|
||||
* filesystem guac_object.
|
||||
*/
|
||||
char* sftp_root_directory;
|
||||
|
||||
/**
|
||||
* The interval at which SSH keepalive messages are sent to the server for
|
||||
* SFTP connections. The default is 0 (disabling keepalives), and a value
|
||||
* of 1 is automatically increased to 2 by libssh2 to avoid busy loop corner
|
||||
* cases.
|
||||
*/
|
||||
int sftp_server_alive_interval;
|
||||
|
||||
/**
|
||||
* Whether file downloads over SFTP should be blocked. If set to "true",
|
||||
* the local client will not be able to download files from the SFTP server.
|
||||
* If set to "false" or not set, file downloads will be allowed.
|
||||
*/
|
||||
bool sftp_disable_download;
|
||||
|
||||
/**
|
||||
* Whether file uploads over SFTP should be blocked. If set to "true", the
|
||||
* local client will not be able to upload files to the SFTP server. If set
|
||||
* to "false" or not set, file uploads will be allowed.
|
||||
*/
|
||||
bool sftp_disable_upload;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The path in which the screen recording should be saved, if enabled. If
|
||||
* no screen recording should be saved, this will be NULL.
|
||||
*/
|
||||
char* recording_path;
|
||||
|
||||
/**
|
||||
* The filename to use for the screen recording, if enabled.
|
||||
*/
|
||||
char* recording_name;
|
||||
|
||||
/**
|
||||
* Whether the screen recording path should be automatically created if it
|
||||
* does not already exist.
|
||||
*/
|
||||
bool create_recording_path;
|
||||
|
||||
/**
|
||||
* Whether output which is broadcast to each connected client (graphics,
|
||||
* streams, etc.) should NOT be included in the session recording. Output
|
||||
* is included by default, as it is necessary for any recording which must
|
||||
* later be viewable as video.
|
||||
*/
|
||||
bool recording_exclude_output;
|
||||
|
||||
/**
|
||||
* Whether changes to mouse state, such as position and buttons pressed or
|
||||
* released, should NOT be included in the session recording. Mouse state
|
||||
* is included by default, as it is necessary for the mouse cursor to be
|
||||
* rendered in any resulting video.
|
||||
*/
|
||||
bool recording_exclude_mouse;
|
||||
|
||||
/**
|
||||
* Whether keys pressed and released should be included in the session
|
||||
* recording. Key events are NOT included by default within the recording,
|
||||
* as doing so has privacy and security implications. Including key events
|
||||
* may be necessary in certain auditing contexts, but should only be done
|
||||
* with caution. Key events can easily contain sensitive information, such
|
||||
* as passwords, credit card numbers, etc.
|
||||
*/
|
||||
bool recording_include_keys;
|
||||
|
||||
} guac_spice_settings;
|
||||
|
||||
/**
|
||||
* Parses all given args, storing them in a newly-allocated settings object. If
|
||||
* the args fail to parse, NULL is returned.
|
||||
*
|
||||
* @param user
|
||||
* The user who submitted the given arguments while joining the
|
||||
* connection.
|
||||
*
|
||||
* @param argc
|
||||
* The number of arguments within the argv array.
|
||||
*
|
||||
* @param argv
|
||||
* The values of all arguments provided by the user.
|
||||
*
|
||||
* @return
|
||||
* A newly-allocated settings object which must be freed with
|
||||
* guac_spice_settings_free() when no longer needed. If the arguments fail
|
||||
* to parse, NULL is returned.
|
||||
*/
|
||||
guac_spice_settings* guac_spice_parse_args(guac_user* user,
|
||||
int argc, const char** argv);
|
||||
|
||||
/**
|
||||
* Frees the given guac_spice_settings object, having been previously allocated
|
||||
* via guac_spice_parse_args().
|
||||
*
|
||||
* @param settings
|
||||
* The settings object to free.
|
||||
*/
|
||||
void guac_spice_settings_free(guac_spice_settings* settings);
|
||||
|
||||
/**
|
||||
* NULL-terminated array of accepted client args.
|
||||
*/
|
||||
extern const char* GUAC_SPICE_CLIENT_ARGS[];
|
||||
|
||||
#endif /* SPICE_SETTINGS_H */
|
42
src/protocols/spice/sftp.c
Normal file
42
src/protocols/spice/sftp.c
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "common-ssh/sftp.h"
|
||||
#include "sftp.h"
|
||||
#include "spice.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/stream.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
int guac_spice_sftp_file_handler(guac_user* user, guac_stream* stream,
|
||||
char* mimetype, char* filename) {
|
||||
|
||||
guac_client* client = user->client;
|
||||
guac_spice_client* spice_client = (guac_spice_client*) client->data;
|
||||
guac_common_ssh_sftp_filesystem* filesystem = spice_client->sftp_filesystem;
|
||||
|
||||
/* Handle file upload */
|
||||
return guac_common_ssh_sftp_handle_file_stream(filesystem, user, stream,
|
||||
mimetype, filename);
|
||||
|
||||
}
|
||||
|
34
src/protocols/spice/sftp.h
Normal file
34
src/protocols/spice/sftp.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_SPICE_SFTP_H
|
||||
#define GUAC_SPICE_SFTP_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* Handles an incoming stream from a Guacamole "file" instruction, saving the
|
||||
* contents of that stream to the file having the given name.
|
||||
*/
|
||||
guac_user_file_handler guac_spice_sftp_file_handler;
|
||||
|
||||
#endif /* SPICE_SFTP_H */
|
||||
|
360
src/protocols/spice/spice-constants.h
Normal file
360
src/protocols/spice/spice-constants.h
Normal file
@ -0,0 +1,360 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef SPICE_CONSTANTS_H
|
||||
#define SPICE_CONSTANTS_H
|
||||
|
||||
/**
|
||||
* The key used to store and retrieve Guacamole-related data from within the
|
||||
* SPICE client structure.
|
||||
*/
|
||||
#define GUAC_SPICE_CLIENT_KEY "GUAC_SPICE"
|
||||
|
||||
/**
|
||||
* The default identifier of the pimary/main display.
|
||||
*/
|
||||
#define GUAC_SPICE_DEFAULT_DISPLAY_ID 0
|
||||
|
||||
/**
|
||||
* The TLS verification value from Guacamole Client that indicates that hostname
|
||||
* verification should be done.
|
||||
*/
|
||||
#define GUAC_SPICE_PARAMETER_TLS_VERIFY_HOSTNAME "hostname"
|
||||
|
||||
/**
|
||||
* The TLS verification value from Guacamole Client that indicates that public
|
||||
* key verification should be performed.
|
||||
*/
|
||||
#define GUAC_SPICE_PARAMETER_TLS_VERIFY_PUBKEY "pubkey"
|
||||
|
||||
/**
|
||||
* The TLS verification value from Guacamole Client that indicates that subject
|
||||
* verification should be performed.
|
||||
*/
|
||||
#define GUAC_SPICE_PARAMETER_TLS_VERIFY_SUBJECT "subject"
|
||||
|
||||
/**
|
||||
* The property within a SPICE client channel that indicates if the SPICE
|
||||
* agent is connected.
|
||||
*/
|
||||
#define SPICE_PROPERTY_AGENT_CONNECTED "agent-connected"
|
||||
|
||||
/**
|
||||
* The SPICE client property that defines CA certificates used to validate
|
||||
* the TLS connection to the SPICE server.
|
||||
*/
|
||||
#define SPICE_PROPERTY_CA "ca"
|
||||
|
||||
/**
|
||||
* The SPICE client property that defines a path on the server running guacd
|
||||
* to the file containing the certificate authority certificates to use to
|
||||
* validate the TLS connection to the SPICE server.
|
||||
*/
|
||||
#define SPICE_PROPERTY_CA_FILE "ca-file"
|
||||
|
||||
/**
|
||||
* The property that the SPICE client uses to set the image cache size. If
|
||||
* undefined a default of 0 will be used.
|
||||
*/
|
||||
#define SPICE_PROPERTY_CACHE_SIZE "cache-size"
|
||||
|
||||
/**
|
||||
* The SPICE client channel property that stores the identifier of the channel.
|
||||
*/
|
||||
#define SPICE_PROPERTY_CHANNEL_ID "channel-id"
|
||||
|
||||
/**
|
||||
* SPICE library property that determines whether or not the sockets are provided
|
||||
* by the client.
|
||||
*/
|
||||
#define SPICE_PROPERTY_CLIENT_SOCKETS "client-sockets"
|
||||
|
||||
/**
|
||||
* The property that tells the SPICE client the color depth to use when
|
||||
* allocating new displays.
|
||||
*/
|
||||
#define SPICE_PROPERTY_COLOR_DEPTH "color-depth"
|
||||
|
||||
/**
|
||||
* The property that tells the SPICE client to enable audio playback and
|
||||
* recording. The SPICE client default is TRUE.
|
||||
*/
|
||||
#define SPICE_PROPERTY_ENABLE_AUDIO "enable-audio"
|
||||
|
||||
/**
|
||||
* Property that enables or disables USB redirection.
|
||||
*/
|
||||
#define SPICE_PROPERTY_ENABLE_USBREDIR "enable-usbredir"
|
||||
|
||||
/**
|
||||
* The property that contains the hostname, IP address, or URL of the SPICE
|
||||
* server that the client should attempt to connect to.
|
||||
*/
|
||||
#define SPICE_PROPERTY_HOST "host"
|
||||
|
||||
/**
|
||||
* A read-only property exposed by the SPICE client library indicating the
|
||||
* current state of key modifiers - such as lock keys - on the server.
|
||||
*/
|
||||
#define SPICE_PROPERTY_KEY_MODIFIERS "key-modifiers"
|
||||
|
||||
/**
|
||||
* The property that indicates the minimum latency for audio playback.
|
||||
*/
|
||||
#define SPICE_PROPERTY_MIN_LATENCY "min-latency"
|
||||
|
||||
/**
|
||||
* The property used to toggle the playback and/or record
|
||||
* mute status on the SPICE server.
|
||||
*/
|
||||
#define SPICE_PROPERTY_MUTE "mute"
|
||||
|
||||
/**
|
||||
* The property used to get or set the number of audio playback and/or recording
|
||||
* channels that will be available between the SPICE server and client.
|
||||
*/
|
||||
#define SPICE_PROPERTY_NUM_CHANNELS "nchannels"
|
||||
|
||||
/**
|
||||
* The property used to tell the SPICE client the password to send on to the
|
||||
* SPICE server for authentication.
|
||||
*/
|
||||
#define SPICE_PROPERTY_PASSWORD "password"
|
||||
|
||||
/**
|
||||
* The property used to set the unencrypted communication port for communicating
|
||||
* with the SPICE server.
|
||||
*/
|
||||
#define SPICE_PROPERTY_PORT "port"
|
||||
|
||||
/**
|
||||
* The property that the SPICE client uses to set the proxy server that is used
|
||||
* to connect to the SPICE server.
|
||||
*/
|
||||
#define SPICE_PROPERTY_PROXY "proxy"
|
||||
|
||||
/**
|
||||
* The property used by the SPICE client to tell the server that the session
|
||||
* should be read-only.
|
||||
*/
|
||||
#define SPICE_PROPERTY_READ_ONLY "read-only"
|
||||
|
||||
/**
|
||||
* The property that the SPICE client uses to determine a local (to guacd)
|
||||
* directory that will be shared with the SPICE server.
|
||||
*/
|
||||
#define SPICE_PROPERTY_SHARED_DIR "shared-dir"
|
||||
|
||||
/**
|
||||
* The property that tells the SPICE client that the shared directory should be
|
||||
* read-only to the SPICE server and should not allow writes.
|
||||
*/
|
||||
#define SPICE_PROPERTY_SHARED_DIR_RO "share-dir-ro"
|
||||
|
||||
/**
|
||||
* The property within the SPICE client that is used to set the port used for
|
||||
* secure, TLS-based communication with the SPICE server.
|
||||
*/
|
||||
#define SPICE_PROPERTY_TLS_PORT "tls-port"
|
||||
|
||||
/**
|
||||
* The property that is used to set the username that the SPICE client will use
|
||||
* to authenticate with the server.
|
||||
*/
|
||||
#define SPICE_PROPERTY_USERNAME "username"
|
||||
|
||||
/**
|
||||
* The property that tells the SPICE client whether or not to verify the
|
||||
* certificate presented by the SPICE server in TLS communications.
|
||||
*/
|
||||
#define SPICE_PROPERTY_VERIFY "verify"
|
||||
|
||||
/**
|
||||
* The property used to get or set the playback and/or recording volume of audio
|
||||
* on the SPICE server to the remote client.
|
||||
*/
|
||||
#define SPICE_PROPERTY_VOLUME "volume"
|
||||
|
||||
/**
|
||||
* The signal sent by the SPICE client when a new channel is created.
|
||||
*/
|
||||
#define SPICE_SIGNAL_CHANNEL_NEW "channel-new"
|
||||
|
||||
/**
|
||||
* The signal sent by the SPICE client when a channel is destroyed.
|
||||
*/
|
||||
#define SPICE_SIGNAL_CHANNEL_DESTROY "channel-destroy"
|
||||
|
||||
/**
|
||||
* The signal sent by the SPICE client when an event occurs on a channel.
|
||||
*/
|
||||
#define SPICE_SIGNAL_CHANNEL_EVENT "channel-event"
|
||||
|
||||
/**
|
||||
* A signal that indicates that the cursor should be hidden from the display
|
||||
* area.
|
||||
*/
|
||||
#define SPICE_SIGNAL_CURSOR_HIDE "cursor-hide"
|
||||
|
||||
/**
|
||||
* A signal that indicates a change in position of the cursor in the display
|
||||
* area.
|
||||
*/
|
||||
#define SPICE_SIGNAL_CURSOR_MOVE "cursor-move"
|
||||
|
||||
/**
|
||||
* A signal that indicates the cursor should be reset to its default context.
|
||||
*/
|
||||
#define SPICE_SIGNAL_CURSOR_RESET "cursor-reset"
|
||||
|
||||
/**
|
||||
* A signal sent to modify cursor aspect and position within the display area.
|
||||
*/
|
||||
#define SPICE_SIGNAL_CURSOR_SET "cursor-set"
|
||||
|
||||
/**
|
||||
* The signal sent by the SPICE client when the client is disconnected from
|
||||
* the server.
|
||||
*/
|
||||
#define SPICE_SIGNAL_DISCONNECTED "disconnected"
|
||||
|
||||
/**
|
||||
* The signal sent to indicate that a region of the display should be updated.
|
||||
*/
|
||||
#define SPICE_SIGNAL_DISPLAY_INVALIDATE "display-invalidate"
|
||||
|
||||
/**
|
||||
* The signal that indicates that a display is ready to be exposed to the client.
|
||||
*/
|
||||
#define SPICE_SIGNAL_DISPLAY_MARK "display-mark"
|
||||
|
||||
/**
|
||||
* The signal indicating when the primary display data/buffer is ready.
|
||||
*/
|
||||
#define SPICE_SIGNAL_DISPLAY_PRIMARY_CREATE "display-primary-create"
|
||||
|
||||
/**
|
||||
* The signal indicating when the primary display surface should be freed and
|
||||
* not made available anymore.
|
||||
*/
|
||||
#define SPICE_SIGNAL_DISPLAY_PRIMARY_DESTROY "display-primary-destroy"
|
||||
|
||||
/**
|
||||
* The signal indicating that a rectangular region of he display is updated
|
||||
* and should be redrawn.
|
||||
*/
|
||||
#define SPICE_SIGNAL_GL_DRAW "gl-draw"
|
||||
|
||||
/**
|
||||
* The signal sent to indicate that the keyboard modifiers - such as lock keys -
|
||||
* have changed and should be updated.
|
||||
*/
|
||||
#define SPICE_SIGNAL_INPUTS_MODIFIERS "inputs-modifiers"
|
||||
|
||||
/**
|
||||
* The signal sent by the SPICE client when the connected status or capabilities
|
||||
* of a channel change.
|
||||
*/
|
||||
#define SPICE_SIGNAL_MAIN_AGENT_UPDATE "main-agent-update"
|
||||
|
||||
/**
|
||||
* Signal fired by the SPICE client when clipboard selection data is available.
|
||||
*/
|
||||
#define SPICE_SIGNAL_MAIN_CLIPBOARD_SELECTION "main-clipboard-selection"
|
||||
|
||||
/**
|
||||
* A signal fired by the SPICE client when clipboard selection data is available
|
||||
* from the guest, and of what type.
|
||||
*/
|
||||
#define SPICE_SIGNAL_MAIN_CLIPBOARD_SELECTION_GRAB "main-clipboard-selection-grab"
|
||||
|
||||
/**
|
||||
* A signal fired by the SPICE client when clipboard selection data is no longer
|
||||
* available from the guest.
|
||||
*/
|
||||
#define SPICE_SIGNAL_MAIN_CLIPBOARD_SELECTION_RELEASE "main-clipboard-selection-release"
|
||||
|
||||
/**
|
||||
* A signal used to request clipboard data from the client.
|
||||
*/
|
||||
#define SPICE_SIGNAL_MAIN_CLIPBOARD_SELECTION_REQUEST "main-clipboard-selection-request"
|
||||
|
||||
/**
|
||||
* A signal used to indicate that the mouse mode has changed.
|
||||
*/
|
||||
#define SPICE_SIGNAL_MAIN_MOUSE_UPDATE "main-mouse-update"
|
||||
|
||||
/**
|
||||
* A signal sent by the SPICE client when the server has indicated that live
|
||||
* migration has started.
|
||||
*/
|
||||
#define SPICE_SIGNAL_MIGRATION_STARTED "migration-started"
|
||||
|
||||
/**
|
||||
* The signal sent by the SPICE client when a MM time discontinuity is
|
||||
* detected.
|
||||
*/
|
||||
#define SPICE_SIGNAL_MM_TIME_RESET "mm-time-reset"
|
||||
|
||||
/**
|
||||
* The signal fired by the SPICE client when a new file transfer task has been
|
||||
* initiated.
|
||||
*/
|
||||
#define SPICE_SIGNAL_NEW_FILE_TRANSFER "new-file-transfer"
|
||||
|
||||
/**
|
||||
* The signal fired when data is available to be played on the client, which
|
||||
* contains a pointer to the data to be played.
|
||||
*/
|
||||
#define SPICE_SIGNAL_PLAYBACK_DATA "playback-data"
|
||||
|
||||
/**
|
||||
* A signal sent when the server is requesting the current audio playback delay.
|
||||
*/
|
||||
#define SPICE_SIGNAL_PLAYBACK_GET_DELAY "playback-get-delay"
|
||||
|
||||
/**
|
||||
* A signal sent when the server is notifying the client that audio playback
|
||||
* should begin, which also contains characteristics of that audio data.
|
||||
*/
|
||||
#define SPICE_SIGNAL_PLAYBACK_START "plaback-start"
|
||||
|
||||
/**
|
||||
* A signal sent when audio playback should cease.
|
||||
*/
|
||||
#define SPICE_SIGNAL_PLAYBACK_STOP "playback-stop"
|
||||
|
||||
/**
|
||||
* A signal indicating that the SPICE server would like to capture audio data
|
||||
* from the client, along with the required format of that data.
|
||||
*/
|
||||
#define SPICE_SIGNAL_RECORD_START "record-start"
|
||||
|
||||
/**
|
||||
* A signal indicating that audio capture should cease.
|
||||
*/
|
||||
#define SPICE_SIGNAL_RECORD_STOP "record-stop"
|
||||
|
||||
/**
|
||||
* The signal indicating that the SPICE server has gone to streaming mode.
|
||||
*/
|
||||
#define SPICE_SIGNAL_STREAMING_MODE "streaming-mode"
|
||||
|
||||
#endif /* SPICE_CONSTANTS_H */
|
||||
|
49
src/protocols/spice/spice-defaults.h
Normal file
49
src/protocols/spice/spice-defaults.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef SPICE_DEFAULTS_H
|
||||
#define SPICE_DEFAULTS_H
|
||||
|
||||
/**
|
||||
* The default hostname to connect to if none is specified.
|
||||
*/
|
||||
#define SPICE_DEFAULT_HOST "localhost"
|
||||
|
||||
/**
|
||||
* The default SPICE port number to connect to if none is specified.
|
||||
*/
|
||||
#define SPICE_DEFAULT_PORT "5900"
|
||||
|
||||
/**
|
||||
* The default encodings to use for the SPICE clipboard.
|
||||
*/
|
||||
#define SPICE_DEFAULT_ENCODINGS "zrle ultra copyrect hextile zlib corre rre raw"
|
||||
|
||||
/**
|
||||
* The default SFTP port to connect to if SFTP is enabled.
|
||||
*/
|
||||
#define SPICE_DEFAULT_SFTP_PORT "22"
|
||||
|
||||
/**
|
||||
* The default root directory to limit SFTP access to.
|
||||
*/
|
||||
#define SPICE_DEFAULT_SFTP_ROOT "/"
|
||||
|
||||
#endif /* SPICE_DEFAULTS_H */
|
||||
|
184
src/protocols/spice/spice.c
Normal file
184
src/protocols/spice/spice.c
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "auth.h"
|
||||
#include "client.h"
|
||||
#include "common/clipboard.h"
|
||||
#include "common/cursor.h"
|
||||
#include "common/display.h"
|
||||
#include "channels/audio.h"
|
||||
#include "channels/clipboard.h"
|
||||
#include "channels/cursor.h"
|
||||
#include "channels/display.h"
|
||||
#include "channels/file.h"
|
||||
#include "log.h"
|
||||
#include "settings.h"
|
||||
#include "spice.h"
|
||||
#include "spice-constants.h"
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
#include "common-ssh/sftp.h"
|
||||
#include "common-ssh/ssh.h"
|
||||
#include "sftp.h"
|
||||
#endif
|
||||
|
||||
#include <glib/gmain.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/timestamp.h>
|
||||
#include <spice-client-glib-2.0/spice-client.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
SpiceSession* guac_spice_get_session(guac_client* client) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Initializing new SPICE session.");
|
||||
|
||||
/* Set up the SPICE session and Guacamole client. */
|
||||
guac_spice_client* spice_client = (guac_spice_client*) client->data;
|
||||
guac_spice_settings* spice_settings = spice_client->settings;
|
||||
|
||||
/* Create a new SPICE client. */
|
||||
SpiceSession* spice_session = spice_session_new();
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Registering new channel callback.");
|
||||
|
||||
/* Register a callback for handling new channel events. */
|
||||
g_signal_connect(spice_session, SPICE_SIGNAL_CHANNEL_NEW,
|
||||
G_CALLBACK(guac_spice_client_channel_handler), client);
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Setting up connection properties.");
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Setting up host/port.");
|
||||
|
||||
/* Set hostname and port */
|
||||
g_object_set(spice_session, SPICE_PROPERTY_HOST, spice_settings->hostname, NULL);
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Connecting to host %s",
|
||||
spice_settings->hostname);
|
||||
if (spice_settings->tls) {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Using TLS mode on port %s",
|
||||
spice_settings->port);
|
||||
g_object_set(spice_session,
|
||||
SPICE_PROPERTY_TLS_PORT, spice_settings->port,
|
||||
SPICE_PROPERTY_VERIFY, spice_settings->tls_verify,
|
||||
NULL);
|
||||
if (spice_settings->ca != NULL)
|
||||
g_object_set(spice_session, SPICE_PROPERTY_CA, spice_settings->ca, NULL);
|
||||
if (spice_settings->ca_file != NULL)
|
||||
g_object_set(spice_session, SPICE_PROPERTY_CA_FILE, spice_settings->ca_file, NULL);
|
||||
}
|
||||
else {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Using plaintext mode on port %s",
|
||||
spice_settings->port);
|
||||
g_object_set(spice_session,
|
||||
SPICE_PROPERTY_PORT, spice_settings->port, NULL);
|
||||
}
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Setting up keyboard layout: %s",
|
||||
spice_settings->server_layout);
|
||||
|
||||
/* Load keymap into client */
|
||||
spice_client->keyboard = guac_spice_keyboard_alloc(client,
|
||||
spice_settings->server_layout);
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Finished setting properties.");
|
||||
|
||||
/* Return the configured session. */
|
||||
return spice_session;
|
||||
|
||||
}
|
||||
|
||||
void* guac_spice_client_thread(void* data) {
|
||||
|
||||
guac_client* client = (guac_client*) data;
|
||||
guac_spice_client* spice_client = (guac_spice_client*) client->data;
|
||||
guac_spice_settings* settings = spice_client->settings;
|
||||
spice_client->spice_mainloop = g_main_loop_new(NULL, false);
|
||||
|
||||
/* Attempt connection */
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Attempting initial connection to SPICE server.");
|
||||
spice_client->spice_session = guac_spice_get_session(client);
|
||||
int retries_remaining = settings->retries;
|
||||
|
||||
/* If unsuccessful, retry as many times as specified */
|
||||
while (spice_client->spice_session == NULL && retries_remaining > 0) {
|
||||
|
||||
guac_client_log(client, GUAC_LOG_INFO,
|
||||
"Connect failed. Waiting %ims before retrying...",
|
||||
GUAC_SPICE_CONNECT_INTERVAL);
|
||||
|
||||
/* Wait for given interval then retry */
|
||||
guac_timestamp_msleep(GUAC_SPICE_CONNECT_INTERVAL);
|
||||
spice_client->spice_session = guac_spice_get_session(client);
|
||||
retries_remaining--;
|
||||
|
||||
}
|
||||
|
||||
/* If the final connect attempt fails, return error */
|
||||
if (spice_client->spice_session == NULL) {
|
||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_NOT_FOUND,
|
||||
"Unable to connect to SPICE server.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Configuration completed, flushing socket.");
|
||||
|
||||
guac_socket_flush(client->socket);
|
||||
|
||||
// guac_timestamp last_frame_end = guac_timestamp_current();
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Connection configuration finished, calling spice_session_connect.");
|
||||
|
||||
if(!spice_session_connect(spice_client->spice_session))
|
||||
return NULL;
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Session connected, entering main loop.");
|
||||
|
||||
/* Handle messages from SPICE server while client is running */
|
||||
while (client->state == GUAC_CLIENT_RUNNING) {
|
||||
|
||||
/* Run the main loop. */
|
||||
g_main_loop_run(spice_client->spice_mainloop);
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Finished main loop.");
|
||||
|
||||
/* Wait for an error on the main channel. */
|
||||
if (spice_client->main_channel != NULL
|
||||
&& spice_channel_get_error(SPICE_CHANNEL(spice_client->main_channel)) != NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Exited main loop, cleaning up.");
|
||||
|
||||
/* Kill client and finish connection */
|
||||
if (spice_client->spice_session != NULL) {
|
||||
guac_client_log(client, GUAC_LOG_DEBUG, "Cleaning up SPICE session.");
|
||||
spice_session_disconnect(spice_client->spice_session);
|
||||
g_object_unref(spice_client->spice_session);
|
||||
spice_client->spice_session = NULL;
|
||||
}
|
||||
guac_client_stop(client);
|
||||
guac_client_log(client, GUAC_LOG_INFO, "Internal SPICE client disconnected");
|
||||
return NULL;
|
||||
|
||||
}
|
199
src/protocols/spice/spice.h
Normal file
199
src/protocols/spice/spice.h
Normal file
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_SPICE_H
|
||||
#define GUAC_SPICE_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "common/clipboard.h"
|
||||
#include "common/display.h"
|
||||
#include "common/iconv.h"
|
||||
#include "common/surface.h"
|
||||
#include "keyboard.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/layer.h>
|
||||
#include <guacamole/recording.h>
|
||||
#include <glib.h>
|
||||
#include <spice-client-glib-2.0/spice-client.h>
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
#include "common-ssh/sftp.h"
|
||||
#include "common-ssh/ssh.h"
|
||||
#include "common-ssh/user.h"
|
||||
#endif
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
/**
|
||||
* SPICE-specific client data.
|
||||
*/
|
||||
typedef struct guac_spice_client {
|
||||
|
||||
/**
|
||||
* The SPICE client thread.
|
||||
*/
|
||||
pthread_t client_thread;
|
||||
|
||||
/**
|
||||
* The underlying SPICE session.
|
||||
*/
|
||||
SpiceSession* spice_session;
|
||||
|
||||
/**
|
||||
* The main SPICE channel.
|
||||
*/
|
||||
SpiceMainChannel* main_channel;
|
||||
|
||||
/**
|
||||
* The SPICE audio playback channel.
|
||||
*/
|
||||
SpicePlaybackChannel* playback_channel;
|
||||
|
||||
/**
|
||||
* The SPICE audio recording/input channel.
|
||||
*/
|
||||
SpiceRecordChannel* record_channel;
|
||||
|
||||
/**
|
||||
* The SPICE channel that handles the cursor display and events.
|
||||
*/
|
||||
SpiceCursorChannel* cursor_channel;
|
||||
|
||||
/**
|
||||
* The SPICE channel that handles mouse and keyboard inputs.
|
||||
*/
|
||||
SpiceInputsChannel* inputs_channel;
|
||||
|
||||
/**
|
||||
* Client settings, parsed from args.
|
||||
*/
|
||||
guac_spice_settings* settings;
|
||||
|
||||
/**
|
||||
* The current display state.
|
||||
*/
|
||||
guac_common_display* display;
|
||||
|
||||
/**
|
||||
* The SPICE display channel.
|
||||
*/
|
||||
SpiceDisplayChannel* spice_display;
|
||||
|
||||
/**
|
||||
* The current state of the keyboard with respect to the RDP session.
|
||||
*/
|
||||
guac_spice_keyboard* keyboard;
|
||||
|
||||
/**
|
||||
* The glib main loop
|
||||
*/
|
||||
GMainLoop* spice_mainloop;
|
||||
|
||||
/**
|
||||
* Internal clipboard.
|
||||
*/
|
||||
guac_common_clipboard* clipboard;
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
/**
|
||||
* The user and credentials used to authenticate for SFTP.
|
||||
*/
|
||||
guac_common_ssh_user* sftp_user;
|
||||
|
||||
/**
|
||||
* The SSH session used for SFTP.
|
||||
*/
|
||||
guac_common_ssh_session* sftp_session;
|
||||
|
||||
/**
|
||||
* An SFTP-based filesystem.
|
||||
*/
|
||||
guac_common_ssh_sftp_filesystem* sftp_filesystem;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The in-progress session recording, or NULL if no recording is in
|
||||
* progress.
|
||||
*/
|
||||
guac_recording* recording;
|
||||
|
||||
/**
|
||||
* Clipboard encoding-specific reader.
|
||||
*/
|
||||
guac_iconv_read* clipboard_reader;
|
||||
|
||||
/**
|
||||
* Clipboard encoding-specific writer.
|
||||
*/
|
||||
guac_iconv_write* clipboard_writer;
|
||||
|
||||
/**
|
||||
* Common attributes for locks.
|
||||
*/
|
||||
pthread_mutexattr_t attributes;
|
||||
|
||||
/**
|
||||
* Lock which is used to synchronizes access to SPICE data structures
|
||||
* between user input and client threads. It prevents input handlers
|
||||
* from running when SPICE data structures are allocated or freed
|
||||
* by the client thread.
|
||||
*/
|
||||
pthread_rwlock_t lock;
|
||||
|
||||
/**
|
||||
* Lock which synchronizes the sending of each SPICE message, ensuring
|
||||
* attempts to send SPICE messages never overlap.
|
||||
*/
|
||||
pthread_mutex_t message_lock;
|
||||
|
||||
} guac_spice_client;
|
||||
|
||||
/**
|
||||
* Allocates a new rfbClient instance given the parameters stored within the
|
||||
* client, returning NULL on failure.
|
||||
*
|
||||
* @param client
|
||||
* The guac_client associated with the settings of the desired SPICE
|
||||
* connection.
|
||||
*
|
||||
* @return
|
||||
* A new rfbClient instance allocated and connected according to the
|
||||
* parameters stored within the given client, or NULL if connecting to the
|
||||
* SPICE server fails.
|
||||
*/
|
||||
SpiceSession* guac_spice_get_session(guac_client* client);
|
||||
|
||||
/**
|
||||
* SPICE client thread. This thread initiates the SPICE connection and
|
||||
* ultimately runs throughout the duration of the client, existing as a single
|
||||
* instance, shared by all users.
|
||||
*
|
||||
* @param data
|
||||
* The guac_client instance associated with the requested SPICE connection.
|
||||
*
|
||||
* @return
|
||||
* Always NULL.
|
||||
*/
|
||||
void* guac_spice_client_thread(void* data);
|
||||
|
||||
#endif /* GUAC_SPICE_H */
|
||||
|
124
src/protocols/spice/user.c
Normal file
124
src/protocols/spice/user.c
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "channels/clipboard.h"
|
||||
#include "input.h"
|
||||
#include "common/display.h"
|
||||
#include "common/dot_cursor.h"
|
||||
#include "common/pointer_cursor.h"
|
||||
#include "user.h"
|
||||
#include "sftp.h"
|
||||
#include "spice.h"
|
||||
|
||||
#include <guacamole/argv.h>
|
||||
#include <guacamole/audio.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
int guac_spice_user_join_handler(guac_user* user, int argc, char** argv) {
|
||||
|
||||
guac_spice_client* spice_client = (guac_spice_client*) user->client->data;
|
||||
|
||||
/* Parse provided arguments */
|
||||
guac_spice_settings* settings = guac_spice_parse_args(user,
|
||||
argc, (const char**) argv);
|
||||
|
||||
/* Fail if settings cannot be parsed */
|
||||
if (settings == NULL) {
|
||||
guac_user_log(user, GUAC_LOG_INFO,
|
||||
"Badly formatted client arguments.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Store settings at user level */
|
||||
user->data = settings;
|
||||
|
||||
/* Connect via SPICE if owner */
|
||||
if (user->owner) {
|
||||
|
||||
/* Store owner's settings at client level */
|
||||
spice_client->settings = settings;
|
||||
|
||||
/* Start client thread */
|
||||
if (pthread_create(&spice_client->client_thread, NULL, guac_spice_client_thread, user->client)) {
|
||||
guac_user_log(user, GUAC_LOG_ERROR, "Unable to start SPICE client thread.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* If not owner, synchronize with current state */
|
||||
else {
|
||||
|
||||
/* Synchronize with current display */
|
||||
guac_common_display_dup(spice_client->display, user, user->socket);
|
||||
guac_socket_flush(user->socket);
|
||||
|
||||
}
|
||||
|
||||
/* Only handle events if not read-only */
|
||||
if (!settings->read_only) {
|
||||
|
||||
/* General mouse/keyboard events */
|
||||
user->mouse_handler = guac_spice_user_mouse_handler;
|
||||
user->key_handler = guac_spice_user_key_handler;
|
||||
|
||||
/* Inbound (client to server) clipboard transfer */
|
||||
if (!settings->disable_paste)
|
||||
user->clipboard_handler = guac_spice_clipboard_handler;
|
||||
|
||||
/* Updates to connection parameters if we own the connection */
|
||||
if (user->owner)
|
||||
user->argv_handler = guac_argv_handler;
|
||||
|
||||
#ifdef ENABLE_COMMON_SSH
|
||||
/* Set generic (non-filesystem) file upload handler */
|
||||
if (settings->enable_sftp && !settings->sftp_disable_upload)
|
||||
user->file_handler = guac_spice_sftp_file_handler;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int guac_spice_user_leave_handler(guac_user* user) {
|
||||
|
||||
guac_spice_client* spice_client = (guac_spice_client*) user->client->data;
|
||||
|
||||
if (spice_client->display) {
|
||||
/* Update shared cursor state */
|
||||
guac_common_cursor_remove_user(spice_client->display->cursor, user);
|
||||
}
|
||||
|
||||
/* Free settings if not owner (owner settings will be freed with client) */
|
||||
if (!user->owner) {
|
||||
guac_spice_settings* settings = (guac_spice_settings*) user->data;
|
||||
guac_spice_settings_free(settings);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
38
src/protocols/spice/user.h
Normal file
38
src/protocols/spice/user.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef GUAC_SPICE_USER_H
|
||||
#define GUAC_SPICE_USER_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <guacamole/user.h>
|
||||
|
||||
/**
|
||||
* Handler for joining users.
|
||||
*/
|
||||
guac_user_join_handler guac_spice_user_join_handler;
|
||||
|
||||
/**
|
||||
* Handler for leaving users.
|
||||
*/
|
||||
guac_user_leave_handler guac_spice_user_leave_handler;
|
||||
|
||||
#endif /* SPICE_USER_H */
|
||||
|
Loading…
Reference in New Issue
Block a user