blob: 317183001dee6f08465951735e8b05a926c0f273 [file] [log] [blame]
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Chapter 21. guacamole-common-js</title><link rel="stylesheet" type="text/css" href="gug.css" /><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot" /><link rel="home" href="index.html" title="Guacamole Manual" /><link rel="up" href="developers-guide.html" title="Part II. Developer's Guide" /><link rel="prev" href="guacamole-common.html" title="Chapter 20. guacamole-common" /><link rel="next" href="guacamole-ext.html" title="Chapter 22. guacamole-ext" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, target-densitydpi=device-dpi"/>
</head><body>
<!-- CONTENT -->
<div id="page"><div id="content">
<div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 21. guacamole-common-js</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="guacamole-common.html">Prev</a> </td><th width="60%" align="center">Part II. Developer's Guide</th><td width="20%" align="right"> <a accesskey="n" href="guacamole-ext.html">Next</a></td></tr></table><hr /></div><div xml:lang="en" class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a id="guacamole-common-js"></a>Chapter 21. guacamole-common-js</h2></div></div></div><div class="toc"><p><strong>Table of Contents</strong></p><dl class="toc"><dt><span class="section"><a href="guacamole-common-js.html#guacamole-client">Guacamole client</a></span></dt><dt><span class="section"><a href="guacamole-common-js.html#http-tunnel">HTTP tunnel</a></span></dt><dt><span class="section"><a href="guacamole-common-js.html#input-abstraction">Input abstraction</a></span></dt><dd><dl><dt><span class="section"><a href="guacamole-common-js.html#guacamole-mouse">Mouse</a></span></dt><dt><span class="section"><a href="guacamole-common-js.html#guacamole-touch">Touch</a></span></dt><dt><span class="section"><a href="guacamole-common-js.html#guacamole-keyboard">Keyboard</a></span></dt></dl></dd><dt><span class="section"><a href="guacamole-common-js.html#on-screen-keyboard">On-screen keyboard</a></span></dt><dd><dl><dt><span class="section"><a href="guacamole-common-js.html#keyboard-layouts">Keyboard layouts</a></span></dt><dt><span class="section"><a href="guacamole-common-js.html#displaying-osk">Displaying the keyboard</a></span></dt><dt><span class="section"><a href="guacamole-common-js.html#styling-the-keyboard">Styling the keyboard</a></span></dt><dt><span class="section"><a href="guacamole-common-js.html#osk-event-handling">Handling key events</a></span></dt></dl></dd></dl></div><a id="idm46420845024048" class="indexterm"></a><a id="idm46420845022704" class="indexterm"></a><p>The Guacamole project provides a JavaScript API for interfacing with
other components that conform to the design of Guacamole, such as
projects using libguac or guacamole-common. This API is called
guacamole-common-js.</p><p>guacamole-common-js provides a JavaScript implementation of a
Guacamole client, as well as tunneling mechanisms for getting protocol
data out of JavaScript and into guacd or the server side of a web
application.</p><p>For convenience, it also provides mouse and keyboard abstraction objects that translate
JavaScript mouse, touch, and keyboard events into consistent data that Guacamole can more
easily digest. The extendable on-screen keyboard that was developed for the Guacamole web
application is also included.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="guacamole-client"></a>Guacamole client</h2></div></div></div><p>The main benefit to using the JavaScript API is the full Guacamole
client implementation, which implements all Guacamole instructions,
and makes use of the tunnel implementations provided by both the
JavaScript and Java APIs.</p><p>Using the Guacamole client is straightforward. The client, like
all other objects within the JavaScript API, is within the
<code class="code">Guacamole</code> namespace. It is instantiated given an
existing, unconnected tunnel:</p><div class="informalexample"><pre class="programlisting">var client = new Guacamole.Client(tunnel);</pre></div><p>Once you have the client, it won't immediately appear within the
DOM. You need to add its display element manually:</p><div class="informalexample"><pre class="programlisting">document.body.appendChild(client.getDisplay().getElement());</pre></div><p>At this point, the client will be visible, rendering all updates
as soon as they are received through the tunnel.</p><div class="informalexample"><pre class="programlisting">client.connect();</pre></div><p>It is possible to pass arbitrary data to the tunnel during
connection which can be used for authentication or for choosing a
particular connection. When the <code class="methodname">connect()</code>
function of the Guacamole client is called, it in turn calls the
<code class="methodname">connect()</code> function of the tunnel
originally given to the client, establishing a connection.</p><div class="important"><h3 class="title">Important</h3><p>When creating the <code class="classname">Guacamole.Client</code>, the
tunnel used must not already be connected. The
<code class="classname">Guacamole.Client</code> will call the
<code class="methodname">connect()</code> function for you when its
own <code class="methodname">connect()</code> function is invoked. If
the tunnel is already connected when it is given to the
<code class="classname">Guacamole.Client</code>, connection may not
work at all.</p></div><p>In general, all instructions available within the Guacamole
protocol are automatically handled by the Guacamole client,
including instructions related to audio and video. The only
instructions which you must handle yourself are "name" (used to name
the connection), "clipboard" (used to update clipboard data on the
client side), and "error" (used when something goes wrong
server-side). Each of these instructions has a corresponding event
handler; you need only supply functions to handle these events. If
any of these event handlers are left unset, the corresponding
instructions are simply ignored.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="http-tunnel"></a>HTTP tunnel</h2></div></div></div><p>Both the Java and JavaScript API implement corresponding ends of
an HTTP tunnel, based on
<code class="classname">XMLHttpRequest</code>.</p><p>The tunnel is a true stream - there is no polling. An initial
request is made from the JavaScript side, and this request is
handled on the Java side. While this request is open, data is
streamed along the connection, and instructions within this stream
are handled as soon as they are received by the client.</p><p>While data is being streamed along this existing connection, a
second connection attempt is made. Data continues to be streamed
along the original connection until the server receives and handles
the second request, at which point the original connection closes
and the stream is transferred to the new connection.</p><p>This process repeats, alternating between active streams, thus
creating an unbroken sequence of instructions, while also allowing
JavaScript to free any memory used by the previously active
connection.</p><p>The tunnel is created by supplying the relative URL to the
server-side tunnel servlet:</p><div class="informalexample"><pre class="programlisting">var tunnel = new Guacamole.Tunnel("tunnel");</pre></div><p>Once created, the tunnel can be passed to a
<code class="classname">Guacamole.Client</code> for use in a Guacamole
connection.</p><p>The tunnel actually takes care of the Guacamole protocol parsing
on behalf of the client, triggering "oninstruction" events for every
instruction received, splitting each element into elements of an
array so that the client doesn't have to.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="input-abstraction"></a>Input abstraction</h2></div></div></div><p>Browsers can be rather finicky when it comes to keyboard and mouse
input, not to mention touch events. There is little agreement on
which keyboard events get fired when, and what detail about the
event is made available to JavaScript. Touch and mouse events can
also cause confusion, as most browsers will generate
<span class="emphasis"><em>both</em></span> events when the user touches the
screen (for compatibility with JavaScript code that only handles
mouse events), making it more difficult for applications to support
both mouse and touch independently.</p><p>The Guacamole JavaScript API abstracts mouse, keyboard, and touch
interaction, providing several helper objects which act as an
abstract interface between you and the browser events.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="guacamole-mouse"></a>Mouse</h3></div></div></div><p>Mouse event abstraction is provided by the
<code class="classname">Guacamole.Mouse</code> object. Given an
arbitrary DOM element, <code class="classname">Guacamole.Mouse</code>
triggers <span class="property">onmousedown</span>,
<span class="property">onmousemove</span>, and
<span class="property">onmouseup</span> events which are consistent
across browsers. This object only response. to true mouse
events. Mouse events which are actually the result of touch
events are ignored.</p><div class="informalexample"><pre class="programlisting">var element = document.getElementById("some-arbitrary-id");
var mouse = new Guacamole.Mouse(element);
mouse.onmousedown =
mouse.onmousemove =
mouse.onmouseup = function(state) {
// Do something with the mouse state received ...
};</pre></div><p>The handles of each event are given an instance of
<code class="classname">Guacamole.Mouse.State</code> which
represents the current state of the mouse, containing the state
of each button (including the scroll wheel) as well as the X and
Y coordinates of the pointer in pixels.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="guacamole-touch"></a>Touch</h3></div></div></div><p>Touch event abstraction is provided by either
<code class="classname">Guacamole.Touchpad</code> (emulates a
touchpad to generate artificial mouse events) or
<code class="classname">Guacamole.Touchscreen</code> (emulates a
touchscreen, again generating artificial mouse events).
Guacamole uses the touchpad emulation, as this provides the most
flexibility and mouse-like features, including scrollwheel and
clicking with different buttons, but your preferences may
differ.</p><div class="informalexample"><pre class="programlisting">var element = document.getElementById("some-arbitrary-id");
var touch = new Guacamole.Touchpad(element); // or Guacamole.Touchscreen
touch.onmousedown =
touch.onmousemove =
touch.onmouseup = function(state) {
// Do something with the mouse state received ...
};</pre></div><p>Note that even though these objects are touch-specific, they
still provide mouse events. The state object given to the event
handlers of each event is still an instance of
<code class="classname">Guacamole.Mouse.State</code>.</p><p>Ultimately, you could assign the same event handler to all the
events of both an instance of
<code class="classname">Guacamole.Mouse</code> as well as
<code class="classname">Guacamole.Touchscreen</code> or
<code class="classname">Guacamole.Touchpad</code>, and you would
magically gain mouse and touch support. This support, being
driven by the needs of remote desktop, is naturally geared
around the mouse and providing a reasonable means of interacting
with it. For an actual mouse, events are translated simply and
literally, while touch events go through additional emulation
and heuristics. From the perspective of the user and the code,
this is all transparent.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="guacamole-keyboard"></a>Keyboard</h3></div></div></div><p>Keyboard events in Guacamole are abstracted with the
<code class="classname">Guacamole.Keyboard</code> object as only
keyup and keydown events; there is no keypress like there is in
JavaScript. Further, all the craziness of keycodes vs. scancodes
vs. key identifiers normally present across browsers is
abstracted away. All your event handlers will see is an X11
keysym, which represent every key unambiguously. Conveniently,
X11 keysyms are also what the Guacamole protocol requires, so if
you want to use <code class="classname">Guacamole.Keyboard</code> to
drive key events sent over the Guacamole protocol, everything
can be connected directly.</p><p>Just like the other input abstraction objects,
<code class="classname">Guacamole.Keyboard</code> requires a DOM
element as an event target. Only key events directed at this
element will be handled.</p><div class="informalexample"><pre class="programlisting">var keyboard = new Guacamole.Keyboard(document);
keyboard.onkeydown = function(keysym) {
// Do something ...
};
keyboard.onkeyup = function(keysym) {
// Do something ...
};</pre></div><p>In this case, we are using <code class="classname">document</code> as
the event target, thus receiving all key events while the
browser window (or tab) has focus.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="on-screen-keyboard"></a>On-screen keyboard</h2></div></div></div><p>The Guacamole JavaScript API also provides an extendable on-screen
keyboard, <code class="classname">Guacamole.OnScreenKeyboard</code>, which
requires the URL of an XML file describing the keyboard layout. The
on-screen keyboard object provides no hard-coded layout information;
the keyboard layout is described entirely within the XML layout
file.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="keyboard-layouts"></a>Keyboard layouts</h3></div></div></div><p>The keyboard layout XML included in the Guacamole web
application would be a good place to start regarding how these
layout files are written, but in general, the keyboard is simply
a set of rows or columns, denoted with <code class="code">&lt;row&gt;</code> and
<code class="code">&lt;column&gt;</code> tags respectively, where each can
be nested within the other as desired.</p><p>Each key is represented with a <code class="code">&lt;key&gt;</code> tag, but
this is not what the user sees, nor what generates the key
event. Each key contains any number of <code class="code">&lt;cap&gt;</code>
tags, which represent the visible part of the key. The cap
describes which X11 keysym will be sent when the key is pressed.
Each cap can be associated with any combination of arbitrary
modifier flags which dictate when that cap is active.</p><p>For example:</p><div class="informalexample"><pre class="programlisting">&lt;keyboard lang="en_US" layout="example" size="5"&gt;
&lt;row&gt;
&lt;key size="4"&gt;
&lt;cap modifier="shift" keysym="0xFFE1"&gt;Shift&lt;/cap&gt;
&lt;/key&gt;
&lt;key&gt;
&lt;cap&gt;a&lt;/cap&gt;
&lt;cap if="shift"&gt;A&lt;/cap&gt;
&lt;/key&gt;
&lt;/row&gt;
&lt;/keyboard&gt;</pre></div><p>Here we have a very simple keyboard which defines only two
keys: "shift" (a modifier) and the letter "a". When "shift" is
pressed, it sets the "shift" modifier, affecting other keys in
the keyboard. The "a" key has two caps: one lowercase (the
default) and one uppercase (which requires the shift modifier to
be active).</p><p>Notice that the shift key needed the keysym explicitly
specified, while the "a" key did not. This is because the
on-screen keyboard will automatically derive the correct keysym
from the text of the key cap if the text contains only a single
character.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="displaying-osk"></a>Displaying the keyboard</h3></div></div></div><p>Once you have a keyboard layout available, adding an on-screen
keyboard to your application is simple:</p><div class="informalexample"><pre class="programlisting">// Add keyboard to body
var keyboard = new Guacamole.OnScreenKeyboard("path/to/layout.xml");
document.body.appendChild(keyboard.getElement());
// Set size of keyboard to 100 pixels
keyboard.resize(100);</pre></div><p>Here, we have explicitly specified the width of the keyboard
as 100 pixels. Normally, you would determine this by inspecting
the width of the containing component, or by deciding on a
reasonable width beforehand. Once the width is given, the height
of the keyboard is determined based on the arrangement of each
row.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="styling-the-keyboard"></a>Styling the keyboard</h3></div></div></div><p>While the <code class="classname">Guacamole.OnScreenKeyboard</code>
object will handle most of the layout, you will still need to
style everything yourself with CSS to get the elements to render
properly and the keys to change state when clicked or activated.
It defines several CSS classes, which you will need to manually
style to get things looking as desired:</p><div class="variablelist"><dl class="variablelist"><dt><span class="term"><code class="classname">guac-keyboard</code></span></dt><dd><p>This class is assigned to the root element
containing the entire keyboard, returned by
<code class="methodname">getElement()</code>,</p></dd><dt><span class="term"><code class="classname">guac-keyboard-row</code></span></dt><dd><p>Assigned to the <code class="code">div</code> elements which
contain each row.</p></dd><dt><span class="term"><code class="classname">guac-keyboard-column</code></span></dt><dd><p>Assigned to the <code class="code">div</code> elements which
contain each column.</p></dd><dt><span class="term"><code class="classname">guac-keyboard-gap</code></span></dt><dd><p>Assigned to any <code class="code">div</code> elements created
as a result of <code class="code">&lt;gap&gt;</code> tags in the
keyboard layout. <code class="code">&lt;gap&gt;</code> tags are
intended to behave as keys with no visible styling
or caps.</p></dd><dt><span class="term"><code class="classname">guac-keyboard-key-container</code></span></dt><dd><p>Assigned to the <code class="code">div</code> element which
contains a key, and provides that key with its
required dimensions. It is this element that will be
scaled relative to the size specified in the layout
XML and the size given to the <code class="code">resize()</code>
function.</p></dd><dt><span class="term"><code class="classname">guac-keyboard-key</code></span></dt><dd><p>Assigned to the <code class="code">div</code> element which
represents the actual key, not the cap. This element
will not directly contain text, but it will contain
all caps that this key can have. With clever CSS
rules, you can take advantage of this and cause
inactive caps to appear on the key in a corner (for
example), or hide them entirely.</p></dd><dt><span class="term"><code class="classname">guac-keyboard-cap</code></span></dt><dd><p>Assigned to the <code class="code">div</code> element
representing a key cap. Each cap is a child of its
corresponding key, and it is up to the author of the
CSS rules to hide or show or reposition each cap
appropriately. Each cap will contain the display
text defined within the <code class="code">&lt;cap&gt;</code>
element in the layout XML.</p></dd><dt><span class="term"><code class="classname">guac-keyboard-requires-<em class="replaceable"><code>MODIFIER</code></em></code></span></dt><dd><p>Added to the cap element when that cap requires a
specific modifier.</p></dd><dt><span class="term"><code class="classname">guac-keyboard-uses-<em class="replaceable"><code>MODIFIER</code></em></code></span></dt><dd><p>Added to the key element when any cap contained
within it requires a specific modifier.</p></dd><dt><span class="term"><code class="classname">guac-keyboard-modifier-<em class="replaceable"><code>MODIFIER</code></em></code></span></dt><dd><p>Added to and removed from the root keyboard
element when a modifier key is activated or
deactivated respectively.</p></dd><dt><span class="term"><code class="classname">guac-keyboard-pressed</code></span></dt><dd><p>Added to and removed from any key element as it is
pressed and released respectively.</p></dd></dl></div><div class="important"><h3 class="title">Important</h3><p>The CSS rules required for the on-screen keyboard to work
as expected can be quite complex. Looking over the CSS rules
used by the on-screen keyboard in the Guacamole web
application would be a good place to start to see how the
appearance of each key can be driven through the simple
class changes described above.</p><p>Inspecting the elements of an active on-screen keyboard
within the Guacamole web application with the developer
tools of your favorite browser is also a good idea.</p></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="osk-event-handling"></a>Handling key events</h3></div></div></div><p>Key events generated by the on-screen keyboard are identical
to those of <code class="classname">Guacamole.Keyboard</code> in that
they consist only of a single X11 keysym. Only keyup and keydown
events exist, as before; there is no keypress event.</p><div class="informalexample"><pre class="programlisting">// Assuming we have an instance of Guacamole.OnScreenKeyboard already
// called "keyboard"
keyboard.onkeydown = function(keysym) {
// Do something ...
};
keyboard.onkeyup = function(keysym) {
// Do something ...
};</pre></div></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="guacamole-common.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="developers-guide.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="guacamole-ext.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 20. <span class="package">guacamole-common</span> </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 22. guacamole-ext</td></tr></table></div>
</div></div>
</body></html>