Last active
January 4, 2025 19:21
-
-
Save yinonburgansky/7be4d0489a0df8c06a923240b8eb0191 to your computer and use it in GitHub Desktop.
windows acceleration function
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# calculation are based on http://www.esreality.com/index.php?a=post&id=1945096 | |
# assuming windows 10 uses the same calculation as windows 7. | |
# guesses have been made calculation is not accurate | |
# touchpad users make sure your touchpad is calibrated with `sudo libinput measure touchpad-size` | |
# import matplotlib.pyplot as plt | |
import struct | |
# set according to your device: | |
xinput_device_id = 13 | |
device_dpi = 1000 # mouse dpi | |
screen_dpi = 157 | |
screen_scaling_factor = 1 | |
sample_point_count = 21 # should be enough but you can try to increase for accuracy of windows function | |
sensitivity_factor = 1.0 | |
# sensitivity factor translation table: (windows slider notches) | |
# 1 = 0.1 | |
# 2 = 0.2 | |
# 3 = 0.4 | |
# 4 = 0.6 | |
# 5 = 0.8 | |
# 6 = 1.0 default | |
# 7 = 1.2 | |
# 8 = 1.4 | |
# 9 = 1.6 | |
# 10 = 1.8 | |
# 11 = 2.0 | |
# TODO: find accurate formulas for scale x and scale y | |
# mouse speed: inch/s to device-units/millisecond | |
scale_x = device_dpi / 1e3 | |
# pointer speed: inch/s to screen pixels/millisecond | |
scale_y = screen_dpi / 1e3 / screen_scaling_factor * sensitivity_factor | |
print(f'scale_x={scale_x}, scale_y={scale_y}') | |
def float16x16(num): | |
return struct.unpack('<i', num[:-4])[0] / int(0xffff) | |
# windows 10 registry values: | |
# HKEY_CURRENT_USER\Control Panel\Mouse\SmoothMouseXCurve | |
X = [ | |
b'\x00\x00\x00\x00\x00\x00\x00\x00', | |
b'\x15\x6e\x00\x00\x00\x00\x00\x00', | |
b'\x00\x40\x01\x00\x00\x00\x00\x00', | |
b'\x29\xdc\x03\x00\x00\x00\x00\x00', | |
b'\x00\x00\x28\x00\x00\x00\x00\x00', | |
] | |
# HKEY_CURRENT_USER\Control Panel\Mouse\SmoothMouseYCurve | |
Y=[ | |
b'\x00\x00\x00\x00\x00\x00\x00\x00', | |
b'\xfd\x11\x01\x00\x00\x00\x00\x00', | |
b'\x00\x24\x04\x00\x00\x00\x00\x00', | |
b'\x00\xfc\x12\x00\x00\x00\x00\x00', | |
b'\x00\xc0\xbb\x01\x00\x00\x00\x00', | |
] | |
windows_points = [[float16x16(x), float16x16(y)] for x,y in zip(X,Y)] | |
print('Windows original points:') | |
for point in windows_points: | |
print(point) | |
# scale windows points according to device config | |
points = [[x * scale_x, y * scale_y] for x, y in windows_points] | |
print('Windows scaled points') | |
for point in points: | |
print(point) | |
# plt.plot(*list(zip(*windows_points)), label=f'windows points') | |
# plt.plot(*list(zip(*points)), label=f'scaled points') | |
# plt.xlabel('device-speed') | |
# plt.ylabel('pointer-speed') | |
# plt.legend(loc='best') | |
# plt.show() | |
# exit() | |
def find2points(x): | |
i = 0 | |
while i < len(points) - 2 and x >= points[i+1][0]: | |
i +=1 | |
assert -1e6 + points[i][0] <= x <= points[i+1][0]+1e6, f'{points[i][0]} <= {x} <= {points[i+1][0]}' | |
return points[i], points[i+1] | |
def interpolate(x): | |
(x0, y0), (x1, y1) = find2points(x) | |
y = ((x-x0)*y1+(x1-x)*y0)/(x1-x0) | |
return y | |
def sample_points(count): | |
# use linear extrapolation for last point to get better accuracy for lower points | |
last_point = -2 | |
max_x = points[last_point][0] | |
step = max_x / (count + last_point) # we need another point for 0 | |
sample_points_x = [si * step for si in range(count)] | |
sample_points_y = [interpolate(x) for x in sample_points_x] | |
return sample_points_x, sample_points_y | |
sample_points_x, sample_points_y = sample_points(sample_point_count) | |
step = sample_points_x[1] - sample_points_x[0] | |
# plt.plot(sample_points_x, sample_points_y, label=f'windows {sample_point_count} points') | |
# plt.plot(*sample_points(1024), label=f'windows 1024 points') | |
# plt.xlabel('device-speed') | |
# plt.ylabel('pointer-speed') | |
# plt.legend(loc='best') | |
# plt.show() | |
# exit() | |
sample_points_str = ";".join(["%.3f" % number for number in sample_points_y]) | |
print(f"libinput custom-step: {step}") | |
print(f"libinput custom-points ({sample_point_count}):") | |
print("\t", sample_points_str) | |
print("libinput test:") | |
print("\t", f"sudo ./builddir/libinput-debug-gui --verbose --set-profile=custom --set-custom-points=\"{sample_points_str}\" --set-custom-step={step:0.10f} --set-custom-type=motion") | |
print('\nxinput set-props commands:') | |
print(f'\txinput set-prop {xinput_device_id} "libinput Accel Profile Enabled" 0, 0, 1') | |
print(f'\txinput set-prop {xinput_device_id} "libinput Accel Custom Motion Points" {sample_points_str.replace(";", ", ")}') | |
print(f'\txinput set-prop {xinput_device_id} "libinput Accel Custom Motion Step" {step:0.10f}') | |
print('\nxinput libinput.conf Options:') | |
print('\tOption "AccelProfile" "custom"') | |
print(f'\tOption "AccelPointsMotion" "{sample_points_str.replace(";", " ")}"') | |
print(f'\tOption "AccelStepMotion" "{step:0.10f}"') |
Is this replicating windows mouse sensitivity with or without enhanced pointer precision?
Is this replicating windows mouse sensitivity with or without enhanced pointer precision?
With enhanced pointer precision
Unfortunately I don't have the exact formula windows 10 uses, so it might feel a bit off compared to windows 10.
you can try to manually change scale_x
and scale_y
values until you get close enough to the desired result, e.g.
scale_x = 3.5
scale_y = 2.7
Thank you very much for the answer. I'll mess around with it.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Beautiful thank you