ELAN触控板改手写板实验

原理:逆向了ETDDeviceInformation.exe中取内核原始PS2数据并计算出多点触摸坐标的部分,然后使用Microsoft.Ink墨迹库来做文字识别。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;

namespace InkTest
{
    class ETD
    {
        [DllImport("kernel32")]
        static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode, byte[] lpInBuffer, uint nInBufferSize, byte[] lpOutBuffer, uint nOutBufferSize, out uint lpBytesReturned, IntPtr lpOverlapped);
        [DllImport("kernel32")]
        static extern IntPtr CreateFileA(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);
        [DllImport("kernel32")]
        static extern IntPtr OpenEventA(uint dwDesiredAccess, bool bInheritHandle, string lpName);
        [DllImport("kernel32")]
        static extern bool ResetEvent(IntPtr hEvent);
        [DllImport("kernel32")]
        static extern uint WaitForSingleObject(IntPtr hHandle, int dwMilliseconds);

        static public void Init()
        {
            var t = new Thread(ETDThread);
            t.Start();
        }
        static public int X;
        static public int Y;

        static void ETDThread()
        {
            IntPtr hDevice = CreateFileA(@"\\.\ETD", 0xC0000000, 0, IntPtr.Zero, 3, 0, IntPtr.Zero);
            IntPtr hEvent = OpenEventA(0x1f0003, false, @"Global\ETDOther_GetKernelData");            
            byte[] ioctlBuf = new byte[124814];
            uint nRet = (uint)ioctlBuf.Length;
            Array.Copy(BitConverter.GetBytes((short)0x608), ioctlBuf, 2);
            DeviceIoControl(hDevice, 0x9c412000, ioctlBuf, nRet, ioctlBuf, nRet, out nRet, IntPtr.Zero);
            int bufIndex = BitConverter.ToInt32(ioctlBuf, 0x406);
            byte[] data = new byte[6];
            while (true)
            {
                WaitForSingleObject(hEvent, -1);
                ResetEvent(hEvent);
                Array.Clear(ioctlBuf, 0, ioctlBuf.Length);
                nRet = (uint)ioctlBuf.Length;
                Array.Copy(BitConverter.GetBytes((short)0x708), ioctlBuf, 2);
                Array.Copy(BitConverter.GetBytes(bufIndex), 0, ioctlBuf, 2, 4);
                DeviceIoControl(hDevice, 0x9c412000, ioctlBuf, nRet, ioctlBuf, nRet, out nRet, IntPtr.Zero);
                int count = BitConverter.ToInt32(ioctlBuf, 10);
                bufIndex = BitConverter.ToInt32(ioctlBuf, 0x480e);

                for (int i = 0; i < count; ++i)
                {
                    byte d1 = ioctlBuf[14 + i * 18 + 4];
                    int d4 = BitConverter.ToInt32(ioctlBuf, 14 + i * 18 + 13);
                    byte d5 = ioctlBuf[14 + i * 18 + 17];
                    data[d4] = d5;
                    if (d4 == 5)
                    {
                        if (d1 == 16 && data[1] == 0) //release
                        {
                            X = Y = 0;
                        }
                        else if (d1 == 17)
                        {
                            X = (data[1] & 0xf) * 0x100 + data[2];
                            Y = (data[4] & 0xf) * 0x100 + data[5];
                        }
                    }
                }
            }
        }
    }
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.Ink;
using System.IO;
using System.Runtime.InteropServices;


namespace InkTest
{
    public partial class Form1 : Form
    {
        List<Point> mPoints = new List<Point>();
        Ink mInk = new Ink();
        int mLastX, mLastY;
        DateTime mLastTime = DateTime.MaxValue;
        [DllImport("user32")]
        static extern int GetKeyState(int nVirtKey);

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            ETD.Init();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            //this.Hide();
            if (GetKeyState(0xA0) > 0)
                return;
            if (ETD.X == 0 && ETD.Y == 0)
            {
                if (mLastX != 0 && mLastY != 0)
                {

                    mInk.Strokes.Add(mInk.CreateStroke(mPoints.ToArray()));
                    mPoints.Clear();
                    mLastTime = DateTime.Now;
                }
                else if (DateTime.Now - mLastTime > TimeSpan.FromSeconds(0.5))
                {
                    string str = mInk.Strokes.ToString();
                    mInk.DeleteStrokes();
                    mLastTime = DateTime.MaxValue;
                    Clipboard.SetText(str);
                    SendKeys.Send("^V");
                }
            }
            else
            {
                mPoints.Add(new Point(ETD.X, -ETD.Y));
            }
            mLastX = ETD.X;
            mLastY = ETD.Y;
            this.Text = string.Format("{0},{1}", ETD.X, ETD.Y);
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Environment.Exit(0);
        }
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *