📄 view.cs
字号:
// Copyright (C) 2004-2005, 2007 Rocky Lo. All Rights Reserved.
//
// This file is part of the VNC system.
//
// The VNC system 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 program 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 program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
//
// If the source code for the VNC system is not available from the place
// whence you received this file, check http://www.uk.research.att.com/vnc or contact
// the authors on vnc@uk.research.att.com for information on obtaining it.
using System;
using System.IO;
using System.Threading;
using System.Collections;
using System.Drawing;
using System.Windows.Forms;
using Vnc.RfbProto;
namespace Vnc.Viewer
{
/// <remarks>
/// This class is responsible for maintaining the server view.
/// This is also responsible for accepting user input and send to the server accordingly.
/// </remars>
internal abstract class View : Form
{
private const byte Delta = 50; // TODO: Find an optimal value.
private const byte BgDelta = 100; // TODO: Find an optimal value.
private const UInt32 CtrlKey = 0x0000FFE3;
private const UInt32 AltKey = 0x0000FFE9;
private const UInt32 EnterKey = 0x0000FF0D;
private const UInt32 DelKey = 0x0000FFFF;
private const UInt32 EscKey = 0x0000FF1B;
private const UInt32 ShiftKey = 0x0000FFE1;
protected const byte NumTapHoldCircles = 8;
protected byte TapHoldRadius = 3;
protected byte BigCircleRadius = 15;
protected byte TapHoldCircleRadius = 3;
// .NET CF does not have Brushes, SystemBrushes, and Pens...
protected Pen viewPen = new Pen(App.Black);
private SolidBrush viewBrush = new SolidBrush(App.Black);
private SolidBrush frameBufBrush = new SolidBrush(App.Black);
protected System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
protected HScrollBar hScrlBar = new HScrollBar();
protected VScrollBar vScrlBar = new VScrollBar();
protected MainMenu menu = new MainMenu();
protected MenuItem connMenu = new MenuItem();
protected MenuItem newConnItem = new MenuItem();
protected MenuItem refreshItem = new MenuItem();
protected MenuItem closeConnItem = new MenuItem();
protected MenuItem viewMenu = new MenuItem();
protected MenuItem viewSingleWinItem = new MenuItem();
protected MenuItem viewDesktopItem = new MenuItem();
private MenuItem rotateMenu = new MenuItem();
private MenuItem cliScalingMenu = new MenuItem();
private MenuItem servScalingMenu = new MenuItem();
private MenuItem pixelSizeMenu = new MenuItem();
protected MenuItem keysMenu = new MenuItem();
private MenuItem fnMenu = new MenuItem();
protected MenuItem optionsMenu = new MenuItem();
protected MenuItem aboutItem = new MenuItem();
private Bitmap frameBuf = null;
private Graphics frameBufGraphics = null;
private Conn conn = null;
protected ConnOpts connOpts = null;
private UInt16 rawFBWidth = 0;
private UInt16 scaledFBWidth = 0;
private UInt16 rawFBHeight = 0;
private UInt16 scaledFBHeight = 0;
private UInt16 newWidth = 0;
private UInt16 newHeight = 0;
private bool isFBResized = false;
protected int mouseX = 0;
protected int mouseY = 0;
protected bool leftBtnDown = false;
protected bool rightBtnDown = false;
protected UInt16 tapHoldCnt = 0;
protected bool isSetSingleWinPending = false;
private bool toKeyUpCtrl = false;
private bool toKeyUpAlt = false;
protected EventHandler fullScrnHdr = null;
protected EventHandler viewWinHdr = null;
protected EventHandler rotateHdr = null;
protected EventHandler cliScalingHdr = null;
protected EventHandler servScalingHdr = null;
protected EventHandler pixelSizeHdr = null;
protected EventHandler keysHdr = null;
private EventHandler resizeFrameBufHdr = null;
private System.Windows.Forms.Timer bgTimer = new System.Windows.Forms.Timer();
private Rectangle invalidRect = new Rectangle();
private Object invalidRectLock = null; // This is the mutex protecting invalidRect.
private bool toSendUpdReq = false;
// "Real" coordinates => server coordinates.
// "FrameBuf" coordinates => coordinates of in-memory buffer. This is the same as
// "Real" coordinates when no rotation is effective.
// "Scrn" coordinates => screen coordinates.
private void RealToFrameBufXY(ref UInt16 x, ref UInt16 y, Orientation orientation, UInt16 frameBufWidth, UInt16 frameBufHeight)
{
UInt16 tempX = x;
switch(orientation)
{
case Orientation.Landscape90:
x = y;
y = (UInt16)(frameBufHeight - 1 - tempX);
break;
case Orientation.Portrait180:
x = (UInt16)(frameBufWidth - 1 - x);
y = (UInt16)(frameBufHeight - 1 - y);
break;
case Orientation.Landscape270:
x = (UInt16)(frameBufWidth - 1 - y);
y = tempX;
break;
}
}
private void RealToFrameBufXY(ref UInt16 x, ref UInt16 y)
{
RealToFrameBufXY(ref x, ref y, connOpts.ViewOpts.Orientation, rawFBWidth, rawFBHeight);
}
private void RealToFrameBufRect(ref Rectangle rect)
{
Rectangle tempRect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height);
switch(connOpts.ViewOpts.Orientation)
{
case Orientation.Landscape90:
rect.X = tempRect.Y;
rect.Y = rawFBHeight - tempRect.X - tempRect.Width;
rect.Width = tempRect.Height;
rect.Height = tempRect.Width;
break;
case Orientation.Portrait180:
rect.X = rawFBWidth - tempRect.X - tempRect.Width;
rect.Y = rawFBHeight - tempRect.Y - tempRect.Height;
break;
case Orientation.Landscape270:
rect.X = rawFBWidth - tempRect.Y - tempRect.Height;
rect.Y = tempRect.X;
rect.Width = tempRect.Height;
rect.Height = tempRect.Width;
break;
}
}
private void RealToScrnXY(ref int x, ref int y)
{
UInt16 x16 = (UInt16)x;
UInt16 y16 = (UInt16)y;
RealToFrameBufXY(ref x16, ref y16);
x = x16;
y = y16;
FrameBufToScrnXY(ref x, ref y);
}
private void RealToScrnRect(ref Rectangle rect)
{
RealToFrameBufRect(ref rect);
FrameBufToScrnRect(ref rect);
}
private void FrameBufToScrnXY(ref int x, ref int y)
{
if(connOpts.ViewOpts.CliScaling != CliScaling.None)
{
x = x * scaledFBWidth / rawFBWidth;
y = y * scaledFBHeight / rawFBHeight;
}
// Scrolling
if(hScrlBar.Visible)
x -= hScrlBar.Value;
if(vScrlBar.Visible)
y -= vScrlBar.Value;
Rectangle viewable = ViewableRect;
x += viewable.X;
y += viewable.Y;
}
private void FrameBufToScrnRect(ref Rectangle rect)
{
int x = rect.Left;
int y = rect.Top;
FrameBufToScrnXY(ref x, ref y);
rect.X = x;
rect.Y = y;
if(connOpts.ViewOpts.CliScaling != CliScaling.None)
{
rect.Width = rect.Width * scaledFBWidth / rawFBWidth;
rect.Height = rect.Height * scaledFBHeight / rawFBHeight;
}
}
private void FrameBufToRealXY(ref UInt16 x, ref UInt16 y)
{
UInt16 tempX = x;
switch(connOpts.ViewOpts.Orientation)
{
case Orientation.Landscape90:
x = (UInt16)(rawFBHeight - 1 - y);
y = tempX;
break;
case Orientation.Portrait180:
x = (UInt16)(rawFBWidth - 1 - x);
y = (UInt16)(rawFBHeight - 1 - y);
break;
case Orientation.Landscape270:
x = y;
y = (UInt16)(rawFBWidth - 1 - tempX);
break;
}
}
private void ScrnToFrameBufXY(ref int x, ref int y)
{
// Scrolling
if(hScrlBar.Visible)
x += hScrlBar.Value;
if(vScrlBar.Visible)
y += vScrlBar.Value;
Rectangle viewable = ViewableRect;
x -= viewable.X;
y -= viewable.Y;
if(connOpts.ViewOpts.CliScaling != CliScaling.None)
{
x = x * rawFBWidth / scaledFBWidth;
y = y * rawFBHeight / scaledFBHeight;
}
x = Math.Max(x, 0);
x = Math.Min(x, rawFBWidth - 1);
y = Math.Max(y, 0);
y = Math.Min(y, rawFBHeight - 1);
}
private void ScrnToFrameBufRect(ref Rectangle rect)
{
int x = rect.Left;
int y = rect.Top;
ScrnToFrameBufXY(ref x, ref y);
rect.X = x;
rect.Y = y;
if(connOpts.ViewOpts.CliScaling != CliScaling.None)
{
rect.Width = rect.Width * rawFBWidth / scaledFBWidth;
rect.Height = rect.Height * rawFBHeight / scaledFBHeight;
}
}
private void ScrnToRealXY(ref int x, ref int y)
{
ScrnToFrameBufXY(ref x, ref y);
UInt16 x16 = (UInt16)x;
UInt16 y16 = (UInt16)y;
FrameBufToRealXY(ref x16, ref y16);
x = x16;
y = y16;
}
internal Color this[UInt16 x, UInt16 y]
{
get
{
RealToFrameBufXY(ref x, ref y);
return frameBuf.GetPixel(x, y);
}
set
{
RealToFrameBufXY(ref x, ref y);
// The caller should lock the frame buffer before changing its content.
// TODO: Anything faster?
frameBuf.SetPixel(x, y, value);
}
}
internal void FillRect(Rectangle rect, Color color)
{
RealToFrameBufRect(ref rect);
frameBufBrush.Color = color;
frameBufGraphics.FillRectangle(frameBufBrush, rect);
}
internal void CopyRect(Rectangle rect, UInt16 x, UInt16 y)
{
// TODO: Anything more efficient?
Rectangle srcRect = new Rectangle(x, y, rect.Width, rect.Height);
RealToFrameBufRect(ref rect);
RealToFrameBufRect(ref srcRect);
Bitmap image = new Bitmap(frameBuf);
frameBufGraphics.DrawImage(image, rect.X, rect.Y, srcRect, GraphicsUnit.Pixel);
image.Dispose();
}
internal void InvalidateRect(Rectangle rect)
{
// The timer event will pick this up and invalidate the area.
Monitor.Enter(invalidRectLock);
invalidRect = Rectangle.Union(invalidRect, rect);
Monitor.Exit(invalidRectLock);
}
internal void SendUpdReq()
{
toSendUpdReq = true;
}
private void BgTicked(object sender, EventArgs e)
{
Monitor.Enter(invalidRectLock);
Rectangle rect = invalidRect;
invalidRect = Rectangle.Empty;
Monitor.Exit(invalidRectLock);
if(rect != Rectangle.Empty)
{
RealToScrnRect(ref rect);
Invalidate(rect);
}
if(toSendUpdReq)
{
toSendUpdReq = false;
try
{
conn.SendUpdReq(true);
}
catch(IOException)
{
Close();
}
}
}
internal void ResizeFrameBuf(UInt16 width, UInt16 height)
{
newWidth = width;
newHeight = height;
isFBResized = true;
Invoke(resizeFrameBufHdr);
}
internal void NewFrameBuf(UInt16 width, UInt16 height)
{
newWidth = width;
newHeight = height;
isFBResized = false;
Invoke(resizeFrameBufHdr);
}
internal void LockFrameBuf()
{
Monitor.Enter(this);
}
internal void UnlockFrameBuf()
{
Monitor.Exit(this);
}
// HScrlBarVal and VScrlBarVal are needed when we resize the window.
// The idea is to try not to change the current position when the window is resized.
// This is quite hard to archieve when rotation is effective.
private UInt16 HScrlBarVal
{
get
{
if(!hScrlBar.Visible)
return 0;
switch(connOpts.ViewOpts.Orientation)
{
case Orientation.Portrait180:
case Orientation.Landscape270:
return (UInt16)(hScrlBar.Maximum + 1 - hScrlBar.Value - hScrlBar.LargeChange);
default:
return (UInt16)hScrlBar.Value;
}
}
set
{
if(!hScrlBar.Visible)
value = 0;
// The maximum that we can assign should be hScrlBar.Maximum - hScrlBar.LargeChange + 1.
// The maximum that we assign here is hScrlBar.Maximum - hScrlBar.LargeChange to work
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -