Merge libguac-client-rdp.

This commit is contained in:
Michael Jumper 2013-06-04 15:52:33 -07:00
commit aaf8a0829d
42 changed files with 7851 additions and 0 deletions

36
protocols/rdp/.gitignore vendored Normal file
View File

@ -0,0 +1,36 @@
# Object code
*.o
*.so
*.lo
*.la
# Backup files
*~
# Release files
*.tar.gz
# Files currently being edited by vim or vi
*.swp
# automake/autoconf
.deps/
.libs/
Makefile
Makefile.in
aclocal.m4
autom4te.cache/
m4/*
!README
config.guess
config.log
config.status
config.sub
configure
depcomp
install-sh
libtool
ltmain.sh
missing

6
protocols/rdp/AUTHORS Normal file
View File

@ -0,0 +1,6 @@
Michael Jumper <mike.jumper@guac-dev.org>
Matt Hortman <matt@FlintRiverSystems.com>
Jocelyn Delalande <j.delalande@ulteo.com>
David Lechevalier <david@ulteo.com>
Alexandre Devely <alex@koumoula.com>
Laurent Meunier <laurent@deltalima.net>

49
protocols/rdp/ChangeLog Normal file
View File

@ -0,0 +1,49 @@
2013-05-09 Michael Jumper <mike.jumper@guac-dev.org>
* Merge contributed keymaps for French and German.
2012-12-25 Michael Jumper <mike.jumper@guac-dev.org>
* Console arguments (fixes #227)
2012-12-13 Michael Jumper <mike.jumper@guac-dev.org>
* Implement PATBLT fallback (fixes #238)
2012-11-22 Michael Jumper <mike.jumper@guac-dev.org>
* Add disable-audio option (fixes #221)
2012-11-02 Michael Jumper <mike.jumper@guac-dev.org>
* Added sound support (fixes #32)
2012-10-22 Michael Jumper <mike.jumper@guac-dev.org>
* Use guac_client_info to choose optimal size if size not overridden
2012-08-31 Laurent Meunier <laurent@deltalima.net>
* Use configured color depth
2012-08-11 Michael Jumper <mike.jumper@guac-dev.org>
* Fix m4/ autoreconf error
2012-05-23 David Pham-Van <d.pham-van@ulteo.com>
* Add SetNull and SetDefault handlers (fixes #148)
2012-05-04 Michael Jumper <mike.jumper@guac-dev.org>
* Removed Alt-code fallback mode
* Added embedded default mouse pointer
2012-05-15 Jocelyn Delalande <j.delalande@ulteo.com>
* Unicode keyboard events
2012-05-04 Michael Jumper <mike.jumper@guac-dev.org>
* Initial release

470
protocols/rdp/LICENSE Normal file
View File

@ -0,0 +1,470 @@
MOZILLA PUBLIC LICENSE
Version 1.1
---------------
1. Definitions.
1.0.1. "Commercial Use" means distribution or otherwise making the
Covered Code available to a third party.
1.1. "Contributor" means each entity that creates or contributes to
the creation of Modifications.
1.2. "Contributor Version" means the combination of the Original
Code, prior Modifications used by a Contributor, and the Modifications
made by that particular Contributor.
1.3. "Covered Code" means the Original Code or Modifications or the
combination of the Original Code and Modifications, in each case
including portions thereof.
1.4. "Electronic Distribution Mechanism" means a mechanism generally
accepted in the software development community for the electronic
transfer of data.
1.5. "Executable" means Covered Code in any form other than Source
Code.
1.6. "Initial Developer" means the individual or entity identified
as the Initial Developer in the Source Code notice required by Exhibit
A.
1.7. "Larger Work" means a work which combines Covered Code or
portions thereof with code not governed by the terms of this License.
1.8. "License" means this document.
1.8.1. "Licensable" means having the right to grant, to the maximum
extent possible, whether at the time of the initial grant or
subsequently acquired, any and all of the rights conveyed herein.
1.9. "Modifications" means any addition to or deletion from the
substance or structure of either the Original Code or any previous
Modifications. When Covered Code is released as a series of files, a
Modification is:
A. Any addition to or deletion from the contents of a file
containing Original Code or previous Modifications.
B. Any new file that contains any part of the Original Code or
previous Modifications.
1.10. "Original Code" means Source Code of computer software code
which is described in the Source Code notice required by Exhibit A as
Original Code, and which, at the time of its release under this
License is not already Covered Code governed by this License.
1.10.1. "Patent Claims" means any patent claim(s), now owned or
hereafter acquired, including without limitation, method, process,
and apparatus claims, in any patent Licensable by grantor.
1.11. "Source Code" means the preferred form of the Covered Code for
making modifications to it, including all modules it contains, plus
any associated interface definition files, scripts used to control
compilation and installation of an Executable, or source code
differential comparisons against either the Original Code or another
well known, available Covered Code of the Contributor's choice. The
Source Code can be in a compressed or archival form, provided the
appropriate decompression or de-archiving software is widely available
for no charge.
1.12. "You" (or "Your") means an individual or a legal entity
exercising rights under, and complying with all of the terms of, this
License or a future version of this License issued under Section 6.1.
For legal entities, "You" includes any entity which controls, is
controlled by, or is under common control with You. For purposes of
this definition, "control" means (a) the power, direct or indirect,
to cause the direction or management of such entity, whether by
contract or otherwise, or (b) ownership of more than fifty percent
(50%) of the outstanding shares or beneficial ownership of such
entity.
2. Source Code License.
2.1. The Initial Developer Grant.
The Initial Developer hereby grants You a world-wide, royalty-free,
non-exclusive license, subject to third party intellectual property
claims:
(a) under intellectual property rights (other than patent or
trademark) Licensable by Initial Developer to use, reproduce,
modify, display, perform, sublicense and distribute the Original
Code (or portions thereof) with or without Modifications, and/or
as part of a Larger Work; and
(b) under Patents Claims infringed by the making, using or
selling of Original Code, to make, have made, use, practice,
sell, and offer for sale, and/or otherwise dispose of the
Original Code (or portions thereof).
(c) the licenses granted in this Section 2.1(a) and (b) are
effective on the date Initial Developer first distributes
Original Code under the terms of this License.
(d) Notwithstanding Section 2.1(b) above, no patent license is
granted: 1) for code that You delete from the Original Code; 2)
separate from the Original Code; or 3) for infringements caused
by: i) the modification of the Original Code or ii) the
combination of the Original Code with other software or devices.
2.2. Contributor Grant.
Subject to third party intellectual property claims, each Contributor
hereby grants You a world-wide, royalty-free, non-exclusive license
(a) under intellectual property rights (other than patent or
trademark) Licensable by Contributor, to use, reproduce, modify,
display, perform, sublicense and distribute the Modifications
created by such Contributor (or portions thereof) either on an
unmodified basis, with other Modifications, as Covered Code
and/or as part of a Larger Work; and
(b) under Patent Claims infringed by the making, using, or
selling of Modifications made by that Contributor either alone
and/or in combination with its Contributor Version (or portions
of such combination), to make, use, sell, offer for sale, have
made, and/or otherwise dispose of: 1) Modifications made by that
Contributor (or portions thereof); and 2) the combination of
Modifications made by that Contributor with its Contributor
Version (or portions of such combination).
(c) the licenses granted in Sections 2.2(a) and 2.2(b) are
effective on the date Contributor first makes Commercial Use of
the Covered Code.
(d) Notwithstanding Section 2.2(b) above, no patent license is
granted: 1) for any code that Contributor has deleted from the
Contributor Version; 2) separate from the Contributor Version;
3) for infringements caused by: i) third party modifications of
Contributor Version or ii) the combination of Modifications made
by that Contributor with other software (except as part of the
Contributor Version) or other devices; or 4) under Patent Claims
infringed by Covered Code in the absence of Modifications made by
that Contributor.
3. Distribution Obligations.
3.1. Application of License.
The Modifications which You create or to which You contribute are
governed by the terms of this License, including without limitation
Section 2.2. The Source Code version of Covered Code may be
distributed only under the terms of this License or a future version
of this License released under Section 6.1, and You must include a
copy of this License with every copy of the Source Code You
distribute. You may not offer or impose any terms on any Source Code
version that alters or restricts the applicable version of this
License or the recipients' rights hereunder. However, You may include
an additional document offering the additional rights described in
Section 3.5.
3.2. Availability of Source Code.
Any Modification which You create or to which You contribute must be
made available in Source Code form under the terms of this License
either on the same media as an Executable version or via an accepted
Electronic Distribution Mechanism to anyone to whom you made an
Executable version available; and if made available via Electronic
Distribution Mechanism, must remain available for at least twelve (12)
months after the date it initially became available, or at least six
(6) months after a subsequent version of that particular Modification
has been made available to such recipients. You are responsible for
ensuring that the Source Code version remains available even if the
Electronic Distribution Mechanism is maintained by a third party.
3.3. Description of Modifications.
You must cause all Covered Code to which You contribute to contain a
file documenting the changes You made to create that Covered Code and
the date of any change. You must include a prominent statement that
the Modification is derived, directly or indirectly, from Original
Code provided by the Initial Developer and including the name of the
Initial Developer in (a) the Source Code, and (b) in any notice in an
Executable version or related documentation in which You describe the
origin or ownership of the Covered Code.
3.4. Intellectual Property Matters
(a) Third Party Claims.
If Contributor has knowledge that a license under a third party's
intellectual property rights is required to exercise the rights
granted by such Contributor under Sections 2.1 or 2.2,
Contributor must include a text file with the Source Code
distribution titled "LEGAL" which describes the claim and the
party making the claim in sufficient detail that a recipient will
know whom to contact. If Contributor obtains such knowledge after
the Modification is made available as described in Section 3.2,
Contributor shall promptly modify the LEGAL file in all copies
Contributor makes available thereafter and shall take other steps
(such as notifying appropriate mailing lists or newsgroups)
reasonably calculated to inform those who received the Covered
Code that new knowledge has been obtained.
(b) Contributor APIs.
If Contributor's Modifications include an application programming
interface and Contributor has knowledge of patent licenses which
are reasonably necessary to implement that API, Contributor must
also include this information in the LEGAL file.
(c) Representations.
Contributor represents that, except as disclosed pursuant to
Section 3.4(a) above, Contributor believes that Contributor's
Modifications are Contributor's original creation(s) and/or
Contributor has sufficient rights to grant the rights conveyed by
this License.
3.5. Required Notices.
You must duplicate the notice in Exhibit A in each file of the Source
Code. If it is not possible to put such notice in a particular Source
Code file due to its structure, then You must include such notice in a
location (such as a relevant directory) where a user would be likely
to look for such a notice. If You created one or more Modification(s)
You may add your name as a Contributor to the notice described in
Exhibit A. You must also duplicate this License in any documentation
for the Source Code where You describe recipients' rights or ownership
rights relating to Covered Code. You may choose to offer, and to
charge a fee for, warranty, support, indemnity or liability
obligations to one or more recipients of Covered Code. However, You
may do so only on Your own behalf, and not on behalf of the Initial
Developer or any Contributor. You must make it absolutely clear than
any such warranty, support, indemnity or liability obligation is
offered by You alone, and You hereby agree to indemnify the Initial
Developer and every Contributor for any liability incurred by the
Initial Developer or such Contributor as a result of warranty,
support, indemnity or liability terms You offer.
3.6. Distribution of Executable Versions.
You may distribute Covered Code in Executable form only if the
requirements of Section 3.1-3.5 have been met for that Covered Code,
and if You include a notice stating that the Source Code version of
the Covered Code is available under the terms of this License,
including a description of how and where You have fulfilled the
obligations of Section 3.2. The notice must be conspicuously included
in any notice in an Executable version, related documentation or
collateral in which You describe recipients' rights relating to the
Covered Code. You may distribute the Executable version of Covered
Code or ownership rights under a license of Your choice, which may
contain terms different from this License, provided that You are in
compliance with the terms of this License and that the license for the
Executable version does not attempt to limit or alter the recipient's
rights in the Source Code version from the rights set forth in this
License. If You distribute the Executable version under a different
license You must make it absolutely clear that any terms which differ
from this License are offered by You alone, not by the Initial
Developer or any Contributor. You hereby agree to indemnify the
Initial Developer and every Contributor for any liability incurred by
the Initial Developer or such Contributor as a result of any such
terms You offer.
3.7. Larger Works.
You may create a Larger Work by combining Covered Code with other code
not governed by the terms of this License and distribute the Larger
Work as a single product. In such a case, You must make sure the
requirements of this License are fulfilled for the Covered Code.
4. Inability to Comply Due to Statute or Regulation.
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Code due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description
must be included in the LEGAL file described in Section 3.4 and must
be included with all distributions of the Source Code. Except to the
extent prohibited by statute or regulation, such description must be
sufficiently detailed for a recipient of ordinary skill to be able to
understand it.
5. Application of this License.
This License applies to code to which the Initial Developer has
attached the notice in Exhibit A and to related Covered Code.
6. Versions of the License.
6.1. New Versions.
Netscape Communications Corporation ("Netscape") may publish revised
and/or new versions of the License from time to time. Each version
will be given a distinguishing version number.
6.2. Effect of New Versions.
Once Covered Code has been published under a particular version of the
License, You may always continue to use it under the terms of that
version. You may also choose to use such Covered Code under the terms
of any subsequent version of the License published by Netscape. No one
other than Netscape has the right to modify the terms applicable to
Covered Code created under this License.
6.3. Derivative Works.
If You create or use a modified version of this License (which you may
only do in order to apply it to code which is not already Covered Code
governed by this License), You must (a) rename Your license so that
the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
"MPL", "NPL" or any confusingly similar phrase do not appear in your
license (except to note that your license differs from this License)
and (b) otherwise make it clear that Your version of the license
contains terms which differ from the Mozilla Public License and
Netscape Public License. (Filling in the name of the Initial
Developer, Original Code or Contributor in the notice described in
Exhibit A shall not of themselves be deemed to be modifications of
this License.)
7. DISCLAIMER OF WARRANTY.
COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
8. TERMINATION.
8.1. This License and the rights granted hereunder will terminate
automatically if You fail to comply with terms herein and fail to cure
such breach within 30 days of becoming aware of the breach. All
sublicenses to the Covered Code which are properly granted shall
survive any termination of this License. Provisions which, by their
nature, must remain in effect beyond the termination of this License
shall survive.
8.2. If You initiate litigation by asserting a patent infringement
claim (excluding declatory judgment actions) against Initial Developer
or a Contributor (the Initial Developer or Contributor against whom
You file such action is referred to as "Participant") alleging that:
(a) such Participant's Contributor Version directly or indirectly
infringes any patent, then any and all rights granted by such
Participant to You under Sections 2.1 and/or 2.2 of this License
shall, upon 60 days notice from Participant terminate prospectively,
unless if within 60 days after receipt of notice You either: (i)
agree in writing to pay Participant a mutually agreeable reasonable
royalty for Your past and future use of Modifications made by such
Participant, or (ii) withdraw Your litigation claim with respect to
the Contributor Version against such Participant. If within 60 days
of notice, a reasonable royalty and payment arrangement are not
mutually agreed upon in writing by the parties or the litigation claim
is not withdrawn, the rights granted by Participant to You under
Sections 2.1 and/or 2.2 automatically terminate at the expiration of
the 60 day notice period specified above.
(b) any software, hardware, or device, other than such Participant's
Contributor Version, directly or indirectly infringes any patent, then
any rights granted to You by such Participant under Sections 2.1(b)
and 2.2(b) are revoked effective as of the date You first made, used,
sold, distributed, or had made, Modifications made by that
Participant.
8.3. If You assert a patent infringement claim against Participant
alleging that such Participant's Contributor Version directly or
indirectly infringes any patent where such claim is resolved (such as
by license or settlement) prior to the initiation of patent
infringement litigation, then the reasonable value of the licenses
granted by such Participant under Sections 2.1 or 2.2 shall be taken
into account in determining the amount or value of any payment or
license.
8.4. In the event of termination under Sections 8.1 or 8.2 above,
all end user license agreements (excluding distributors and resellers)
which have been validly granted by You or any distributor hereunder
prior to termination shall survive termination.
9. LIMITATION OF LIABILITY.
UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
(INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
10. U.S. GOVERNMENT END USERS.
The Covered Code is a "commercial item," as that term is defined in
48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
software" and "commercial computer software documentation," as such
terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
all U.S. Government End Users acquire Covered Code with only those
rights set forth herein.
11. MISCELLANEOUS.
This License represents the complete agreement concerning subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. This License shall be governed by
California law provisions (except to the extent applicable law, if
any, provides otherwise), excluding its conflict-of-law provisions.
With respect to disputes in which at least one party is a citizen of,
or an entity chartered or registered to do business in the United
States of America, any litigation relating to this License shall be
subject to the jurisdiction of the Federal Courts of the Northern
District of California, with venue lying in Santa Clara County,
California, with the losing party responsible for costs, including
without limitation, court costs and reasonable attorneys' fees and
expenses. The application of the United Nations Convention on
Contracts for the International Sale of Goods is expressly excluded.
Any law or regulation which provides that the language of a contract
shall be construed against the drafter shall not apply to this
License.
12. RESPONSIBILITY FOR CLAIMS.
As between Initial Developer and the Contributors, each party is
responsible for claims and damages arising, directly or indirectly,
out of its utilization of rights under this License and You agree to
work with Initial Developer and Contributors to distribute such
responsibility on an equitable basis. Nothing herein is intended or
shall be deemed to constitute any admission of liability.
13. MULTIPLE-LICENSED CODE.
Initial Developer may designate portions of the Covered Code as
"Multiple-Licensed". "Multiple-Licensed" means that the Initial
Developer permits you to utilize portions of the Covered Code under
Your choice of the NPL or the alternative licenses, if any, specified
by the Initial Developer in the file described in Exhibit A.
EXHIBIT A -Mozilla Public License.
``The contents of this file are subject to the Mozilla Public License
Version 1.1 (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.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific language governing rights and limitations
under the License.
The Original Code is ______________________________________.
The Initial Developer of the Original Code is ________________________.
Portions created by ______________________ are Copyright (C) ______
_______________________. All Rights Reserved.
Contributor(s): ______________________________________.
Alternatively, the contents of this file may be used under the terms
of the _____ license (the "[___] License"), in which case the
provisions of [______] License are applicable instead of those
above. If you wish to allow use of your version of this file only
under the terms of the [____] License and not to allow others to use
your version of this file under the MPL, indicate your decision by
deleting the provisions above and replace them with the notice and
other provisions required by the [___] License. If you do not delete
the provisions above, a recipient may use your version of this file
under either the MPL or the [___] License."
[NOTE: The text of this Exhibit A may differ slightly from the text of
the notices in the Source Code files of the Original Code. You should
use the text of this Exhibit A rather than the text found in the
Original Code Source Code for Your Modifications.]

99
protocols/rdp/Makefile.am Normal file
View File

@ -0,0 +1,99 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (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.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is libguac-client-rdp.
#
# The Initial Developer of the Original Code is
# Michael Jumper.
# Portions created by the Initial Developer are Copyright (C) 2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I m4
AM_CFLAGS = -Werror -Wall -Iinclude
lib_LTLIBRARIES = libguac-client-rdp.la
freerdp_LTLIBRARIES = guac_rdpsnd.la
libguac_client_rdp_la_SOURCES = \
$(OGG_SOURCES) \
src/audio.c \
src/client.c \
src/default_pointer.c \
src/guac_handlers.c \
src/rdp_bitmap.c \
src/rdp_cliprdr.c \
src/rdp_gdi.c \
src/rdp_glyph.c \
src/rdp_keymap_base.c \
src/rdp_keymap.c \
src/rdp_keymap_de_de.c \
src/rdp_keymap_failsafe.c \
src/rdp_keymap_fr_fr.c \
src/rdp_keymap_en_us.c \
src/rdp_pointer.c \
src/wav_encoder.c
guac_rdpsnd_la_SOURCES = \
guac_rdpsnd/messages.c \
guac_rdpsnd/service.c \
src/audio.c
noinst_HEADERS = \
$(OGG_HEADERS) \
guac_rdpsnd/messages.h \
guac_rdpsnd/service.h \
include/audio.h \
include/client.h \
include/config.h \
include/default_pointer.h \
include/guac_handlers.h \
include/rdp_bitmap.h \
include/rdp_cliprdr.h \
include/rdp_gdi.h \
include/rdp_glyph.h \
include/rdp_keymap.h \
include/rdp_pointer.h \
include/wav_encoder.h
# Compile OGG support if available
if ENABLE_OGG
libguac_client_rdp_la_SOURCES += src/ogg_encoder.c
noinst_HEADERS += include/ogg_encoder.h
endif
libguac_client_rdp_la_LDFLAGS = -version-info 0:0:0
guac_rdpsnd_la_LDFLAGS = -module -avoid-version -shared
freerdpdir = ${libdir}/freerdp/
EXTRA_DIST = LICENSE

75
protocols/rdp/README Normal file
View File

@ -0,0 +1,75 @@
------------------------------------------------------------
About this README
------------------------------------------------------------
This README is intended to provide quick and to-the-point documentation for
technical users intending to compile parts of Guacamole themselves.
Distribution-specific packages are available from the files section of the main
project page:
http://sourceforge.net/projects/guacamole/files/
Distribution-specific documentation is provided on the Guacamole wiki:
http://guac-dev.org/
------------------------------------------------------------
What is libguac-client-rdp?
------------------------------------------------------------
libguac-client-rdp is a protocol support plugin for the Guacamole proxy (guacd)
which provides support for RDP, the proprietary remote desktop protocol used
by Windows Remote Deskop / Terminal Services, via the libfreerdp library.
------------------------------------------------------------
Compiling and installing libguac-client-rdp
------------------------------------------------------------
Please note that distribution-specific pre-compiled packages are available from
the files section of the main project site:
http://sourceforge.net/projects/guacamole/files/
libguac-client-rdp is built using the popular GNU Automake, and thus provides
the standard configure script.
1) Run configure
$ ./configure
Assuming all dependencies have been installed, this should succeed without
errors.
2) Run make
$ make
libguac-client-rdp will now compile.
3) Install (as root)
# make install
libguac-client-rdp will install to your /usr/local/lib directory by default.
You can change the install location by using the --prefix option for
configure.
You will need to run ldconfig (as root) so that guacd can find the library
when needed:
# ldconfig
------------------------------------------------------------
Reporting problems
------------------------------------------------------------
Please report any bugs encountered by opening a new ticket at the Trac system
hosted at:
http://guac-dev.org/trac/

View File

@ -0,0 +1,86 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (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.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is libguac-client-rdp.
#
# The Initial Developer of the Original Code is
# Michael Jumper.
# Portions created by the Initial Developer are Copyright (C) 2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
AC_INIT(src/client.c)
AM_INIT_AUTOMAKE([libguac-client-rdp], 0.7.4)
AC_CONFIG_MACRO_DIR([m4])
# Checks for programs.
AC_PROG_CC
AC_PROG_CC_C99
AC_PROG_LIBTOOL
# Checks for libraries.
AC_CHECK_LIB([guac], [guac_client_plugin_open],, AC_MSG_ERROR("libguac must be installed first"))
AC_CHECK_LIB([cairo], [cairo_create],, AC_MSG_ERROR("cairo is required for drawing instructions"))
AC_CHECK_LIB([freerdp-cache], [glyph_cache_register_callbacks],, AC_MSG_ERROR("libfreerdp-cache is required (part of FreeRDP)"))
AC_CHECK_LIB([freerdp-core], [freerdp_new],, AC_MSG_ERROR("libfreerdp-core is required (part of FreeRDP)"))
AC_CHECK_LIB([freerdp-channels], [freerdp_channels_new],, AC_MSG_ERROR("libfreerdp-channels is required (part of FreeRDP)"))
AC_CHECK_LIB([freerdp-utils], [xzalloc],, AC_MSG_ERROR("libfreerdp-utils is required (part of FreeRDP)"))
AC_CHECK_LIB([freerdp-codec], [freerdp_image_convert],, AC_MSG_ERROR("libfreerdp-codec is required (part of FreeRDP)"))
AC_CHECK_LIB([pthread], [pthread_mutex_init],, AC_MSG_ERROR("libpthread is required"))
# Check for libvorbisenc
have_vorbisenc=yes
AC_CHECK_HEADER(vorbis/vorbisenc.h,, [have_vorbisenc=no])
AC_CHECK_LIB([vorbisenc], [vorbis_encode_init],, [have_vorbisenc=no])
AM_CONDITIONAL([ENABLE_OGG], [test "x${have_vorbisenc}" = "xyes"])
if test "x${have_vorbisenc}" = "xno"
then
AC_MSG_WARN([
--------------------------------------------
Unable to find libvorbisenc.
Sound will not be encoded with Ogg Vorbis.
--------------------------------------------])
else
AC_DEFINE([ENABLE_OGG])
fi
# Checks for header files.
AC_CHECK_HEADERS([guacamole/client.h guacamole/guacio.h guacamole/protocol.h freerdp/locale/keyboard.h freerdp/kbd/layouts.h])
# Check for FreeRDP version-specific features
AC_CHECK_MEMBERS([rdpPointer.SetDefault, rdpPointer.SetNull],
[], [],
[[#include <freerdp/freerdp.h>]])
# Checks for library functions.
AC_FUNC_MALLOC
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

View File

@ -0,0 +1,313 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/constants.h>
#include <freerdp/types.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/stream.h>
#include <freerdp/utils/svc_plugin.h>
#include <guacamole/client.h>
#include "audio.h"
#include "service.h"
#include "messages.h"
#include "client.h"
/* MESSAGE HANDLERS */
void guac_rdpsnd_formats_handler(guac_rdpsndPlugin* rdpsnd,
audio_stream* audio, STREAM* input_stream,
guac_rdpsnd_pdu_header* header) {
int server_format_count;
int server_version;
int i;
STREAM* output_stream;
int output_body_size;
unsigned char* output_stream_end;
rdp_guac_client_data* guac_client_data =
(rdp_guac_client_data*) audio->client->data;
/* Format header */
stream_seek(input_stream, 14);
stream_read_uint16(input_stream, server_format_count);
stream_seek_uint8(input_stream);
stream_read_uint16(input_stream, server_version);
stream_seek_uint8(input_stream);
/* Initialize Client Audio Formats and Version PDU */
output_stream = stream_new(24);
stream_write_uint8(output_stream, SNDC_FORMATS);
stream_write_uint8(output_stream, 0);
/* Fill in body size later */
stream_seek_uint16(output_stream); /* offset = 0x02 */
/* Flags, volume, and pitch */
stream_write_uint32(output_stream, TSSNDCAPS_ALIVE);
stream_write_uint32(output_stream, 0);
stream_write_uint32(output_stream, 0);
/* Datagram port (UDP) */
stream_write_uint16(output_stream, 0);
/* Fill in format count later */
stream_seek_uint16(output_stream); /* offset = 0x12 */
/* Version and padding */
stream_write_uint8(output_stream, 0);
stream_write_uint16(output_stream, 6);
stream_write_uint8(output_stream, 0);
/* Check each server format, respond if supported */
for (i=0; i < server_format_count; i++) {
unsigned char* format_start;
int format_tag;
int channels;
int rate;
int bps;
int body_size;
/* Remember position in stream */
stream_get_mark(input_stream, format_start);
/* Read format */
stream_read_uint16(input_stream, format_tag);
stream_read_uint16(input_stream, channels);
stream_read_uint32(input_stream, rate);
stream_seek_uint32(input_stream);
stream_seek_uint16(input_stream);
stream_read_uint16(input_stream, bps);
/* Skip past extra data */
stream_read_uint16(input_stream, body_size);
stream_seek(input_stream, body_size);
/* If PCM, accept */
if (format_tag == WAVE_FORMAT_PCM) {
/* If can fit another format, accept it */
if (rdpsnd->format_count < GUAC_RDP_MAX_FORMATS) {
/* Add channel */
int current = rdpsnd->format_count++;
rdpsnd->formats[current].rate = rate;
rdpsnd->formats[current].channels = channels;
rdpsnd->formats[current].bps = bps;
/* Log format */
guac_client_log_info(audio->client,
"Accepted format: %i-bit PCM with %i channels at "
"%i Hz",
bps, channels, rate);
/* Queue format for sending as accepted */
stream_check_size(output_stream, 18 + body_size);
stream_write(output_stream, format_start, 18 + body_size);
/*
* BEWARE that using stream_check_size means that any "marks"
* set via stream_set_mark on output_stream are invalid.
*/
}
/* Otherwise, log that we dropped one */
else
guac_client_log_info(audio->client,
"Dropped valid format: %i-bit PCM with %i channels at "
"%i Hz",
bps, channels, rate);
}
}
/* Calculate size of PDU */
output_body_size = stream_get_length(output_stream) - 4;
stream_get_mark(output_stream, output_stream_end);
/* Set body size */
stream_set_pos(output_stream, 0x02);
stream_write_uint16(output_stream, output_body_size);
/* Set format count */
stream_set_pos(output_stream, 0x12);
stream_write_uint16(output_stream, rdpsnd->format_count);
/* Reposition cursor at end (necessary for message send) */
stream_set_mark(output_stream, output_stream_end);
/* Send accepted formats */
pthread_mutex_lock(&(guac_client_data->rdp_lock));
svc_plugin_send((rdpSvcPlugin*)rdpsnd, output_stream);
/* If version greater than 6, must send Quality Mode PDU */
if (server_version >= 6) {
/* Always send High Quality for now */
output_stream = stream_new(8);
stream_write_uint8(output_stream, SNDC_QUALITYMODE);
stream_write_uint8(output_stream, 0);
stream_write_uint16(output_stream, 4);
stream_write_uint16(output_stream, HIGH_QUALITY);
stream_write_uint16(output_stream, 0);
svc_plugin_send((rdpSvcPlugin*)rdpsnd, output_stream);
}
pthread_mutex_unlock(&(guac_client_data->rdp_lock));
}
/* server is getting a feel of the round trip time */
void guac_rdpsnd_training_handler(guac_rdpsndPlugin* rdpsnd,
audio_stream* audio, STREAM* input_stream,
guac_rdpsnd_pdu_header* header) {
int data_size;
STREAM* output_stream;
rdp_guac_client_data* guac_client_data =
(rdp_guac_client_data*) audio->client->data;
/* Read timestamp and data size */
stream_read_uint16(input_stream, rdpsnd->server_timestamp);
stream_read_uint16(input_stream, data_size);
/* Send training response */
output_stream = stream_new(8);
stream_write_uint8(output_stream, SNDC_TRAINING);
stream_write_uint8(output_stream, 0);
stream_write_uint16(output_stream, 4);
stream_write_uint16(output_stream, rdpsnd->server_timestamp);
stream_write_uint16(output_stream, data_size);
pthread_mutex_lock(&(guac_client_data->rdp_lock));
svc_plugin_send((rdpSvcPlugin*) rdpsnd, output_stream);
pthread_mutex_unlock(&(guac_client_data->rdp_lock));
}
void guac_rdpsnd_wave_info_handler(guac_rdpsndPlugin* rdpsnd,
audio_stream* audio, STREAM* input_stream,
guac_rdpsnd_pdu_header* header) {
unsigned char buffer[4];
int format;
/* Read wave information */
stream_read_uint16(input_stream, rdpsnd->server_timestamp);
stream_read_uint16(input_stream, format);
stream_read_uint8(input_stream, rdpsnd->waveinfo_block_number);
stream_seek(input_stream, 3);
stream_read(input_stream, buffer, 4);
/*
* Size of incoming wave data is equal to the body size field of this
* header, less the size of a WaveInfo PDU (not including the header),
* thus body_size - 12.
*/
rdpsnd->incoming_wave_size = header->body_size - 12;
/* Read wave in next iteration */
rdpsnd->next_pdu_is_wave = true;
/* Init stream with requested format */
audio_stream_begin(audio,
rdpsnd->formats[format].rate,
rdpsnd->formats[format].channels,
rdpsnd->formats[format].bps);
/* Write initial 4 bytes of data */
audio_stream_write_pcm(audio, buffer, 4);
}
void guac_rdpsnd_wave_handler(guac_rdpsndPlugin* rdpsnd,
audio_stream* audio, STREAM* input_stream,
guac_rdpsnd_pdu_header* header) {
rdpSvcPlugin* plugin = (rdpSvcPlugin*)rdpsnd;
rdp_guac_client_data* guac_client_data =
(rdp_guac_client_data*) audio->client->data;
/* Wave Confirmation PDU */
STREAM* output_stream = stream_new(8);
/* Get wave data */
unsigned char* buffer = stream_get_head(input_stream) + 4;
/* Write rest of audio packet */
audio_stream_write_pcm(audio, buffer, rdpsnd->incoming_wave_size);
audio_stream_end(audio);
/* Write Wave Confirmation PDU */
stream_write_uint8(output_stream, SNDC_WAVECONFIRM);
stream_write_uint8(output_stream, 0);
stream_write_uint16(output_stream, 4);
stream_write_uint16(output_stream, rdpsnd->server_timestamp);
stream_write_uint8(output_stream, rdpsnd->waveinfo_block_number);
stream_write_uint8(output_stream, 0);
/* Send Wave Confirmation PDU */
pthread_mutex_lock(&(guac_client_data->rdp_lock));
svc_plugin_send(plugin, output_stream);
pthread_mutex_unlock(&(guac_client_data->rdp_lock));
/* We no longer expect to receive wave data */
rdpsnd->next_pdu_is_wave = false;
}
void guac_rdpsnd_close_handler(guac_rdpsndPlugin* rdpsnd,
audio_stream* audio, STREAM* input_stream,
guac_rdpsnd_pdu_header* header) {
/* STUB: Do nothing for now */
}

