移动触控板






4.58/5 (21投票s)
Mobile TouchPad 允许您通过触摸板手机控制您的 PC。您可以轻松连接到您的桌面,无需进行任何配置。
目录
什么是 Mobile TouchPad?
Mobile TouchPad 允许您通过触摸板手机控制您的 PC。您可以轻松连接到您的桌面,无需进行任何配置,您只需要激活驱动程序(也包含源代码)并启用标准的 ActiveSync。
您可以在演示文稿中使用它,或者控制您的媒体中心。
引言
我尝试解释为移动设备编写代码是多么简单。该项目包含两个解决方案,需要两个程序,因为一个程序会拦截移动设备上的鼠标移动,而第二个程序则与桌面进行交互。
我解决了一些关于
- ActiveSync
- OpenNETCF Mobile Ink
- 鼠标钩子
- Marshal
- P/Invoke
- Socket(套接字)
- 字节序列化/反序列化
- 注册表
开发者要求
首先,要部署任何 WM 应用程序,您需要 Windows Mobile 6 Professional and Standard Software Development Kits Refresh[^]。
在这里,您可以找到您系统的所有要求,并且可以选择平台 Pro 或 Standard 或两者都选。您至少需要其中之一。我推荐您使用“Professional Windows Mobile 6 Professional SDK Refresh.msi”,这是 Pocket PC 的新 SDK。
请单独检查每个应用程序的系统要求。
总之,我添加了简要的系统要求
- Microsoft Visual Studio 2005
- Microsoft Visual Studio 2005 SP1 [^]
- Microsoft .NET Compact Framework v2 SP2 [^]
- 对于 Windows XP - ActiveSync 4.5 [^]
- 对于 Windows Vista - Windows Mobile Device Center [^]
其他要求
对于移动墨迹,我更喜欢使用免费的 Mobile Ink Library。OpenNETCF Mobile Ink 是一个提供 WM 6 Ink 支持的组件,可以在 此处 [^] 获取,并根据 MIT X11 许可证 [^] 发布。
我使用这个库,首先因为它免费且开源,而且非常易于使用,我将向您展示如何使用它。
使用移动端代码
移动解决方案名为 MobileTouchPad
,您可以在 _WM_ 文件夹下找到它。移动应用程序将类似于下图。
OpenNETCF Mobile Ink
如上所示,我使用它是因为它可以为触摸提供一些酷炫的效果。目前,我编写了触摸的线条,并在释放屏幕后将其清除。使用此组件非常简单,在项目中使用的步骤是
添加 Using 和 Reference
using OpenNETCF.WindowsMobile.Ink;
using OpenNETCF.WindowsMobile.Ink.Interfaces;
安装下载的 OpenNETCF Mobile Ink 文件后,您可以在此处找到它(您也可以在安装目录中找到源代码)。
添加一个 Panel
在您的窗体上添加一个 Panel 或 PictureBox,它将成为您的触摸板,我将其命名为 panelTouchPad
。
添加 Overlay
在您的 Panel 上添加一个 overlay
。
IInkOverlay overlay;
添加 Load 事件处理程序
在加载窗体时,将 Panel 附加到 overlay
。
overlay.hWnd = pictureBox1.Handle;
overlay.Enabled = true;
添加 Event Stroke
这将启用 ink
。
overlay = Ink.CreateInstance();
overlay.SetEventInterest(InkCollectorEventInterest.Stroke, true);
调整屏幕
在 Resize 窗体中,检索屏幕坐标并调整 panelTouchPad
以适应屏幕。
Rectangle oScreen = Screen.PrimaryScreen.WorkingArea;
panelTouchPad.Location = new System.Drawing.Point(0, 0);
panelTouchPad.Size = new System.Drawing.Size
(oScreen.Size.Width, oScreen.Size.Height - oScreen.Y);
清除屏幕
overlay.Enabled = false;
overlay.Ink = InkDisp.CreateInstance();
overlay.Enabled = true;
好了,第一步已经结束,现在我们有一个非常简单的移动画板。
鼠标移动
要简单地拦截鼠标移动,我使用 panelTouchPad
的 MouseMove
的 EventHandler
。在这里,我决定如何将数据发送到桌面。我每次都保存最后一个点,并且只发送一个步进移动到桌面。数据可以是 (+1,0) (-1,1) (0,-1) 等。
Point pointDirection = new Point();
pointDirection.X = e.X - LastPoint.X ;
pointDirection.Y = e.Y - LastPoint.Y ;
SendData(pointDirection);
LastPoint.X = e.X;
LastPoint.Y = e.Y;
按钮按下和双击
要拦截按钮按下,您需要添加 KeyDown
和 KeyPress
的 KeyEventHandler
,并以零移动发送。
private void FormTouchPad_KeyDown(object sender, KeyEventArgs e)
{
m_buttonState = CommonStruct.MouseButtonState.ButtonPressed;
SendData(new Point(0,0));
}
private void FormTouchPad_KeyUp(object sender, KeyEventArgs e)
{
m_buttonState = CommonStruct.MouseButtonState.None;
SendData(new Point(0, 0));
}
要拦截双击,请为 panelTouchPad
添加 DoubleClick
事件,并以零移动发送。
m_buttonState = CommonStruct.MouseButtonState.DblClick;
SendData(new Point(0,0));
如您在此处所见,我为两个解决方案使用了通用的 CommonStruct
结构。
这是按钮状态的 enum
。
public enum MouseButtonState
{
None = 0,
ButtonClick,
ButtonPressed,
DblClick
}
这是按钮操作的 struct
。
public struct TouchPro
{
public Point point;
public MouseButtonState buttonState;
}
这个通用结构在 Common.cs 中。
桌面 IP
信息:要与桌面通信,您需要同步设备或模拟器。为此,您需要安装 ActiveSync 4.5 作为 Windows XP 的系统要求,以及 Windows Vista 的 Windows Mobile Device Center。
同步后,您只需将连接设置为 DMA 即可,使用此选项,您可以动态检索桌面 IP。
为了检索桌面 IP,我使用了一些由 ActiveSync 启用的注册表项。这些项存储在 [HKEY_LOCAL_MACHINE\Comm\Tcpip\Hosts\ppp_peer]
中,或者如果不存在,则存储在 [HKEY_LOCAL_MACHINE\Comm\Tcpip\Hosts\dtpt_peer]
中。如果您遇到问题,我建议您参考这个 博客 [^]。
使用模拟器
您可以使用模拟器来测试项目,但显然鼠标交互可能会有些困难。
注意:如果您使用模拟器,则必须激活基座。
在 Visual Studio 2005 中,打开 **Tools** 菜单并选择 **Device Emulator Manager**。在 Device emulator manager 中,选择您当前的模拟器并选择 **cradle**。
ActiveSync 启动后,您可能会注意到一个小的托盘图标,类似于网络图标,带有向左和向右旋转的加号。
序列化/反序列化
使用套接字,我需要将我的类转换为 byte[]
。通常在桌面上,我使用 BinaryFormatter
和 MemoryStream
,但在 WM 中,该引用丢失了……不过,我找到了另一种方法,使用 Marshaling。这是我在我的两个项目(可以在 Common.cs 中找到)中使用的 CommonConvertion
。
class CommonConvertion
{
public static byte[] StructureToByteArray(object obj)
{
int Length = Marshal.SizeOf(obj);
byte[] bytearray = new byte[Length];
IntPtr ptr = Marshal.AllocHGlobal(Length);
Marshal.StructureToPtr(obj, ptr, false);
Marshal.Copy(ptr, bytearray, 0, Length);
Marshal.FreeHGlobal(ptr);
return bytearray;
}
public static void ByteArrayToStructure(byte[] bytearray, ref object obj)
{
int Length = Marshal.SizeOf(obj);
IntPtr ptr = Marshal.AllocHGlobal(Length);
Marshal.Copy(bytearray, 0, ptr, Length);
obj = Marshal.PtrToStructure(ptr, obj.GetType());
Marshal.FreeHGlobal(ptr);
}
}
连接并发送数据到桌面
为了将数据发送到桌面,我更倾向于使用 TCP/IP 而不是 Web 服务、Rapi 等,因为它更简单(我认为)。
TCP 用法
定义一个 TcpClient
和一个 NetworkStream
,它们在应用程序生命周期内一直使用。
private TcpClient m_client;
private NetworkStream m_stream;
在构造函数中,添加到服务器的连接并打开到它的流。
m_client = new TcpClient(server, port);
m_stream = m_client.GetStream();
如果失败(桌面服务器已关闭),应用程序会在您每次触摸屏幕时尝试连接到服务器,并向您显示一个消息框……您可以继续不连接,或者继续在其上绘制……。
最后,我们按照前面在 MouseMove
中看到的发送数据。这里的代码显示了一个新方法 SendData
。这是一个我管理数据并将其发送到桌面的方法。
private void SendData(Point pointDirection)
{
...
CommonStruct.TouchPro AddMove = new CommonStruct.TouchPro();
AddMove.point = pointDirection;
AddMove.buttonState = m_buttonState;
object objTmp = (object)AddMove;
Byte[] data = CommonConvertion.StructureToByteArray(AddMove);
m_networkstream.Write(data, 0, data.Length);
...
}
使用桌面端代码
解决方案名为 DriverMobileTouchPad
,您可以在 _x86_ 文件夹下找到它。这是一个显示其界面的屏幕截图。在这里,您必须激活服务器以等待移动设备连接。
移动设备有多种限制,其中最重要的是屏幕分辨率低。为了避免这个问题,我添加了更改光标速度的可能性。
连接并接收来自移动设备的数据
TCP 用法
在窗体中,我创建了一个服务器并在某个端口上等待连接。
m_tcpserver = new TcpListener(IPAddress.Any, 5000);
m_tcpserver.Start();
m_tcpserver.BeginAcceptTcpClient
( new AsyncCallback(DoAcceptTcpClientCallback), m_tcpserver);
警告:请记住在您的防火墙上打开端口 5000。
当它连接到客户端时,它开始在 DoAcceptTcpClientCallback
中从打开的流中读取 stream.Read
,并将其转换为我的通用 struct
。读取数据后,使用 CommonConvertion
进行反序列化,如这里显示的序列化/反序列化。
CommonStruct.TouchPro AddMove = new CommonStruct.TouchPro();
object objTmp = new object();
objTmp = (object)AddMove;
CommonConvertion.ByteArrayToStructure(bytes, iBufflen, ref objTmp);
AddMove = (CommonStruct.TouchPro)objTmp;
鼠标交互
为了交互,我创建了一个名为 MouseMov
的类。在这里,我使用 P/Invoke 来发送单击(按下和释放)和双击。
[DllImport("user32.dll")]
private static extern void mouse_event
(UInt32 dwFlags, UInt32 dx, UInt32 dy, UInt32 dwData, IntPtr dwExtraInfo);
private const UInt32 MOUSEEVENTF_LEFTDOWN = 0x0002;
private const UInt32 MOUSEEVENTF_LEFTUP = 0x0004;
internal static void SendUp()
{
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, new System.IntPtr());
}
internal static void MoveMouse(Point p)
{
Cursor.Position = new Point(Cursor.Position.X + p.X, Cursor.Position.Y + p.Y);
}
MoveMouse
是一个简单的光标移动。
internal static void SendDown()
{
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, new System.IntPtr());
}
好了,我们终于完成了。尝试运行我添加的两个解决方案,您可以看到代码在运行。让我知道您遇到的问题以及您的想法。玩得开心!
链接
我发现了这些链接非常有帮助
- MSDN: Windows Mobile Ink [^]
- OpenNETCF: Mobile Ink Library [^]
- MSDN: P/Invoke and Marshaling [^]
- 博客:Windows Mobile 设备上的 Hosts 文件等效项 [^]
历史
- 2008 年 11 月 10 日 - 首次发布 - v 10 2008