├── TabletDriverService
├── config
│ ├── user.cfg
│ ├── init.cfg
│ ├── tablet.cfg
│ └── wacom.cfg
├── ProcessCommand.h
├── stdafx.cpp
├── targetver.h
├── Vector2D.h
├── TabletBenchmark.h
├── TabletDriverService.vcxproj.user
├── PositionRingBuffer.h
├── TabletSettings.cpp
├── ScreenMapper.h
├── TabletFilterPeak.h
├── TabletFilter.h
├── TabletSettings.h
├── stdafx.h
├── TabletFilterNoiseReduction.h
├── Vector2D.cpp
├── CommandLine.h
├── HIDDevice.h
├── USBDevice.h
├── TabletBenchmark.cpp
├── TabletFilter.cpp
├── TabletFilterSmoothing.h
├── TabletFilterPeak.cpp
├── PositionRingBuffer.cpp
├── VMulti.h
├── Tablet.h
├── Logger.h
├── ScreenMapper.cpp
├── TabletFilterNoiseReduction.cpp
├── startuplog.txt
├── TabletDriverService.vcxproj.filters
├── TabletFilterSmoothing.cpp
├── Logger.cpp
├── HIDDevice.cpp
├── CommandLine.cpp
├── USBDevice.cpp
├── docs
│ └── VMulti_Report_Descriptor.txt
├── Tablet.cpp
├── VMulti.cpp
└── TabletDriverService.vcxproj
├── images
├── 1.png
├── 2.png
├── 3.png
├── 4.png
├── 5.png
├── 6.png
├── 7.png
├── Fun.png
├── simple.png
├── smooth.png
├── straight.png
├── formula_example.png
├── prediction_fun.png
├── prediction_straight.png
├── prediction_simplesmooth.png
├── prediction_formula_example.png
├── Big latency and big prediction.png
├── Straight - Pretty good realtime accurate.png
└── Smooth 2 + prediction = accurate with small overshot.png
├── TabletDriverGUI
├── Resources
│ ├── AppIcon.ico
│ └── AppIcon.xcf
├── Properties
│ ├── Settings.settings
│ ├── Settings.Designer.cs
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ └── Resources.resx
├── App.xaml
├── App.config
├── TabletDriverGUI.csproj.user
├── NativeMethods.cs
├── Utils.cs
├── WacomArea.xaml
├── app.manifest
├── App.xaml.cs
├── Area.cs
├── WacomArea.xaml.cs
├── Configuration.cs
├── TabletDriverGUI.csproj
├── VersionHelper.cs
└── TabletDriver.cs
├── .github
└── ISSUE_TEMPLATE.md
├── .gitignore
└── TabletDriver.sln
/TabletDriverService/config/user.cfg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/images/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devocub/TabletDriver/HEAD/images/1.png
--------------------------------------------------------------------------------
/images/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devocub/TabletDriver/HEAD/images/2.png
--------------------------------------------------------------------------------
/images/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devocub/TabletDriver/HEAD/images/3.png
--------------------------------------------------------------------------------
/images/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devocub/TabletDriver/HEAD/images/4.png
--------------------------------------------------------------------------------
/images/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devocub/TabletDriver/HEAD/images/5.png
--------------------------------------------------------------------------------
/images/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devocub/TabletDriver/HEAD/images/6.png
--------------------------------------------------------------------------------
/images/7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devocub/TabletDriver/HEAD/images/7.png
--------------------------------------------------------------------------------
/images/Fun.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devocub/TabletDriver/HEAD/images/Fun.png
--------------------------------------------------------------------------------
/images/simple.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devocub/TabletDriver/HEAD/images/simple.png
--------------------------------------------------------------------------------
/images/smooth.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devocub/TabletDriver/HEAD/images/smooth.png
--------------------------------------------------------------------------------
/images/straight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devocub/TabletDriver/HEAD/images/straight.png
--------------------------------------------------------------------------------
/images/formula_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devocub/TabletDriver/HEAD/images/formula_example.png
--------------------------------------------------------------------------------
/images/prediction_fun.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devocub/TabletDriver/HEAD/images/prediction_fun.png
--------------------------------------------------------------------------------
/images/prediction_straight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devocub/TabletDriver/HEAD/images/prediction_straight.png
--------------------------------------------------------------------------------
/images/prediction_simplesmooth.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devocub/TabletDriver/HEAD/images/prediction_simplesmooth.png
--------------------------------------------------------------------------------
/TabletDriverGUI/Resources/AppIcon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devocub/TabletDriver/HEAD/TabletDriverGUI/Resources/AppIcon.ico
--------------------------------------------------------------------------------
/TabletDriverGUI/Resources/AppIcon.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devocub/TabletDriver/HEAD/TabletDriverGUI/Resources/AppIcon.xcf
--------------------------------------------------------------------------------
/images/prediction_formula_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devocub/TabletDriver/HEAD/images/prediction_formula_example.png
--------------------------------------------------------------------------------
/images/Big latency and big prediction.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devocub/TabletDriver/HEAD/images/Big latency and big prediction.png
--------------------------------------------------------------------------------
/images/Straight - Pretty good realtime accurate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devocub/TabletDriver/HEAD/images/Straight - Pretty good realtime accurate.png
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ## Hardware/software information
6 | Windows Version:
7 |
8 | Tablet Driver version:
9 |
10 | Tablet model:
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.vs
2 | /Release
3 | /Debug
4 | /TabletDriverGUI/bin/
5 | /TabletDriverGUI/obj/
6 | /TabletDriverService/Release/
7 | /TabletDriverService/Debug/
8 |
9 |
--------------------------------------------------------------------------------
/TabletDriverService/config/init.cfg:
--------------------------------------------------------------------------------
1 | Log startuplog.txt
2 | LogDirect true
3 | Include "config\tablet.cfg"
4 | Include "config\wacom.cfg"
5 | Include "config\user.cfg"
6 |
--------------------------------------------------------------------------------
/images/Smooth 2 + prediction = accurate with small overshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Devocub/TabletDriver/HEAD/images/Smooth 2 + prediction = accurate with small overshot.png
--------------------------------------------------------------------------------
/TabletDriverGUI/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/TabletDriverService/ProcessCommand.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "CommandLine.h"
3 |
4 | bool ProcessCommand(CommandLine *cmd);
5 | bool ReadCommandFile(string filename);
6 | void LogTabletArea(string text);
7 | void LogInformation();
8 | void LogStatus();
9 | bool CheckTablet();
--------------------------------------------------------------------------------
/TabletDriverGUI/App.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/TabletDriverGUI/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/TabletDriverService/stdafx.cpp:
--------------------------------------------------------------------------------
1 | // stdafx.cpp : source file that includes just the standard includes
2 | // TabletDriverService.pch will be the pre-compiled header
3 | // stdafx.obj will contain the pre-compiled type information
4 |
5 | #include "stdafx.h"
6 |
7 | // TODO: reference any additional headers you need in STDAFX.H
8 | // and not in this file
9 |
--------------------------------------------------------------------------------
/TabletDriverService/targetver.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // Including SDKDDKVer.h defines the highest available Windows platform.
4 |
5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
7 |
8 | #include
9 |
--------------------------------------------------------------------------------
/TabletDriverService/Vector2D.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | class Vector2D {
3 | public:
4 | double x;
5 | double y;
6 | Vector2D();
7 | ~Vector2D();
8 |
9 | void Set(double x, double y);
10 | void Set(Vector2D vector);
11 | void Add(double x, double y);
12 | void Add(Vector2D vector);
13 | void Multiply(double value);
14 | double Distance(Vector2D target);
15 | void CopyTo(Vector2D target);
16 | };
17 |
18 |
--------------------------------------------------------------------------------
/TabletDriverService/TabletBenchmark.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Vector2D.h"
4 |
5 | class TabletBenchmark {
6 | public:
7 | double minX;
8 | double maxX;
9 | double minY;
10 | double maxY;
11 | int totalPackets;
12 | int packetCounter;
13 | bool isRunning;
14 |
15 | TabletBenchmark();
16 | ~TabletBenchmark();
17 | void Start(int packetCount);
18 | void Update(Vector2D position);
19 | };
20 |
21 |
--------------------------------------------------------------------------------
/TabletDriverService/TabletDriverService.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | config\init.cfg
5 | WindowsLocalDebugger
6 |
7 |
--------------------------------------------------------------------------------
/TabletDriverService/PositionRingBuffer.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Vector2D.h"
4 |
5 | class PositionRingBuffer {
6 | public:
7 | Vector2D buffer[100];
8 | int maxLength;
9 | int length;
10 | int count;
11 | int index;
12 | bool isValid;
13 |
14 | void SetLength(int length);
15 | void Add(Vector2D vector);
16 | bool GetLatest(Vector2D *output, int delta);
17 | void Reset();
18 |
19 | Vector2D *operator[](std::size_t index);
20 |
21 |
22 | PositionRingBuffer();
23 | ~PositionRingBuffer();
24 | };
25 |
26 |
--------------------------------------------------------------------------------
/TabletDriverGUI/TabletDriverGUI.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | publish\
5 |
6 |
7 |
8 |
9 |
10 | en-US
11 | false
12 |
13 |
--------------------------------------------------------------------------------
/TabletDriverService/TabletSettings.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "TabletSettings.h"
3 |
4 |
5 | //
6 | // Constructor
7 | //
8 | TabletSettings::TabletSettings() {
9 | // Initial settings
10 | reportId = 0;
11 | reportLength = 8;
12 | detectMask = 0x00;
13 | ignoreMask = 0x00;
14 | maxX = 1;
15 | maxY = 1;
16 | maxPressure = 1;
17 | clickPressure = 0;
18 | width = 1;
19 | height = 1;
20 | skew = 0;
21 | type = TabletNormal;
22 | mouseWheelSpeed = 50;
23 | }
24 |
25 | //
26 | // Destructor
27 | //
28 | TabletSettings::~TabletSettings() {
29 | }
30 |
--------------------------------------------------------------------------------
/TabletDriverService/ScreenMapper.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "Tablet.h"
3 |
4 | typedef struct {
5 | double x;
6 | double y;
7 | double width;
8 | double height;
9 | } Area;
10 |
11 | class ScreenMapper {
12 | public:
13 | Tablet * tablet;
14 | Area areaTablet;
15 | Area areaScreen;
16 | Area areaVirtualScreen;
17 | double rotationMatrix[4];
18 |
19 | ScreenMapper(Tablet *t);
20 | void SetRotation(double angle);
21 | bool GetRotatedTabletPosition(double *x, double *y);
22 | bool GetScreenPosition(double *x, double *y);
23 | };
24 |
25 |
--------------------------------------------------------------------------------
/TabletDriverService/TabletFilterPeak.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "PositionRingBuffer.h"
4 | #include "Vector2D.h"
5 |
6 | class TabletFilterPeak : public TabletFilter {
7 | public:
8 |
9 | PositionRingBuffer buffer;
10 | Vector2D position;
11 | double distanceThreshold;
12 |
13 | void Reset(Vector2D targetVector);
14 | void SetTarget(Vector2D targetVector, double h);
15 | void SetPosition(Vector2D vector, double h);
16 | bool GetPosition(Vector2D *outputVector);
17 | void Update();
18 |
19 |
20 | TabletFilterPeak();
21 | ~TabletFilterPeak();
22 | };
23 |
24 |
--------------------------------------------------------------------------------
/TabletDriverService/TabletFilter.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | class TabletFilter {
3 | public:
4 | virtual void SetTarget(Vector2D vector, double h) = 0;
5 | virtual void Reset(Vector2D vector) = 0;
6 | virtual void SetPosition(Vector2D vector, double h) = 0;
7 | virtual bool GetPosition(Vector2D *vector) = 0;
8 | virtual void Update() = 0;
9 |
10 | HANDLE timer;
11 | UINT uTimerID;
12 | LPTIMECALLBACK callback;
13 | double timerInterval;
14 |
15 | bool isEnabled;
16 | bool isValid;
17 |
18 | TabletFilter();
19 |
20 | bool StartTimer();
21 | bool StopTimer();
22 |
23 | };
24 |
25 |
--------------------------------------------------------------------------------
/TabletDriverService/TabletSettings.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | class TabletSettings {
3 | public:
4 |
5 | enum TabletType {
6 | TabletNormal,
7 | TypeWacomIntuos,
8 | TypeWacom4100,
9 | TypeWacomDrivers
10 | };
11 |
12 | BYTE detectMask;
13 | BYTE ignoreMask;
14 | int maxX;
15 | int maxY;
16 | int maxPressure;
17 | int clickPressure;
18 | int keepTipDown;
19 | double width;
20 | double height;
21 | BYTE reportId;
22 | int reportLength;
23 | double skew;
24 | TabletType type;
25 | int mouseWheelSpeed;
26 |
27 | TabletSettings();
28 | ~TabletSettings();
29 | };
30 |
31 |
--------------------------------------------------------------------------------
/TabletDriverGUI/NativeMethods.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace TabletDriverGUI
5 | {
6 | public class NativeMethods
7 | {
8 | public const int HWND_BROADCAST = 0xffff;
9 | public static readonly int WM_SHOWTABLETDRIVERGUI = RegisterWindowMessage("WM_SHOWTABLETDRIVERGUI");
10 |
11 | [DllImport("user32")]
12 | public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
13 | [DllImport("user32")]
14 | public static extern int RegisterWindowMessage(string message);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/TabletDriverService/stdafx.h:
--------------------------------------------------------------------------------
1 | // stdafx.h : include file for standard system include files,
2 | // or project specific include files that are used frequently, but
3 | // are changed infrequently
4 | //
5 | #pragma once
6 | #include "targetver.h"
7 |
8 | #include
9 | #include
10 | #include
11 |
12 | #include "VMulti.h"
13 | #include "Tablet.h"
14 | #include "ScreenMapper.h"
15 |
16 | // Global variables...
17 | extern VMulti *vmulti;
18 | extern Tablet *tablet;
19 | extern ScreenMapper *mapper;
20 | extern void CleanupAndExit(int code);
21 |
22 |
23 | // TODO: reference additional headers your program requires here
24 |
--------------------------------------------------------------------------------
/TabletDriverService/TabletFilterNoiseReduction.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "PositionRingBuffer.h"
4 |
5 | class TabletFilterNoiseReduction : public TabletFilter {
6 | public:
7 |
8 | PositionRingBuffer buffer;
9 | Vector2D position;
10 | Vector2D lastTarget;
11 |
12 | int iterations;
13 | double distanceThreshold;
14 |
15 | void Reset(Vector2D position);
16 | void SetTarget(Vector2D targetVector, double h);
17 | void SetPosition(Vector2D vector, double h);
18 | bool GetPosition(Vector2D *outputVector);
19 | void Update();
20 |
21 | bool GetAverageVector(Vector2D *output);
22 | bool GetGeometricMedianVector(Vector2D *output, int iterations);
23 |
24 | TabletFilterNoiseReduction();
25 | ~TabletFilterNoiseReduction();
26 | };
27 |
28 |
--------------------------------------------------------------------------------
/TabletDriverService/Vector2D.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "Vector2D.h"
3 |
4 | //
5 | // Constructor
6 | //
7 | Vector2D::Vector2D() {
8 | x = 0;
9 | y = 0;
10 | }
11 |
12 | //
13 | // Destructor
14 | //
15 | Vector2D::~Vector2D() {
16 | }
17 |
18 | void Vector2D::Set(double x, double y) {
19 | this->x = x;
20 | this->y = y;
21 | }
22 |
23 | void Vector2D::Set(Vector2D vector) {
24 | Set(vector.x, vector.y);
25 | }
26 |
27 | void Vector2D::Add(double x, double y) {
28 | this->x += x;
29 | this->y += y;
30 | }
31 |
32 | void Vector2D::Add(Vector2D vector) {
33 | Add(vector.x, vector.y);
34 | }
35 |
36 | void Vector2D::Multiply(double value) {
37 | this->x *= value;
38 | this->y *= value;
39 | }
40 |
41 | double Vector2D::Distance(Vector2D target) {
42 | double dx = target.x - this->x;
43 | double dy = target.y - this->y;
44 | return sqrt(dx * dx + dy * dy);
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/TabletDriverService/CommandLine.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | using namespace std;
11 |
12 | class CommandLine {
13 | public:
14 | string line;
15 | string command;
16 | vector values;
17 | int valueCount;
18 | bool isValid;
19 |
20 | CommandLine(string text);
21 | ~CommandLine();
22 | bool is(string command);
23 | int Parse(string text);
24 | string ParseHex(string str);
25 | string GetString(int index, string defaultValue);
26 | string GetStringLower(int index, string defaultValue);
27 | int GetInt(int index, int defaultValue);
28 | long GetLong(int index, long defaultValue);
29 | double GetDouble(int index, double defaultValue);
30 | float GetFloat(int index, float defaultValue);
31 | bool GetBoolean(int index, bool defaultValue);
32 | };
33 |
34 |
--------------------------------------------------------------------------------
/TabletDriverService/HIDDevice.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 |
14 | using namespace std;
15 |
16 | class HIDDevice {
17 | private:
18 | HANDLE _deviceHandle;
19 | public:
20 | bool isOpen;
21 | bool debugEnabled;
22 | USHORT vendorId;
23 | USHORT productId;
24 | USHORT usagePage;
25 | USHORT usage;
26 |
27 | HIDDevice(USHORT VendorId, USHORT ProductId, USHORT UsagePage, USHORT Usage);
28 | HIDDevice();
29 | ~HIDDevice();
30 | bool OpenDevice(HANDLE *handle, USHORT vendorId, USHORT productId, USHORT usagePage, USHORT usage);
31 | int Read(void *buffer, int length);
32 | int Write(void *buffer, int length);
33 | bool SetFeature(void *buffer, int length);
34 | bool GetFeature(void *buffer, int length);
35 | void CloseDevice();
36 | };
--------------------------------------------------------------------------------
/TabletDriverService/USBDevice.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | using namespace std;
17 |
18 | class USBDevice {
19 | private:
20 | HANDLE _deviceHandle;
21 | WINUSB_INTERFACE_HANDLE _usbHandle;
22 | bool OpenDevice(string usbDeviceGUIDString, int stringId, string stringMatch);
23 | public:
24 | string guid;
25 | int stringId;
26 | string stringMatch;
27 |
28 | bool isOpen;
29 | USBDevice(string Guid, int StringId, string StringMatch);
30 | ~USBDevice();
31 | int Read(UCHAR pipeId, void *buffer, int length);
32 | int Write(UCHAR pipeId, void *buffer, int length);
33 | int ControlTransfer(UCHAR requestType, UCHAR request, USHORT value, USHORT index, void *buffer, USHORT length);
34 | void CloseDevice();
35 | };
--------------------------------------------------------------------------------
/TabletDriverService/TabletBenchmark.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "TabletBenchmark.h"
3 |
4 | //
5 | // Constructor
6 | //
7 | TabletBenchmark::TabletBenchmark() {
8 | maxX = 0;
9 | minX = 0;
10 | maxY = 0;
11 | minY = 0;
12 | totalPackets = 0;
13 | packetCounter = 0;
14 | }
15 |
16 | //
17 | // Destructor
18 | //
19 | TabletBenchmark::~TabletBenchmark() {
20 | }
21 |
22 |
23 | //
24 | // Start tablet benchmark
25 | //
26 | void TabletBenchmark::Start(int packetCount) {
27 | maxX = -10000;
28 | maxY = -10000;
29 | minX = 10000;
30 | minY = 10000;
31 | totalPackets = packetCount;
32 | packetCounter = packetCount;
33 | isRunning = true;
34 | }
35 |
36 | void TabletBenchmark::Update(Vector2D position) {
37 | if (isRunning) {
38 | if (packetCounter > 0) {
39 | if (position.x < minX) minX = position.x;
40 | if (position.x > maxX) maxX = position.x;
41 | if (position.y < minY) minY = position.y;
42 | if (position.y > maxY) maxY = position.y;
43 | packetCounter--;
44 | }
45 | else {
46 | isRunning = false;
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/TabletDriverService/TabletFilter.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "TabletFilter.h"
3 |
4 |
5 | TabletFilter::TabletFilter() {
6 | timer = NULL;
7 | timerInterval = 2;
8 | isValid = false;
9 | isEnabled = false;
10 | }
11 |
12 | //
13 | // Start Timer
14 | //
15 | bool TabletFilter::StartTimer() {
16 | if (timer == NULL) {
17 | MMRESULT result = timeSetEvent(
18 | (UINT)timerInterval,//UINT uDelay,
19 | 0,//UINT uResolution,
20 | callback, //LPTIMECALLBACK lpTimeProc,
21 | NULL, //DWORD_PTR dwUser,
22 | TIME_PERIODIC | TIME_KILL_SYNCHRONOUS //UINT fuEvent
23 | );
24 | if (result == NULL) {
25 | return false;
26 | }
27 | else {
28 | timer = (HANDLE)1; // for code compatibility purposes
29 | uTimerID = result;
30 | }
31 | }
32 | return true;
33 | }
34 |
35 |
36 | //
37 | // Stop Timer
38 | //
39 | bool TabletFilter::StopTimer() {
40 | if (timer == NULL) return false;
41 |
42 | MMRESULT result = timeKillEvent(uTimerID);
43 | // Returns TIMERR_NOERROR if successful or MMSYSERR_INVALPARAM if the specified timer event does not exist.
44 | if (result == TIMERR_NOERROR)
45 | {
46 | timer = NULL;
47 | return true;
48 | }
49 | return false;
50 | }
--------------------------------------------------------------------------------
/TabletDriverGUI/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace TabletDriverGUI.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/TabletDriverService/TabletFilterSmoothing.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Vector2D.h"
4 | #include "TabletFilter.h"
5 |
6 | class TabletFilterSmoothing : public TabletFilter {
7 | public:
8 | double latency;
9 | double weight;
10 | double threshold;
11 |
12 | bool AntichatterEnabled;
13 | double antichatterStrength;
14 | double antichatterMultiplier;
15 | double antichatterOffsetX;
16 | double antichatterOffsetY;
17 |
18 | bool PredictionEnabled;
19 | double PredictionSharpness;
20 | double PredictionStrength;
21 | double PredictionOffsetX;
22 | double PredictionOffsetY;
23 |
24 | Vector2D target;
25 | Vector2D prev_target;
26 | Vector2D calculated_target;
27 | Vector2D position;
28 | double z;
29 |
30 | TabletFilterSmoothing();
31 | ~TabletFilterSmoothing();
32 |
33 | void SetTarget(Vector2D vector, double h);
34 | void SetPosition(Vector2D vector, double h);
35 | bool GetPosition(Vector2D *outputVector);
36 | void Update();
37 |
38 | void Reset(Vector2D position);
39 | double SetPosition(double x, double y, double h);
40 | double GetLatency(double filterWeight, double interval, double threshold);
41 | double GetLatency(double filterWeight);
42 | double GetLatency();
43 | double GetWeight(double latency, double interval, double threshold);
44 | double GetWeight(double latency);
45 | void SetLatency(double latency);
46 | };
47 |
48 |
--------------------------------------------------------------------------------
/TabletDriverService/TabletFilterPeak.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "TabletFilterPeak.h"
3 |
4 | #define LOG_MODULE "Peak"
5 | #include "Logger.h"
6 |
7 | //
8 | // Constructor
9 | //
10 | TabletFilterPeak::TabletFilterPeak() {
11 |
12 | // Buffer length
13 | buffer.SetLength(3);
14 |
15 | // Default distance threshold
16 | distanceThreshold = 10;
17 | }
18 |
19 |
20 | //
21 | // Destructor
22 | //
23 | TabletFilterPeak::~TabletFilterPeak() {
24 | }
25 |
26 |
27 | //
28 | // TabletFilter methods
29 | //
30 | // reset
31 | void TabletFilterPeak::Reset(Vector2D targetVector) {
32 | buffer.Reset();
33 | }
34 | // Set target position
35 | void TabletFilterPeak::SetTarget(Vector2D targetVector, double h) {
36 | buffer.Add(targetVector);
37 | }
38 | // Set position
39 | void TabletFilterPeak::SetPosition(Vector2D vector, double h) {
40 | position.x = vector.x;
41 | position.y = vector.y;
42 | }
43 | // Get position
44 | bool TabletFilterPeak::GetPosition(Vector2D *outputVector) {
45 | outputVector->x = position.x;
46 | outputVector->y = position.y;
47 | return true;
48 | }
49 | // Update
50 | void TabletFilterPeak::Update() {
51 | Vector2D oldPosition;
52 | double distance;
53 |
54 | // Buffer valid?
55 | if (
56 | buffer.GetLatest(&oldPosition, -1)
57 | &&
58 | buffer.GetLatest(&position, 0)
59 | ) {
60 |
61 | // Jump longer than the distance threshold?
62 | distance = oldPosition.Distance(position);
63 | if (distance > distanceThreshold) {
64 |
65 | /*
66 | LOG_DEBUG("PEAK! %0.2f,%0.2f -> %0.2f,%0.2f = %0.2f mm\n",
67 | oldPosition.x, oldPosition.y,
68 | position.x, position.y,
69 | distance
70 | );
71 | */
72 |
73 | position.x = oldPosition.x;
74 | position.y = oldPosition.y;
75 |
76 | // Reset buffer
77 | buffer.Reset();
78 |
79 | }
80 | }
81 | }
--------------------------------------------------------------------------------
/TabletDriverService/PositionRingBuffer.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "PositionRingBuffer.h"
3 |
4 |
5 | //
6 | // Constructor
7 | //
8 | PositionRingBuffer::PositionRingBuffer() {
9 | maxLength = sizeof(buffer) / sizeof(Vector2D);
10 | length = 0;
11 | count = 0;
12 | index = 0;
13 | isValid = false;
14 | }
15 |
16 |
17 | //
18 | // Destructor
19 | //
20 | PositionRingBuffer::~PositionRingBuffer() {
21 | }
22 |
23 |
24 | //
25 | // Set buffer length
26 | //
27 | void PositionRingBuffer::SetLength(int len) {
28 | if(len > maxLength) {
29 | length = maxLength;
30 | } else {
31 | length = len;
32 | }
33 | }
34 |
35 |
36 | //
37 | // Add position to buffer
38 | //
39 | void PositionRingBuffer::Add(Vector2D vector) {
40 | buffer[index].x = vector.x;
41 | buffer[index].y = vector.y;
42 | index++;
43 | count++;
44 | if(count > length) {
45 | count = length;
46 | }
47 | if(index >= length) {
48 | index = 0;
49 | }
50 | isValid = true;
51 | }
52 |
53 |
54 | //
55 | // Get position history from the buffer
56 | //
57 | bool PositionRingBuffer::GetLatest(Vector2D *output, int delta) {
58 | int newIndex;
59 |
60 | // Buffer empty?
61 | if(count == 0) return false;
62 |
63 | // Valid delta?
64 | if(delta > 0 || delta <= -count) return false;
65 |
66 | newIndex = index - 1 + delta;
67 |
68 | // Limits
69 | if(newIndex < 0) newIndex = count + newIndex;
70 |
71 | if(newIndex < 0 || newIndex >= count) {
72 | return false;
73 | }
74 |
75 | output->x = buffer[newIndex].x;
76 | output->y = buffer[newIndex].y;
77 | return true;
78 | }
79 |
80 |
81 | //
82 | // Reset buffer
83 | //
84 | void PositionRingBuffer::Reset() {
85 | count = 0;
86 | index = 0;
87 | isValid = false;
88 | }
89 |
90 |
91 |
92 | //
93 | // [] operator
94 | //
95 | Vector2D *PositionRingBuffer::operator[](std::size_t index) {
96 | return &(buffer[index]);
97 | }
--------------------------------------------------------------------------------
/TabletDriverGUI/Utils.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 |
3 | namespace TabletDriverGUI
4 | {
5 | public class Utils
6 | {
7 | public static CultureInfo cultureInfo = null;
8 |
9 |
10 | //
11 | // Check and create culture info
12 | //
13 | public static void CheckCultureInfo()
14 | {
15 | if (cultureInfo == null)
16 | {
17 | cultureInfo = new CultureInfo("en-US");
18 | cultureInfo.NumberFormat.PerMilleSymbol = "";
19 |
20 | cultureInfo.NumberFormat.NumberDecimalSeparator = ".";
21 | cultureInfo.NumberFormat.NumberGroupSeparator = "";
22 |
23 | cultureInfo.NumberFormat.PercentDecimalSeparator = ".";
24 | cultureInfo.NumberFormat.PercentGroupSeparator = "";
25 |
26 | cultureInfo.NumberFormat.CurrencyDecimalSeparator = ".";
27 | cultureInfo.NumberFormat.CurrencyGroupSeparator = "";
28 | }
29 | }
30 |
31 | //
32 | // String to Number
33 | //
34 | public static bool ParseNumber(string str, out double val)
35 | {
36 | CheckCultureInfo();
37 | val = 0;
38 | if (double.TryParse(str, NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign, cultureInfo.NumberFormat, out double tmp))
39 | {
40 | val = tmp;
41 | return true;
42 | }
43 | return false;
44 | }
45 |
46 | //
47 | // Number to String
48 | //
49 | public static string GetNumberString(double val)
50 | {
51 | CheckCultureInfo();
52 | return GetNumberString(val, "0.##");
53 | }
54 | public static string GetNumberString(double val, string format)
55 | {
56 | CheckCultureInfo();
57 | return val.ToString(format, cultureInfo.NumberFormat);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/TabletDriverService/VMulti.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "HIDDevice.h"
4 | #include "Vector2D.h"
5 |
6 | class VMulti {
7 | private:
8 | HIDDevice * hidDevice;
9 | BYTE reportBuffer[65];
10 | BYTE lastReportBuffer[65];
11 | public:
12 |
13 | enum VMultiMode {
14 | ModeAbsoluteMouse,
15 | ModeRelativeMouse,
16 | ModeDigitizer,
17 | ModeSendInput
18 | };
19 |
20 | struct {
21 | BYTE vmultiId;
22 | BYTE reportLength;
23 | BYTE reportId;
24 | BYTE buttons;
25 | USHORT x;
26 | USHORT y;
27 | BYTE wheel;
28 | } reportAbsoluteMouse;
29 |
30 | struct {
31 | BYTE vmultiId;
32 | BYTE reportLength;
33 | BYTE reportId;
34 | BYTE buttons;
35 | BYTE x;
36 | BYTE y;
37 | BYTE wheel;
38 | } reportRelativeMouse;
39 |
40 | struct {
41 | BYTE vmultiId;
42 | BYTE reportLength;
43 | BYTE reportId;
44 | BYTE buttons;
45 | USHORT x;
46 | USHORT y;
47 | USHORT pressure;
48 | } reportDigitizer;
49 |
50 |
51 | // Position Integer
52 | typedef struct {
53 | int x;
54 | int y;
55 | } PositionInt;
56 |
57 | // Relative mouse data
58 | struct {
59 | PositionInt currentPosition;
60 | Vector2D lastPosition;
61 | Vector2D targetPosition;
62 | double sensitivity;
63 | double resetDistance;
64 | } relativeData;
65 |
66 |
67 | struct {
68 | double primaryWidth = GetSystemMetrics(SM_CXSCREEN);
69 | double primaryHeight = GetSystemMetrics(SM_CYSCREEN);
70 | double virtualWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
71 | double virtualHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
72 | double virtualX = GetSystemMetrics(SM_XVIRTUALSCREEN);
73 | double virtualY = GetSystemMetrics(SM_YVIRTUALSCREEN);
74 | } monitorInfo;
75 |
76 | VMultiMode mode;
77 | bool isOpen;
78 | bool debugEnabled;
79 | bool outputEnabled;
80 | int lastButtons;
81 |
82 |
83 |
84 | VMulti();
85 | ~VMulti();
86 | bool HasReportChanged();
87 | void ResetRelativeData(double x, double y);
88 | void UpdateMonitorInfo();
89 | void CreateReport(BYTE buttons, double x, double y, double pressure);
90 | int ResetReport();
91 | int WriteReport();
92 | };
93 |
94 |
95 |
--------------------------------------------------------------------------------
/TabletDriverGUI/WacomArea.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/TabletDriverGUI/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using System.Windows;
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | [assembly: AssemblyTitle("TabletDriverGUI")]
11 | [assembly: AssemblyDescription("")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("")]
14 | [assembly: AssemblyProduct("TabletDriverGUI")]
15 | [assembly: AssemblyCopyright("Copyright © 2018")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | [assembly: ComVisible(false)]
23 |
24 | //In order to begin building localizable applications, set
25 | //CultureYouAreCodingWith in your .csproj file
26 | //inside a . For example, if you are using US english
27 | //in your source files, set the to en-US. Then uncomment
28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in
29 | //the line below to match the UICulture setting in the project file.
30 |
31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
32 |
33 |
34 | [assembly: ThemeInfo(
35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
36 | //(used if a resource is not found in the page,
37 | // or application resource dictionaries)
38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
39 | //(used if a resource is not found in the page,
40 | // app, or any theme specific resource dictionaries)
41 | )]
42 |
43 |
44 | // Version information for an assembly consists of the following four values:
45 | //
46 | // Major Version
47 | // Minor Version
48 | // Build Number
49 | // Revision
50 | //
51 | // You can specify all the values or you can default the Build and Revision Numbers
52 | // by using the '*' as shown below:
53 | // [assembly: AssemblyVersion("1.0.*")]
54 | [assembly: AssemblyVersion("1.0.0.0")]
55 | [assembly: AssemblyFileVersion("1.0.0.0")]
56 |
--------------------------------------------------------------------------------
/TabletDriverService/Tablet.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include "USBDevice.h"
6 | #include "HIDDevice.h"
7 | #include "TabletSettings.h"
8 | #include "TabletFilterSmoothing.h"
9 | #include "TabletFilterNoiseReduction.h"
10 | #include "TabletFilterPeak.h"
11 | #include "TabletBenchmark.h"
12 | #include "Vector2D.h"
13 |
14 | using namespace std;
15 |
16 | class Tablet {
17 | public:
18 |
19 | USBDevice * usbDevice;
20 | HIDDevice * hidDevice;
21 | HIDDevice * hidDevice2;
22 | int usbPipeId;
23 |
24 | //
25 | // Enums
26 | //
27 | enum TabletButtons {
28 | Button1, Button2, Button3, Button4,
29 | Button5, Button6, Button7, Button8
30 | };
31 |
32 | // Tablet packet state
33 | enum TabletPacketState {
34 | PacketPositionInvalid = 0,
35 | PacketValid = 1,
36 | PacketInvalid = 2
37 | };
38 |
39 | //
40 | // Position report data
41 | //
42 | #pragma pack(1)
43 | struct {
44 | BYTE reportId;
45 | BYTE buttons;
46 | USHORT x;
47 | USHORT y;
48 | USHORT pressure;
49 | USHORT z;
50 | } reportData;
51 |
52 | //
53 | // Tablet state
54 | //
55 | struct {
56 | bool isValid;
57 | BYTE buttons;
58 | Vector2D position;
59 | double pressure;
60 | double z;
61 | } state;
62 |
63 | // Settings
64 | TabletSettings settings;
65 |
66 | // Smoothing filter
67 | TabletFilterSmoothing smoothing;
68 |
69 | // Noise reduction filter
70 | TabletFilterNoiseReduction noise;
71 |
72 | // Peak filter
73 | TabletFilterPeak peak;
74 |
75 | // Timed filter
76 | TabletFilter *filterTimed[10];
77 | int filterTimedCount;
78 |
79 | // Packet filter
80 | TabletFilter *filterPacket[10];
81 | int filterPacketCount;
82 |
83 | // Benchmark
84 | TabletBenchmark benchmark;
85 |
86 | // Button map
87 | BYTE buttonMap[16];
88 |
89 | //
90 | string name = "Unknown";
91 | bool isOpen;
92 | bool debugEnabled;
93 | int skipPackets;
94 |
95 | // Pen tip button keep down
96 | int tipDownCounter;
97 |
98 | // Tablet initialize buffers
99 | BYTE *initFeature;
100 | int initFeatureLength;
101 | BYTE *initReport;
102 | int initReportLength;
103 |
104 | Tablet(string usbGUID, int stringId, string stringMatch);
105 | Tablet(USHORT vendorId, USHORT productId, USHORT usagePage, USHORT usage);
106 | Tablet();
107 | ~Tablet();
108 |
109 | bool Init();
110 | bool IsConfigured();
111 |
112 | int ReadPosition();
113 | bool Write(void *buffer, int length);
114 | bool Read(void *buffer, int length);
115 | void CloseDevice();
116 |
117 | };
118 |
--------------------------------------------------------------------------------
/TabletDriver.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27130.2010
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TabletDriverGUI", "TabletDriverGUI\TabletDriverGUI.csproj", "{6793EBBD-0EC4-4254-9573-A19ECA79F2C8}"
7 | EndProject
8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TabletDriverService", "TabletDriverService\TabletDriverService.vcxproj", "{3101CEC2-8F39-45FD-943B-79A488AD05EA}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D6136950-9BE8-4645-9FA5-65E70E9DC1FA}"
11 | ProjectSection(SolutionItems) = preProject
12 | README.md = README.md
13 | EndProjectSection
14 | EndProject
15 | Global
16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
17 | Debug|Any CPU = Debug|Any CPU
18 | Debug|x64 = Debug|x64
19 | Debug|x86 = Debug|x86
20 | Release|Any CPU = Release|Any CPU
21 | Release|x64 = Release|x64
22 | Release|x86 = Release|x86
23 | EndGlobalSection
24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
25 | {6793EBBD-0EC4-4254-9573-A19ECA79F2C8}.Debug|Any CPU.ActiveCfg = Release|Any CPU
26 | {6793EBBD-0EC4-4254-9573-A19ECA79F2C8}.Debug|Any CPU.Build.0 = Release|Any CPU
27 | {6793EBBD-0EC4-4254-9573-A19ECA79F2C8}.Debug|x64.ActiveCfg = Debug|Any CPU
28 | {6793EBBD-0EC4-4254-9573-A19ECA79F2C8}.Debug|x64.Build.0 = Debug|Any CPU
29 | {6793EBBD-0EC4-4254-9573-A19ECA79F2C8}.Debug|x86.ActiveCfg = Debug|Any CPU
30 | {6793EBBD-0EC4-4254-9573-A19ECA79F2C8}.Debug|x86.Build.0 = Debug|Any CPU
31 | {6793EBBD-0EC4-4254-9573-A19ECA79F2C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
32 | {6793EBBD-0EC4-4254-9573-A19ECA79F2C8}.Release|Any CPU.Build.0 = Release|Any CPU
33 | {6793EBBD-0EC4-4254-9573-A19ECA79F2C8}.Release|x64.ActiveCfg = Release|Any CPU
34 | {6793EBBD-0EC4-4254-9573-A19ECA79F2C8}.Release|x64.Build.0 = Release|Any CPU
35 | {6793EBBD-0EC4-4254-9573-A19ECA79F2C8}.Release|x86.ActiveCfg = Release|Any CPU
36 | {6793EBBD-0EC4-4254-9573-A19ECA79F2C8}.Release|x86.Build.0 = Release|Any CPU
37 | {3101CEC2-8F39-45FD-943B-79A488AD05EA}.Debug|Any CPU.ActiveCfg = Release|Win32
38 | {3101CEC2-8F39-45FD-943B-79A488AD05EA}.Debug|Any CPU.Build.0 = Release|Win32
39 | {3101CEC2-8F39-45FD-943B-79A488AD05EA}.Debug|x64.ActiveCfg = Debug|x64
40 | {3101CEC2-8F39-45FD-943B-79A488AD05EA}.Debug|x64.Build.0 = Debug|x64
41 | {3101CEC2-8F39-45FD-943B-79A488AD05EA}.Debug|x86.ActiveCfg = Debug|Win32
42 | {3101CEC2-8F39-45FD-943B-79A488AD05EA}.Debug|x86.Build.0 = Debug|Win32
43 | {3101CEC2-8F39-45FD-943B-79A488AD05EA}.Release|Any CPU.ActiveCfg = Release|Win32
44 | {3101CEC2-8F39-45FD-943B-79A488AD05EA}.Release|x64.ActiveCfg = Release|x64
45 | {3101CEC2-8F39-45FD-943B-79A488AD05EA}.Release|x64.Build.0 = Release|x64
46 | {3101CEC2-8F39-45FD-943B-79A488AD05EA}.Release|x86.ActiveCfg = Release|Win32
47 | {3101CEC2-8F39-45FD-943B-79A488AD05EA}.Release|x86.Build.0 = Release|Win32
48 | EndGlobalSection
49 | GlobalSection(SolutionProperties) = preSolution
50 | HideSolutionNode = FALSE
51 | EndGlobalSection
52 | GlobalSection(ExtensibilityGlobals) = postSolution
53 | SolutionGuid = {A4C69FC2-B4E8-4852-81F0-7FDC4EB09313}
54 | EndGlobalSection
55 | EndGlobal
56 |
--------------------------------------------------------------------------------
/TabletDriverGUI/app.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
52 |
53 |
54 | true/PM
55 |
56 |
57 |
58 |
59 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/TabletDriverGUI/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace TabletDriverGUI.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TabletDriverGUI.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 |
63 | ///
64 | /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
65 | ///
66 | internal static System.Drawing.Icon AppIcon {
67 | get {
68 | object obj = ResourceManager.GetObject("AppIcon", resourceCulture);
69 | return ((System.Drawing.Icon)(obj));
70 | }
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/TabletDriverService/Logger.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 |
21 | #ifndef LOG_MODULE
22 | #define LOG_MODULE "Logger"
23 | #endif
24 |
25 | #define LOGGER_FILE(file) logger.OpenLogFile(file)
26 | #define LOGGER_START(...) logger.Start()
27 | #define LOGGER_STOP(...) logger.Stop()
28 | #define LOGGER_PROCESS(...) logger.ProcessMessages()
29 | #define LOGGER_DIRECT logger.directPrint
30 |
31 | #define LOG_DIE(...) (logger.LogMessage(logger.LogLevelCritical, LOG_MODULE, __VA_ARGS__), LOGGER_PROCESS(); exit(1))
32 | #define LOG_DIEBUFFER(buf, len, ...) (logger.LogBuffer(LogLevelCritical, LOG_MODULE, buf, len, __VA_ARGS__), LOGGER_PROCESS(), exit(1))
33 |
34 | #define LOG_ERROR(...) logger.LogMessage(logger.LogLevelError, LOG_MODULE, __VA_ARGS__)
35 | #define LOG_ERRORBUFFER(buf, len, ...) logger.LogBuffer(logger.LogLevelError, LOG_MODULE, buf, len, __VA_ARGS__)
36 |
37 | #define LOG_WARNING(...) logger.LogMessage(logger.LogLevelWarning, LOG_MODULE, __VA_ARGS__)
38 | #define LOG_WARNINGBUFFER(buf, len, ...) logger.LogBuffer(4, LOG_MODULE, buf, len, __VA_ARGS__)
39 |
40 | #define LOG_NOTE(...) logger.LogMessage(logger.LogLevelNote, LOG_MODULE, __VA_ARGS__)
41 | #define LOG_NOTEBUFFER(buf, len, ...) logger.LogBuffer(logger.LogLevelNote, LOG_MODULE, buf, len, __VA_ARGS__)
42 |
43 | #define LOG_STATUS(...) logger.LogMessage(logger.LogLevelStatus, LOG_MODULE, __VA_ARGS__)
44 | #define LOG_STATUSBUFFER(buf, len, ...) logger.LogBuffer(logger.LogLevelStatus, LOG_MODULE, buf, len, __VA_ARGS__)
45 |
46 | #define LOG_INFO(...) logger.LogMessage(logger.LogLevelInfo, LOG_MODULE, __VA_ARGS__)
47 | #define LOG_INFOBUFFER(buf, len, ...) logger.LogBuffer(logger.LogLevelInfo, LOG_MODULE, buf, len, __VA_ARGS__)
48 |
49 | #define LOG_DEBUG(...) logger.LogMessage(logger.LogLevelDebug, LOG_MODULE, __VA_ARGS__)
50 | #define LOG_DEBUGBUFFER(buf, len, ...) logger.LogBuffer(logger.LogLevelDebug, LOG_MODULE, buf, len, __VA_ARGS__)
51 |
52 |
53 | using namespace std;
54 |
55 | class Logger {
56 | private:
57 | thread threadLog;
58 | void run();
59 | mutex lockMessages;
60 | bool newMessage;
61 | ofstream logFile;
62 | bool logToFile;
63 |
64 | public:
65 | enum LogLevels {
66 | LogLevelUnknown,
67 | LogLevelUnknown2,
68 | LogLevelCritical,
69 | LogLevelError,
70 | LogLevelWarning,
71 | LogLevelNote,
72 | LogLevelStatus,
73 | LogLevelInfo,
74 | LogLevelDebug
75 | };
76 | typedef struct {
77 | tm time;
78 | int level;
79 | string module;
80 | string text;
81 | } LogItem;
82 | vector messages;
83 | string levelNames[9] = {
84 | "",
85 | "",
86 | "CRITICAL",
87 | "ERROR",
88 | "WARNING",
89 | "NOTE",
90 | "STATUS",
91 | "INFO",
92 | "DEBUG"
93 | };
94 | bool isRunning;
95 | bool directPrint;
96 | string logFilename = "";
97 |
98 | void OutputMessage(LogItem *message);
99 | void ProcessMessages();
100 | void LogMessage(int level, string module, const char *fmt, ...);
101 | void LogBuffer(int level, string module, void *buffer, int length, const char *fmt, ...);
102 | int verbosity;
103 | Logger();
104 | void AddMessage(LogItem *message);
105 | void Start();
106 | void Stop();
107 | bool OpenLogFile(string filename);
108 | bool CloseLogFile();
109 | };
110 | extern Logger logger;
111 |
112 |
--------------------------------------------------------------------------------
/TabletDriverService/ScreenMapper.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "ScreenMapper.h"
3 |
4 | #define LOG_MODULE "ScreenMapper"
5 | #include "Logger.h"
6 |
7 | #include
8 |
9 | #define _USE_MATH_DEFINES
10 | #include
11 | #include
12 |
13 | ScreenMapper::ScreenMapper(Tablet *t) {
14 | this->tablet = t;
15 |
16 | // Default Virtual Screen Area
17 | areaVirtualScreen.width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
18 | areaVirtualScreen.height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
19 | areaVirtualScreen.x = 0;
20 | areaVirtualScreen.y = 0;
21 |
22 | // Default Tablet Area
23 | areaTablet.width = 80;
24 | areaTablet.height = 45;
25 | areaTablet.x = 10;
26 | areaTablet.y = 10;
27 |
28 |
29 | // Default Screen Area
30 | areaScreen.width = 1920;
31 | areaScreen.height = 1080;
32 | areaScreen.x = 0;
33 | areaScreen.y = 0;
34 |
35 | // Default Rotation Matrix
36 | rotationMatrix[0] = 1;
37 | rotationMatrix[1] = 0;
38 | rotationMatrix[2] = 0;
39 | rotationMatrix[3] = 1;
40 |
41 |
42 | }
43 |
44 | //
45 | // Create rotation matrix
46 | //
47 | void ScreenMapper::SetRotation(double angle) {
48 | angle *= M_PI / 180;
49 | rotationMatrix[0] = cos(angle);
50 | rotationMatrix[1] = -sin(angle);
51 | rotationMatrix[2] = sin(angle);
52 | rotationMatrix[3] = cos(angle);
53 | }
54 |
55 | //
56 | // Get rotated tablet position
57 | //
58 | bool ScreenMapper::GetRotatedTabletPosition(double *x, double *y) {
59 | double mapX, mapY;
60 | double tmpX, tmpY;
61 |
62 | mapX = (*x);
63 | mapY = (*y);
64 |
65 | // Offset tablet so that the center is at zero
66 | mapX -= tablet->settings.width / 2.0;
67 | mapY -= tablet->settings.height / 2.0;
68 |
69 | // Rotate
70 | tmpX = mapX;
71 | tmpY = mapY;
72 | mapX = tmpX * rotationMatrix[0] + tmpY * rotationMatrix[1];
73 | mapY = tmpX * rotationMatrix[2] + tmpY * rotationMatrix[3];
74 |
75 | // Offset back to center from zero
76 | mapX += tablet->settings.width / 2.0;
77 | mapY += tablet->settings.height / 2.0;
78 |
79 | // Set pointer values
80 | *x = mapX;
81 | *y = mapY;
82 |
83 | return true;
84 | }
85 |
86 | //
87 | // Get screen position. Return values between 0 and 1
88 | //
89 | bool ScreenMapper::GetScreenPosition(double *x, double *y) {
90 | double mapX, mapY;
91 | double tmpX, tmpY;
92 |
93 | mapX = (*x);
94 | mapY = (*y);
95 |
96 | // Offset tablet area position
97 | mapX -= areaTablet.x;
98 | mapY -= areaTablet.y;
99 |
100 | // Rotate
101 | tmpX = mapX;
102 | tmpY = mapY;
103 | mapX = tmpX * rotationMatrix[0] + tmpY * rotationMatrix[1];
104 | mapY = tmpX * rotationMatrix[2] + tmpY * rotationMatrix[3];
105 |
106 | // Offset half of tablet area size
107 | mapX += areaTablet.width / 2.0;
108 | mapY += areaTablet.height / 2.0;
109 |
110 | // Normalize tablet area
111 | mapX /= areaTablet.width;
112 | mapY /= areaTablet.height;
113 |
114 |
115 | // Scale to screen area size
116 | mapX *= (areaScreen.width);
117 | mapY *= (areaScreen.height);
118 |
119 | // Offset screen area
120 | mapX += areaScreen.x;
121 | mapY += areaScreen.y;
122 |
123 | // Limit cursor to screen area
124 | if (mapX < areaScreen.x + 1) mapX = areaScreen.x + 1;
125 | if (mapY < areaScreen.y + 1) mapY = areaScreen.y + 1;
126 | if (mapX > areaScreen.x + areaScreen.width) mapX = areaScreen.x + areaScreen.width;
127 | if (mapY > areaScreen.y + areaScreen.height) mapY = areaScreen.y + areaScreen.height;
128 |
129 |
130 | // Normalize screen area
131 | mapX /= areaVirtualScreen.width;
132 | mapY /= areaVirtualScreen.height;
133 |
134 | // Limit values
135 | if (mapX > 1) mapX = 1;
136 | if (mapY > 1) mapY = 1;
137 |
138 | // Set pointer values
139 | *x = mapX;
140 | *y = mapY;
141 |
142 | return 1;
143 | }
--------------------------------------------------------------------------------
/TabletDriverService/TabletFilterNoiseReduction.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "TabletFilterNoiseReduction.h"
3 |
4 |
5 | //
6 | // Constructor
7 | //
8 | TabletFilterNoiseReduction::TabletFilterNoiseReduction() {
9 | distanceThreshold = 0;
10 | iterations = 10;
11 | }
12 |
13 | //
14 | // Destructor
15 | //
16 | TabletFilterNoiseReduction::~TabletFilterNoiseReduction() {
17 | }
18 |
19 | //
20 | // TabletFilter methods
21 | //
22 |
23 | // Reset
24 | void TabletFilterNoiseReduction::Reset(Vector2D position) {
25 | lastTarget.Set(position);
26 | buffer.Reset();
27 | }
28 |
29 | // Set target position
30 | void TabletFilterNoiseReduction::SetTarget(Vector2D targetVector, double h) {
31 | lastTarget.Set(targetVector);
32 | buffer.Add(targetVector);
33 | }
34 |
35 | // Set position
36 | void TabletFilterNoiseReduction::SetPosition(Vector2D vector, double h) {
37 | position.x = vector.x;
38 | position.y = vector.y;
39 | }
40 |
41 | // Get position
42 | bool TabletFilterNoiseReduction::GetPosition(Vector2D *outputVector) {
43 | outputVector->x = position.x;
44 | outputVector->y = position.y;
45 | return true;
46 | }
47 |
48 | // Update
49 | void TabletFilterNoiseReduction::Update() {
50 |
51 | // One position in the buffer?
52 | if (buffer.count == 1) {
53 | position.x = buffer[0]->x;
54 | position.y = buffer[0]->y;
55 | return;
56 | }
57 |
58 | // Calculate geometric median from the buffer positions
59 | GetGeometricMedianVector(&position, iterations);
60 |
61 | // Reset the buffer when distance to last target position is larger than the threshold
62 | if (buffer.isValid) {
63 | double distance = lastTarget.Distance(position);
64 | if (distance > distanceThreshold) {
65 | buffer.Reset();
66 | position.Set(lastTarget);
67 | }
68 | }
69 | }
70 |
71 | //
72 | // Average Position Vector
73 | //
74 | bool TabletFilterNoiseReduction::GetAverageVector(Vector2D *output) {
75 | double x, y;
76 | if (!buffer.isValid) return false;
77 |
78 | x = y = 0;
79 | for (int i = 0; i < buffer.count; i++) {
80 | x += buffer[i]->x;
81 | y += buffer[i]->y;
82 | }
83 | output->x = x / buffer.count;
84 | output->y = y / buffer.count;
85 | return true;
86 | }
87 |
88 | //
89 | // Geometric Median Position Vector
90 | //
91 | bool TabletFilterNoiseReduction::GetGeometricMedianVector(Vector2D *output, int iterations) {
92 |
93 | Vector2D candidate, next;
94 | double minimumDistance = 0.001;
95 |
96 | double denominator, dx, dy, distance, weight;
97 | int i;
98 |
99 | // Calculate the starting position
100 | if (GetAverageVector(&candidate)) {
101 | }
102 | else {
103 | return false;
104 | }
105 |
106 | // Iterate
107 | for (int iteration = 0; iteration < iterations; iteration++) {
108 |
109 | denominator = 0;
110 |
111 | // Loop through the buffer and calculate a denominator.
112 | for (i = 0; i < buffer.count; i++) {
113 | dx = candidate.x - buffer[i]->x;
114 | dy = candidate.y - buffer[i]->y;
115 | distance = sqrt(dx*dx + dy * dy);
116 | if (distance > minimumDistance) {
117 | denominator += 1.0 / distance;
118 | }
119 | else {
120 | denominator += 1.0 / minimumDistance;
121 | }
122 | }
123 |
124 | // Reset the next vector
125 | next.x = 0;
126 | next.y = 0;
127 |
128 | // Loop through the buffer and calculate a weighted average
129 | for (i = 0; i < buffer.count; i++) {
130 | dx = candidate.x - buffer[i]->x;
131 | dy = candidate.y - buffer[i]->y;
132 | distance = sqrt(dx*dx + dy * dy);
133 | if (distance > minimumDistance) {
134 | weight = 1.0 / distance;
135 | }
136 | else {
137 | weight = 1.0 / minimumDistance;
138 | }
139 |
140 | next.x += buffer[i]->x * weight / denominator;
141 | next.y += buffer[i]->y * weight / denominator;
142 | }
143 |
144 | // Set the new candidate vector
145 | candidate.x = next.x;
146 | candidate.y = next.y;
147 | }
148 |
149 | // Set output
150 | output->x = candidate.x;
151 | output->y = candidate.y;
152 |
153 | return true;
154 |
155 | }
156 |
157 |
--------------------------------------------------------------------------------
/TabletDriverService/startuplog.txt:
--------------------------------------------------------------------------------
1 | 2018-06-08 11:29:35 [INFO] \ Reading 'config\init.cfg'
2 | 2018-06-08 11:29:35 [INFO] >> Log startuplog.txt
3 | 2018-06-08 11:29:35 [INFO] Log file 'startuplog.txt' opened.
4 | 2018-06-08 11:29:35 [INFO] >> LogDirect true
5 | 2018-06-08 11:29:35 [INFO] Log direct print = True
6 | 2018-06-08 11:29:35 [INFO] >> Include "config\tablet.cfg"
7 | 2018-06-08 11:29:35 [INFO] \ Reading 'config\tablet.cfg'
8 | 2018-06-08 11:29:35 [INFO] >> #
9 | 2018-06-08 11:29:35 [INFO] >> # Example tablet definition:
10 | 2018-06-08 11:29:35 [INFO] >> # Tablet 0x056a 0x00dd 0x0D 0x01
11 | 2018-06-08 11:29:35 [INFO] >> #
12 | 2018-06-08 11:29:35 [INFO] >> # VID: 0x056a
13 | 2018-06-08 11:29:35 [INFO] >> # PID: 0x00dd
14 | 2018-06-08 11:29:35 [INFO] >> # HID Usage Page: 0x0D
15 | 2018-06-08 11:29:35 [INFO] >> # HID Usage: 0x01
16 | 2018-06-08 11:29:35 [INFO] >> #
17 | 2018-06-08 11:29:35 [INFO] >> #
18 | 2018-06-08 11:29:35 [INFO] >> # Wacom CTL-470 (Wacom drivers installed)
19 | 2018-06-08 11:29:35 [INFO] >> #
20 | 2018-06-08 11:29:35 [INFO] >> Tablet 0x056a 0x00dd 0xFF00 0x000A
21 | 2018-06-08 11:29:35 [WARNING] Can't open HID tablet 0x056A 0x00DD 0xFF00 0x000A
22 | 2018-06-08 11:29:35 [INFO] >> Name "Wacom CTL-470 (Wacom drivers installed)"
23 | 2018-06-08 11:29:35 [INFO] >> ReportId 0x02
24 | 2018-06-08 11:29:35 [INFO] >> ReportLength 11
25 | 2018-06-08 11:29:35 [INFO] >> DetectMask 0x40
26 | 2018-06-08 11:29:35 [INFO] >> MaxX 14720
27 | 2018-06-08 11:29:35 [INFO] >> MaxY 9200
28 | 2018-06-08 11:29:35 [INFO] >> MaxPressure 1023
29 | 2018-06-08 11:29:35 [INFO] >> Width 147.2
30 | 2018-06-08 11:29:35 [INFO] >> Height 92.0
31 | 2018-06-08 11:29:35 [INFO] >> Type WacomDrivers
32 | 2018-06-08 11:29:35 [INFO] >> #
33 | 2018-06-08 11:29:35 [INFO] >> # Wacom CTL-470
34 | 2018-06-08 11:29:35 [INFO] >> #
35 | 2018-06-08 11:29:35 [INFO] >> Tablet 0x056a 0x00dd 0x0D 0x01
36 | 2018-06-08 11:29:35 [INFO] Tablet found!
37 | 2018-06-08 11:29:35 [INFO] >> Name "Wacom CTL-470"
38 | 2018-06-08 11:29:35 [INFO] Tablet name = 'Wacom CTL-470'
39 | 2018-06-08 11:29:35 [INFO] >> ReportId 0x02
40 | 2018-06-08 11:29:35 [INFO] Tablet report id = 2
41 | 2018-06-08 11:29:35 [INFO] >> ReportLength 10
42 | 2018-06-08 11:29:35 [INFO] Tablet report length = 10
43 | 2018-06-08 11:29:35 [INFO] >> DetectMask 0x40
44 | 2018-06-08 11:29:35 [INFO] Tablet detect mask = 40
45 | 2018-06-08 11:29:35 [INFO] >> MaxX 14720
46 | 2018-06-08 11:29:35 [INFO] Tablet max X = 14720
47 | 2018-06-08 11:29:35 [INFO] >> MaxY 9200
48 | 2018-06-08 11:29:35 [INFO] Tablet max Y = 9200
49 | 2018-06-08 11:29:35 [INFO] >> MaxPressure 1023
50 | 2018-06-08 11:29:35 [INFO] Tablet max pressure = 1023
51 | 2018-06-08 11:29:35 [INFO] >> Width 147.2
52 | 2018-06-08 11:29:35 [INFO] Tablet width = 147.20 mm
53 | 2018-06-08 11:29:35 [INFO] >> Height 92.0
54 | 2018-06-08 11:29:35 [INFO] Tablet height = 92.00 mm
55 | 2018-06-08 11:29:35 [INFO] >> InitFeature 0x02 0x02
56 | 2018-06-08 11:29:35 [INFO] Tablet init feature report: { 0x02, 0x02 }
57 | 2018-06-08 11:29:35 [INFO] >> #
58 | 2018-06-08 11:29:35 [INFO] >> # Wacom CTH-470 ???
59 | 2018-06-08 11:29:35 [INFO] >> #
60 | 2018-06-08 11:29:35 [INFO] >> Tablet 0x056a 0x00de 0x0D 0x01
61 | 2018-06-08 11:29:35 [INFO] Tablet is already defined!
62 | 2018-06-08 11:29:35 [INFO] / End of 'config\tablet.cfg'
63 | 2018-06-08 11:29:35 [INFO] >> Include "config\wacom.cfg"
64 | 2018-06-08 11:29:35 [INFO] \ Reading 'config\wacom.cfg'
65 | 2018-06-08 11:29:35 [INFO] >> #
66 | 2018-06-08 11:29:35 [INFO] >> # This file is automatically generated from these sources:
67 | 2018-06-08 11:29:35 [INFO] >> # https://github.com/linuxwacom/input-wacom/blob/master/3.7/wacom_wac.h
68 | 2018-06-08 11:29:35 [INFO] >> # https://github.com/linuxwacom/input-wacom/blob/master/3.7/wacom_wac.c
69 | 2018-06-08 11:29:35 [INFO] >> # https://github.com/linuxwacom/input-wacom/wiki/Device-IDs
70 | 2018-06-08 11:29:35 [INFO] >> #
71 | 2018-06-08 11:29:35 [INFO] >> # DO NOT EDIT THIS FILE!
72 | 2018-06-08 11:29:35 [INFO] >> # Make the configuration modifications to the tablet.cfg
73 | 2018-06-08 11:29:35 [INFO] >> # Tablet.cfg will overwrite the settings from this file, if the tablet is found.
74 | 2018-06-08 11:29:35 [INFO] >> #
75 | 2018-06-08 11:29:35 [INFO] >> # Wacom PTK-450
76 | 2018-06-08 11:29:35 [INFO] >> Tablet 0x056A 0x0029 0xFF0D 0x0001
77 | 2018-06-08 11:29:35 [INFO] Tablet is already defined!
78 | 2018-06-08 11:29:35 [INFO] / End of 'config\wacom.cfg'
79 | 2018-06-08 11:29:35 [INFO] >> Include "config\user.cfg"
80 | 2018-06-08 11:29:35 [INFO] \ Reading 'config\user.cfg'
81 | 2018-06-08 11:29:35 [INFO] / End of 'config\user.cfg'
82 | 2018-06-08 11:29:35 [INFO] / End of 'config\init.cfg'
83 |
--------------------------------------------------------------------------------
/TabletDriverGUI/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Reflection;
4 | using System.Runtime.InteropServices;
5 | using System.Threading;
6 | using System.Windows;
7 |
8 | namespace TabletDriverGUI
9 | {
10 | public partial class App : Application
11 | {
12 | // Single Instance GUID
13 | public static Guid InstanceGuid = new Guid("30fa6b68-de2b-4a43-a9f1-6b23f4ba2b56");
14 | Mutex instanceMutex;
15 |
16 | public App()
17 | {
18 |
19 | //
20 | // Prevent multiple instances of TabletDriverGUI
21 | //
22 | instanceMutex = new Mutex(true, "Local\\" + InstanceGuid.ToString());
23 | if (instanceMutex.WaitOne(TimeSpan.Zero, true))
24 | {
25 |
26 | //
27 | // Kill old TabletDriverService.exe instances
28 | //
29 | Process[] processes = Process.GetProcessesByName("TabletDriverService");
30 | foreach (Process process in processes)
31 | {
32 | if (process.ProcessName == "TabletDriverService")
33 | {
34 | try
35 | {
36 | process.Kill();
37 | }
38 | catch (Exception)
39 | {
40 | MessageBox.Show(
41 | "You have another TabletDriverService.exe running in the background. " +
42 | "Please shutdown that before starting the GUI!",
43 | "Error!", MessageBoxButton.OK, MessageBoxImage.Error
44 | );
45 | instanceMutex.ReleaseMutex();
46 | Shutdown();
47 | return;
48 | }
49 | }
50 | }
51 |
52 | //
53 | // Check Wacom processes
54 | //
55 | string[] wacomProcessNames =
56 | {
57 | "Pen_Tablet",
58 | "Wacom_Tablet"
59 | };
60 |
61 | processes = Process.GetProcesses();
62 | foreach (Process process in processes)
63 | {
64 | foreach (string wacomProcessName in wacomProcessNames)
65 | {
66 | if (process.ProcessName.ToLower() == wacomProcessName.ToLower())
67 | {
68 | try
69 | {
70 | process.Kill();
71 | }
72 | catch (Exception)
73 | {
74 | MessageBox.Show(
75 | "You have Wacom driver processes running in the background:\n " +
76 | string.Join("\n ", wacomProcessNames) +
77 | "\n\nPlease shutdown those before starting the GUI!",
78 | "Error!", MessageBoxButton.OK, MessageBoxImage.Error
79 | );
80 | instanceMutex.ReleaseMutex();
81 | Shutdown();
82 | return;
83 | }
84 | }
85 | }
86 | }
87 |
88 |
89 | MainWindow mainWindow = new MainWindow();
90 | mainWindow.Show();
91 | Exit += App_Exit;
92 | }
93 | else
94 | {
95 | // Broadcast to the another instance to show itself
96 | NativeMethods.PostMessage(
97 | (IntPtr)NativeMethods.HWND_BROADCAST,
98 | NativeMethods.WM_SHOWTABLETDRIVERGUI,
99 | IntPtr.Zero,
100 | IntPtr.Zero);
101 | Shutdown();
102 | }
103 | }
104 |
105 | private void App_Exit(object sender, ExitEventArgs e)
106 | {
107 | try
108 | {
109 | instanceMutex.ReleaseMutex();
110 | }
111 | catch (Exception)
112 | {
113 | }
114 | }
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/TabletDriverGUI/Area.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows;
3 |
4 | namespace TabletDriverGUI
5 | {
6 | public class Area
7 | {
8 | private double _width;
9 | private double _height;
10 |
11 | public double Width
12 | {
13 | get
14 | {
15 | return _width;
16 | }
17 | set
18 | {
19 | _width = value;
20 | UpdateCorners();
21 |
22 | }
23 | }
24 | public double Height
25 | {
26 | get
27 | {
28 | return _height;
29 | }
30 | set
31 | {
32 | _height = value;
33 | UpdateCorners();
34 |
35 | }
36 | }
37 | public double X;
38 | public double Y;
39 | public double Rotation
40 | {
41 | get { return _rotation; }
42 | set
43 | {
44 | double angle;
45 | _rotation = value;
46 | angle = _rotation * Math.PI / 180;
47 | _rotationMatrix[0] = Math.Cos(angle);
48 | _rotationMatrix[1] = Math.Sin(angle);
49 | _rotationMatrix[2] = -Math.Sin(angle);
50 | _rotationMatrix[3] = Math.Cos(angle);
51 | UpdateCorners();
52 | }
53 | }
54 |
55 | private double _rotation;
56 | private double[] _rotationMatrix;
57 |
58 | private Point[] _corners;
59 |
60 | public Area()
61 | {
62 | _corners = new Point[4] {
63 | new Point(0,0),
64 | new Point(0,0),
65 | new Point(0,0),
66 | new Point(0,0)
67 | };
68 | _rotation = 0;
69 | _rotationMatrix = new double[4] { 1, 0, 0, 1 };
70 |
71 | _width = 0;
72 | _height = 0;
73 | X = 0;
74 | Y = 0;
75 |
76 | }
77 | public Area(double width, double height, double x, double y) : this()
78 | {
79 | _width = width;
80 | _height = height;
81 | X = x;
82 | Y = y;
83 | UpdateCorners();
84 | }
85 |
86 |
87 | private void UpdateCorners()
88 | {
89 | GetRotatedPoint(ref _corners[0], -_width / 2.0, -_height / 2.0);
90 | GetRotatedPoint(ref _corners[1], _width / 2.0, -_height / 2.0);
91 | GetRotatedPoint(ref _corners[2], _width / 2.0, _height / 2.0);
92 | GetRotatedPoint(ref _corners[3], -_width / 2.0, _height / 2.0);
93 | }
94 |
95 | public void GetRotatedPoint(ref Point p, double x, double y)
96 | {
97 | p.X = x * _rotationMatrix[0] + y * _rotationMatrix[1];
98 | p.Y = x * _rotationMatrix[2] + y * _rotationMatrix[3];
99 | }
100 |
101 | //
102 | //
103 | //
104 | public Point[] Corners
105 | {
106 | get { return _corners; }
107 | }
108 |
109 |
110 | //
111 | // Bounding Box
112 | //
113 | public double[] GetBoundingBox()
114 | {
115 | double[] box = new double[4] {
116 | 999999,-99999,
117 | 999999,-99999
118 | };
119 | foreach (Point p in _corners)
120 | {
121 | if (p.X < box[0]) box[0] = p.X;
122 | if (p.X > box[1]) box[1] = p.X;
123 | if (p.Y < box[2]) box[2] = p.Y;
124 | if (p.Y > box[3]) box[3] = p.Y;
125 |
126 | }
127 |
128 | return box;
129 | }
130 |
131 | //
132 | // Scale to fit inside another area
133 | //
134 | public void ScaleInside(Area target)
135 | {
136 | double scale;
137 | double[] box = GetBoundingBox();
138 |
139 | scale = Math.Max(
140 | Math.Abs(box[1] * 2 / target.Width),
141 | Math.Abs(box[3] * 2 / target.Height)
142 | );
143 |
144 | _width /= scale;
145 | _height /= scale;
146 | UpdateCorners();
147 | }
148 |
149 | public void MoveInside(Area target)
150 | {
151 | double[] box = GetBoundingBox();
152 | double[] targetBox = target.GetBoundingBox();
153 | if (X + box[0] < target.X + targetBox[0])
154 | X = target.X + targetBox[0] - box[0];
155 | if (X + box[1] > target.X + targetBox[1])
156 | X = target.X + targetBox[1] - box[1];
157 |
158 | if (Y + box[2] < target.Y + targetBox[2])
159 | Y = target.Y + targetBox[2] - box[2];
160 | if (Y + box[3] > target.Y + targetBox[3])
161 | Y = target.Y + targetBox[3] - box[3];
162 | }
163 |
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/TabletDriverService/TabletDriverService.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Header Files
20 |
21 |
22 | Header Files
23 |
24 |
25 | Header Files
26 |
27 |
28 | Header Files
29 |
30 |
31 | Header Files
32 |
33 |
34 | Header Files
35 |
36 |
37 | Header Files
38 |
39 |
40 | Header Files
41 |
42 |
43 | Header Files
44 |
45 |
46 | Header Files
47 |
48 |
49 | Header Files
50 |
51 |
52 | Header Files
53 |
54 |
55 | Header Files
56 |
57 |
58 | Header Files
59 |
60 |
61 | Header Files
62 |
63 |
64 | Header Files
65 |
66 |
67 | Header Files
68 |
69 |
70 | Header Files
71 |
72 |
73 |
74 |
75 | Source Files
76 |
77 |
78 | Source Files
79 |
80 |
81 | Source Files
82 |
83 |
84 | Source Files
85 |
86 |
87 | Source Files
88 |
89 |
90 | Source Files
91 |
92 |
93 | Source Files
94 |
95 |
96 | Source Files
97 |
98 |
99 | Source Files
100 |
101 |
102 | Source Files
103 |
104 |
105 | Source Files
106 |
107 |
108 | Source Files
109 |
110 |
111 | Source Files
112 |
113 |
114 | Source Files
115 |
116 |
117 | Source Files
118 |
119 |
120 | Source Files
121 |
122 |
123 | Source Files
124 |
125 |
126 | Source Files
127 |
128 |
129 |
130 |
131 | Resource Files
132 |
133 |
134 | Resource Files
135 |
136 |
137 | Resource Files
138 |
139 |
140 | Resource Files
141 |
142 |
143 |
--------------------------------------------------------------------------------
/TabletDriverGUI/WacomArea.xaml.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Win32;
2 | using System;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text.RegularExpressions;
6 | using System.Windows;
7 |
8 | namespace TabletDriverGUI
9 | {
10 | ///
11 | /// Interaction logic for WacomArea.xaml
12 | ///
13 | public partial class WacomArea : Window
14 | {
15 | public WacomArea()
16 | {
17 | WindowStartupLocation = WindowStartupLocation.CenterScreen;
18 | InitializeComponent();
19 | }
20 |
21 | private void ButtonSet_Click(object sender, RoutedEventArgs e)
22 | {
23 | DialogResult = true;
24 | }
25 |
26 | private void ButtonCancel_Click(object sender, RoutedEventArgs e)
27 | {
28 | DialogResult = false;
29 | }
30 |
31 | private void ButtonLoad_Click(object sender, RoutedEventArgs e)
32 | {
33 | OpenFileDialog dialog = new OpenFileDialog
34 | {
35 | InitialDirectory = Directory.GetCurrentDirectory(),
36 | Filter = "Wacom Backup(*.wacomprefs;*.tabletprefs)|*.wacomprefs;*.tabletprefs"
37 | };
38 | if (dialog.ShowDialog() == true)
39 | {
40 | LoadFromBackup(dialog.FileName);
41 | }
42 | }
43 |
44 | //
45 | // Load setting from Wacom backup
46 | //
47 | private void LoadFromBackup(string filepath)
48 | {
49 | try
50 | {
51 | string data = File.ReadAllText(filepath);
52 | data = data.Replace("<", "<");
53 | data = data.Replace(">", ">");
54 |
55 | double[] areaValues = new double[4] { 0, 0, 0, 0 };
56 | double[] lastAreaValues = new double[4];
57 | bool first = true;
58 |
59 | /*
60 |
61 |
62 | 15200
63 | 9500
64 | 0
65 |
66 |
67 | 0
68 | 0
69 | 0
70 |
71 |
72 | */
73 |
74 | //
75 | // Regular expression
76 | //
77 | MatchCollection matches = Regex.Matches(
78 | data,
79 | "]*>.*?" +
80 | "([0-9]+).*?" +
82 | "([0-9]+).*?" +
83 | "([0-9]+).*?" +
85 | "([0-9]+).*?" +
86 | "",
87 | RegexOptions.Singleline | RegexOptions.IgnoreCase
88 | );
89 |
90 | //
91 | // Loop through regex matches
92 | //
93 | foreach (Match match in matches)
94 | {
95 | if (
96 | Utils.ParseNumber(match.Groups[1].ToString(), out areaValues[0]) &&
97 | Utils.ParseNumber(match.Groups[2].ToString(), out areaValues[1]) &&
98 | Utils.ParseNumber(match.Groups[3].ToString(), out areaValues[2]) &&
99 | Utils.ParseNumber(match.Groups[4].ToString(), out areaValues[3])
100 | )
101 | {
102 | // Stop at first different area value set
103 | if (!first && !areaValues.SequenceEqual(lastAreaValues))
104 | break;
105 |
106 | Array.Copy(areaValues, lastAreaValues, 4);
107 | first = false;
108 | }
109 | }
110 |
111 | // Set text fields
112 | if (areaValues[0] != 0 && areaValues[1] != 0)
113 | {
114 | textWacomLeft.Text = Utils.GetNumberString(areaValues[2]);
115 | textWacomRight.Text = Utils.GetNumberString(areaValues[2] + areaValues[0]);
116 | textWacomTop.Text = Utils.GetNumberString(areaValues[3]);
117 | textWacomBottom.Text = Utils.GetNumberString(areaValues[3] + areaValues[1]);
118 | }
119 |
120 | // Show error
121 | else
122 | {
123 | MessageBox.Show("Couldn't read the backup file!", "ERROR!",
124 | MessageBoxButton.OK, MessageBoxImage.Error);
125 | }
126 |
127 | }
128 |
129 | // Exception
130 | catch (Exception)
131 | {
132 | MessageBox.Show("Couldn't read the backup file!", "ERROR!",
133 | MessageBoxButton.OK, MessageBoxImage.Error);
134 | }
135 |
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/TabletDriverGUI/Configuration.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Collections;
4 | using System.IO;
5 | using System.Xml;
6 | using System.Xml.Serialization;
7 |
8 | namespace TabletDriverGUI
9 | {
10 | [XmlRootAttribute("Configuration", IsNullable = true)]
11 | public class Configuration
12 | {
13 | public int ConfigVersion;
14 | public Area TabletArea;
15 | public Area TabletFullArea;
16 | public bool ForceAspectRatio;
17 | public double Rotation;
18 | public bool Invert;
19 | public bool ForceFullArea;
20 | public OutputModes OutputMode;
21 | public enum OutputModes
22 | {
23 | Absolute = 0,
24 | Relative = 1,
25 | Digitizer = 2
26 | }
27 |
28 | public Area ScreenArea;
29 |
30 | public double SmoothingLatency;
31 | public int SmoothingInterval;
32 | public bool SmoothingEnabled;
33 |
34 | public bool AntichatterEnabled;
35 | public double AntichatterStrength;
36 | public double AntichatterMultiplier;
37 | public double AntichatterOffsetX;
38 | public double AntichatterOffsetY;
39 |
40 | public bool PredictionEnabled;
41 | public double PredictionSharpness;
42 | public double PredictionStrength;
43 | public double PredictionOffsetX;
44 | public double PredictionOffsetY;
45 |
46 | public Area DesktopSize;
47 | public bool AutomaticDesktopSize;
48 |
49 | [XmlArray("ButtonMap")]
50 | [XmlArrayItem("Button")]
51 | public int[] ButtonMap;
52 | public bool DisableButtons;
53 | public int mouseWheelSpeed;
54 |
55 | [XmlArray("CommandsAfter")]
56 | [XmlArrayItem("Command")]
57 | public string[] CommandsAfter;
58 |
59 | [XmlArray("CommandsBefore")]
60 | [XmlArrayItem("Command")]
61 | public string[] CommandsBefore;
62 |
63 | public int WindowWidth;
64 | public int WindowHeight;
65 |
66 | public bool RunAtStartup;
67 |
68 | public string DriverPath;
69 | public string DriverArguments;
70 |
71 | public bool DeveloperMode;
72 |
73 |
74 | public Configuration()
75 | {
76 | ConfigVersion = 1;
77 |
78 | // Screen Map
79 | ScreenArea = new Area(0, 0, 0, 0);
80 |
81 | // Tablet area
82 | TabletArea = new Area(80, 45, 40, 22.5);
83 | TabletFullArea = new Area(100, 50, 50, 25);
84 | ForceFullArea = true;
85 | OutputMode = 0;
86 | ForceAspectRatio = true;
87 | Rotation = 0;
88 |
89 | DesktopSize = new Area(0, 0, 0, 0);
90 | AutomaticDesktopSize = true;
91 |
92 | ButtonMap = new int[] { 1, 2, 3 };
93 | DisableButtons = false;
94 | mouseWheelSpeed = 50;
95 |
96 | SmoothingEnabled = false;
97 | SmoothingLatency = 0;
98 | SmoothingInterval = 4;
99 |
100 | AntichatterEnabled = true;
101 | AntichatterStrength = 3.0;
102 | AntichatterMultiplier = 1.0;
103 | AntichatterOffsetX = 0.0;
104 | AntichatterOffsetY = 1.0;
105 |
106 | PredictionEnabled = true;
107 | PredictionSharpness = 1.0;
108 | PredictionStrength = 1.1;
109 | PredictionOffsetX = 3.0;
110 | PredictionOffsetY = 0.3;
111 |
112 | CommandsAfter = new string[] { "" };
113 | CommandsBefore = new string[] { "" };
114 |
115 | WindowWidth = 800;
116 | WindowHeight = 710;
117 |
118 | RunAtStartup = false;
119 |
120 | DriverPath = "bin/TabletDriverService.exe";
121 | DriverArguments = "config/init.cfg";
122 |
123 | DeveloperMode = false;
124 | }
125 |
126 |
127 | public void Write(string filename)
128 | {
129 | var fileWriter = new StreamWriter(filename);
130 |
131 | XmlSerializer serializer = new XmlSerializer(typeof(Configuration));
132 | XmlWriterSettings xmlWriterSettings = new XmlWriterSettings() { Indent = true };
133 | XmlWriter writer = XmlWriter.Create(fileWriter, xmlWriterSettings);
134 | try
135 | {
136 | serializer.Serialize(writer, this);
137 | }
138 | catch (Exception)
139 | {
140 | fileWriter.Close();
141 | throw;
142 | }
143 | fileWriter.Close();
144 | }
145 |
146 | public static Configuration CreateFromFile(string filename)
147 | {
148 | Configuration config = null;
149 | var serializer = new XmlSerializer(typeof(Configuration));
150 | var settings = new XmlWriterSettings() { Indent = true };
151 | var reader = XmlReader.Create(filename);
152 |
153 | try
154 | {
155 | config = (Configuration)serializer.Deserialize(reader);
156 | }
157 | catch (Exception)
158 | {
159 | reader.Close();
160 | throw;
161 | }
162 | reader.Close();
163 | return config;
164 | }
165 | }
166 |
167 |
168 | }
169 |
--------------------------------------------------------------------------------
/TabletDriverService/TabletFilterSmoothing.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "TabletFilterSmoothing.h"
3 |
4 | //
5 | // Constructor
6 | //
7 | TabletFilterSmoothing::TabletFilterSmoothing() {
8 | latency = 2.0;
9 | weight = 1.000;
10 | threshold = 0.9;
11 |
12 | AntichatterEnabled = true;
13 | antichatterStrength = 3;
14 | antichatterMultiplier = 1;
15 | antichatterOffsetX = 0.0;
16 | antichatterOffsetY = 0.0;
17 |
18 | prev_target.x = 0.0;
19 | prev_target.y = 0.0;
20 |
21 | PredictionEnabled = true;
22 | PredictionSharpness = 1.0;
23 | PredictionStrength = 1.1;
24 | PredictionOffsetX = 3.0;
25 | PredictionOffsetY = 0.3;
26 | }
27 |
28 |
29 | //
30 | // Destructor
31 | //
32 | TabletFilterSmoothing::~TabletFilterSmoothing() {
33 | }
34 |
35 |
36 | //
37 | // TabletFilter methods
38 | //
39 |
40 | // Reset
41 | void TabletFilterSmoothing::Reset(Vector2D position) {
42 | target.Set(position);
43 | prev_target.Set(position);
44 | calculated_target.Set(position);
45 | position.Set(position);
46 | }
47 |
48 | // Set target position
49 | void TabletFilterSmoothing::SetTarget(Vector2D vector, double h) {
50 | this->target.x = vector.x;
51 | this->target.y = vector.y;
52 | this->z = h;
53 | }
54 |
55 | // Set current position
56 | void TabletFilterSmoothing::SetPosition(Vector2D vector, double h) {
57 | position.x = vector.x;
58 | position.y = vector.y;
59 | z = h;
60 | }
61 |
62 | // Get current position
63 | bool TabletFilterSmoothing::GetPosition(Vector2D *outputVector) {
64 | outputVector->x = position.x;
65 | outputVector->y = position.y;
66 | return true;
67 | }
68 |
69 | // Update
70 | void TabletFilterSmoothing::Update() {
71 |
72 | double deltaX, deltaY, distance, weightModifier, predictionModifier;
73 |
74 | // Prediction
75 | if (PredictionEnabled)
76 | {
77 | // Calculate predicted position onNewPacket
78 | if (prev_target.x != target.x or prev_target.y != target.y)
79 | {
80 | // Calculate distance between last 2 packets and prediction
81 | deltaX = target.x - prev_target.x;
82 | deltaY = target.y - prev_target.y;
83 | distance = sqrt(deltaX * deltaX + deltaY * deltaY);
84 | predictionModifier = 1 / cosh((distance - PredictionOffsetX) * PredictionSharpness) * PredictionStrength + PredictionOffsetY;
85 |
86 | // Apply prediction
87 | deltaX *= predictionModifier;
88 | deltaY *= predictionModifier;
89 |
90 | // Update predicted position
91 | calculated_target.x = target.x + deltaX;
92 | calculated_target.y = target.y + deltaY;
93 |
94 | // Update old position for further prediction
95 | prev_target.x = target.x;
96 | prev_target.y = target.y;
97 | }
98 | }
99 | else {
100 | calculated_target.x = target.x;
101 | calculated_target.y = target.y;
102 | }
103 |
104 | // Smoothing
105 | deltaX = calculated_target.x - position.x;
106 | deltaY = calculated_target.y - position.y;
107 | distance = sqrt(deltaX * deltaX + deltaY * deltaY);
108 |
109 | /*if (distance <= 0.01) {
110 | position.x = target.x;
111 | position.y = target.y;
112 | }
113 | // Regular smoothing
114 | else*/ if (!AntichatterEnabled) {
115 | position.x += deltaX * weight;
116 | position.y += deltaY * weight;
117 | }
118 | // Devocub smoothing
119 | else {
120 |
121 | // Increase weight of filter in {formula} times
122 | weightModifier = pow((distance + antichatterOffsetX), antichatterStrength*-1)*antichatterMultiplier;
123 |
124 | // Limit minimum
125 | if (weightModifier + antichatterOffsetY < 0)
126 | weightModifier = 0;
127 | else
128 | weightModifier = pow((distance + antichatterOffsetX), antichatterStrength*-1)*antichatterMultiplier + antichatterOffsetY;
129 |
130 | // Limit maximum
131 | /*if (weightModifier > 1000)
132 | weightModifier = 1000;*/
133 |
134 | weightModifier = weight / weightModifier;
135 | if (weightModifier > 1) weightModifier = 1;
136 | else if (weightModifier < 0) weightModifier = 0;
137 |
138 | position.x += deltaX * weightModifier;
139 | position.y += deltaY * weightModifier;
140 |
141 | // z ~= height, strength of signal from pen
142 | // 480 z is 14-41
143 | // 470 z is 0-30
144 | }
145 | }
146 |
147 |
148 |
149 |
150 |
151 | // Set position
152 | double TabletFilterSmoothing::SetPosition(double x, double y, double h) {
153 | this->position.x = x;
154 | this->position.y = y;
155 | this->z = h;
156 | }
157 |
158 |
159 | //
160 | // Calculate filter latency
161 | //
162 | double TabletFilterSmoothing::GetLatency(double filterWeight, double interval, double threshold) {
163 | double target = 1 - threshold;
164 | double stepCount = -log(1 / target) / log(1 - filterWeight);
165 | return stepCount * interval;
166 | }
167 | double TabletFilterSmoothing::GetLatency(double filterWeight) {
168 | return this->GetLatency(filterWeight, timerInterval, threshold);
169 | }
170 | double TabletFilterSmoothing::GetLatency() {
171 | return this->GetLatency(weight, timerInterval, threshold);
172 | }
173 |
174 |
175 | //
176 | // Calculate filter weight
177 | //
178 | double TabletFilterSmoothing::GetWeight(double latency, double interval, double threshold) {
179 | double stepCount = latency / interval;
180 | double target = 1 - threshold;
181 | return 1 - 1 / pow(1 / target, 1 / stepCount);
182 | }
183 | double TabletFilterSmoothing::GetWeight(double latency) {
184 | return this->GetWeight(latency, this->timerInterval, this->threshold);
185 | }
186 |
187 | // Set Latency
188 | void TabletFilterSmoothing::SetLatency(double latency) {
189 | this->weight = GetWeight(latency);
190 | this->latency = latency;
191 | }
192 |
193 |
194 |
--------------------------------------------------------------------------------
/TabletDriverService/Logger.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "Logger.h"
3 |
4 | //
5 | // Constructor
6 | //
7 | Logger::Logger() {
8 | verbosity = LogLevelDebug;
9 | newMessage = false;
10 | directPrint = false;
11 | }
12 |
13 |
14 | void Logger::OutputMessage(LogItem *message) {
15 | char timeBuffer[64];
16 | char moduleBuffer[128];
17 |
18 | strftime(timeBuffer, 64, "%Y-%m-%d %H:%M:%S", &message->time);
19 | if(message->module.length() > 0) {
20 | sprintf_s(moduleBuffer, " [%s]", message->module.c_str());
21 | } else {
22 | moduleBuffer[0] = 0;
23 | }
24 |
25 | try {
26 | cout << timeBuffer << moduleBuffer << " [" << levelNames[message->level] << "] " << message->text << flush;
27 | } catch(exception) {
28 | exit(1);
29 | }
30 | if(logFile && logFile.is_open()) {
31 | logFile << timeBuffer << moduleBuffer << " [" << levelNames[message->level] << "] " << message->text << flush;
32 | }
33 | }
34 |
35 | //
36 | // Process messages
37 | //
38 | void Logger::ProcessMessages() {
39 |
40 | // Lock message list
41 | lockMessages.lock();
42 |
43 | // Copy message list to a temporary list
44 | vector tmp(messages);
45 | messages.clear();
46 |
47 | // Unlock message list
48 | lockMessages.unlock();
49 |
50 | // Loop through messages
51 | for(auto message : tmp) {
52 | if(!directPrint) {
53 | OutputMessage(&message);
54 | }
55 | }
56 | }
57 |
58 |
59 | //
60 | // Log message
61 | //
62 | void Logger::LogMessage(int level, string module, const char *fmt, ...) {
63 | char message[4096];
64 | int maxLength = sizeof(message) - 1;
65 | int index;
66 | time_t t;
67 | message[0] = 0;
68 |
69 | // Clamp level
70 | if(level < 2)
71 | level = 2;
72 | else if(level > 8)
73 | level = 8;
74 |
75 | if(level <= verbosity) {
76 | index = 0;
77 | time(&t);
78 |
79 | // Loop through arguments
80 | va_list ap;
81 | va_start(ap, fmt);
82 | if(index < maxLength) index += vsnprintf(message + index, maxLength - index, fmt, ap);
83 | va_end(ap);
84 |
85 | // New line at the end when the message is larger than max length
86 | if(index >= maxLength) {
87 | message[maxLength - 1] = '\n';
88 | message[maxLength] = 0;
89 | }
90 |
91 | // Add message
92 | LogItem logItem;
93 | localtime_s(&logItem.time, &t);
94 | logItem.level = level;
95 | logItem.module = module;
96 | logItem.text = message;
97 | AddMessage(&logItem);
98 | }
99 | }
100 |
101 | //
102 | // Log buffer data
103 | //
104 | void Logger::LogBuffer(int level, string module, void *buffer, int length, const char *fmt, ...) {
105 | bool newLine = false;
106 | char message[4096];
107 | int maxLength = sizeof(message) - 1;
108 | time_t t;
109 | int index;
110 | message[0] = 0;
111 |
112 | // Clamp level
113 | if(level < 2)
114 | level = 2;
115 | else if(level > 7)
116 | level = 7;
117 |
118 | if(level <= verbosity) {
119 | index = 0;
120 | time(&t);
121 |
122 | // Loop through arguments
123 | va_list ap;
124 | va_start(ap, fmt);
125 | if(index < maxLength) index += vsnprintf(message + index, maxLength - index, fmt, ap);
126 | va_end(ap);
127 |
128 | // Detect new line
129 | newLine = (fmt[strlen(fmt) - 1] == '\n');
130 | if(newLine) {
131 | if(index < maxLength) index += snprintf(message + index, maxLength - index, " { ");
132 |
133 | } else {
134 | if(index < maxLength) index += snprintf(message + index, maxLength - index, "{ ");
135 | }
136 |
137 |
138 | // Loop through buffer bytes
139 | for(int i = 0; i < length; i++) {
140 |
141 | // Last byte
142 | if(i == length - 1) {
143 | if(index < maxLength) index += snprintf(message + index, maxLength - index, "0x%02x", ((unsigned char*)buffer)[i]);
144 |
145 | //
146 | } else {
147 | if(index < maxLength) index += snprintf(message + index, maxLength - index, "0x%02x, ", ((unsigned char*)buffer)[i]);
148 |
149 | }
150 | // New line after every 12th byte
151 | if(newLine && (i + 1) % 12 == 0 && i != length - 1) {
152 | if(index < maxLength) index += snprintf(message + index, maxLength - index, "\n ");
153 | }
154 | }
155 |
156 | // Ending bracket
157 | if(index < maxLength) index += snprintf(message + index, maxLength - index, " }\n");
158 |
159 | // New line at the end when the message is larger than max length
160 | if(index >= maxLength) {
161 | message[maxLength - 1] = '\n';
162 | message[maxLength] = 0;
163 | }
164 |
165 | // Add message
166 | LogItem logItem;
167 | localtime_s(&logItem.time, &t);
168 | logItem.level = level;
169 | logItem.module = module;
170 | logItem.text = message;
171 | AddMessage(&logItem);
172 | }
173 | }
174 |
175 | //
176 | // Add message to list
177 | //
178 | void Logger::AddMessage(LogItem *message) {
179 |
180 | // Direct print (skips the message buffer)
181 | if(directPrint) {
182 | OutputMessage(message);
183 | }
184 |
185 | // Lock message list
186 | lockMessages.lock();
187 |
188 | // Add message
189 | messages.push_back(*message);
190 |
191 | // Unlock message list
192 | lockMessages.unlock();
193 |
194 | newMessage = true;
195 | }
196 |
197 |
198 | //
199 | // Logger thread
200 | //
201 | void Logger::run() {
202 | while(true) {
203 |
204 | // Wait for messages
205 | if(newMessage) {
206 |
207 | // Set new message flag to false
208 | newMessage = false;
209 |
210 | // Process messages
211 | ProcessMessages();
212 | }
213 |
214 | // Shutdown the thread
215 | if(!isRunning && !newMessage) break;
216 |
217 | // Sleep 10ms
218 | Sleep(10);
219 | }
220 | }
221 |
222 | //
223 | // Open log file
224 | //
225 | bool Logger::OpenLogFile(string filename) {
226 | if(logFile && logFile.is_open()) {
227 | logFile.close();
228 | }
229 | logFile = ofstream(filename, ofstream::out);
230 | if(!logFile) {
231 | return false;
232 | }
233 | logFilename = filename;
234 | return true;
235 | }
236 |
237 | //
238 | // Close log file
239 | //
240 | bool Logger::CloseLogFile() {
241 | if(logFile && logFile.is_open()) {
242 | logFile.close();
243 | return true;
244 | }
245 | return false;
246 | }
247 |
248 |
249 | //
250 | // Start logger thread
251 | //
252 | void Logger::Start() {
253 | if(!isRunning) {
254 | isRunning = true;
255 | threadLog = thread([this] { this->run(); });
256 | }
257 | }
258 |
259 | //
260 | // Stop logger thread
261 | //
262 | void Logger::Stop() {
263 | if(isRunning) {
264 | isRunning = false;
265 | newMessage = true;
266 | threadLog.join();
267 | if(logFile && logFile.is_open()) {
268 | logFile.close();
269 | }
270 | }
271 | }
272 |
273 | Logger logger;
274 |
--------------------------------------------------------------------------------
/TabletDriverGUI/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 |
122 | ..\Resources\AppIcon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
123 |
124 |
--------------------------------------------------------------------------------
/TabletDriverGUI/TabletDriverGUI.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {6793EBBD-0EC4-4254-9573-A19ECA79F2C8}
8 | WinExe
9 | TabletDriverGUI
10 | TabletDriverGUI
11 | v4.6.1
12 | 512
13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 4
15 | true
16 | publish\
17 | true
18 | Disk
19 | false
20 | Foreground
21 | 7
22 | Days
23 | false
24 | false
25 | true
26 | 0
27 | 1.0.0.%2a
28 | false
29 | false
30 | true
31 |
32 |
33 | AnyCPU
34 | true
35 | full
36 | false
37 | bin\Debug\
38 | DEBUG;TRACE
39 | prompt
40 | 4
41 |
42 |
43 | AnyCPU
44 | pdbonly
45 | false
46 | bin\Release\
47 | TRACE
48 | prompt
49 | 4
50 | true
51 | Off
52 |
53 |
54 | Resources\AppIcon.ico
55 |
56 |
57 |
58 | app.manifest
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | 4.0
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | MSBuild:Compile
78 | Designer
79 |
80 |
81 |
82 |
83 |
84 |
85 | WacomArea.xaml
86 |
87 |
88 | MSBuild:Compile
89 | Designer
90 |
91 |
92 | App.xaml
93 | Code
94 |
95 |
96 |
97 |
98 | MainWindow.xaml
99 | Code
100 |
101 |
102 | Designer
103 | MSBuild:Compile
104 |
105 |
106 |
107 |
108 | Code
109 |
110 |
111 | True
112 | True
113 | Resources.resx
114 |
115 |
116 | True
117 | Settings.settings
118 | True
119 |
120 |
121 | ResXFileCodeGenerator
122 | Resources.Designer.cs
123 |
124 |
125 |
126 | SettingsSingleFileGenerator
127 | Settings.Designer.cs
128 |
129 |
130 |
131 |
132 | Designer
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 | False
141 | Microsoft .NET Framework 4.6.1 %28x86 and x64%29
142 | true
143 |
144 |
145 | False
146 | .NET Framework 3.5 SP1
147 | false
148 |
149 |
150 |
151 |
--------------------------------------------------------------------------------
/TabletDriverService/HIDDevice.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "HIDDevice.h"
3 |
4 | #define LOG_MODULE "HIDDevice"
5 | #include "Logger.h"
6 |
7 | HIDDevice::HIDDevice(USHORT VendorId, USHORT ProductId, USHORT UsagePage, USHORT Usage) : HIDDevice() {
8 | this->vendorId = VendorId;
9 | this->productId = ProductId;
10 | this->usagePage = UsagePage;
11 | this->usage = Usage;
12 | if (this->OpenDevice(&this->_deviceHandle, this->vendorId, this->productId, this->usagePage, this->usage)) {
13 | isOpen = true;
14 | }
15 | }
16 |
17 | HIDDevice::HIDDevice() {
18 | isOpen = false;
19 | _deviceHandle = NULL;
20 | }
21 |
22 | HIDDevice::~HIDDevice() {
23 | CloseDevice();
24 | }
25 |
26 | bool HIDDevice::OpenDevice(HANDLE *handle, USHORT vendorId, USHORT productId, USHORT usagePage, USHORT usage) {
27 | HDEVINFO deviceInfo;
28 | SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
29 | PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData;
30 | SP_DEVINFO_DATA deviceInfoData;
31 | DWORD dwSize, dwMemberIdx;
32 | GUID hidGuid;
33 | BYTE stringBytes[1024];
34 |
35 | PHIDP_PREPARSED_DATA hidPreparsedData;
36 | HIDD_ATTRIBUTES hidAttributes;
37 | HIDP_CAPS hidCapabilities;
38 |
39 | HANDLE deviceHandle;
40 |
41 | HANDLE resultHandle = 0;
42 |
43 | HidD_GetHidGuid(&hidGuid);
44 |
45 | // Setup device info
46 | deviceInfo = SetupDiGetClassDevs(&hidGuid, NULL, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
47 | if (deviceInfo == INVALID_HANDLE_VALUE) {
48 | LOG_ERROR("Invalid device info!\n");
49 | return false;
50 | }
51 |
52 | // Enumerate device interface data
53 | deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
54 | dwMemberIdx = 0;
55 | SetupDiEnumDeviceInterfaces(deviceInfo, NULL, &hidGuid, dwMemberIdx, &deviceInterfaceData);
56 | while (GetLastError() != ERROR_NO_MORE_ITEMS) {
57 | deviceInfoData.cbSize = sizeof(deviceInfoData);
58 |
59 | // Get the required buffer size for device interface detail data
60 | SetupDiGetDeviceInterfaceDetail(deviceInfo, &deviceInterfaceData, NULL, 0, &dwSize, NULL);
61 |
62 | // Allocate device interface detail data
63 | deviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(dwSize);
64 | deviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
65 |
66 | // Get interface detail
67 | if (SetupDiGetDeviceInterfaceDetail(deviceInfo, &deviceInterfaceData, deviceInterfaceDetailData, dwSize, &dwSize, &deviceInfoData)) {
68 |
69 | // Open HID
70 | deviceHandle = CreateFile(
71 | deviceInterfaceDetailData->DevicePath,
72 | GENERIC_READ | GENERIC_WRITE,
73 | FILE_SHARE_READ | FILE_SHARE_WRITE,
74 | NULL,
75 | OPEN_EXISTING,
76 | 0,
77 | NULL);
78 |
79 | // HID handle valid?
80 | if (deviceHandle != INVALID_HANDLE_VALUE) {
81 |
82 | // HID Attributes
83 | HidD_GetAttributes(deviceHandle, &hidAttributes);
84 |
85 | // HID Preparsed data
86 | HidD_GetPreparsedData(deviceHandle, &hidPreparsedData);
87 |
88 | // HID Capabilities
89 | HidP_GetCaps(hidPreparsedData, &hidCapabilities);
90 |
91 | // Debug logging
92 | if (this->debugEnabled) {
93 |
94 | string manufacturerName = "";
95 | string productName = "";
96 |
97 | // HID manufacturer string
98 | if (HidD_GetManufacturerString(deviceHandle, &stringBytes, sizeof(stringBytes))) {
99 | for (int i = 0; i < (int)sizeof(stringBytes); i += 2) {
100 | if (stringBytes[i]) {
101 | manufacturerName.push_back(stringBytes[i]);
102 | }
103 | else {
104 | break;
105 | }
106 | }
107 | }
108 |
109 | // HID product string
110 | if (HidD_GetProductString(deviceHandle, &stringBytes, sizeof(stringBytes))) {
111 | for (int i = 0; i < (int)sizeof(stringBytes); i += 2) {
112 | if (stringBytes[i]) {
113 | productName.push_back(stringBytes[i]);
114 | }
115 | else {
116 | break;
117 | }
118 | }
119 | }
120 |
121 | LOG_DEBUG("HID Device: Vendor: '%s' Product: '%s'\n", manufacturerName.c_str(), productName.c_str());
122 | LOG_DEBUG(" Vendor Id: 0x%04X, Product Id: 0x%04X\n",
123 | hidAttributes.VendorID,
124 | hidAttributes.ProductID
125 | );
126 | LOG_DEBUG(" Usage Page: 0x%04X, Usage: 0x%04X\n",
127 | hidCapabilities.UsagePage,
128 | hidCapabilities.Usage
129 | );
130 | LOG_DEBUG(" FeatureLen: %d, InputLen: %d, OutputLen: %d\n",
131 | hidCapabilities.FeatureReportByteLength,
132 | hidCapabilities.InputReportByteLength,
133 | hidCapabilities.OutputReportByteLength
134 | );
135 | LOG_DEBUG("\n");
136 | }
137 |
138 | // Set the result handle if this is the correct device
139 | if (!resultHandle &&
140 | hidAttributes.VendorID == vendorId &&
141 | hidAttributes.ProductID == productId &&
142 | hidCapabilities.UsagePage == usagePage &&
143 | hidCapabilities.Usage == usage
144 | ) {
145 | resultHandle = deviceHandle;
146 |
147 | // Close the HID handle if the device is incorrect
148 | }
149 | else {
150 | CloseHandle(deviceHandle);
151 | }
152 |
153 | // Free HID preparsed data
154 | HidD_FreePreparsedData(hidPreparsedData);
155 | }
156 | }
157 |
158 | // Free memory
159 | delete deviceInterfaceDetailData;
160 |
161 | // Get next interface data
162 | SetupDiEnumDeviceInterfaces(deviceInfo, NULL, &hidGuid, ++dwMemberIdx, &deviceInterfaceData);
163 | }
164 |
165 | // Destroy device info
166 | SetupDiDestroyDeviceInfoList(deviceInfo);
167 |
168 | // Copy found handle
169 | if (resultHandle && resultHandle != INVALID_HANDLE_VALUE) {
170 | memcpy(handle, &resultHandle, sizeof(HANDLE));
171 | return true;
172 | }
173 |
174 | return false;
175 | }
176 |
177 | // Read HID report
178 | int HIDDevice::Read(void *buffer, int length) {
179 | //return HidD_GetInputReport(_deviceHandle, buffer, length);
180 | DWORD bytesRead;
181 | if (ReadFile(_deviceHandle, buffer, length, &bytesRead, 0)) {
182 | return bytesRead;
183 | }
184 | return 0;
185 | }
186 |
187 | // Write HID report
188 | int HIDDevice::Write(void *buffer, int length) {
189 | DWORD bytesWritten;
190 | if (WriteFile(_deviceHandle, buffer, length, &bytesWritten, 0)) {
191 | return bytesWritten;
192 | }
193 | return 0;
194 | }
195 |
196 | // Set feature report
197 | bool HIDDevice::SetFeature(void *buffer, int length) {
198 | return HidD_SetFeature(_deviceHandle, buffer, length);
199 | }
200 |
201 | // Get feature report
202 | bool HIDDevice::GetFeature(void *buffer, int length) {
203 | return HidD_GetFeature(_deviceHandle, buffer, length);
204 | }
205 |
206 | // Close the device
207 | void HIDDevice::CloseDevice() {
208 | if (isOpen && _deviceHandle != NULL && _deviceHandle != INVALID_HANDLE_VALUE) {
209 | try {
210 | CloseHandle(_deviceHandle);
211 | }
212 | catch (exception) {}
213 | }
214 | isOpen = false;
215 | }
216 |
--------------------------------------------------------------------------------
/TabletDriverService/CommandLine.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "CommandLine.h"
3 |
4 | #define LOG_MODULE "CommandLine"
5 | #include "Logger.h"
6 |
7 | //
8 | // Constructor
9 | //
10 | CommandLine::CommandLine(string text) {
11 | this->line = text;
12 | this->Parse(text);
13 | }
14 |
15 | //
16 | // Destructor
17 | //
18 | CommandLine::~CommandLine() {
19 | }
20 |
21 | //
22 | // Command matcher
23 | //
24 | bool CommandLine::is(string command) {
25 |
26 | string match = this->command;
27 | transform(command.begin(), command.end(), command.begin(), ::tolower);
28 | transform(match.begin(), match.end(), match.begin(), ::tolower);
29 |
30 | if (command.compare(match) == 0) {
31 | return true;
32 | }
33 | return false;
34 | }
35 |
36 |
37 | //
38 | // Parse
39 | //
40 | int CommandLine::Parse(string line) {
41 |
42 | string item = "";
43 | vector items;
44 |
45 | int lineLength = line.size();
46 | int itemLength = 0;
47 | int itemCount = 0;
48 | int index = 0;
49 |
50 | char currentChar;
51 | char previousChar = 0;
52 | char splitChars[] = " ,:(){}[]";
53 | char endChars[] = { '\r', '\n', ';', 0 };
54 | char commentChar = '#';
55 | char escapeChar = '\\';
56 | char enclosingChar = '"';
57 |
58 | bool isSplitChar = false;
59 | bool isEndChar = false;
60 | bool isEnclosingChar = false;
61 | bool isLastChar = false;
62 | bool isEnclosed = false;
63 |
64 | for (std::string::iterator it = line.begin(); it != line.end(); ++it) {
65 | currentChar = *it;
66 |
67 | // Comment char
68 | if (!isEnclosed && currentChar == commentChar) {
69 | if (itemLength > 0) {
70 | items.push_back(item);
71 | }
72 | break;
73 | }
74 |
75 | // Is split char?
76 | isSplitChar = false;
77 | for (int i = 0; i < (int)sizeof(splitChars); i++) {
78 | if (splitChars[i] && currentChar == splitChars[i]) {
79 | isSplitChar = true;
80 | break;
81 | }
82 | }
83 |
84 | // Is end char?
85 | isEndChar = false;
86 | for (int i = 0; i < (int)sizeof(endChars); i++) {
87 | if (currentChar == endChars[i]) {
88 | isEndChar = true;
89 | break;
90 | }
91 | }
92 |
93 | // Is last char?
94 | isLastChar = false;
95 | if (index == lineLength - 1) {
96 | isLastChar = true;
97 | }
98 |
99 |
100 | // Toggle enclosing
101 | isEnclosingChar = false;
102 | if (currentChar == enclosingChar && previousChar != escapeChar) {
103 | isEnclosed = !isEnclosed;
104 | isEnclosingChar = true;
105 | }
106 |
107 | // New item
108 | if (
109 | !isEnclosed &&
110 | (
111 | isSplitChar ||
112 | isEndChar ||
113 | (itemCount == 0 && currentChar == '=') ||
114 | (itemCount == 1 && itemLength == 0 && currentChar == '=') ||
115 | isLastChar ||
116 | (isLastChar && isEnclosingChar)
117 | )
118 | ) {
119 |
120 | //INFO("char: %c\n", currentChar);
121 | //INFO("itemCount = %d\n", itemCount);
122 | //INFO("itemLength = %d\n", itemLength);
123 |
124 | // Last char
125 | if (isLastChar && !isEndChar && !isSplitChar) {
126 | if (!isEnclosingChar) {
127 | item.push_back(currentChar);
128 | itemLength = 1;
129 | }
130 | }
131 |
132 | // Create new item
133 | if (itemLength > 0) {
134 | items.push_back(item);
135 | item = "";
136 | itemLength = 0;
137 | itemCount++;
138 | }
139 | else {
140 | item = "";
141 | itemLength = 0;
142 | }
143 |
144 | // Stop parsing at end of the line
145 | if (isEndChar) {
146 | break;
147 | }
148 |
149 | // Add text to item
150 | }
151 | else if (currentChar >= 32) {
152 | if (itemCount == 0 && currentChar == '=') {
153 | }
154 | else if (isEnclosingChar) {
155 | }
156 | else if (currentChar == escapeChar && !isEnclosed) {
157 | }
158 | else {
159 | item.push_back(currentChar);
160 | itemLength++;
161 | }
162 | }
163 | index++;
164 | previousChar = currentChar;
165 | }
166 |
167 | // Set command
168 | if (itemCount > 0) {
169 | command = items[0];
170 | isValid = true;
171 | }
172 | else {
173 | isValid = false;
174 | }
175 |
176 | // Set values
177 | values.clear();
178 | for (int i = 1; i < (int)items.size(); i++) {
179 | values.push_back(items[i]);
180 | }
181 |
182 | valueCount = values.size();
183 | return valueCount;
184 | }
185 |
186 |
187 | //
188 | // Parse hex string
189 | //
190 | string CommandLine::ParseHex(string str) {
191 | if (str.size() >= 3 && str[0] == '0' && str[1] == 'x') {
192 | try {
193 | string tmp = str.substr(2, str.size() - 2);
194 | return to_string(stol(tmp, 0, 16));
195 | }
196 | catch (exception) {
197 | }
198 | }
199 | return str;
200 | }
201 |
202 |
203 | //
204 | // Get string value
205 | //
206 | string CommandLine::GetString(int index, string defaultValue) {
207 | if (index < valueCount) {
208 | return values[index];
209 | }
210 | return defaultValue;
211 | }
212 |
213 |
214 | //
215 | // Get lowercase string value
216 | //
217 | string CommandLine::GetStringLower(int index, string defaultValue) {
218 | string str = GetString(index, defaultValue);
219 | transform(str.begin(), str.end(), str.begin(), ::tolower);
220 | return str;
221 | }
222 |
223 |
224 | //
225 | // Get integer
226 | //
227 | int CommandLine::GetInt(int index, int defaultValue) {
228 | if (index < valueCount) {
229 | try {
230 | auto value = stoi(ParseHex(values[index]));
231 | return value;
232 | }
233 | catch (exception) {}
234 | }
235 | return defaultValue;
236 | }
237 |
238 |
239 | //
240 | // Get long integer
241 | //
242 | long CommandLine::GetLong(int index, long defaultValue) {
243 | if (index < valueCount) {
244 | try {
245 | auto value = stol(ParseHex(values[index]));
246 | return value;
247 | }
248 | catch (exception) {}
249 | }
250 | return defaultValue;
251 | }
252 |
253 |
254 | //
255 | // Get double precision floating point number
256 | //
257 | double CommandLine::GetDouble(int index, double defaultValue) {
258 | if (index < valueCount) {
259 | try {
260 | auto value = stod(ParseHex(values[index]));
261 | return value;
262 | }
263 | catch (exception) {}
264 | }
265 | return defaultValue;
266 | }
267 |
268 |
269 | //
270 | // Get floating point number
271 | //
272 | float CommandLine::GetFloat(int index, float defaultValue) {
273 | if (index < valueCount) {
274 | try {
275 | auto value = stof(ParseHex(values[index]));
276 | return value;
277 | }
278 | catch (exception) {}
279 | }
280 | return defaultValue;
281 | }
282 |
283 |
284 | //
285 | // Get boolean
286 | //
287 | bool CommandLine::GetBoolean(int index, bool defaultValue) {
288 | if (GetInt(index, 0) > 0) return true;
289 | string str = GetStringLower(index, "");
290 | if (str == "true") return true;
291 | if (str == "on") return true;
292 | if (str == "false") return false;
293 | if (str == "off") return false;
294 | if (str == "0") return false;
295 | return defaultValue;
296 | }
297 |
--------------------------------------------------------------------------------
/TabletDriverService/USBDevice.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "USBDevice.h"
3 |
4 | #define LOG_MODULE "USBDevice"
5 | #include "Logger.h"
6 |
7 | USBDevice::USBDevice(string Guid, int StringId, string StringMatch) {
8 | this->guid = Guid;
9 | this->stringId = StringId;
10 | this->stringMatch = StringMatch;
11 | isOpen = false;
12 | if (this->OpenDevice(guid, stringId, stringMatch)) {
13 | isOpen = true;
14 | }
15 | }
16 | USBDevice::~USBDevice() {
17 | this->CloseDevice();
18 | }
19 |
20 |
21 | bool USBDevice::OpenDevice(string usbDeviceGUIDString, int stringId, string stringSearch) {
22 | GUID usbDeviceGUID;
23 |
24 | HDEVINFO deviceInfo;
25 | SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
26 | PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData;
27 | SP_DEVINFO_DATA deviceInfoData;
28 | DWORD dwSize;
29 | DWORD dwMemberIdx;
30 |
31 | HANDLE deviceHandle = 0;
32 | WINUSB_INTERFACE_HANDLE usbHandle = 0;
33 |
34 | USB_INTERFACE_DESCRIPTOR usbInterfaceDescriptor;
35 |
36 | ULONG readBytes = 0;
37 |
38 |
39 | std::wstring stemp = std::wstring(usbDeviceGUIDString.begin(), usbDeviceGUIDString.end());
40 | LPCWSTR wstringGUID = stemp.c_str();
41 |
42 | _deviceHandle = NULL;
43 | _usbHandle = NULL;
44 |
45 | HRESULT hr = CLSIDFromString(wstringGUID, (LPCLSID)&usbDeviceGUID);
46 | if (hr != S_OK) {
47 | LOG_ERROR("Can't create the USB Device GUID!\n");
48 | return false;
49 | }
50 |
51 | // Setup device Info
52 | deviceInfo = SetupDiGetClassDevs(&usbDeviceGUID, NULL, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
53 | if (deviceInfo == INVALID_HANDLE_VALUE) {
54 | LOG_ERROR("Device info invalid!\n");
55 | SetupDiDestroyDeviceInfoList(deviceInfo);
56 | return false;
57 | }
58 |
59 | // Enumerate device interface data
60 | deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
61 | dwMemberIdx = 0;
62 | SetupDiEnumDeviceInterfaces(deviceInfo, NULL, &usbDeviceGUID, dwMemberIdx, &deviceInterfaceData);
63 | while (GetLastError() != ERROR_NO_MORE_ITEMS) {
64 |
65 | // Get the required buffer size.
66 | deviceInfoData.cbSize = sizeof(deviceInfoData);
67 | SetupDiGetDeviceInterfaceDetail(deviceInfo, &deviceInterfaceData, NULL, 0, &dwSize, NULL);
68 |
69 | // Allocate memory
70 | deviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(dwSize);
71 | deviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
72 |
73 | // Get device interface detail data
74 | if (SetupDiGetDeviceInterfaceDetail(deviceInfo, &deviceInterfaceData, deviceInterfaceDetailData, dwSize, &dwSize, &deviceInfoData)) {
75 |
76 | //LOG_DEBUG("USB Device path: %S\n", deviceInterfaceDetailData->DevicePath);
77 |
78 | // Create File
79 | deviceHandle = CreateFile(deviceInterfaceDetailData->DevicePath,
80 | GENERIC_READ | GENERIC_WRITE,
81 | FILE_SHARE_READ | FILE_SHARE_WRITE,
82 | NULL,
83 | OPEN_EXISTING,
84 | FILE_FLAG_OVERLAPPED,
85 | NULL);
86 |
87 | if (deviceHandle != INVALID_HANDLE_VALUE) {
88 | //LOG_DEBUG("Handle: %lu\n", (ULONG)deviceHandle);
89 |
90 | // Init WinUsb
91 | WinUsb_Initialize(deviceHandle, &usbHandle);
92 | if (!usbHandle) {
93 | LOG_ERROR("ERROR! Unable to start WinUSB for the device!\n");
94 | if (deviceHandle != INVALID_HANDLE_VALUE)
95 | CloseHandle(deviceHandle);
96 | return false;
97 | }
98 | //LOG_DEBUG("USB Handle: %d\n", (ULONG)usbHandle);
99 |
100 | // Query interface settings
101 | ZeroMemory(&usbInterfaceDescriptor, sizeof(USB_INTERFACE_DESCRIPTOR));
102 | if (WinUsb_QueryInterfaceSettings(usbHandle, 0, &usbInterfaceDescriptor)) {
103 |
104 | WINUSB_SETUP_PACKET setupPacket;
105 | ULONG bytesRead;
106 | BYTE buffer[64];
107 | string str = "";
108 |
109 | setupPacket.RequestType = 0x80;
110 | setupPacket.Request = 0x06;
111 | setupPacket.Value = (0x03 << 8) | stringId;
112 | setupPacket.Index = 0x0409;
113 | setupPacket.Length = 64;
114 |
115 | // String request
116 | if (WinUsb_ControlTransfer(usbHandle, setupPacket, buffer, 64, &bytesRead, NULL)) {
117 |
118 | // Create string from bytes
119 | for (int i = 2; i < (int)bytesRead; i += 2) {
120 | str.push_back(buffer[i]);
121 | }
122 | LOG_DEBUG("USB String (%d): %s\n", stringId, str.c_str());
123 |
124 | // Device string longer than the search string
125 | if (bytesRead >= stringSearch.length() * 2) {
126 |
127 | // Match!
128 | if (str.compare(0, stringSearch.size(), stringSearch) == 0) {
129 | _deviceHandle = deviceHandle;
130 | _usbHandle = usbHandle;
131 | }
132 | }
133 | }
134 | }
135 | else {
136 | LOG_ERROR("ERROR! Can't query interface settings!\n");
137 | }
138 |
139 | if (_usbHandle == NULL && usbHandle && usbHandle != INVALID_HANDLE_VALUE)
140 | WinUsb_Free(usbHandle);
141 |
142 | if (_deviceHandle == NULL && deviceHandle && deviceHandle != INVALID_HANDLE_VALUE)
143 | CloseHandle(deviceHandle);
144 | }
145 | }
146 |
147 | // Free memory
148 | std::free(deviceInterfaceDetailData);
149 |
150 | // Continue looping
151 | SetupDiEnumDeviceInterfaces(deviceInfo, NULL, &usbDeviceGUID, ++dwMemberIdx, &deviceInterfaceData);
152 | }
153 |
154 | SetupDiDestroyDeviceInfoList(deviceInfo);
155 |
156 | if (_deviceHandle && _deviceHandle != INVALID_HANDLE_VALUE
157 | &&
158 | _usbHandle && _usbHandle != INVALID_HANDLE_VALUE
159 | )
160 | return true;
161 |
162 | return false;
163 | }
164 |
165 |
166 | int USBDevice::Read(UCHAR pipeId, void *buffer, int length) {
167 | ULONG bytesRead;
168 | try {
169 | if (WinUsb_ReadPipe(_usbHandle, pipeId, (UCHAR *)buffer, length, &bytesRead, 0)) {
170 | return (int)bytesRead;
171 | }
172 | }
173 | catch (exception &e) {
174 | LOG_ERROR("Exception USB: %s\n", e.what());
175 | }
176 | return 0;
177 | }
178 |
179 | int USBDevice::Write(UCHAR pipeId, void *buffer, int length) {
180 | ULONG bytesWritten;
181 | if (WinUsb_WritePipe(_usbHandle, pipeId, (UCHAR *)buffer, length, &bytesWritten, 0)) {
182 | return (int)bytesWritten;
183 | }
184 | return 0;
185 | }
186 |
187 |
188 | int USBDevice::ControlTransfer(UCHAR requestType, UCHAR request, USHORT value, USHORT index, void *buffer, USHORT length) {
189 | WINUSB_SETUP_PACKET usbSetupPacket;
190 | ULONG bytesRead;
191 | usbSetupPacket.RequestType = requestType;
192 | usbSetupPacket.Request = request;
193 | usbSetupPacket.Length = length;
194 | usbSetupPacket.Value = value;
195 | usbSetupPacket.Index = index;
196 | if (WinUsb_ControlTransfer(_usbHandle, usbSetupPacket, (UCHAR*)buffer, length, &bytesRead, NULL)) {
197 | return bytesRead;
198 | }
199 | return 0;
200 | }
201 |
202 | void USBDevice::CloseDevice() {
203 | if (_usbHandle != NULL && _usbHandle != INVALID_HANDLE_VALUE) {
204 | try {
205 | printf("ASD\n");
206 | WinUsb_Free(_usbHandle);
207 | }
208 | catch (exception &e) {
209 | printf("WinUsb ERROR! %s\n", e.what());
210 | }
211 | }
212 | if (_deviceHandle != NULL && _deviceHandle != INVALID_HANDLE_VALUE) {
213 | try {
214 | printf("DAS\n");
215 | CloseHandle(_deviceHandle);
216 | }
217 | catch (exception &e) {
218 | printf("HID ERROR! %s\n", e.what());
219 | }
220 | }
221 | isOpen = false;
222 | }
223 |
--------------------------------------------------------------------------------
/TabletDriverGUI/VersionHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace TabletDriverGUI
5 | {
6 | public static class VersionHelper
7 | {
8 | const byte VER_EQUAL = 1;
9 | const byte VER_GREATER = 2;
10 | const byte VER_GREATER_EQUAL = 3;
11 | const byte VER_LESS = 4;
12 | const byte VER_LESS_EQUAL = 5;
13 | const byte VER_AND = 6;
14 | const byte VER_OR = 7;
15 |
16 | const byte VER_CONDITION_MASK = 7;
17 | const byte VER_NUM_BITS_PER_CONDITION_MASK = 3;
18 |
19 | //
20 | // RtlVerifyVersionInfo() type mask bits
21 | //
22 |
23 | const uint VER_MINORVERSION = 0x0000001;
24 | const uint VER_MAJORVERSION = 0x0000002;
25 | const uint VER_BUILDNUMBER = 0x0000004;
26 | const uint VER_PLATFORMID = 0x0000008;
27 | const uint VER_SERVICEPACKMINOR = 0x0000010;
28 | const uint VER_SERVICEPACKMAJOR = 0x0000020;
29 | const uint VER_SUITENAME = 0x0000040;
30 | const uint VER_PRODUCT_TYPE = 0x0000080;
31 |
32 | // wProductType
33 | // Any additional information about the system.This member can be one of the following values.
34 | const byte VER_NT_DOMAIN_CONTROLLER = 0x0000002;
35 | const byte VER_NT_SERVER = 0x0000003;
36 | const byte VER_NT_WORKSTATION = 0x0000001;
37 |
38 | //
39 | // _WIN32_WINNT version constants
40 | //
41 | const ushort _WIN32_WINNT_NT4 = 0x0400;
42 | const ushort _WIN32_WINNT_WIN2K = 0x0500;
43 | const ushort _WIN32_WINNT_WINXP = 0x0501;
44 | const ushort _WIN32_WINNT_WS03 = 0x0502;
45 | const ushort _WIN32_WINNT_WIN6 = 0x0600;
46 | const ushort _WIN32_WINNT_VISTA = 0x0600;
47 | const ushort _WIN32_WINNT_WS08 = 0x0600;
48 | const ushort _WIN32_WINNT_LONGHORN = 0x0600;
49 | const ushort _WIN32_WINNT_WIN7 = 0x0601;
50 | const ushort _WIN32_WINNT_WIN8 = 0x0602;
51 | const ushort _WIN32_WINNT_WINBLUE = 0x0603;
52 | const ushort _WIN32_WINNT_WINTHRESHOLD = 0x0A00; /* ABRACADABRA_THRESHOLD*/
53 | const ushort _WIN32_WINNT_WIN10 = 0x0A00; /* ABRACADABRA_THRESHOLD*/
54 |
55 | const bool FALSE = false;
56 |
57 | static byte LOBYTE(ushort w)
58 | {
59 | return ((byte)(w & 0xff));
60 | }
61 |
62 | static byte HIBYTE(ushort w)
63 | {
64 | return ((byte)(w >> 8 & 0xff));
65 | }
66 |
67 | [DllImport("kernel32.dll")]
68 | static extern ulong VerSetConditionMask(ulong ConditionMask, uint TypeMask, byte Condition);
69 |
70 | [DllImport("kernel32.dll")]
71 | static extern bool VerifyVersionInfoW(ref OSVERSIONINFOEXW lpVersionInformation, uint dwTypeMask, ulong dwlConditionMask);
72 |
73 |
74 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
75 | struct OSVERSIONINFOEXW
76 | {
77 | public int dwOSVersionInfoSize;
78 | public int dwMajorVersion;
79 | public int dwMinorVersion;
80 | public int dwBuildNumber;
81 | public int dwPlatformId;
82 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
83 | public string szCSDVersion;
84 | public UInt16 wServicePackMajor;
85 | public UInt16 wServicePackMinor;
86 | public UInt16 wSuiteMask;
87 | public byte wProductType;
88 | public byte wReserved;
89 | }
90 |
91 |
92 | public static bool
93 | IsWindowsVersionOrGreater(ushort wMajorVersion, ushort wMinorVersion, ushort wServicePackMajor)
94 | {
95 | var osvi = new OSVERSIONINFOEXW
96 | {
97 | dwOSVersionInfoSize = Marshal.SizeOf(typeof(OSVERSIONINFOEXW))
98 | };
99 |
100 | var dwlConditionMask = VerSetConditionMask(
101 | VerSetConditionMask(
102 | VerSetConditionMask(
103 | 0, VER_MAJORVERSION, VER_GREATER_EQUAL),
104 | VER_MINORVERSION, VER_GREATER_EQUAL),
105 | VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
106 |
107 | osvi.dwMajorVersion = wMajorVersion;
108 | osvi.dwMinorVersion = wMinorVersion;
109 | osvi.wServicePackMajor = wServicePackMajor;
110 |
111 | return VerifyVersionInfoW(ref osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
112 | }
113 |
114 | public static bool
115 | IsWindowsXPOrGreater()
116 | {
117 | return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 0);
118 | }
119 |
120 | public static bool
121 | IsWindowsXPSP1OrGreater()
122 | {
123 | return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 1);
124 | }
125 |
126 | public static bool
127 | IsWindowsXPSP2OrGreater()
128 | {
129 | return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 2);
130 | }
131 |
132 | public static bool
133 | IsWindowsXPSP3OrGreater()
134 | {
135 | return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 3);
136 | }
137 |
138 | public static bool
139 | IsWindowsVistaOrGreater()
140 | {
141 | return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0);
142 | }
143 |
144 | public static bool
145 | IsWindowsVistaSP1OrGreater()
146 | {
147 | return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 1);
148 | }
149 |
150 | public static bool
151 | IsWindowsVistaSP2OrGreater()
152 | {
153 | return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 2);
154 | }
155 |
156 | public static bool
157 | IsWindows7OrGreater()
158 | {
159 | return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 0);
160 | }
161 |
162 | public static bool
163 | IsWindows7SP1OrGreater()
164 | {
165 | return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 1);
166 | }
167 |
168 | public static bool
169 | IsWindows8OrGreater()
170 | {
171 | return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), LOBYTE(_WIN32_WINNT_WIN8), 0);
172 | }
173 |
174 | public static bool
175 | IsWindows8Point1OrGreater()
176 | {
177 | return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE), LOBYTE(_WIN32_WINNT_WINBLUE), 0);
178 | }
179 |
180 | public static bool
181 | IsWindowsThresholdOrGreater()
182 | {
183 | return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINTHRESHOLD), LOBYTE(_WIN32_WINNT_WINTHRESHOLD), 0);
184 | }
185 |
186 | public static bool
187 | IsWindows10OrGreater()
188 | {
189 | return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINTHRESHOLD), LOBYTE(_WIN32_WINNT_WINTHRESHOLD), 0);
190 | }
191 |
192 | public static bool
193 | IsWindowsServer()
194 | {
195 | var osvi = new OSVERSIONINFOEXW
196 | {
197 | dwOSVersionInfoSize = Marshal.SizeOf(typeof(OSVERSIONINFOEXW)),
198 | wProductType = VER_NT_WORKSTATION
199 | };
200 |
201 | var dwlConditionMask = VerSetConditionMask(0, VER_PRODUCT_TYPE, VER_EQUAL);
202 |
203 | return !VerifyVersionInfoW(ref osvi, VER_PRODUCT_TYPE, dwlConditionMask);
204 | }
205 |
206 | }
207 | }
208 |
--------------------------------------------------------------------------------
/TabletDriverService/docs/VMulti_Report_Descriptor.txt:
--------------------------------------------------------------------------------
1 | //
2 | // Feature
3 | //
4 | 0x09, 0x0E, // Usage (0x0E)
5 | 0xA1, 0x01, // Collection (Application)
6 | 0x85, 0x02, // Report ID (2)
7 | 0x09, 0x23, // Usage (0x23)
8 | 0xA1, 0x02, // Collection (Logical)
9 | 0x09, 0x52, // Usage (0x52)
10 | 0x09, 0x53, // Usage (0x53)
11 | 0x15, 0x00, // Logical Minimum (0)
12 | 0x25, 0x0A, // Logical Maximum (10)
13 | 0x75, 0x08, // Report Size (8)
14 | 0x95, 0x02, // Report Count (2)
15 | 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
16 | 0xC0, // End Collection
17 | 0xC0, // End Collection
18 |
19 | //
20 | // Absolute mouse
21 | //
22 | 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
23 | 0x09, 0x02, // Usage (Mouse)
24 | 0xA1, 0x01, // Collection (Application)
25 | 0x85, 0x03, // Report ID (3)
26 | 0x09, 0x01, // Usage (Pointer)
27 | 0xA1, 0x00, // Collection (Physical)
28 | 0x05, 0x09, // Usage Page (Button)
29 | 0x19, 0x01, // Usage Minimum (0x01)
30 | 0x29, 0x05, // Usage Maximum (0x05)
31 | 0x15, 0x00, // Logical Minimum (0)
32 | 0x25, 0x01, // Logical Maximum (1)
33 | 0x75, 0x01, // Report Size (1)
34 | 0x95, 0x05, // Report Count (5)
35 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
36 | 0x95, 0x03, // Report Count (3)
37 | 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
38 | 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
39 | 0x26, 0xFF, 0x7F, // Logical Maximum (32767)
40 | 0x75, 0x10, // Report Size (16)
41 | 0x95, 0x01, // Report Count (1)
42 | 0x55, 0x0F, // Unit Exponent (-1)
43 | 0x65, 0x11, // Unit (System: SI Linear, Length: Centimeter)
44 | 0x35, 0x00, // Physical Minimum (0)
45 | 0x45, 0x00, // Physical Maximum (0)
46 | 0x09, 0x30, // Usage (X)
47 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
48 | 0x09, 0x31, // Usage (Y)
49 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
50 | 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
51 | 0x09, 0x38, // Usage (Wheel)
52 | 0x15, 0x81, // Logical Minimum (-127)
53 | 0x25, 0x7F, // Logical Maximum (127)
54 | 0x75, 0x08, // Report Size (8)
55 | 0x95, 0x01, // Report Count (1)
56 | 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
57 | 0xC0, // End Collection
58 | 0xC0, // End Collection
59 |
60 |
61 | //
62 | // Relative mouse
63 | //
64 | 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
65 | 0x09, 0x02, // Usage (Mouse)
66 | 0xA1, 0x01, // Collection (Application)
67 | 0x85, 0x04, // Report ID (4)
68 | 0x09, 0x01, // Usage (Pointer)
69 | 0xA1, 0x00, // Collection (Physical)
70 | 0x05, 0x09, // Usage Page (Button)
71 | 0x19, 0x01, // Usage Minimum (0x01)
72 | 0x29, 0x05, // Usage Maximum (0x05)
73 | 0x15, 0x00, // Logical Minimum (0)
74 | 0x25, 0x01, // Logical Maximum (1)
75 | 0x75, 0x01, // Report Size (1)
76 | 0x95, 0x05, // Report Count (5)
77 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
78 | 0x95, 0x03, // Report Count (3)
79 | 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
80 | 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
81 | 0x09, 0x30, // Usage (X)
82 | 0x09, 0x31, // Usage (Y)
83 | 0x15, 0x81, // Logical Minimum (-127)
84 | 0x25, 0x7F, // Logical Maximum (127)
85 | 0x75, 0x08, // Report Size (8)
86 | 0x95, 0x02, // Report Count (2)
87 | 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
88 | 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
89 | 0x09, 0x38, // Usage (Wheel)
90 | 0x15, 0x81, // Logical Minimum (-127)
91 | 0x25, 0x7F, // Logical Maximum (127)
92 | 0x75, 0x08, // Report Size (8)
93 | 0x95, 0x01, // Report Count (1)
94 | 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
95 | 0xC0, // End Collection
96 | 0xC0, // End Collection
97 |
98 |
99 | //
100 | // Digitizer
101 | //
102 | 0x05, 0x0D, // Usage Page (Digitizer)
103 | 0x09, 0x01, // Usage (Digitizer)
104 | 0xA1, 0x01, // Collection (Application)
105 | 0x85, 0x05, // Report ID (5)
106 | 0x09, 0x20, // Usage (Stylus)
107 | 0xA1, 0x00, // Collection (Physical)
108 | 0x09, 0x42, // Usage (Tip Switch)
109 | 0x09, 0x44, // Usage (Barrel Switch)
110 | 0x09, 0x45, // Usage (Eraser)
111 | 0x15, 0x00, // Logical Minimum (0)
112 | 0x25, 0x01, // Logical Maximum (1)
113 | 0x75, 0x01, // Report Size (1)
114 | 0x95, 0x03, // Report Count (3)
115 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
116 | 0x95, 0x02, // Report Count (2)
117 | 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
118 | 0x09, 0x32, // Usage (In Range)
119 | 0x95, 0x01, // Report Count (1)
120 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
121 | 0x95, 0x02, // Report Count (2)
122 | 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
123 | 0x75, 0x10, // Report Size (16)
124 | 0x95, 0x01, // Report Count (1)
125 | 0x35, 0x00, // Physical Minimum (0)
126 | 0xA4, // Push
127 | 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
128 | 0x09, 0x30, // Usage (X)
129 | 0x46, 0xCB, 0x02, // Physical Maximum (715)
130 | 0x26, 0xFF, 0x7F, // Logical Maximum (32767)
131 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
132 | 0x09, 0x31, // Usage (Y)
133 | 0x46, 0xCB, 0x02, // Physical Maximum (715)
134 | 0x26, 0xFF, 0x7F, // Logical Maximum (32767)
135 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
136 | 0xB4, // Pop
137 | 0x09, 0x30, // Usage (Tip Pressure)
138 | 0x45, 0x00, // Physical Maximum (0)
139 | 0x26, 0xFF, 0x07, // Logical Maximum (2047)
140 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
141 | 0xC0, // End Collection
142 | 0xC0, // End Collection
143 |
144 |
145 |
146 |
147 |
148 | //
149 | // VMulti Control
150 | //
151 | 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
152 | 0x09, 0x01, // Usage (0x01)
153 | 0xA1, 0x01, // Collection (Application)
154 | 0x85, 0x40, // Report ID (64)
155 | 0x15, 0x00, // Logical Minimum (0)
156 | 0x26, 0xFF, 0x00, // Logical Maximum (255)
157 | 0x75, 0x08, // Report Size (8)
158 | 0x95, 0x40, // Report Count (64)
159 | 0x09, 0x02, // Usage (0x02)
160 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
161 | 0x95, 0x40, // Report Count (64)
162 | 0x09, 0x02, // Usage (0x02)
163 | 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
164 | 0xC0, // End Collection
165 |
166 |
167 |
168 | //
169 | // VMulti Message
170 | //
171 | 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
172 | 0x09, 0x02, // Usage (0x02)
173 | 0xA1, 0x01, // Collection (Application)
174 | 0x85, 0x10, // Report ID (16)
175 | 0x15, 0x00, // Logical Minimum (0)
176 | 0x26, 0xFF, 0x00, // Logical Maximum (255)
177 | 0x75, 0x08, // Report Size (8)
178 | 0x95, 0x20, // Report Count (32)
179 | 0x09, 0x02, // Usage (0x02)
180 | 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
181 | 0x95, 0x40, // Report Count (64)
182 | 0x09, 0x02, // Usage (0x02)
183 | 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
184 | 0xC0, // End Collection
185 |
186 |
187 |
188 |
189 | // 303 bytes
190 |
191 |
--------------------------------------------------------------------------------
/TabletDriverService/Tablet.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "Tablet.h"
3 |
4 | #define LOG_MODULE "Tablet"
5 | #include "Logger.h"
6 |
7 |
8 | //
9 | // USB Device Constructor
10 | //
11 | Tablet::Tablet(string usbGUID, int stringId, string stringMatch) : Tablet() {
12 | usbDevice = new USBDevice(usbGUID, stringId, stringMatch);
13 | if (usbDevice->isOpen) {
14 | this->isOpen = true;
15 | usbPipeId = 0x81;
16 | }
17 | else {
18 | delete usbDevice;
19 | usbDevice = NULL;
20 | }
21 | }
22 |
23 | //
24 | // HID Device Constructor
25 | //
26 | Tablet::Tablet(USHORT vendorId, USHORT productId, USHORT usagePage, USHORT usage) : Tablet() {
27 | hidDevice = new HIDDevice(vendorId, productId, usagePage, usage);
28 | if (hidDevice->isOpen) {
29 | this->isOpen = true;
30 | }
31 | else {
32 | delete hidDevice;
33 | hidDevice = NULL;
34 | }
35 | }
36 |
37 | //
38 | // Common constructor
39 | //
40 | Tablet::Tablet() {
41 |
42 | name = "Unknown";
43 | usbDevice = NULL;
44 | hidDevice = NULL;
45 | hidDevice2 = NULL;
46 |
47 | usbPipeId = 0;
48 |
49 | // Init reports
50 | initFeature = NULL;
51 | initFeatureLength = 0;
52 | initReport = NULL;
53 | initReportLength = 0;
54 |
55 | // Reset state
56 | memset(&state, 0, sizeof(state));
57 |
58 | // Filters
59 | filterTimed[0] = &smoothing;
60 | filterTimedCount = 1;
61 | filterPacket[0] = &noise;
62 | //filterPacket[1] = &peak;
63 | filterPacketCount = 1;
64 |
65 | peak.isEnabled = true;
66 |
67 | // Button map
68 | memset(&buttonMap, 0, sizeof(buttonMap));
69 | buttonMap[0] = 1;
70 | buttonMap[1] = 2;
71 | buttonMap[2] = 3;
72 |
73 | // Tablet connection open
74 | isOpen = false;
75 |
76 | // Debug output
77 | debugEnabled = false;
78 |
79 | // Skip first packets, some of those might be invalid.
80 | skipPackets = 5;
81 |
82 | // Keep tip down packet counter
83 | tipDownCounter = 0;
84 |
85 | }
86 |
87 | //
88 | // Destructor
89 | //
90 | Tablet::~Tablet() {
91 | CloseDevice();
92 | if (usbDevice != NULL)
93 | delete usbDevice;
94 | if (hidDevice != NULL)
95 | delete hidDevice;
96 | if (hidDevice2 != NULL)
97 | delete hidDevice2;
98 | if (initReport != NULL)
99 | delete initReport;
100 | if (initFeature != NULL)
101 | delete initFeature;
102 | }
103 |
104 |
105 | //
106 | // Init
107 | //
108 | bool Tablet::Init() {
109 |
110 | // Feature report
111 | if (initFeature != NULL) {
112 | if (hidDevice->SetFeature(initFeature, initFeatureLength)) {
113 | return true;
114 | }
115 | return false;
116 | }
117 |
118 | // Output report
119 | if (initReport != NULL) {
120 | if (hidDevice->Write(initReport, initReportLength)) {
121 | return true;
122 | }
123 | return false;
124 | }
125 |
126 | // USB (Huion)
127 | if (usbDevice != NULL) {
128 | BYTE buffer[64];
129 | int status;
130 |
131 | // String Id 200
132 | status = usbDevice->ControlTransfer(0x80, 0x06, (0x03 << 8) | 200, 0x0409, buffer, 64);
133 |
134 | // String Id 100
135 | status += usbDevice->ControlTransfer(0x80, 0x06, (0x03 << 8) | 100, 0x0409, buffer, 64);
136 |
137 | if (status > 0) {
138 | return true;
139 | }
140 | return false;
141 | }
142 |
143 | return true;
144 | }
145 |
146 |
147 | //
148 | // Check if the tablet has enough configuration parameters set
149 | //
150 | bool Tablet::IsConfigured() {
151 | if (
152 | settings.maxX > 1 &&
153 | settings.maxY > 1 &&
154 | settings.maxPressure > 1 &&
155 | settings.width > 1 &&
156 | settings.height > 1
157 | ) return true;
158 | return false;
159 | }
160 |
161 | //
162 | // Read Position
163 | //
164 | int Tablet::ReadPosition() {
165 | UCHAR buffer[1024];
166 | UCHAR *data;
167 | int buttonIndex;
168 |
169 |
170 | // Read report
171 | if (!this->Read(buffer, settings.reportLength)) {
172 | return -1;
173 | }
174 |
175 | // Skip packets
176 | if (skipPackets > 0) {
177 | skipPackets--;
178 | return Tablet::PacketInvalid;
179 | }
180 |
181 |
182 | // Set data pointer
183 | if (settings.type == TabletSettings::TypeWacomDrivers) {
184 | data = buffer + 1;
185 | }
186 | else {
187 | data = buffer;
188 | }
189 |
190 | //
191 | // Wacom Intuos data format
192 | //
193 | if (settings.type == TabletSettings::TypeWacomIntuos) {
194 | reportData.reportId = data[0];
195 | reportData.buttons = data[1] & ~0x01;
196 | reportData.x = ((data[2] * 0x100 + data[3]) << 1) | ((data[9] >> 1) & 1);
197 | reportData.y = ((data[4] * 0x100 + data[5]) << 1) | (data[9] & 1);
198 | reportData.pressure = (data[6] << 3) | ((data[7] & 0xC0) >> 5) | (data[1] & 1);
199 | //distance = buffer[9] >> 2;
200 |
201 | //
202 | // Wacom 4100 data format
203 | //
204 | }
205 | else if (settings.type == TabletSettings::TypeWacom4100) {
206 |
207 | // Wacom driver device
208 | if (settings.reportLength == 193) {
209 | data = buffer + 1;
210 | }
211 |
212 | reportData.reportId = data[0];
213 | reportData.buttons = data[1] & ~0x01;
214 | reportData.x = (data[2] | (data[3] << 8) | (data[4] << 16));
215 | reportData.y = (data[5] | (data[6] << 8) | (data[7] << 16));
216 | reportData.pressure = (data[8] | (data[9] << 8));
217 |
218 | //
219 | // Copy buffer to struct
220 | //
221 | }
222 | else {
223 | memcpy(&reportData, data, sizeof(reportData));
224 | }
225 |
226 |
227 | // Validate packet id
228 | if (settings.reportId > 0 && reportData.reportId != settings.reportId) {
229 | return Tablet::PacketInvalid;
230 | }
231 |
232 |
233 |
234 | // Detect mask
235 | if (settings.detectMask > 0 && (reportData.buttons & settings.detectMask) != settings.detectMask) {
236 | return Tablet::PacketPositionInvalid;
237 | }
238 |
239 | // Ignore mask
240 | if (settings.ignoreMask > 0 && (reportData.buttons & settings.ignoreMask) == settings.ignoreMask) {
241 | return Tablet::PacketPositionInvalid;
242 | }
243 |
244 | //
245 | // Use pen pressure to detect the pen tip click
246 | //
247 | if (settings.clickPressure > 0) {
248 | reportData.buttons &= ~1;
249 | if (reportData.pressure > settings.clickPressure) {
250 | reportData.buttons |= 1;
251 | }
252 |
253 | // Force tip button down if pressure is detected
254 | }
255 | else if (reportData.pressure > 10) {
256 | reportData.buttons |= 1;
257 | }
258 |
259 | // Keep pen tip button down for a few packets
260 | if (settings.keepTipDown > 0) {
261 | if (reportData.buttons & 0x01) {
262 | tipDownCounter = settings.keepTipDown;
263 | }
264 | if (tipDownCounter-- >= 0) {
265 | reportData.buttons |= 1;
266 | }
267 | }
268 |
269 |
270 | // Set valid
271 | state.isValid = true;
272 |
273 | // Button map
274 | reportData.buttons = reportData.buttons & 0x0F;
275 | state.buttons = 0;
276 | for (buttonIndex = 0; buttonIndex < sizeof(buttonMap); buttonIndex++) {
277 |
278 | // Button is set
279 | if (buttonMap[buttonIndex] > 0) {
280 |
281 | // Button is pressed
282 | if ((reportData.buttons & (1 << buttonIndex)) > 0) {
283 | state.buttons |= (1 << (buttonMap[buttonIndex] - 1));
284 | }
285 | }
286 | }
287 |
288 | // Convert report data to state
289 | state.position.x = ((double)reportData.x / (double)settings.maxX) * settings.width;
290 | //state.position.x = ((double)data[8] / 256) * settings.width;
291 | state.position.y = ((double)reportData.y / (double)settings.maxY) * settings.height;
292 | state.z = (double)data[8];
293 | if (settings.skew != 0)
294 | state.position.x += state.position.y * settings.skew;
295 | state.pressure = ((double)reportData.pressure / (double)settings.maxPressure);
296 |
297 | // Tablet benchmark update
298 | benchmark.Update(state.position);
299 |
300 | // Packet and position is valid
301 | return Tablet::PacketValid;
302 | }
303 |
304 |
305 | //
306 | // Read report from tablet
307 | //
308 | bool Tablet::Read(void *buffer, int length) {
309 | if (!isOpen) return false;
310 | bool status = false;
311 | if (usbDevice != NULL) {
312 | status = usbDevice->Read(usbPipeId, buffer, length) > 0;
313 | }
314 | else if (hidDevice != NULL) {
315 | status = hidDevice->Read(buffer, length);
316 | }
317 | if (debugEnabled && status) {
318 | LOG_DEBUGBUFFER(buffer, length, "Read: ");
319 | }
320 | return status;
321 | }
322 |
323 | //
324 | // Write report to the tablet
325 | //
326 | bool Tablet::Write(void *buffer, int length) {
327 | if (!isOpen) return false;
328 | if (usbDevice != NULL) {
329 | return usbDevice->Write(usbPipeId, buffer, length) > 0;
330 | }
331 | else if (hidDevice != NULL) {
332 | return hidDevice->Write(buffer, length);
333 | }
334 | return false;
335 | }
336 |
337 | //
338 | // Close tablet
339 | //
340 | void Tablet::CloseDevice() {
341 | if (isOpen) {
342 | if (usbDevice != NULL) {
343 | usbDevice->CloseDevice();
344 | }
345 | else if (hidDevice != NULL) {
346 | hidDevice->CloseDevice();
347 | }
348 | }
349 | isOpen = false;
350 | }
--------------------------------------------------------------------------------
/TabletDriverService/VMulti.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include "VMulti.h"
3 |
4 | #define LOG_MODULE "VMulti"
5 | #include "Logger.h"
6 |
7 | // Constructor
8 | VMulti::VMulti() {
9 | isOpen = false;
10 | debugEnabled = false;
11 | lastButtons = 0;
12 |
13 | mode = ModeAbsoluteMouse;
14 |
15 | // Absolute mouse init
16 | reportAbsoluteMouse.vmultiId = 0x40;
17 | reportAbsoluteMouse.reportLength = 7;
18 | reportAbsoluteMouse.reportId = 3;
19 | reportAbsoluteMouse.buttons = 0;
20 | reportAbsoluteMouse.wheel = 0;
21 |
22 | // Relative mouse init
23 | reportRelativeMouse.vmultiId = 0x40;
24 | reportRelativeMouse.reportLength = 5;
25 | reportRelativeMouse.reportId = 4;
26 | reportRelativeMouse.buttons = 0;
27 | reportRelativeMouse.x = 0;
28 | reportRelativeMouse.y = 0;
29 | reportRelativeMouse.wheel = 0;
30 |
31 | // Digitizer / Windows Ink init
32 | reportDigitizer.vmultiId = 0x40;
33 | reportDigitizer.reportLength = 8;
34 | reportDigitizer.reportId = 5;
35 | reportDigitizer.buttons = 0;
36 | reportDigitizer.pressure = 0;
37 |
38 | // Relative mouse data
39 | memset(&relativeData, 0, sizeof(relativeData));
40 | relativeData.sensitivity = 1;
41 | relativeData.resetDistance = 50;
42 |
43 | // Monitor info
44 | UpdateMonitorInfo();
45 |
46 | // Report buffers
47 | memset(reportBuffer, 0, 65);
48 | memset(lastReportBuffer, 0, 65);
49 |
50 | hidDevice = new HIDDevice(0x00FF, 0xBACC, 0xFF00, 0x0001);
51 | if (hidDevice->isOpen) {
52 | isOpen = true;
53 | outputEnabled = true;
54 |
55 | }
56 | else {
57 | delete hidDevice;
58 | hidDevice = NULL;
59 | }
60 | }
61 |
62 | // Destructor
63 | VMulti::~VMulti() {
64 | if (hidDevice != NULL)
65 | delete hidDevice;
66 | }
67 |
68 | //
69 | // Has report data changed?
70 | //
71 | bool VMulti::HasReportChanged() {
72 |
73 | if (memcmp(reportBuffer, lastReportBuffer, 65) == 0) {
74 | return false;
75 | }
76 | return true;
77 | }
78 |
79 | //
80 | // Reset relative mouse data
81 | //
82 | void VMulti::ResetRelativeData(double x, double y) {
83 | relativeData.targetPosition.Set(x, y);
84 | relativeData.lastPosition.Set(x, y);
85 | relativeData.currentPosition.x = (int)x;
86 | relativeData.currentPosition.y = (int)y;
87 | }
88 |
89 |
90 | //
91 | // Update monitor information
92 | //
93 | void VMulti::UpdateMonitorInfo() {
94 | monitorInfo.primaryWidth = GetSystemMetrics(SM_CXSCREEN);
95 | monitorInfo.primaryHeight = GetSystemMetrics(SM_CYSCREEN);
96 | monitorInfo.virtualWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
97 | monitorInfo.virtualHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
98 | monitorInfo.virtualX = GetSystemMetrics(SM_XVIRTUALSCREEN);
99 | monitorInfo.virtualY = GetSystemMetrics(SM_YVIRTUALSCREEN);
100 | }
101 |
102 |
103 | //
104 | // Create report
105 | //
106 | void VMulti::CreateReport(BYTE buttons, double x, double y, double pressure) {
107 | double dx, dy, distance;
108 |
109 | //
110 | // Absolute mouse
111 | //
112 | if (mode == VMulti::ModeAbsoluteMouse) {
113 | reportAbsoluteMouse.buttons = buttons;
114 | reportAbsoluteMouse.x = (USHORT)round(x * 32767.0);
115 | reportAbsoluteMouse.y = (USHORT)round(y * 32767.0);
116 |
117 | memcpy(reportBuffer, &reportAbsoluteMouse, sizeof(reportAbsoluteMouse));
118 | if (debugEnabled) {
119 | LOG_DEBUGBUFFER(&reportAbsoluteMouse, 9, "VMulti Absolute: ");
120 | }
121 | }
122 |
123 | //
124 | // Relative mouse
125 | //
126 | else if (mode == VMulti::ModeRelativeMouse) {
127 |
128 | // Buttons
129 | reportRelativeMouse.buttons = buttons;
130 |
131 | // Mouse move delta
132 | dx = x - relativeData.lastPosition.x;
133 | dy = y - relativeData.lastPosition.y;
134 | distance = sqrt(dx * dx + dy * dy);
135 |
136 | // Reset relative position when the move distance is long enough
137 | if (distance > relativeData.resetDistance) {
138 | ResetRelativeData(x, y);
139 | dx = 0;
140 | dy = 0;
141 | }
142 |
143 | // Sensitivity
144 | dx *= relativeData.sensitivity;
145 | dy *= relativeData.sensitivity;
146 |
147 | // Move target position
148 | relativeData.targetPosition.Add(dx, dy);
149 |
150 | // Send difference of current position and target position
151 | reportRelativeMouse.x = (BYTE)(relativeData.targetPosition.x - relativeData.currentPosition.x);
152 | reportRelativeMouse.y = (BYTE)(relativeData.targetPosition.y - relativeData.currentPosition.y);
153 |
154 | // Add report position to real position
155 | relativeData.currentPosition.x += reportRelativeMouse.x;
156 | relativeData.currentPosition.y += reportRelativeMouse.y;
157 |
158 | // Last position
159 | relativeData.lastPosition.Set(x, y);
160 |
161 | memcpy(reportBuffer, &reportRelativeMouse, sizeof(reportRelativeMouse));
162 | if (debugEnabled) {
163 | LOG_DEBUGBUFFER(&reportRelativeMouse, 10, "VMulti Relative: ");
164 | }
165 | }
166 |
167 | //
168 | // Digitizer
169 | //
170 | else if (mode == VMulti::ModeDigitizer) {
171 | reportDigitizer.buttons = buttons | 0x20;
172 | reportDigitizer.x = (USHORT)floor(x * 32767.0 - 5);
173 | reportDigitizer.y = (USHORT)floor(y * 32767.0 - 5);
174 | reportDigitizer.pressure = (USHORT)floor(pressure * 2047.0);
175 | if (reportDigitizer.pressure > 2047) {
176 | reportDigitizer.pressure = 2047;
177 | }
178 | memcpy(reportBuffer, &reportDigitizer, sizeof(reportDigitizer));
179 | if (debugEnabled) {
180 | LOG_DEBUGBUFFER(&reportDigitizer, 10, "VMulti Digitizer: ");
181 | }
182 | }
183 |
184 | //
185 | // SendInput
186 | //
187 | else if (mode == ModeSendInput) {
188 |
189 | if (debugEnabled) {
190 | LOG_DEBUG("%0.0f,%0.0f | %0.0f,%0.0f | %0.0f,%0.0f\n",
191 | monitorInfo.primaryWidth, monitorInfo.primaryHeight,
192 | monitorInfo.virtualWidth, monitorInfo.virtualHeight,
193 | monitorInfo.virtualX, monitorInfo.virtualY
194 | );
195 | }
196 | INPUT input = { 0 };
197 | input.type = INPUT_MOUSE;
198 | input.mi.mouseData = 0;
199 | input.mi.dx = (LONG)floor(
200 | x * 65535.0 * (monitorInfo.virtualWidth / monitorInfo.primaryWidth)
201 | + (monitorInfo.virtualX / monitorInfo.primaryWidth * 65535.0)
202 | );
203 | input.mi.dy = (LONG)floor(
204 | y * 65535.0 * (monitorInfo.virtualHeight / monitorInfo.primaryHeight)
205 | + (monitorInfo.virtualY / monitorInfo.primaryHeight * 65535.0)
206 | );
207 | input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
208 |
209 | // Mouse 1
210 | if ((buttons & 0x01) && !(lastButtons & 0x01)) input.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
211 | else if (!(buttons & 0x01) && (lastButtons & 0x01)) input.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
212 |
213 | // Mouse 2
214 | if ((buttons & 0x02) && !(lastButtons & 0x02)) input.mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;
215 | else if (!(buttons & 0x02) && (lastButtons & 0x02)) input.mi.dwFlags |= MOUSEEVENTF_RIGHTUP;
216 |
217 | // Mouse 3
218 | if ((buttons & 0x04) && !(lastButtons & 0x04)) input.mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
219 | else if (!(buttons & 0x04) && (lastButtons & 0x04)) input.mi.dwFlags |= MOUSEEVENTF_MIDDLEUP;
220 |
221 | lastButtons = buttons;
222 |
223 | memcpy(reportBuffer, &input, sizeof(INPUT));
224 | }
225 |
226 |
227 | }
228 |
229 |
230 |
231 | //
232 | // Send reset report
233 | //
234 | int VMulti::ResetReport() {
235 | if (!outputEnabled) return true;
236 |
237 | // Absolute
238 | if (mode == ModeAbsoluteMouse) {
239 | reportAbsoluteMouse.buttons = 0;
240 | reportAbsoluteMouse.wheel = 0;
241 | memcpy(reportBuffer, &reportAbsoluteMouse, sizeof(reportAbsoluteMouse));
242 |
243 | // Relative
244 | }
245 | else if (mode == ModeRelativeMouse) {
246 | reportRelativeMouse.buttons = 0;
247 | reportRelativeMouse.x = 0;
248 | reportRelativeMouse.y = 0;
249 | reportRelativeMouse.wheel = 0;
250 | memcpy(reportBuffer, &reportRelativeMouse, sizeof(reportRelativeMouse));
251 |
252 | // Digitizer
253 | }
254 | else if (mode == ModeDigitizer) {
255 | reportDigitizer.buttons = 0;
256 | reportDigitizer.pressure = 0;
257 | memcpy(reportBuffer, &reportDigitizer, sizeof(reportDigitizer));
258 |
259 | // Send Input
260 | }
261 | else if (mode == ModeSendInput) {
262 | INPUT input = { 0 };
263 | input.type = INPUT_MOUSE;
264 | input.mi.mouseData = 0;
265 | input.mi.dx = 0;
266 | input.mi.dy = 0;
267 | input.mi.dwFlags = MOUSEEVENTF_LEFTUP | MOUSEEVENTF_RIGHTUP | MOUSEEVENTF_MIDDLEUP;
268 | memcpy(reportBuffer, &input, sizeof(INPUT));
269 | memcpy(lastReportBuffer, reportBuffer, 65);
270 | return 0;
271 | }
272 |
273 | memcpy(lastReportBuffer, reportBuffer, 65);
274 | return hidDevice->Write(reportBuffer, 65);
275 | }
276 |
277 |
278 | //
279 | // Write report
280 | //
281 | int VMulti::WriteReport() {
282 | if (!outputEnabled) return true;
283 |
284 | memcpy(lastReportBuffer, reportBuffer, 65);
285 |
286 | if (mode == ModeSendInput) {
287 | return SendInput(1, (LPINPUT)reportBuffer, sizeof(INPUT));
288 | }
289 | else {
290 | return hidDevice->Write(reportBuffer, 65);
291 | }
292 | }
--------------------------------------------------------------------------------
/TabletDriverGUI/TabletDriver.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Timers;
6 |
7 | namespace TabletDriverGUI
8 | {
9 | public class TabletDriver
10 | {
11 | // Event handlers
12 | public delegate void DriverEventHandler(object sender, DriverEventArgs e);
13 | public event DriverEventHandler MessageReceived;
14 | public event DriverEventHandler ErrorReceived;
15 | public event EventHandler Started;
16 | public event EventHandler Stopped;
17 | public enum DriverEventType
18 | {
19 | Error,
20 | Message
21 | }
22 | public class DriverEventArgs : EventArgs
23 | {
24 | public DriverEventType Type;
25 | public string Message;
26 | public DriverEventArgs(DriverEventType type, string message)
27 | {
28 | Type = type;
29 | Message = message;
30 | }
31 | }
32 |
33 | // Console stuff
34 | public List ConsoleBuffer;
35 | public bool HasConsoleUpdated;
36 | private int ConsoleMaxLines;
37 | private System.Threading.Mutex mutexConsoleUpdate;
38 |
39 | // Other variables
40 | private string servicePath;
41 | private Process processService;
42 | private Timer timerWatchdog;
43 | private bool running;
44 | public bool IsRunning { get { return running; } }
45 |
46 | //
47 | // Constructor
48 | //
49 | public TabletDriver(string servicePath)
50 | {
51 | this.servicePath = servicePath;
52 | this.processService = null;
53 | timerWatchdog = new Timer(2000);
54 | timerWatchdog.Elapsed += TimerWatchdog_Elapsed;
55 |
56 | ConsoleMaxLines = 300;
57 | ConsoleBuffer = new List(ConsoleMaxLines);
58 | mutexConsoleUpdate = new System.Threading.Mutex();
59 | }
60 |
61 | //
62 | // Driver watchdog
63 | //
64 | private void TimerWatchdog_Elapsed(object sender, ElapsedEventArgs e)
65 | {
66 | if (running)
67 | {
68 | //Console.WriteLine("ID: " + processDriver.Id);
69 | if (processService.HasExited)
70 | {
71 | RaiseError("Driver watchdog detected a service shutdown!");
72 | Stop();
73 | }
74 |
75 | processService.Refresh();
76 | switch (processService.PriorityClass)
77 | {
78 | case ProcessPriorityClass.High:
79 | case ProcessPriorityClass.RealTime:
80 | break;
81 | default:
82 | RaiseError("TabletDriverService priority too low! Run the GUI as an administrator or change the priority to high!");
83 | break;
84 | }
85 | }
86 | }
87 |
88 | //
89 | // Send command to the driver service
90 | //
91 | public void SendCommand(string line)
92 | {
93 | if (running)
94 | processService.StandardInput.WriteLine(line);
95 | }
96 |
97 | //
98 | // Add text to console
99 | //
100 | public void ConsoleAddText(string line)
101 | {
102 | mutexConsoleUpdate.WaitOne();
103 | ConsoleBuffer.Add(line);
104 | HasConsoleUpdated = true;
105 |
106 | // Limit console buffer size
107 | if (ConsoleBuffer.Count >= ConsoleMaxLines)
108 | ConsoleBuffer.RemoveRange(0, ConsoleBuffer.Count - ConsoleMaxLines);
109 |
110 | mutexConsoleUpdate.ReleaseMutex();
111 | }
112 |
113 |
114 | //
115 | // Console mutex lock
116 | //
117 | public void ConsoleLock()
118 | {
119 | mutexConsoleUpdate.WaitOne();
120 | }
121 | // Console mutex unlock
122 | public void ConsoleUnlock()
123 | {
124 | mutexConsoleUpdate.ReleaseMutex();
125 | }
126 |
127 |
128 | //
129 | // Raise error message
130 | //
131 | private void RaiseError(string text)
132 | {
133 | ErrorReceived?.Invoke(this, new DriverEventArgs(DriverEventType.Error, text));
134 | }
135 |
136 | //
137 | // Driver service disposed
138 | //
139 | private void ProcessService_Disposed(object sender, EventArgs e)
140 | {
141 | Stop();
142 | }
143 |
144 | //
145 | // Driver service exited
146 | //
147 | private void ProcessService_Exited(object sender, EventArgs e)
148 | {
149 | Stop();
150 | }
151 |
152 | //
153 | // Driver service error received
154 | //
155 | private void ProcessService_ErrorDataReceived(object sender, DataReceivedEventArgs e)
156 | {
157 | ConsoleAddText("ERROR! " + e.Data);
158 | ErrorReceived?.Invoke(this, new DriverEventArgs(DriverEventType.Error, e.Data));
159 | }
160 |
161 | //
162 | // Driver service data received
163 | //
164 | private void ProcessService_OutputDataReceived(object sender, DataReceivedEventArgs e)
165 | {
166 | if (e.Data == null)
167 | {
168 | if (running)
169 | Stop();
170 | }
171 | else
172 | {
173 | ConsoleAddText(e.Data);
174 | MessageReceived?.Invoke(this, new DriverEventArgs(DriverEventType.Message, e.Data));
175 | }
176 | }
177 |
178 | //
179 | // Start the driver service
180 | //
181 | public void Start(string processPath, string arguments)
182 | {
183 |
184 | if (!File.Exists(processPath))
185 | {
186 | throw new FileNotFoundException(processPath + " not found!");
187 | }
188 |
189 |
190 | // Try to start the driver
191 | try
192 | {
193 | // Create process start info
194 | ProcessStartInfo startInfo = new ProcessStartInfo
195 | {
196 | FileName = processPath,
197 | Arguments = arguments,
198 | UseShellExecute = false,
199 | RedirectStandardOutput = true,
200 | RedirectStandardError = true,
201 | RedirectStandardInput = true,
202 | CreateNoWindow = true,
203 | WindowStyle = ProcessWindowStyle.Normal
204 | };
205 |
206 | // Create process
207 | processService = new Process
208 | {
209 | StartInfo = startInfo
210 | };
211 | processService.OutputDataReceived += ProcessService_OutputDataReceived;
212 | processService.ErrorDataReceived += ProcessService_ErrorDataReceived;
213 | processService.Exited += ProcessService_Exited;
214 | processService.Disposed += ProcessService_Disposed;
215 |
216 | // Start process
217 | if (processService.Start())
218 | {
219 | processService.BeginOutputReadLine();
220 |
221 | // Set process priority
222 | try
223 | {
224 | processService.PriorityClass = ProcessPriorityClass.High;
225 | }
226 | catch (Exception)
227 | {
228 | }
229 |
230 | running = true;
231 | timerWatchdog.Start();
232 |
233 | Started?.Invoke(this, new EventArgs());
234 | }
235 |
236 | // Start failed
237 | else
238 | {
239 | throw new Exception("Can't start the driver service!");
240 | }
241 | }
242 |
243 | // Start failed
244 | catch (Exception e)
245 | {
246 | throw e;
247 | }
248 | }
249 |
250 |
251 | //
252 | // Stop the driver service
253 | //
254 | public void Stop()
255 | {
256 | if (!running) return;
257 | running = false;
258 | timerWatchdog.Stop();
259 | try
260 | {
261 | processService.CancelOutputRead();
262 | processService.Kill();
263 | processService.Dispose();
264 | }
265 | catch (Exception)
266 | {
267 | }
268 | Stopped?.Invoke(this, new EventArgs());
269 | }
270 |
271 |
272 | }
273 | }
274 |
--------------------------------------------------------------------------------
/TabletDriverService/config/tablet.cfg:
--------------------------------------------------------------------------------
1 | #
2 | # Example tablet definition:
3 | # Tablet 0x056a 0x00dd 0x0D 0x01
4 | #
5 | # VID: 0x056a
6 | # PID: 0x00dd
7 | # HID Usage Page: 0x0D
8 | # HID Usage: 0x01
9 | #
10 |
11 |
12 | #
13 | # Wacom CTL-470 (Wacom drivers installed)
14 | #
15 | Tablet 0x056a 0x00dd 0xFF00 0x000A
16 | Name "Wacom CTL-470 (Wacom drivers installed)"
17 | ReportId 0x02
18 | ReportLength 11
19 | DetectMask 0x40
20 | MaxX 14720
21 | MaxY 9200
22 | MaxPressure 1023
23 | Width 147.2
24 | Height 92.0
25 | Type WacomDrivers
26 |
27 |
28 | #
29 | # Wacom CTL-470
30 | #
31 | Tablet 0x056a 0x00dd 0x0D 0x01
32 | Name "Wacom CTL-470"
33 | ReportId 0x02
34 | ReportLength 10
35 | DetectMask 0x40
36 | MaxX 14720
37 | MaxY 9200
38 | MaxPressure 1023
39 | Width 147.2
40 | Height 92.0
41 | InitFeature 0x02 0x02
42 |
43 |
44 | #
45 | # Wacom CTH-470 ???
46 | #
47 | Tablet 0x056a 0x00de 0x0D 0x01
48 | Name "Wacom CTH-470"
49 | ReportId 0x02
50 | ReportLength 10
51 | DetectMask 0x40
52 | MaxX 14720
53 | MaxY 9200
54 | MaxPressure 1023
55 | Width 147.2
56 | Height 92.0
57 | InitFeature 0x02 0x02
58 |
59 |
60 | #
61 | # Wacom CTH-670 ???
62 | #
63 | Tablet 0x056a 0x00df 0x0D 0x01
64 | Name "Wacom CTH-670"
65 | ReportId 0x02
66 | ReportLength 10
67 | DetectMask 0x40
68 | MaxX 21648
69 | MaxY 13700
70 | MaxPressure 1023
71 | Width 216.48
72 | Height 137.0
73 | InitFeature 0x02 0x02
74 |
75 |
76 | #
77 | # Wacom CTL-471 (Wacom drivers installed)
78 | #
79 | Tablet 0x056a 0x0300 0xFF00 0x000A
80 | Name "Wacom CTL-471 (Wacom drivers installed)"
81 | ReportLength 11
82 | DetectMask 0x40
83 | MaxX 15200
84 | MaxY 9500
85 | MaxPressure 1023
86 | Width 152.00
87 | Height 95.00
88 | Type WacomDrivers
89 |
90 |
91 | #
92 | # Wacom CTL-471
93 | #
94 | Tablet 0x056a 0x0300 0xFF0D 0x01
95 | Name "Wacom CTL-471"
96 | ReportLength 10
97 | DetectMask 0x40
98 | MaxX 15200
99 | MaxY 9500
100 | MaxPressure 1023
101 | Width 152.00
102 | Height 95.00
103 | InitFeature 0x02 0x02
104 |
105 |
106 | #
107 | # Wacom CTL-671 ???
108 | #
109 | Tablet 0x056a 0x0301 0xFF0D 0x01
110 | Name "Wacom CTL-671"
111 | ReportLength 10
112 | DetectMask 0x40
113 | MaxX 21648
114 | MaxY 13530
115 | MaxPressure 1023
116 | Width 216.48
117 | Height 135.30
118 | InitFeature 0x02 0x02
119 |
120 |
121 | #
122 | # Wacom CTL-472
123 | #
124 | Tablet 0x056a 0x037a 0xFF00 0x000A
125 | Name "Wacom CTL-472 (Wacom drivers installed)"
126 | ReportId 0x02
127 | ReportLength 11
128 | DetectMask 0x40
129 | MaxX 15200
130 | MaxY 9500
131 | MaxPressure 2047
132 | Width 152.0
133 | Height 95.0
134 | Type WacomDrivers
135 |
136 |
137 | #
138 | # Wacom CTL-472
139 | #
140 | Tablet 0x056a 0x037a 0xFF0D 0x0001
141 | Name "Wacom CTL-472"
142 | ReportId 0x02
143 | ReportLength 10
144 | DetectMask 0x40
145 | MaxX 15200
146 | MaxY 9500
147 | MaxPressure 2047
148 | Width 152.0
149 | Height 95.0
150 | InitFeature 0x02 0x02
151 |
152 |
153 | #
154 | # Wacom CTL-672 ???
155 | #
156 | Tablet 0x056a 0x037b 0xFF0D 0x0001
157 | Name "Wacom CTL-672"
158 | ReportId 0x02
159 | ReportLength 10
160 | DetectMask 0x40
161 | MaxX 21600
162 | MaxY 13500
163 | MaxPressure 2047
164 | Width 216.00
165 | Height 135.00
166 | InitFeature 0x02 0x02
167 |
168 |
169 | #
170 | # Wacom CTL-480 (Wacom drivers installed)
171 | #
172 | Tablet 0x056a 0x030e 0xFF00 0x000A
173 | Name "Wacom CTL-480 (Wacom drivers installed)"
174 | ReportId 0x02
175 | ReportLength 11
176 | DetectMask 0x40
177 | MaxX 15200
178 | MaxY 9500
179 | MaxPressure 1023
180 | Width 152.0
181 | Height 95.0
182 | Type WacomDrivers
183 |
184 |
185 | #
186 | # Wacom CTL-480
187 | #
188 | Tablet 0x056a 0x030e 0xFF0D 0x0001
189 | Name "Wacom CTL-480"
190 | ReportId 0x02
191 | ReportLength 10
192 | DetectMask 0x40
193 | MaxX 15200
194 | MaxY 9500
195 | MaxPressure 1023
196 | Width 152.0
197 | Height 95.0
198 | InitFeature 0x02 0x02
199 |
200 |
201 | #
202 | # Wacom CTH-480 (Wacom drivers installed)
203 | #
204 | Tablet 0x056a 0x0302 0xFF00 0x000A
205 | Name "Wacom CTH-480 (Wacom drivers installed)"
206 | ReportId 0x02
207 | ReportLength 11
208 | DetectMask 0x40
209 | MaxX 15200
210 | MaxY 9500
211 | MaxPressure 1023
212 | Width 152.0
213 | Height 95.0
214 | Type WacomDrivers
215 |
216 |
217 | #
218 | # Wacom CTH-480
219 | #
220 | Tablet 0x056a 0x0302 0xFF0D 0x0001
221 | Name "Wacom CTH-480"
222 | ReportId 0x02
223 | ReportLength 10
224 | DetectMask 0x40
225 | MaxX 15200
226 | MaxY 9500
227 | MaxPressure 1023
228 | Width 152.0
229 | Height 95.0
230 | InitFeature 0x02 0x02
231 |
232 |
233 | #
234 | # Wacom CTL-680 ???
235 | #
236 | Tablet 0x056a 0x0323 0xFF0D 0x0001
237 | Name "Wacom CTL-680"
238 | ReportId 0x02
239 | ReportLength 10
240 | DetectMask 0x40
241 | MaxX 21600
242 | MaxY 13500
243 | MaxPressure 1023
244 | Width 216.0
245 | Height 135.0
246 | InitFeature 0x02 0x02
247 |
248 |
249 | #
250 | # Wacom CTH-680 ???
251 | #
252 | Tablet 0x056a 0x0303 0xFF0D 0x0001
253 | Name "Wacom CTH-680"
254 | ReportId 0x02
255 | ReportLength 10
256 | DetectMask 0x40
257 | MaxX 21600
258 | MaxY 13500
259 | MaxPressure 1023
260 | Width 216.0
261 | Height 135.0
262 | InitFeature 0x02 0x02
263 |
264 |
265 | #
266 | # Wacom CTL-490
267 | #
268 | Tablet 0x056a 0x033b 0xFF0D 0x0001
269 | Name "Wacom CTL-490"
270 | ReportId 0x10
271 | ReportLength 10
272 | DetectMask 0xA0
273 | MaxX 15200
274 | MaxY 9500
275 | MaxPressure 2047
276 | KeepTipDown 2 packets
277 | Width 152.0
278 | Height 95.0
279 | #Feature 0x83 0x02 0x00
280 | InitFeature 0x02 0x02
281 | Type WacomIntuos
282 |
283 |
284 | #
285 | # Wacom CTH-490 ???
286 | #
287 | Tablet 0x056a 0x033c 0xFF0D 0x0001
288 | Name "Wacom CTH-490"
289 | ReportId 0x10
290 | ReportLength 10
291 | DetectMask 0xA0
292 | MaxX 15200
293 | MaxY 9500
294 | MaxPressure 2047
295 | KeepTipDown 2 packets
296 | Width 152.0
297 | Height 95.0
298 | InitFeature 0x02 0x02
299 | Type WacomIntuos
300 |
301 |
302 | #
303 | # Wacom CTL-4100
304 | #
305 | Tablet 0x056a 0x0376 0xFF0D 0x0001
306 | Tablet 0x056a 0x0374 0xFF0D 0x0001
307 | Name "Wacom CTL-4100"
308 | ReportId 0x10
309 | ReportLength 192
310 | DetectMask 0x40
311 | MaxX 15200
312 | MaxY 9500
313 | MaxPressure 4095
314 | Width 152.0
315 | Height 95.0
316 | Type Wacom4100
317 |
318 | #
319 | # Wacom CTL-4100 (Wacom drivers installed)
320 | #
321 | Tablet 0x056a 0x0376 0xFF00 0x000A
322 | Tablet 0x056a 0x0374 0xFF00 0x000A
323 | Name "Wacom CTL-4100 (Wacom drivers installed)"
324 | ReportId 0x10
325 | ReportLength 193
326 | DetectMask 0x40
327 | MaxX 15200
328 | MaxY 9500
329 | MaxPressure 4095
330 | Width 152.0
331 | Height 95.0
332 | Type Wacom4100
333 |
334 |
335 | #
336 | # Wacom CTL-4100 Bluetooth
337 | Tablet 0x056a 0x0377 0xFF0D 0x0001
338 | Name "Wacom CTL-4100 Bluetooth (Experimental)"
339 | ReportId100 Bluetooth
340 | # 0x81
341 | ReportLength 361
342 | DetectMask 0xE0
343 | MaxX 15200
344 | MaxY 9500
345 | MaxPressure 4095
346 | Width 152.0
347 | Height 95.0
348 |
349 |
350 | #
351 | # Wacom PTH-451 ???
352 | #
353 | Tablet 0x056a 0x0314 0xFF0D 0x01
354 | Name "Wacom PTH-451"
355 | ReportLength 10
356 | DetectMask 0xE0
357 | MaxX 31496
358 | MaxY 19685
359 | MaxPressure 2047
360 | Width 157.0
361 | Height 98.0
362 | InitFeature 0x02 0x02
363 | Type WacomIntuos
364 |
365 |
366 | #
367 | # Wacom PTH-850
368 | #
369 | Tablet 0x056A 0x0028 0x00D 0x0001
370 | Name "Wacom PTH-850"
371 | ReportLength 10
372 | DetectMask 0xE0
373 | MaxX 65024
374 | MaxY 40640
375 | MaxPressure 2047
376 | Width 325.120
377 | Height 203.200
378 | InitFeature 0x02 0x02
379 | Type WacomIntuos
380 |
381 |
382 |
383 | #
384 | # XP-Pen G430
385 | #
386 | Tablet 0x28BD 0x0075 0xFF0A 0x0001
387 | Name "XP-Pen G430"
388 | ReportId 0x02
389 | ReportLength 8
390 | DetectMask 0x80
391 | MaxX 45720
392 | MaxY 29210
393 | MaxPressure 2047
394 | Width 102.4
395 | Height 76.2
396 | InitReport 0x02 0xB0 0x02 0x00 0x00 0x00 0x00 0x00
397 |
398 |
399 | #
400 | # XP-Pen G540 Pro
401 | #
402 | Tablet 0x28BD 0x0061 0xFF0A 0x0001
403 | Name "XP-Pen G540 Pro"
404 | ReportId 0x02
405 | ReportLength 8
406 | DetectMask 0x80
407 | MaxX 45720
408 | MaxY 29210
409 | MaxPressure 8191
410 | Width 147.0
411 | Height 101.6
412 | InitReport 0x02 0xB0 0x02 0x00 0x00 0x00 0x00 0x00
413 |
414 |
415 | #
416 | # XP-Pen G640
417 | #
418 | Tablet 0x28BD 0x0094 0xFF0A 0x0001
419 | Name "XP-Pen G640"
420 | ReportId 0x02
421 | ReportLength 8
422 | DetectMask 0x80
423 | MaxX 32000
424 | MaxY 20000
425 | MaxPressure 8191
426 | Width 160.0
427 | Height 100.0
428 | InitReport 0x02 0xB0 0x02 0x00 0x00 0x00 0x00 0x00
429 |
430 |
431 | #
432 | # XP-Pen Deco 01
433 | #
434 | Tablet 0x28BD 0x0042 0xFF0A 0x0001
435 | Name "XP-Pen Deco 01"
436 | ReportId 0x02
437 | ReportLength 8
438 | DetectMask 0x80
439 | MaxX 25400
440 | MaxY 15875
441 | MaxPressure 8191
442 | Width 254.0
443 | Height 158.75
444 | InitReport 0x02 0xB0 0x02 0x00 0x00 0x00 0x00 0x00
445 |
446 |
447 | #
448 | # Huion 420
449 | #
450 | Tablet "{62F12D4C-3431-4EFD-8DD7-8E9AAB18D30C}" 6 420
451 | Name "Huion 420"
452 | ReportId 0x07
453 | ReportLength 8
454 | DetectMask 0x80
455 | MaxX 8340
456 | MaxY 4680
457 | MaxPressure 2047
458 | Width 101.6
459 | Height 56.6
460 |
461 |
462 | #
463 | # Huion H420
464 | #
465 | Tablet "{62F12D4C-3431-4EFD-8DD7-8E9AAB18D30C}" 6 H420
466 | Name "Huion H420"
467 | ReportLength 8
468 | DetectMask 0x80
469 | MaxX 8340
470 | MaxY 4680
471 | MaxPressure 2047
472 | Width 101.6
473 | Height 56.6
474 |
475 |
476 | #
477 | # Huion H430P
478 | #
479 | Tablet "{62F12D4C-3431-4EFD-8DD7-8E9AAB18D30C}" 201 HUION_T176
480 | Name "Huion H430P"
481 | ReportId 0x08
482 | ReportLength 12
483 | DetectMask 0x80
484 | IgnoreMask 0x60
485 | MaxX 24384
486 | MaxY 15240
487 | MaxPressure 4095
488 | Width 121.92
489 | Height 76.20
490 |
491 |
492 | #
493 | # Huion H640P
494 | #
495 | Tablet "{62F12D4C-3431-4EFD-8DD7-8E9AAB18D30C}" 201 HUION_T173
496 | Name "Huion H640P"
497 | ReportId 0x08
498 | ReportLength 8
499 | DetectMask 0x80
500 | MaxX 31999
501 | MaxY 20000
502 | MaxPressure 8191
503 | Width 160.0
504 | Height 100.0
505 |
506 |
507 | #
508 | # Gaomon S56K
509 | #
510 | Tablet "{62F12D4C-3431-4EFD-8DD7-8E9AAB18D30C}" 201 HUION_T156
511 | Name "Gaomon S56K"
512 | ReportId 0x07
513 | ReportLength 8
514 | DetectMask 0x80
515 | MaxX 25196
516 | MaxY 18896
517 | MaxPressure 2047
518 | Width 160.0
519 | Height 120.0
520 |
521 |
522 | #
523 | # Huion osu!tablet
524 | #
525 | Tablet "{62F12D4C-3431-4EFD-8DD7-8E9AAB18D30C}" 200 HVAN
526 | Name "Huion osu!tablet (check the GitHub issue #99)"
527 | ReportId 0x07
528 | ReportLength 8
529 | DetectMask 0x80
530 | MaxX 8340
531 | MaxY 4680
532 | MaxPressure 2047
533 | Width 101.6
534 | Height 56.6
535 |
536 |
--------------------------------------------------------------------------------
/TabletDriverService/TabletDriverService.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 15.0
23 | {3101CEC2-8F39-45FD-943B-79A488AD05EA}
24 | Win32Proj
25 | TabletDriverService
26 | 10.0.17763.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v141
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v141
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v141
46 | Unicode
47 |
48 |
49 | Application
50 | false
51 | v141
52 | true
53 | Unicode
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | true
75 |
76 |
77 | true
78 |
79 |
80 | false
81 | Build
82 |
83 |
84 | false
85 |
86 |
87 |
88 | Use
89 | Level3
90 | Disabled
91 | true
92 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
93 | true
94 | stdcpp14
95 |
96 |
97 | Console
98 | true
99 |
100 |
101 |
102 |
103 | Use
104 | Level3
105 | Disabled
106 | true
107 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
108 | true
109 |
110 |
111 | Console
112 | true
113 |
114 |
115 |
116 |
117 | Use
118 | Level3
119 | MaxSpeed
120 | true
121 | true
122 | true
123 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
124 | true
125 |
126 |
127 | Console
128 | true
129 | true
130 | true
131 |
132 |
133 | xcopy /C /Y "$(TargetPath)" "$(SolutionDir)TabletDriverGUI\bin\Debug\bin\"
134 | xcopy /C /Y "$(TargetPath)" "$(SolutionDir)TabletDriverGUI\bin\Release\bin\"
135 |
136 | xcopy /C /Y "$(ProjectDir)config\tablet.cfg" "$(SolutionDir)TabletDriverGUI\bin\Release\config\"
137 | xcopy /C /Y "$(ProjectDir)config\tablet.cfg" "$(SolutionDir)TabletDriverGUI\bin\Debug\config\"
138 |
139 | xcopy /C /Y "$(ProjectDir)config\wacom.cfg" "$(SolutionDir)TabletDriverGUI\bin\Release\config\"
140 | xcopy /C /Y "$(ProjectDir)config\wacom.cfg" "$(SolutionDir)TabletDriverGUI\bin\Debug\config\"
141 |
142 | xcopy /C /Y "$(ProjectDir)config\user.cfg" "$(SolutionDir)TabletDriverGUI\bin\Release\config\"
143 | xcopy /C /Y "$(ProjectDir)config\user.cfg" "$(SolutionDir)TabletDriverGUI\bin\Debug\config\"
144 |
145 | xcopy /C /Y "$(ProjectDir)config\init.cfg" "$(SolutionDir)TabletDriverGUI\bin\Release\config\"
146 | xcopy /C /Y "$(ProjectDir)config\init.cfg" "$(SolutionDir)TabletDriverGUI\bin\Debug\config\"
147 |
148 | Copy files
149 | copyfiles.txt
150 |
151 |
152 |
153 |
154 | Use
155 | Level3
156 | MaxSpeed
157 | true
158 | true
159 | true
160 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
161 | true
162 |
163 |
164 | Console
165 | true
166 | true
167 | true
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 | Create
207 | Create
208 | Create
209 | Create
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
--------------------------------------------------------------------------------
/TabletDriverService/config/wacom.cfg:
--------------------------------------------------------------------------------
1 | #
2 | # This file is automatically generated from these sources:
3 | # https://github.com/linuxwacom/input-wacom/blob/master/3.7/wacom_wac.h
4 | # https://github.com/linuxwacom/input-wacom/blob/master/3.7/wacom_wac.c
5 | # https://github.com/linuxwacom/input-wacom/wiki/Device-IDs
6 | #
7 | # DO NOT EDIT THIS FILE!
8 | # Make the configuration modifications to the tablet.cfg
9 | # Tablet.cfg will overwrite the settings from this file, if the tablet is found.
10 | #
11 |
12 |
13 | # Wacom PTK-450
14 | Tablet 0x056A 0x0029 0xFF0D 0x0001
15 | Tablet 0x056A 0x0029 0x000D 0x0001
16 | Name "Wacom PTK-450"
17 | ReportLength 10
18 | DetectMask 0xE0
19 | MaxX 31496
20 | MaxY 19685
21 | MaxPressure 2047
22 | Width 157.480
23 | Height 98.425
24 | InitFeature 0x02 0x02
25 | Type WacomIntuos
26 |
27 |
28 | # Wacom PTK-650
29 | Tablet 0x056A 0x002A 0xFF0D 0x0001
30 | Tablet 0x056A 0x002A 0x000D 0x0001
31 | Name "Wacom PTK-650"
32 | ReportLength 10
33 | DetectMask 0xE0
34 | MaxX 44704
35 | MaxY 27940
36 | MaxPressure 2047
37 | Width 223.520
38 | Height 139.700
39 | InitFeature 0x02 0x02
40 | Type WacomIntuos
41 |
42 |
43 | # Wacom PTH-450
44 | Tablet 0x056A 0x0026 0xFF0D 0x0001
45 | Tablet 0x056A 0x0026 0x000D 0x0001
46 | Name "Wacom PTH-450"
47 | ReportLength 10
48 | DetectMask 0xE0
49 | MaxX 31496
50 | MaxY 19685
51 | MaxPressure 2047
52 | Width 157.480
53 | Height 98.425
54 | InitFeature 0x02 0x02
55 | Type WacomIntuos
56 |
57 |
58 | # Wacom PTH-451
59 | Tablet 0x056A 0x0314 0xFF0D 0x0001
60 | Tablet 0x056A 0x0314 0x000D 0x0001
61 | Name "Wacom PTH-451"
62 | ReportLength 10
63 | DetectMask 0x40
64 | MaxX 31496
65 | MaxY 19685
66 | MaxPressure 2047
67 | Width 157.480
68 | Height 98.425
69 | InitFeature 0x02 0x02
70 | Type WacomIntuos
71 |
72 |
73 | # Wacom PTH-650
74 | Tablet 0x056A 0x0027 0xFF0D 0x0001
75 | Tablet 0x056A 0x0027 0x000D 0x0001
76 | Name "Wacom PTH-650"
77 | ReportLength 10
78 | DetectMask 0xE0
79 | MaxX 44704
80 | MaxY 27940
81 | MaxPressure 2047
82 | Width 223.520
83 | Height 139.700
84 | InitFeature 0x02 0x02
85 | Type WacomIntuos
86 |
87 |
88 | # Wacom PTH-651
89 | Tablet 0x056A 0x0315 0xFF0D 0x0001
90 | Tablet 0x056A 0x0315 0x000D 0x0001
91 | Name "Wacom PTH-651"
92 | ReportLength 10
93 | DetectMask 0x40
94 | MaxX 44704
95 | MaxY 27940
96 | MaxPressure 2047
97 | Width 223.520
98 | Height 139.700
99 | InitFeature 0x02 0x02
100 | Type WacomIntuos
101 |
102 |
103 | # Wacom PTH-850
104 | Tablet 0x056A 0x0028 0xFF0D 0x0001
105 | Tablet 0x056A 0x0028 0x000D 0x0001
106 | Name "Wacom PTH-850"
107 | ReportLength 10
108 | DetectMask 0xE0
109 | MaxX 65024
110 | MaxY 40640
111 | MaxPressure 2047
112 | Width 325.120
113 | Height 203.200
114 | InitFeature 0x02 0x02
115 | Type WacomIntuos
116 |
117 |
118 | # Wacom PTH-851
119 | Tablet 0x056A 0x0317 0xFF0D 0x0001
120 | Tablet 0x056A 0x0317 0x000D 0x0001
121 | Name "Wacom PTH-851"
122 | ReportLength 10
123 | DetectMask 0x40
124 | MaxX 65024
125 | MaxY 40640
126 | MaxPressure 2047
127 | Width 325.120
128 | Height 203.200
129 | InitFeature 0x02 0x02
130 | Type WacomIntuos
131 |
132 |
133 | # Wacom MTE-450
134 | Tablet 0x056A 0x0065 0xFF0D 0x0001
135 | Tablet 0x056A 0x0065 0x000D 0x0001
136 | Name "Wacom MTE-450"
137 | ReportLength 9
138 | DetectMask 0x00
139 | MaxX 14760
140 | MaxY 9225
141 | MaxPressure 511
142 | Width 147.600
143 | Height 92.250
144 | InitFeature 0x02 0x02
145 |
146 |
147 | # Wacom CTT-460
148 | Tablet 0x056A 0x00D0 0xFF0D 0x0001
149 | Tablet 0x056A 0x00D0 0x000D 0x0001
150 | Name "Wacom CTT-460"
151 | ReportLength 9
152 | DetectMask 0x40
153 | MaxX 14720
154 | MaxY 9200
155 | MaxPressure 1023
156 | Width 147.200
157 | Height 92.000
158 | InitFeature 0x02 0x02
159 |
160 |
161 | # Wacom CTL-460
162 | Tablet 0x056A 0x00D4 0xFF0D 0x0001
163 | Tablet 0x056A 0x00D4 0x000D 0x0001
164 | Name "Wacom CTL-460"
165 | ReportLength 9
166 | DetectMask 0x40
167 | MaxX 14720
168 | MaxY 9200
169 | MaxPressure 1023
170 | Width 147.200
171 | Height 92.000
172 | InitFeature 0x02 0x02
173 |
174 |
175 | # Wacom CTL-470
176 | Tablet 0x056A 0x00DD 0xFF0D 0x0001
177 | Tablet 0x056A 0x00DD 0x000D 0x0001
178 | Name "Wacom CTL-470"
179 | ReportLength 10
180 | DetectMask 0x40
181 | MaxX 14720
182 | MaxY 9200
183 | MaxPressure 1023
184 | Width 147.200
185 | Height 92.000
186 | InitFeature 0x02 0x02
187 |
188 |
189 | # Wacom CTL-471
190 | Tablet 0x056A 0x0300 0xFF0D 0x0001
191 | Tablet 0x056A 0x0300 0x000D 0x0001
192 | Name "Wacom CTL-471"
193 | ReportLength 10
194 | DetectMask 0x40
195 | MaxX 14720
196 | MaxY 9225
197 | MaxPressure 1023
198 | Width 147.200
199 | Height 92.250
200 | InitFeature 0x02 0x02
201 |
202 |
203 | # Wacom CTL-472
204 | Tablet 0x056A 0x037A 0xFF0D 0x0001
205 | Tablet 0x056A 0x037A 0x000D 0x0001
206 | Name "Wacom CTL-472"
207 | ReportLength 10
208 | DetectMask 0x40
209 | MaxX 15200
210 | MaxY 9500
211 | MaxPressure 2047
212 | Width 152.000
213 | Height 95.000
214 | InitFeature 0x02 0x02
215 |
216 |
217 | # Wacom CTL-480
218 | Tablet 0x056A 0x030E 0xFF0D 0x0001
219 | Tablet 0x056A 0x030E 0x000D 0x0001
220 | Name "Wacom CTL-480"
221 | ReportLength 10
222 | DetectMask 0x40
223 | MaxX 15200
224 | MaxY 9500
225 | MaxPressure 1023
226 | Width 152.000
227 | Height 95.000
228 | InitFeature 0x02 0x02
229 |
230 |
231 | # Wacom CTL-490
232 | Tablet 0x056A 0x033B 0xFF0D 0x0001
233 | Tablet 0x056A 0x033B 0x000D 0x0001
234 | Name "Wacom CTL-490"
235 | ReportLength 10
236 | DetectMask 0x40
237 | MaxX 15200
238 | MaxY 9500
239 | MaxPressure 2047
240 | Width 152.000
241 | Height 95.000
242 | InitFeature 0x02 0x02
243 | Type WacomIntuos
244 |
245 |
246 | # Wacom CTL-660
247 | Tablet 0x056A 0x00D5 0xFF0D 0x0001
248 | Tablet 0x056A 0x00D5 0x000D 0x0001
249 | Name "Wacom CTL-660"
250 | ReportLength 9
251 | DetectMask 0x40
252 | MaxX 21648
253 | MaxY 13700
254 | MaxPressure 1023
255 | Width 216.480
256 | Height 137.000
257 | InitFeature 0x02 0x02
258 |
259 |
260 | # Wacom CTL-671
261 | Tablet 0x056A 0x0301 0xFF0D 0x0001
262 | Tablet 0x056A 0x0301 0x000D 0x0001
263 | Name "Wacom CTL-671"
264 | ReportLength 10
265 | DetectMask 0x40
266 | MaxX 21648
267 | MaxY 13530
268 | MaxPressure 1023
269 | Width 216.480
270 | Height 135.300
271 | InitFeature 0x02 0x02
272 |
273 |
274 | # Wacom CTL-672
275 | Tablet 0x056A 0x037B 0xFF0D 0x0001
276 | Tablet 0x056A 0x037B 0x000D 0x0001
277 | Name "Wacom CTL-672"
278 | ReportLength 10
279 | DetectMask 0x40
280 | MaxX 21600
281 | MaxY 13500
282 | MaxPressure 2047
283 | Width 216.000
284 | Height 135.000
285 | InitFeature 0x02 0x02
286 |
287 |
288 | # Wacom CTL-680
289 | Tablet 0x056A 0x0323 0xFF0D 0x0001
290 | Tablet 0x056A 0x0323 0x000D 0x0001
291 | Name "Wacom CTL-680"
292 | ReportLength 10
293 | DetectMask 0x40
294 | MaxX 21600
295 | MaxY 13500
296 | MaxPressure 1023
297 | Width 216.000
298 | Height 135.000
299 | InitFeature 0x02 0x02
300 |
301 |
302 | # Wacom CTL-690
303 | Tablet 0x056A 0x033D 0xFF0D 0x0001
304 | Tablet 0x056A 0x033D 0x000D 0x0001
305 | Name "Wacom CTL-690"
306 | ReportLength 10
307 | DetectMask 0x40
308 | MaxX 21600
309 | MaxY 13500
310 | MaxPressure 2047
311 | Width 216.000
312 | Height 135.000
313 | InitFeature 0x02 0x02
314 | Type WacomIntuos
315 |
316 |
317 | # Wacom CTH-460(A)
318 | Tablet 0x056A 0x00D6 0xFF0D 0x0001
319 | Tablet 0x056A 0x00D6 0x000D 0x0001
320 | Name "Wacom CTH-460(A)"
321 | ReportLength 9
322 | DetectMask 0x40
323 | MaxX 14720
324 | MaxY 9200
325 | MaxPressure 1023
326 | Width 147.200
327 | Height 92.000
328 | InitFeature 0x02 0x02
329 |
330 |
331 | # Wacom CTH-461(A)
332 | Tablet 0x056A 0x00D7 0xFF0D 0x0001
333 | Tablet 0x056A 0x00D7 0x000D 0x0001
334 | Name "Wacom CTH-461(A)"
335 | ReportLength 9
336 | DetectMask 0x40
337 | MaxX 14720
338 | MaxY 9200
339 | MaxPressure 1023
340 | Width 147.200
341 | Height 92.000
342 | InitFeature 0x02 0x02
343 |
344 |
345 | # Wacom CTH-461SE
346 | Tablet 0x056A 0x00DA 0xFF0D 0x0001
347 | Tablet 0x056A 0x00DA 0x000D 0x0001
348 | Name "Wacom CTH-461SE"
349 | ReportLength 9
350 | DetectMask 0x40
351 | MaxX 14720
352 | MaxY 9200
353 | MaxPressure 1023
354 | Width 147.200
355 | Height 92.000
356 | InitFeature 0x02 0x02
357 |
358 |
359 | # Wacom CTH-460
360 | Tablet 0x056A 0x00D1 0xFF0D 0x0001
361 | Tablet 0x056A 0x00D1 0x000D 0x0001
362 | Name "Wacom CTH-460"
363 | ReportLength 9
364 | DetectMask 0x40
365 | MaxX 14720
366 | MaxY 9200
367 | MaxPressure 1023
368 | Width 147.200
369 | Height 92.000
370 | InitFeature 0x02 0x02
371 |
372 |
373 | # Wacom CTH-461
374 | Tablet 0x056A 0x00D2 0xFF0D 0x0001
375 | Tablet 0x056A 0x00D2 0x000D 0x0001
376 | Name "Wacom CTH-461"
377 | ReportLength 9
378 | DetectMask 0x40
379 | MaxX 14720
380 | MaxY 9200
381 | MaxPressure 1023
382 | Width 147.200
383 | Height 92.000
384 | InitFeature 0x02 0x02
385 |
386 |
387 | # Wacom CTH-470
388 | Tablet 0x056A 0x00DE 0xFF0D 0x0001
389 | Tablet 0x056A 0x00DE 0x000D 0x0001
390 | Name "Wacom CTH-470"
391 | ReportLength 10
392 | DetectMask 0x40
393 | MaxX 14720
394 | MaxY 9200
395 | MaxPressure 1023
396 | Width 147.200
397 | Height 92.000
398 | InitFeature 0x02 0x02
399 |
400 |
401 | # Wacom CTH-480
402 | Tablet 0x056A 0x0302 0xFF0D 0x0001
403 | Tablet 0x056A 0x0302 0x000D 0x0001
404 | Name "Wacom CTH-480"
405 | ReportLength 10
406 | DetectMask 0x40
407 | MaxX 15200
408 | MaxY 9500
409 | MaxPressure 1023
410 | Width 152.000
411 | Height 95.000
412 | InitFeature 0x02 0x02
413 |
414 |
415 | # Wacom CTH-490
416 | Tablet 0x056A 0x033C 0xFF0D 0x0001
417 | Tablet 0x056A 0x033C 0x000D 0x0001
418 | Name "Wacom CTH-490"
419 | ReportLength 10
420 | DetectMask 0x40
421 | MaxX 15200
422 | MaxY 9500
423 | MaxPressure 2047
424 | Width 152.000
425 | Height 95.000
426 | InitFeature 0x02 0x02
427 | Type WacomIntuos
428 |
429 |
430 | # Wacom CTH-661
431 | Tablet 0x056A 0x00D3 0xFF0D 0x0001
432 | Tablet 0x056A 0x00D3 0x000D 0x0001
433 | Name "Wacom CTH-661"
434 | ReportLength 9
435 | DetectMask 0x40
436 | MaxX 21648
437 | MaxY 13700
438 | MaxPressure 1023
439 | Width 216.480
440 | Height 137.000
441 | InitFeature 0x02 0x02
442 |
443 |
444 | # Wacom CTH-661(A)
445 | Tablet 0x056A 0x00D8 0xFF0D 0x0001
446 | Tablet 0x056A 0x00D8 0x000D 0x0001
447 | Name "Wacom CTH-661(A)"
448 | ReportLength 9
449 | DetectMask 0x40
450 | MaxX 21648
451 | MaxY 13700
452 | MaxPressure 1023
453 | Width 216.480
454 | Height 137.000
455 | InitFeature 0x02 0x02
456 |
457 |
458 | # Wacom CTH-661SE
459 | Tablet 0x056A 0x00DB 0xFF0D 0x0001
460 | Tablet 0x056A 0x00DB 0x000D 0x0001
461 | Name "Wacom CTH-661SE"
462 | ReportLength 9
463 | DetectMask 0x40
464 | MaxX 21648
465 | MaxY 13700
466 | MaxPressure 1023
467 | Width 216.480
468 | Height 137.000
469 | InitFeature 0x02 0x02
470 |
471 |
472 | # Wacom CTH-670
473 | Tablet 0x056A 0x00DF 0xFF0D 0x0001
474 | Tablet 0x056A 0x00DF 0x000D 0x0001
475 | Name "Wacom CTH-670"
476 | ReportLength 10
477 | DetectMask 0x40
478 | MaxX 21648
479 | MaxY 13700
480 | MaxPressure 1023
481 | Width 216.480
482 | Height 137.000
483 | InitFeature 0x02 0x02
484 |
485 |
486 | # Wacom CTH-680
487 | Tablet 0x056A 0x0303 0xFF0D 0x0001
488 | Tablet 0x056A 0x0303 0x000D 0x0001
489 | Name "Wacom CTH-680"
490 | ReportLength 10
491 | DetectMask 0x40
492 | MaxX 21600
493 | MaxY 13500
494 | MaxPressure 1023
495 | Width 216.000
496 | Height 135.000
497 | InitFeature 0x02 0x02
498 |
499 |
500 | # Wacom CTH-690
501 | Tablet 0x056A 0x033E 0xFF0D 0x0001
502 | Tablet 0x056A 0x033E 0x000D 0x0001
503 | Name "Wacom CTH-690"
504 | ReportLength 10
505 | DetectMask 0x40
506 | MaxX 21600
507 | MaxY 13500
508 | MaxPressure 2047
509 | Width 216.000
510 | Height 135.000
511 | InitFeature 0x02 0x02
512 | Type WacomIntuos
513 |
514 |
515 | # Wacom CTE-450
516 | Tablet 0x056A 0x0017 0xFF0D 0x0001
517 | Tablet 0x056A 0x0017 0x000D 0x0001
518 | Name "Wacom CTE-450"
519 | ReportLength 9
520 | DetectMask 0x00
521 | MaxX 14760
522 | MaxY 9225
523 | MaxPressure 511
524 | Width 147.600
525 | Height 92.250
526 | InitFeature 0x02 0x02
527 |
528 |
529 | # Wacom CTE-650
530 | Tablet 0x056A 0x0018 0xFF0D 0x0001
531 | Tablet 0x056A 0x0018 0x000D 0x0001
532 | Name "Wacom CTE-650"
533 | ReportLength 9
534 | DetectMask 0x00
535 | MaxX 21648
536 | MaxY 13530
537 | MaxPressure 511
538 | Width 216.480
539 | Height 135.300
540 | InitFeature 0x02 0x02
541 |
542 |
543 | #
544 | # Automatically generated Wacom tablet configurations (37):
545 | # PTK-450, PTK-650, PTH-450, PTH-451, PTH-650, PTH-651, PTH-850, PTH-851,
546 | # MTE-450, CTT-460, CTL-460, CTL-470, CTL-471, CTL-472, CTL-480, CTL-490,
547 | # CTL-660, CTL-671, CTL-672, CTL-680, CTL-690, CTH-460(A), CTH-461(A), CTH-461SE,
548 | # CTH-460, CTH-461, CTH-470, CTH-480, CTH-490, CTH-661, CTH-661(A), CTH-661SE,
549 | # CTH-670, CTH-680, CTH-690, CTE-450, CTE-650
550 | #
551 |
--------------------------------------------------------------------------------