View File

@ -0,0 +1,162 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __GUAC_RDPSND_MESSAGES_H
#define __GUAC_RDPSND_MESSAGES_H
/*
* PDU Message Types
*/
/**
* Close PDU
*/
#define SNDC_CLOSE 1
/**
* WaveInfo PDU. This PDU is sent just before wave data is sent.
*/
#define SNDC_WAVE 2
/**
* Wave Confirm PDU. This PDU is sent in response to the WaveInfo PDU,
* confirming it has been received and played.
*/
#define SNDC_WAVECONFIRM 5
/**
* Training PDU. This PDU is sent by the server occasionally and must be
* responded to with another training PDU, similar to Guac's sync message.
*/
#define SNDC_TRAINING 6
/**
* Server Audio Formats and Version PDU. This PDU is sent by the server to
* advertise to the client which audio formats are supported.
*/
#define SNDC_FORMATS 7
/**
* Quality Mode PDU. This PDU must be sent by the client to select an audio
* quality mode if the server is at least version 6.
*/
#define SNDC_QUALITYMODE 12
/*
* Quality Modes
*/
/**
* Dynamic Quality. The server will choose the audio quality based on its
* perception of latency.
*/
#define DYNAMIC_QUALITY 0x0000
/**
* Medium Quality. The server prioritizes bandwidth over quality.
*/
#define MEDIUM_QUALITY 0x0001
/**
* High Quality. The server prioritizes quality over bandwidth.
*/
#define HIGH_QUALITY 0x0002
/*
* Capabilities
*/
#define TSSNDCAPS_ALIVE 1
/*
* Sound Formats
*/
#define WAVE_FORMAT_PCM 1
/**
* The header common to all RDPSND PDUs.
*/
typedef struct guac_rdpsnd_pdu_header {
/**
* The type of message represented by this PDU (SNDC_WAVE, etc.)
*/
int message_type;
/**
* The size of the remainder of the message.
*/
int body_size;
} guac_rdpsnd_pdu_header;
/**
* Handler for the SNDC_FORMATS (Server Audio Formats and Version) PDU.
*/
void guac_rdpsnd_formats_handler(guac_rdpsndPlugin* rdpsnd,
audio_stream* audio, STREAM* input_stream,
guac_rdpsnd_pdu_header* header);
/**
* Handler for the SNDC_TRAINING (Training) PDU.
*/
void guac_rdpsnd_training_handler(guac_rdpsndPlugin* rdpsnd,
audio_stream* audio, STREAM* input_stream,
guac_rdpsnd_pdu_header* header);
/**
* Handler for the SNDC_WAVE (WaveInfo) PDU.
*/
void guac_rdpsnd_wave_info_handler(guac_rdpsndPlugin* rdpsnd,
audio_stream* audio, STREAM* input_stream,
guac_rdpsnd_pdu_header* header);
/**
* Handler for the SNDWAV (Wave) PDU which follows any WaveInfo PDU.
*/
void guac_rdpsnd_wave_handler(guac_rdpsndPlugin* rdpsnd,
audio_stream* audio, STREAM* input_stream,
guac_rdpsnd_pdu_header* header);
/**
* Handler for the SNDC_CLOSE (Close) PDU.
*/
void guac_rdpsnd_close_handler(guac_rdpsndPlugin* rdpsnd,
audio_stream* audio, STREAM* input_stream,
guac_rdpsnd_pdu_header* header);
#endif

View File

@ -0,0 +1,140 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <stdlib.h>
#include <string.h>
#include <freerdp/constants.h>
#include <freerdp/types.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/stream.h>
#include <freerdp/utils/svc_plugin.h>
#include <guacamole/client.h>
#include "audio.h"
#include "service.h"
#include "messages.h"
/* Define service, associate with "rdpsnd" channel */
DEFINE_SVC_PLUGIN(guac_rdpsnd, "rdpsnd",
CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP)
/*
* Service Handlers
*/
void guac_rdpsnd_process_connect(rdpSvcPlugin* plugin) {
/* Get audio stream from plugin */
audio_stream* audio = (audio_stream*)
plugin->channel_entry_points.pExtendedData;
/* Update every 10 ms */
plugin->interval_ms = 10;
/* Log that sound has been loaded */
guac_client_log_info(audio->client, "guac_rdpsnd connected.");
}
void guac_rdpsnd_process_terminate(rdpSvcPlugin* plugin) {
xfree(plugin);
}
void guac_rdpsnd_process_event(rdpSvcPlugin* plugin, RDP_EVENT* event) {
freerdp_event_free(event);
}
void guac_rdpsnd_process_receive(rdpSvcPlugin* plugin,
STREAM* input_stream) {
guac_rdpsndPlugin* rdpsnd = (guac_rdpsndPlugin*) plugin;
guac_rdpsnd_pdu_header header;
/* Get audio stream from plugin */
audio_stream* audio = (audio_stream*)
plugin->channel_entry_points.pExtendedData;
/* Read RDPSND PDU header */
stream_read_uint8(input_stream, header.message_type);
stream_seek_uint8(input_stream);
stream_read_uint16(input_stream, header.body_size);
/*
* If next PDU is SNDWAVE (due to receiving WaveInfo PDU previously),
* ignore the header and parse as a Wave PDU.
*/
if (rdpsnd->next_pdu_is_wave) {
guac_rdpsnd_wave_handler(rdpsnd, audio, input_stream, &header);
return;
}
/* Dispatch message to standard handlers */
switch (header.message_type) {
/* Server Audio Formats and Version PDU */
case SNDC_FORMATS:
guac_rdpsnd_formats_handler(rdpsnd, audio,
input_stream, &header);
break;
/* Training PDU */
case SNDC_TRAINING:
guac_rdpsnd_training_handler(rdpsnd, audio,
input_stream, &header);
break;
/* WaveInfo PDU */
case SNDC_WAVE:
guac_rdpsnd_wave_info_handler(rdpsnd, audio,
input_stream, &header);
break;
/* Close PDU */
case SNDC_CLOSE:
guac_rdpsnd_close_handler(rdpsnd, audio,
input_stream, &header);
break;
}
}

View File

@ -0,0 +1,146 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __GUAC_RDPSND_SERVICE_H
#define __GUAC_RDPSND_SERVICE_H
/**
* The maximum number of PCM formats to accept during the initial RDPSND
* handshake with the RDP server.
*/
#define GUAC_RDP_MAX_FORMATS 16
/**
* Abstract representation of a PCM format, including the sample rate, number
* of channels, and bits per sample.
*/
typedef struct guac_pcm_format {
/**
* The sample rate of this PCM format.
*/
int rate;
/**
* The number off channels used by this PCM format. This will typically
* be 1 or 2.
*/
int channels;
/**
* The number of bits per sample within this PCM format. This should be
* either 8 or 16.
*/
int bps;
} guac_pcm_format;
/**
* Structure representing the current state of the Guacamole RDPSND plugin for
* FreeRDP.
*/
typedef struct guac_rdpsndPlugin {
/**
* The FreeRDP parts of this plugin. This absolutely MUST be first.
* FreeRDP depends on accessing this structure as if it were an instance
* of rdpSvcPlugin.
*/
rdpSvcPlugin plugin;
/**
* The block number of the last SNDC_WAVE (WaveInfo) PDU received.
*/
int waveinfo_block_number;
/**
* Whether the next PDU coming is a SNDWAVE (Wave) PDU. Wave PDUs do not
* have headers, and are indicated by the receipt of a WaveInfo PDU.
*/
int next_pdu_is_wave;
/**
* The size, in bytes, of the wave data in the coming Wave PDU, if any.
*/
int incoming_wave_size;
/**
* The last received server timestamp.
*/
int server_timestamp;
/**
* All formats agreed upon by server and client during the initial format
* exchange. All of these formats will be PCM, which is the only format
* guaranteed to be supported (based on the official RDP documentation).
*/
guac_pcm_format formats[GUAC_RDP_MAX_FORMATS];
/**
* The total number of formats.
*/
int format_count;
} guac_rdpsndPlugin;
/**
* Handler called when this plugin is loaded by FreeRDP.
*/
void guac_rdpsnd_process_connect(rdpSvcPlugin* plugin);
/**
* Handler called when this plugin receives data along its designated channel.
*/
void guac_rdpsnd_process_receive(rdpSvcPlugin* plugin,
STREAM* input_stream);
/**
* Handler called when this plugin is being unloaded.
*/
void guac_rdpsnd_process_terminate(rdpSvcPlugin* plugin);
/**
* Handler called when this plugin receives an event. For the sake of RDPSND,
* all events will be ignored and simply free'd.
*/
void guac_rdpsnd_process_event(rdpSvcPlugin* plugin, RDP_EVENT* event);
#endif

View File

