summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Palecki <[email protected]>2021-01-20 00:42:24 -0800
committerJacob Palecki <[email protected]>2021-01-20 00:42:24 -0800
commit77b4c7876918cac82494ec8fc15a22fdab5cf714 (patch)
tree66b2c7d86cecf0846c3b5cdaa69c6991858ed931
parentRemove debug statement (diff)
parentshow custom dialog on bad input (#63) (diff)
downloadrawaccel-77b4c7876918cac82494ec8fc15a22fdab5cf714.tar.xz
rawaccel-77b4c7876918cac82494ec8fc15a22fdab5cf714.zip
merge with master builds
-rw-r--r--.gitignore11
-rw-r--r--common/common.vcxitems1
-rw-r--r--common/rawaccel-io-def.h4
-rw-r--r--common/rawaccel-settings.h3
-rw-r--r--common/utility-rawinput.hpp74
-rw-r--r--doc/Guide.md4
-rw-r--r--driver/driver.cpp75
-rw-r--r--driver/driver.h3
-rw-r--r--grapher/Form1.Designer.cs23
-rw-r--r--grapher/Form1.cs22
-rw-r--r--grapher/MessageDialog.Designer.cs98
-rw-r--r--grapher/MessageDialog.cs24
-rw-r--r--grapher/Models/AccelGUI.cs20
-rw-r--r--grapher/Models/AccelGUIFactory.cs11
-rw-r--r--grapher/Models/Devices/DeviceIDItem.cs73
-rw-r--r--grapher/Models/Devices/DeviceIDManager.cs86
-rw-r--r--grapher/Models/Mouse/MouseData.cs17
-rw-r--r--grapher/Models/Mouse/MouseWatcher.cs33
-rw-r--r--grapher/Models/Mouse/PointData.cs13
-rw-r--r--grapher/Models/Serialized/RawAccelSettings.cs3
-rw-r--r--grapher/Models/Serialized/SettingsManager.cs8
-rw-r--r--grapher/grapher.csproj10
-rw-r--r--installer/installer.cpp4
-rw-r--r--signed/driver/rawaccel.sysbin61096 -> 61640 bytes
-rw-r--r--uninstaller/uninstaller.cpp23
-rw-r--r--wrapper/wrapper.cpp27
-rw-r--r--wrapper/wrapper.vcxproj4
27 files changed, 585 insertions, 89 deletions
diff --git a/.gitignore b/.gitignore
index 71d9e60..2a7c213 100644
--- a/.gitignore
+++ b/.gitignore
@@ -138,6 +138,17 @@ _TeamCity*
.axoCover/*
!.axoCover/settings.json
+# Visual Studio code
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+*.code-workspace
+
+# Local History for Visual Studio Code
+.history/
+
# Visual Studio code coverage results
*.coverage
*.coveragexml
diff --git a/common/common.vcxitems b/common/common.vcxitems
index 2b03405..ba9bd98 100644
--- a/common/common.vcxitems
+++ b/common/common.vcxitems
@@ -29,6 +29,7 @@
<ClInclude Include="$(MSBuildThisFileDirectory)rawaccel-version.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)rawaccel.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)utility-install.hpp" />
+ <ClInclude Include="$(MSBuildThisFileDirectory)utility-rawinput.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)x64-util.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)vec2.h" />
</ItemGroup>
diff --git a/common/rawaccel-io-def.h b/common/rawaccel-io-def.h
index d8d4088..e169390 100644
--- a/common/rawaccel-io-def.h
+++ b/common/rawaccel-io-def.h
@@ -8,6 +8,6 @@
#define RA_DEV_TYPE 0x8888u
-#define RA_READ CTL_CODE(RA_DEV_TYPE, 0x888, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+#define RA_READ CTL_CODE(RA_DEV_TYPE, 0x888, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define RA_WRITE CTL_CODE(RA_DEV_TYPE, 0x889, METHOD_BUFFERED, FILE_ANY_ACCESS)
-#define RA_GET_VERSION CTL_CODE(RA_DEV_TYPE, 0x88a, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+#define RA_GET_VERSION CTL_CODE(RA_DEV_TYPE, 0x88a, METHOD_BUFFERED, FILE_ANY_ACCESS)
diff --git a/common/rawaccel-settings.h b/common/rawaccel-settings.h
index 755fa2c..6fa2aa9 100644
--- a/common/rawaccel-settings.h
+++ b/common/rawaccel-settings.h
@@ -3,6 +3,8 @@
#include "vec2.h"
#include "accel-base.hpp"
+#define MAX_DEV_ID_LEN 200
+
namespace rawaccel {
using milliseconds = double;
@@ -25,6 +27,7 @@ namespace rawaccel {
domain_args domain_args = {};
vec2d range_weights = { 1, 1 };
milliseconds time_min = DEFAULT_TIME_MIN;
+ wchar_t device_id[MAX_DEV_ID_LEN] = {0};
};
}
diff --git a/common/utility-rawinput.hpp b/common/utility-rawinput.hpp
new file mode 100644
index 0000000..3c44068
--- /dev/null
+++ b/common/utility-rawinput.hpp
@@ -0,0 +1,74 @@
+#pragma once
+
+#pragma comment(lib, "cfgmgr32.lib")
+
+#include <iostream>
+#include <string>
+#include <system_error>
+#include <vector>
+
+#include <Windows.h>
+#include <cfgmgr32.h>
+#include <initguid.h> // needed for devpkey.h to parse properly
+#include <devpkey.h>
+
+// returns device handles corresponding to a "device id"
+// https://docs.microsoft.com/en-us/windows-hardware/drivers/install/device-ids
+std::vector<HANDLE> rawinput_handles_from_dev_id(const std::wstring& dev_id, DWORD input_type = RIM_TYPEMOUSE) {
+ const UINT RI_ERROR = -1;
+
+ UINT num_devs = 0;
+
+ if (GetRawInputDeviceList(NULL, &num_devs, sizeof(RAWINPUTDEVICELIST)) == RI_ERROR) {
+ throw std::system_error(GetLastError(), std::system_category(), "GetRawInputDeviceList failed");
+ }
+
+ auto devs = std::vector<RAWINPUTDEVICELIST>(num_devs);
+
+ if (GetRawInputDeviceList(&devs[0], &num_devs, sizeof(RAWINPUTDEVICELIST)) == RI_ERROR) {
+ throw std::system_error(GetLastError(), std::system_category(), "GetRawInputDeviceList failed");
+ }
+
+ std::vector<HANDLE> handles;
+
+ for (auto&& dev : devs) {
+ if (dev.dwType != input_type) continue;
+
+ WCHAR name[256] = {};
+ UINT name_size = sizeof(name);
+
+ if (GetRawInputDeviceInfoW(dev.hDevice, RIDI_DEVICENAME, name, &name_size) == RI_ERROR) {
+ throw std::system_error(GetLastError(), std::system_category(), "GetRawInputDeviceInfoW failed");
+ }
+
+ ULONG id_size = 0;
+ DEVPROPTYPE type;
+ CONFIGRET cm_res;
+
+ cm_res = CM_Get_Device_Interface_PropertyW(name, &DEVPKEY_Device_InstanceId,
+ &type, NULL, &id_size, 0);
+
+ if (cm_res != CR_BUFFER_SMALL && cm_res != CR_SUCCESS) {
+ throw std::runtime_error("CM_Get_Device_Interface_PropertyW failed (" +
+ std::to_string(cm_res) + ')');
+ }
+
+ std::wstring id((static_cast<size_t>(id_size) + 1) / 2, '\0');
+
+ cm_res = CM_Get_Device_Interface_PropertyW(name, &DEVPKEY_Device_InstanceId,
+ &type, reinterpret_cast<PBYTE>(&id[0]), &id_size, 0);
+
+ if (cm_res != CR_SUCCESS) {
+ throw std::runtime_error("CM_Get_Device_Interface_PropertyW failed (" +
+ std::to_string(cm_res) + ')');
+ }
+
+ // remove instance id
+ id.resize(id.find_last_of('\\'));
+
+ if (id == dev_id) handles.push_back(dev.hDevice);
+ }
+
+ return handles;
+}
+
diff --git a/doc/Guide.md b/doc/Guide.md
index 4ac296d..54fbbc8 100644
--- a/doc/Guide.md
+++ b/doc/Guide.md
@@ -35,7 +35,7 @@ The above is much more clear with an example. Let's say I have
and I move my mouse to create an input of (30,40) at a poll rate of 1000 hz.
-Then our input speed is sqrt(30^2 + 40^2) = 50 counts/ms. Our accelerated sensitivity is calculated to be (1 + 0.1 \* 50) * 0.5 = 1.5 \* 0.5 = 0.75. So our output velocity is 0.75 \* 50 = 37.5. If I run the previous calculations with input speed 49.9 I get output velocity 37.40005, so our gain is about (37.5-37.40005)/(50-49.9) = 0.9995. Here is a picture of the charts in Raw Accel showing the same thing:
+Then our input speed is sqrt(30^2 + 40^2) = 50 counts/ms. Our accelerated sensitivity is calculated to be (1 + 0.01 \* 50) * 0.5 = 1.5 \* 0.5 = 0.75. So our output velocity is 0.75 \* 50 = 37.5. If I run the previous calculations with input speed 49.9 I get output velocity 37.40005, so our gain is about (37.5-37.40005)/(50-49.9) = 0.9995. Here is a picture of the charts in Raw Accel showing the same thing:
![SensVelocityGainExample](images/accel_readme_example.png)
@@ -100,4 +100,4 @@ This curve looks like an "S" with the top half bigger than the bottom. Mathemati
![MotivityExample](images/motivity_example.png)
## Further Help
-Further help and frequently asked questions can be found in the FAQ.
+Further help and frequently asked questions can be found in the [FAQ](https://github.com/a1xd/rawaccel/blob/master/doc/FAQ.md).
diff --git a/driver/driver.cpp b/driver/driver.cpp
index a99a70b..a92f773 100644
--- a/driver/driver.cpp
+++ b/driver/driver.cpp
@@ -54,15 +54,18 @@ Arguments:
WDFDEVICE hDevice = WdfWdmDeviceGetWdfDeviceHandle(DeviceObject);
PDEVICE_EXTENSION devExt = FilterGetData(hDevice);
- if (!(InputDataStart->Flags & MOUSE_MOVE_ABSOLUTE)) {
- auto num_packets = InputDataEnd - InputDataStart;
-
+ auto num_packets = InputDataEnd - InputDataStart;
+
+ bool any = num_packets > 0;
+ bool rel_move = !(InputDataStart->Flags & MOUSE_MOVE_ABSOLUTE);
+ bool dev_match = global.args.device_id[0] == 0 ||
+ wcsncmp(devExt->dev_id, global.args.device_id, MAX_DEV_ID_LEN) == 0;
+
+ if (any && rel_move && dev_match) {
// if IO is backed up to the point where we get more than 1 packet here
// then applying accel is pointless as we can't get an accurate timing
bool enable_accel = num_packets == 1;
- vec2d carry = devExt->carry;
-
auto it = InputDataStart;
do {
vec2d input = {
@@ -86,21 +89,20 @@ Arguments:
global.modifier.apply_sensitivity(input);
- double carried_result_x = input.x + carry.x;
- double carried_result_y = input.y + carry.y;
+ double carried_result_x = input.x + devExt->carry.x;
+ double carried_result_y = input.y + devExt->carry.y;
LONG out_x = static_cast<LONG>(carried_result_x);
LONG out_y = static_cast<LONG>(carried_result_y);
- carry.x = carried_result_x - out_x;
- carry.y = carried_result_y - out_y;
+ devExt->carry.x = carried_result_x - out_x;
+ devExt->carry.y = carried_result_y - out_y;
it->LastX = out_x;
it->LastY = out_y;
} while (++it != InputDataEnd);
- devExt->carry = carry;
}
(*(PSERVICE_CALLBACK_ROUTINE)devExt->UpperConnectData.ClassService)(
@@ -144,6 +146,8 @@ Return Value:
NTSTATUS status;
void* buffer;
+ size_t bytes_out = 0;
+
UNREFERENCED_PARAMETER(Queue);
UNREFERENCED_PARAMETER(OutputBufferLength);
UNREFERENCED_PARAMETER(InputBufferLength);
@@ -164,6 +168,7 @@ Return Value:
}
else {
*reinterpret_cast<ra::settings*>(buffer) = global.args;
+ bytes_out = sizeof(ra::settings);
}
break;
case RA_WRITE:
@@ -203,6 +208,7 @@ Return Value:
}
else {
*reinterpret_cast<ra::version_t*>(buffer) = { RA_VER_MAJOR, RA_VER_MINOR, RA_VER_PATCH };
+ bytes_out = sizeof(ra::version_t);
}
break;
default:
@@ -210,7 +216,7 @@ Return Value:
break;
}
- WdfRequestComplete(Request, status);
+ WdfRequestCompleteWithInformation(Request, status, bytes_out);
}
#pragma warning(pop) // enable 28118 again
@@ -465,7 +471,7 @@ Return Value:
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes,
DEVICE_EXTENSION);
-
+
//
// Create a framework device object. This call will in turn create
// a WDM deviceobject, attach to the lower stack and set the
@@ -477,6 +483,33 @@ Return Value:
return status;
}
+ //
+ // get device id from bus driver
+ //
+ DEVICE_OBJECT* pdo = WdfDeviceWdmGetPhysicalDevice(hDevice);
+
+ KEVENT ke;
+ KeInitializeEvent(&ke, NotificationEvent, FALSE);
+ IO_STATUS_BLOCK iosb = {};
+ PIRP Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
+ pdo, NULL, 0, NULL, &ke, &iosb);
+ Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
+ PIO_STACK_LOCATION stack = IoGetNextIrpStackLocation(Irp);
+ stack->MinorFunction = IRP_MN_QUERY_ID;
+ stack->Parameters.QueryId.IdType = BusQueryDeviceID;
+
+ NTSTATUS nts = IoCallDriver(pdo, Irp);
+
+ if (nts == STATUS_PENDING) {
+ KeWaitForSingleObject(&ke, Executive, KernelMode, FALSE, NULL);
+ }
+
+ if (NT_SUCCESS(nts)) {
+ auto* id_ptr = reinterpret_cast<WCHAR*>(iosb.Information);
+ wcsncpy(FilterGetData(hDevice)->dev_id, id_ptr, MAX_DEV_ID_LEN);
+ DebugPrint(("Device ID = %ws\n", id_ptr));
+ ExFreePool(id_ptr);
+ }
//
// Configure the default queue to be Parallel. Do not use sequential queue
@@ -561,7 +594,7 @@ Routine Description:
//
// Connect a mouse class device driver to the port driver.
//
- case IOCTL_INTERNAL_MOUSE_CONNECT:
+ case IOCTL_INTERNAL_MOUSE_CONNECT: {
//
// Only allow one connection.
//
@@ -569,19 +602,19 @@ Routine Description:
status = STATUS_SHARING_VIOLATION;
break;
}
-
+
//
// Copy the connection parameters to the device extension.
//
- status = WdfRequestRetrieveInputBuffer(Request,
- sizeof(CONNECT_DATA),
- reinterpret_cast<PVOID*>(&connectData),
- &length);
- if(!NT_SUCCESS(status)){
+ status = WdfRequestRetrieveInputBuffer(Request,
+ sizeof(CONNECT_DATA),
+ reinterpret_cast<PVOID*>(&connectData),
+ &length);
+ if (!NT_SUCCESS(status)) {
DebugPrint(("WdfRequestRetrieveInputBuffer failed %x\n", status));
break;
}
-
+
devExt->counter = 0;
devExt->carry = {};
devExt->UpperConnectData = *connectData;
@@ -595,7 +628,7 @@ Routine Description:
connectData->ClassService = RawaccelCallback;
break;
-
+ }
//
// Disconnect a mouse class device driver from the port driver.
//
diff --git a/driver/driver.h b/driver/driver.h
index 8554f8c..a0381fb 100644
--- a/driver/driver.h
+++ b/driver/driver.h
@@ -4,7 +4,7 @@
#include <kbdmou.h>
#include <wdf.h>
-#include "vec2.h"
+#include "rawaccel-settings.h"
#if DBG
#define DebugPrint(_x_) DbgPrint _x_
@@ -21,6 +21,7 @@ typedef struct _DEVICE_EXTENSION {
counter_t counter;
vec2d carry;
CONNECT_DATA UpperConnectData;
+ WCHAR dev_id[MAX_DEV_ID_LEN];
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_EXTENSION, FilterGetData)
diff --git a/grapher/Form1.Designer.cs b/grapher/Form1.Designer.cs
index d5dc37f..13aefb7 100644
--- a/grapher/Form1.Designer.cs
+++ b/grapher/Form1.Designer.cs
@@ -180,6 +180,7 @@ namespace grapher
this.gainOffsetToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.legacyOffsetToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.AutoWriteMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.UseSpecificDeviceMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.chartsPanel = new System.Windows.Forms.Panel();
this.GainChartY = new System.Windows.Forms.DataVisualization.Charting.Chart();
this.VelocityChartY = new System.Windows.Forms.DataVisualization.Charting.Chart();
@@ -281,7 +282,6 @@ namespace grapher
this.optionsPanel.Name = "optionsPanel";
this.optionsPanel.Size = new System.Drawing.Size(483, 956);
this.optionsPanel.TabIndex = 34;
- this.optionsPanel.Paint += new System.Windows.Forms.PaintEventHandler(this.optionsPanel_Paint);
//
// FakeBox
//
@@ -1178,7 +1178,8 @@ namespace grapher
this.advancedToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.capStyleToolStripMenuItem,
this.offsetStyleToolStripMenuItem,
- this.AutoWriteMenuItem});
+ this.AutoWriteMenuItem,
+ this.UseSpecificDeviceMenuItem});
this.advancedToolStripMenuItem.Name = "advancedToolStripMenuItem";
this.advancedToolStripMenuItem.Size = new System.Drawing.Size(72, 20);
this.advancedToolStripMenuItem.Text = "Advanced";
@@ -1236,6 +1237,21 @@ namespace grapher
this.AutoWriteMenuItem.Size = new System.Drawing.Size(210, 22);
this.AutoWriteMenuItem.Text = "Apply Settings On Startup";
//
+ // AutoWriteMenuItem
+ //
+ this.AutoWriteMenuItem.Checked = true;
+ this.AutoWriteMenuItem.CheckOnClick = true;
+ this.AutoWriteMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.AutoWriteMenuItem.Name = "AutoWriteMenuItem";
+ this.AutoWriteMenuItem.Size = new System.Drawing.Size(210, 22);
+ this.AutoWriteMenuItem.Text = "Apply Settings On Startup";
+ //
+ // UseSpecificDeviceMenuItem
+ //
+ this.UseSpecificDeviceMenuItem.Name = "UseSpecificDeviceMenuItem";
+ this.UseSpecificDeviceMenuItem.Size = new System.Drawing.Size(210, 22);
+ this.UseSpecificDeviceMenuItem.Text = "Use Specific Device";
+ //
// chartsPanel
//
this.chartsPanel.AutoScroll = true;
@@ -1498,8 +1514,6 @@ namespace grapher
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "RawAcceleration";
this.Text = "Raw Accel";
- this.Load += new System.EventHandler(this.Form1_Load);
- this.Paint += new System.Windows.Forms.PaintEventHandler(this.RawAcceleration_Paint);
this.optionsPanel.ResumeLayout(false);
this.optionsPanel.PerformLayout();
this.DirectionalityPanel.ResumeLayout(false);
@@ -1636,6 +1650,7 @@ namespace grapher
private System.Windows.Forms.Label LpNormActiveValue;
private System.Windows.Forms.Label RangeActiveValueY;
private System.Windows.Forms.CheckBox FakeBox;
+ private System.Windows.Forms.ToolStripMenuItem UseSpecificDeviceMenuItem;
}
}
diff --git a/grapher/Form1.cs b/grapher/Form1.cs
index 06f76f1..71a5e01 100644
--- a/grapher/Form1.cs
+++ b/grapher/Form1.cs
@@ -69,6 +69,7 @@ namespace grapher
gainOffsetToolStripMenuItem,
legacyOffsetToolStripMenuItem,
AutoWriteMenuItem,
+ UseSpecificDeviceMenuItem,
ScaleMenuItem,
DPITextBox,
PollRateTextBox,
@@ -173,19 +174,18 @@ namespace grapher
protected override void WndProc(ref Message m)
{
- if (m.Msg == 0x00ff)
+ if (m.Msg == 0x00ff) // WM_INPUT
{
AccelGUI.MouseWatcher.ReadMouseMove(m);
}
+ else if (m.Msg == 0x00fe) // WM_INPUT_DEVICE_CHANGE
+ {
+ AccelGUI.UpdateInputManagers();
+ }
base.WndProc(ref m);
}
- private void Form1_Load(object sender, EventArgs e)
- {
-
- }
-
public void ResetAutoScroll()
{
chartsPanel.AutoScrollPosition = Constants.Origin;
@@ -205,16 +205,6 @@ namespace grapher
};
}
- private void RawAcceleration_Paint(object sender, PaintEventArgs e)
- {
- //AccelGUI.AccelCharts.DrawLastMovement();
- }
-
#endregion Method
-
- private void optionsPanel_Paint(object sender, PaintEventArgs e)
- {
-
- }
}
}
diff --git a/grapher/MessageDialog.Designer.cs b/grapher/MessageDialog.Designer.cs
new file mode 100644
index 0000000..f7fa8d6
--- /dev/null
+++ b/grapher/MessageDialog.Designer.cs
@@ -0,0 +1,98 @@
+
+namespace grapher
+{
+ partial class MessageDialog
+ {
+ /// <summary>
+ /// Required designer variable.
+ /// </summary>
+ private System.ComponentModel.IContainer components = null;
+
+ /// <summary>
+ /// Clean up any resources being used.
+ /// </summary>
+ /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ /// <summary>
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ /// </summary>
+ private void InitializeComponent()
+ {
+ this.tableLayoutPanel = new System.Windows.Forms.TableLayoutPanel();
+ this.okButton = new System.Windows.Forms.Button();
+ this.messageLabel = new System.Windows.Forms.Label();
+ this.tableLayoutPanel.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // tableLayoutPanel
+ //
+ this.tableLayoutPanel.AutoSize = true;
+ this.tableLayoutPanel.ColumnCount = 1;
+ this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
+ this.tableLayoutPanel.Controls.Add(this.okButton, 0, 1);
+ this.tableLayoutPanel.Controls.Add(this.messageLabel, 0, 0);
+ this.tableLayoutPanel.ForeColor = System.Drawing.SystemColors.ControlText;
+ this.tableLayoutPanel.Location = new System.Drawing.Point(0, 0);
+ this.tableLayoutPanel.Name = "tableLayoutPanel";
+ this.tableLayoutPanel.Padding = new System.Windows.Forms.Padding(5);
+ this.tableLayoutPanel.RowCount = 2;
+ this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
+ this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 35F));
+ this.tableLayoutPanel.Size = new System.Drawing.Size(224, 61);
+ this.tableLayoutPanel.TabIndex = 2;
+ //
+ // okButton
+ //
+ this.okButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
+ this.okButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+ this.okButton.Location = new System.Drawing.Point(74, 30);
+ this.okButton.Name = "okButton";
+ this.okButton.Size = new System.Drawing.Size(75, 23);
+ this.okButton.TabIndex = 4;
+ this.okButton.Text = "&OK";
+ this.okButton.UseVisualStyleBackColor = true;
+ //
+ // messageLabel
+ //
+ this.messageLabel.AutoSize = true;
+ this.messageLabel.Location = new System.Drawing.Point(8, 5);
+ this.messageLabel.Name = "messageLabel";
+ this.messageLabel.Size = new System.Drawing.Size(35, 13);
+ this.messageLabel.TabIndex = 3;
+ this.messageLabel.Text = "label1";
+ //
+ // MessageDialog
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.AutoSize = true;
+ this.CancelButton = this.okButton;
+ this.ClientSize = new System.Drawing.Size(224, 61);
+ this.Controls.Add(this.tableLayoutPanel);
+ this.Name = "MessageDialog";
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+ this.tableLayoutPanel.ResumeLayout(false);
+ this.tableLayoutPanel.PerformLayout();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.TableLayoutPanel tableLayoutPanel;
+ private System.Windows.Forms.Button okButton;
+ private System.Windows.Forms.Label messageLabel;
+ }
+} \ No newline at end of file
diff --git a/grapher/MessageDialog.cs b/grapher/MessageDialog.cs
new file mode 100644
index 0000000..0e153f8
--- /dev/null
+++ b/grapher/MessageDialog.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace grapher
+{
+ public partial class MessageDialog : Form
+ {
+ public MessageDialog(string message, string title = "")
+ {
+ InitializeComponent();
+ Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
+ Text = title;
+ messageLabel.Text = message;
+ }
+
+ }
+}
diff --git a/grapher/Models/AccelGUI.cs b/grapher/Models/AccelGUI.cs
index e125310..5f05798 100644
--- a/grapher/Models/AccelGUI.cs
+++ b/grapher/Models/AccelGUI.cs
@@ -1,4 +1,5 @@
using grapher.Models.Calculations;
+using grapher.Models.Devices;
using grapher.Models.Mouse;
using grapher.Models.Options;
using grapher.Models.Serialized;
@@ -23,7 +24,8 @@ namespace grapher
Button writeButton,
ButtonBase toggleButton,
MouseWatcher mouseWatcher,
- ToolStripMenuItem scaleMenuItem)
+ ToolStripMenuItem scaleMenuItem,
+ DeviceIDManager deviceIDManager)
{
AccelForm = accelForm;
AccelCalculator = accelCalculator;
@@ -36,6 +38,7 @@ namespace grapher
DefaultButtonFont = WriteButton.Font;
SmallButtonFont = new Font(WriteButton.Font.Name, WriteButton.Font.Size * Constants.SmallButtonSizeFactor);
MouseWatcher = mouseWatcher;
+ DeviceIDManager = deviceIDManager;
ScaleMenuItem.Click += new System.EventHandler(OnScaleMenuItemClick);
WriteButton.Click += new System.EventHandler(OnWriteButtonClick);
@@ -95,6 +98,10 @@ namespace grapher
public ToolStripMenuItem ScaleMenuItem { get; }
+ public DeviceIDManager DeviceIDManager { get; }
+
+ public Action UpdateInputManagers { get; private set; }
+
private Timer ChartRefresh { get; }
private Font SmallButtonFont { get; }
@@ -144,6 +151,7 @@ namespace grapher
directionalMultipliers = driverSettings.directionalMultipliers,
domainArgs = ApplyOptions.Directionality.GetDomainArgs(),
rangeXY = ApplyOptions.Directionality.GetRangeXY(),
+ deviceID = DeviceIDManager.ID,
};
ButtonDelay(WriteButton);
@@ -156,7 +164,7 @@ namespace grapher
}
else
{
- throw new Exception($"Bad arguments:\n\n{errors}");
+ new MessageDialog(errors.ToString(), "bad input").ShowDialog();
}
}
@@ -164,6 +172,14 @@ namespace grapher
{
UpdateShownActiveValues(args);
UpdateGraph(args);
+
+ UpdateInputManagers = () =>
+ {
+ MouseWatcher.UpdateHandles(args.deviceID);
+ DeviceIDManager.Update(args.deviceID);
+ };
+
+ UpdateInputManagers();
}
public void UpdateGraph(DriverSettings args)
diff --git a/grapher/Models/AccelGUIFactory.cs b/grapher/Models/AccelGUIFactory.cs
index 802ce4b..9ca1578 100644
--- a/grapher/Models/AccelGUIFactory.cs
+++ b/grapher/Models/AccelGUIFactory.cs
@@ -1,4 +1,5 @@
using grapher.Models.Calculations;
+using grapher.Models.Devices;
using grapher.Models.Mouse;
using grapher.Models.Options;
using grapher.Models.Options.Directionality;
@@ -33,6 +34,7 @@ namespace grapher.Models
ToolStripMenuItem gainOffsetToolStripMenuItem,
ToolStripMenuItem legacyOffsetToolStripMenuItem,
ToolStripMenuItem autoWriteMenuItem,
+ ToolStripMenuItem useSpecificDeviceMenuItem,
ToolStripMenuItem scaleMenuItem,
ToolStripTextBox dpiTextBox,
ToolStripTextBox pollRateTextBox,
@@ -391,16 +393,20 @@ namespace grapher.Models
lockXYLabel,
accelCharts);
+ var deviceIdManager = new DeviceIDManager(useSpecificDeviceMenuItem);
+
var settings = new SettingsManager(
activeAccel,
accelCalculator.DPI,
accelCalculator.PollRate,
autoWriteMenuItem,
showLastMouseMoveMenuItem,
- showVelocityGainToolStripMenuItem);
+ showVelocityGainToolStripMenuItem,
+ deviceIdManager);
var mouseWatcher = new MouseWatcher(form, mouseLabel, accelCharts, settings);
+
return new AccelGUI(
form,
accelCalculator,
@@ -410,7 +416,8 @@ namespace grapher.Models
writeButton,
toggleButton,
mouseWatcher,
- scaleMenuItem);
+ scaleMenuItem,
+ deviceIdManager);
}
#endregion Methods
diff --git a/grapher/Models/Devices/DeviceIDItem.cs b/grapher/Models/Devices/DeviceIDItem.cs
new file mode 100644
index 0000000..63c2761
--- /dev/null
+++ b/grapher/Models/Devices/DeviceIDItem.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace grapher.Models.Devices
+{
+ public class DeviceIDItem
+ {
+ public DeviceIDItem(string name, string id, DeviceIDManager manager)
+ {
+ Name = name;
+ ID = id;
+ Manager = manager;
+ DeviceIDMenuItem = new ToolStripMenuItem();
+ DeviceIDMenuItem.Checked = false;
+ DeviceIDMenuItem.Text = MenuItemText();
+ DeviceIDMenuItem.Click += OnClicked;
+ manager.DeviceIDsMenuItem.DropDownItems.Add(DeviceIDMenuItem);
+ }
+
+ private ToolStripMenuItem DeviceIDMenuItem { get; }
+
+ public string Name { get; }
+
+ public string ID { get; }
+
+ private DeviceIDManager Manager { get; }
+
+ public void SetActivated()
+ {
+ DeviceIDMenuItem.Checked = true;
+ }
+
+ public void SetDeactivated()
+ {
+ DeviceIDMenuItem.Checked = false;
+ }
+
+ private string MenuItemText() => string.IsNullOrEmpty(ID) ? $"{Name}" : $"{Name}: {ID}";
+
+ private string DisconnectedText() => $"Disconnected: {ID}";
+
+ public void SetDisconnected()
+ {
+ DeviceIDMenuItem.ForeColor = Color.DarkGray;
+ DeviceIDMenuItem.Text = DisconnectedText();
+ }
+
+ public void OnClicked(object sender, EventArgs e)
+ {
+ Manager.SetActive(this);
+ }
+
+ public override bool Equals(object obj)
+ {
+ return obj is DeviceIDItem item &&
+ Name == item.Name &&
+ ID == item.ID;
+ }
+
+ public override int GetHashCode()
+ {
+ int hashCode = -1692744877;
+ hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Name);
+ hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(ID);
+ return hashCode;
+ }
+ }
+}
diff --git a/grapher/Models/Devices/DeviceIDManager.cs b/grapher/Models/Devices/DeviceIDManager.cs
new file mode 100644
index 0000000..c50cda8
--- /dev/null
+++ b/grapher/Models/Devices/DeviceIDManager.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Management;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace grapher.Models.Devices
+{
+ public class DeviceIDManager
+ {
+ public DeviceIDManager(ToolStripMenuItem deviceIDs)
+ {
+ DeviceIDsMenuItem = deviceIDs;
+ DeviceIDsMenuItem.Checked = false;
+ }
+
+ public ToolStripMenuItem DeviceIDsMenuItem { get; }
+
+ public string ID { get => SelectedDeviceID.ID; }
+
+ public DeviceIDItem SelectedDeviceID { get; private set; }
+
+ public Dictionary<string, DeviceIDItem> DeviceIDs { get; private set; }
+
+ public static IEnumerable<(string, string)> GetDeviceIDs(string PNPClass = "Mouse")
+ {
+ ManagementObjectSearcher searcher = new ManagementObjectSearcher(new SelectQuery("Win32_PnPEntity"));
+
+ foreach (ManagementObject obj in searcher.Get())
+ {
+ if (obj["PNPClass"] != null && obj["PNPClass"].ToString().Equals(PNPClass) && obj["DeviceID"] != null)
+ {
+ string name = obj["Name"].ToString();
+
+ string devInstanceID = obj["DeviceID"].ToString();
+ string devID = devInstanceID.Remove(devInstanceID.LastIndexOf('\\'));
+
+ yield return (name, devID);
+ }
+ }
+ }
+
+ public void SetActive(DeviceIDItem deviceIDItem)
+ {
+ if (SelectedDeviceID != null)
+ {
+ SelectedDeviceID.SetDeactivated();
+ }
+
+ SelectedDeviceID = deviceIDItem;
+ SelectedDeviceID.SetActivated();
+ }
+
+ public void Update(string devID)
+ {
+ DeviceIDsMenuItem.DropDownItems.Clear();
+
+ bool found = string.IsNullOrEmpty(devID);
+
+ var anyDevice = new DeviceIDItem("Any", string.Empty, this);
+
+ if (found) SetActive(anyDevice);
+
+ foreach (var device in GetDeviceIDs().Distinct())
+ {
+ var deviceItem = new DeviceIDItem(device.Item1, device.Item2, this);
+ if (!found && deviceItem.ID.Equals(devID))
+ {
+ SetActive(deviceItem);
+ found = true;
+ }
+ }
+
+ if (!found)
+ {
+ var deviceItem = new DeviceIDItem(string.Empty, devID, this);
+ deviceItem.SetDisconnected();
+ SetActive(deviceItem);
+ }
+ }
+
+ }
+}
diff --git a/grapher/Models/Mouse/MouseData.cs b/grapher/Models/Mouse/MouseData.cs
index e59a969..5944fe4 100644
--- a/grapher/Models/Mouse/MouseData.cs
+++ b/grapher/Models/Mouse/MouseData.cs
@@ -8,7 +8,6 @@ namespace grapher.Models.Mouse
public MouseData()
{
- Lock = new Object();
X = 0;
Y = 0;
}
@@ -17,18 +16,13 @@ namespace grapher.Models.Mouse
#region Properties
- public Object Lock { get; }
-
private int X { get; set; }
private int Y { get; set; }
public void Set(int x, int y)
{
- lock (Lock)
- {
- X = x;
- Y = y;
- }
+ X = x;
+ Y = y;
}
#endregion Properties
@@ -37,11 +31,8 @@ namespace grapher.Models.Mouse
public void Get(out int x, out int y)
{
- lock (Lock)
- {
- x = X;
- y = Y;
- }
+ x = X;
+ y = Y;
}
#endregion Methods
diff --git a/grapher/Models/Mouse/MouseWatcher.cs b/grapher/Models/Mouse/MouseWatcher.cs
index 3cc8bd0..163829f 100644
--- a/grapher/Models/Mouse/MouseWatcher.cs
+++ b/grapher/Models/Mouse/MouseWatcher.cs
@@ -1,5 +1,6 @@
using grapher.Models.Serialized;
using System;
+using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
@@ -398,7 +399,11 @@ namespace grapher.Models.Mouse
/// <summary>If set, the application-defined keyboard device hotkeys are not handled. However, the system hotkeys; for example, ALT+TAB and CTRL+ALT+DEL, are still handled. By default, all keyboard hotkeys are handled. NoHotKeys can be specified even if NoLegacy is not specified and WindowHandle is NULL.</summary>
NoHotKeys = 0x00000200,
/// <summary>If set, application keys are handled. NoLegacy must be specified. Keyboard only.</summary>
- AppKeys = 0x00000400
+ AppKeys = 0x00000400,
+ /// <summary>If set, this enables the caller to receive input in the background only if the foreground application does not process it. In other words, if the foreground application is not registered for raw input, then the background application that is registered will receive the input.</summary>
+ ExInputSink = 0x00001000,
+ /// <summary>If set, this enables the caller to receive WM_INPUT_DEVICE_CHANGE notifications for device arrival and device removal.</summary>
+ DevNotify = 0x00002000
}
/// <summary>Value type for raw input devices.</summary>
@@ -686,12 +691,13 @@ namespace grapher.Models.Mouse
AccelCharts = accelCharts;
SettingsManager = setMngr;
MouseData = new MouseData();
+ DeviceHandles = new List<IntPtr>();
RAWINPUTDEVICE device = new RAWINPUTDEVICE();
device.WindowHandle = ContainingForm.Handle;
device.UsagePage = HIDUsagePage.Generic;
device.Usage = HIDUsage.Mouse;
- device.Flags = RawInputDeviceFlags.InputSink;
+ device.Flags = RawInputDeviceFlags.InputSink | RawInputDeviceFlags.DevNotify;
RAWINPUTDEVICE[] devices = new RAWINPUTDEVICE[1];
devices[0] = device;
@@ -716,6 +722,10 @@ namespace grapher.Models.Mouse
private Stopwatch Stopwatch { get; }
+ private List<IntPtr> DeviceHandles { get; }
+
+ private bool AnyDevice { get; set; }
+
private double PollTime
{
get => 1000 / SettingsManager.PollRateField.Data;
@@ -725,6 +735,16 @@ namespace grapher.Models.Mouse
#region Methods
+ public void UpdateHandles(string devID)
+ {
+ DeviceHandles.Clear();
+ AnyDevice = string.IsNullOrEmpty(devID);
+ if (!AnyDevice)
+ {
+ RawInputInterop.AddHandlesFromID(devID, DeviceHandles);
+ }
+ }
+
public void UpdateLastMove()
{
MouseData.Get(out var x, out var y);
@@ -733,15 +753,14 @@ namespace grapher.Models.Mouse
public void ReadMouseMove(Message message)
{
- RawInput rawInput = new RawInput();
- int outSize = 0;
+ RawInput rawInput;
int size = Marshal.SizeOf(typeof(RawInput));
-
- outSize = GetRawInputData((IntPtr)message.LParam, RawInputCommand.Input, out rawInput, ref size, Marshal.SizeOf(typeof(RAWINPUTHEADER)));
+ _ = GetRawInputData(message.LParam, RawInputCommand.Input, out rawInput, ref size, Marshal.SizeOf(typeof(RAWINPUTHEADER)));
bool relative = !rawInput.Data.Mouse.Flags.HasFlag(RawMouseFlags.MoveAbsolute);
+ bool deviceMatch = AnyDevice || DeviceHandles.Contains(rawInput.Header.Device);
- if (relative && (rawInput.Data.Mouse.LastX != 0 || rawInput.Data.Mouse.LastY != 0))
+ if (relative && deviceMatch && (rawInput.Data.Mouse.LastX != 0 || rawInput.Data.Mouse.LastY != 0))
{
var time = Stopwatch.Elapsed.TotalMilliseconds;
Stopwatch.Restart();
diff --git a/grapher/Models/Mouse/PointData.cs b/grapher/Models/Mouse/PointData.cs
index e3f44ea..87bfc62 100644
--- a/grapher/Models/Mouse/PointData.cs
+++ b/grapher/Models/Mouse/PointData.cs
@@ -8,7 +8,6 @@ namespace grapher.Models.Mouse
public PointData()
{
- Lock = new Object();
X = new double[] { 0.01 };
Y = new double[] { 0.01 };
}
@@ -17,18 +16,13 @@ namespace grapher.Models.Mouse
#region Properties
- public Object Lock { get; }
-
private double[] X { get; set; }
private double[] Y { get; set; }
public void Set(double x, double y)
{
- lock(Lock)
- {
- X[0] = x;
- Y[0] = y;
- }
+ X[0] = x;
+ Y[0] = y;
}
#endregion Properties
@@ -37,11 +31,8 @@ namespace grapher.Models.Mouse
public void Get(out double[] x, out double[] y)
{
- lock(Lock)
- {
x = X;
y = Y;
- }
}
#endregion Methods
diff --git a/grapher/Models/Serialized/RawAccelSettings.cs b/grapher/Models/Serialized/RawAccelSettings.cs
index dcaf864..f4fb1e2 100644
--- a/grapher/Models/Serialized/RawAccelSettings.cs
+++ b/grapher/Models/Serialized/RawAccelSettings.cs
@@ -125,7 +125,8 @@ namespace grapher.Models.Serialized
bool wholeOrNoY = accelSettings.combineMagnitudes ||
accelSettings.modes.y == AccelMode.noaccel;
- return accelSettings.sensitivity.x == 1 &&
+ return string.IsNullOrEmpty(accelSettings.deviceID) &&
+ accelSettings.sensitivity.x == 1 &&
accelSettings.sensitivity.y == 1 &&
accelSettings.directionalMultipliers.x <= 0 &&
accelSettings.directionalMultipliers.y <= 0 &&
diff --git a/grapher/Models/Serialized/SettingsManager.cs b/grapher/Models/Serialized/SettingsManager.cs
index 41ebcb5..40652dd 100644
--- a/grapher/Models/Serialized/SettingsManager.cs
+++ b/grapher/Models/Serialized/SettingsManager.cs
@@ -3,6 +3,8 @@ using System;
using System.Windows.Forms;
using System.Threading;
using System.Text;
+using System.Drawing;
+using grapher.Models.Devices;
namespace grapher.Models.Serialized
{
@@ -16,7 +18,8 @@ namespace grapher.Models.Serialized
Field pollRateField,
ToolStripMenuItem autoWrite,
ToolStripMenuItem showLastMouseMove,
- ToolStripMenuItem showVelocityAndGain)
+ ToolStripMenuItem showVelocityAndGain,
+ DeviceIDManager deviceIDManager)
{
ActiveAccel = activeAccel;
DpiField = dpiField;
@@ -24,6 +27,7 @@ namespace grapher.Models.Serialized
AutoWriteMenuItem = autoWrite;
ShowLastMouseMoveMenuItem = showLastMouseMove;
ShowVelocityAndGainMoveMenuItem = showVelocityAndGain;
+ DeviceIDManager = deviceIDManager;
}
#endregion Constructors
@@ -38,6 +42,8 @@ namespace grapher.Models.Serialized
public Field PollRateField { get; private set; }
+ public DeviceIDManager DeviceIDManager { get; }
+
private ToolStripMenuItem AutoWriteMenuItem { get; set; }
private ToolStripMenuItem ShowLastMouseMoveMenuItem { get; set; }
diff --git a/grapher/grapher.csproj b/grapher/grapher.csproj
index 88e7752..8673325 100644
--- a/grapher/grapher.csproj
+++ b/grapher/grapher.csproj
@@ -59,6 +59,7 @@
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
+ <Reference Include="System.Management" />
<Reference Include="System.Windows.Forms.DataVisualization" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
@@ -80,6 +81,12 @@
<Compile Include="Constants\Constants.cs" />
<Compile Include="Layouts\MotivityLayout.cs" />
<Compile Include="Layouts\NaturalGainLayout.cs" />
+ <Compile Include="MessageDialog.cs">
+ <SubType>Form</SubType>
+ </Compile>
+ <Compile Include="MessageDialog.Designer.cs">
+ <DependentUpon>MessageDialog.cs</DependentUpon>
+ </Compile>
<Compile Include="Models\AccelGUIFactory.cs" />
<Compile Include="Models\Calculations\AccelCalculator.cs" />
<Compile Include="Models\Calculations\AccelChartData.cs" />
@@ -95,6 +102,8 @@
<Compile Include="Models\Charts\EstimatedPoints.cs" />
<Compile Include="Models\Charts\ChartState\XYOneGraphState.cs" />
<Compile Include="Models\Charts\ChartState\XYTwoGraphState.cs" />
+ <Compile Include="Models\Devices\DeviceIDItem.cs" />
+ <Compile Include="Models\Devices\DeviceIDManager.cs" />
<Compile Include="Models\Mouse\MouseData.cs" />
<Compile Include="Models\Mouse\MouseWatcher.cs" />
<Compile Include="Models\Mouse\PointData.cs" />
@@ -134,6 +143,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="AboutBox.resx">
<DependentUpon>AboutBox.cs</DependentUpon>
+ <SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Form1.resx">
<DependentUpon>Form1.cs</DependentUpon>
diff --git a/installer/installer.cpp b/installer/installer.cpp
index 916209f..279fefc 100644
--- a/installer/installer.cpp
+++ b/installer/installer.cpp
@@ -53,6 +53,10 @@ int main() {
fs::path target = get_target_path();
+ if (fs::exists(target)) {
+ std::cout << "Driver already installed. Removing previous installation.\n";
+ }
+
add_service(target);
fs::path tmp = make_temp_path(target);
diff --git a/signed/driver/rawaccel.sys b/signed/driver/rawaccel.sys
index 3762899..0fef07f 100644
--- a/signed/driver/rawaccel.sys
+++ b/signed/driver/rawaccel.sys
Binary files differ
diff --git a/uninstaller/uninstaller.cpp b/uninstaller/uninstaller.cpp
index 8d9e890..bd9c564 100644
--- a/uninstaller/uninstaller.cpp
+++ b/uninstaller/uninstaller.cpp
@@ -4,13 +4,23 @@
int main() {
try {
- modify_upper_filters([](std::vector<std::wstring>& filters) {
- std::erase(filters, DRIVER_NAME);
+ bool reboot_required = false;
+ modify_upper_filters([&reboot_required](std::vector<std::wstring>& filters) {
+ // check if driver is present in upper filters
+ bool driver_present = std::find(filters.begin(), filters.end(), DRIVER_NAME) != filters.end();
+ if (driver_present) {
+ std::erase(filters, DRIVER_NAME);
+ reboot_required = true;
+ }
});
fs::path target = get_target_path();
fs::path tmp = make_temp_path(target);
+ if (fs::exists(target) || fs::exists(tmp)) {
+ reboot_required = true;
+ }
+
// schedule tmp to be deleted if rename target -> tmp is successful
if (MoveFileExW(target.c_str(), tmp.c_str(), MOVEFILE_REPLACE_EXISTING)) {
MoveFileExW(tmp.c_str(), NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
@@ -18,7 +28,14 @@ int main() {
else { // tmp is in use and delete is already scheduled
if (fs::exists(target)) fs::remove(target);
}
- std::cout << "Removal complete, change will take effect after restart.\n";
+
+ if (reboot_required) {
+ std::cout << "Removal complete, change will take effect after restart.\n";
+ }
+ else {
+ std::cout << "No installed driver found.\n";
+ }
+
}
catch (const std::system_error& e) {
std::cerr << "Error: " << e.what() << ' ' << e.code() << '\n';
diff --git a/wrapper/wrapper.cpp b/wrapper/wrapper.cpp
index fdde5a4..7fd0a92 100644
--- a/wrapper/wrapper.cpp
+++ b/wrapper/wrapper.cpp
@@ -1,13 +1,16 @@
#pragma once
#include <type_traits>
+#include <msclr\marshal_cppstd.h>
#include <rawaccel.hpp>
#include <rawaccel-version.h>
+#include <utility-rawinput.hpp>
#include "wrapper_io.hpp"
using namespace System;
+using namespace System::Collections::Generic;
using namespace System::Runtime::InteropServices;
using namespace System::Reflection;
@@ -59,7 +62,7 @@ public value struct DomainArgs
};
[JsonObject(ItemRequired = Required::Always)]
-[StructLayout(LayoutKind::Sequential)]
+[StructLayout(LayoutKind::Sequential, CharSet = CharSet::Unicode)]
public ref struct DriverSettings
{
literal String^ Key = "Driver settings";
@@ -92,6 +95,10 @@ public ref struct DriverSettings
[JsonProperty(Required = Required::Default)]
double minimumTime;
+ [JsonProperty("Device ID", Required = Required::Default)]
+ [MarshalAs(UnmanagedType::ByValTStr, SizeConst = MAX_DEV_ID_LEN)]
+ String^ deviceID = "";
+
bool ShouldSerializeminimumTime()
{
return minimumTime > 0 && minimumTime != DEFAULT_TIME_MIN;
@@ -231,6 +238,24 @@ public:
}
};
+public ref struct RawInputInterop
+{
+ static void AddHandlesFromID(String^ deviceID, List<IntPtr>^ rawInputHandles)
+ {
+ try
+ {
+ std::vector<HANDLE> nativeHandles = rawinput_handles_from_dev_id(
+ msclr::interop::marshal_as<std::wstring>(deviceID));
+
+ for (auto nh : nativeHandles) rawInputHandles->Add(IntPtr(nh));
+ }
+ catch (const std::exception& e)
+ {
+ throw gcnew System::Exception(gcnew String(e.what()));
+ }
+ }
+};
+
public ref struct DriverInterop
{
literal double WriteDelayMs = WRITE_DELAY;
diff --git a/wrapper/wrapper.vcxproj b/wrapper/wrapper.vcxproj
index 4f8ed1c..721a981 100644
--- a/wrapper/wrapper.vcxproj
+++ b/wrapper/wrapper.vcxproj
@@ -59,7 +59,7 @@
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
- <AdditionalDependencies />
+ <AdditionalDependencies>User32.lib;</AdditionalDependencies>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>$(SolutionDir)/common;</AdditionalIncludeDirectories>
@@ -72,7 +72,7 @@
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
- <AdditionalDependencies />
+ <AdditionalDependencies>User32.lib;</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>copy /Y "$(TargetPath)" "$(SolutionDir)signed\$(TargetFileName)" &amp;