私は何年もの間、安いLogitechM215ワイヤレスマウスを持っていました。それでも完全に機能します。
私のラップトップ用に、同じパフォーマンスを期待して、Logitechのマウスを2つ追加購入しました。問題:垂直方向の感度は両方で厄介です。 x軸に沿った感度は素晴らしいですが、y軸に沿った感度は私がそれらを使用するのが嫌いなほど遅いです。 (この問題はデスクトップPCでも繰り返されます。)
私は知っています Windowsでポインタ速度を調整する方法 、しかし私は両方の軸をスケーリングするつもりはありません-y軸だけです。 どうやらUbuntuでこれを行う方法 があり、私は今尋ねているのと本質的に同じ質問をする多くのフォーラムを精査しましたが、役に立ちませんでした。この質問 ここでも尋ねられました 、しかしコメントは何の助けにもなりませんでした。
誰かがWindows8.1内でこれを行う方法を知っていますか?レジストリを変更したり、役立つソフトウェアをダウンロードしたりすることに慣れています。
私はM310を持っていて、同じ問題に取り組んできました。圧縮空気でレンズを掃除することで成功した人もいます。しかし、私にとっては、実際には私のマウスパッドでした...パッドを90度回転させて、効果があるかどうかを確認します。
これは完璧ではないオプションですが、役に立ちます。これは元々、ユーザーNextronによって https://autohotkey.com/board/topic/13531-adjusting-mouse-sensitivevity-via-hotkey/ で提供されていました。
このスクリプトは、WindowsでXとYの感度を個別に変更する余裕を与え、すべてのマウスとすべてのバージョンのWindowsで機能します。感度の整数倍を使用する必要があるという点で完全ではなく、マウスの動きのパルスを乗算することによって動作します。
new MouseAccelerator(0, 1)
と表示されている場合は、それをnew MouseAccelerator (<amount to multiply X sensitivity by> - 1, <amount to multiply Y sensitivity by> - 1)
に変更します。例えば。 MouseAccelerator(0, 1)
はYの動きを2倍にしますが、Xの動きには影響しません。MouseAccelerator(2, 1)
は水平方向の動きを3倍にし、垂直方向の動きを2倍にします。変更したスクリプトを実行します。ヒット F12 シャットダウンしたいとき。
;The SendInput DllCall is specifically 32-bit. So check for the correct bitness of AutoHotkey and if not, try to run the right one.
If (A_PtrSize=8){
SplitPath, A_AhkPath,,Dir
Run %Dir%\AutoHotkeyU32.exe %A_ScriptFullPath%
ExitApp
}
;Call below to accelerate the mouse input. The first two parameters are the integer factors of artificial amplification added on top of the physical input.
;The first is for horizontal/x-axis movement, the second for vertical/y-axis movement.
new MouseAccelerator(0, 1)
F12::ExitApp
; Gets called when mouse moves or stops
; x and y are DELTA moves (Amount moved since last message), NOT coordinates.
MouseAcceleratorEvent(x := 0, y := 0, accelerationx := 2, accelerationy := 2){
static MouseAcceleratorPaused
If !(MouseAcceleratorPaused){
MouseAcceleratorPaused:=true
VarSetCapacity( MouseInput, 28, 0 )
NumPut( x * accelerationx, MouseInput, 4, "Int" ) ; dx
NumPut( y * accelerationy, MouseInput, 8, "Int" ) ; dy
NumPut( 0x0001, MouseInput, 16, "UInt" ) ; MOUSEEVENTF_MOVE = 0x0001
DllCall("SendInput", "UInt", 1, "UInt", &MouseInput, "Int", 28 )
sleep,-1
MouseAcceleratorPaused:=false
}
}
; ================================== LIBRARY ========================================
; Instantiate this class and pass it a func name or a Function Object
; The specified function will be called with the delta move for the X and Y axes
; Normally, there is no windows message "mouse stopped", so one is simulated.
; After 10ms of no mouse movement, the callback is called with 0 for X and Y
; https://autohotkey.com/boards/viewtopic.php?f=19&t=10159
Class MouseAccelerator {
__New(accelerationx:=2, accelerationy:=2, callback:="MouseAcceleratorEvent"){
static DevSize := 8 + A_PtrSize
static RIDEV_INPUTSINK := 0x00000100
this.TimeoutFn := this.TimeoutFunc.Bind(this)
this.Callback := callback
this.Accelerationx := accelerationx
this.Accelerationy := accelerationy
; Register mouse for WM_INPUT messages.
VarSetCapacity(RAWINPUTDEVICE, DevSize)
NumPut(1, RAWINPUTDEVICE, 0, "UShort")
NumPut(2, RAWINPUTDEVICE, 2, "UShort")
NumPut(RIDEV_INPUTSINK, RAWINPUTDEVICE, 4, "Uint")
; WM_INPUT needs a hwnd to route to, so get the hwnd of the AHK Gui.
; It doesn't matter if the GUI is showing, it still exists
Gui +hwndhwnd
NumPut(hwnd, RAWINPUTDEVICE, 8, "Uint")
this.RAWINPUTDEVICE := RAWINPUTDEVICE
DllCall("RegisterRawInputDevices", "Ptr", &RAWINPUTDEVICE, "UInt", 1, "UInt", DevSize )
fn := this.MouseMoved.Bind(this)
OnMessage(0x00FF, fn)
}
__Delete(){
static RIDEV_REMOVE := 0x00000001
static DevSize := 8 + A_PtrSize
RAWINPUTDEVICE := this.RAWINPUTDEVICE
NumPut(RIDEV_REMOVE, RAWINPUTDEVICE, 4, "Uint")
DllCall("RegisterRawInputDevices", "Ptr", &RAWINPUTDEVICE, "UInt", 1, "UInt", DevSize )
}
; Called when the mouse moved.
; Messages tend to contain small (+/- 1) movements, and happen frequently (~20ms)
MouseMoved(wParam, lParam){
; RawInput statics
static DeviceSize := 2 * A_PtrSize, iSize := 0, sz := 0, offsets := {x: (20+A_PtrSize*2), y: (24+A_PtrSize*2)}, uRawInput
static axes := {x: 1, y: 2}
; Find size of rawinput data - only needs to be run the first time.
if (!iSize){
r := DllCall("GetRawInputData", "UInt", lParam, "UInt", 0x10000003, "Ptr", 0, "UInt*", iSize, "UInt", 8 + (A_PtrSize * 2))
VarSetCapacity(uRawInput, iSize)
}
sz := iSize ; param gets overwritten with # of bytes output, so preserve iSize
; Get RawInput data
r := DllCall("GetRawInputData", "UInt", lParam, "UInt", 0x10000003, "Ptr", &uRawInput, "UInt*", sz, "UInt", 8 + (A_PtrSize * 2))
x := NumGet(&uRawInput, offsets.x, "Int")
y := NumGet(&uRawInput, offsets.y, "Int")
this.Callback.(x, y, this.Accelerationx, this.Accelerationy)
; There is no message for "Stopped", so simulate one
fn := this.TimeoutFn
SetTimer, % fn, -10
}
TimeoutFunc(){
this.Callback.(0, 0)
}
}
これは、デバイスごとに感度を上げたり下げたりすることができるコードです(1つのマウスの感度を下げることはできますが、別のマウスには影響を与えません)。
ブロッキングにはRawInput(C#DLLで実装)とSetWindowsHookEx(純粋なAHKで実装))を使用します。
この方法が機能するようになったのはごく最近のことなので、問題や改善できることがあるかもしれません。私の取り組みを詳しく説明しているスレッド ここ がAHKフォーラムにあります-そこにはもっと最新のバージョンや機能豊富なバージョンがあるかもしれません。
C#コード
新しいクラスライブラリプロジェクトを開始し、NuGetを介してSharpDX.RawInputへの参照を追加しますDLLはMouseDelta.dllと呼ばれ、同じフォルダーにある必要があります。
ビルドすると、2つのSharpDXDLLがビルドフォルダーに吐き出されるはずです。スクリプトにもこれらが必要です。
using System;
using System.Windows.Forms;
using SharpDX.Multimedia;
using SharpDX.RawInput;
using System.Threading;
using System.Collections.Generic;
public class MouseDelta
{
private readonly Thread messagePump;
public dynamic relativeMoveCallback;
public dynamic wheelCallback;
static private Dictionary<IntPtr, string> seenMice = new Dictionary<IntPtr, string>();
static private string subscribedMouse = null;
private AutoResetEvent messagePumpRunning = new AutoResetEvent(false);
public MouseDelta()
{
// start message pump in its own thread
messagePump = new Thread(RunMessagePump) { Name = "ManualMessagePump" };
messagePump.Start();
messagePumpRunning.WaitOne();
}
public void SubscribeRelativeMove(dynamic callback, string mouseId = null)
{
SetSubscribedMouse(mouseId);
relativeMoveCallback = callback;
}
public void SubscribeWheel(dynamic callback, string mouseId = null)
{
SetSubscribedMouse(mouseId);
wheelCallback = callback;
}
private void SetSubscribedMouse(string mouseId)
{
if (mouseId != null)
{
subscribedMouse = mouseId == "0" ? null : mouseId;
}
}
// the message pump thread
private void RunMessagePump()
{
// Create control to handle windows messages
MessageHandler messageHandler = new MessageHandler();
// Register for RawInput mouse messages
Device.RegisterDevice(UsagePage.Generic, UsageId.GenericMouse, DeviceFlags.InputSink, messageHandler.Handle);
Device.MouseInput += ProcessMouseInput;
messagePumpRunning.Set();
Application.Run();
}
private void ProcessMouseInput(object sender, MouseInputEventArgs args)
{
//Console.WriteLine(string.Format("(x,y):({0},{1}) Buttons: {2} State: {3} Wheel: {4}\r\n", args.X, args.Y, args.ButtonFlags, args.Mode, args.WheelDelta));
// Handle mouse filtering
if (!seenMice.ContainsKey(args.Device))
{
DeviceInfo info = null;
var devices = Device.GetDevices();
foreach (var dev in devices)
{
if (dev.Handle == args.Device)
{
info = dev;
break;
}
}
if (info == null)
return;
string item = info.DeviceName;
item = item.Substring(4);
string[] split = item.Split('#');
//string id_01 = split[0]; // ACPI (Class code)
string id_02 = split[1]; // PNP0303 (SubClass code)
//string id_03 = split[2]; // 3&13c0b0c5&0 (Protocol code)
seenMice.Add(args.Device, id_02);
}
if (subscribedMouse != null && subscribedMouse != seenMice[args.Device])
{
return;
}
// Fire appropriate Callback
if (args.Mode == MouseMode.MoveRelative && relativeMoveCallback != null && (Math.Abs(args.X) + Math.Abs(args.Y) > 0))
{
relativeMoveCallback(args.X, args.Y, seenMice[args.Device]);
}
else if (args.WheelDelta != 0 && wheelCallback != null)
{
wheelCallback(args.WheelDelta / 120, seenMice[args.Device]);
}
}
}
// Useful SO post on handling messages - code for overriding WndProc
// https://stackoverflow.com/questions/2443867/message-pump-in-net-windows-service
// Although the above code is not quite complete. This blog post has the implementation for MessageData
// http://joe-bq-wang.iteye.com/blog/1882661
// However, by overriding WndProc, we have to process all messages, and then you do not get a SharpDX object..
// ... you just appear to get a raw WM_INPUT message
// For now, this seems to serve our purposes
internal class MessageHandler : NativeWindow
{
public MessageHandler()
{
CreateHandle(new CreateParams());
}
}
メインのAHKスクリプト(これを編集するだけで済みます)
; ================= USER SCRIPT ================
#SingleInstance force
#NoEnv
#include CLR.ahk
#include MouseDelta.ahk
OnExit, UnhookAndClose
GoSub, Hook
Gui, Add, Text, , Select Mouse:
mdw := new MouseDeltaWrapper("x+5 yp-3 w200")
mdw.SubscribeMove(Func("MoveEvent"))
mdw.SubscribeWheel(Func("WheelEvent"))
Gui, Show
return
^Esc::
UnhookAndClose:
GuiClose:
GoSub, UnHook
ExitApp
Hook:
hHookMouse := SetWindowsHookEx(WH_MOUSE_LL := 14, RegisterCallback("MouseMove", "Fast"))
return
UnHook:
UnhookWindowsHookEx(hHookMouse)
return
MoveEvent(x, y, mouseId){
Global mdw
if (mdw.SelectedMouse == 0 || mdw.SelectedMouse == mouseId){
DllCall("mouse_event",uint,1,int, x ,int, y,uint,0,int,0)
}
}
WheelEvent(value, mouseId){
ToolTip % "Wheel: " value ", ID: " mouseId
}
AHKラッパー
同じフォルダにMouseDelta.ahkとして保存
; ================= WRAPPER LIBRARY ================
class MouseDeltaWrapper {
SeenMice := {}
SelectedMouse := 0
MoveCallback := 0
__New(guiOptions := "", dllPath := "MouseDelta.dll"){
this.Callback := callback
Gui, +HwndHwnd
this.GuiHwnd := Hwnd
Gui, Add, DDL, % "hwndhDDL " guiOptions, Any||
this.hDDL := hDDL
fn := this._UserSelectedMouse.Bind(this)
GuiControl, +g, % this.hDDL, % fn
asm := CLR_LoadLibrary(dllPath)
md := asm.CreateInstance("MouseDelta")
md.SubscribeRelativeMove(this._MoveEvent.Bind(this))
md.SubscribeWheel(this._WheelEvent.Bind(this))
this.md := md
this._UserSelectedMouse()
}
SubscribeMove(callback){
this.MoveCallback := callback
}
SubscribeWheel(callback){
this.WheelCallback := callback
}
_UserSelectedMouse(){
GuiControlGet, mouseId, , % this.hDDL
this.SelectedMouse := mouseId == "Any" ? 0 : mouseId
if (this.MoveCallback != 0)
this.md.SubscribeRelativeMove(this._MoveEvent.Bind(this), this.SelectedMouse)
if (this.WheelCallback != 0)
this.md.SubscribeWheel(this._WheelEvent.Bind(this), this.SelectedMouse)
}
_AddMouseToDDL(mouseId){
GuiControl, , % this.hDDL, % mouseId
}
_UpdateMice(mouseId){
if (!this.SeenMice.HasKey(mouseId)){
this.SeenMice[mouseId] := 1
this._AddMouseToDDL(mouseId)
}
}
_MoveEvent(x, y, mouseId){
this._UpdateMice(mouseId)
if (this.MoveCallback != 0 && (this.SelectedMouse == 0 || this.SelectedMouse == mouseId)){
this.MoveCallback.Call(x, y, mouseId)
}
}
_WheelEvent(value, mouseId){
this._UpdateMice(mouseId)
if (this.WheelCallback != 0 && (this.SelectedMouse == 0 || this.SelectedMouse == mouseId)){
this.WheelCallback.Call(value, mouseId)
}
}
}
MouseMove(nCode, wParam, lParam)
{
Critical
SetFormat, Integer, D
If !nCode && (wParam = 0x200){
; Mouse movement - process
if (NumGet(lParam+0, 12, "int")){
; if the LLMHF_INJECTED flag is set, this is "injected" input (Came from mouse_event)
; Let this input through
Return CallNextHookEx(nCode, wParam, lParam)
} else {
; Block the input
Return 1
}
} else {
; Other mouse message - let through
Return CallNextHookEx(nCode, wParam, lParam)
}
}
SetWindowsHookEx(idHook, pfn)
{
;Return DllCall("SetWindowsHookEx", "int", idHook, "Uint", pfn, "Uint", DllCall("GetModuleHandle", "Uint", 0), "Uint", 0)
;The hMod parameter must be set to NULL if the dwThreadId parameter specifies a thread created by the current process and if the hook procedure is within the code associated with the current process
DllCall("SetWindowsHookEx", "int", idHook, "Uint", pfn, "Uint", 0, "Uint", 0)
}
UnhookWindowsHookEx(hHook)
{
Return DllCall("UnhookWindowsHookEx", "Uint", hHook)
}
CallNextHookEx(nCode, wParam, lParam, hHook = 0)
{
Return DllCall("CallNextHookEx", "Uint", hHook, "int", nCode, "Uint", wParam, "Uint", lParam)
}
CLRライブラリ-AHKがC#DLLと相互運用できるようにします。
これをCLR.ahkとして同じフォルダーまたはAHKLibフォルダーに保存します
; ==========================================================
; .NET Framework Interop
; http://www.autohotkey.com/forum/topic26191.html
; ==========================================================
;
; Author: Lexikos
; Version: 1.2
; Requires: AutoHotkey_L v1.0.96+
;
; Modified by evilC for compatibility with AHK_H as well as AHK_L
; "null" is a reserved Word in AHK_H, so did search & Replace from "null" to "_null"
CLR_LoadLibrary(AssemblyName, AppDomain=0)
{
if !AppDomain
AppDomain := CLR_GetDefaultDomain()
e := ComObjError(0)
Loop 1 {
if Assembly := AppDomain.Load_2(AssemblyName)
break
static _null := ComObject(13,0)
args := ComObjArray(0xC, 1), args[0] := AssemblyName
typeofAssembly := AppDomain.GetType().Assembly.GetType()
if Assembly := typeofAssembly.InvokeMember_3("LoadWithPartialName", 0x158, _null, _null, args)
break
if Assembly := typeofAssembly.InvokeMember_3("LoadFrom", 0x158, _null, _null, args)
break
}
ComObjError(e)
return Assembly
}
CLR_CreateObject(Assembly, TypeName, Args*)
{
if !(argCount := Args.MaxIndex())
return Assembly.CreateInstance_2(TypeName, true)
vargs := ComObjArray(0xC, argCount)
Loop % argCount
vargs[A_Index-1] := Args[A_Index]
static Array_Empty := ComObjArray(0xC,0), _null := ComObject(13,0)
return Assembly.CreateInstance_3(TypeName, true, 0, _null, vargs, _null, Array_Empty)
}
CLR_CompileC#(Code, References="", AppDomain=0, FileName="", CompilerOptions="")
{
return CLR_CompileAssembly(Code, References, "System", "Microsoft.CSharp.CSharpCodeProvider", AppDomain, FileName, CompilerOptions)
}
CLR_CompileVB(Code, References="", AppDomain=0, FileName="", CompilerOptions="")
{
return CLR_CompileAssembly(Code, References, "System", "Microsoft.VisualBasic.VBCodeProvider", AppDomain, FileName, CompilerOptions)
}
CLR_StartDomain(ByRef AppDomain, BaseDirectory="")
{
static _null := ComObject(13,0)
args := ComObjArray(0xC, 5), args[0] := "", args[2] := BaseDirectory, args[4] := ComObject(0xB,false)
AppDomain := CLR_GetDefaultDomain().GetType().InvokeMember_3("CreateDomain", 0x158, _null, _null, args)
return A_LastError >= 0
}
CLR_StopDomain(ByRef AppDomain)
{ ; ICorRuntimeHost::UnloadDomain
DllCall("SetLastError", "uint", hr := DllCall(NumGet(NumGet(0+RtHst:=CLR_Start())+20*A_PtrSize), "ptr", RtHst, "ptr", ComObjValue(AppDomain))), AppDomain := ""
return hr >= 0
}
; NOTE: IT IS NOT NECESSARY TO CALL THIS FUNCTION unless you need to load a specific version.
CLR_Start(Version="") ; returns ICorRuntimeHost*
{
static RtHst := 0
; The simple method gives no control over versioning, and seems to load .NET v2 even when v4 is present:
; return RtHst ? RtHst : (RtHst:=COM_CreateObject("CLRMetaData.CorRuntimeHost","{CB2F6722-AB3A-11D2-9C40-00C04FA30A3E}"), DllCall(NumGet(NumGet(RtHst+0)+40),"uint",RtHst))
if RtHst
return RtHst
EnvGet SystemRoot, SystemRoot
if Version =
Loop % SystemRoot "\Microsoft.NET\Framework" (A_PtrSize=8?"64":"") "\*", 2
if (FileExist(A_LoopFileFullPath "\mscorlib.dll") && A_LoopFileName > Version)
Version := A_LoopFileName
if DllCall("mscoree\CorBindToRuntimeEx", "wstr", Version, "ptr", 0, "uint", 0
, "ptr", CLR_GUID(CLSID_CorRuntimeHost, "{CB2F6723-AB3A-11D2-9C40-00C04FA30A3E}")
, "ptr", CLR_GUID(IID_ICorRuntimeHost, "{CB2F6722-AB3A-11D2-9C40-00C04FA30A3E}")
, "ptr*", RtHst) >= 0
DllCall(NumGet(NumGet(RtHst+0)+10*A_PtrSize), "ptr", RtHst) ; Start
return RtHst
}
;
; INTERNAL FUNCTIONS
;
CLR_GetDefaultDomain()
{
static defaultDomain := 0
if !defaultDomain
{ ; ICorRuntimeHost::GetDefaultDomain
if DllCall(NumGet(NumGet(0+RtHst:=CLR_Start())+13*A_PtrSize), "ptr", RtHst, "ptr*", p:=0) >= 0
defaultDomain := ComObject(p), ObjRelease(p)
}
return defaultDomain
}
CLR_CompileAssembly(Code, References, ProviderAssembly, ProviderType, AppDomain=0, FileName="", CompilerOptions="")
{
if !AppDomain
AppDomain := CLR_GetDefaultDomain()
if !(asmProvider := CLR_LoadLibrary(ProviderAssembly, AppDomain))
|| !(codeProvider := asmProvider.CreateInstance(ProviderType))
|| !(codeCompiler := codeProvider.CreateCompiler())
return 0
if !(asmSystem := (ProviderAssembly="System") ? asmProvider : CLR_LoadLibrary("System", AppDomain))
return 0
; Convert | delimited list of references into an array.
StringSplit, Refs, References, |, %A_Space%%A_Tab%
aRefs := ComObjArray(8, Refs0)
Loop % Refs0
aRefs[A_Index-1] := Refs%A_Index%
; Set parameters for compiler.
prms := CLR_CreateObject(asmSystem, "System.CodeDom.Compiler.CompilerParameters", aRefs)
, prms.OutputAssembly := FileName
, prms.GenerateInMemory := FileName=""
, prms.GenerateExecutable := SubStr(FileName,-3)=".exe"
, prms.CompilerOptions := CompilerOptions
, prms.IncludeDebugInformation := true
; Compile!
compilerRes := codeCompiler.CompileAssemblyFromSource(prms, Code)
if error_count := (errors := compilerRes.Errors).Count
{
error_text := ""
Loop % error_count
error_text .= ((e := errors.Item[A_Index-1]).IsWarning ? "Warning " : "Error ") . e.ErrorNumber " on line " e.Line ": " e.ErrorText "`n`n"
MsgBox, 16, Compilation Failed, %error_text%
return 0
}
; Success. Return Assembly object or path.
return compilerRes[FileName="" ? "CompiledAssembly" : "PathToAssembly"]
}
CLR_GUID(ByRef GUID, sGUID)
{
VarSetCapacity(GUID, 16, 0)
return DllCall("ole32\CLSIDFromString", "wstr", sGUID, "ptr", &GUID) >= 0 ? &GUID : ""
}
Razer Synapseに似たLogitechマウス用のカスタムソフトウェアはありますか?そこにカスタム感度設定を見つけることができるかもしれません。
私はここに私の同様のケースの解決策を置きたいと思います。私は垂直方向と水平方向の感度の間にかなりの不均衡がありました。
最後に、「マウスのプロパティ」の「ポインタの精度を上げる」のチェックを外して、バランスを取り戻しました。
それはかなり不明確でした。私は多くの時間を費やして、ほとんど運が良かったので解決策を見つけたので、ここにそれを固定したいと思います。