@ -0,0 +1,212 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __GUAC_TEST_AUDIO_H
#define __GUAC_TEST_AUDIO_H
#include <guacamole/client.h>
#include <guacamole/stream.h>
typedef struct audio_stream audio_stream;
/**
* Handler which is called when the audio stream is opened.
*/
typedef void audio_encoder_begin_handler(audio_stream* audio);
/**
* Handler which is called when the audio stream is closed.
*/
typedef void audio_encoder_end_handler(audio_stream* audio);
/**
* Handler which is called when the audio stream is flushed.
*/
typedef void audio_encoder_write_handler(audio_stream* audio,
unsigned char* pcm_data, int length);
/**
* Arbitrary audio codec encoder.
*/
typedef struct audio_encoder {
/**
* The mimetype of the audio data encoded by this audio
* encoder.
*/
const char* mimetype;
/**
* Handler which will be called when the audio stream is opened.
*/
audio_encoder_begin_handler* begin_handler;
/**
* Handler which will be called when the audio stream is flushed.
*/
audio_encoder_write_handler* write_handler;
/**
* Handler which will be called when the audio stream is closed.
*/
audio_encoder_end_handler* end_handler;
} audio_encoder;
/**
* Basic audio stream. PCM data is added to the stream. When the stream is
* flushed, a write handler receives PCM data packets and, presumably, streams
* them to the guac_stream provided.
*/
struct audio_stream {
/**
* PCM data buffer, 16-bit samples, 2-channel, 44100 Hz.
*/
unsigned char* pcm_data;
/**
* Number of bytes in buffer.
*/
int used;
/**
* Maximum number of bytes in buffer.
*/
int length;
/**
* Encoded audio data buffer, as written by the encoder.
*/
unsigned char* encoded_data;
/**
* Number of bytes in the encoded data buffer.
*/
int encoded_data_used;
/**
* Maximum number of bytes in the encoded data buffer.
*/
int encoded_data_length;
/**
* Arbitrary codec encoder. When the PCM buffer is flushed, PCM data will
* be sent to this encoder.
*/
audio_encoder* encoder;
/**
* The client associated with this audio stream.
*/
guac_client* client;
/**
* The actual stream associated with this audio stream.
*/
guac_stream* stream;
/**
* The number of samples per second of PCM data sent to this stream.
*/
int rate;
/**
* The number of audio channels per sample of PCM data. Legal values are
* 1 or 2.
*/
int channels;
/**
* The number of bits per sample per channel for PCM data. Legal values are
* 8 or 16.
*/
int bps;
/**
* The number of PCM bytes written since the audio chunk began.
*/
int pcm_bytes_written;
/**
* Encoder-specific state data.
*/
void* data;
};
/**
* Allocates a new audio stream.
*/
audio_stream* audio_stream_alloc(guac_client* client,
audio_encoder* encoder);
/**
* Frees the given audio stream.
*/
void audio_stream_free(audio_stream* stream);
/**
* Begins a new audio stream.
*/
void audio_stream_begin(audio_stream* stream, int rate, int channels, int bps);
/**
* Ends the current audio stream.
*/
void audio_stream_end(audio_stream* stream);
/**
* Writes PCM data to the given audio stream.
*/
void audio_stream_write_pcm(audio_stream* stream,
unsigned char* data, int length);
/**
* Flushes the given audio stream.
*/
void audio_stream_flush(audio_stream* stream);
/**
* Appends arbitrarily-encoded data to the encoded_data buffer
* within the given audio stream.
*/
void audio_stream_write_encoded(audio_stream* audio,
unsigned char* data, int length);
#endif

View File

@ -0,0 +1,221 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef _GUAC_RDP_CLIENT_H
#define _GUAC_RDP_CLIENT_H
#include <cairo/cairo.h>
#include <freerdp/freerdp.h>
#include <freerdp/codec/color.h>
#include <guacamole/client.h>
#include "audio.h"
#include "rdp_keymap.h"
/**
* The default RDP port.
*/
#define RDP_DEFAULT_PORT 3389
/**
* Default screen width, in pixels.
*/
#define RDP_DEFAULT_WIDTH 1024
/**
* Default screen height, in pixels.
*/
#define RDP_DEFAULT_HEIGHT 768
/**
* Default color depth, in bits.
*/
#define RDP_DEFAULT_DEPTH 16
/**
* Client data that will remain accessible through the guac_client.
* This should generally include data commonly used by Guacamole handlers.
*/
typedef struct rdp_guac_client_data {
/**
* Pointer to the FreeRDP client instance handling the current connection.
*/
freerdp* rdp_inst;
/**
* The settings structure associated with the FreeRDP client instance
* handling the current connection.
*/
rdpSettings* settings;
/**
* Button mask containing the OR'd value of all currently pressed buttons.
*/
int mouse_button_mask;
/**
* Cairo surface which will receive all TRANSPARENT glyphs.
*/
cairo_surface_t* trans_glyph_surface;
/**
* Cairo surface which will receive all OPAQUE glyphs.
*/
cairo_surface_t* opaque_glyph_surface;
/**
* The current Cairo surface which will receive all drawn glyphs,
* depending on whether we are currently drawing transparent or
* opaque glyphs.
*/
cairo_surface_t* glyph_surface;
/**
* Cairo instance for drawing to the current glyph surface.
*/
cairo_t* glyph_cairo;
/**
* The Guacamole layer that GDI operations should draw to. RDP messages
* exist which change this surface to allow drawing to occur off-screen.
*/
const guac_layer* current_surface;
/**
* Whether graphical operations are restricted to a specific bounding
* rectangle.
*/
int bounded;
/**
* The X coordinate of the upper-left corner of the bounding rectangle,
* if any.
*/
int bounds_left;
/**
* The Y coordinate of the upper-left corner of the bounding rectangle,
* if any.
*/
int bounds_top;
/**
* The X coordinate of the lower-right corner of the bounding rectangle,
* if any.
*/
int bounds_right;
/**
* The Y coordinate of the lower-right corner of the bounding rectangle,
* if any.
*/
int bounds_bottom;
/**
* The keymap to use when translating keysyms into scancodes or sequences
* of scancodes for RDP.
*/
guac_rdp_static_keymap keymap;
/**
* The state of all keys, based on whether events for pressing/releasing
* particular keysyms have been received. This is necessary in order to
* determine which keys must be released/pressed when a particular
* keysym can only be typed through a sequence of scancodes (such as
* an Alt-code) because the server-side keymap does not support that
* keysym.
*/
guac_rdp_keysym_state_map keysym_state;
/**
* The current text (NOT Unicode) clipboard contents.
*/
char* clipboard;
/**
* Whether audio is enabled.
*/
int audio_enabled;
/**
* Audio output, if any.
*/
audio_stream* audio;
/**
* Lock which is locked and unlocked for each update.
*/
pthread_mutex_t update_lock;
/**
* Lock which is locked and unlocked for each RDP message.
*/
pthread_mutex_t rdp_lock;
pthread_mutexattr_t attributes;
} rdp_guac_client_data;
/**
* Client data that will remain accessible through the RDP context.
* This should generally include data commonly used by FreeRDP handlers.
*/
typedef struct rdp_freerdp_context {
/**
* The parent context. THIS MUST BE THE FIRST ELEMENT.
*/
rdpContext _p;
/**
* Pointer to the guac_client instance handling the RDP connection with
* this context.
*/
guac_client* client;
/**
* Color conversion structure to be used to convert RDP images to PNGs.
*/
CLRCONV* clrconv;
} rdp_freerdp_context;
#endif

View File

View File

@ -0,0 +1,76 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef _GUAC_RDP_DEFAULT_POINTER_H
#define _GUAC_RDP_DEFAULT_POINTER_H
#include <cairo/cairo.h>
#include <guacamole/client.h>
/**
* Width of the embedded mouse cursor graphic.
*/
extern const int guac_rdp_default_pointer_width;
/**
* Height of the embedded mouse cursor graphic.
*/
extern const int guac_rdp_default_pointer_height;
/**
* Number of bytes in each row of the embedded mouse cursor graphic.
*/
extern const int guac_rdp_default_pointer_stride;
/**
* The Cairo grapic format of the mouse cursor graphic.
*/
extern const cairo_format_t guac_rdp_default_pointer_format;
/**
* Embedded mouse cursor graphic.
*/
extern unsigned char guac_rdp_default_pointer[];
/**
* Set the cursor of the remote display to the embedded cursor graphic.
*
* @param client The guac_client to send the cursor to.
*/
void guac_rdp_set_default_pointer(guac_client* client);
#endif

View File

@ -0,0 +1,50 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef _GUAC_RDP_GUAC_HANDLERS_H
#define _GUAC_RDP_GUAC_HANDLERS_H
#include <guacamole/client.h>
int rdp_guac_client_free_handler(guac_client* client);
int rdp_guac_client_handle_messages(guac_client* client);
int rdp_guac_client_mouse_handler(guac_client* client, int x, int y, int mask);
int rdp_guac_client_key_handler(guac_client* client, int keysym, int pressed);
int rdp_guac_client_clipboard_handler(guac_client* client, char* data);
#endif

View File

@ -0,0 +1,67 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __GUAC_OGG_ENCODER_H
#define __GUAC_OGG_ENCODER_H
#include "audio.h"
#include <vorbis/vorbisenc.h>
typedef struct ogg_encoder_state {
/**
* Ogg state
*/
ogg_stream_state ogg_state;
ogg_page ogg_page;
ogg_packet ogg_packet;
/**
* Vorbis state
*/
vorbis_info info;
vorbis_comment comment;
vorbis_dsp_state vorbis_state;
vorbis_block vorbis_block;
} ogg_encoder_state;
extern audio_encoder* ogg_encoder;
#endif

View File

@ -0,0 +1,71 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef _GUAC_RDP_RDP_BITMAP_H
#define _GUAC_RDP_RDP_BITMAP_H
#include <freerdp/freerdp.h>
#include <guacamole/protocol.h>
typedef struct guac_rdp_bitmap {
/**
* FreeRDP bitmap data - MUST GO FIRST.
*/
rdpBitmap bitmap;
/**
* Guacamole layer containing cached image data.
*/
guac_layer* layer;
/**
* The number of times a bitmap has been used.
*/
int used;
} guac_rdp_bitmap;
void guac_rdp_cache_bitmap(rdpContext* context, rdpBitmap* bitmap);
void guac_rdp_bitmap_new(rdpContext* context, rdpBitmap* bitmap);
void guac_rdp_bitmap_decompress(rdpContext* context, rdpBitmap* bitmap, uint8* data, int width, int height, int bpp, int length, boolean compressed);
void guac_rdp_bitmap_paint(rdpContext* context, rdpBitmap* bitmap);
void guac_rdp_bitmap_free(rdpContext* context, rdpBitmap* bitmap);
void guac_rdp_bitmap_setsurface(rdpContext* context, rdpBitmap* bitmap, boolean primary);
#endif

View File

@ -0,0 +1,56 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __GUAC_RDP_RDP_CLIPRDR_H
#define __GUAC_RDP_RDP_CLIPRDR_H
#include <freerdp/freerdp.h>
void guac_rdp_process_cliprdr_event(guac_client* client, RDP_EVENT* event);
void guac_rdp_process_cb_monitor_ready(guac_client* client, RDP_EVENT* event);
void guac_rdp_process_cb_format_list(guac_client* client,
RDP_CB_FORMAT_LIST_EVENT* event);
void guac_rdp_process_cb_data_request(guac_client* client,
RDP_CB_DATA_REQUEST_EVENT* event);
void guac_rdp_process_cb_data_response(guac_client* client,
RDP_CB_DATA_RESPONSE_EVENT* event);
#endif

View File

@ -0,0 +1,56 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef _GUAC_RDP_RDP_GDI_H
#define _GUAC_RDP_RDP_GDI_H
#include <guacamole/protocol.h>
#include <freerdp/freerdp.h>
guac_composite_mode guac_rdp_rop3_transfer_function(guac_client* client,
int rop3);
void guac_rdp_gdi_dstblt(rdpContext* context, DSTBLT_ORDER* dstblt);
void guac_rdp_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt);
void guac_rdp_gdi_scrblt(rdpContext* context, SCRBLT_ORDER* scrblt);
void guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt);
void guac_rdp_gdi_opaquerect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect);
void guac_rdp_gdi_palette_update(rdpContext* context, PALETTE_UPDATE* palette);
void guac_rdp_gdi_set_bounds(rdpContext* context, rdpBounds* bounds);
void guac_rdp_gdi_end_paint(rdpContext* context);
#endif

View File

@ -0,0 +1,67 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef _GUAC_RDP_RDP_GLYPH_H
#define _GUAC_RDP_RDP_GLYPH_H
#include <freerdp/freerdp.h>
#include <guacamole/protocol.h>
typedef struct guac_rdp_glyph {
/**
* FreeRDP glyph data - MUST GO FIRST.
*/
rdpGlyph glyph;
/**
* Cairo surface layer containing cached image data.
*/
cairo_surface_t* surface;
} guac_rdp_glyph;
void guac_rdp_glyph_new(rdpContext* context, rdpGlyph* glyph);
void guac_rdp_glyph_draw(rdpContext* context, rdpGlyph* glyph, int x, int y);
void guac_rdp_glyph_free(rdpContext* context, rdpGlyph* glyph);
void guac_rdp_glyph_begindraw(rdpContext* context,
int x, int y, int width, int height, uint32 fgcolor, uint32 bgcolor);
void guac_rdp_glyph_enddraw(rdpContext* context,
int x, int y, int width, int height, uint32 fgcolor, uint32 bgcolor);
#endif

View File

@ -0,0 +1,230 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef _GUAC_RDP_RDP_KEYMAP_H
#define _GUAC_RDP_RDP_KEYMAP_H
#ifdef HAVE_FREERDP_LOCALE_KEYBOARD_H
#include <freerdp/locale/keyboard.h>
#else
#include <freerdp/kbd/layouts.h>
#endif
/**
* Represents a keysym-to-scancode mapping for RDP, with extra information
* about the state of prerequisite keysyms.
*/
typedef struct guac_rdp_keysym_desc {
/**
* The keysym being mapped.
*/
int keysym;
/**
* The scancode this keysym maps to.
*/
int scancode;
/**
* Required RDP-specific flags.
*/
int flags;
/**
* Null-terminated list of keysyms which must be down for this keysym
* to be properly typed.
*/
const int* set_keysyms;
/**
* Null-terminated list of keysyms which must be up for this keysym
* to be properly typed.
*/
const int* clear_keysyms;
} guac_rdp_keysym_desc;
/**
* Hierarchical keysym mapping
*/
typedef struct guac_rdp_keymap guac_rdp_keymap;
struct guac_rdp_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_rdp_keymap* parent;
/**
* Descriptive name of this keymap
*/
const char* name;
/**
* Null-terminated array of scancode mappings.
*/
const guac_rdp_keysym_desc* mapping;
/**
* FreeRDP keyboard layout associated with this
* keymap. If this keymap is selected, this layout
* will be requested from the server.
*/
const uint32 freerdp_keyboard_layout;
};
/**
* Static mapping from keysyms to scancodes.
*/
typedef guac_rdp_keysym_desc guac_rdp_static_keymap[0x200][0x100];
/**
* Mapping from keysym to current state
*/
typedef int guac_rdp_keysym_state_map[0x200][0x100];
/**
* US English keymap.
*/
extern const guac_rdp_keymap guac_rdp_keymap_en_us;
/**
* German keymap.
*/
extern const guac_rdp_keymap guac_rdp_keymap_de_de;
/**
* French keymap.
*/
extern const guac_rdp_keymap guac_rdp_keymap_fr_fr;
/**
* Failsafe (Unicode events for all printable characters) keymap.
*/
extern const guac_rdp_keymap guac_rdp_keymap_failsafe;
/**
* Common, base keymap for non-printable keys.
*/
extern const guac_rdp_keymap guac_rdp_keymap_base;
/**
* Simple macro for determing whether a keysym can be stored (or retrieved)
* from any keymap.
*/
#define GUAC_RDP_KEYSYM_STORABLE(keysym) ((keysym) <= 0xFFFF || ((keysym) & 0xFFFF0000) == 0x01000000)
/**
* Simple macro for referencing the mapped value of a scancode for a given
* keysym. The idea here is that a keysym of the form 0xABCD will map to
* mapping[0xAB][0xCD] while a keysym of the form 0x100ABCD will map to
* mapping[0x1AB][0xCD].
*/
#define GUAC_RDP_KEYSYM_LOOKUP(keysym_mapping, keysym) ( \
(keysym_mapping) \
[(((keysym) & 0xFF00) >> 8) | ((keysym) >> 16)] \
[(keysym) & 0xFF] \
)
/**
* Keysym string containing only the left "shift" key.
*/
extern const int GUAC_KEYSYMS_SHIFT[];
/**
* Keysym string containing both "shift" keys.
*/
extern const int GUAC_KEYSYMS_ALL_SHIFT[];
/**
* Keysym string containing only the right "alt" key (AltGr).
*/
extern const int GUAC_KEYSYMS_ALTGR[];
/**
* Keysym string containing the right "alt" key (AltGr) and
* left shift.
*/
extern const int GUAC_KEYSYMS_SHIFT_ALTGR[];
/**
* Keysym string containing the right "alt" key (AltGr) and
* both shift keys.
*/
extern const int GUAC_KEYSYMS_ALL_SHIFT_ALTGR[];
/**
* Keysym string containing only the left "ctrl" key.
*/
extern const int GUAC_KEYSYMS_CTRL[];
/**
* Keysym string containing both "ctrl" keys.
*/
extern const int GUAC_KEYSYMS_ALL_CTRL[];
/**
* Keysym string containing only the left "alt" key.
*/
extern const int GUAC_KEYSYMS_ALT[];
/**
* Keysym string containing both "alt" keys.
*/
extern const int GUAC_KEYSYMS_ALL_ALT[];
/**
* Keysym string containing the left "alt" and left "ctrl" keys
*/
extern const int GUAC_KEYSYMS_CTRL_ALT[];
/**
* Keysym string containing all modifier keys.
*/
extern const int GUAC_KEYSYMS_ALL_MODIFIERS[];
/**
* NULL-terminated array of all keymaps.
*/
extern const guac_rdp_keymap* GUAC_KEYMAPS[];
#endif

View File

@ -0,0 +1,66 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David PHAM-VAN <d.pham-van@ulteo.com> Ulteo SAS - http://www.ulteo.com
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef _GUAC_RDP_RDP_POINTER_H
#define _GUAC_RDP_RDP_POINTER_H
#include <freerdp/freerdp.h>
#include <guacamole/protocol.h>
typedef struct guac_rdp_pointer {
/**
* FreeRDP pointer data - MUST GO FIRST.
*/
rdpPointer pointer;
/**
* Guacamole layer containing cached image data.
*/
guac_layer* layer;
} guac_rdp_pointer;
void guac_rdp_pointer_new(rdpContext* context, rdpPointer* pointer);
void guac_rdp_pointer_set(rdpContext* context, rdpPointer* pointer);
void guac_rdp_pointer_free(rdpContext* context, rdpPointer* pointer);
void guac_rdp_pointer_set_null(rdpContext* context);
void guac_rdp_pointer_set_default(rdpContext* context);
#endif

View File

@ -0,0 +1,144 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __GUAC_WAV_ENCODER_H
#define __GUAC_WAV_ENCODER_H
#include "audio.h"
typedef struct wav_encoder_riff_header {
/**
* The RIFF chunk header, normally the string "RIFF".
*/
unsigned char chunk_id[4];
/**
* Size of the entire file, not including chunk_id or chunk_size.
*/
unsigned char chunk_size[4];
/**
* The format of this file, normally the string "WAVE".
*/
unsigned char chunk_format[4];
} wav_encoder_riff_header;
typedef struct wav_encoder_fmt_header {
/**
* ID of this subchunk. For the fmt subchunk, this should be "fmt ".
*/
unsigned char subchunk_id[4];
/**
* The size of the rest of this subchunk. For PCM, this will be 16.
*/
unsigned char subchunk_size[4];
/**
* Format of this subchunk. For PCM, this will be 1.
*/
unsigned char subchunk_format[2];
/**
* The number of channels in the PCM data.
*/
unsigned char subchunk_channels[2];
/**
* The sample rate of the PCM data.
*/
unsigned char subchunk_sample_rate[4];
/**
* The sample rate of the PCM data in bytes per second.
*/
unsigned char subchunk_byte_rate[4];
/**
* The number of bytes per sample.
*/
unsigned char subchunk_block_align[2];
/**
* The number of bits per sample.
*/
unsigned char subchunk_bps[2];
} wav_encoder_fmt_header;
typedef struct wav_encoder_state {
/**
* Arbitrary PCM data available for writing when the overall WAV is
* flushed.
*/
unsigned char* data_buffer;
/**
* The number of bytes currently present in the data buffer.
*/
int used;
/**
* The total number of bytes that can be written into the data buffer
* without requiring resizing.
*/
int length;
} wav_encoder_state;
typedef struct wav_encoder_data_header {
/**
* ID of this subchunk. For the data subchunk, this should be "data".
*/
unsigned char subchunk_id[4];
/**
* The number of bytes in the PCM data.
*/
unsigned char subchunk_size[4];
} wav_encoder_data_header;
extern audio_encoder* wav_encoder;
#endif

12
protocols/rdp/m4/README Normal file
View File

@ -0,0 +1,12 @@
This file exists such that the m4/ directory will be created when cloning the
git repository.
The m4/ directory is not directly used by this project, but libtoolize
populates this directory with files, recommending that the directory be
included in the macro search path for aclocal.
Because autoreconf runs aclocal before libtoolize, this directory will not
exist when autoreconf is run, triggering an error from aclocal.
Creating this directory (and keeping this file in it as a placeholder)
prevents this error.

179
protocols/rdp/src/audio.c Normal file
View File

