/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
+ * Copyright (C) 2011-2013 D. R. Commander. All Rights Reserved.
* Copyright (C) 2011-2013 Brian P. Hinz
- *
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
////////////////////////////////////////////////////////////////////
// The following methods are all called from the RFB thread
- public CConn(VncViewer viewer_, Socket sock_,
+ public CConn(VncViewer viewer_, Socket sock_,
String vncServerName)
{
serverHost = null; serverPort = 0; sock = sock_; viewer = viewer_;
options = new OptionsDialog(this);
options.initDialog();
clipboardDialog = new ClipboardDialog(this);
- firstUpdate = true; pendingUpdate = false; continuousUpdates = false;
+ firstUpdate = true; pendingUpdate = false; continuousUpdates = false;
forceNonincremental = true; supportsSyncFence = false;
-
setShared(viewer.shared.getValue());
upg = this;
if (sock != null) {
String name = sock.getPeerEndpoint();
- vlog.info("Accepted connection from "+name);
+ vlog.info("Accepted connection from " + name);
} else {
if (vncServerName != null &&
!viewer.alwaysShowServerDialog.getValue()) {
if (supportsSyncFence)
requestNewUpdate();
}
-
public boolean showMsgBox(int flags, String title, String text)
{
if (viewport != null)
viewport.dispose();
viewport = null;
- }
+ }
// blockCallback() is called when reading from the socket would block.
public void blockCallback() {
} catch (java.lang.InterruptedException e) {
throw new Exception(e.getMessage());
}
- }
+ }
// getUserPasswd() is called by the CSecurity object when it needs us to read
// a password from the user.
} catch(IOException e) {
throw new Exception("Failed to read VncPasswd file");
}
- String PlainPasswd =
- VncAuth.unobfuscatePasswd(obfPwd);
+ String PlainPasswd = VncAuth.unobfuscatePasswd(obfPwd);
passwd.append(PlainPasswd);
passwd.setLength(PlainPasswd.length());
return true;
// setDesktopSize() is called when the desktop size changes (including when
// it is set initially).
public void setDesktopSize(int w, int h) {
- super.setDesktopSize(w,h);
+ super.setDesktopSize(w, h);
resizeFramebuffer();
}
if ((reason == screenTypes.reasonClient) &&
(result != screenTypes.resultSuccess)) {
- vlog.error("SetDesktopSize failed: "+result);
+ vlog.error("SetDesktopSize failed: " + result);
return;
}
}
// clientRedirect() migrates the client to another host/port
- public void clientRedirect(int port, String host,
+ public void clientRedirect(int port, String host,
String x509subject) {
try {
sock.close();
{
// can't call super.super.fence(flags, len, data);
cp.supportsFence = true;
-
+
if ((flags & fenceTypes.fenceFlagRequest) != 0) {
// We handle everything synchronously so we trivially honor these modes
flags = flags & (fenceTypes.fenceFlagBlockBefore | fenceTypes.fenceFlagBlockAfter);
-
+
writer().writeFence(flags, len, data);
return;
}
-
+
if (len == 0) {
// Initial probe
if ((flags & fenceTypes.fenceFlagSyncNext) != 0) {
supportsSyncFence = true;
-
+
if (cp.supportsContinuousUpdates) {
vlog.info("Enabling continuous updates");
continuousUpdates = true;
// Pixel format change
MemInStream memStream = new MemInStream(data, 0, len);
PixelFormat pf = new PixelFormat();
-
+
pf.read(memStream);
-
+
desktop.setServerPF(pf);
cp.setPF(pf);
}
// get the response back. That way we will be synchronised with
// when the server switches.
MemOutStream memStream = new MemOutStream();
-
+
pf.write(memStream);
-
+
writer().writeFence(fenceTypes.fenceFlagRequest | fenceTypes.fenceFlagSyncNext,
memStream.length(), (byte[])memStream.data());
} else {
}
String str = pf.print();
- vlog.info("Using pixel format "+str);
+ vlog.info("Using pixel format " + str);
writer().writeSetPixelFormat(pf);
formatChange = false;
if (forceNonincremental || !continuousUpdates) {
pendingUpdate = true;
- writer().writeFramebufferUpdateRequest(new Rect(0,0,cp.width,cp.height),
+ writer().writeFramebufferUpdateRequest(new Rect(0, 0, cp.width, cp.height),
!forceNonincremental);
}
if (desktop != null)
desktop.resetLocalCursor();
}
-
+
checkEncodings();
-
+
if (state() != RFBSTATE_NORMAL) {
/* Process security types which don't use encryption */
if (options.encNone.isSelected()) {
// writeClientCutText() is called from the clipboard dialog
public void writeClientCutText(String str, int len) {
- if (state() != RFBSTATE_NORMAL) return;
- writer().writeClientCutText(str,len);
+ if (state() != RFBSTATE_NORMAL || shuttingDown)
+ return;
+ writer().writeClientCutText(str, len);
}
public void writeKeyEvent(int keysym, boolean down) {
- if (state() != RFBSTATE_NORMAL) return;
+ if (state() != RFBSTATE_NORMAL || shuttingDown)
+ return;
writer().writeKeyEvent(keysym, down);
}
public void writeKeyEvent(KeyEvent ev) {
- if (ev.getID() != KeyEvent.KEY_PRESSED && !ev.isActionKey())
+ int keysym = 0, keycode, key, location, fakeModifiers = 0;
+
+ if (shuttingDown)
return;
- int keysym, keycode, currentModifiers;
+ boolean down = (ev.getID() == KeyEvent.KEY_PRESSED);
- currentModifiers = ev.getModifiers();
keycode = ev.getKeyCode();
+ key = ev.getKeyChar();
+ location = ev.getKeyLocation();
- if (!ev.isActionKey()) {
- vlog.debug("key press "+ev.getKeyChar());
- if (ev.getKeyChar() < 32) {
- // if the ctrl modifier key is down, send the equivalent ASCII since we
- // will send the ctrl modifier anyway
-
- if ((currentModifiers & KeyEvent.CTRL_MASK) != 0) {
- if ((currentModifiers & KeyEvent.SHIFT_MASK) != 0) {
- keysym = ev.getKeyChar() + 64;
- if (keysym == -1)
- return;
- } else {
- keysym = ev.getKeyChar() + 96;
- if (keysym == 127) keysym = 95;
- }
- } else {
- switch (keycode) {
- case KeyEvent.VK_BACK_SPACE: keysym = Keysyms.BackSpace; break;
- case KeyEvent.VK_TAB: keysym = Keysyms.Tab; break;
- case KeyEvent.VK_ENTER: keysym = Keysyms.Return; break;
- case KeyEvent.VK_ESCAPE: keysym = Keysyms.Escape; break;
- default: return;
- }
- }
+ vlog.debug((ev.isActionKey() ? "action " : "") + "key " +
+ (down ? "PRESS" : "release") + " code " + keycode +
+ " location " + location + " ASCII " + key);
- } else if (ev.getKeyChar() == 127) {
- keysym = Keysyms.Delete;
+ if (!ev.isActionKey()) {
+ if (keycode >= KeyEvent.VK_0 && keycode <= KeyEvent.VK_9 &&
+ location == KeyEvent.KEY_LOCATION_NUMPAD)
+ keysym = Keysyms.KP_0 + keycode - KeyEvent.VK_0;
- } else {
- keysym = UnicodeToKeysym.translate(ev.getKeyChar());
+ switch (keycode) {
+ case KeyEvent.VK_BACK_SPACE: keysym = Keysyms.BackSpace; break;
+ case KeyEvent.VK_TAB: keysym = Keysyms.Tab; break;
+ case KeyEvent.VK_ENTER:
+ if (location == KeyEvent.KEY_LOCATION_NUMPAD)
+ keysym = Keysyms.KP_Enter;
+ else
+ keysym = Keysyms.Return; break;
+ case KeyEvent.VK_ESCAPE: keysym = Keysyms.Escape; break;
+ case KeyEvent.VK_NUMPAD0: keysym = Keysyms.KP_0; break;
+ case KeyEvent.VK_NUMPAD1: keysym = Keysyms.KP_1; break;
+ case KeyEvent.VK_NUMPAD2: keysym = Keysyms.KP_2; break;
+ case KeyEvent.VK_NUMPAD3: keysym = Keysyms.KP_3; break;
+ case KeyEvent.VK_NUMPAD4: keysym = Keysyms.KP_4; break;
+ case KeyEvent.VK_NUMPAD5: keysym = Keysyms.KP_5; break;
+ case KeyEvent.VK_NUMPAD6: keysym = Keysyms.KP_6; break;
+ case KeyEvent.VK_NUMPAD7: keysym = Keysyms.KP_7; break;
+ case KeyEvent.VK_NUMPAD8: keysym = Keysyms.KP_8; break;
+ case KeyEvent.VK_NUMPAD9: keysym = Keysyms.KP_9; break;
+ case KeyEvent.VK_DECIMAL: keysym = Keysyms.KP_Decimal; break;
+ case KeyEvent.VK_ADD: keysym = Keysyms.KP_Add; break;
+ case KeyEvent.VK_SUBTRACT: keysym = Keysyms.KP_Subtract; break;
+ case KeyEvent.VK_MULTIPLY: keysym = Keysyms.KP_Multiply; break;
+ case KeyEvent.VK_DIVIDE: keysym = Keysyms.KP_Divide; break;
+ case KeyEvent.VK_DELETE:
+ if (location == KeyEvent.KEY_LOCATION_NUMPAD)
+ keysym = Keysyms.KP_Delete;
+ else
+ keysym = Keysyms.Delete; break;
+ case KeyEvent.VK_CLEAR:
+ if (location == KeyEvent.KEY_LOCATION_NUMPAD)
+ keysym = Keysyms.KP_Begin;
+ else
+ keysym = Keysyms.Clear; break;
+ case KeyEvent.VK_CONTROL:
+ if (down)
+ modifiers |= Event.CTRL_MASK;
+ else
+ modifiers &= ~Event.CTRL_MASK;
+ if (location == KeyEvent.KEY_LOCATION_RIGHT)
+ keysym = Keysyms.Control_R;
+ else
+ keysym = Keysyms.Control_L; break;
+ case KeyEvent.VK_ALT:
+ if (down)
+ modifiers |= Event.ALT_MASK;
+ else
+ modifiers &= ~Event.ALT_MASK;
+ if (location == KeyEvent.KEY_LOCATION_RIGHT)
+ keysym = Keysyms.Alt_R;
+ else
+ keysym = Keysyms.Alt_L; break;
+ case KeyEvent.VK_SHIFT:
+ if (down)
+ modifiers |= Event.SHIFT_MASK;
+ else
+ modifiers &= ~Event.SHIFT_MASK;
+ if (location == KeyEvent.KEY_LOCATION_RIGHT)
+ keysym = Keysyms.Shift_R;
+ else
+ keysym = Keysyms.Shift_L; break;
+ case KeyEvent.VK_META:
+ if (down)
+ modifiers |= Event.META_MASK;
+ else
+ modifiers &= ~Event.META_MASK;
+ if (location == KeyEvent.KEY_LOCATION_RIGHT)
+ keysym = Keysyms.Meta_R;
+ else
+ keysym = Keysyms.Meta_L; break;
+ default:
+ if (ev.isControlDown() && ev.isAltDown()) {
+ // Handle AltGr key on international keyboards
+ if ((keycode >= 32 && keycode <= 126) ||
+ (keycode >= 160 && keycode <= 255))
+ key = keycode;
+ fakeModifiers |= Event.ALT_MASK | Event.CTRL_MASK;
+ } else if (ev.isControlDown()) {
+ // For CTRL-<letter>, CTRL is sent separately, so just send <letter>.
+ if ((key >= 1 && key <= 26 && !ev.isShiftDown()) ||
+ // CTRL-{, CTRL-|, CTRL-} also map to ASCII 96-127
+ (key >= 27 && key <= 29 && ev.isShiftDown()))
+ key += 96;
+ // For CTRL-SHIFT-<letter>, send capital <letter> to emulate behavior
+ // of Linux. For CTRL-@, send @. For CTRL-_, send _. For CTRL-^,
+ // send ^.
+ else if (key < 32)
+ key += 64;
+ // Windows and Mac sometimes return CHAR_UNDEFINED with CTRL-SHIFT
+ // combinations, so best we can do is send the key code if it is
+ // a valid ASCII symbol.
+ else if (key == KeyEvent.CHAR_UNDEFINED && keycode >= 0 &&
+ keycode <= 127)
+ key = keycode;
+ }
+ keysym = UnicodeToKeysym.translate(key);
if (keysym == -1)
return;
-
- // Windows 7 or some Java version send key events that require the
- // following special treatment with the German Alt-Gr Key. They send
- // ALT + CTRL before the normal key event. They should be suppressed
- if ((currentModifiers & KeyEvent.CTRL_MASK) != 0
- && (currentModifiers & KeyEvent.ALT_MASK) != 0
- && ((keysym == 0x5c) || (keysym == 0x7c) // backslash bar
- || (keysym == 0x5b) || (keysym == 0x5d) // [ ]
- || (keysym == 0x7b) || (keysym == 0x7d) // { }
- || (keysym == 0x7e) || (keysym == 0x40) // ~ @
- || (keysym == 0x20ac) || (keysym == 0xb5) // Euro Micro
- || (keysym == 0xb2) || (keysym == 0xb3)) // ^2 ^3
- )
- currentModifiers &= (~ KeyEvent.CTRL_MASK) & (~ KeyEvent.ALT_MASK);
}
-
} else {
// KEY_ACTION
- vlog.debug("key action " + keycode);
switch (keycode) {
- case KeyEvent.VK_HOME: keysym = Keysyms.Home; break;
- case KeyEvent.VK_END: keysym = Keysyms.End; break;
- case KeyEvent.VK_PAGE_UP: keysym = Keysyms.Page_Up; break;
- case KeyEvent.VK_PAGE_DOWN: keysym = Keysyms.Page_Down; break;
- case KeyEvent.VK_UP: keysym = Keysyms.Up; break;
- case KeyEvent.VK_DOWN: keysym = Keysyms.Down; break;
- case KeyEvent.VK_LEFT: keysym = Keysyms.Left; break;
- case KeyEvent.VK_RIGHT: keysym = Keysyms.Right; break;
+ case KeyEvent.VK_HOME:
+ if (location == KeyEvent.KEY_LOCATION_NUMPAD)
+ keysym = Keysyms.KP_Home;
+ else
+ keysym = Keysyms.Home; break;
+ case KeyEvent.VK_END:
+ if (location == KeyEvent.KEY_LOCATION_NUMPAD)
+ keysym = Keysyms.KP_End;
+ else
+ keysym = Keysyms.End; break;
+ case KeyEvent.VK_PAGE_UP:
+ if (location == KeyEvent.KEY_LOCATION_NUMPAD)
+ keysym = Keysyms.KP_Page_Up;
+ else
+ keysym = Keysyms.Page_Up; break;
+ case KeyEvent.VK_PAGE_DOWN:
+ if (location == KeyEvent.KEY_LOCATION_NUMPAD)
+ keysym = Keysyms.KP_Page_Down;
+ else
+ keysym = Keysyms.Page_Down; break;
+ case KeyEvent.VK_UP:
+ if (location == KeyEvent.KEY_LOCATION_NUMPAD)
+ keysym = Keysyms.KP_Up;
+ else
+ keysym = Keysyms.Up; break;
+ case KeyEvent.VK_DOWN:
+ if (location == KeyEvent.KEY_LOCATION_NUMPAD)
+ keysym = Keysyms.KP_Down;
+ else
+ keysym = Keysyms.Down; break;
+ case KeyEvent.VK_LEFT:
+ if (location == KeyEvent.KEY_LOCATION_NUMPAD)
+ keysym = Keysyms.KP_Left;
+ else
+ keysym = Keysyms.Left; break;
+ case KeyEvent.VK_RIGHT:
+ if (location == KeyEvent.KEY_LOCATION_NUMPAD)
+ keysym = Keysyms.KP_Right;
+ else
+ keysym = Keysyms.Right; break;
case KeyEvent.VK_F1: keysym = Keysyms.F1; break;
case KeyEvent.VK_F2: keysym = Keysyms.F2; break;
case KeyEvent.VK_F3: keysym = Keysyms.F3; break;
case KeyEvent.VK_F10: keysym = Keysyms.F10; break;
case KeyEvent.VK_F11: keysym = Keysyms.F11; break;
case KeyEvent.VK_F12: keysym = Keysyms.F12; break;
+ case KeyEvent.VK_F13: keysym = Keysyms.F13; break;
case KeyEvent.VK_PRINTSCREEN: keysym = Keysyms.Print; break;
- case KeyEvent.VK_PAUSE: keysym = Keysyms.Pause; break;
- case KeyEvent.VK_INSERT: keysym = Keysyms.Insert; break;
+ case KeyEvent.VK_PAUSE:
+ if (ev.isControlDown())
+ keysym = Keysyms.Break;
+ else
+ keysym = Keysyms.Pause;
+ break;
+ case KeyEvent.VK_INSERT:
+ if (location == KeyEvent.KEY_LOCATION_NUMPAD)
+ keysym = Keysyms.KP_Insert;
+ else
+ keysym = Keysyms.Insert; break;
+ case KeyEvent.VK_KP_DOWN: keysym = Keysyms.KP_Down; break;
+ case KeyEvent.VK_KP_LEFT: keysym = Keysyms.KP_Left; break;
+ case KeyEvent.VK_KP_RIGHT: keysym = Keysyms.KP_Right; break;
+ case KeyEvent.VK_KP_UP: keysym = Keysyms.KP_Up; break;
+ case KeyEvent.VK_NUM_LOCK: keysym = Keysyms.Num_Lock; break;
+ case KeyEvent.VK_WINDOWS: keysym = Keysyms.Super_L; break;
+ case KeyEvent.VK_CONTEXT_MENU: keysym = Keysyms.Menu; break;
+ case KeyEvent.VK_SCROLL_LOCK: keysym = Keysyms.Scroll_Lock; break;
+ case KeyEvent.VK_CAPS_LOCK: keysym = Keysyms.Caps_Lock; break;
+ case KeyEvent.VK_BEGIN:
+ if (location == KeyEvent.KEY_LOCATION_NUMPAD)
+ keysym = Keysyms.KP_Begin;
+ else
+ keysym = Keysyms.Begin; break;
default: return;
}
}
- writeModifiers(currentModifiers);
- writeKeyEvent(keysym, true);
- writeKeyEvent(keysym, false);
- writeModifiers(0);
+ if (fakeModifiers != 0) {
+ if ((fakeModifiers & Event.CTRL_MASK) != 0) {
+ vlog.debug("Fake L Ctrl raised");
+ writeKeyEvent(Keysyms.Control_L, false);
+ }
+ if ((modifiers & Event.ALT_MASK) != 0) {
+ vlog.debug("Fake R Alt raised");
+ writeKeyEvent(Keysyms.Alt_R, false);
+ }
+ }
+ writeKeyEvent(keysym, down);
+ if (fakeModifiers != 0) {
+ if ((fakeModifiers & Event.CTRL_MASK) != 0) {
+ vlog.debug("Fake L Ctrl pressed");
+ writeKeyEvent(Keysyms.Control_L, true);
+ }
+ if ((modifiers & Event.ALT_MASK) != 0) {
+ vlog.debug("Fake R Alt pressed");
+ writeKeyEvent(Keysyms.Alt_R, true);
+ }
+ fakeModifiers = 0;
+ }
}
public void writePointerEvent(MouseEvent ev) {
- if (state() != RFBSTATE_NORMAL) return;
+ if (state() != RFBSTATE_NORMAL || shuttingDown)
+ return;
switch (ev.getID()) {
case MouseEvent.MOUSE_PRESSED:
break;
}
- writeModifiers(ev.getModifiers() & ~KeyEvent.ALT_MASK & ~KeyEvent.META_MASK);
-
- if (cp.width != desktop.scaledWidth ||
+ if (cp.width != desktop.scaledWidth ||
cp.height != desktop.scaledHeight) {
- int sx = (desktop.scaleWidthRatio == 1.00)
- ? ev.getX() : (int)Math.floor(ev.getX()/desktop.scaleWidthRatio);
- int sy = (desktop.scaleHeightRatio == 1.00)
- ? ev.getY() : (int)Math.floor(ev.getY()/desktop.scaleHeightRatio);
+ int sx = (desktop.scaleWidthRatio == 1.00) ?
+ ev.getX() : (int)Math.floor(ev.getX() / desktop.scaleWidthRatio);
+ int sy = (desktop.scaleHeightRatio == 1.00) ?
+ ev.getY() : (int)Math.floor(ev.getY() / desktop.scaleHeightRatio);
ev.translatePoint(sx - ev.getX(), sy - ev.getY());
}
-
- writer().writePointerEvent(new Point(ev.getX(),ev.getY()), buttonMask);
- if (buttonMask == 0) writeModifiers(0);
+ writer().writePointerEvent(new Point(ev.getX(), ev.getY()), buttonMask);
}
public void writeWheelEvent(MouseWheelEvent ev) {
- if (state() != RFBSTATE_NORMAL) return;
+ if (state() != RFBSTATE_NORMAL || shuttingDown)
+ return;
int x, y;
int clicks = ev.getWheelRotation();
if (clicks < 0) {
} else {
buttonMask = 16;
}
- writeModifiers(ev.getModifiers() & ~KeyEvent.ALT_MASK & ~KeyEvent.META_MASK);
- for (int i=0;i<Math.abs(clicks);i++) {
+ for (int i = 0; i < Math.abs(clicks); i++) {
x = ev.getX();
y = ev.getY();
writer().writePointerEvent(new Point(x, y), buttonMask);
buttonMask = 0;
writer().writePointerEvent(new Point(x, y), buttonMask);
}
- writeModifiers(0);
}
- synchronized void writeModifiers(int m) {
- if ((m & Event.SHIFT_MASK) != (pressedModifiers & Event.SHIFT_MASK))
- writeKeyEvent(Keysyms.Shift_L, (m & Event.SHIFT_MASK) != 0);
- if ((m & Event.CTRL_MASK) != (pressedModifiers & Event.CTRL_MASK))
- writeKeyEvent(Keysyms.Control_L, (m & Event.CTRL_MASK) != 0);
- if ((m & Event.ALT_MASK) != (pressedModifiers & Event.ALT_MASK))
- writeKeyEvent(Keysyms.Alt_L, (m & Event.ALT_MASK) != 0);
- if ((m & Event.META_MASK) != (pressedModifiers & Event.META_MASK))
- writeKeyEvent(Keysyms.Meta_L, (m & Event.META_MASK) != 0);
- pressedModifiers = m;
+ synchronized void releaseModifiers() {
+ if ((modifiers & Event.SHIFT_MASK) != 0)
+ writeKeyEvent(Keysyms.Shift_L, false);
+ if ((modifiers & Event.CTRL_MASK) != 0)
+ writeKeyEvent(Keysyms.Control_L, false);
+ if ((modifiers & Event.ALT_MASK) != 0)
+ writeKeyEvent(Keysyms.Alt_L, false);
+ if ((modifiers & Event.META_MASK) != 0)
+ writeKeyEvent(Keysyms.Meta_L, false);
+ modifiers = 0;
}
// checkEncodings() sends a setEncodings message if one is needed.
private void checkEncodings() {
if (encodingChange && (writer() != null)) {
- vlog.info("Requesting "+Encodings.encodingName(currentEncoding)+" encoding");
+ vlog.info("Requesting " + Encodings.encodingName(currentEncoding) +
+ " encoding");
writer().writeSetEncodings(currentEncoding, true);
encodingChange = false;
}
// the following are only ever accessed by the GUI thread:
int buttonMask;
- int pressedModifiers;
private String serverHost;
private int serverPort;
private boolean supportsSyncFence;
+ int modifiers;
public int menuKeyCode;
Viewport viewport;
private boolean fullColour;
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2006 Constantin Kaplinsky. All Rights Reserved.
* Copyright (C) 2009 Paul Donohue. All Rights Reserved.
- * Copyright (C) 2010, 2012 D. R. Commander. All Rights Reserved.
+ * Copyright (C) 2010, 2012-2013 D. R. Commander. All Rights Reserved.
* Copyright (C) 2011-2013 Brian P. Hinz
- *
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
import com.tigervnc.rfb.Cursor;
import com.tigervnc.rfb.Point;
-class DesktopWindow extends JPanel implements
- Runnable,
- MouseListener,
- MouseMotionListener,
- MouseWheelListener,
- KeyListener
-{
+class DesktopWindow extends JPanel implements Runnable, MouseListener,
+ MouseMotionListener, MouseWheelListener, KeyListener {
////////////////////////////////////////////////////////////////////
// The following methods are all called from the RFB thread
- public DesktopWindow(int width, int height, PixelFormat serverPF, CConn cc_) {
+ public DesktopWindow(int width, int height, PixelFormat serverPF,
+ CConn cc_) {
cc = cc_;
setSize(width, height);
setOpaque(false);
BufferedImage.TYPE_INT_ARGB);
java.awt.Point hotspot = new java.awt.Point(0,0);
nullCursor = tk.createCustomCursor(cursorImage, hotspot, "nullCursor");
+ cursorImage.flush();
if (!cc.cp.supportsLocalCursor && !bestSize.equals(new Dimension(0,0)))
setCursor(nullCursor);
addMouseListener(this);
public void focusGained(FocusEvent e) {
checkClipboard();
}
+ public void focusLost(FocusEvent e) {
+ cc.releaseModifiers();
+ }
});
setFocusTraversalKeysEnabled(false);
setFocusable(true);
}
-
+
public int width() {
return getWidth();
}
return getHeight();
}
- final public PixelFormat getPF() { return im.getPF(); }
+ public final PixelFormat getPF() { return im.getPF(); }
- public void setViewport(Viewport viewport)
- {
+ public void setViewport(Viewport viewport) {
viewport.setChild(this);
}
// Methods called from the RFB thread - these need to be synchronized
// wherever they access data shared with the GUI thread.
- public void setCursor(int w, int h, Point hotspot,
+ public void setCursor(int w, int h, Point hotspot,
int[] data, byte[] mask) {
// strictly we should use a mutex around this test since useLocalCursor
// might be being altered by the GUI thread. However it's only a single
(im.cm.getBlue(data[y * w + x]));
}
}
- System.arraycopy(mask, y * maskBytesPerRow, cursor.mask,
+ System.arraycopy(mask, y * maskBytesPerRow, cursor.mask,
y * ((cursor.width() + 7) / 8), maskBytesPerRow);
}
ColorModel.getRGBdefault(),
cursor.data, 0, cursor.width());
Image srcImage = tk.createImage(cursorSrc);
- BufferedImage cursorImage;
+ BufferedImage cursorImage;
cursorImage = new BufferedImage(bestSize.width, bestSize.height,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = cursorImage.createGraphics();
RenderingHints.VALUE_RENDER_SPEED);
g2.drawImage(srcImage, 0, 0, (int)Math.min(cw, bestSize.width),
(int)Math.min(ch, bestSize.height), 0, 0, cursor.width(),
- cursor.height(), null) ;
+ cursor.height(), null);
g2.dispose();
srcImage.flush();
int x = (int)Math.floor((float)cursor.hotspot.x * scaleWidthRatio);
int y = (int)Math.floor((float)cursor.hotspot.y * scaleHeightRatio);
- x = (int)Math.min(x, Math.max(bestSize.width-1, 0));
- y = (int)Math.min(y, Math.max(bestSize.height-1, 0));
+ x = (int)Math.min(x, Math.max(bestSize.width - 1, 0));
+ y = (int)Math.min(y, Math.max(bestSize.height - 1, 0));
java.awt.Point hs = new java.awt.Point(x, y);
- if (!bestSize.equals(new Dimension(0,0)))
+ if (!bestSize.equals(new Dimension(0, 0)))
softCursor = tk.createCustomCursor(cursorImage, hs, "softCursor");
cursorImage.flush();
if (softCursor != null) {
- setCursor(softCursor);
+ setCursor(softCursor);
cursorAvailable = false;
return;
}
// because getting java to recalculate its internal translation table and
// redraw the screen is expensive.
- synchronized public void setColourMapEntries(int firstColour, int nColours,
+ public synchronized void setColourMapEntries(int firstColour, int nColours,
int[] rgbs) {
im.setColourMapEntries(firstColour, nColours, rgbs);
if (nColours <= 256) {
}
// Update the actual window with the changed parts of the framebuffer.
- public void updateWindow()
- {
+ public void updateWindow() {
Rect r = damage;
if (!r.is_empty()) {
if (cc.cp.width != scaledWidth || cc.cp.height != scaledHeight) {
im.resize(w, h);
}
- final public void fillRect(int x, int y, int w, int h, int pix)
- {
+ public final void fillRect(int x, int y, int w, int h, int pix) {
if (overlapsCursor(x, y, w, h)) hideLocalCursor();
im.fillRect(x, y, w, h, pix);
damageRect(new Rect(x, y, x+w, y+h));
showLocalCursor();
}
- final public void imageRect(int x, int y, int w, int h,
- Object pix) {
+ public final void imageRect(int x, int y, int w, int h,
+ Object pix) {
if (overlapsCursor(x, y, w, h)) hideLocalCursor();
im.imageRect(x, y, w, h, pix);
damageRect(new Rect(x, y, x+w, y+h));
showLocalCursor();
}
- final public void copyRect(int x, int y, int w, int h,
- int srcX, int srcY) {
+ public final void copyRect(int x, int y, int w, int h,
+ int srcX, int srcY) {
if (overlapsCursor(x, y, w, h) || overlapsCursor(srcX, srcY, w, h))
hideLocalCursor();
im.copyRect(x, y, w, h, srcX, srcY);
final boolean overlapsCursor(int x, int y, int w, int h) {
return (x < cursorBackingX + cursorBacking.width() &&
y < cursorBackingY + cursorBacking.height() &&
- x+w > cursorBackingX && y+h > cursorBackingY);
+ x + w > cursorBackingX && y + h > cursorBackingY);
}
if (cc.cp.width != scaledWidth || cc.cp.height != scaledHeight) {
g2.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
- g2.drawImage(im.getImage(), 0, 0, scaledWidth, scaledHeight, null);
+ g2.drawImage(im.getImage(), 0, 0, scaledWidth, scaledHeight, null);
} else {
g2.drawImage(im.getImage(), 0, 0, null);
}
g2.dispose();
}
-
+
String oldContents = "";
-
- synchronized public void checkClipboard() {
+
+ public synchronized void checkClipboard() {
SecurityManager sm = System.getSecurityManager();
try {
if (sm != null) sm.checkSystemClipboardAccess();
oldContents = newContents;
cc.clipboardDialog.setContents(newContents);
}
- } catch (java.lang.Exception e) {
+ } catch(java.lang.Exception e) {
System.out.println("Exception getting clipboard data: " + e.getMessage());
}
}
}
}
- /** Mouse-Motion callback function */
+ // Mouse-Motion callback function
private void mouseMotionCB(MouseEvent e) {
if (!cc.viewer.viewOnly.getValue() &&
e.getX() >= 0 && e.getX() <= scaledWidth &&
}
}
lastX = e.getX();
- lastY = e.getY();
+ lastY = e.getY();
}
- public void mouseDragged(MouseEvent e) { mouseMotionCB(e);}
- public void mouseMoved(MouseEvent e) { mouseMotionCB(e);}
+ public void mouseDragged(MouseEvent e) { mouseMotionCB(e); }
+ public void mouseMoved(MouseEvent e) { mouseMotionCB(e); }
- /** Mouse callback function */
+ // Mouse callback function
private void mouseCB(MouseEvent e) {
if (!cc.viewer.viewOnly.getValue()) {
if ((e.getID() == MouseEvent.MOUSE_RELEASED) ||
lastX = e.getX();
lastY = e.getY();
}
- public void mouseReleased(MouseEvent e){ mouseCB(e);}
- public void mousePressed(MouseEvent e) { mouseCB(e);}
- public void mouseClicked(MouseEvent e){}
- public void mouseEntered(MouseEvent e){}
- public void mouseExited(MouseEvent e){}
-
- /** MouseWheel callback function */
+ public void mouseReleased(MouseEvent e) { mouseCB(e); }
+ public void mousePressed(MouseEvent e) { mouseCB(e); }
+ public void mouseClicked(MouseEvent e) {}
+ public void mouseEntered(MouseEvent e) {}
+ public void mouseExited(MouseEvent e) {}
+
+ // MouseWheel callback function
private void mouseWheelCB(MouseWheelEvent e) {
if (!cc.viewer.viewOnly.getValue())
cc.writeWheelEvent(e);
}
- public void mouseWheelMoved(MouseWheelEvent e){
+
+ public void mouseWheelMoved(MouseWheelEvent e) {
mouseWheelCB(e);
}
- /** Handle the key-typed event. */
+ // Handle the key-typed event.
public void keyTyped(KeyEvent e) {}
- /** Handle the key-released event. */
- public void keyReleased(KeyEvent e) {}
- /** Handle the key-pressed event. */
+
+ // Handle the key-released event.
+ public void keyReleased(KeyEvent e) {
+ if (!cc.viewer.viewOnly.getValue())
+ cc.writeKeyEvent(e);
+ }
+
+ // Handle the key-pressed event.
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == MenuKey.getMenuKeyCode()) {
- int sx = (scaleWidthRatio == 1.00)
- ? lastX : (int)Math.floor(lastX*scaleWidthRatio);
- int sy = (scaleHeightRatio == 1.00)
- ? lastY : (int)Math.floor(lastY*scaleHeightRatio);
+ int sx = (scaleWidthRatio == 1.00) ?
+ lastX : (int)Math.floor(lastX * scaleWidthRatio);
+ int sy = (scaleHeightRatio == 1.00) ?
+ lastY : (int)Math.floor(lastY * scaleHeightRatio);
java.awt.Point ev = new java.awt.Point(lastX, lastY);
ev.translate(sx - lastX, sy - lastY);
cc.showMenu((int)ev.getX(), (int)ev.getY());
return;
}
+ int ctrlAltShiftMask = Event.SHIFT_MASK | Event.CTRL_MASK | Event.ALT_MASK;
+ if ((e.getModifiers() & ctrlAltShiftMask) == ctrlAltShiftMask) {
+ switch (e.getKeyCode()) {
+ case KeyEvent.VK_F:
+ cc.toggleFullScreen();
+ return;
+ case KeyEvent.VK_I:
+ cc.showInfo();
+ return;
+ case KeyEvent.VK_N:
+ VncViewer.newViewer(cc.viewer);
+ return;
+ case KeyEvent.VK_O:
+ cc.options.showDialog(cc.viewport);
+ return;
+ case KeyEvent.VK_R:
+ cc.refresh();
+ return;
+ case KeyEvent.VK_LEFT:
+ case KeyEvent.VK_RIGHT:
+ case KeyEvent.VK_UP:
+ case KeyEvent.VK_DOWN:
+ return;
+ }
+ }
+ if ((e.getModifiers() & Event.META_MASK) == Event.META_MASK) {
+ switch (e.getKeyCode()) {
+ case KeyEvent.VK_COMMA:
+ case KeyEvent.VK_N:
+ case KeyEvent.VK_W:
+ case KeyEvent.VK_I:
+ case KeyEvent.VK_R:
+ case KeyEvent.VK_L:
+ case KeyEvent.VK_F:
+ case KeyEvent.VK_Z:
+ case KeyEvent.VK_T:
+ return;
+ }
+ }
if (!cc.viewer.viewOnly.getValue())
cc.writeKeyEvent(e);
}
// Note that mutex MUST be held when hideLocalCursor() and showLocalCursor()
// are called.
- synchronized private void hideLocalCursor() {
+ private synchronized void hideLocalCursor() {
// - Blit the cursor backing store over the cursor
if (cursorVisible) {
cursorVisible = false;
}
}
- synchronized private void showLocalCursor() {
+ private synchronized void showLocalCursor() {
if (cursorAvailable && !cursorVisible) {
if (!im.getPF().equal(cursor.getPF()) ||
cursor.width() == 0 || cursor.height() == 0) {
cursorBackingX = x;
cursorBackingY = y;
cursorBacking.setSize(w, h);
-
+
for (int j = 0; j < h; j++)
- System.arraycopy(im.data, (y+j) * im.width() + x,
- cursorBacking.data, j*w, w);
+ System.arraycopy(im.data, (y + j) * im.width() + x,
+ cursorBacking.data, j * w, w);
im.maskRect(cursorLeft, cursorTop, cursor.width(), cursor.height(),
cursor.data, cursor.mask);
// run() is executed by the setColourMapEntriesTimerThread - it sleeps for
// 100ms before actually updating the colourmap.
- synchronized public void run() {
+ public synchronized void run() {
try {
Thread.sleep(100);
- } catch (InterruptedException e) {}
+ } catch(InterruptedException e) {}
im.updateColourMap();
setColourMapEntriesTimerThread = null;
}