Skip to content

Commit

Permalink
Mouse panning with CTRL+SHIFT+ALT+LEFTMOUSE. Mouze zooming with CTRL+…
Browse files Browse the repository at this point in the history
…SHIFT+ALT+MOUSEWHEEL; Scrollbars disabled to avoid interfering with pan/zoom code (no one needs scrollbars anyway with mouse panning/zooming)
  • Loading branch information
Petr Janecek committed Oct 30, 2021
1 parent 13fa00d commit ee14754
Show file tree
Hide file tree
Showing 8 changed files with 284 additions and 25 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.vs
Debug/
Release/

# Prerequisites
*.d

Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# TightVNC Viewer panning/zooming with mouse

Panning .... CTRL+SHIFT+ALT + LEFT MOUSE BUTTON drag/drop

Zooming .... CTRL+SHIFT+ALT + MOUSE WHEEL up/down


Disabled scrollbars (no need for them with mouse pan/zoom; not worth the effort making them work)

Disabled Window auto-resize when zooming (to keep the view non-jumping while mouse zooming)
107 changes: 101 additions & 6 deletions tvnviewer/DesktopWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@

#include "DesktopWindow.h"

DesktopWindow::DesktopWindow(LogWriter *logWriter, ConnectionConfig *conConf)
DesktopWindow::DesktopWindow(LogWriter *logWriter, ConnectionConfig *conConf,
std::function<bool(unsigned char mouseKeys, unsigned short wheelSpeed, POINT position)> onMouseCb)
: m_logWriter(logWriter),
m_clipboard(0),
m_showVert(false),
Expand All @@ -38,8 +39,11 @@ DesktopWindow::DesktopWindow(LogWriter *logWriter, ConnectionConfig *conConf)
m_ctrlDown(false),
m_altDown(false),
m_previousMousePos(-1, -1),
m_previousMousePosNoClamp(-1, 1),
m_previousMouseState(0),
m_isBackgroundDirty(false)
m_isBackgroundDirty(false),
m_isDragging(false),
m_onMouseCb( onMouseCb )
{
m_rfbKeySym = std::auto_ptr<RfbKeySym>(new RfbKeySym(this, m_logWriter));
}
Expand Down Expand Up @@ -184,6 +188,23 @@ bool DesktopWindow::onVScroll(WPARAM wParam, LPARAM lParam)

bool DesktopWindow::onMouse(unsigned char mouseButtons, unsigned short wheelSpeed, POINT position)
{
// position = mouse coord in client area of viewer window
//{ char buf[200]; sprintf(buf, "DesktopWindow::onMouse x=%d, y=%d\n", position.x, position.y); OutputDebugStringA(buf); }

// mouse position in remote view coordinates relative to top left corner of remote frame buffer
POINTS mousePosNoClamp = getViewerCoord(position.x, position.y, false);
m_previousMousePosNoClamp.x = mousePosNoClamp.x;
m_previousMousePosNoClamp.y = mousePosNoClamp.y;
//{ char buf[200]; sprintf(buf, "mouseNoClamp x=%d, y=%d\n", mousePosNoClamp.x, mousePosNoClamp.y); OutputDebugStringA(buf); }

if( m_onMouseCb )
{
if( m_onMouseCb( mouseButtons, wheelSpeed, position ) )
{
return true;
}
}

// If mode is "view-only", then skip event.
if (m_conConf->isViewOnly()) {
return true;
Expand All @@ -207,6 +228,8 @@ bool DesktopWindow::onMouse(unsigned char mouseButtons, unsigned short wheelSpee
}
}



// Translate coordinates from the Viewer Window to Desktop Window.
POINTS mousePos = getViewerCoord(position.x, position.y);
Point pos;
Expand Down Expand Up @@ -326,7 +349,9 @@ void DesktopWindow::doDraw(DeviceContext *dc)
return;
}