@ -0,0 +1,179 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <guacamole/protocol.h>
#include <guacamole/client.h>
#include <guacamole/stream.h>
#include "audio.h"
#include "client.h"
audio_stream* audio_stream_alloc(guac_client* client, audio_encoder* encoder) {
/* Allocate stream */
audio_stream* audio = (audio_stream*) malloc(sizeof(audio_stream));
audio->client = client;
/* Reset buffer stats */
audio->used = 0;
audio->length = 0x40000;
audio->encoded_data_used = 0;
audio->encoded_data_length = 0x40000;
/* Allocate buffers */
audio->pcm_data = malloc(audio->length);
audio->encoded_data = malloc(audio->encoded_data_length);
/* Assign encoder */
audio->encoder = encoder;
audio->stream = guac_client_alloc_stream(client);
return audio;
}
void audio_stream_begin(audio_stream* audio, int rate, int channels, int bps) {
/* Load PCM properties */
audio->rate = rate;
audio->channels = channels;
audio->bps = bps;
/* Reset write counter */
audio->pcm_bytes_written = 0;
/* Call handler */
audio->encoder->begin_handler(audio);
}
void audio_stream_end(audio_stream* audio) {
double duration;
rdp_guac_client_data* data = (rdp_guac_client_data*) audio->client->data;
/* Flush stream and finish encoding */
audio_stream_flush(audio);
audio->encoder->end_handler(audio);
/* Calculate duration of PCM data */
duration = ((double) (audio->pcm_bytes_written * 1000 * 8))
/ audio->rate / audio->channels / audio->bps;
pthread_mutex_lock(&(data->update_lock));
/* Send audio */
guac_protocol_send_audio(audio->stream->socket,
0, audio->encoder->mimetype,
duration, audio->encoded_data, audio->encoded_data_used);
pthread_mutex_unlock(&(data->update_lock));
/* Clear data */
audio->encoded_data_used = 0;
}
void audio_stream_free(audio_stream* audio) {
free(audio->pcm_data);
free(audio);
}
void audio_stream_write_pcm(audio_stream* audio,
unsigned char* data, int length) {
/* Update counter */
audio->pcm_bytes_written += length;
/* Resize audio buffer if necessary */
if (length > audio->length) {
/* Resize to double provided length */
audio->length = length*2;
audio->pcm_data = realloc(audio->pcm_data, audio->length);
}
/* Flush if necessary */
if (audio->used + length > audio->length)
audio_stream_flush(audio);
/* Append to buffer */
memcpy(&(audio->pcm_data[audio->used]), data, length);
audio->used += length;
}
void audio_stream_flush(audio_stream* audio) {
/* If data in buffer */
if (audio->used != 0) {
/* Write data */
audio->encoder->write_handler(audio,
audio->pcm_data, audio->used);
/* Reset buffer */
audio->used = 0;
}
}
void audio_stream_write_encoded(audio_stream* audio,
unsigned char* data, int length) {
/* Resize audio buffer if necessary */
if (audio->encoded_data_used + length > audio->encoded_data_length) {
/* Increase to double concatenated size to accomodate */
audio->encoded_data_length = (audio->encoded_data_length + length)*2;
audio->encoded_data = realloc(audio->encoded_data,
audio->encoded_data_length);
}
/* Append to buffer */
memcpy(&(audio->encoded_data[audio->encoded_data_used]), data, length);
audio->encoded_data_used += length;
}

602
protocols/rdp/src/client.c Normal file
View File

@ -0,0 +1,602 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Matt Hortman
* David PHAM-VAN <d.pham-van@ulteo.com> Ulteo SAS - http://www.ulteo.com
* Laurent Meunier <laurent@deltalima.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#define _XOPEN_SOURCE 500
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/select.h>
#include <errno.h>
#include <freerdp/freerdp.h>
#include <freerdp/utils/memory.h>
#include <freerdp/cache/bitmap.h>
#include <freerdp/cache/brush.h>
#include <freerdp/cache/glyph.h>
#include <freerdp/cache/palette.h>
#include <freerdp/cache/pointer.h>
#include <freerdp/cache/offscreen.h>
#include <freerdp/channels/channels.h>
#include <freerdp/input.h>
#include <freerdp/constants.h>
#include <guacamole/socket.h>
#include <guacamole/protocol.h>
#include <guacamole/client.h>
#include <guacamole/error.h>
#include "audio.h"
#include "wav_encoder.h"
#ifdef ENABLE_OGG
#include "ogg_encoder.h"
#endif
#include "client.h"
#include "guac_handlers.h"
#include "rdp_keymap.h"
#include "rdp_bitmap.h"
#include "rdp_glyph.h"
#include "rdp_pointer.h"
#include "rdp_gdi.h"
#include "default_pointer.h"
/* Client plugin arguments */
const char* GUAC_CLIENT_ARGS[] = {
"hostname",
"port",
"domain",
"username",
"password",
"width",
"height",
"initial-program",
"color-depth",
"disable-audio",
"console",
"console-audio",
"server-layout",
NULL
};
enum RDP_ARGS_IDX {
IDX_HOSTNAME,
IDX_PORT,
IDX_DOMAIN,
IDX_USERNAME,
IDX_PASSWORD,
IDX_WIDTH,
IDX_HEIGHT,
IDX_INITIAL_PROGRAM,
IDX_COLOR_DEPTH,
IDX_DISABLE_AUDIO,
IDX_CONSOLE,
IDX_CONSOLE_AUDIO,
IDX_SERVER_LAYOUT,
RDP_ARGS_COUNT
};
int __guac_receive_channel_data(freerdp* rdp_inst, int channelId, uint8* data, int size, int flags, int total_size) {
return freerdp_channels_data(rdp_inst, channelId, data, size, flags, total_size);
}
boolean rdp_freerdp_pre_connect(freerdp* instance) {
rdpContext* context = instance->context;
guac_client* client = ((rdp_freerdp_context*) context)->client;
rdpChannels* channels = context->channels;
rdpBitmap* bitmap;
rdpGlyph* glyph;
rdpPointer* pointer;
rdpPrimaryUpdate* primary;
CLRCONV* clrconv;
int i;
rdp_guac_client_data* guac_client_data =
(rdp_guac_client_data*) client->data;
/* Load clipboard plugin */
if (freerdp_channels_load_plugin(channels, instance->settings,
"cliprdr", NULL))
guac_client_log_error(client, "Failed to load cliprdr plugin.");
/* If audio enabled, choose an encoder */
if (guac_client_data->audio_enabled) {
/* Choose an encoding */
for (i=0; client->info.audio_mimetypes[i] != NULL; i++) {
const char* mimetype = client->info.audio_mimetypes[i];
#ifdef ENABLE_OGG
/* If Ogg is supported, done. */
if (strcmp(mimetype, ogg_encoder->mimetype) == 0) {
guac_client_log_info(client, "Loading Ogg Vorbis encoder.");
guac_client_data->audio = audio_stream_alloc(client,
ogg_encoder);
break;
}
#endif
/* If wav is supported, done. */
if (strcmp(mimetype, wav_encoder->mimetype) == 0) {
guac_client_log_info(client, "Loading wav encoder.");
guac_client_data->audio = audio_stream_alloc(client,
wav_encoder);
break;
}
}
/* If an encoding is available, load the sound plugin */
if (guac_client_data->audio != NULL) {
/* Load sound plugin */
if (freerdp_channels_load_plugin(channels, instance->settings,
"guac_rdpsnd", guac_client_data->audio))
guac_client_log_error(client,
"Failed to load guac_rdpsnd plugin.");
}
else
guac_client_log_info(client,
"No available audio encoding. Sound disabled.");
} /* end if audio enabled */
/* Init color conversion structure */
clrconv = xnew(CLRCONV);
clrconv->alpha = 1;
clrconv->invert = 0;
clrconv->rgb555 = 0;
clrconv->palette = xnew(rdpPalette);
((rdp_freerdp_context*) context)->clrconv = clrconv;
/* Init FreeRDP cache */
instance->context->cache = cache_new(instance->settings);
/* Set up bitmap handling */
bitmap = xnew(rdpBitmap);
bitmap->size = sizeof(guac_rdp_bitmap);
bitmap->New = guac_rdp_bitmap_new;
bitmap->Free = guac_rdp_bitmap_free;
bitmap->Paint = guac_rdp_bitmap_paint;
bitmap->Decompress = guac_rdp_bitmap_decompress;
bitmap->SetSurface = guac_rdp_bitmap_setsurface;
graphics_register_bitmap(context->graphics, bitmap);
xfree(bitmap);
/* Set up glyph handling */
glyph = xnew(rdpGlyph);
glyph->size = sizeof(guac_rdp_glyph);
glyph->New = guac_rdp_glyph_new;
glyph->Free = guac_rdp_glyph_free;
glyph->Draw = guac_rdp_glyph_draw;
glyph->BeginDraw = guac_rdp_glyph_begindraw;
glyph->EndDraw = guac_rdp_glyph_enddraw;
graphics_register_glyph(context->graphics, glyph);
xfree(glyph);
/* Set up pointer handling */
pointer = xnew(rdpPointer);
pointer->size = sizeof(guac_rdp_pointer);
pointer->New = guac_rdp_pointer_new;
pointer->Free = guac_rdp_pointer_free;
pointer->Set = guac_rdp_pointer_set;
#ifdef HAVE_RDPPOINTER_SETNULL
pointer->SetNull = guac_rdp_pointer_set_null;
#endif
#ifdef HAVE_RDPPOINTER_SETDEFAULT
pointer->SetDefault = guac_rdp_pointer_set_default;
#endif
graphics_register_pointer(context->graphics, pointer);
xfree(pointer);
/* Set up GDI */
instance->update->EndPaint = guac_rdp_gdi_end_paint;
instance->update->Palette = guac_rdp_gdi_palette_update;
instance->update->SetBounds = guac_rdp_gdi_set_bounds;
primary = instance->update->primary;
primary->DstBlt = guac_rdp_gdi_dstblt;
primary->PatBlt = guac_rdp_gdi_patblt;
primary->ScrBlt = guac_rdp_gdi_scrblt;
primary->MemBlt = guac_rdp_gdi_memblt;
primary->OpaqueRect = guac_rdp_gdi_opaquerect;
pointer_cache_register_callbacks(instance->update);
glyph_cache_register_callbacks(instance->update);
brush_cache_register_callbacks(instance->update);
bitmap_cache_register_callbacks(instance->update);
offscreen_cache_register_callbacks(instance->update);
palette_cache_register_callbacks(instance->update);
/* Init channels (pre-connect) */
if (freerdp_channels_pre_connect(channels, instance)) {
guac_protocol_send_error(client->socket, "Error initializing RDP client channel manager");
guac_socket_flush(client->socket);
return false;
}
return true;
}
boolean rdp_freerdp_post_connect(freerdp* instance) {
rdpContext* context = instance->context;
guac_client* client = ((rdp_freerdp_context*) context)->client;
rdpChannels* channels = instance->context->channels;
/* Init channels (post-connect) */
if (freerdp_channels_post_connect(channels, instance)) {
guac_protocol_send_error(client->socket, "Error initializing RDP client channel manager");
guac_socket_flush(client->socket);
return false;
}
/* Client handlers */
client->free_handler = rdp_guac_client_free_handler;
client->handle_messages = rdp_guac_client_handle_messages;
client->mouse_handler = rdp_guac_client_mouse_handler;
client->key_handler = rdp_guac_client_key_handler;
client->clipboard_handler = rdp_guac_client_clipboard_handler;
return true;
}
void rdp_freerdp_context_new(freerdp* instance, rdpContext* context) {
context->channels = freerdp_channels_new();
}
void rdp_freerdp_context_free(freerdp* instance, rdpContext* context) {
/* EMPTY */
}
void __guac_rdp_client_load_keymap(guac_client* client,
const guac_rdp_keymap* keymap) {
rdp_guac_client_data* guac_client_data =
(rdp_guac_client_data*) client->data;
/* Get mapping */
const guac_rdp_keysym_desc* mapping = keymap->mapping;
/* If parent exists, load parent first */
if (keymap->parent != NULL)
__guac_rdp_client_load_keymap(client, keymap->parent);
/* Log load */
guac_client_log_info(client, "Loading keymap \"%s\"", keymap->name);
/* Load mapping into keymap */
while (mapping->keysym != 0) {
/* Copy mapping */
GUAC_RDP_KEYSYM_LOOKUP(guac_client_data->keymap, mapping->keysym) =
*mapping;
/* Next keysym */
mapping++;
}
}
int guac_client_init(guac_client* client, int argc, char** argv) {
rdp_guac_client_data* guac_client_data;
freerdp* rdp_inst;
rdpSettings* settings;
char* hostname;
int port = RDP_DEFAULT_PORT;
boolean bitmap_cache;
/**
* Selected server-side keymap. Client will be assumed to also use this
* keymap. Keys will be sent to server based on client input on a
* best-effort basis.
*/
const guac_rdp_keymap* chosen_keymap;
if (argc < RDP_ARGS_COUNT) {
guac_protocol_send_error(client->socket,
"Wrong argument count received.");
guac_socket_flush(client->socket);
guac_error = GUAC_STATUS_BAD_ARGUMENT;
guac_error_message = "Wrong argument count received";
return 1;
}
/* If port specified, use it */
if (argv[IDX_PORT][0] != '\0')
port = atoi(argv[IDX_PORT]);
hostname = argv[IDX_HOSTNAME];
/* Allocate client data */
guac_client_data = malloc(sizeof(rdp_guac_client_data));
/* Init client */
freerdp_channels_global_init();
rdp_inst = freerdp_new();
rdp_inst->PreConnect = rdp_freerdp_pre_connect;
rdp_inst->PostConnect = rdp_freerdp_post_connect;
rdp_inst->ReceiveChannelData = __guac_receive_channel_data;
/* Allocate FreeRDP context */
rdp_inst->context_size = sizeof(rdp_freerdp_context);
rdp_inst->ContextNew = (pContextNew) rdp_freerdp_context_new;
rdp_inst->ContextFree = (pContextFree) rdp_freerdp_context_free;
freerdp_context_new(rdp_inst);
/* Set settings */
settings = rdp_inst->settings;
/* Console */
settings->console_session = (strcmp(argv[IDX_CONSOLE], "true") == 0);
settings->console_audio = (strcmp(argv[IDX_CONSOLE_AUDIO], "true") == 0);
/* --no-auth */
settings->authentication = false;
/* --sec rdp */
settings->rdp_security = true;
settings->tls_security = false;
settings->nla_security = false;
settings->encryption = true;
settings->encryption_method = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
settings->encryption_level = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
/* Use optimal width unless overridden */
settings->width = client->info.optimal_width;
if (argv[IDX_WIDTH][0] != '\0')
settings->width = atoi(argv[IDX_WIDTH]);
/* Use default width if given width is invalid. */
if (settings->width <= 0) {
settings->width = RDP_DEFAULT_WIDTH;
guac_client_log_error(client,
"Invalid width: \"%s\". Using default of %i.",
argv[IDX_WIDTH], settings->width);
}
/* Round width up to nearest multiple of 4 */
settings->width = (settings->width + 3) & ~0x3;
/* Use optimal height unless overridden */
settings->height = client->info.optimal_height;
if (argv[IDX_HEIGHT][0] != '\0')
settings->height = atoi(argv[IDX_HEIGHT]);
/* Use default height if given height is invalid. */
if (settings->height <= 0) {
settings->height = RDP_DEFAULT_HEIGHT;
guac_client_log_error(client,
"Invalid height: \"%s\". Using default of %i.",
argv[IDX_WIDTH], settings->height);
}
/* Set hostname */
settings->hostname = strdup(hostname);
settings->port = port;
settings->window_title = strdup(hostname);
/* Domain */
if (argv[IDX_DOMAIN][0] != '\0')
settings->domain = strdup(argv[IDX_DOMAIN]);
/* Username */
if (argv[IDX_USERNAME][0] != '\0')
settings->username = strdup(argv[IDX_USERNAME]);
/* Password */
if (argv[IDX_PASSWORD][0] != '\0') {
settings->password = strdup(argv[IDX_PASSWORD]);
settings->autologon = 1;
}
/* Initial program */
if (argv[IDX_INITIAL_PROGRAM][0] != '\0')
settings->shell = strdup(argv[IDX_INITIAL_PROGRAM]);
/* Session color depth */
settings->color_depth = RDP_DEFAULT_DEPTH;
if (argv[IDX_COLOR_DEPTH][0] != '\0')
settings->color_depth = atoi(argv[IDX_COLOR_DEPTH]);
/* Use default depth if given depth is invalid. */
if (settings->color_depth == 0) {
settings->color_depth = RDP_DEFAULT_DEPTH;
guac_client_log_error(client,
"Invalid color-depth: \"%s\". Using default of %i.",
argv[IDX_WIDTH], settings->color_depth);
}
/* Audio enable/disable */
guac_client_data->audio_enabled =
(strcmp(argv[IDX_DISABLE_AUDIO], "true") != 0);
/* Order support */
bitmap_cache = settings->bitmap_cache;
settings->os_major_type = OSMAJORTYPE_UNSPECIFIED;
settings->os_minor_type = OSMINORTYPE_UNSPECIFIED;
settings->order_support[NEG_DSTBLT_INDEX] = true;
settings->order_support[NEG_PATBLT_INDEX] = false; /* PATBLT not yet supported */
settings->order_support[NEG_SCRBLT_INDEX] = true;
settings->order_support[NEG_OPAQUE_RECT_INDEX] = true;
settings->order_support[NEG_DRAWNINEGRID_INDEX] = false;
settings->order_support[NEG_MULTIDSTBLT_INDEX] = false;
settings->order_support[NEG_MULTIPATBLT_INDEX] = false;
settings->order_support[NEG_MULTISCRBLT_INDEX] = false;
settings->order_support[NEG_MULTIOPAQUERECT_INDEX] = false;
settings->order_support[NEG_MULTI_DRAWNINEGRID_INDEX] = false;
settings->order_support[NEG_LINETO_INDEX] = false;
settings->order_support[NEG_POLYLINE_INDEX] = false;
settings->order_support[NEG_MEMBLT_INDEX] = bitmap_cache;
settings->order_support[NEG_MEM3BLT_INDEX] = false;
settings->order_support[NEG_MEMBLT_V2_INDEX] = bitmap_cache;
settings->order_support[NEG_MEM3BLT_V2_INDEX] = false;
settings->order_support[NEG_SAVEBITMAP_INDEX] = false;
settings->order_support[NEG_GLYPH_INDEX_INDEX] = true;
settings->order_support[NEG_FAST_INDEX_INDEX] = true;
settings->order_support[NEG_FAST_GLYPH_INDEX] = true;
settings->order_support[NEG_POLYGON_SC_INDEX] = false;
settings->order_support[NEG_POLYGON_CB_INDEX] = false;
settings->order_support[NEG_ELLIPSE_SC_INDEX] = false;
settings->order_support[NEG_ELLIPSE_CB_INDEX] = false;
/* Store client data */
guac_client_data->rdp_inst = rdp_inst;
guac_client_data->bounded = false;
guac_client_data->mouse_button_mask = 0;
guac_client_data->current_surface = GUAC_DEFAULT_LAYER;
guac_client_data->clipboard = NULL;
guac_client_data->audio = NULL;
/* Recursive attribute for locks */
pthread_mutexattr_init(&(guac_client_data->attributes));
pthread_mutexattr_settype(&(guac_client_data->attributes),
PTHREAD_MUTEX_RECURSIVE);
/* Init update lock */
pthread_mutex_init(&(guac_client_data->update_lock),
&(guac_client_data->attributes));
/* Init RDP lock */
pthread_mutex_init(&(guac_client_data->rdp_lock),
&(guac_client_data->attributes));
/* Clear keysym state mapping and keymap */
memset(guac_client_data->keysym_state, 0,
sizeof(guac_rdp_keysym_state_map));
memset(guac_client_data->keymap, 0,
sizeof(guac_rdp_static_keymap));
client->data = guac_client_data;
((rdp_freerdp_context*) rdp_inst->context)->client = client;
/* Pick keymap based on argument */
if (argv[IDX_SERVER_LAYOUT][0] != '\0') {
/* US English Qwerty */
if (strcmp("en-us-qwerty", argv[IDX_SERVER_LAYOUT]) == 0)
chosen_keymap = &guac_rdp_keymap_en_us;
/* German Qwertz */
else if (strcmp("de-de-qwertz", argv[IDX_SERVER_LAYOUT]) == 0)
chosen_keymap = &guac_rdp_keymap_de_de;
/* French Azerty */
else if (strcmp("fr-fr-azerty", argv[IDX_SERVER_LAYOUT]) == 0)
chosen_keymap = &guac_rdp_keymap_fr_fr;
/* Failsafe (Unicode) keymap */
else if (strcmp("failsafe", argv[IDX_SERVER_LAYOUT]) == 0)
chosen_keymap = &guac_rdp_keymap_failsafe;
/* If keymap unknown, resort to failsafe */
else {
guac_client_log_error(client,
"Unknown layout \"%s\". Using the failsafe layout instead.",
argv[IDX_SERVER_LAYOUT]);
chosen_keymap = &guac_rdp_keymap_failsafe;
}
}
/* If no keymap requested, assume US */
else
chosen_keymap = &guac_rdp_keymap_en_us;
/* Load keymap into client */
__guac_rdp_client_load_keymap(client, chosen_keymap);
/* Set server-side keymap */
settings->kbd_layout = chosen_keymap->freerdp_keyboard_layout;
/* Connect to RDP server */
if (!freerdp_connect(rdp_inst)) {
guac_protocol_send_error(client->socket,
"Error connecting to RDP server");
guac_socket_flush(client->socket);
guac_error = GUAC_STATUS_BAD_STATE;
guac_error_message = "Error connecting to RDP server";
return 1;
}
/* Send connection name */
guac_protocol_send_name(client->socket, settings->window_title);
/* Send size */
guac_protocol_send_size(client->socket, GUAC_DEFAULT_LAYER,
settings->width, settings->height);
/* Create glyph surfaces */
guac_client_data->opaque_glyph_surface = cairo_image_surface_create(
CAIRO_FORMAT_RGB24, settings->width, settings->height);
guac_client_data->trans_glyph_surface = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32, settings->width, settings->height);
/* Set default pointer */
guac_rdp_set_default_pointer(client);
/* Success */
return 0;
}

View File

