You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by de...@apache.org on 2013/11/08 09:16:12 UTC
[9/9] git commit: updated refs/heads/master to a98c473
Remote Desktop Protocol(RDP) client that is suitable for including in the console VM.
The client renders RDP to a window created by Java. It is important for Hyper-V support,
because Hyper-V provides access to the consoles of VMs that it is running over RDP.
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/a98c473d
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/a98c473d
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/a98c473d
Branch: refs/heads/master
Commit: a98c473dca9ff2af1275f6c9afda773fc416a727
Parents: 57ba367
Author: Devdeep Singh <de...@gmail.com>
Authored: Fri Nov 8 13:16:44 2013 +0530
Committer: Devdeep Singh <de...@gmail.com>
Committed: Fri Nov 8 13:35:11 2013 +0530
----------------------------------------------------------------------
.../console-proxy-rdp/rdpconsole/README.txt | 50 +
services/console-proxy-rdp/rdpconsole/pom.xml | 49 +
.../console-proxy-rdp/rdpconsole/rdp-config.bat | 42 +
.../src/main/java/common/AwtBellAdapter.java | 76 ++
.../src/main/java/common/AwtCanvasAdapter.java | 164 +++
.../main/java/common/AwtClipboardAdapter.java | 55 +
.../src/main/java/common/AwtKeyEventSource.java | 53 +
.../main/java/common/AwtMouseEventSource.java | 71 ++
.../src/main/java/common/BitmapOrder.java | 48 +
.../src/main/java/common/BitmapRectangle.java | 74 ++
.../main/java/common/BufferedImageCanvas.java | 79 ++
.../common/BufferedImageCopyRectAdapter.java | 124 ++
.../java/common/BufferedImagePixelsAdapter.java | 147 +++
.../rdpconsole/src/main/java/common/Client.java | 137 +++
.../src/main/java/common/CopyRectOrder.java | 39 +
.../src/main/java/common/KeyOrder.java | 45 +
.../src/main/java/common/MouseOrder.java | 41 +
.../src/main/java/common/OrderType.java | 22 +
.../src/main/java/common/ScreenDescription.java | 168 +++
.../main/java/common/SizeChangeListener.java | 22 +
.../java/rdpclient/AwtRdpKeyboardAdapter.java | 351 ++++++
.../main/java/rdpclient/AwtRdpMouseAdapter.java | 180 +++
.../java/rdpclient/ClientConfirmActivePDU.java | 1132 ++++++++++++++++++
.../main/java/rdpclient/ClientFastPathPDU.java | 55 +
.../src/main/java/rdpclient/ClientInfoPDU.java | 456 +++++++
.../rdpclient/ClientMCSAttachUserRequest.java | 102 ++
...JoinRequest_ServerMCSChannelConfirmPDUs.java | 222 ++++
.../java/rdpclient/ClientMCSConnectInitial.java | 669 +++++++++++
.../rdpclient/ClientMCSErectDomainRequest.java | 190 +++
.../java/rdpclient/ClientPacketSniffer.java | 50 +
.../java/rdpclient/ClientSynchronizePDU.java | 248 ++++
.../src/main/java/rdpclient/ClientTpkt.java | 54 +
.../ClientX224ConnectionRequestPDU.java | 156 +++
.../main/java/rdpclient/ClientX224DataPdu.java | 54 +
.../src/main/java/rdpclient/HandshakeEnd.java | 27 +
.../src/main/java/rdpclient/MockServer.java | 197 +++
.../src/main/java/rdpclient/PacketSniffer.java | 75 ++
.../java/rdpclient/RLEBitmapDecompression.java | 1014 ++++++++++++++++
.../src/main/java/rdpclient/RdpClient.java | 214 ++++
.../src/main/java/rdpclient/RdpConstants.java | 74 ++
.../src/main/java/rdpclient/RdpState.java | 33 +
.../main/java/rdpclient/ServerBitmapUpdate.java | 201 ++++
.../java/rdpclient/ServerChannel1003Router.java | 530 ++++++++
.../rdpclient/ServerControlPDUCooperate.java | 117 ++
.../ServerControlPDUGrantedControl.java | 114 ++
.../java/rdpclient/ServerDemandActivePDU.java | 661 ++++++++++
.../src/main/java/rdpclient/ServerFastPath.java | 259 ++++
.../ServerLicenseErrorPDUValidClient.java | 121 ++
.../ServerMCSAttachUserConfirmPDU.java | 133 ++
.../ServerMCSChannelJoinConfirmPDU.java | 89 ++
.../rdpclient/ServerMCSConnectResponse.java | 283 +++++
.../src/main/java/rdpclient/ServerMCSPDU.java | 149 +++
.../java/rdpclient/ServerPacketSniffer.java | 52 +
.../java/rdpclient/ServerPaletteUpdate.java | 78 ++
.../java/rdpclient/ServerSynchronizePDU.java | 115 ++
.../src/main/java/rdpclient/ServerTpkt.java | 70 ++
.../ServerX224ConnectionConfirmPDU.java | 237 ++++
.../main/java/rdpclient/ServerX224DataPdu.java | 64 +
.../rdpclient/TrustAllX509TrustManager.java | 40 +
.../main/java/rdpclient/UpgradeSocketToSSL.java | 44 +
.../main/java/streamer/AssertingByteBuffer.java | 107 ++
.../src/main/java/streamer/BaseElement.java | 417 +++++++
.../src/main/java/streamer/BufferPool.java | 36 +
.../src/main/java/streamer/ByteBuffer.java | 826 +++++++++++++
.../src/main/java/streamer/DataSink.java | 24 +
.../src/main/java/streamer/DataSource.java | 60 +
.../src/main/java/streamer/Direction.java | 21 +
.../src/main/java/streamer/Element.java | 120 ++
.../src/main/java/streamer/Event.java | 33 +
.../src/main/java/streamer/FakeSink.java | 69 ++
.../src/main/java/streamer/FakeSource.java | 125 ++
.../main/java/streamer/InputStreamSource.java | 194 +++
.../rdpconsole/src/main/java/streamer/Link.java | 66 +
.../src/main/java/streamer/MockSink.java | 111 ++
.../src/main/java/streamer/MockSource.java | 88 ++
.../src/main/java/streamer/OneTimeSwitch.java | 133 ++
.../src/main/java/streamer/Order.java | 23 +
.../main/java/streamer/OutputStreamSink.java | 153 +++
.../src/main/java/streamer/Pipeline.java | 91 ++
.../src/main/java/streamer/PipelineImpl.java | 309 +++++
.../src/main/java/streamer/Queue.java | 136 +++
.../src/main/java/streamer/SocketWrapper.java | 239 ++++
.../src/main/java/streamer/SyncLink.java | 402 +++++++
.../vncclient/AwtKeyboardEventToVncAdapter.java | 369 ++++++
.../vncclient/AwtMouseEventToVncAdapter.java | 71 ++
.../main/java/vncclient/EncodingsMessage.java | 63 +
.../vncclient/FrameBufferUpdateRequest.java | 127 ++
.../vncclient/RGB888LE32PixelFormatRequest.java | 90 ++
.../src/main/java/vncclient/RfbConstants.java | 85 ++
.../src/main/java/vncclient/VncClient.java | 107 ++
.../src/main/java/vncclient/VncInitializer.java | 244 ++++
.../main/java/vncclient/VncMessageHandler.java | 419 +++++++
.../java/vncclient/Vnc_3_3_Authentication.java | 291 +++++
.../src/main/java/vncclient/Vnc_3_3_Hello.java | 115 ++
.../rdpconsole/src/test/doc/README.txt | 32 +
.../rdpconsole/src/test/doc/dev-rdp-config.bat | 126 ++
.../rdpconsole/src/test/doc/rdp-key.pem | 23 +
.../src/test/java/rdpclient/MockServerTest.java | 189 +++
98 files changed, 16550 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/README.txt
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/README.txt b/services/console-proxy-rdp/rdpconsole/README.txt
new file mode 100644
index 0000000..15029d4
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/README.txt
@@ -0,0 +1,50 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+This project contains code for basic VNC and RDP clients.
+
+VNC client can be invoked using following command:
+
+ mvn exec:java -Dexec.mainClass="common.Client" -Dexec.args="vnc 192.168.0.101 5901 password"
+
+where
+ * vnc - name of protcol;
+ * 192.168.0.101 - IP of VNC server;
+ * 5901 - port of VNC server screen (5900+display number);
+ * password - VNC server password.
+
+
+RDP client can be invoked using following command:
+
+ mvn exec:java -Dexec.mainClass="common.Client" -Dexec.args="rdp 192.168.0.101 3389 Administrator"
+
+where
+ * rdp - name of protcol;
+ * 192.168.0.101 - IP of RDP server;
+ * 3389 - port of RDP server;
+ * Administrator - user name for loging dialog.
+
+
+Limitations of VNC client:
+ * only basic functionality work.
+
+Limitations of RDP client:
+ * it uses SSL/TLS;
+ * NLA is not supported;
+ * only basic functionality work.
+
+
+To configure and start RDP service properly, run rdp-config.bat on server.
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/pom.xml
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/pom.xml b/services/console-proxy-rdp/rdpconsole/pom.xml
new file mode 100644
index 0000000..d1b4918
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/pom.xml
@@ -0,0 +1,49 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>rdpclient</groupId>
+ <artifactId>rdpclient</artifactId>
+ <version>4.3.0-SNAPSHOT</version>
+ <packaging>jar</packaging>
+
+ <name>rdpclient</name>
+ <url>http://maven.apache.org</url>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tomcat.embed</groupId>
+ <artifactId>tomcat-embed-core</artifactId>
+ <version>7.0.30</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/rdp-config.bat
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/rdp-config.bat b/services/console-proxy-rdp/rdpconsole/rdp-config.bat
new file mode 100644
index 0000000..e951014
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/rdp-config.bat
@@ -0,0 +1,42 @@
+rem Licensed to the Apache Software Foundation (ASF) under one
+rem or more contributor license agreements. See the NOTICE file
+rem distributed with this work for additional information
+rem regarding copyright ownership. The ASF licenses this file
+rem to you under the Apache License, Version 2.0 (the
+rem "License"); you may not use this file except in compliance
+rem with the License. You may obtain a copy of the License at
+rem
+rem http://www.apache.org/licenses/LICENSE-2.0
+rem
+rem Unless required by applicable law or agreed to in writing,
+rem software distributed under the License is distributed on an
+rem "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+rem KIND, either express or implied. See the License for the
+rem specific language governing permissions and limitations
+rem under the License.
+
+rem
+rem Configure and start RDP service.
+rem
+
+rem Turn off firewall
+
+netsh advfirewall firewall set rule group="Remote Desktop" new enable=yes
+
+rem Enable TS connections
+
+reg add "HKLM\System\CurrentControlSet\Control\Terminal Server" /v "AllowTSConnections" /t REG_DWORD /d 1 /f
+reg add "HKLM\System\CurrentControlSet\Control\Terminal Server" /v "fDenyTSConnections" /t REG_DWORD /d 0 /f
+
+rem Disable RDP NLA
+
+reg add "HKLM\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v UserAuthentication /t REG_DWORD /d 0 /f
+
+rem Enable TS service
+
+sc config TermService start=auto
+
+rem Start TS service
+
+net start Termservice
+
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtBellAdapter.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtBellAdapter.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtBellAdapter.java
new file mode 100644
index 0000000..3318c09
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtBellAdapter.java
@@ -0,0 +1,76 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package common;
+
+import java.awt.Toolkit;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Element;
+import streamer.FakeSource;
+import streamer.Link;
+import streamer.Pipeline;
+import streamer.PipelineImpl;
+
+public class AwtBellAdapter extends BaseElement {
+
+ public AwtBellAdapter(String id) {
+ super(id);
+ declarePads();
+ }
+
+ private void declarePads() {
+ inputPads.put(STDIN, null);
+ }
+
+ @Override
+ public void handleData(ByteBuffer buf, Link link) {
+ if (verbose)
+ System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+ if (buf == null)
+ return;
+
+ Toolkit.getDefaultToolkit().beep();
+ }
+
+ public String toString() {
+ return "Bell(" + id + ")";
+ }
+
+ /**
+ * Example.
+ */
+ public static void main(String args[]) {
+ System.setProperty("streamer.Element.debug", "true");
+
+ Element source = new FakeSource("source") {
+ {
+ this.incommingBufLength = 0;
+ this.delay = 1000;
+ this.numBuffers = 3;
+ }
+ };
+
+ Element sink = new AwtBellAdapter("sink");
+
+ Pipeline pipeline = new PipelineImpl("test");
+ pipeline.addAndLink(source, sink);
+ pipeline.runMainLoop("source", STDOUT, false, false);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtCanvasAdapter.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtCanvasAdapter.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtCanvasAdapter.java
new file mode 100644
index 0000000..12dd88b
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtCanvasAdapter.java
@@ -0,0 +1,164 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package common;
+
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.WritableRaster;
+
+import rdpclient.ServerBitmapUpdate;
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Element;
+import streamer.Link;
+import streamer.Order;
+import streamer.Pipeline;
+import streamer.PipelineImpl;
+
+public class AwtCanvasAdapter extends BaseElement {
+
+ protected ScreenDescription screen;
+
+ public AwtCanvasAdapter(String id, BufferedImageCanvas canvas, ScreenDescription screen) {
+ super(id);
+ this.canvas = canvas;
+ this.screen = screen;
+ }
+
+ protected BufferedImageCanvas canvas;
+
+ public String toString() {
+ return "AwtRdpAdapter(" + id + ")";
+ }
+
+ @Override
+ public void handleData(ByteBuffer buf, Link link) {
+ if (verbose)
+ System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+ Order order = (Order) buf.getOrder();
+ switch ((OrderType) order.type) {
+
+ case BITMAP_UPDATE:
+ handleBitmap((BitmapOrder) order, buf);
+ break;
+
+ case COPY_RECT:
+ handleCopyRect((CopyRectOrder) order, buf);
+ break;
+
+ default:
+ throw new RuntimeException("Order is not implemented: " + buf + ".");
+ // break;
+ }
+
+ buf.unref();
+ }
+
+ private void handleCopyRect(CopyRectOrder order, ByteBuffer buf) {
+ // TODO Auto-generated method stub
+ // Copy image
+ canvas.getOfflineGraphics().copyArea(order.srcX, order.srcY, order.width, order.height, order.x - order.srcX, order.y - order.srcY);
+
+ // Request update of repainted area
+ canvas.repaint(order.x, order.y, order.width, order.height);
+
+ }
+
+ private void handleBitmap(BitmapOrder order, ByteBuffer buf) {
+ // Draw rectangle on offline buffer
+ BufferedImage image = canvas.getOfflineImage();
+ Graphics2D g = (Graphics2D) image.getGraphics();
+
+ for (BitmapRectangle rectangle : order.rectangles) {
+ // *DEBUG*/System.out.println("["+this+"] DEBUG: Rectangle: " +
+ // rectangle.toString());
+
+ int x = rectangle.x;
+ int y = rectangle.y;
+ int width = rectangle.width;
+ int height = rectangle.height;
+ int bufferWidth = rectangle.bufferWidth;
+ int bufferHeight = rectangle.bufferHeight;
+
+ BufferedImage rectImage;
+ switch (rectangle.colorDepth) {
+ case 8: {
+ rectImage = new BufferedImage(bufferWidth, height, BufferedImage.TYPE_BYTE_INDEXED, screen.colorMap);
+ WritableRaster raster = rectImage.getRaster();
+ raster.setDataElements(0, 0, bufferWidth, bufferHeight, rectangle.bitmapDataStream.toByteArray());
+ break;
+ }
+ case 15: {
+ rectImage = new BufferedImage(bufferWidth, height, BufferedImage.TYPE_USHORT_555_RGB);
+ WritableRaster raster = rectImage.getRaster();
+ raster.setDataElements(0, 0, bufferWidth, bufferHeight, rectangle.bitmapDataStream.toShortArray());
+ break;
+ }
+ case 16: {
+ rectImage = new BufferedImage(bufferWidth, height, BufferedImage.TYPE_USHORT_565_RGB);
+ WritableRaster raster = rectImage.getRaster();
+ raster.setDataElements(0, 0, bufferWidth, bufferHeight, rectangle.bitmapDataStream.toShortArray());
+ break;
+ }
+ case 24:
+ case 32: {
+ rectImage = new BufferedImage(bufferWidth, height, BufferedImage.TYPE_INT_RGB);
+ WritableRaster raster = rectImage.getRaster();
+ raster.setDataElements(0, 0, bufferWidth, bufferHeight, rectangle.bitmapDataStream.toIntLEArray());
+ break;
+ }
+ default:
+ throw new RuntimeException("Unsupported color depth: " + rectangle.colorDepth + ".");
+ }
+
+ g.setClip(x, y, width, height);
+ g.drawImage(rectImage, x, y, null);
+
+ // Request update of repainted area
+ canvas.repaint(x, y, width, height);
+ }
+
+ }
+
+ /**
+ * Example.
+ */
+ public static void main(String args[]) {
+ // System.setProperty("streamer.Link.debug", "true");
+ // System.setProperty("streamer.Element.debug", "true");
+ // System.setProperty("streamer.Pipeline.debug", "true");
+ ByteBuffer packet = new ByteBuffer(new byte[] { 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x10, 0x00,
+ 0x01, 0x04, 0x0a, 0x00, 0x0c, (byte) 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 });
+
+ Pipeline pipeline = new PipelineImpl("test");
+
+ Element bitmap = new ServerBitmapUpdate("bitmap");
+
+ BufferedImageCanvas canvas = new BufferedImageCanvas(1024, 768);
+ Element adapter = new AwtCanvasAdapter("test", canvas, null) {
+ {
+ verbose = true;
+ }
+ };
+ pipeline.addAndLink(bitmap, adapter);
+
+ bitmap.handleData(packet, null);
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtClipboardAdapter.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtClipboardAdapter.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtClipboardAdapter.java
new file mode 100644
index 0000000..aeed41c
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtClipboardAdapter.java
@@ -0,0 +1,55 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package common;
+
+import java.awt.Toolkit;
+import java.awt.datatransfer.StringSelection;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Link;
+import vncclient.VncMessageHandler;
+
+public class AwtClipboardAdapter extends BaseElement {
+
+ public AwtClipboardAdapter(String id) {
+ super(id);
+ declarePads();
+ }
+
+ private void declarePads() {
+ inputPads.put(STDIN, null);
+ }
+
+ @Override
+ public void handleData(ByteBuffer buf, Link link) {
+ if (verbose)
+ System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+ if (buf == null)
+ return;
+
+ String content = (String) buf.getMetadata(VncMessageHandler.CLIPBOARD_CONTENT);
+ StringSelection contents = new StringSelection(content);
+ Toolkit.getDefaultToolkit().getSystemClipboard().setContents(contents, null);
+ }
+
+ public String toString() {
+ return "Clipboard(" + id + ")";
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtKeyEventSource.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtKeyEventSource.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtKeyEventSource.java
new file mode 100644
index 0000000..a754796
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtKeyEventSource.java
@@ -0,0 +1,53 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package common;
+
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+
+public class AwtKeyEventSource extends BaseElement implements KeyListener {
+
+ public AwtKeyEventSource(String id) {
+ super(id);
+ }
+
+ @Override
+ public void keyTyped(KeyEvent e) {
+ // Nothing to do
+
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ sendEvent(e, true);
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ sendEvent(e, false);
+ }
+
+ private void sendEvent(KeyEvent e, boolean pressed) {
+ ByteBuffer buf=new ByteBuffer(new KeyOrder(e, pressed));
+
+ pushDataToAllOuts(buf);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtMouseEventSource.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtMouseEventSource.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtMouseEventSource.java
new file mode 100644
index 0000000..f3e58fc
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtMouseEventSource.java
@@ -0,0 +1,71 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package common;
+
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+
+public class AwtMouseEventSource extends BaseElement implements MouseListener, MouseMotionListener {
+
+ public AwtMouseEventSource(String id) {
+ super(id);
+ }
+
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ // Nothing to do
+ }
+
+ @Override
+ public void mousePressed(MouseEvent e) {
+ MouseOrder order = new MouseOrder(e);
+ order.pressed = true;
+ pushDataToAllOuts(new ByteBuffer(order));
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ MouseOrder order = new MouseOrder(e);
+ order.released = true;
+ pushDataToAllOuts(new ByteBuffer(order));
+ }
+
+ @Override
+ public void mouseEntered(MouseEvent e) {
+ // Nothing to do
+ }
+
+ @Override
+ public void mouseExited(MouseEvent e) {
+ // Nothing to do
+ }
+
+ @Override
+ public void mouseDragged(MouseEvent e) {
+ pushDataToAllOuts(new ByteBuffer(new MouseOrder(e)));
+ }
+
+ @Override
+ public void mouseMoved(MouseEvent e) {
+ pushDataToAllOuts(new ByteBuffer(new MouseOrder(e)));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/BitmapOrder.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/BitmapOrder.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/BitmapOrder.java
new file mode 100644
index 0000000..438755f
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/BitmapOrder.java
@@ -0,0 +1,48 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package common;
+
+import java.util.Arrays;
+
+
+import streamer.Order;
+
+/**
+ * Not an order, but derived from Order class for compatibility with orders.
+ *
+ * @see http://msdn.microsoft.com/en-us/library/dd306368.aspx
+ */
+public class BitmapOrder extends Order {
+
+ public BitmapOrder() {
+ type = OrderType.BITMAP_UPDATE;
+ }
+
+ /**
+ * Structures, each of which contains a rectangular clipping taken from the
+ * server-side screen frame buffer.
+ */
+ public BitmapRectangle rectangles[];
+
+ @Override
+ public String toString() {
+ final int maxLen = 10;
+ return String.format("BitmapUpdateOrder [rectangles=%s]", rectangles != null ? Arrays.asList(rectangles).subList(0, Math.min(rectangles.length, maxLen))
+ : null);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/BitmapRectangle.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/BitmapRectangle.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/BitmapRectangle.java
new file mode 100644
index 0000000..f0c178e
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/BitmapRectangle.java
@@ -0,0 +1,74 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package common;
+
+import streamer.ByteBuffer;
+
+/**
+ * @see http://msdn.microsoft.com/en-us/library/cc240612.aspx
+ */
+public class BitmapRectangle {
+
+ /**
+ * Left bound of the rectangle.
+ */
+ public int x;
+
+ /**
+ * Top bound of the rectangle.
+ */
+ public int y;
+
+ /**
+ * Width of the rectangle.
+ */
+ public int width;
+
+ /**
+ * Height of the rectangle.
+ */
+ public int height;
+
+ /**
+ * Color depth of the rectangle data in bits-per-pixel.
+ */
+ public int colorDepth;
+
+ /**
+ * Variable-length array of bytes describing a raw uncompressed bitmap image.
+ */
+ public ByteBuffer bitmapDataStream;
+
+ /**
+ * Size of single horizontal scan line.
+ */
+ public int bufferWidth;
+
+ /**
+ * Number of horizontal scan lines in buffer.
+ */
+ public int bufferHeight;
+
+ @Override
+ public String toString() {
+ return String
+ .format(
+ "BitmapUpdateRectangle [x=%s, y=%s, width=%s, height=%s, bitsPerPixel=%s, bitmapDataStream=%s]",
+ x, y, width, height, colorDepth, bitmapDataStream);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImageCanvas.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImageCanvas.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImageCanvas.java
new file mode 100644
index 0000000..6e7738f
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImageCanvas.java
@@ -0,0 +1,79 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package common;
+
+import java.awt.Canvas;
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+
+/**
+ * A <code>BuffereImageCanvas</code> component represents frame buffer image on the
+ * screen. It also notifies its subscribers when screen is repainted.
+ */
+public class BufferedImageCanvas extends Canvas {
+ private static final long serialVersionUID = 1L;
+
+ // Offline screen buffer
+ private BufferedImage offlineImage;
+
+ // Cached Graphics2D object for offline screen buffer
+ private Graphics2D graphics;
+
+ public BufferedImageCanvas(int width, int height) {
+ super();
+
+ setBackground(Color.black);
+
+ setFocusable(true);
+
+ // Don't intercept TAB key
+ setFocusTraversalKeysEnabled(false);
+
+ setCanvasSize(width, height);
+ }
+
+ public void setCanvasSize(int width, int height) {
+ this.offlineImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+ graphics = offlineImage.createGraphics();
+
+ setSize(offlineImage.getWidth(), offlineImage.getHeight());
+ }
+
+ @Override
+ public void update(Graphics g) {
+ // Call paint() directly, without clearing screen first
+ paint(g);
+ }
+
+ @Override
+ public void paint(Graphics g) {
+ // Only part of image, requested with repaint(Rectangle), will be
+ // painted on screen.
+ g.drawImage(offlineImage, 0, 0, this);
+ }
+
+ public BufferedImage getOfflineImage() {
+ return offlineImage;
+ }
+
+ public Graphics2D getOfflineGraphics() {
+ return graphics;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImageCopyRectAdapter.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImageCopyRectAdapter.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImageCopyRectAdapter.java
new file mode 100644
index 0000000..bbd5142
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImageCopyRectAdapter.java
@@ -0,0 +1,124 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package common;
+
+import java.awt.image.DataBufferInt;
+import java.util.Arrays;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Element;
+import streamer.Link;
+
+public class BufferedImageCopyRectAdapter extends BaseElement {
+
+ public static final String SRC_X = "srcX";
+ public static final String SRC_Y = "srcY";
+ public static final String TARGET_X = "x";
+ public static final String TARGET_Y = "y";
+ public static final String WIDTH = "width";
+ public static final String HEIGHT = "height";
+
+ protected BufferedImageCanvas canvas;
+
+ public BufferedImageCopyRectAdapter(String id, BufferedImageCanvas canvas) {
+ super(id);
+ this.canvas = canvas;
+ declarePads();
+ }
+
+ private void declarePads() {
+ inputPads.put(STDIN, null);
+ }
+
+ public String toString() {
+ return "Renderer(" + id + ")";
+ }
+
+ @Override
+ public void handleData(ByteBuffer buf, Link link) {
+ if (buf == null)
+ return;
+
+ if (verbose)
+ System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+ int x = (Integer) buf.getMetadata(TARGET_X);
+ int y = (Integer) buf.getMetadata(TARGET_Y);
+ int width = (Integer) buf.getMetadata(WIDTH);
+ int height = (Integer) buf.getMetadata(HEIGHT);
+ int srcX = (Integer) buf.getMetadata(SRC_X);
+ int srcY = (Integer) buf.getMetadata(SRC_Y);
+ buf.unref();
+
+ // Copy image
+ canvas.getOfflineGraphics().copyArea(srcX, srcY, width, height, x - srcX, y - srcY);
+
+ // Request update of repainted area
+ canvas.repaint(x, y, width, height);
+ }
+
+ public static void main(String args[]) {
+ System.setProperty("streamer.Element.debug", "true");
+
+ BufferedImageCanvas canvas = new BufferedImageCanvas(4, 4);
+
+ Element renderer = new BufferedImageCopyRectAdapter("renderer", canvas);
+
+ int[] pixelsBeforeCopy = new int[] {
+ // 0
+ 1, 2, 3, 4,
+ // 1
+ 5, 6, 7, 8,
+ // 2
+ 9, 10, 11, 12,
+ // 3
+ 13, 14, 15, 16 };
+ int[] pixelsAfterCopy = new int[] {
+ // 0
+ 11, 12, 3, 4,
+ // 1
+ 15, 16, 7, 8,
+ // 2
+ 9, 10, 11, 12,
+ // 3
+ 13, 14, 15, 16 };
+
+
+ // Initalize image
+ int[] data = ((DataBufferInt) canvas.getOfflineImage().getRaster().getDataBuffer()).getData();
+ System.arraycopy(pixelsBeforeCopy, 0, data, 0, pixelsBeforeCopy.length);
+
+ ByteBuffer buf = new ByteBuffer(new byte[0]);
+ buf.putMetadata(TARGET_X, 0);
+ buf.putMetadata(TARGET_Y, 0);
+ buf.putMetadata(WIDTH, 2);
+ buf.putMetadata(HEIGHT, 2);
+ buf.putMetadata(SRC_X, 2);
+ buf.putMetadata(SRC_Y, 2);
+
+ renderer.handleData(buf, null);
+
+ data = ((DataBufferInt) canvas.getOfflineImage().getRaster().getDataBuffer()).getData();
+ String actualData = Arrays.toString(data);
+ String expectedData = Arrays.toString(pixelsAfterCopy);
+ if (!actualData.equals(expectedData))
+ System.err.println("Actual image: " + actualData + "\nExpected image: " + expectedData + ".");
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImagePixelsAdapter.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImagePixelsAdapter.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImagePixelsAdapter.java
new file mode 100644
index 0000000..95e7738
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImagePixelsAdapter.java
@@ -0,0 +1,147 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package common;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferInt;
+import java.util.Arrays;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Element;
+import streamer.Link;
+
+public class BufferedImagePixelsAdapter extends BaseElement {
+
+ public static final String TARGET_X = "x";
+ public static final String TARGET_Y = "y";
+ public static final String WIDTH = "width";
+ public static final String HEIGHT = "height";
+ public static final String RGB888LE32 = "RGB888LE32";
+ public static final String PIXEL_FORMAT = "pixel_format";
+
+ protected BufferedImageCanvas canvas;
+
+ public BufferedImagePixelsAdapter(String id, BufferedImageCanvas canvas) {
+ super(id);
+ this.canvas = canvas;
+ declarePads();
+ }
+
+ private void declarePads() {
+ inputPads.put(STDIN, null);
+ }
+
+ public String toString() {
+ return "Renderer(" + id + ")";
+ }
+
+ @Override
+ public void handleData(ByteBuffer buf, Link link) {
+ if (verbose)
+ System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+ int x = (Integer) buf.getMetadata(TARGET_X);
+ int y = (Integer) buf.getMetadata(TARGET_Y);
+ int rectWidth = (Integer) buf.getMetadata(WIDTH);
+ int rectHeight = (Integer) buf.getMetadata(HEIGHT);
+ String format = (String) buf.getMetadata(PIXEL_FORMAT);
+
+ int bpp;
+ // Support RGB888/32 little endian only
+ if (format != null && RGB888LE32.equals(format)) {
+ bpp = 4;
+ // TODO: support more formats
+ } else
+ throw new RuntimeException("Unsupported format: " + format + ". Supported formats: " + RGB888LE32 + ".");
+
+ int dataLength = rectWidth * rectHeight * bpp;
+ if (!cap(buf, dataLength, dataLength, link, false))
+ return;
+
+ // Draw rectangle on offline buffer
+ BufferedImage image = canvas.getOfflineImage();
+
+ DataBuffer dataBuf = image.getRaster().getDataBuffer();
+
+ switch (dataBuf.getDataType()) {
+
+ case DataBuffer.TYPE_INT: {
+
+ // Convert array of bytes to array of int's
+ int[] intArray = buf.toIntLEArray();
+
+ // We chose RGB888 model, so Raster will use DataBufferInt type
+ DataBufferInt dataBuffer = (DataBufferInt) dataBuf;
+
+ int imageWidth = image.getWidth();
+ int imageHeight = image.getHeight();
+
+ // Paint rectangle directly on buffer, line by line
+ int[] imageBuffer = dataBuffer.getData();
+
+ for (int srcLine = 0, dstLine = y; srcLine < rectHeight && dstLine < imageHeight; srcLine++, dstLine++) {
+ try {
+ System.arraycopy(intArray, srcLine * rectWidth, imageBuffer, x + dstLine * imageWidth, rectWidth);
+ } catch (IndexOutOfBoundsException e) {
+ }
+ }
+ break;
+ }
+
+ default:
+ throw new RuntimeException("Unsupported data buffer in buffered image: expected data buffer of type int (DataBufferInt). Actual data buffer type: "
+ + dataBuf.getClass().getSimpleName());
+ }
+
+ // Request update of repainted area
+ canvas.repaint(x, y, rectWidth, rectHeight);
+
+ buf.unref();
+ }
+
+ public static void main(String args[]) {
+ System.setProperty("streamer.Element.debug", "true");
+
+ BufferedImageCanvas canvas = new BufferedImageCanvas(4, 4);
+
+ Element renderer = new BufferedImagePixelsAdapter("renderer", canvas);
+
+ byte[] pixels = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+
+ int[] pixelsLE = new int[] { 0x04030201, 0x08070605, 0x0c0b0a09, 0x100f0e0d, 0x04030201, 0x08070605, 0x0c0b0a09, 0x100f0e0d, 0x04030201, 0x08070605,
+ 0x0c0b0a09, 0x100f0e0d, 0x04030201, 0x08070605, 0x0c0b0a09, 0x100f0e0d };
+
+ ByteBuffer buf = new ByteBuffer(pixels);
+ buf.putMetadata(TARGET_X, 0);
+ buf.putMetadata(TARGET_Y, 0);
+ buf.putMetadata(WIDTH, 4);
+ buf.putMetadata(HEIGHT, 4);
+ buf.putMetadata(PIXEL_FORMAT, RGB888LE32);
+
+ renderer.handleData(buf, null);
+
+ String actualData = Arrays.toString(((DataBufferInt) canvas.getOfflineImage().getRaster().getDataBuffer()).getData());
+ String expectedData = Arrays.toString(pixelsLE);
+ if (!actualData.equals(expectedData))
+ System.err.println("Actual image: " + actualData + "\nExpected image: " + expectedData + ".");
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/Client.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/Client.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/Client.java
new file mode 100644
index 0000000..343fe0a
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/Client.java
@@ -0,0 +1,137 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package common;
+
+import java.awt.Frame;
+import java.awt.ScrollPane;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.net.InetSocketAddress;
+
+import rdpclient.RdpClient;
+import streamer.Element;
+import streamer.Pipeline;
+import streamer.PipelineImpl;
+import streamer.SocketWrapper;
+import vncclient.VncClient;
+
+public class Client {
+
+ private static Frame frame;
+ private static SocketWrapper socket;
+ private static ScrollPane scroller;
+ private static ScreenDescription screen;
+ private static BufferedImageCanvas canvas;
+
+ public static void main(String args[]) {
+ // System.setProperty("streamer.Link.debug", "true");
+ // System.setProperty("streamer.Element.debug", "true");
+ // System.setProperty("streamer.Pipeline.debug", "true");
+
+ try {
+ if (args.length < 4) {
+ System.out.println("Usage: \n java common.Client vnc IP PORT PASSWORD\n java common.Client rdp IP PORT username\n");
+ System.exit(0);
+ }
+
+ String connectionType = args[0];
+ String hostname = args[1];
+ int port = Integer.parseInt(args[2]);
+ String userNameOrPassword = args[3];
+
+ // Create address from arguments
+ InetSocketAddress address = new InetSocketAddress(hostname, port);
+
+ // Create socket wrapper
+ socket = new SocketWrapper("socket");
+
+ screen = new ScreenDescription();
+ canvas = new BufferedImageCanvas(1024, 768);
+ screen.addSizeChangeListener(new SizeChangeListener() {
+ @Override
+ public void sizeChanged(int width, int height) {
+ if (canvas != null) {
+ canvas.setCanvasSize(width, height);
+ if (scroller != null)
+ scroller.setSize(canvas.getWidth(), canvas.getHeight());
+ }
+ }
+ });
+
+ // Assemble pipeline
+ Element main;
+ if ("vnc".equals(connectionType)) {
+ main = new VncClient("client", userNameOrPassword, screen, canvas);
+ } else if ("rdp".equals(connectionType)) {
+ main = new RdpClient("client", userNameOrPassword, screen, canvas);
+ } else {
+ throw new RuntimeException("Unknown connection type. Expected value: \"vnc\" or \"rdp\", actual value: \"" + connectionType + "\".");
+ }
+
+ Pipeline pipeline = new PipelineImpl("Client");
+ pipeline.add(socket, main);
+ pipeline.link("socket", main.getId(), "socket");
+
+ pipeline.validate();
+
+ frame = createVncClientMainWindow(canvas, "VNC", new WindowAdapter() {
+ public void windowClosing(WindowEvent evt) {
+ shutdown();
+ }
+ });
+
+ try {
+ // Connect socket to remote server and run main loop(s)
+ socket.connect(address);
+ } finally {
+ shutdown();
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace(System.err);
+ }
+ }
+
+ protected static void shutdown() {
+ if (frame != null) {
+ frame.setVisible(false);
+ frame.dispose();
+ }
+ if (socket != null)
+ socket.shutdown();
+ }
+
+ protected static Frame createVncClientMainWindow(BufferedImageCanvas canvas, String title, WindowListener windowListener) {
+ // Create AWT windows
+ Frame frame = new Frame(title + " - RDP");
+
+ // Use scrolling pane to support screens, which are larger than ours
+ scroller = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
+ scroller.add(canvas);
+ scroller.setSize(canvas.getWidth(), canvas.getHeight());
+
+ frame.add(scroller);
+ frame.pack();
+ frame.setVisible(true);
+
+ frame.addWindowListener(windowListener);
+
+ return frame;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/CopyRectOrder.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/CopyRectOrder.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/CopyRectOrder.java
new file mode 100644
index 0000000..5f0c0f7
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/CopyRectOrder.java
@@ -0,0 +1,39 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package common;
+
+
+import streamer.Order;
+
+public class CopyRectOrder extends Order {
+ public int srcX;
+ public int srcY;
+ public int width;
+ public int height;
+ public int x;
+ public int y;
+
+ public CopyRectOrder() {
+ type = OrderType.COPY_RECT;
+ }
+
+ @Override
+ public String toString() {
+ return "CopyRectOrder [srcX=" + srcX + ", srcY=" + srcY + ", width=" + width + ", height=" + height + ", x=" + x + ", y=" + y + "]";
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/KeyOrder.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/KeyOrder.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/KeyOrder.java
new file mode 100644
index 0000000..726d8a0
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/KeyOrder.java
@@ -0,0 +1,45 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package common;
+
+import java.awt.event.KeyEvent;
+
+import streamer.Order;
+
+public class KeyOrder extends Order {
+ public KeyOrder() {
+ type = "key event";
+ }
+
+ public KeyOrder(KeyEvent event, boolean pressed) {
+ type = "key event";
+
+ this.event = event;
+ this.pressed = pressed;
+ }
+
+ public KeyEvent event;
+
+ public boolean pressed;
+
+ @Override
+ public String toString() {
+ return "KeyOrder [event=" + event + ", pressed=" + pressed + "]";
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/MouseOrder.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/MouseOrder.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/MouseOrder.java
new file mode 100644
index 0000000..d6670fa
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/MouseOrder.java
@@ -0,0 +1,41 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package common;
+
+import java.awt.event.MouseEvent;
+
+import streamer.Order;
+
+public class MouseOrder extends Order {
+
+ public MouseOrder() {
+ type = "mouse order";
+ }
+
+ public MouseOrder(MouseEvent event) {
+ type = "mouse order";
+ this.event = event;
+ }
+
+ public MouseEvent event;
+ public boolean pressed;
+ public boolean released;
+ @Override
+ public String toString() {
+ return "MouseOrder [event=" + event + ", pressed=" + pressed + ", released=" + released + "]";
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/OrderType.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/OrderType.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/OrderType.java
new file mode 100644
index 0000000..1e77ea9
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/OrderType.java
@@ -0,0 +1,22 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package common;
+
+public enum OrderType {
+ BITMAP_UPDATE, COPY_RECT,
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/ScreenDescription.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/ScreenDescription.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/ScreenDescription.java
new file mode 100644
index 0000000..a01f22e
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/ScreenDescription.java
@@ -0,0 +1,168 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package common;
+
+import java.awt.image.IndexColorModel;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * VncScreenDescription - contains information about remote VNC screen.
+ */
+public class ScreenDescription {
+
+ protected Set<SizeChangeListener> sizeChangeListeners = new HashSet<SizeChangeListener>();
+
+ // Frame buffer size
+ protected int framebufferWidth = -1;
+ protected int framebufferHeight = -1;
+
+ // Desktop name
+ protected String desktopName = null;
+
+ // Bytes per pixel
+ protected int bytesPerPixel;
+ protected int colorDepth;
+ protected int bitsPerPixel;
+ protected int redShift;
+ protected int greenShift;
+ protected int blueShift;
+ protected int redMax;
+ protected int greenMax;
+ protected int blueMax;
+ protected boolean bigEndianFlag;
+ protected boolean trueColorFlag;
+
+ public IndexColorModel colorMap = null;
+
+ public ScreenDescription() {
+ }
+
+ /**
+ * Store information about server pixel format.
+ */
+ public void setPixelFormat(int bitsPerPixel, int depth, boolean bigEndianFlag, boolean trueColorFlag, int redMax, int greenMax, int blueMax, int redShift,
+ int greenShift, int blueShift) {
+
+ this.bytesPerPixel = (bitsPerPixel + 7) / 8;
+
+ this.bitsPerPixel = bitsPerPixel;
+ this.colorDepth = depth;
+ this.bigEndianFlag = bigEndianFlag;
+ this.trueColorFlag = trueColorFlag;
+
+ this.redMax = redMax;
+ this.greenMax = greenMax;
+ this.blueMax = blueMax;
+ this.redShift = redShift;
+ this.greenShift = greenShift;
+ this.blueShift = blueShift;
+ }
+
+ /**
+ * Store information about server pixel format.
+ */
+ public void setPixelFormatRGBTrueColor(int bitsPerPixel) {
+
+ switch(bitsPerPixel) {
+ case 8:
+ setPixelFormat(8, 8, false, false, -1, -1, -1, -1, -1, -1);
+ break;
+ case 15:
+ setPixelFormat(16, 15, false, true, 31, 31, 31, 0, 5, 10);
+ break;
+ case 16:
+ setPixelFormat(16, 16, false, true, 31, 63, 31, 0, 5, 11);
+ break;
+ case 24:
+ setPixelFormat(24, 24, false, true, 255, 255, 255, 0, 8, 16);
+ break;
+ case 32:
+ setPixelFormat(32, 24, false, true, 255, 255, 255, 0, 8, 16);
+ break;
+ default:
+ throw new RuntimeException("Unknown color depth.");
+ }
+
+ }
+
+ /**
+ * Store information about server screen size.
+ */
+ public void setFramebufferSize(int width, int height) {
+ if (height <= 0 || width <= 0)
+ throw new RuntimeException("Incorrect framebuffer size: " + width + "x" + height + ".");
+
+ this.framebufferWidth = width;
+ this.framebufferHeight = height;
+
+ callSizeChangeListeners(width, height);
+ }
+
+ protected void callSizeChangeListeners(int width, int height) {
+ for(SizeChangeListener listener:sizeChangeListeners) {
+ listener.sizeChanged(width, height);
+ }
+ }
+
+ /**
+ * Store server desktop name.
+ */
+ public void setDesktopName(String desktopName) {
+ this.desktopName = desktopName;
+ }
+
+ // Getters for variables, as usual
+
+ public String getDesktopName() {
+ return desktopName;
+ }
+
+ public int getBytesPerPixel() {
+ return bytesPerPixel;
+ }
+
+ public int getFramebufferHeight() {
+ return framebufferHeight;
+ }
+
+ public int getFramebufferWidth() {
+ return framebufferWidth;
+ }
+
+ public boolean isRGB888_32_LE() {
+ return (colorDepth == 24 && bitsPerPixel == 32 && redShift == 0 && greenShift == 8 && blueShift == 16 && redMax == 255 && greenMax == 255 && blueMax == 255
+ && !bigEndianFlag && trueColorFlag);
+ }
+
+ @Override
+ public String toString() {
+ return "ScreenDescription [framebufferWidth=" + framebufferWidth + ", framebufferHeight=" + framebufferHeight + ", desktopName=" + desktopName
+ + ", bytesPerPixel=" + bytesPerPixel + ", depth=" + colorDepth + ", bitsPerPixel=" + bitsPerPixel + ", redShift=" + redShift + ", greenShift=" + greenShift
+ + ", blueShift=" + blueShift + ", redMax=" + redMax + ", greenMax=" + greenMax + ", blueMax=" + blueMax + ", bigEndianFlag=" + bigEndianFlag
+ + ", trueColorFlag=" + trueColorFlag + "]";
+ }
+
+ public void addSizeChangeListener(SizeChangeListener sizeChangeListener) {
+ sizeChangeListeners.add(sizeChangeListener);
+ }
+
+ public int getColorDeph() {
+ return colorDepth;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/SizeChangeListener.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/SizeChangeListener.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/SizeChangeListener.java
new file mode 100644
index 0000000..d658d1b
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/SizeChangeListener.java
@@ -0,0 +1,22 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package common;
+
+public interface SizeChangeListener {
+
+ public void sizeChanged(int width, int height);
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpKeyboardAdapter.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpKeyboardAdapter.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpKeyboardAdapter.java
new file mode 100644
index 0000000..f19f09c
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpKeyboardAdapter.java
@@ -0,0 +1,351 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package rdpclient;
+
+import java.awt.event.KeyEvent;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Link;
+
+import common.KeyOrder;
+
+public class AwtRdpKeyboardAdapter extends BaseElement {
+
+ /**
+ * Absence of this flag indicates a key-down event, while its presence
+ * indicates a key-release event.
+ */
+ public static final int FASTPATH_INPUT_KBDFLAGS_RELEASE = 0x01;
+
+ /**
+ * Keystroke message contains an extended scancode. For enhanced 101-key and
+ * 102-key keyboards, extended keys include the right ALT and right CTRL keys
+ * on the main section of the keyboard; the INS, DEL, HOME, END, PAGE UP, PAGE
+ * DOWN and ARROW keys in the clusters to the left of the numeric keypad; and
+ * the Divide ("/") and ENTER keys in the numeric keypad.
+ */
+ public static final int FASTPATH_INPUT_KBDFLAGS_EXTENDED = 0x02;
+
+ public static final int FASTPATH_INPUT_EVENT_SCANCODE = 0;
+
+ public AwtRdpKeyboardAdapter(String id) {
+ super(id);
+ }
+
+ @Override
+ public void handleData(ByteBuffer buf, Link link) {
+ if (verbose)
+ System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+ KeyOrder order = (KeyOrder) buf.getOrder();
+ buf.unref();
+
+ ByteBuffer outBuf = new ByteBuffer(2, true);
+
+ int scanCode = map_en_us(order.event);
+
+ // eventHeader (1 byte): An 8-bit, unsigned integer. The format of this
+ // field is the same as the eventHeader byte field described in section
+ // 2.2.8.1.2.2. The eventCode bitfield (3 bits in size) MUST be set to
+ // FASTPATH_INPUT_EVENT_SCANCODE (0). The eventFlags bitfield (5 bits in
+ // size) contains flags describing the keyboard event.
+ outBuf.writeByte((scanCode >> 8) | (FASTPATH_INPUT_EVENT_SCANCODE << 5) | ((order.pressed) ? 0 : FASTPATH_INPUT_KBDFLAGS_RELEASE));
+
+ // keyCode (1 byte): An 8-bit, unsigned integer. The scancode of the key
+ // which triggered the event.
+ outBuf.writeByte(scanCode);
+
+ // Push buffer to one pad only, so it can be modified without copying of
+ // data
+ pushDataToPad(STDOUT, outBuf);
+ }
+
+ /**
+ * Return key scan code (in lower byte) and extended flags (in second byte).
+ */
+ private int map_en_us(KeyEvent event) {
+ // Also set extended key flag when necessary.
+ // For enhanced 101-key and 102-key keyboards, extended keys include the
+ // right ALT and right CTRL keys on the main section of the keyboard; the
+ // INS, DEL, HOME, END, PAGE UP, PAGE DOWN and ARROW keys in the clusters to
+ // the left of the numeric keypad; and the Divide ("/") and ENTER keys in
+ // the numeric keypad.
+
+ switch (event.getKeyCode()) {
+ // Functional keys
+ case KeyEvent.VK_ESCAPE:
+ return 1;
+ case KeyEvent.VK_F1:
+ return 59;
+ case KeyEvent.VK_F2:
+ return 60;
+ case KeyEvent.VK_F3:
+ return 61;
+ case KeyEvent.VK_F4:
+ return 62;
+ case KeyEvent.VK_F5:
+ return 63;
+ case KeyEvent.VK_F6:
+ return 64;
+ case KeyEvent.VK_F7:
+ return 65;
+ case KeyEvent.VK_F8:
+ return 66;
+ case KeyEvent.VK_F9:
+ return 67;
+ case KeyEvent.VK_F10:
+ return 68;
+ case KeyEvent.VK_F11:
+ return 87;
+ case KeyEvent.VK_F12:
+ return 88;
+
+ // Row #1
+ case KeyEvent.VK_BACK_QUOTE:
+ return 41;
+ case KeyEvent.VK_1:
+ return 2;
+ case KeyEvent.VK_2:
+ return 3;
+ case KeyEvent.VK_3:
+ return 4;
+ case KeyEvent.VK_4:
+ return 5;
+ case KeyEvent.VK_5:
+ return 6;
+ case KeyEvent.VK_6:
+ return 7;
+ case KeyEvent.VK_7:
+ return 8;
+ case KeyEvent.VK_8:
+ return 9;
+ case KeyEvent.VK_9:
+ return 10;
+ case KeyEvent.VK_0:
+ return 11;
+ case KeyEvent.VK_MINUS:
+ return 12;
+ case KeyEvent.VK_EQUALS:
+ return 13;
+ case KeyEvent.VK_BACK_SPACE:
+ return 14;
+
+ // Row #2
+ case KeyEvent.VK_TAB:
+ return 15;
+ case KeyEvent.VK_Q:
+ return 16;
+ case KeyEvent.VK_W:
+ return 17;
+ case KeyEvent.VK_E:
+ return 18;
+ case KeyEvent.VK_R:
+ return 19;
+ case KeyEvent.VK_T:
+ return 20;
+ case KeyEvent.VK_Y:
+ return 21;
+ case KeyEvent.VK_U:
+ return 22;
+ case KeyEvent.VK_I:
+ return 23;
+ case KeyEvent.VK_O:
+ return 24;
+ case KeyEvent.VK_P:
+ return 25;
+ case KeyEvent.VK_OPEN_BRACKET:
+ return 26;
+ case KeyEvent.VK_CLOSE_BRACKET:
+ return 27;
+ case KeyEvent.VK_ENTER:
+ switch (event.getKeyLocation()) {
+ default:
+ case KeyEvent.KEY_LOCATION_STANDARD:
+ return 28;
+ case KeyEvent.KEY_LOCATION_NUMPAD:
+ return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 28;
+ }
+
+ // Row #3
+ case KeyEvent.VK_CAPS_LOCK:
+ return 58;
+ case KeyEvent.VK_A:
+ return 30;
+ case KeyEvent.VK_S:
+ return 31;
+ case KeyEvent.VK_D:
+ return 32;
+ case KeyEvent.VK_F:
+ return 33;
+ case KeyEvent.VK_G:
+ return 34;
+ case KeyEvent.VK_H:
+ return 35;
+ case KeyEvent.VK_J:
+ return 36;
+ case KeyEvent.VK_K:
+ return 37;
+ case KeyEvent.VK_L:
+ return 38;
+ case KeyEvent.VK_SEMICOLON:
+ return 39;
+ case KeyEvent.VK_QUOTE:
+ return 40;
+
+ // Row #4
+ case KeyEvent.VK_SHIFT:
+ switch (event.getKeyLocation()) {
+ default:
+ case KeyEvent.KEY_LOCATION_LEFT:
+ return 42;
+ case KeyEvent.KEY_LOCATION_RIGHT:
+ return 54;
+ }
+ case KeyEvent.VK_BACK_SLASH:
+ return 43;
+ case KeyEvent.VK_Z:
+ return 44;
+ case KeyEvent.VK_X:
+ return 45;
+ case KeyEvent.VK_C:
+ return 46;
+ case KeyEvent.VK_V:
+ return 47;
+ case KeyEvent.VK_B:
+ return 48;
+ case KeyEvent.VK_N:
+ return 49;
+ case KeyEvent.VK_M:
+ return 50;
+ case KeyEvent.VK_COMMA:
+ return 51;
+ case KeyEvent.VK_PERIOD:
+ return 52;
+ case KeyEvent.VK_SLASH:
+ return 53;
+
+ //
+ // Bottom row
+ case KeyEvent.VK_CONTROL:
+ switch (event.getKeyLocation()) {
+ default:
+ case KeyEvent.KEY_LOCATION_LEFT:
+ return 29;
+ case KeyEvent.KEY_LOCATION_RIGHT:
+ return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 29;
+ }
+ case KeyEvent.VK_WINDOWS:
+ switch (event.getKeyLocation()) {
+ default:
+ case KeyEvent.KEY_LOCATION_LEFT:
+ return 91;
+ case KeyEvent.KEY_LOCATION_RIGHT:
+ return 92;
+ }
+ case KeyEvent.VK_ALT:
+ switch (event.getKeyLocation()) {
+ default:
+ case KeyEvent.KEY_LOCATION_LEFT:
+ return 56;
+ case KeyEvent.KEY_LOCATION_RIGHT:
+ return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 56;
+ }
+ case KeyEvent.VK_ALT_GRAPH:
+ return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 56;
+
+ case KeyEvent.VK_SPACE:
+ return 57;
+
+ case KeyEvent.VK_CONTEXT_MENU:
+ return 93;
+
+ //
+ // Special keys
+ case KeyEvent.VK_PRINTSCREEN:
+ return 55;
+ case KeyEvent.VK_SCROLL_LOCK:
+ return 70;
+ case KeyEvent.VK_PAUSE:
+ return 29;
+
+ // Text navigation keys
+ case KeyEvent.VK_INSERT:
+ return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 82;
+ case KeyEvent.VK_HOME:
+ return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 71;
+ case KeyEvent.VK_PAGE_UP:
+ return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 73;
+ case KeyEvent.VK_DELETE:
+ return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 83;
+ case KeyEvent.VK_END:
+ return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 79;
+ case KeyEvent.VK_PAGE_DOWN:
+ return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 81;
+
+ // Cursor keys
+ case KeyEvent.VK_UP:
+ return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 72;
+ case KeyEvent.VK_LEFT:
+ return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 75;
+ case KeyEvent.VK_DOWN:
+ return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 80;
+ case KeyEvent.VK_RIGHT:
+ return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 77;
+
+ // Keypad
+ case KeyEvent.VK_NUM_LOCK:
+ return 69;
+ case KeyEvent.VK_DIVIDE:
+ return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 53;
+ case KeyEvent.VK_MULTIPLY:
+ return 55;
+ case KeyEvent.VK_SUBTRACT:
+ return 74;
+ case KeyEvent.VK_ADD:
+ return 78;
+
+ case KeyEvent.VK_NUMPAD7:
+ return 71;
+ case KeyEvent.VK_NUMPAD8:
+ return 72;
+ case KeyEvent.VK_NUMPAD9:
+ return 73;
+ case KeyEvent.VK_NUMPAD4:
+ return 75;
+ case KeyEvent.VK_NUMPAD5:
+ return 76;
+ case KeyEvent.VK_NUMPAD6:
+ return 77;
+ case KeyEvent.VK_NUMPAD1:
+ return 79;
+ case KeyEvent.VK_NUMPAD2:
+ return 80;
+ case KeyEvent.VK_NUMPAD3:
+ return 81;
+ case KeyEvent.VK_NUMPAD0:
+ return 82;
+ case KeyEvent.VK_DECIMAL:
+ return 83;
+
+ default:
+ System.err.println("Key is not mapped: " + event + ".");
+ return 57; // Space
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpMouseAdapter.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpMouseAdapter.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpMouseAdapter.java
new file mode 100644
index 0000000..371bffc
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpMouseAdapter.java
@@ -0,0 +1,180 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package rdpclient;
+
+import java.awt.event.MouseEvent;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Link;
+
+import common.MouseOrder;
+
+/**
+ * @see http://msdn.microsoft.com/en-us/library/cc240594.aspx
+ */
+public class AwtRdpMouseAdapter extends BaseElement {
+ public static int FASTPATH_INPUT_EVENT_MOUSE = 0x01;
+
+ /**
+ * Event is a mouse wheel rotation. The only valid flags in a wheel rotation
+ * event are PTRFLAGS_WHEEL_NEGATIVE and the WheelRotationMask; all other
+ * pointer flags are ignored.
+ */
+ public static int PTRFLAGS_WHEEL = 0x0200;
+
+ /**
+ * Wheel rotation value (contained in the WheelRotationMask bit field) is
+ * negative and MUST be sign-extended before injection at the server.
+ */
+ public static int PTRFLAGS_WHEEL_NEGATIVE = 0x0100;
+
+ /**
+ * Bit field describing the number of rotation units the mouse wheel was
+ * rotated. The value is negative if the PTRFLAGS_WHEEL_NEGATIVE flag is set.
+ */
+ public static int WHEEL_ROTATION_MASK = 0x01FF;
+
+ /**
+ * Indicates that the mouse position MUST be updated to the location specified
+ * by the xPos and yPos fields.
+ */
+ public static int PTRFLAGS_MOVE = 0x0800;
+
+ /**
+ * Indicates that a click event has occurred at the position specified by the
+ * xPos and yPos fields. The button flags indicate which button has been
+ * clicked and at least one of these flags MUST be set.
+ */
+ public static int PTRFLAGS_DOWN = 0x8000;
+
+ /**
+ * Mouse button 1 (left button) was clicked or released. If the PTRFLAGS_DOWN
+ * flag is set, then the button was clicked, otherwise it was released.
+ */
+ public static int PTRFLAGS_BUTTON1 = 0x1000;
+
+ /**
+ * Mouse button 2 (right button) was clicked or released. If the PTRFLAGS_DOWN
+ * flag is set, then the button was clicked, otherwise it was released.
+ */
+ public static int PTRFLAGS_BUTTON2 = 0x2000;
+
+ /**
+ * Mouse button 3 (middle button or wheel) was clicked or released. If the
+ * PTRFLAGS_DOWN flag is set, then the button was clicked, otherwise it was
+ * released.
+ */
+ public static int PTRFLAGS_BUTTON3 = 0x4000;
+
+ public AwtRdpMouseAdapter(String id) {
+ super(id);
+ }
+
+ @Override
+ public void handleData(ByteBuffer buf, Link link) {
+ if (verbose)
+ System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+ // Get mouse event
+ MouseOrder order = (MouseOrder) buf.getOrder();
+
+ ByteBuffer outBuf = new ByteBuffer(7, true);
+
+ // eventHeader (1 byte): An 8-bit, unsigned integer. EventCode bitfield (top
+ // 3 bits) MUST be set to FASTPATH_INPUT_EVENT_MOUSE (1). The
+ // eventFlags bitfield (low 5 bits) MUST be zeroed out.
+ outBuf.writeByte(FASTPATH_INPUT_EVENT_MOUSE << 5);
+
+ // pointerFlags (2 bytes): A 16-bit, unsigned integer.
+ outBuf.writeShortLE(getPointerFlags(order));
+
+ // xPos (2 bytes): A 16-bit, unsigned integer. The x-coordinate of the
+ // pointer.
+ outBuf.writeShortLE(order.event.getX());
+
+ // yPos (2 bytes): A 16-bit, unsigned integer. The y-coordinate of the
+ // pointer.
+ outBuf.writeShortLE(order.event.getY());
+
+ // Push buffer to one pad only, so it can be modified without copying of
+ // data
+ pushDataToPad(STDOUT, outBuf);
+ }
+
+ // Remember mouse buttons
+ protected boolean button1, button2, button3;
+
+ protected int getPointerFlags(MouseOrder order) {
+ int flags = 0;
+
+ int modifiers = order.event.getModifiersEx();
+
+ if (order.pressed) {
+ // Mouse pressed
+ flags |= PTRFLAGS_DOWN;
+
+ // Check, which one of buttons is released
+ boolean b1 = ((modifiers & MouseEvent.BUTTON1_DOWN_MASK) > 0) && !button1;
+ boolean b2 = ((modifiers & MouseEvent.BUTTON2_DOWN_MASK) > 0) && !button2;
+ boolean b3 = ((modifiers & MouseEvent.BUTTON3_DOWN_MASK) > 0) && !button3;
+
+ if (b1) {
+ flags |= PTRFLAGS_BUTTON1;
+ button1 = true;
+ }
+
+ if (b2) {
+ flags |= PTRFLAGS_BUTTON3;
+ button2 = true;
+ }
+
+ if (b3) {
+ flags |= PTRFLAGS_BUTTON2;
+ button3 = true;
+ }
+ } else if (order.released) {
+ // Mouse released
+
+ // Check, which one of buttons is released
+ boolean b1 = !((modifiers & MouseEvent.BUTTON1_DOWN_MASK) > 0) && button1;
+ boolean b2 = !((modifiers & MouseEvent.BUTTON2_DOWN_MASK) > 0) && button2;
+ boolean b3 = !((modifiers & MouseEvent.BUTTON3_DOWN_MASK) > 0) && button3;
+
+ if (b1) {
+ flags |= PTRFLAGS_BUTTON1;
+ button1 = false;
+ }
+
+ if (b2) {
+ flags |= PTRFLAGS_BUTTON3;
+ button2 = false;
+ }
+
+ if (b3) {
+ flags |= PTRFLAGS_BUTTON2;
+ button3 = false;
+ }
+ } else {
+ // Mouse moved
+ flags |= PTRFLAGS_MOVE;
+ }
+
+ return flags;
+ }
+
+}