scrollProcessing(fbWidth, fbHeight);
// PJ FIXME
// disabling scrollbar processing as it interferes with mouse wheel zooming
//scrollProcessing(fbWidth, fbHeight);

int iHorzPos = 0;
int iVertPos = 0;
Expand All @@ -339,7 +364,9 @@ void DesktopWindow::doDraw(DeviceContext *dc)
iVertPos = m_sbar.getVertPos();
}

m_scManager.setStartPoint(iHorzPos, iVertPos);
// PJ FIXME
// disabling scrollbar processing as it interferes with mouse wheel zooming
//m_scManager.setStartPoint(iHorzPos, iVertPos);

Rect src, dst;
m_scManager.getSourceRect(&src);
Expand Down Expand Up @@ -592,14 +619,33 @@ void DesktopWindow::setScale(int scale)
}
}

POINTS DesktopWindow::getViewerCoord(long xPos, long yPos)
void DesktopWindow::setScaleCenterToMouseCursor(int scale)
{
AutoLock al(&m_bufferLock);

m_scManager.setScaleWithCenter(scale, m_previousMousePosNoClamp.x, m_previousMousePosNoClamp.y );
// update scroll bars to avoid returning the view back
m_sbar.setHorzPos( m_scManager.getStartPos().x );
m_sbar.setVertPos( m_scManager.getStartPos().y );

m_winResize = true;
// Invalidate all area of desktop window.
if (m_hWnd != 0) {
redraw();
}
}


POINTS DesktopWindow::getViewerCoord(long xPos, long yPos, bool clamp)
{
Rect rect;
POINTS p;

m_scManager.getDestinationRect(&rect);
// it checks this point in the rect
if (!rect.isPointInRect(xPos, yPos)) {
if (!rect.isPointInRect(xPos, yPos)
&& clamp // PJ FIXME - when calculating mouse position for zoom centering we do not want clamping
) {
p.x = -1;
p.y = -1;
return p;
Expand Down Expand Up @@ -731,3 +777,52 @@ void DesktopWindow::sendCutTextEvent(const StringStorage *cutText)
exception.getMessage());
}
}

void DesktopWindow::startDragging(POINT mousePos)
{
if( m_isDragging ) return;
m_isDragging = true;
POINT wiewStartPos = m_scManager.getStartPos();
m_dragStartViewStartPos.x = wiewStartPos.x;
m_dragStartViewStartPos.y = wiewStartPos.y;
m_dragStartMousePos.x = mousePos.x;
m_dragStartMousePos.y = mousePos.y;
//{ char buf[200]; sprintf(buf, "Started Dragging"); OutputDebugStringA(buf); }
}

void DesktopWindow::stopDragging(POINT mousePos)
{
m_isDragging = false;
}

bool DesktopWindow::isDragging()
{
return m_isDragging;
}

void DesktopWindow::doDragging(POINT mousePos)
{
if( !m_isDragging ) return;

Point screenMouseDelta;
screenMouseDelta.x = mousePos.x - m_dragStartMousePos.x;
screenMouseDelta.y = mousePos.y - m_dragStartMousePos.y;

// convert our screen delta to the potentially scaled remote delta
float zoom = (float)m_scManager.getScale() / 100.f; if(zoom < 0 ) zoom = 1.f;
Point remoteMouseDelta;
remoteMouseDelta.x = (int)((float)(mousePos.x - m_dragStartMousePos.x) / zoom);
remoteMouseDelta.y = (int)((float)(mousePos.y - m_dragStartMousePos.y) / zoom);

//{ char buf[200]; sprintf(buf, "Dragging=%d, delta x=%d, y=%d\n", m_isDragging, remoteMouseDelta.x, remoteMouseDelta.y); OutputDebugStringA(buf); }

// move the view in the direction of the mouse movement
// (mouse to the right => view start point to the left to see the area more to the right)
m_scManager.setStartPoint( m_dragStartViewStartPos.x - remoteMouseDelta.x, m_dragStartViewStartPos.y - remoteMouseDelta.y );

// Invalidate all area of desktop window.
if (m_hWnd != 0) {
redraw();
}
}