@ -0,0 +1,106 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <cairo/cairo.h>
#include <guacamole/client.h>
#include <guacamole/protocol.h>
#include <guacamole/socket.h>
/* Macros for prettying up the embedded image. */
#define X 0x00,0x00,0x00,0xFF
#define O 0xFF,0xFF,0xFF,0xFF
#define _ 0x00,0x00,0x00,0x00
/* Dimensions */
const int guac_rdp_default_pointer_width = 11;
const int guac_rdp_default_pointer_height = 16;
/* Format */
const cairo_format_t guac_rdp_default_pointer_format = CAIRO_FORMAT_ARGB32;
const int guac_rdp_default_pointer_stride = 44;
/* Embedded pointer graphic */
unsigned char guac_rdp_default_pointer[] = {
O,_,_,_,_,_,_,_,_,_,_,
O,O,_,_,_,_,_,_,_,_,_,
O,X,O,_,_,_,_,_,_,_,_,
O,X,X,O,_,_,_,_,_,_,_,
O,X,X,X,O,_,_,_,_,_,_,
O,X,X,X,X,O,_,_,_,_,_,
O,X,X,X,X,X,O,_,_,_,_,
O,X,X,X,X,X,X,O,_,_,_,
O,X,X,X,X,X,X,X,O,_,_,
O,X,X,X,X,X,X,X,X,O,_,
O,X,X,X,X,X,O,O,O,O,O,
O,X,X,O,X,X,O,_,_,_,_,
O,X,O,_,O,X,X,O,_,_,_,
O,O,_,_,O,X,X,O,_,_,_,
O,_,_,_,_,O,X,X,O,_,_,
_,_,_,_,_,O,O,O,O,_,_
};
void guac_rdp_set_default_pointer(guac_client* client) {
guac_socket* socket = client->socket;
/* Draw to buffer */
guac_layer* cursor = guac_client_alloc_buffer(client);
cairo_surface_t* graphic = cairo_image_surface_create_for_data(
guac_rdp_default_pointer,
guac_rdp_default_pointer_format,
guac_rdp_default_pointer_width,
guac_rdp_default_pointer_height,
guac_rdp_default_pointer_stride);
guac_protocol_send_png(socket, GUAC_COMP_SRC, cursor, 0, 0, graphic);
cairo_surface_destroy(graphic);
/* Set cursor */
guac_protocol_send_cursor(socket, 0, 0, cursor,
0, 0,
guac_rdp_default_pointer_width,
guac_rdp_default_pointer_height);
/* Free buffer */
guac_client_free_buffer(client, cursor);
}

View File

@ -0,0 +1,439 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Matt Hortman
* Jocelyn DELALANDE <j.delalande@ulteo.com> Ulteo SAS - http://www.ulteo.com
*
* Portions created by Ulteo SAS employees are Copyright (C) 2012 Ulteo SAS
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <errno.h>
#include <freerdp/freerdp.h>
#include <freerdp/channels/channels.h>
#include <freerdp/input.h>
#include <freerdp/codec/color.h>
#include <freerdp/cache/cache.h>
#include <freerdp/utils/event.h>
#include <freerdp/plugins/cliprdr.h>
#include <guacamole/socket.h>
#include <guacamole/protocol.h>
#include <guacamole/client.h>
#include <guacamole/error.h>
#include "client.h"
#include "rdp_keymap.h"
#include "rdp_cliprdr.h"
#include "guac_handlers.h"
void __guac_rdp_update_keysyms(guac_client* client, const int* keysym_string, int from, int to);
int __guac_rdp_send_keysym(guac_client* client, int keysym, int pressed);
int rdp_guac_client_free_handler(guac_client* client) {
rdp_guac_client_data* guac_client_data =
(rdp_guac_client_data*) client->data;
freerdp* rdp_inst = guac_client_data->rdp_inst;
rdpChannels* channels = rdp_inst->context->channels;
/* Clean up RDP client */
freerdp_channels_close(channels, rdp_inst);
freerdp_channels_free(channels);
freerdp_disconnect(rdp_inst);
freerdp_clrconv_free(((rdp_freerdp_context*) rdp_inst->context)->clrconv);
cache_free(rdp_inst->context->cache);
freerdp_free(rdp_inst);
/* Free client data */
cairo_surface_destroy(guac_client_data->opaque_glyph_surface);
cairo_surface_destroy(guac_client_data->trans_glyph_surface);
free(guac_client_data->clipboard);
free(guac_client_data);
return 0;
}
int rdp_guac_client_handle_messages(guac_client* client) {
rdp_guac_client_data* guac_client_data = (rdp_guac_client_data*) client->data;
freerdp* rdp_inst = guac_client_data->rdp_inst;
rdpChannels* channels = rdp_inst->context->channels;
int index;
int max_fd, fd;
void* read_fds[32];
void* write_fds[32];
int read_count = 0;
int write_count = 0;
fd_set rfds, wfds;
RDP_EVENT* event;
struct timeval timeout = {
.tv_sec = 0,
.tv_usec = 250000
};
/* get rdp fds */
if (!freerdp_get_fds(rdp_inst, read_fds, &read_count, write_fds, &write_count)) {
guac_error = GUAC_STATUS_BAD_STATE;
guac_error_message = "Unable to read RDP file descriptors";
return 1;
}
/* get channel fds */
if (!freerdp_channels_get_fds(channels, rdp_inst, read_fds, &read_count, write_fds, &write_count)) {
guac_error = GUAC_STATUS_BAD_STATE;
guac_error_message = "Unable to read RDP channel file descriptors";
return 1;
}
/* Construct read fd_set */
max_fd = 0;
FD_ZERO(&rfds);
for (index = 0; index < read_count; index++) {
fd = (int)(long) (read_fds[index]);
if (fd > max_fd)
max_fd = fd;
FD_SET(fd, &rfds);
}
/* Construct write fd_set */
FD_ZERO(&wfds);
for (index = 0; index < write_count; index++) {
fd = (int)(long) (write_fds[index]);
if (fd > max_fd)
max_fd = fd;
FD_SET(fd, &wfds);
}
/* If no file descriptors, error */
if (max_fd == 0) {
guac_error = GUAC_STATUS_BAD_STATE;
guac_error_message = "No file descriptors";
return 1;
}
/* Otherwise, wait for file descriptors given */
if (select(max_fd + 1, &rfds, &wfds, NULL, &timeout) == -1) {
/* these are not really errors */
if (!((errno == EAGAIN) ||
(errno == EWOULDBLOCK) ||
(errno == EINPROGRESS) ||
(errno == EINTR))) /* signal occurred */
{
guac_error = GUAC_STATUS_SEE_ERRNO;
guac_error_message = "Error waiting for file descriptor";
return 1;
}
}
pthread_mutex_lock(&(guac_client_data->rdp_lock));
/* Check the libfreerdp fds */
if (!freerdp_check_fds(rdp_inst)) {
guac_error = GUAC_STATUS_BAD_STATE;
guac_error_message = "Error handling RDP file descriptors";
return 1;
}
/* Check channel fds */
if (!freerdp_channels_check_fds(channels, rdp_inst)) {
guac_error = GUAC_STATUS_BAD_STATE;
guac_error_message = "Error handling RDP channel file descriptors";
return 1;
}
/* Check for channel events */
event = freerdp_channels_pop_event(channels);
if (event) {
/* Handle clipboard events */
if (event->event_class == RDP_EVENT_CLASS_CLIPRDR)
guac_rdp_process_cliprdr_event(client, event);
freerdp_event_free(event);
}
/* Handle RDP disconnect */
if (freerdp_shall_disconnect(rdp_inst)) {
guac_error = GUAC_STATUS_NO_INPUT;
guac_error_message = "RDP server closed connection";
return 1;
}
pthread_mutex_unlock(&(guac_client_data->rdp_lock));
/* Flush any audio */
if (guac_client_data->audio != NULL) {
pthread_mutex_lock(&(guac_client_data->update_lock));
guac_socket_flush(guac_client_data->audio->stream->socket);
pthread_mutex_unlock(&(guac_client_data->update_lock));
}
/* Success */
return 0;
}
int rdp_guac_client_mouse_handler(guac_client* client, int x, int y, int mask) {
rdp_guac_client_data* guac_client_data = (rdp_guac_client_data*) client->data;
freerdp* rdp_inst = guac_client_data->rdp_inst;
pthread_mutex_lock(&(guac_client_data->rdp_lock));
/* If button mask unchanged, just send move event */
if (mask == guac_client_data->mouse_button_mask)
rdp_inst->input->MouseEvent(rdp_inst->input, PTR_FLAGS_MOVE, x, y);
/* Otherwise, send events describing button change */
else {
/* Mouse buttons which have JUST become released */
int released_mask = guac_client_data->mouse_button_mask & ~mask;
/* Mouse buttons which have JUST become pressed */
int pressed_mask = ~guac_client_data->mouse_button_mask & mask;
/* Release event */
if (released_mask & 0x07) {
/* Calculate flags */
int flags = 0;
if (released_mask & 0x01) flags |= PTR_FLAGS_BUTTON1;
if (released_mask & 0x02) flags |= PTR_FLAGS_BUTTON3;
if (released_mask & 0x04) flags |= PTR_FLAGS_BUTTON2;
rdp_inst->input->MouseEvent(rdp_inst->input, flags, x, y);
}
/* Press event */
if (pressed_mask & 0x07) {
/* Calculate flags */
int flags = PTR_FLAGS_DOWN;
if (pressed_mask & 0x01) flags |= PTR_FLAGS_BUTTON1;
if (pressed_mask & 0x02) flags |= PTR_FLAGS_BUTTON3;
if (pressed_mask & 0x04) flags |= PTR_FLAGS_BUTTON2;
if (pressed_mask & 0x08) flags |= PTR_FLAGS_WHEEL | 0x78;
if (pressed_mask & 0x10) flags |= PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x88;
/* Send event */
rdp_inst->input->MouseEvent(rdp_inst->input, flags, x, y);
}
/* Scroll event */
if (pressed_mask & 0x18) {
/* Down */
if (pressed_mask & 0x08)
rdp_inst->input->MouseEvent(
rdp_inst->input,
PTR_FLAGS_WHEEL | 0x78,
x, y);
/* Up */
if (pressed_mask & 0x10)
rdp_inst->input->MouseEvent(
rdp_inst->input,
PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | 0x88,
x, y);
}
guac_client_data->mouse_button_mask = mask;
}
pthread_mutex_unlock(&(guac_client_data->rdp_lock));
return 0;
}
int __guac_rdp_send_keysym(guac_client* client, int keysym, int pressed) {
rdp_guac_client_data* guac_client_data = (rdp_guac_client_data*) client->data;
freerdp* rdp_inst = guac_client_data->rdp_inst;
/* If keysym can be in lookup table */
if (GUAC_RDP_KEYSYM_STORABLE(keysym)) {
/* Look up scancode mapping */
const guac_rdp_keysym_desc* keysym_desc =
&GUAC_RDP_KEYSYM_LOOKUP(guac_client_data->keymap, keysym);
/* If defined, send event */
if (keysym_desc->scancode != 0) {
pthread_mutex_lock(&(guac_client_data->rdp_lock));
/* If defined, send any prerequesite keys that must be set */
if (keysym_desc->set_keysyms != NULL)
__guac_rdp_update_keysyms(client, keysym_desc->set_keysyms, 0, 1);
/* If defined, release any keys that must be cleared */
if (keysym_desc->clear_keysyms != NULL)
__guac_rdp_update_keysyms(client, keysym_desc->clear_keysyms, 1, 0);
/* Send actual key */
rdp_inst->input->KeyboardEvent(
rdp_inst->input,
keysym_desc->flags
| (pressed ? KBD_FLAGS_DOWN : KBD_FLAGS_RELEASE),
keysym_desc->scancode);
/* If defined, release any keys that were originally released */
if (keysym_desc->set_keysyms != NULL)
__guac_rdp_update_keysyms(client, keysym_desc->set_keysyms, 0, 0);
/* If defined, send any keys that were originally set */
if (keysym_desc->clear_keysyms != NULL)
__guac_rdp_update_keysyms(client, keysym_desc->clear_keysyms, 1, 1);
pthread_mutex_unlock(&(guac_client_data->rdp_lock));
return 0;
}
}
/* Fall back to unicode events if undefined inside current keymap */
/* Only send when key pressed - Unicode events do not have
* DOWN/RELEASE flags */
if (pressed) {
/* Translate keysym into codepoint */
int codepoint;
if (keysym <= 0xFF)
codepoint = keysym;
else if (keysym >= 0x1000000)
codepoint = keysym & 0xFFFFFF;
else {
guac_client_log_info(client,
"Unmapped keysym has no equivalent unicode "
"value: 0x%x", keysym);
return 0;
}
pthread_mutex_lock(&(guac_client_data->rdp_lock));
/* Send Unicode event */
rdp_inst->input->UnicodeKeyboardEvent(
rdp_inst->input,
0, codepoint);
pthread_mutex_unlock(&(guac_client_data->rdp_lock));
}
return 0;
}
void __guac_rdp_update_keysyms(guac_client* client, const int* keysym_string, int from, int to) {
rdp_guac_client_data* guac_client_data = (rdp_guac_client_data*) client->data;
int keysym;
/* Send all keysyms in string, NULL terminated */
while ((keysym = *keysym_string) != 0) {
/* Get current keysym state */
int current_state = GUAC_RDP_KEYSYM_LOOKUP(guac_client_data->keysym_state, keysym);
/* If key is currently in given state, send event for changing it to specified "to" state */
if (current_state == from)
__guac_rdp_send_keysym(client, *keysym_string, to);
/* Next keysym */
keysym_string++;
}
}
int rdp_guac_client_key_handler(guac_client* client, int keysym, int pressed) {
rdp_guac_client_data* guac_client_data = (rdp_guac_client_data*) client->data;
/* Update keysym state */
if (GUAC_RDP_KEYSYM_STORABLE(keysym))
GUAC_RDP_KEYSYM_LOOKUP(guac_client_data->keysym_state, keysym) = pressed;
return __guac_rdp_send_keysym(client, keysym, pressed);
}
int rdp_guac_client_clipboard_handler(guac_client* client, char* data) {
rdpChannels* channels =
((rdp_guac_client_data*) client->data)->rdp_inst->context->channels;
RDP_CB_FORMAT_LIST_EVENT* format_list =
(RDP_CB_FORMAT_LIST_EVENT*) freerdp_event_new(
RDP_EVENT_CLASS_CLIPRDR,
RDP_EVENT_TYPE_CB_FORMAT_LIST,
NULL, NULL);
/* Free existing data */
free(((rdp_guac_client_data*) client->data)->clipboard);
/* Store data in client */
((rdp_guac_client_data*) client->data)->clipboard = strdup(data);
/* Notify server that text data is now available */
format_list->formats = (uint32*) malloc(sizeof(uint32));
format_list->formats[0] = CB_FORMAT_TEXT;
format_list->num_formats = 1;
freerdp_channels_send_event(channels, (RDP_EVENT*) format_list);
return 0;
}

View File

@ -0,0 +1,211 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <stdlib.h>
#include <guacamole/client.h>
#include <guacamole/protocol.h>
#include <vorbis/vorbisenc.h>
#include "audio.h"
#include "ogg_encoder.h"
void ogg_encoder_begin_handler(audio_stream* audio) {
/* Allocate stream state */
ogg_encoder_state* state = (ogg_encoder_state*)
malloc(sizeof(ogg_encoder_state));
/* Init state */
vorbis_info_init(&(state->info));
vorbis_encode_init_vbr(&(state->info), audio->channels, audio->rate, 0.4);
vorbis_analysis_init(&(state->vorbis_state), &(state->info));
vorbis_block_init(&(state->vorbis_state), &(state->vorbis_block));
vorbis_comment_init(&(state->comment));
vorbis_comment_add_tag(&(state->comment), "ENCODER", "libguac-client-rdp");
ogg_stream_init(&(state->ogg_state), rand());
/* Write headers */
{
ogg_packet header;
ogg_packet header_comm;
ogg_packet header_code;
vorbis_analysis_headerout(
&(state->vorbis_state),
&(state->comment),
&header, &header_comm, &header_code);
ogg_stream_packetin(&(state->ogg_state), &header);
ogg_stream_packetin(&(state->ogg_state), &header_comm);
ogg_stream_packetin(&(state->ogg_state), &header_code);
/* For each packet */
while (ogg_stream_flush(&(state->ogg_state), &(state->ogg_page)) != 0) {
/* Write packet header */
audio_stream_write_encoded(audio,
state->ogg_page.header,
state->ogg_page.header_len);
/* Write packet body */
audio_stream_write_encoded(audio,
state->ogg_page.body,
state->ogg_page.body_len);
}
}
audio->data = state;
}
void ogg_encoder_write_blocks(audio_stream* audio) {
/* Get state */
ogg_encoder_state* state = (ogg_encoder_state*) audio->data;
while (vorbis_analysis_blockout(&(state->vorbis_state),
&(state->vorbis_block)) == 1) {
/* Analyze */
vorbis_analysis(&(state->vorbis_block), NULL);
vorbis_bitrate_addblock(&(state->vorbis_block));
/* Flush Ogg pages */
while (vorbis_bitrate_flushpacket(&(state->vorbis_state),
&(state->ogg_packet))) {
/* Weld packet into bitstream */
ogg_stream_packetin(&(state->ogg_state), &(state->ogg_packet));
/* Write out pages */
while (ogg_stream_pageout(&(state->ogg_state),
&(state->ogg_page)) != 0) {
/* Write packet header */
audio_stream_write_encoded(audio,
state->ogg_page.header,
state->ogg_page.header_len);
/* Write packet body */
audio_stream_write_encoded(audio,
state->ogg_page.body,
state->ogg_page.body_len);
if (ogg_page_eos(&(state->ogg_page)))
break;
}
}
}
}
void ogg_encoder_end_handler(audio_stream* audio) {
/* Get state */
ogg_encoder_state* state = (ogg_encoder_state*) audio->data;
/* Write end-of-stream */
vorbis_analysis_wrote(&(state->vorbis_state), 0);
ogg_encoder_write_blocks(audio);
/* Clean up encoder */
ogg_stream_clear(&(state->ogg_state));
vorbis_block_clear(&(state->vorbis_block));
vorbis_dsp_clear(&(state->vorbis_state));
vorbis_comment_clear(&(state->comment));
vorbis_info_clear(&(state->info));
/* Free stream state */
free(audio->data);
}
void ogg_encoder_write_handler(audio_stream* audio,
unsigned char* pcm_data, int length) {
/* Get state */
ogg_encoder_state* state = (ogg_encoder_state*) audio->data;
/* Calculate samples */
int samples = length / audio->channels * 8 / audio->bps;
int i;
/* Get buffer */
float** buffer = vorbis_analysis_buffer(&(state->vorbis_state), samples);
signed char* readbuffer = (signed char*) pcm_data;
for (i=0; i<samples; i++) {
/* FIXME: For now, assume 2 channels, 16-bit */
int left = ((readbuffer[i*4+1]<<8)|(0x00ff&(int)readbuffer[i*4]));
int right = ((readbuffer[i*4+3]<<8)|(0x00ff&(int)readbuffer[i*4+2]));
/* Store sample in buffer */
buffer[0][i] = left / 32768.f;
buffer[1][i] = right / 32768.f;
}
/* Submit data */
vorbis_analysis_wrote(&(state->vorbis_state), samples);
/* Write data */
ogg_encoder_write_blocks(audio);
}
/* Encoder handlers */
audio_encoder _ogg_encoder = {
.mimetype = "audio/ogg",
.begin_handler = ogg_encoder_begin_handler,
.write_handler = ogg_encoder_write_handler,
.end_handler = ogg_encoder_end_handler
};
/* Actual encoder */
audio_encoder* ogg_encoder = &_ogg_encoder;

View File

@ -0,0 +1,216 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Matt Hortman
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <cairo/cairo.h>
#include <guacamole/socket.h>
#include <guacamole/client.h>
#include <guacamole/protocol.h>
#include <freerdp/freerdp.h>
#include <freerdp/utils/memory.h>
#include <freerdp/codec/color.h>
#include <freerdp/codec/bitmap.h>
#include "client.h"
#include "rdp_bitmap.h"
void guac_rdp_cache_bitmap(rdpContext* context, rdpBitmap* bitmap) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_socket* socket = client->socket;
/* Allocate buffer */
guac_layer* buffer = guac_client_alloc_buffer(client);
/* Cache image data if present */
if (bitmap->data != NULL) {
rdp_guac_client_data* data = (rdp_guac_client_data*) client->data;
pthread_mutex_lock(&(data->update_lock));
/* Create surface from image data */
cairo_surface_t* surface = cairo_image_surface_create_for_data(
bitmap->data, CAIRO_FORMAT_RGB24,
bitmap->width, bitmap->height, 4*bitmap->width);
/* Send surface to buffer */
guac_protocol_send_png(socket,
GUAC_COMP_SRC, buffer, 0, 0, surface);
/* Free surface */
cairo_surface_destroy(surface);
pthread_mutex_unlock(&(data->update_lock));
}
/* Store buffer reference in bitmap */
((guac_rdp_bitmap*) bitmap)->layer = buffer;
}
void guac_rdp_bitmap_new(rdpContext* context, rdpBitmap* bitmap) {
/* Convert image data if present */
if (bitmap->data != NULL) {
/* Convert image data to 32-bit RGB */
unsigned char* image_buffer = freerdp_image_convert(bitmap->data, NULL,
bitmap->width, bitmap->height,
context->instance->settings->color_depth,
32, ((rdp_freerdp_context*) context)->clrconv);
/* Free existing image, if any */
if (image_buffer != bitmap->data)
free(bitmap->data);
/* Store converted image in bitmap */
bitmap->data = image_buffer;
}
/* No corresponding layer yet - caching is deferred. */
((guac_rdp_bitmap*) bitmap)->layer = NULL;
/* Start at zero usage */
((guac_rdp_bitmap*) bitmap)->used = 0;
}
void guac_rdp_bitmap_paint(rdpContext* context, rdpBitmap* bitmap) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_socket* socket = client->socket;
int width = bitmap->right - bitmap->left + 1;
int height = bitmap->bottom - bitmap->top + 1;
rdp_guac_client_data* data = (rdp_guac_client_data*) client->data;
pthread_mutex_lock(&(data->update_lock));
/* If not cached, cache if necessary */
if (((guac_rdp_bitmap*) bitmap)->layer == NULL
&& ((guac_rdp_bitmap*) bitmap)->used >= 1)
guac_rdp_cache_bitmap(context, bitmap);
/* If cached, retrieve from cache */
if (((guac_rdp_bitmap*) bitmap)->layer != NULL)
guac_protocol_send_copy(socket,
((guac_rdp_bitmap*) bitmap)->layer,
0, 0, width, height,
GUAC_COMP_OVER,
GUAC_DEFAULT_LAYER, bitmap->left, bitmap->top);
/* Otherwise, draw with stored image data */
else if (bitmap->data != NULL) {
/* Create surface from image data */
cairo_surface_t* surface = cairo_image_surface_create_for_data(
bitmap->data, CAIRO_FORMAT_RGB24,
width, height, 4*bitmap->width);
/* Send surface to buffer */
guac_protocol_send_png(socket,
GUAC_COMP_OVER, GUAC_DEFAULT_LAYER,
bitmap->left, bitmap->top, surface);
/* Free surface */
cairo_surface_destroy(surface);
}
/* Increment usage counter */
((guac_rdp_bitmap*) bitmap)->used++;
pthread_mutex_unlock(&(data->update_lock));
}
void guac_rdp_bitmap_free(rdpContext* context, rdpBitmap* bitmap) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
/* If cached, free buffer */
if (((guac_rdp_bitmap*) bitmap)->layer != NULL)
guac_client_free_buffer(client, ((guac_rdp_bitmap*) bitmap)->layer);
}
void guac_rdp_bitmap_setsurface(rdpContext* context, rdpBitmap* bitmap, boolean primary) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
if (primary)
((rdp_guac_client_data*) client->data)->current_surface
= GUAC_DEFAULT_LAYER;
else {
/* If not available as a surface, make available. */
if (((guac_rdp_bitmap*) bitmap)->layer == NULL)
guac_rdp_cache_bitmap(context, bitmap);
((rdp_guac_client_data*) client->data)->current_surface
= ((guac_rdp_bitmap*) bitmap)->layer;
}
}
void guac_rdp_bitmap_decompress(rdpContext* context, rdpBitmap* bitmap, uint8* data, int width, int height, int bpp, int length, boolean compressed) {
int size = width * height * (bpp + 7) / 8;
if (bitmap->data == NULL)
bitmap->data = (uint8*) xmalloc(size);
else
bitmap->data = (uint8*) xrealloc(bitmap->data, size);
if (compressed)
bitmap_decompress(data, bitmap->data, width, height, length, bpp, bpp);
else
freerdp_image_flip(data, bitmap->data, width, height, bpp);
bitmap->compressed = false;
bitmap->length = size;
bitmap->bpp = bpp;
}

