From e66e371eee17a602f29453a8c0407e0cabf60ece Mon Sep 17 00:00:00 2001 From: DRC Date: Sat, 9 Oct 2021 09:23:21 -0500 Subject: [PATCH] Viewer: Menu options & hotkeys for zooming in/out (when non-automatic desktop scaling is enabled) Note that, unfortunately, there is no straightforward way to use '+' as an accelerator in Swing, since that character is usually not located on the primary keyboard layer. Because the key codes in Swing are only valid for a U.S. keyboard layout, there is not enough information in the KeyEvent to determine, with any degree of reliability, whether Ctrl-Alt-Shift + or Ctrl-Alt-Shift - has been pressed. Thus, the new implementation of this feature uses the 8 and 9 keys for, respectively, zooming out and in instead of the - and + keys. This provides a similar feel to the old implementation when using U.S. keyboards, since the 8 and 9 keys are also adjacent to the 0 key. Refer to #135 --- ChangeLog.md | 8 ++ java/com/turbovnc/vncviewer/CConn.java | 79 +++++++++++++++++++ .../com/turbovnc/vncviewer/DesktopWindow.java | 36 +++++++++ java/com/turbovnc/vncviewer/F8Menu.java | 30 ++++++- java/com/turbovnc/vncviewer/MacMenuBar.java | 33 +++++++- java/com/turbovnc/vncviewer/Viewport.java | 17 +++- 6 files changed, 198 insertions(+), 5 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index ca6afea77..43332b0d3 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -206,6 +206,14 @@ they are rendered irrelevant by other settings. mode to be toggled more quickly. This functionality previously only existed in the Windows TurboVNC Viewer. +29. Added F8 menu options, Mac menu options, and corresponding hotkeys +(CTRL-ALT-SHIFT-9 and Command-9, CTRL-ALT-SHIFT-8 and Command-8, +CTRL-ALT-SHIFT-0 and Command-0) to the TurboVNC Viewer that can be used to +zoom in (increase the scaling factor), zoom out (decrease the scaling factor), +or reset the scaling factor to 100% when automatic desktop resizing and +automatic scaling are disabled. This functionality previously only existed in +the Windows TurboVNC Viewer. + 2.2.7 ===== diff --git a/java/com/turbovnc/vncviewer/CConn.java b/java/com/turbovnc/vncviewer/CConn.java index b5a3cc287..5ae924bd2 100644 --- a/java/com/turbovnc/vncviewer/CConn.java +++ b/java/com/turbovnc/vncviewer/CConn.java @@ -1700,6 +1700,12 @@ else if (reconfigure) } if (opts.viewOnly != oldOpts.viewOnly) menu.viewOnly.setSelected(opts.viewOnly); + if (opts.scalingFactor != oldOpts.scalingFactor || + !opts.desktopSize.equalsIgnoreID(oldOpts.desktopSize)) { + if (viewport != null) + viewport.updateMacMenuZoom(); + menu.updateZoom(); + } if (deleteRestore) { savedState = -1; savedRect = new Rectangle(-1, -1, 0, 0); @@ -1721,6 +1727,79 @@ public boolean supportsSetDesktopSize() { return cp.supportsSetDesktopSize || firstUpdate; } + // EDT + public void zoomIn() { + if (opts.desktopSize.mode == Options.SIZE_AUTO || + opts.scalingFactor == Options.SCALE_AUTO || + opts.scalingFactor == Options.SCALE_FIXEDRATIO) + return; + + int sf = opts.scalingFactor; + if (sf < 100) + sf = ((sf / 10) + 1) * 10; + else if (sf >= 100 && sf <= 200) + sf = ((sf / 25) + 1) * 25; + else + sf = ((sf / 50) + 1) * 50; + if (sf > 400) sf = 400; + opts.scalingFactor = sf; + + savedState = -1; + savedRect = new Rectangle(-1, -1, 0, 0); + if (!viewport.lionFSSupported() || !opts.fullScreen) + recreateViewport(); + else + reconfigureAndRepaintViewport(false); + savedState = -1; + savedRect = new Rectangle(-1, -1, 0, 0); + } + + // EDT + public void zoomOut() { + if (opts.desktopSize.mode == Options.SIZE_AUTO || + opts.scalingFactor == Options.SCALE_AUTO || + opts.scalingFactor == Options.SCALE_FIXEDRATIO) + return; + + int sf = opts.scalingFactor; + if (sf <= 100) + sf = (((sf + 9) / 10) - 1) * 10; + else if (sf >= 100 && sf <= 200) + sf = (((sf + 24) / 25) - 1) * 25; + else + sf = (((sf + 49) / 50) - 1) * 50; + if (sf < 10) sf = 10; + opts.scalingFactor = sf; + + savedState = -1; + savedRect = new Rectangle(-1, -1, 0, 0); + if (!viewport.lionFSSupported() || !opts.fullScreen) + recreateViewport(); + else + reconfigureAndRepaintViewport(false); + savedState = -1; + savedRect = new Rectangle(-1, -1, 0, 0); + } + + // EDT + public void zoom100() { + if (opts.desktopSize.mode == Options.SIZE_AUTO || + opts.scalingFactor == Options.SCALE_AUTO || + opts.scalingFactor == Options.SCALE_FIXEDRATIO) + return; + + opts.scalingFactor = 100; + + savedState = -1; + savedRect = new Rectangle(-1, -1, 0, 0); + if (!viewport.lionFSSupported() || !opts.fullScreen) + recreateViewport(); + else + reconfigureAndRepaintViewport(false); + savedState = -1; + savedRect = new Rectangle(-1, -1, 0, 0); + } + // EDT public void toggleToolbar() { if (opts.fullScreen) diff --git a/java/com/turbovnc/vncviewer/DesktopWindow.java b/java/com/turbovnc/vncviewer/DesktopWindow.java index 3eb3bb197..87ff56eac 100644 --- a/java/com/turbovnc/vncviewer/DesktopWindow.java +++ b/java/com/turbovnc/vncviewer/DesktopWindow.java @@ -625,6 +625,35 @@ public void keyPressed(KeyEvent e) { case KeyEvent.VK_Z: cc.sizeWindow(); return; + case KeyEvent.VK_9: + case KeyEvent.VK_NUMPAD9: + case KeyEvent.VK_ADD: + if (cc.opts.desktopSize.mode != Options.SIZE_AUTO && + cc.opts.scalingFactor != Options.SCALE_AUTO && + cc.opts.scalingFactor != Options.SCALE_FIXEDRATIO) { + cc.zoomIn(); + return; + } + break; + case KeyEvent.VK_8: + case KeyEvent.VK_NUMPAD8: + case KeyEvent.VK_SUBTRACT: + if (cc.opts.desktopSize.mode != Options.SIZE_AUTO && + cc.opts.scalingFactor != Options.SCALE_AUTO && + cc.opts.scalingFactor != Options.SCALE_FIXEDRATIO) { + cc.zoomOut(); + return; + } + break; + case KeyEvent.VK_0: + case KeyEvent.VK_NUMPAD0: + if (cc.opts.desktopSize.mode != Options.SIZE_AUTO && + cc.opts.scalingFactor != Options.SCALE_AUTO && + cc.opts.scalingFactor != Options.SCALE_FIXEDRATIO) { + cc.zoom100(); + return; + } + break; case KeyEvent.VK_LEFT: case KeyEvent.VK_RIGHT: case KeyEvent.VK_UP: @@ -656,6 +685,13 @@ public void keyPressed(KeyEvent e) { case KeyEvent.VK_Z: case KeyEvent.VK_T: return; + case KeyEvent.VK_9: + case KeyEvent.VK_8: + case KeyEvent.VK_0: + if (cc.opts.desktopSize.mode != Options.SIZE_AUTO && + cc.opts.scalingFactor != Options.SCALE_AUTO && + cc.opts.scalingFactor != Options.SCALE_FIXEDRATIO) + return; } } if ((e.getModifiersEx() & InputEvent.ALT_DOWN_MASK) == diff --git a/java/com/turbovnc/vncviewer/F8Menu.java b/java/com/turbovnc/vncviewer/F8Menu.java index f7ab1e7be..11a0aa84e 100644 --- a/java/com/turbovnc/vncviewer/F8Menu.java +++ b/java/com/turbovnc/vncviewer/F8Menu.java @@ -68,6 +68,9 @@ public F8Menu(CConn cc_) { defaultSize = addMenuItem("Default Window Size/Position (Ctrl-Alt-Shift-Z)", KeyEvent.VK_Z); + zoomIn = addMenuItem("Zoom In (Ctrl-Alt-Shift-9)", KeyEvent.VK_9); + zoomOut = addMenuItem("Zoom Out (Ctrl-Alt-Shift-8)", KeyEvent.VK_8); + zoom100 = addMenuItem("Zoom 100% (Ctrl-Alt-Shift-0)", KeyEvent.VK_0); showToolbar = new JCheckBoxMenuItem("Show Toolbar (Ctrl-Alt-Shift-T)"); showToolbar.setMnemonic(KeyEvent.VK_T); showToolbar.setSelected(cc.opts.showToolbar); @@ -118,6 +121,8 @@ public void popupMenuCanceled(PopupMenuEvent e) { public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {} public void popupMenuWillBecomeVisible(PopupMenuEvent e) {} }); + + updateZoom(); } JMenuItem addMenuItem(String str, int mnemonic) { @@ -157,6 +162,15 @@ public void actionPerformed(ActionEvent ev) { } else if (actionMatch(ev, defaultSize)) { cc.sizeWindow(); firePopupMenuCanceled(); + } else if (actionMatch(ev, zoomIn)) { + cc.zoomIn(); + firePopupMenuCanceled(); + } else if (actionMatch(ev, zoomOut)) { + cc.zoomOut(); + firePopupMenuCanceled(); + } else if (actionMatch(ev, zoom100)) { + cc.zoom100(); + firePopupMenuCanceled(); } else if (actionMatch(ev, tileWindows)) { VncViewer.tileWindows(); } else if (actionMatch(ev, clipboard)) { @@ -211,8 +225,22 @@ public void actionPerformed(ActionEvent ev) { } } + void updateZoom() { + if (cc.opts.desktopSize.mode == Options.SIZE_AUTO || + cc.opts.scalingFactor == Options.SCALE_AUTO || + cc.opts.scalingFactor == Options.SCALE_FIXEDRATIO) { + zoomIn.setEnabled(false); + zoomOut.setEnabled(false); + zoom100.setEnabled(false); + } else { + zoomIn.setEnabled(true); + zoomOut.setEnabled(true); + zoom100.setEnabled(true); + } + } + CConn cc; - JMenuItem defaultSize, tileWindows; + JMenuItem defaultSize, zoomIn, zoomOut, zoom100, tileWindows; JMenuItem exit, clipboard, ctrlAltDel, ctrlEsc, refresh, losslessRefresh; JMenuItem newConn, options, info, profile, screenshot, about, dismiss; static JMenuItem f8; diff --git a/java/com/turbovnc/vncviewer/MacMenuBar.java b/java/com/turbovnc/vncviewer/MacMenuBar.java index ebef8e8db..def13caa3 100644 --- a/java/com/turbovnc/vncviewer/MacMenuBar.java +++ b/java/com/turbovnc/vncviewer/MacMenuBar.java @@ -171,6 +171,15 @@ public MacMenuBar(CConn cc_) { defaultSize = addMenuItem(connMenu, "Default Window Size/Position"); defaultSize.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, acceleratorMask)); + zoomIn = addMenuItem(connMenu, "Zoom In"); + zoomIn.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_9, + acceleratorMask)); + zoomOut = addMenuItem(connMenu, "Zoom Out"); + zoomOut.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_8, + acceleratorMask)); + zoom100 = addMenuItem(connMenu, "Zoom 100%", KeyEvent.VK_0); + zoom100.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_0, + acceleratorMask)); tileWindows = addMenuItem(connMenu, "Tile All Viewer Windows"); tileWindows.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, acceleratorMask)); @@ -195,6 +204,8 @@ public MacMenuBar(CConn cc_) { clipboard = addMenuItem(connMenu, "Clipboard ..."); add(connMenu); + + updateZoom(); } JMenuItem addMenuItem(JMenu menu, String str, int mnemonic) { @@ -220,6 +231,12 @@ public void actionPerformed(ActionEvent ev) { cc.toggleFullScreen(); } else if (actionMatch(ev, defaultSize)) { cc.sizeWindow(); + } else if (actionMatch(ev, zoomIn)) { + cc.zoomIn(); + } else if (actionMatch(ev, zoomOut)) { + cc.zoomOut(); + } else if (actionMatch(ev, zoom100)) { + cc.zoom100(); } else if (actionMatch(ev, tileWindows)) { VncViewer.tileWindows(); } else if (actionMatch(ev, showToolbar)) { @@ -271,8 +288,22 @@ void updateProfile() { profile.setSelected(cc.profileDialog.isVisible()); } + void updateZoom() { + if (cc.opts.desktopSize.mode == Options.SIZE_AUTO || + cc.opts.scalingFactor == Options.SCALE_AUTO || + cc.opts.scalingFactor == Options.SCALE_FIXEDRATIO) { + zoomIn.setEnabled(false); + zoomOut.setEnabled(false); + zoom100.setEnabled(false); + } else { + zoomIn.setEnabled(true); + zoomOut.setEnabled(true); + zoom100.setEnabled(true); + } + } + CConn cc; - JMenuItem defaultSize, tileWindows; + JMenuItem defaultSize, zoomIn, zoomOut, zoom100, tileWindows; JMenuItem clipboard, ctrlAltDel, ctrlEsc, refresh, losslessRefresh; JMenuItem newConn, closeConn, info, screenshot; JCheckBoxMenuItem profile, fullScreen, showToolbar, viewOnly; diff --git a/java/com/turbovnc/vncviewer/Viewport.java b/java/com/turbovnc/vncviewer/Viewport.java index 03725934f..52fb7b7bb 100644 --- a/java/com/turbovnc/vncviewer/Viewport.java +++ b/java/com/turbovnc/vncviewer/Viewport.java @@ -332,6 +332,11 @@ public void updateMacMenuProfile() { macMenu.updateProfile(); } + public void updateMacMenuZoom() { + if (macMenu != null) + macMenu.updateZoom(); + } + public void setChild(DesktopWindow child) { sp.getViewport().setView(child); } @@ -373,6 +378,11 @@ private void showToolbar(boolean show, boolean force) { } public void updateTitle() { + String scaleString = new String(""); + if (cc.opts.scalingFactor != 100 && + cc.opts.scalingFactor != Options.SCALE_AUTO && + cc.opts.scalingFactor != Options.SCALE_FIXEDRATIO) + scaleString = new String("- " + cc.opts.scalingFactor + "%"); int enc = cc.lastServerEncoding; if (enc < 0) enc = cc.currentEncoding; if (enc == RFB.ENCODING_TIGHT) { @@ -380,13 +390,14 @@ public void updateTitle() { String[] subsampStr = { "1X", "4X", "2X", "Gray" }; setTitle(cc.cp.name() + " [Tight + JPEG " + subsampStr[cc.opts.subsampling] + " Q" + cc.opts.quality + - " + CL " + cc.opts.compressLevel + "]"); + " + CL " + cc.opts.compressLevel + "]" + scaleString); } else { setTitle(cc.cp.name() + " [Lossless Tight" + - " + CL " + cc.opts.compressLevel + "]"); + " + CL " + cc.opts.compressLevel + "]" + scaleString); } } else { - setTitle(cc.cp.name() + " [" + RFB.encodingName(enc) + "]"); + setTitle(cc.cp.name() + " [" + RFB.encodingName(enc) + "]" + + scaleString); } }