33 changes: 31 additions & 2 deletions tvnviewer/DesktopWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#ifndef _DESKTOP_WINDOW_H_
#define _DESKTOP_WINDOW_H_

#include <functional>
#include "win-system/WinClipboard.h"
#include "gui/DibFrameBuffer.h"
#include "region/Rect.h"
Expand All @@ -42,7 +43,9 @@ class DesktopWindow : public PaintWindow,
protected RfbKeySymListener
{
public:
DesktopWindow(LogWriter *logWriter, ConnectionConfig *conConf);
DesktopWindow(LogWriter *logWriter, ConnectionConfig *conConf,
std::function<bool(unsigned char mouseKeys, unsigned short wheelSpeed, POINT position)> onMouseCb
);
virtual ~DesktopWindow();

void setClipboardData(const StringStorage *strText);
Expand All @@ -54,6 +57,7 @@ class DesktopWindow : public PaintWindow,

// set scale of image, can -1 = Auto, in percent
void setScale(int scale);
void setScaleCenterToMouseCursor(int scale);
// it returns the image width and height considering scale
Rect getViewerGeometry();
// it returns the image width and height.
Expand Down Expand Up @@ -83,6 +87,13 @@ class DesktopWindow : public PaintWindow,
// Set function for m_winKeyIgnore.
void setWinKeyIgnore(bool winKeyIgnore) { m_rfbKeySym->setWinKeyIgnore(winKeyIgnore); }

Point getMousePos() { return m_previousMousePos; }

void startDragging(POINT mousePos);
void stopDragging(POINT mousePos);
bool isDragging();
void doDragging(POINT mousePos);

protected:
//
// Overrides RfbKeySymListener::onRfbKeySymEvent().
Expand All @@ -106,7 +117,12 @@ class DesktopWindow : public PaintWindow,
bool onSize(WPARAM wParam, LPARAM lParam);
bool onDestroy();

POINTS getViewerCoord(long xPos, long yPos);
// if clamp==false the coordinate returned will not be clamped to the viewer area
// (so it could become negative if input coordinate is above or on the left of the
// top left corner of the remote screen). This is used for mouse wheel zoom centering
// around mouse cursor pos (clamping might change the zooming center during the wheel zooming)
POINTS getViewerCoord(long xPos, long yPos, bool clamp=true);

void calculateWndSize(bool isChanged);
void applyScrollbarChanges(bool isChanged, bool isVert, bool isHorz, int wndWidth, int wndHeight);

Expand All @@ -129,6 +145,11 @@ class DesktopWindow : public PaintWindow,
unsigned char m_previousMouseState;
Point m_previousMousePos;

// our mouse cursor position in remote screen pixels, relative to top left corner of remote screen,
// not clamped into the remote screen rectangle (will be negative if on the left or above the remote screen),
// used as zoom center point
Point m_previousMousePosNoClamp;

// scroll bars: vertical and horizontal
ScrollBar m_sbar;

Expand Down Expand Up @@ -162,6 +183,14 @@ class DesktopWindow : public PaintWindow,
ConnectionConfig *m_conConf;
bool m_isBackgroundDirty;

bool m_isDragging; // are we currently panning the view with the mouse?
Point m_dragStartViewStartPos; // scaleMgr.StartPos when started dragging
Point m_dragStartMousePos; // mouse desktop screen pos (local, not remote) when started dragging


private:
std::function<bool(unsigned char mouseKeys, unsigned short wheelSpeed, POINT position)> m_onMouseCb;

private:
void doDraw(DeviceContext *dc);
void scrollProcessing(int fbWidth, int fbHeight);
Expand Down
38 changes: 34 additions & 4 deletions tvnviewer/ScaleManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,36 @@ void ScaleManager::keepAspectRatio(Rect *rc) const
void ScaleManager::setScale(int scale)
{
m_scale = scale;
setStartPoint(m_xStart, m_yStart);
// PJ FIXME
// we need the only place where we pan the view to be in the mouse zooming code
//setStartPoint(m_xStart, m_yStart);
}

void ScaleManager::setScaleWithCenter(int scale, int xCenter, int yCenter)
{

float zoomCoef = (float) scale / m_scale; // how much we zoomed in
if( m_scale < 0 ) zoomCoef = 1;
//{ char buf[200]; sprintf(buf, "zoomCoef=%f, center x=%d, y=%d\n", zoomCoef, xCenter, yCenter); OutputDebugStringA(buf); }
// dist of center point from left/top border of our view
int left1 = xCenter - m_xStart;
int top1 = yCenter - m_yStart;

m_scale = scale;

// keep our centering point at same relative location in our view
int new_xStart = (int)(xCenter - (float) left1 / zoomCoef);
int new_yStart = (int)(yCenter - (float) top1 / zoomCoef);

setStartPoint(new_xStart, new_yStart);
}

void ScaleManager::setWindow(Rect *rcWnd)
{
m_rcWindow = rcWnd;
setStartPoint(m_xStart, m_yStart);
// PJ FIXME
// we need the only place where we pan the view to be in the mouse zooming code
//setStartPoint(m_xStart, m_yStart);
}

Rect ScaleManager::calcScaled(const Rect *rcViewed, bool bCent)
Expand Down Expand Up @@ -168,8 +191,12 @@ void ScaleManager::setStartPoint(int x, int y)
int wndHeight = m_rcWindow.getHeight();

if (m_scale != -1) {
x = x * DEFAULT_SCALE_DENOMERATOR / m_scale;
y = y * DEFAULT_SCALE_DENOMERATOR / m_scale;
// PJ FIXME
// This hack breaks the conventions on tightVNC...
// We want the new start point to be exactly the one set from the mouse zooming code (which does
// not count with scaling in this function)
//x = x * DEFAULT_SCALE_DENOMERATOR / m_scale;
//y = y * DEFAULT_SCALE_DENOMERATOR / m_scale;

wndWidth = wndWidth * DEFAULT_SCALE_DENOMERATOR / m_scale;
wndHeight = wndHeight * DEFAULT_SCALE_DENOMERATOR / m_scale;
Expand All @@ -180,6 +207,8 @@ void ScaleManager::setStartPoint(int x, int y)
wndHeight = m_scrHeight;
}

//{ char buf[200]; sprintf(buf, "StartPoint x=%d, y=%d\n", x, y); OutputDebugStringA(buf); }

m_xStart = x;
m_yStart = y;
m_rcViewed.left = x;
Expand All @@ -204,6 +233,7 @@ void ScaleManager::setStartPoint(int x, int y)
Rect rcScaled = calcScaled(&m_rcViewed, true);
}


void ScaleManager::getViewedRect(Rect *rcViewed) const
{
Rect rect(&m_rcViewed);
Expand Down
10 changes: 9 additions & 1 deletion tvnviewer/ScaleManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ class ScaleManager
void setScreenResolution(int maxWidth, int maxHeight);
// set the scale of image, for example, 10 - it means 10% from original
void setScale(int scale);

// set the scale while keeping given center point on the same screen location
// (so we are zooming around given point - usually the mouse cursor)
void setScaleWithCenter(int scale, int xCenter, int yCenter);

int getScale() { return m_scale; }
POINT getStartPos() { POINT p; p.x = m_xStart; p.y=m_yStart; return p; }

// set the rectangle of window
void setWindow(Rect *rcWnd);

Expand All @@ -50,7 +58,7 @@ class ScaleManager
int getHorzPoints() const;

// set the current starting point
// point is scaled
// point is scaled PJ: NOT ANY MORE!!! Hacked in favor of the mouse wheel zooming code...
void setStartPoint(int x, int y);

// get viewed rectangle
Expand Down
Loading

0 comments on commit ee14754

Please sign in to comment.