View File

@ -0,0 +1,204 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <freerdp/freerdp.h>
#include <freerdp/channels/channels.h>
#include <freerdp/utils/event.h>
#include <freerdp/plugins/cliprdr.h>
#include <guacamole/client.h>
#include <guacamole/protocol.h>
#include "client.h"
#include "rdp_cliprdr.h"
void guac_rdp_process_cliprdr_event(guac_client* client, RDP_EVENT* event) {
switch (event->event_type) {
case RDP_EVENT_TYPE_CB_MONITOR_READY:
guac_rdp_process_cb_monitor_ready(client, event);
break;
case RDP_EVENT_TYPE_CB_FORMAT_LIST:
guac_rdp_process_cb_format_list(client,
(RDP_CB_FORMAT_LIST_EVENT*) event);
break;
case RDP_EVENT_TYPE_CB_DATA_REQUEST:
guac_rdp_process_cb_data_request(client,
(RDP_CB_DATA_REQUEST_EVENT*) event);
break;
case RDP_EVENT_TYPE_CB_DATA_RESPONSE:
guac_rdp_process_cb_data_response(client,
(RDP_CB_DATA_RESPONSE_EVENT*) event);
break;
default:
guac_client_log_info(client,
"Unknown cliprdr event type: 0x%x",
event->event_type);
}
}
void guac_rdp_process_cb_monitor_ready(guac_client* client, RDP_EVENT* event) {
rdpChannels* channels =
((rdp_guac_client_data*) client->data)->rdp_inst->context->channels;
RDP_CB_FORMAT_LIST_EVENT* format_list =
(RDP_CB_FORMAT_LIST_EVENT*) freerdp_event_new(
RDP_EVENT_CLASS_CLIPRDR,
RDP_EVENT_TYPE_CB_FORMAT_LIST,
NULL, NULL);
/* Received notification of clipboard support. */
/* Respond with supported format list */
format_list->formats = (uint32*) malloc(sizeof(uint32));
format_list->formats[0] = CB_FORMAT_TEXT;
format_list->num_formats = 1;
freerdp_channels_send_event(channels, (RDP_EVENT*) format_list);
}
void guac_rdp_process_cb_format_list(guac_client* client,
RDP_CB_FORMAT_LIST_EVENT* event) {
rdpChannels* channels =
((rdp_guac_client_data*) client->data)->rdp_inst->context->channels;
/* Received notification of available data */
int i;
for (i=0; i<event->num_formats; i++) {
/* If plain text available, request it */
if (event->formats[i] == CB_FORMAT_TEXT) {
/* Create new data request */
RDP_CB_DATA_REQUEST_EVENT* data_request =
(RDP_CB_DATA_REQUEST_EVENT*) freerdp_event_new(
RDP_EVENT_CLASS_CLIPRDR,
RDP_EVENT_TYPE_CB_DATA_REQUEST,
NULL, NULL);
/* We want plain text */
data_request->format = CB_FORMAT_TEXT;
/* Send request */
freerdp_channels_send_event(channels, (RDP_EVENT*) data_request);
return;
}
}
/* Otherwise, no supported data available */
guac_client_log_info(client, "Ignoring unsupported clipboard data");
}
void guac_rdp_process_cb_data_request(guac_client* client,
RDP_CB_DATA_REQUEST_EVENT* event) {
rdpChannels* channels =
((rdp_guac_client_data*) client->data)->rdp_inst->context->channels;
/* If text requested, send clipboard text contents */
if (event->format == CB_FORMAT_TEXT) {
/* Get clipboard data */
const char* clipboard =
((rdp_guac_client_data*) client->data)->clipboard;
/* Create new data response */
RDP_CB_DATA_RESPONSE_EVENT* data_response =
(RDP_CB_DATA_RESPONSE_EVENT*) freerdp_event_new(
RDP_EVENT_CLASS_CLIPRDR,
RDP_EVENT_TYPE_CB_DATA_RESPONSE,
NULL, NULL);
/* Set data and length */
if (clipboard != NULL) {
data_response->data = (uint8*) strdup(clipboard);
data_response->size = strlen(clipboard) + 1;
}
else {
data_response->data = (uint8*) strdup("");
data_response->size = 1;
}
/* Send response */
freerdp_channels_send_event(channels, (RDP_EVENT*) data_response);
}
/* Otherwise ... failure */
else
guac_client_log_error(client,
"Server requested unsupported clipboard data type");
}
void guac_rdp_process_cb_data_response(guac_client* client,
RDP_CB_DATA_RESPONSE_EVENT* event) {
/* Received clipboard data */
if (event->data[event->size - 1] == '\0') {
/* Free existing data */
free(((rdp_guac_client_data*) client->data)->clipboard);
/* Store clipboard data */
((rdp_guac_client_data*) client->data)->clipboard =
strdup((char*) event->data);
/* Send clipboard data */
guac_protocol_send_clipboard(client->socket, (char*) event->data);
}
else
guac_client_log_error(client,
"Clipboard data missing null terminator");
}

522
protocols/rdp/src/rdp_gdi.c Normal file
View File

@ -0,0 +1,522 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Matt Hortman
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <pthread.h>
#include <freerdp/freerdp.h>
#include <guacamole/client.h>
#include "client.h"
#include "rdp_bitmap.h"
static void __guac_rdp_clip_rect(rdp_guac_client_data* data, int* x, int* y, int* w, int* h) {
if (data->bounded) {
/* Get rect coordinates */
int clipped_left = *x;
int clipped_top = *y;
int clipped_right = clipped_left + *w - 1;
int clipped_bottom = clipped_top + *h - 1;
/* Clip left */
if (clipped_left < data->bounds_left) clipped_left = data->bounds_left;
else if (clipped_left > data->bounds_right) clipped_left = data->bounds_right;
/* Clip right */
if (clipped_right < data->bounds_left) clipped_right = data->bounds_left;
else if (clipped_right > data->bounds_right) clipped_right = data->bounds_right;
/* Clip top */
if (clipped_top < data->bounds_top) clipped_top = data->bounds_top;
else if (clipped_top > data->bounds_bottom) clipped_top = data->bounds_bottom;
/* Clip bottom */
if (clipped_bottom < data->bounds_top) clipped_bottom = data->bounds_top;
else if (clipped_bottom > data->bounds_bottom) clipped_bottom = data->bounds_bottom;
/* Store new rect dimensions */
*x = clipped_left;
*y = clipped_top;
*w = clipped_right - clipped_left + 1;
*h = clipped_bottom - clipped_top + 1;
}
}
guac_transfer_function guac_rdp_rop3_transfer_function(guac_client* client,
int rop3) {
/* Translate supported ROP3 opcodes into composite modes */
switch (rop3) {
/* "DSon" !(src | dest) */
case 0x11: return GUAC_TRANSFER_BINARY_NOR;
/* "DSna" !src & dest */
case 0x22: return GUAC_TRANSFER_BINARY_NSRC_AND;
/* "Sn" !src */
case 0x33: return GUAC_TRANSFER_BINARY_NSRC;
/* "SDna" (src & !dest) */
case 0x44: return GUAC_TRANSFER_BINARY_NDEST_AND;
/* "Dn" !dest */
case 0x55: return GUAC_TRANSFER_BINARY_NDEST;
/* "SRCINVERT" (src ^ dest) */
case 0x66: return GUAC_TRANSFER_BINARY_XOR;
/* "DSan" !(src & dest) */
case 0x77: return GUAC_TRANSFER_BINARY_NAND;
/* "SRCAND" (src & dest) */
case 0x88: return GUAC_TRANSFER_BINARY_AND;
/* "DSxn" !(src ^ dest) */
case 0x99: return GUAC_TRANSFER_BINARY_XNOR;
/* "MERGEPAINT" (!src | dest)*/
case 0xBB: return GUAC_TRANSFER_BINARY_NSRC_OR;
/* "SDno" (src | !dest) */
case 0xDD: return GUAC_TRANSFER_BINARY_NDEST_OR;
/* "SRCPAINT" (src | dest) */
case 0xEE: return GUAC_TRANSFER_BINARY_OR;
/* 0x00 = "BLACKNESS" (0) */
/* 0xAA = "NOP" (dest) */
/* 0xCC = "SRCCOPY" (src) */
/* 0xFF = "WHITENESS" (1) */
}
/* Log warning if ROP3 opcode not supported */
guac_client_log_info (client, "guac_rdp_rop3_transfer_function: "
"UNSUPPORTED opcode = 0x%02X", rop3);
/* Default to BINARY_SRC */
return GUAC_TRANSFER_BINARY_SRC;
}
void guac_rdp_gdi_dstblt(rdpContext* context, DSTBLT_ORDER* dstblt) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
const guac_layer* current_layer = ((rdp_guac_client_data*) client->data)->current_surface;
int x = dstblt->nLeftRect;
int y = dstblt->nTopRect;
int w = dstblt->nWidth;
int h = dstblt->nHeight;
rdp_guac_client_data* data = (rdp_guac_client_data*) client->data;
pthread_mutex_lock(&(data->update_lock));
/* Clip operation to bounds */
__guac_rdp_clip_rect(data, &x, &y, &w, &h);
switch (dstblt->bRop) {
/* Blackness */
case 0:
/* Send black rectangle */
guac_protocol_send_rect(client->socket, current_layer, x, y, w, h);
guac_protocol_send_cfill(client->socket,
GUAC_COMP_OVER, current_layer,
0, 0, 0, 255);
break;
/* DSTINVERT */
case 0x55:
/* Invert */
guac_protocol_send_transfer(client->socket,
current_layer, x, y, w, h,
GUAC_TRANSFER_BINARY_NDEST,
current_layer, x, y);
break;
/* NOP */
case 0xAA:
break;
/* Whiteness */
case 0xFF:
guac_protocol_send_rect(client->socket, current_layer, x, y, w, h);
guac_protocol_send_cfill(client->socket,
GUAC_COMP_OVER, current_layer,
0xFF, 0xFF, 0xFF, 0xFF);
break;
/* Unsupported ROP3 */
default:
guac_client_log_info(client,
"guac_rdp_gdi_dstblt(rop3=0x%x)", dstblt->bRop);
}
pthread_mutex_unlock(&(data->update_lock));
}
void guac_rdp_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) {
/*
* Note that this is not a full implementation of PATBLT. This is a
* fallback implementation which only renders a solid block of background
* color using the specified ROP3 operation, ignoring whatever brush
* was actually specified.
*
* As libguac-client-rdp explicitly tells the server not to send PATBLT,
* well-behaved RDP servers will not use this operation at all, while
* others will at least have a fallback.
*/
/* Get client and current layer */
guac_client* client = ((rdp_freerdp_context*) context)->client;
const guac_layer* current_layer =
((rdp_guac_client_data*) client->data)->current_surface;
int x = patblt->nLeftRect;
int y = patblt->nTopRect;
int w = patblt->nWidth;
int h = patblt->nHeight;
rdp_guac_client_data* data = (rdp_guac_client_data*) client->data;
/* Layer for actual transfer */
guac_layer* buffer;
/*
* Warn that rendering is a fallback, as the server should not be sending
* this order.
*/
guac_client_log_info(client, "Using fallback PATBLT (server is ignoring "
"negotiated client capabilities)");
/* Clip operation to bounds */
__guac_rdp_clip_rect(data, &x, &y, &w, &h);
/* Render rectangle based on ROP */
switch (patblt->bRop) {
/* If blackness, send black rectangle */
case 0x00:
guac_protocol_send_rect(client->socket, current_layer, x, y, w, h);
guac_protocol_send_cfill(client->socket,
GUAC_COMP_OVER, current_layer,
0x00, 0x00, 0x00, 0xFF);
break;
/* If NOP, do nothing */
case 0xAA:
break;
/* If operation is just a copy, send foreground only */
case 0xCC:
case 0xF0:
guac_protocol_send_rect(client->socket, current_layer, x, y, w, h);
guac_protocol_send_cfill(client->socket,
GUAC_COMP_OVER, current_layer,
(patblt->foreColor >> 16) & 0xFF,
(patblt->foreColor >> 8 ) & 0xFF,
(patblt->foreColor ) & 0xFF,
0xFF);
break;
/* If whiteness, send white rectangle */
case 0xFF:
guac_protocol_send_rect(client->socket, current_layer, x, y, w, h);
guac_protocol_send_cfill(client->socket,
GUAC_COMP_OVER, current_layer,
0xFF, 0xFF, 0xFF, 0xFF);
break;
/* Otherwise, invert entire rect */
default:
/* Allocate buffer for transfer */
buffer = guac_client_alloc_buffer(client);
/* Send rectangle stroke */
guac_protocol_send_rect(client->socket, buffer,
0, 0, w, h);
/* Fill rectangle with fore color only */
guac_protocol_send_cfill(client->socket, GUAC_COMP_OVER, buffer,
0xFF, 0xFF, 0xFF, 0xFF);
/* Transfer */
guac_protocol_send_transfer(client->socket,
/* ... from buffer */
buffer, 0, 0, w, h,
/* ... inverting */
GUAC_TRANSFER_BINARY_XOR,
/* ... to current layer */
current_layer, x, y);
/* Done with buffer */
guac_client_free_buffer(client, buffer);
}
}
void guac_rdp_gdi_scrblt(rdpContext* context, SCRBLT_ORDER* scrblt) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
const guac_layer* current_layer = ((rdp_guac_client_data*) client->data)->current_surface;
int x = scrblt->nLeftRect;
int y = scrblt->nTopRect;
int w = scrblt->nWidth;
int h = scrblt->nHeight;
int x_src = scrblt->nXSrc;
int y_src = scrblt->nYSrc;
rdp_guac_client_data* data = (rdp_guac_client_data*) client->data;
pthread_mutex_lock(&(data->update_lock));
/* Clip operation to bounds */
__guac_rdp_clip_rect(data, &x, &y, &w, &h);
/* Update source coordinates */
x_src += x - scrblt->nLeftRect;
y_src += y - scrblt->nTopRect;
/* Copy screen rect to current surface */
guac_protocol_send_copy(client->socket,
GUAC_DEFAULT_LAYER, x_src, y_src, w, h,
GUAC_COMP_OVER, current_layer, x, y);
pthread_mutex_unlock(&(data->update_lock));
}
void guac_rdp_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
const guac_layer* current_layer = ((rdp_guac_client_data*) client->data)->current_surface;
guac_socket* socket = client->socket;
guac_rdp_bitmap* bitmap = (guac_rdp_bitmap*) memblt->bitmap;
int x = memblt->nLeftRect;
int y = memblt->nTopRect;
int w = memblt->nWidth;
int h = memblt->nHeight;
int x_src = memblt->nXSrc;
int y_src = memblt->nYSrc;
rdp_guac_client_data* data = (rdp_guac_client_data*) client->data;
pthread_mutex_lock(&(data->update_lock));
/* Clip operation to bounds */
__guac_rdp_clip_rect(data, &x, &y, &w, &h);
/* Update source coordinates */
x_src += x - memblt->nLeftRect;
y_src += y - memblt->nTopRect;
switch (memblt->bRop) {
/* If blackness, send black rectangle */
case 0x00:
guac_protocol_send_rect(client->socket, current_layer, x, y, w, h);
guac_protocol_send_cfill(client->socket,
GUAC_COMP_OVER, current_layer,
0x00, 0x00, 0x00, 0xFF);
break;
/* If NOP, do nothing */
case 0xAA:
break;
/* If operation is just SRC, simply copy */
case 0xCC:
/* If not cached, cache if necessary */
if (((guac_rdp_bitmap*) bitmap)->layer == NULL
&& ((guac_rdp_bitmap*) bitmap)->used >= 1)
guac_rdp_cache_bitmap(context, memblt->bitmap);
/* If not cached, send as PNG */
if (bitmap->layer == NULL) {
if (memblt->bitmap->data != NULL) {
/* Create surface from image data */
cairo_surface_t* surface = cairo_image_surface_create_for_data(
memblt->bitmap->data + 4*(x_src + y_src*memblt->bitmap->width),
CAIRO_FORMAT_RGB24, w, h, 4*memblt->bitmap->width);
/* Send surface to buffer */
guac_protocol_send_png(socket,
GUAC_COMP_OVER, current_layer,
x, y, surface);
/* Free surface */
cairo_surface_destroy(surface);
}
}
/* Otherwise, copy */
else
guac_protocol_send_copy(socket,
bitmap->layer, x_src, y_src, w, h,
GUAC_COMP_OVER, current_layer, x, y);
/* Increment usage counter */
((guac_rdp_bitmap*) bitmap)->used++;
break;
/* If whiteness, send white rectangle */
case 0xFF:
guac_protocol_send_rect(client->socket, current_layer, x, y, w, h);
guac_protocol_send_cfill(client->socket,
GUAC_COMP_OVER, current_layer,
0xFF, 0xFF, 0xFF, 0xFF);
break;
/* Otherwise, use transfer */
default:
/* If not available as a surface, make available. */
if (bitmap->layer == NULL)
guac_rdp_cache_bitmap(context, memblt->bitmap);
guac_protocol_send_transfer(socket,
bitmap->layer, x_src, y_src, w, h,
guac_rdp_rop3_transfer_function(client, memblt->bRop),
current_layer, x, y);
/* Increment usage counter */
((guac_rdp_bitmap*) bitmap)->used++;
}
pthread_mutex_unlock(&(data->update_lock));
}
void guac_rdp_gdi_opaquerect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
uint32 color = freerdp_color_convert_var(opaque_rect->color,
context->instance->settings->color_depth, 32,
((rdp_freerdp_context*) context)->clrconv);
const guac_layer* current_layer = ((rdp_guac_client_data*) client->data)->current_surface;
rdp_guac_client_data* data = (rdp_guac_client_data*) client->data;
pthread_mutex_lock(&(data->update_lock));
int x = opaque_rect->nLeftRect;
int y = opaque_rect->nTopRect;
int w = opaque_rect->nWidth;
int h = opaque_rect->nHeight;
/* Clip operation to bounds */
__guac_rdp_clip_rect(data, &x, &y, &w, &h);
guac_protocol_send_rect(client->socket, current_layer, x, y, w, h);
guac_protocol_send_cfill(client->socket,
GUAC_COMP_OVER, current_layer,
(color >> 16) & 0xFF,
(color >> 8 ) & 0xFF,
(color ) & 0xFF,
255);
pthread_mutex_unlock(&(data->update_lock));
}
void guac_rdp_gdi_palette_update(rdpContext* context, PALETTE_UPDATE* palette) {
CLRCONV* clrconv = ((rdp_freerdp_context*) context)->clrconv;
clrconv->palette->count = palette->number;
clrconv->palette->entries = palette->entries;
}
void guac_rdp_gdi_set_bounds(rdpContext* context, rdpBounds* bounds) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
rdp_guac_client_data* data = (rdp_guac_client_data*) client->data;
/* If no bounds given, clear bounding rect */
if (bounds == NULL)
data->bounded = false;
/* Otherwise, set bounding rectangle */
else {
data->bounded = true;
data->bounds_left = bounds->left;
data->bounds_top = bounds->top;
data->bounds_right = bounds->right;
data->bounds_bottom = bounds->bottom;
}
}
void guac_rdp_gdi_end_paint(rdpContext* context) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_socket_flush(client->socket);
}

View File

@ -0,0 +1,243 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Matt Hortman
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <pthread.h>
#include <freerdp/freerdp.h>
#include <guacamole/client.h>
#include <guacamole/error.h>
#include "client.h"
#include "rdp_glyph.h"
void guac_rdp_glyph_new(rdpContext* context, rdpGlyph* glyph) {
int x, y, i;
int stride;
unsigned char* image_buffer;
unsigned char* image_buffer_row;
unsigned char* data = glyph->aj;
int width = glyph->cx;
int height = glyph->cy;
/* Init Cairo buffer */
stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
image_buffer = malloc(height*stride);
image_buffer_row = image_buffer;
/* Copy image data from image data to buffer */
for (y = 0; y<height; y++) {
unsigned int* image_buffer_current;
/* Get current buffer row, advance to next */
image_buffer_current = (unsigned int*) image_buffer_row;
image_buffer_row += stride;
for (x = 0; x<width;) {
/* Get byte from image data */
unsigned int v = *(data++);
/* Read bits, write pixels */
for (i = 0; i<8 && x<width; i++, x++) {
/* Output RGB */
if (v & 0x80)
*(image_buffer_current++) = 0xFF000000;
else
*(image_buffer_current++) = 0x00000000;
/* Next bit */
v <<= 1;
}
}
}
/* Store glyph surface */
((guac_rdp_glyph*) glyph)->surface = cairo_image_surface_create_for_data(
image_buffer, CAIRO_FORMAT_ARGB32, width, height, stride);
}
void guac_rdp_glyph_draw(rdpContext* context, rdpGlyph* glyph, int x, int y) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
rdp_guac_client_data* guac_client_data = (rdp_guac_client_data*) client->data;
/* Do not attempt to draw glyphs if glyph drawing is not begun */
if (guac_client_data->glyph_cairo == NULL)
return;
/* Use glyph as mask */
cairo_mask_surface(
guac_client_data->glyph_cairo,
((guac_rdp_glyph*) glyph)->surface, x, y);
}
void guac_rdp_glyph_free(rdpContext* context, rdpGlyph* glyph) {
unsigned char* image_buffer = cairo_image_surface_get_data(
((guac_rdp_glyph*) glyph)->surface);
/* Free surface */
cairo_surface_destroy(((guac_rdp_glyph*) glyph)->surface);
free(image_buffer);
}
void guac_rdp_glyph_begindraw(rdpContext* context,
int x, int y, int width, int height, uint32 fgcolor, uint32 bgcolor) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
rdp_guac_client_data* guac_client_data =
(rdp_guac_client_data*) client->data;
/* Convert foreground color */
fgcolor = freerdp_color_convert_var(fgcolor,
context->instance->settings->color_depth, 32,
((rdp_freerdp_context*) context)->clrconv);
/* Fill background with color if specified */
if (width != 0 && height != 0) {
/* Prepare for opaque glyphs */
guac_client_data->glyph_surface =
guac_client_data->opaque_glyph_surface;
/* Create cairo instance */
guac_client_data->glyph_cairo = cairo_create(
guac_client_data->glyph_surface);
/* Convert background color */
bgcolor = freerdp_color_convert_var(bgcolor,
context->instance->settings->color_depth, 32,
((rdp_freerdp_context*) context)->clrconv);
/* Fill background */
cairo_rectangle(guac_client_data->glyph_cairo,
x, y, width, height);
cairo_set_source_rgb(guac_client_data->glyph_cairo,
((bgcolor & 0xFF0000) >> 16) / 255.0,
((bgcolor & 0x00FF00) >> 8 ) / 255.0,
( bgcolor & 0x0000FF ) / 255.0);
cairo_fill(guac_client_data->glyph_cairo);
}
/* Otherwise, prepare for transparent glyphs */
else {
/* Select transparent glyph surface */
guac_client_data->glyph_surface =
guac_client_data->trans_glyph_surface;
guac_client_data->glyph_cairo = cairo_create(
guac_client_data->glyph_surface);
/* Clear surface */
cairo_set_operator(guac_client_data->glyph_cairo,
CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(guac_client_data->glyph_cairo, 0, 0, 0, 0);
cairo_paint(guac_client_data->glyph_cairo);
/* Restore operator */
cairo_set_operator(guac_client_data->glyph_cairo,
CAIRO_OPERATOR_OVER);
}
/* Prepare for glyph drawing */
cairo_set_source_rgb(guac_client_data->glyph_cairo,
((fgcolor & 0xFF0000) >> 16) / 255.0,
((fgcolor & 0x00FF00) >> 8 ) / 255.0,
( fgcolor & 0x0000FF ) / 255.0);
}
void guac_rdp_glyph_enddraw(rdpContext* context,
int x, int y, int width, int height, uint32 fgcolor, uint32 bgcolor) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
rdp_guac_client_data* guac_client_data = (rdp_guac_client_data*) client->data;
const guac_layer* current_layer = ((rdp_guac_client_data*) client->data)->current_surface;
pthread_mutex_lock(&(guac_client_data->update_lock));
/* Use glyph surface to provide image data for glyph rectangle */
cairo_surface_t* glyph_surface = guac_client_data->glyph_surface;
int stride = cairo_image_surface_get_stride(glyph_surface);
/* Calculate bounds */
int max_width = cairo_image_surface_get_width(glyph_surface) - x;
int max_height = cairo_image_surface_get_height(glyph_surface) - y;
/* Ensure dimensions of glyph do not exceed bounds */
if (width > max_width) width = max_width;
if (height > max_height) height = max_height;
/* Ensure data is ready */
cairo_surface_flush(glyph_surface);
/* Create surface for subsection with text */
cairo_surface_t* surface = cairo_image_surface_create_for_data(
cairo_image_surface_get_data(glyph_surface) + 4*x + y*stride,
cairo_image_surface_get_format(glyph_surface),
width, height, stride);
/* Send surface with all glyphs to layer */
guac_protocol_send_png(client->socket,
GUAC_COMP_OVER, current_layer, x, y,
surface);
/* Destroy surface */
cairo_surface_destroy(surface);
/* Destroy cairo instance */
cairo_destroy(guac_client_data->glyph_cairo);
pthread_mutex_unlock(&(guac_client_data->update_lock));
}

View File

@ -0,0 +1,61 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "rdp_keymap.h"
const int GUAC_KEYSYMS_SHIFT[] = {0xFFE1, 0};
const int GUAC_KEYSYMS_ALL_SHIFT[] = {0xFFE1, 0xFFE2, 0};
const int GUAC_KEYSYMS_ALTGR[] = {0xFFEA, 0};
const int GUAC_KEYSYMS_SHIFT_ALTGR[] = {0xFFE1, 0xFFEA, 0};
const int GUAC_KEYSYMS_ALL_SHIFT_ALTGR[] = {0xFFE1, 0xFFE2, 0xFFEA, 0};
const int GUAC_KEYSYMS_CTRL[] = {0xFFE3, 0};
const int GUAC_KEYSYMS_ALL_CTRL[] = {0xFFE3, 0xFFE4, 0};
const int GUAC_KEYSYMS_ALT[] = {0xFFE9, 0};
const int GUAC_KEYSYMS_ALL_ALT[] = {0xFFE9, 0xFFEA, 0};
const int GUAC_KEYSYMS_CTRL_ALT[] = {0xFFE3, 0xFFE9, 0};
const int GUAC_KEYSYMS_ALL_MODIFIERS[] = {
0xFFE1, 0xFFE2, /* Left and right shift */
0xFFE3, 0xFFE4, /* Left and right control */
0xFFE9, 0xFFEA, /* Left and right alt (AltGr) */
0
};

View File

@ -0,0 +1,220 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Matt Hortman
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <freerdp/input.h>
#include "rdp_keymap.h"
static guac_rdp_keysym_desc __guac_rdp_keymap_mapping[] = {
/* BackSpace */
{ .keysym = 0xff08, .scancode = 0x0E },
/* Tab */
{ .keysym = 0xff09, .scancode = 0x0F },
/* Return */
{ .keysym = 0xff0d, .scancode = 0x1C },
/* Scroll_Lock */
{ .keysym = 0xff14, .scancode = 0x46 },
/* Escape */
{ .keysym = 0xff1b, .scancode = 0x01 },
/* Home */
{ .keysym = 0xff50, .scancode = 0x47,
.flags = KBD_FLAGS_EXTENDED },
/* Left */
{ .keysym = 0xff51, .scancode = 0x4B,
.flags = KBD_FLAGS_EXTENDED },
/* Up */
{ .keysym = 0xff52, .scancode = 0x48,
.flags = KBD_FLAGS_EXTENDED },
/* Right */
{ .keysym = 0xff53, .scancode = 0x4D,
.flags = KBD_FLAGS_EXTENDED },
/* Down */
{ .keysym = 0xff54, .scancode = 0x50,
.flags = KBD_FLAGS_EXTENDED },
/* Page_Up */
{ .keysym = 0xff55, .scancode = 0x49,
.flags = KBD_FLAGS_EXTENDED },
/* Menu */
{ .keysym = 0xff67, .scancode = 0x5D,
.flags = KBD_FLAGS_EXTENDED },
/* Page_Down */
{ .keysym = 0xff56, .scancode = 0x51,
.flags = KBD_FLAGS_EXTENDED },
/* End */
{ .keysym = 0xff57, .scancode = 0x4F,
.flags = KBD_FLAGS_EXTENDED },
/* Insert */
{ .keysym = 0xff63, .scancode = 0x52,
.flags = KBD_FLAGS_EXTENDED },
/* Num_Lock */
{ .keysym = 0xff7f, .scancode = 0x45 },
/* KP_0 */
{ .keysym = 0xffb0, .scancode = 0x52 },
/* KP_1 */
{ .keysym = 0xffb1, .scancode = 0x4F },
/* KP_2 */
{ .keysym = 0xffb2, .scancode = 0x50 },
/* KP_3 */
{ .keysym = 0xffb3, .scancode = 0x51 },
/* KP_4 */
{ .keysym = 0xffb4, .scancode = 0x4B },
/* KP_5 */
{ .keysym = 0xffb5, .scancode = 0x4C },
/* KP_6 */
{ .keysym = 0xffb6, .scancode = 0x4D },
/* KP_7 */
{ .keysym = 0xffb7, .scancode = 0x47 },
/* KP_8 */
{ .keysym = 0xffb8, .scancode = 0x48 },
/* KP_9 */
{ .keysym = 0xffb9, .scancode = 0x49 },
/* F1 */
{ .keysym = 0xffbe, .scancode = 0x3B },
/* F2 */
{ .keysym = 0xffbf, .scancode = 0x3C },
/* F3 */
{ .keysym = 0xffc0, .scancode = 0x3D },
/* F4 */
{ .keysym = 0xffc1, .scancode = 0x3E },
/* F5 */
{ .keysym = 0xffc2, .scancode = 0x3F },
/* F6 */
{ .keysym = 0xffc3, .scancode = 0x40 },
/* F7 */
{ .keysym = 0xffc4, .scancode = 0x41 },
/* F8 */
{ .keysym = 0xffc5, .scancode = 0x42 },
/* F9 */
{ .keysym = 0xffc6, .scancode = 0x43 },
/* F10 */
{ .keysym = 0xffc7, .scancode = 0x44 },
/* F11 */
{ .keysym = 0xffc8, .scancode = 0x57 },
/* F12 */
{ .keysym = 0xffc9, .scancode = 0x58 },
/* Shift_L */
{ .keysym = 0xffe1, .scancode = 0x2A },
/* Shift_R */
{ .keysym = 0xffe2, .scancode = 0x36 },
/* Control_L */
{ .keysym = 0xffe3, .scancode = 0x1D },
/* Control_R */
{ .keysym = 0xffe4, .scancode = 0x9D },
/* Caps_Lock */
{ .keysym = 0xffe5, .scancode = 0x3A,
.flags = KBD_FLAGS_EXTENDED },
/* Alt_L */
{ .keysym = 0xffe9, .scancode = 0x38 },
/* Alt_R */
{ .keysym = 0xffea, .scancode = 0x38,
.flags = KBD_FLAGS_EXTENDED },
/* ISO_Level3_Shift */
{ .keysym = 0xfe03, .scancode = 0x38,
.flags = KBD_FLAGS_EXTENDED },
/* Super_L */
{ .keysym = 0xffeb, .scancode = 0x5B,
.flags = KBD_FLAGS_EXTENDED },
/* Super_R */
{ .keysym = 0xffec, .scancode = 0x5C,
.flags = KBD_FLAGS_EXTENDED },
/* Delete */
{ .keysym = 0xffff, .scancode = 0x53,
.flags = KBD_FLAGS_EXTENDED },
{0}
};
const guac_rdp_keymap guac_rdp_keymap_base = {
.name = "base",
.parent = NULL,
.mapping = __guac_rdp_keymap_mapping
};

View File

