Merge libguac-client-rdp.
This commit is contained in:
commit
aaf8a0829d
36
protocols/rdp/.gitignore
vendored
Normal file
36
protocols/rdp/.gitignore
vendored
Normal 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
6
protocols/rdp/AUTHORS
Normal 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
49
protocols/rdp/ChangeLog
Normal 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
470
protocols/rdp/LICENSE
Normal 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
99
protocols/rdp/Makefile.am
Normal 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
75
protocols/rdp/README
Normal 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/
|
||||||
|
|
86
protocols/rdp/configure.in
Normal file
86
protocols/rdp/configure.in
Normal 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
|
313
protocols/rdp/guac_rdpsnd/messages.c
Normal file
313
protocols/rdp/guac_rdpsnd/messages.c
Normal 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 */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
162
protocols/rdp/guac_rdpsnd/messages.h
Normal file
162
protocols/rdp/guac_rdpsnd/messages.h
Normal 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
|
||||||
|
|
140
protocols/rdp/guac_rdpsnd/service.c
Normal file
140
protocols/rdp/guac_rdpsnd/service.c
Normal 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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
146
protocols/rdp/guac_rdpsnd/service.h
Normal file
146
protocols/rdp/guac_rdpsnd/service.h
Normal 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
|
||||||
|
|
212
protocols/rdp/include/audio.h
Normal file
212
protocols/rdp/include/audio.h
Normal 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
|
||||||
|
|
221
protocols/rdp/include/client.h
Normal file
221
protocols/rdp/include/client.h
Normal 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
|
||||||
|
|
0
protocols/rdp/include/config.h
Normal file
0
protocols/rdp/include/config.h
Normal file
76
protocols/rdp/include/default_pointer.h
Normal file
76
protocols/rdp/include/default_pointer.h
Normal 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
|
50
protocols/rdp/include/guac_handlers.h
Normal file
50
protocols/rdp/include/guac_handlers.h
Normal 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
|
||||||
|
|
67
protocols/rdp/include/ogg_encoder.h
Normal file
67
protocols/rdp/include/ogg_encoder.h
Normal 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
|
||||||
|
|
71
protocols/rdp/include/rdp_bitmap.h
Normal file
71
protocols/rdp/include/rdp_bitmap.h
Normal 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
|
56
protocols/rdp/include/rdp_cliprdr.h
Normal file
56
protocols/rdp/include/rdp_cliprdr.h
Normal 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
|
||||||
|
|
56
protocols/rdp/include/rdp_gdi.h
Normal file
56
protocols/rdp/include/rdp_gdi.h
Normal 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
|
67
protocols/rdp/include/rdp_glyph.h
Normal file
67
protocols/rdp/include/rdp_glyph.h
Normal 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
|
230
protocols/rdp/include/rdp_keymap.h
Normal file
230
protocols/rdp/include/rdp_keymap.h
Normal 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
|
||||||
|
|
66
protocols/rdp/include/rdp_pointer.h
Normal file
66
protocols/rdp/include/rdp_pointer.h
Normal 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
|
144
protocols/rdp/include/wav_encoder.h
Normal file
144
protocols/rdp/include/wav_encoder.h
Normal 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
12
protocols/rdp/m4/README
Normal 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
179
protocols/rdp/src/audio.c
Normal 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
602
protocols/rdp/src/client.c
Normal 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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
106
protocols/rdp/src/default_pointer.c
Normal file
106
protocols/rdp/src/default_pointer.c
Normal 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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
439
protocols/rdp/src/guac_handlers.c
Normal file
439
protocols/rdp/src/guac_handlers.c
Normal 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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
211
protocols/rdp/src/ogg_encoder.c
Normal file
211
protocols/rdp/src/ogg_encoder.c
Normal 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;
|
||||||
|
|
216
protocols/rdp/src/rdp_bitmap.c
Normal file
216
protocols/rdp/src/rdp_bitmap.c
Normal 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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
204
protocols/rdp/src/rdp_cliprdr.c
Normal file
204
protocols/rdp/src/rdp_cliprdr.c
Normal 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
522
protocols/rdp/src/rdp_gdi.c
Normal 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);
|
||||||
|
}
|
||||||
|
|
243
protocols/rdp/src/rdp_glyph.c
Normal file
243
protocols/rdp/src/rdp_glyph.c
Normal 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));
|
||||||
|
}
|
||||||
|
|
61
protocols/rdp/src/rdp_keymap.c
Normal file
61
protocols/rdp/src/rdp_keymap.c
Normal 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
|
||||||
|
};
|
||||||
|
|
220
protocols/rdp/src/rdp_keymap_base.c
Normal file
220
protocols/rdp/src/rdp_keymap_base.c
Normal 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
|
||||||
|
|
||||||
|
};
|
||||||
|
|
552
protocols/rdp/src/rdp_keymap_de_de.c
Normal file
552
protocols/rdp/src/rdp_keymap_de_de.c
Normal 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
|
||||||
|
|
||||||
|
};
|
||||||
|
|
442
protocols/rdp/src/rdp_keymap_en_us.c
Normal file
442
protocols/rdp/src/rdp_keymap_en_us.c
Normal 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
|
||||||
|
|
||||||
|
};
|
||||||
|
|
63
protocols/rdp/src/rdp_keymap_failsafe.c
Normal file
63
protocols/rdp/src/rdp_keymap_failsafe.c
Normal 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
|
||||||
|
|
||||||
|
};
|
||||||
|
|
560
protocols/rdp/src/rdp_keymap_fr_fr.c
Normal file
560
protocols/rdp/src/rdp_keymap_fr_fr.c
Normal 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
|
||||||
|
|
||||||
|
};
|
||||||
|
|
120
protocols/rdp/src/rdp_pointer.c
Normal file
120
protocols/rdp/src/rdp_pointer.c
Normal 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 */
|
||||||
|
}
|
||||||
|
|
201
protocols/rdp/src/wav_encoder.c
Normal file
201
protocols/rdp/src/wav_encoder.c
Normal 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;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user