From 530c4e603d5b544becb37f380f9a6e48ac952ed4 Mon Sep 17 00:00:00 2001 From: jynychen Date: Wed, 7 Aug 2019 03:27:05 +0800 Subject: [PATCH] init v0.7 --- CHANGELOG | 4 + README.md | 0 makerelease.bat | 9 + resource.h | 14 ++ tpmiddle.cpp | 427 +++++++++++++++++++++++++++++++++++++++ tpmiddle.rc | Bin 0 -> 4572 bytes tpmiddle.sln | 23 +++ tpmiddle.vcxproj | 124 ++++++++++++ tpmiddle.vcxproj.filters | 32 +++ 9 files changed, 633 insertions(+) create mode 100644 CHANGELOG delete mode 100644 README.md create mode 100644 makerelease.bat create mode 100644 resource.h create mode 100644 tpmiddle.cpp create mode 100644 tpmiddle.rc create mode 100644 tpmiddle.sln create mode 100644 tpmiddle.vcxproj create mode 100644 tpmiddle.vcxproj.filters diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..a2f65e8 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,4 @@ +Release 0.7: +* Refactored Code, Added normal mode (activate with any command line parameter in *.LNK link files) which does just forward the events of all input devices (e.g. trackpoint and trackpad, this happens practically), added debug code and debug for delta events only, updated copyright messages and versions, updated VS project for relative paths of the Synaptics SDK. +* Device will disable events for middle button events permanently (at least as long machine is not rebooted) to avoid multiple events (default event from driver and ours). Filtering events in NORMAL_MODE when multiple devices are connected (only on chnages). Added reset only mode with 2 parameters to restore original middle button behavior for the driver. +* Added normal command line parsing with parameters, settings properties is done only in resetOnly and NORMAL_MODE diff --git a/README.md b/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/makerelease.bat b/makerelease.bat new file mode 100644 index 0000000..1ce01ef --- /dev/null +++ b/makerelease.bat @@ -0,0 +1,9 @@ +@ECHO OFF + +SET BINDIR=C:\Program Files\7-Zip +SET EXE=%BINDIR%\7z.exe + +"%EXE%" a -tzip tpmiddle CHANGELOG *.bat *.h *.cpp *.rc *.sln *.vcxproj *.filters + + + diff --git a/resource.h b/resource.h new file mode 100644 index 0000000..819c23c --- /dev/null +++ b/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by tpmiddle.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/tpmiddle.cpp b/tpmiddle.cpp new file mode 100644 index 0000000..705e299 --- /dev/null +++ b/tpmiddle.cpp @@ -0,0 +1,427 @@ +#include +#include +#include +#include + +// To work correctly ThinkPad must be configured in the "Only Classic TrackPoint Mode" + +#if defined(_WIN32) || defined(_WIN64) + #define snprintf _snprintf + #define vsnprintf _vsnprintf + #define strcasecmp _stricmp + #define strncasecmp _strnicmp +#endif + +#include "SynKit.h" +int connectionTypes[] = { SE_ConnectionAny }; +char* connectionTypeNames[] = { "(any connection)" }; +int connectionTypeCount = 1; + +int deviceTypes[] = {SE_DeviceMouse, SE_DeviceTouchPad, SE_DeviceWheelMouse, SE_DeviceIBMCompatibleStick, + SE_DeviceStyk, SE_DeviceFiveButtonWheelMouse, SE_DevicecPad}; +char* deviceTypeNames[] = {"Mouse", "TouchPad", "WheelMouse", "IBMCompatibleStick", "Styk", "FiveButtonWheelMouse", "cPad"}; +int deviceTypeCount = 7; + +int wantedDeviceTypes[] = { SE_DeviceIBMCompatibleStick, SE_DeviceStyk, SE_DeviceTouchPad }; +char* wantedDeviceTypeNames[] = {"IBMCompatibleStick", "Styk", "TouchPad"}; +int wantedDeviceTypeCount = 3; + +static bool NORMAL_MODE = 0; +static bool DELTA_DEBUG = 0; +//#define DISABLE_ALL_EVENTS + +void listDevices(ISynAPI *pAPI) +{ +#ifdef _DEBUG + __time64_t ltime; + _time64( <ime ); + printf("Device list: %s", _ctime64( <ime ) ); + + for (int conn = 0; conn < connectionTypeCount; ++conn) + for (int dev = 0; dev < deviceTypeCount; ++dev) + { + long handle = -1; + + while (pAPI->FindDevice(connectionTypes[conn], deviceTypes[dev], &handle) == SYN_OK) + { + printf("Found: connection %d, device %d, %s on %s\n", conn, dev, deviceTypeNames[dev], connectionTypeNames[conn]); + } + } +#endif +} + +#define MAX_DEVICE_COUNT 100 + +struct deviceState +{ + ISynDevice* device; + HANDLE event; + BOOL isMiddleClicked; + ULONGLONG middleClickTimeout; + + SynDeviceType deviceType; +}; +deviceState deviceStates[MAX_DEVICE_COUNT]; +int connectedDeviceCount = 0; + +HANDLE hEvents[MAX_DEVICE_COUNT + 1]; + +void connectDevices(ISynAPI *pAPI, bool resetOnly = false) +{ +#ifdef _DEBUG + __time64_t ltime; + _time64( <ime ); + printf("Connecting to devices: %s", _ctime64( <ime ) ); +#endif + + connectedDeviceCount = 0; + for (int conn = 0; conn < connectionTypeCount; ++conn) + for (int dev = 0; dev < wantedDeviceTypeCount; ++dev) + { + long handle = -1; + + while (pAPI->FindDevice(connectionTypes[conn], wantedDeviceTypes[dev], &handle) == SYN_OK) + { +#ifdef _DEBUG + printf("Connecting to: connection %d, device %d, logical_id %d, %s on %s\n", conn, dev, connectedDeviceCount, wantedDeviceTypeNames[dev], connectionTypeNames[conn]); +#endif + if (pAPI->CreateDevice(handle, &deviceStates[connectedDeviceCount].device) != SYN_OK) + { +#ifdef _DEBUG + printf("Cannot obtain a device object.\n"); +#else + MessageBox(NULL, "Cannot obtain a device object.", "TP Middle", MB_ICONERROR | MB_OK); +#endif + continue; + } + + char eventName[100]; + sprintf(eventName, "tpmiddleDevice%d_%d", GetCurrentProcessId(), connectedDeviceCount); + deviceStates[connectedDeviceCount].event = CreateEvent(0, 0, 0, eventName); + deviceStates[connectedDeviceCount].device->SetEventNotification(deviceStates[connectedDeviceCount].event); + hEvents[connectedDeviceCount + 1] = deviceStates[connectedDeviceCount].event; + + deviceStates[connectedDeviceCount].isMiddleClicked = FALSE; + deviceStates[connectedDeviceCount].middleClickTimeout = 0; + deviceStates[connectedDeviceCount].device->GetProperty(SP_DeviceType, (long *)&deviceStates[connectedDeviceCount].deviceType); + + if (NORMAL_MODE || resetOnly) + { + long lMask; + deviceStates[connectedDeviceCount].device->GetProperty(SP_MiddleButtonAction, &lMask); + if (resetOnly) + { + lMask &= ~SF_ActionAll; + lMask |= SF_ActionAuxilliary; + } + if (NORMAL_MODE) lMask &= ~SF_ActionAll; + deviceStates[connectedDeviceCount].device->SetProperty(SP_MiddleButtonAction, lMask); + } + + ++connectedDeviceCount; + } + } +} + +void disconnectDevices(ISynAPI *pAPI) +{ +#ifdef _DEBUG + __time64_t ltime; + _time64( <ime ); + printf("Disconnecting devices: %s", _ctime64( <ime ) ); +#endif + + for (int i = 0; i < connectedDeviceCount; ++i) + { + CloseHandle(deviceStates[i].event); + deviceStates[i].device->Release(); + deviceStates[i].device = NULL; + } + + connectedDeviceCount = 0; +} + +void sendMiddleMouse(int devNum, bool buttondown) +{ + static bool lastbuttondown = false; + if (NORMAL_MODE && buttondown == lastbuttondown) return; + lastbuttondown = buttondown; + INPUT Input={0}; + + ZeroMemory(&Input,sizeof(INPUT)); + Input.type = INPUT_MOUSE; + Input.mi.dwFlags = MOUSEEVENTF_MIDDLEUP; + if (buttondown) Input.mi.dwFlags = MOUSEEVENTF_MIDDLEDOWN; + SendInput(1,&Input,sizeof(INPUT)); +#ifdef _DEBUG + __time64_t ltime; + _time64( <ime ); + printf("Packet: device %d, sendMiddleMouse=%i, %s", devNum, buttondown, _ctime64( <ime )); +#endif +} + +// Derived from http://www.cmake.org/pipermail/cmake/2004-June/005172.html +char** CommandLineToArgvA(LPSTR lpCmdLine, int& argc) +{ + // parse a few of the command line arguments + // a space delimites an argument except when it is inside a quote + + char** argv; + unsigned int i; + int j; + + argc = 1; + int pos = 0; + for (i = 0; i < strlen(lpCmdLine); i++) + { + while (lpCmdLine[i] == ' ' && i < strlen(lpCmdLine)) i++; + if (lpCmdLine[i] == '\"') + { + i++; + while (lpCmdLine[i] != '\"' && i < strlen(lpCmdLine)) + { + i++; + pos++; + } + argc++; + pos = 0; + } + else + { + while (lpCmdLine[i] != ' ' && i < strlen(lpCmdLine)) + { + i++; + pos++; + } + argc++; + pos = 0; + } + } + + argv = (char**)malloc(sizeof(char*)* (argc+1)); + + argv[0] = (char*)malloc(1024); + ::GetModuleFileName(0, argv[0],1024); + + for(j=1; j= 2) + { + if (strcasecmp((const char*)argv[1], "-r") == 0) resetOnly = true; + if (strcasecmp((const char*)argv[1], "-n") == 0) NORMAL_MODE = 1; + } +#ifdef _DEBUG + printf("argc=%i, NORMAL_MODE=%i, resetOnly=%i\n", argc, NORMAL_MODE, resetOnly); +#else +#if 0 + char s[100]; + wsprintf(s, "argc=%i, NORMAL_MODE=%i, resetOnly=%i", argc, NORMAL_MODE, resetOnly); + MessageBox(NULL, s, "NORMAL_MODE", MB_OK); +#endif +#endif + ISynAPI *pAPI = NULL; + + int counter = 0; + while (true) + { + HRESULT ret = SynCreateAPI(&pAPI); + + if (ret == SYN_OK) + break; + +#ifdef _DEBUG + printf("Cannot obtain an API object: 0x%lx. Retrying...\n", ret); +#endif + + ++counter; + + if (counter == 60) + { +#ifdef _DEBUG + printf("Initialization failed.\n", ret); + getchar(); +#else + char buf[2000]; + sprintf(buf, "Cannot obtain an API object: 0x%lx.", ret); + MessageBox(NULL, buf, "TP Middle", MB_ICONERROR | MB_OK); +#endif + exit(-1); + } + + Sleep(1000); + } + + char eventName[100]; + sprintf(eventName, "tpmiddleApi%d", GetCurrentProcessId()); + hEvents[0] = CreateEvent(0, 0, 0, eventName); + pAPI->SetEventNotification(hEvents[0]); + + listDevices(pAPI); + + connectDevices(pAPI, resetOnly); + if (resetOnly) + { + disconnectDevices(pAPI); + pAPI->Release(); + exit(0); + } + + SynPacket Packet; + bool deviceOldMiddleClick = FALSE; + while (true) + { + DWORD res = MsgWaitForMultipleObjects(connectedDeviceCount + 1, hEvents, FALSE, INFINITE, QS_ALLINPUT); + if (res == WAIT_OBJECT_0) + { + listDevices(pAPI); + disconnectDevices(pAPI); + connectDevices(pAPI); + } + else if (res <= WAIT_OBJECT_0 + connectedDeviceCount) + { + int devNum = res - WAIT_OBJECT_0 - 1; + while (deviceStates[devNum].device->LoadPacket(Packet) != SYNE_FAIL) + { + bool deviceMiddleClick = FALSE; + if (deviceStates[devNum].deviceType == SE_DeviceTouchPad) + { + deviceMiddleClick = (Packet.ButtonState() & SF_ButtonExtended3) == SF_ButtonExtended3; + } + else + { + deviceMiddleClick = (Packet.ButtonState() & SF_ButtonMiddle) == SF_ButtonMiddle; + } + +#if defined(_DEBUG) && !defined(DISABLE_ALL_EVENTS) + __time64_t ltime; + _time64( <ime ); + + + if (deviceStates[devNum].deviceType == SE_DeviceTouchPad) + { + if (!DELTA_DEBUG || (DELTA_DEBUG && !!deviceMiddleClick != !!deviceStates[devNum].isMiddleClicked)) + printf("Packet: device %d, state %x, deviceIsM: %d, isM: %d, %s", devNum, Packet.ButtonState(), deviceMiddleClick, deviceStates[devNum].isMiddleClicked, _ctime64(<ime)); + } + else + { + if (!DELTA_DEBUG || (DELTA_DEBUG && !!deviceMiddleClick != !!deviceStates[devNum].isMiddleClicked)) + printf("Packet: device %d, state %x, xyz %d %d %d, deviceIsM: %d, isM: %d, %s", devNum, Packet.ButtonState(), Packet.XDelta(), + Packet.YDelta(), Packet.ZDelta(), deviceMiddleClick, deviceStates[devNum].isMiddleClicked, _ctime64(<ime)); + } +#endif + if ((!deviceStates[devNum].isMiddleClicked) && deviceMiddleClick) + { + deviceStates[devNum].isMiddleClicked = TRUE; + deviceStates[devNum].middleClickTimeout = GetTickCount64() + GetDoubleClickTime() / 2; + if (NORMAL_MODE) + { + sendMiddleMouse(devNum, true); + } + else + { +#ifdef _DEBUG + __time64_t ltime; + _time64( <ime ); + printf("Middle click started: device %d, %s", devNum, _ctime64( <ime ) ); +#endif + } + } + + if (deviceStates[devNum].isMiddleClicked && !deviceMiddleClick) + { + deviceStates[devNum].isMiddleClicked = FALSE; + if (NORMAL_MODE) + { + sendMiddleMouse(devNum, false); + } + else + { + if (deviceStates[devNum].middleClickTimeout > GetTickCount64() && false) + { + Sleep(50); + sendMiddleMouse(devNum, true); + Sleep(50); + sendMiddleMouse(devNum, false); +#ifdef _DEBUG + __time64_t ltime; + _time64( <ime ); + printf("Middle click finished: device %d, %s", devNum, _ctime64( <ime ) ); +#endif + } + else + { +#ifdef _DEBUG + __time64_t ltime; + _time64( <ime ); + printf("Middle click timeouted: device %d, %s", devNum, _ctime64( <ime ) ); +#endif + } + } + } + } + } + else if (res == WAIT_OBJECT_0 + connectedDeviceCount + 1) + { + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + else + return FALSE; + } + + disconnectDevices(pAPI); + pAPI->Release(); + + return 0; +} diff --git a/tpmiddle.rc b/tpmiddle.rc new file mode 100644 index 0000000000000000000000000000000000000000..a0e2ad359de8317d3f7f682018852123b3f45e24 GIT binary patch literal 4572 zcmd6rT~8W86o$`rlm3S-CQX}K1+_6=Dj+qY7(r|k6M`aYs$c-4P5Q5U-}ZTD8FrUl zY^1#)lVN7g%=!M9S$_XowN(r3z;5iq2G+MBy=x<2O<+TNu(sW@D%uBHU{`i&J^BFn zh_M4~z$m;2W*5u@R-$%e_ncX=*Y*l7t8QEZ+GF>Y(;as z8L75`R*7&?Q&;WiKI3U+LKDjSV3!=mV)-#HjrXY^XXUfs*Qj2=TC*}=`#b1faWz4! zVBE56?3v}qb+(MDY6=WVBS+zaKJ<+wNaYYL2O3uz$pAofTm5-#HCDHnv61|kq zlB>KO7iV57c`d81q@zu?Q;++3vF2VnKkAm(T|PwPKK}4wS z-zCq49pCYAVFsMoBYVqJX98kw**57K^Nx$^+A;J>xiFu}j1<_@t_Qm=?}cs?IHulq=~Dv41;zVPe@ zGOBHiaUyFqc)1*5wWJKuepo4!r#$EE+*e(#VOLouhXf=1tvA>e9=buZOZ?PB*8WsB zW>fQ7k)#@Gv*k28=Qo+x5l&WZ^1FU);zzw^WP==X>(z5l73tY`;;zl=61Z-S96oQm z%JPlXDYKt;&aU38Z|QnR4Y()Lwhpa%M~7tyOX~qW5i>IbNa>vfja= zLz8V+=uh-{I3;t_bI3z;ldf@=rL#4VpY>)RFzQu5ZO#87dlmXuj=DT|kIxisS9oDG z@mhLEZ<(TdX{@1Bf%cJGNV88bvRrM%P zC~G8XG*dO5eM8UpHeRgzIWCQ~jrZ^#d+tjo{UV9eTdcV>lSF>}*RNi^5TF0*^|o9r YJH(}tgtOzjN43%aGU+eewBJSP51VQo1poj5 literal 0 HcmV?d00001 diff --git a/tpmiddle.sln b/tpmiddle.sln new file mode 100644 index 0000000..d7cba21 --- /dev/null +++ b/tpmiddle.sln @@ -0,0 +1,23 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tpmiddle", "tpmiddle.vcxproj", "{8F8F9E71-4E43-419D-8916-6BACAF30DBC4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + RelDebug|Win32 = RelDebug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8F8F9E71-4E43-419D-8916-6BACAF30DBC4}.Debug|Win32.ActiveCfg = Debug|Win32 + {8F8F9E71-4E43-419D-8916-6BACAF30DBC4}.Debug|Win32.Build.0 = Debug|Win32 + {8F8F9E71-4E43-419D-8916-6BACAF30DBC4}.RelDebug|Win32.ActiveCfg = RelDebug|Win32 + {8F8F9E71-4E43-419D-8916-6BACAF30DBC4}.RelDebug|Win32.Build.0 = RelDebug|Win32 + {8F8F9E71-4E43-419D-8916-6BACAF30DBC4}.Release|Win32.ActiveCfg = Release|Win32 + {8F8F9E71-4E43-419D-8916-6BACAF30DBC4}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tpmiddle.vcxproj b/tpmiddle.vcxproj new file mode 100644 index 0000000..522a397 --- /dev/null +++ b/tpmiddle.vcxproj @@ -0,0 +1,124 @@ + + + + + Debug + Win32 + + + RelDebug + Win32 + + + Release + Win32 + + + + {8F8F9E71-4E43-419D-8916-6BACAF30DBC4} + tpmiddle + + + + Application + true + MultiByte + + + Application + false + true + MultiByte + + + Application + false + true + MultiByte + + + + + + + + + + + + + + + + Include;$(IncludePath) + Lib;$(LibraryPath) + + + Include;$(IncludePath) + + + D:\mwrobel\cpp\synaptics\Include;$(IncludePath) + + + Lib;$(LibraryPath) + + + D:\mwrobel\cpp\synaptics\Lib;$(LibraryPath) + + + + Level3 + Disabled + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + true + SynCom.lib;%(AdditionalDependencies) + Console + + + + + Level3 + MaxSpeed + true + true + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + true + true + true + SynCom.lib;%(AdditionalDependencies) + Windows + + + + + Level3 + MaxSpeed + true + true + _DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + true + true + true + SynCom.lib;%(AdditionalDependencies) + Console + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tpmiddle.vcxproj.filters b/tpmiddle.vcxproj.filters new file mode 100644 index 0000000..8880464 --- /dev/null +++ b/tpmiddle.vcxproj.filters @@ -0,0 +1,32 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Header Files + + + + + Resource Files + + + \ No newline at end of file