@ -0,0 +1,552 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <freerdp/input.h>
#ifdef HAVE_FREERDP_LOCALE_KEYBOARD_H
#include <freerdp/locale/keyboard.h>
#else
#include <freerdp/kbd/layouts.h>
#endif
#include "rdp_keymap.h"
static guac_rdp_keysym_desc __guac_rdp_keymap_mapping[] = {
/* space */
{ .keysym = 0x0020, .scancode = 0x39 },
/* exclam */
{ .keysym = 0x0021, .scancode = 0x02,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* quotedbl */
{ .keysym = 0x0022, .scancode = 0x03,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* numbersign */
{ .keysym = 0x0023, .scancode = 0x2b,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* dollar */
{ .keysym = 0x0024, .scancode = 0x05,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* percent */
{ .keysym = 0x0025, .scancode = 0x06,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* ampersand */
{ .keysym = 0x0026, .scancode = 0x07,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* quoteright */
{ .keysym = 0x0027, .scancode = 0x2b,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* parenleft */
{ .keysym = 0x0028, .scancode = 0x09,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* parenright */
{ .keysym = 0x0029, .scancode = 0x0A,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* asterisk */
{ .keysym = 0x002a, .scancode = 0x1b,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* plus */
{ .keysym = 0x002b, .scancode = 0x1b,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* comma */
{ .keysym = 0x002c, .scancode = 0x33,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* minus */
{ .keysym = 0x002d, .scancode = 0x35,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* period */
{ .keysym = 0x002e, .scancode = 0x34,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* slash */
{ .keysym = 0x002f, .scancode = 0x08,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* 0 */
{ .keysym = 0x0030, .scancode = 0x0B,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* 1 */
{ .keysym = 0x0031, .scancode = 0x02,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* 2 */
{ .keysym = 0x0032, .scancode = 0x03,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* 3 */
{ .keysym = 0x0033, .scancode = 0x04,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* 4 */
{ .keysym = 0x0034, .scancode = 0x05,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* 5 */
{ .keysym = 0x0035, .scancode = 0x06,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* 6 */
{ .keysym = 0x0036, .scancode = 0x07,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* 7 */
{ .keysym = 0x0037, .scancode = 0x08,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* 8 */
{ .keysym = 0x0038, .scancode = 0x09,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* 9 */
{ .keysym = 0x0039, .scancode = 0x0A,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* colon */
{ .keysym = 0x003a, .scancode = 0x34,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* semicolon */
{ .keysym = 0x003b, .scancode = 0x33,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* less */
{ .keysym = 0x003c, .scancode = 0x56,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* equal */
{ .keysym = 0x003d, .scancode = 0x0B,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* greater */
{ .keysym = 0x003e, .scancode = 0x56,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* question */
{ .keysym = 0x003f, .scancode = 0x0c,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* at */
{ .keysym = 0x0040, .scancode = 0x10,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* A */
{ .keysym = 0x0041, .scancode = 0x1E,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* B */
{ .keysym = 0x0042, .scancode = 0x30,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* C */
{ .keysym = 0x0043, .scancode = 0x2E,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* D */
{ .keysym = 0x0044, .scancode = 0x20,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* E */
{ .keysym = 0x0045, .scancode = 0x12,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* F */
{ .keysym = 0x0046, .scancode = 0x21,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* G */
{ .keysym = 0x0047, .scancode = 0x22,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* H */
{ .keysym = 0x0048, .scancode = 0x23,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* I */
{ .keysym = 0x0049, .scancode = 0x17,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* J */
{ .keysym = 0x004a, .scancode = 0x24,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* K */
{ .keysym = 0x004b, .scancode = 0x25,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* L */
{ .keysym = 0x004c, .scancode = 0x26,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* M */
{ .keysym = 0x004d, .scancode = 0x32,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* N */
{ .keysym = 0x004e, .scancode = 0x31,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* O */
{ .keysym = 0x004f, .scancode = 0x18,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* P */
{ .keysym = 0x0050, .scancode = 0x19,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* Q */
{ .keysym = 0x0051, .scancode = 0x10,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* R */
{ .keysym = 0x0052, .scancode = 0x13,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* S */
{ .keysym = 0x0053, .scancode = 0x1F,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* T */
{ .keysym = 0x0054, .scancode = 0x14,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* U */
{ .keysym = 0x0055, .scancode = 0x16,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* V */
{ .keysym = 0x0056, .scancode = 0x2F,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* W */
{ .keysym = 0x0057, .scancode = 0x11,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* X */
{ .keysym = 0x0058, .scancode = 0x2D,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* Y */
{ .keysym = 0x0059, .scancode = 0x2c,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* Z */
{ .keysym = 0x005a, .scancode = 0x15,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* bracketleft */
{ .keysym = 0x005b, .scancode = 0x09,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* backslash */
{ .keysym = 0x005c, .scancode = 0x0c,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* bracketright */
{ .keysym = 0x005d, .scancode = 0x0a,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* underscore */
{ .keysym = 0x005f, .scancode = 0x35,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* dead grave */
{ .keysym = 0xfe50, .scancode = 0x0d,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* dead acute */
{ .keysym = 0xfe51, .scancode = 0x0d,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* dead circum */
{ .keysym = 0xfe52, .scancode = 0x29,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* degree */
{ .keysym = 0x00b0, .scancode = 0x29,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* a */
{ .keysym = 0x0061, .scancode = 0x1E,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* b */
{ .keysym = 0x0062, .scancode = 0x30,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* c */
{ .keysym = 0x0063, .scancode = 0x2E,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* d */
{ .keysym = 0x0064, .scancode = 0x20,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* e */
{ .keysym = 0x0065, .scancode = 0x12,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* f */
{ .keysym = 0x0066, .scancode = 0x21,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* g */
{ .keysym = 0x0067, .scancode = 0x22,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* h */
{ .keysym = 0x0068, .scancode = 0x23,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* i */
{ .keysym = 0x0069, .scancode = 0x17,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* j */
{ .keysym = 0x006a, .scancode = 0x24,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* k */
{ .keysym = 0x006b, .scancode = 0x25,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* l */
{ .keysym = 0x006c, .scancode = 0x26,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* m */
{ .keysym = 0x006d, .scancode = 0x32,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* n */
{ .keysym = 0x006e, .scancode = 0x31,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* o */
{ .keysym = 0x006f, .scancode = 0x18,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* p */
{ .keysym = 0x0070, .scancode = 0x19,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* q */
{ .keysym = 0x0071, .scancode = 0x10,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* r */
{ .keysym = 0x0072, .scancode = 0x13,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* s */
{ .keysym = 0x0073, .scancode = 0x1F,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* t */
{ .keysym = 0x0074, .scancode = 0x14,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* u */
{ .keysym = 0x0075, .scancode = 0x16,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* v */
{ .keysym = 0x0076, .scancode = 0x2F,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* w */
{ .keysym = 0x0077, .scancode = 0x11,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* x */
{ .keysym = 0x0078, .scancode = 0x2D,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* y */
{ .keysym = 0x0079, .scancode = 0x2c,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* z */
{ .keysym = 0x007a, .scancode = 0x15,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* ä */
{ .keysym = 0x00e4, .scancode = 0x28,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* Ä */
{ .keysym = 0x00c4, .scancode = 0x28,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* ö */
{ .keysym = 0x00f6, .scancode = 0x27,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* Ö */
{ .keysym = 0x00d6, .scancode = 0x27,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* ü */
{ .keysym = 0x00fc, .scancode = 0x1a,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* Ü */
{ .keysym = 0x00dc, .scancode = 0x1a,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* ß */
{ .keysym = 0x00df, .scancode = 0x0c,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* braceleft */
{ .keysym = 0x007b, .scancode = 0x08,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* bar */
{ .keysym = 0x007c, .scancode = 0x56,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* braceright */
{ .keysym = 0x007d, .scancode = 0x0b,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* dead tilde */
{ .keysym = 0xfe53, .scancode = 0x1b,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* euro */
{ .keysym = 0x10020ac, .scancode = 0x12,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* mu */
{ .keysym = 0x00b5, .scancode = 0x32,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* two superior */
{ .keysym = 0x00b2, .scancode = 0x03,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* three superior */
{ .keysym = 0x00b3, .scancode = 0x04,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
{0}
};
const guac_rdp_keymap guac_rdp_keymap_de_de = {
.name = "de-de-qwertz",
.parent = &guac_rdp_keymap_base,
.mapping = __guac_rdp_keymap_mapping,
.freerdp_keyboard_layout = KBD_GERMAN
};

View File

@ -0,0 +1,442 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Matt Hortman
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <freerdp/input.h>
#ifdef HAVE_FREERDP_LOCALE_KEYBOARD_H
#include <freerdp/locale/keyboard.h>
#else
#include <freerdp/kbd/layouts.h>
#endif
#include "rdp_keymap.h"
static guac_rdp_keysym_desc __guac_rdp_keymap_mapping[] = {
/* space */
{ .keysym = 0x0020, .scancode = 0x39 },
/* exclam */
{ .keysym = 0x0021, .scancode = 0x02,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* quotedbl */
{ .keysym = 0x0022, .scancode = 0x28,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* numbersign */
{ .keysym = 0x0023, .scancode = 0x04,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* dollar */
{ .keysym = 0x0024, .scancode = 0x05,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* percent */
{ .keysym = 0x0025, .scancode = 0x06,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* ampersand */
{ .keysym = 0x0026, .scancode = 0x08,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* quoteright */
{ .keysym = 0x0027, .scancode = 0x28 },
/* parenleft */
{ .keysym = 0x0028, .scancode = 0x0A,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* parenright */
{ .keysym = 0x0029, .scancode = 0x0B,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* asterisk */
{ .keysym = 0x002a, .scancode = 0x09,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* plus */
{ .keysym = 0x002b, .scancode = 0x0D,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* comma */
{ .keysym = 0x002c, .scancode = 0x33,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* minus */
{ .keysym = 0x002d, .scancode = 0x0C,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* period */
{ .keysym = 0x002e, .scancode = 0x34,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* slash */
{ .keysym = 0x002f, .scancode = 0x35,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* 0 */
{ .keysym = 0x0030, .scancode = 0x0B,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* 1 */
{ .keysym = 0x0031, .scancode = 0x02,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* 2 */
{ .keysym = 0x0032, .scancode = 0x03,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* 3 */
{ .keysym = 0x0033, .scancode = 0x04,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* 4 */
{ .keysym = 0x0034, .scancode = 0x05,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* 5 */
{ .keysym = 0x0035, .scancode = 0x06,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* 6 */
{ .keysym = 0x0036, .scancode = 0x07,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* 7 */
{ .keysym = 0x0037, .scancode = 0x08,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* 8 */
{ .keysym = 0x0038, .scancode = 0x09,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* 9 */
{ .keysym = 0x0039, .scancode = 0x0A,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* colon */
{ .keysym = 0x003a, .scancode = 0x27,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* semicolon */
{ .keysym = 0x003b, .scancode = 0x27,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* less */
{ .keysym = 0x003c, .scancode = 0x33,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* equal */
{ .keysym = 0x003d, .scancode = 0x0D,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* greater */
{ .keysym = 0x003e, .scancode = 0x34,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* question */
{ .keysym = 0x003f, .scancode = 0x35,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* at */
{ .keysym = 0x0040, .scancode = 0x03,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* A */
{ .keysym = 0x0041, .scancode = 0x1E,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* B */
{ .keysym = 0x0042, .scancode = 0x30,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* C */
{ .keysym = 0x0043, .scancode = 0x2E,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* D */
{ .keysym = 0x0044, .scancode = 0x20,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* E */
{ .keysym = 0x0045, .scancode = 0x12,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* F */
{ .keysym = 0x0046, .scancode = 0x21,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* G */
{ .keysym = 0x0047, .scancode = 0x22,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* H */
{ .keysym = 0x0048, .scancode = 0x23,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* I */
{ .keysym = 0x0049, .scancode = 0x17,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* J */
{ .keysym = 0x004a, .scancode = 0x24,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* K */
{ .keysym = 0x004b, .scancode = 0x25,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* L */
{ .keysym = 0x004c, .scancode = 0x26,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* M */
{ .keysym = 0x004d, .scancode = 0x32,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* N */
{ .keysym = 0x004e, .scancode = 0x31,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* O */
{ .keysym = 0x004f, .scancode = 0x18,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* P */
{ .keysym = 0x0050, .scancode = 0x19,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* Q */
{ .keysym = 0x0051, .scancode = 0x10,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* R */
{ .keysym = 0x0052, .scancode = 0x13,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* S */
{ .keysym = 0x0053, .scancode = 0x1F,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* T */
{ .keysym = 0x0054, .scancode = 0x14,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* U */
{ .keysym = 0x0055, .scancode = 0x16,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* V */
{ .keysym = 0x0056, .scancode = 0x2F,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* W */
{ .keysym = 0x0057, .scancode = 0x11,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* X */
{ .keysym = 0x0058, .scancode = 0x2D,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* Y */
{ .keysym = 0x0059, .scancode = 0x15,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* Z */
{ .keysym = 0x005a, .scancode = 0x2C,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* bracketleft */
{ .keysym = 0x005b, .scancode = 0x1A,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* backslash */
{ .keysym = 0x005c, .scancode = 0x2B,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* bracketright */
{ .keysym = 0x005d, .scancode = 0x1B,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* asciicircum */
{ .keysym = 0x005e, .scancode = 0x07,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* underscore */
{ .keysym = 0x005f, .scancode = 0x0C,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* quoteleft */
{ .keysym = 0x0060, .scancode = 0x29,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* a */
{ .keysym = 0x0061, .scancode = 0x1E,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* b */
{ .keysym = 0x0062, .scancode = 0x30,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* c */
{ .keysym = 0x0063, .scancode = 0x2E,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* d */
{ .keysym = 0x0064, .scancode = 0x20,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* e */
{ .keysym = 0x0065, .scancode = 0x12,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* f */
{ .keysym = 0x0066, .scancode = 0x21,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* g */
{ .keysym = 0x0067, .scancode = 0x22,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* h */
{ .keysym = 0x0068, .scancode = 0x23,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* i */
{ .keysym = 0x0069, .scancode = 0x17,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* j */
{ .keysym = 0x006a, .scancode = 0x24,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* k */
{ .keysym = 0x006b, .scancode = 0x25,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* l */
{ .keysym = 0x006c, .scancode = 0x26,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* m */
{ .keysym = 0x006d, .scancode = 0x32,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* n */
{ .keysym = 0x006e, .scancode = 0x31,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* o */
{ .keysym = 0x006f, .scancode = 0x18,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* p */
{ .keysym = 0x0070, .scancode = 0x19,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* q */
{ .keysym = 0x0071, .scancode = 0x10,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* r */
{ .keysym = 0x0072, .scancode = 0x13,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* s */
{ .keysym = 0x0073, .scancode = 0x1F,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* t */
{ .keysym = 0x0074, .scancode = 0x14,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* u */
{ .keysym = 0x0075, .scancode = 0x16,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* v */
{ .keysym = 0x0076, .scancode = 0x2F,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* w */
{ .keysym = 0x0077, .scancode = 0x11,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* x */
{ .keysym = 0x0078, .scancode = 0x2D,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* y */
{ .keysym = 0x0079, .scancode = 0x15,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* z */
{ .keysym = 0x007a, .scancode = 0x2C,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT },
/* braceleft */
{ .keysym = 0x007b, .scancode = 0x1A,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* bar */
{ .keysym = 0x007c, .scancode = 0x2B,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* braceright */
{ .keysym = 0x007d, .scancode = 0x1B,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* asciitilde */
{ .keysym = 0x007e, .scancode = 0x29,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
{0}
};
const guac_rdp_keymap guac_rdp_keymap_en_us = {
.name = "en-us-qwerty",
.parent = &guac_rdp_keymap_base,
.mapping = __guac_rdp_keymap_mapping,
.freerdp_keyboard_layout = KBD_US
};

View File

@ -0,0 +1,63 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <freerdp/input.h>
#ifdef HAVE_FREERDP_LOCALE_KEYBOARD_H
#include <freerdp/locale/keyboard.h>
#else
#include <freerdp/kbd/layouts.h>
#endif
#include "rdp_keymap.h"
static guac_rdp_keysym_desc __guac_rdp_keymap_mapping[] = {
{0}
};
const guac_rdp_keymap guac_rdp_keymap_failsafe = {
.name = "failsafe",
.parent = &guac_rdp_keymap_base,
.mapping = __guac_rdp_keymap_mapping,
.freerdp_keyboard_layout = KBD_US
};

View File

@ -0,0 +1,560 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Alexandre Devely
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <freerdp/input.h>
#ifdef HAVE_FREERDP_LOCALE_KEYBOARD_H
#include <freerdp/locale/keyboard.h>
#else
#include <freerdp/kbd/layouts.h>
#endif
#include "rdp_keymap.h"
static guac_rdp_keysym_desc __guac_rdp_keymap_mapping[] = {
/* space */
{ .keysym = 0x0020, .scancode = 0x39 },
/* exclam */
{ .keysym = 0x0021, .scancode = 0x35,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* quotedbl */
{ .keysym = 0x0022, .scancode = 0x04,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* numbersign */
{ .keysym = 0x0023, .scancode = 0x04,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* dollar */
{ .keysym = 0x0024, .scancode = 0x1b,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* percent */
{ .keysym = 0x0025, .scancode = 0x28,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* ampersand */
{ .keysym = 0x0026, .scancode = 0x02,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* quoteright */
{ .keysym = 0x0027, .scancode = 0x05,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* parenleft */
{ .keysym = 0x0028, .scancode = 0x06,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* parenright */
{ .keysym = 0x0029, .scancode = 0x0c,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* asterisk */
{ .keysym = 0x002a, .scancode = 0x2b,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* plus */
{ .keysym = 0x002b, .scancode = 0x0D,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* comma */
{ .keysym = 0x002c, .scancode = 0x32,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* minus */
{ .keysym = 0x002d, .scancode = 0x07,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* period */
{ .keysym = 0x002e, .scancode = 0x33,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* slash */
{ .keysym = 0x002f, .scancode = 0x34,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* 0 */
{ .keysym = 0x0030, .scancode = 0x0B,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* 1 */
{ .keysym = 0x0031, .scancode = 0x02,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* 2 */
{ .keysym = 0x0032, .scancode = 0x03,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* 3 */
{ .keysym = 0x0033, .scancode = 0x04,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* 4 */
{ .keysym = 0x0034, .scancode = 0x05,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* 5 */
{ .keysym = 0x0035, .scancode = 0x06,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* 6 */
{ .keysym = 0x0036, .scancode = 0x07,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* 7 */
{ .keysym = 0x0037, .scancode = 0x08,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* 8 */
{ .keysym = 0x0038, .scancode = 0x09,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* 9 */
{ .keysym = 0x0039, .scancode = 0x0A,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* colon */
{ .keysym = 0x003a, .scancode = 0x34,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* semicolon */
{ .keysym = 0x003b, .scancode = 0x33,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* less */
{ .keysym = 0x003c, .scancode = 0x56,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* equal */
{ .keysym = 0x003d, .scancode = 0x0D,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* greater */
{ .keysym = 0x003e, .scancode = 0x56,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* question */
{ .keysym = 0x003f, .scancode = 0x32,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* at */
{ .keysym = 0x0040, .scancode = 0x0B,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* A */
{ .keysym = 0x0041, .scancode = 0x10,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* B */
{ .keysym = 0x0042, .scancode = 0x30,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* C */
{ .keysym = 0x0043, .scancode = 0x2E,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* D */
{ .keysym = 0x0044, .scancode = 0x20,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* E */
{ .keysym = 0x0045, .scancode = 0x12,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* F */
{ .keysym = 0x0046, .scancode = 0x21,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* G */
{ .keysym = 0x0047, .scancode = 0x22,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* H */
{ .keysym = 0x0048, .scancode = 0x23,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* I */
{ .keysym = 0x0049, .scancode = 0x17,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* J */
{ .keysym = 0x004a, .scancode = 0x24,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* K */
{ .keysym = 0x004b, .scancode = 0x25,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* L */
{ .keysym = 0x004c, .scancode = 0x26,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* M */
{ .keysym = 0x004d, .scancode = 0x27,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* N */
{ .keysym = 0x004e, .scancode = 0x31,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* O */
{ .keysym = 0x004f, .scancode = 0x18,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* P */
{ .keysym = 0x0050, .scancode = 0x19,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* Q */
{ .keysym = 0x0051, .scancode = 0x1E,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* R */
{ .keysym = 0x0052, .scancode = 0x13,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* S */
{ .keysym = 0x0053, .scancode = 0x1F,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* T */
{ .keysym = 0x0054, .scancode = 0x14,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* U */
{ .keysym = 0x0055, .scancode = 0x16,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* V */
{ .keysym = 0x0056, .scancode = 0x2F,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* W */
{ .keysym = 0x0057, .scancode = 0x2C,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* X */
{ .keysym = 0x0058, .scancode = 0x2D,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* Y */
{ .keysym = 0x0059, .scancode = 0x15,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* Z */
{ .keysym = 0x005a, .scancode = 0x11,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* bracketleft */
{ .keysym = 0x005b, .scancode = 0x06,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* backslash */
{ .keysym = 0x005c, .scancode = 0x09,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* bracketright */
{ .keysym = 0x005d, .scancode = 0x0c,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* asciicircum */
{ .keysym = 0x005e, .scancode = 0x0a,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* underscore */
{ .keysym = 0x005f, .scancode = 0x09,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* quoteleft */
{ .keysym = 0x0060, .scancode = 0x08,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* a */
{ .keysym = 0x0061, .scancode = 0x10,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* b */
{ .keysym = 0x0062, .scancode = 0x30,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* c */
{ .keysym = 0x0063, .scancode = 0x2E,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* d */
{ .keysym = 0x0064, .scancode = 0x20,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* e */
{ .keysym = 0x0065, .scancode = 0x12,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* f */
{ .keysym = 0x0066, .scancode = 0x21,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* g */
{ .keysym = 0x0067, .scancode = 0x22,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* h */
{ .keysym = 0x0068, .scancode = 0x23,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* i */
{ .keysym = 0x0069, .scancode = 0x17,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* j */
{ .keysym = 0x006a, .scancode = 0x24,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* k */
{ .keysym = 0x006b, .scancode = 0x25,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* l */
{ .keysym = 0x006c, .scancode = 0x26,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* m */
{ .keysym = 0x006d, .scancode = 0x27,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* n */
{ .keysym = 0x006e, .scancode = 0x31,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* o */
{ .keysym = 0x006f, .scancode = 0x18,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* p */
{ .keysym = 0x0070, .scancode = 0x19,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* q */
{ .keysym = 0x0071, .scancode = 0x1E,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* r */
{ .keysym = 0x0072, .scancode = 0x13,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* s */
{ .keysym = 0x0073, .scancode = 0x1F,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* t */
{ .keysym = 0x0074, .scancode = 0x14,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* u */
{ .keysym = 0x0075, .scancode = 0x16,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* v */
{ .keysym = 0x0076, .scancode = 0x2F,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* w */
{ .keysym = 0x0077, .scancode = 0x2C,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* x */
{ .keysym = 0x0078, .scancode = 0x2D,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* y */
{ .keysym = 0x0079, .scancode = 0x15,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* z */
{ .keysym = 0x007a, .scancode = 0x11,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* braceleft */
{ .keysym = 0x007b, .scancode = 0x05,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* bar */
{ .keysym = 0x007c, .scancode = 0x07,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* braceright */
{ .keysym = 0x007d, .scancode = 0x0D,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* asciitilde */
{ .keysym = 0x007e, .scancode = 0x03,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* pound */
{ .keysym = 0x00a3, .scancode = 0x1b,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* currency */
{ .keysym = 0x00a4, .scancode = 0x1b,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* section */
{ .keysym = 0x00a7, .scancode = 0x35,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* degree */
{ .keysym = 0x00b0, .scancode = 0x0c,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* micro */
{ .keysym = 0x00b5, .scancode = 0x2b,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* dead umlaut */
{ .keysym = 0xfe57, .scancode = 0x1a,
.clear_keysyms = GUAC_KEYSYMS_ALTGR,
.set_keysyms = GUAC_KEYSYMS_SHIFT },
/* dead circum */
{ .keysym = 0xfe52, .scancode = 0x1a,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* à */
{ .keysym = 0x00e0, .scancode = 0x0b,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* ç */
{ .keysym = 0x00e7, .scancode = 0x0a,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* è */
{ .keysym = 0x00e8, .scancode = 0x08,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* é */
{ .keysym = 0x00e9, .scancode = 0x03,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* ù */
{ .keysym = 0x00f9, .scancode = 0x28,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
/* euro */
{ .keysym = 0x10020ac, .scancode = 0x12,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT,
.set_keysyms = GUAC_KEYSYMS_ALTGR },
/* two superior */
{ .keysym = 0x00b2, .scancode = 0x29,
.clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR },
{0}
};
const guac_rdp_keymap guac_rdp_keymap_fr_fr = {
.name = "fr-fr-azerty",
.parent = &guac_rdp_keymap_base,
.mapping = __guac_rdp_keymap_mapping,
.freerdp_keyboard_layout = KBD_FRENCH
};

View File

@ -0,0 +1,120 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David PHAM-VAN <d.pham-van@ulteo.com> Ulteo SAS - http://www.ulteo.com
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <pthread.h>
#include <freerdp/freerdp.h>
#include <guacamole/client.h>
#include "client.h"
#include "rdp_pointer.h"
#include "default_pointer.h"
void guac_rdp_pointer_new(rdpContext* context, rdpPointer* pointer) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_socket* socket = client->socket;
/* Allocate data for image */
unsigned char* data =
(unsigned char*) malloc(pointer->width * pointer->height * 4);
/* Allocate layer */
guac_layer* buffer = guac_client_alloc_buffer(client);
cairo_surface_t* surface;
rdp_guac_client_data* client_data = (rdp_guac_client_data*) client->data;
pthread_mutex_lock(&(client_data->update_lock));
/* Convert to alpha cursor if mask data present */
if (pointer->andMaskData && pointer->xorMaskData)
freerdp_alpha_cursor_convert(data,
pointer->xorMaskData, pointer->andMaskData,
pointer->width, pointer->height, pointer->xorBpp,
((rdp_freerdp_context*) context)->clrconv);
/* Create surface from image data */
surface = cairo_image_surface_create_for_data(
data, CAIRO_FORMAT_ARGB32,
pointer->width, pointer->height, 4*pointer->width);
/* Send surface to buffer */
guac_protocol_send_png(socket, GUAC_COMP_SRC, buffer, 0, 0, surface);
/* Free surface */
cairo_surface_destroy(surface);
free(data);
/* Remember buffer */
((guac_rdp_pointer*) pointer)->layer = buffer;
pthread_mutex_unlock(&(client_data->update_lock));
}
void guac_rdp_pointer_set(rdpContext* context, rdpPointer* pointer) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_socket* socket = client->socket;
rdp_guac_client_data* data = (rdp_guac_client_data*) client->data;
pthread_mutex_lock(&(data->update_lock));
/* Set cursor */
guac_protocol_send_cursor(socket, pointer->xPos, pointer->yPos,
((guac_rdp_pointer*) pointer)->layer,
0, 0, pointer->width, pointer->height);
pthread_mutex_unlock(&(data->update_lock));
}
void guac_rdp_pointer_free(rdpContext* context, rdpPointer* pointer) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
guac_client_free_buffer(client, ((guac_rdp_pointer*) pointer)->layer);
}
void guac_rdp_pointer_set_null(rdpContext* context) {
/* STUB */
}
void guac_rdp_pointer_set_default(rdpContext* context) {
/* STUB */
}

View File

@ -0,0 +1,201 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac-client-rdp.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#define WAV_BUFFER_SIZE 0x4000
#include <stdlib.h>
#include <string.h>
#include <guacamole/client.h>
#include <guacamole/protocol.h>
#include "audio.h"
#include "wav_encoder.h"
void wav_encoder_begin_handler(audio_stream* audio) {
/* Allocate stream state */
wav_encoder_state* state = (wav_encoder_state*)
malloc(sizeof(wav_encoder_state));
/* Initialize buffer */
state->length = WAV_BUFFER_SIZE;
state->used = 0;
state->data_buffer = (unsigned char*) malloc(state->length);
audio->data = state;
}
void _wav_encoder_write_le(unsigned char* buffer, int value, int length) {
int offset;
/* Write all bytes in the given value in little-endian byte order */
for (offset=0; offset<length; offset++) {
/* Store byte */
*buffer = value & 0xFF;
/* Move to next byte */
value >>= 8;
buffer++;
}
}
void wav_encoder_end_handler(audio_stream* audio) {
/*
* Static header init
*/
wav_encoder_riff_header riff_header = {
.chunk_id = "RIFF",
.chunk_format = "WAVE"
};
wav_encoder_fmt_header fmt_header = {
.subchunk_id = "fmt ",
.subchunk_size = {0x10, 0x00, 0x00, 0x00}, /* 16 */
.subchunk_format = {0x01, 0x00} /* 1 = PCM */
};
wav_encoder_data_header data_header = {
.subchunk_id = "data"
};
/* Get state */
wav_encoder_state* state = (wav_encoder_state*) audio->data;
/*
* RIFF HEADER
*/
/* Chunk size */
_wav_encoder_write_le(riff_header.chunk_size,
4 + sizeof(fmt_header) + sizeof(data_header) + state->used,
sizeof(riff_header.chunk_size));
audio_stream_write_encoded(audio,
(unsigned char*) &riff_header,
sizeof(riff_header));
/*
* FMT HEADER
*/
/* Channels */
_wav_encoder_write_le(fmt_header.subchunk_channels,
audio->channels, sizeof(fmt_header.subchunk_channels));
/* Sample rate */
_wav_encoder_write_le(fmt_header.subchunk_sample_rate,
audio->rate, sizeof(fmt_header.subchunk_sample_rate));
/* Byte rate */
_wav_encoder_write_le(fmt_header.subchunk_byte_rate,
audio->rate * audio->channels * audio->bps / 8,
sizeof(fmt_header.subchunk_byte_rate));
/* Block align */
_wav_encoder_write_le(fmt_header.subchunk_block_align,
audio->channels * audio->bps / 8,
sizeof(fmt_header.subchunk_block_align));
/* Bits per second */
_wav_encoder_write_le(fmt_header.subchunk_bps,
audio->bps, sizeof(fmt_header.subchunk_bps));
audio_stream_write_encoded(audio,
(unsigned char*) &fmt_header,
sizeof(fmt_header));
/*
* DATA HEADER
*/
/* PCM data size */
_wav_encoder_write_le(data_header.subchunk_size,
state->used, sizeof(data_header.subchunk_size));
audio_stream_write_encoded(audio,
(unsigned char*) &data_header,
sizeof(data_header));
/* Write .wav data */
audio_stream_write_encoded(audio, state->data_buffer, state->used);
/* Free stream state */
free(state);
}
void wav_encoder_write_handler(audio_stream* audio,
unsigned char* pcm_data, int length) {
/* Get state */
wav_encoder_state* state = (wav_encoder_state*) audio->data;
/* Increase size of buffer if necessary */
if (state->used + length > state->length) {
/* Increase to double concatenated size to accomodate */
state->length = (state->length + length)*2;
state->data_buffer = realloc(state->data_buffer,
state->length);
}
/* Append to buffer */
memcpy(&(state->data_buffer[state->used]), pcm_data, length);
state->used += length;
}
/* Encoder handlers */
audio_encoder _wav_encoder = {
.mimetype = "audio/wav",
.begin_handler = wav_encoder_begin_handler,
.write_handler = wav_encoder_write_handler,
.end_handler = wav_encoder_end_handler
};
/* Actual encoder */
audio_encoder* wav_encoder = &_wav_encoder;