Categories

让 trackpoint 的 middle-click 与 scroll 共存

trackpointThinkpad 上的小红点(Trackpoint)一直是让人爱不释手的东西,使用起来非常方便,也不像触摸板那样经常会不小心碰到,另外,用 trackpoint 还可以很方便地模拟滚轮操作,在 Windows 下,只要安装了 trackpoint 的驱动,就可以在控制面板里设置滚动了,设置好以后只要按下中键,然后移动 trackpoint 就可以实现像上、下、左、右四个方向的滚动了。不过其实我一般是不用这个功能的,有些程序(比如 Firefox)本身就支持中键点击启动滚动,无论是 trackpoint 还是普通的鼠标(不过工作方式有些不同,有些时候,如在 Google Reader 页面上不太好用),当然,最大的原因还是启用了这个驱动之后原本的鼠标中键功能就丧失了。例如,在 Firefox 里可以用鼠标中键点击在后台打开新标签,或者中键单击关闭标签等,都会变得不可用。如何同时使用滚动和中键的功能,我 google 了很久都没有找到满意的答案。

不过我后来发现在 Linux 下倒是可以很方便地办到这一点,创建一个文件 /etc/hal/fdi/policy/mouse-wheel.fdi ,内容如下:

1
2
3
4
5
6
7
8
<match key="info.product" string="TPPS/2 IBM TrackPoint">
  <merge key="input.x11_options.EmulateWheel" type="string">true</merge>
  <merge key="input.x11_options.EmulateWheelButton" type="string">2</merge>
  <merge key="input.x11_options.YAxisMapping" type="string">4 5</merge>
  <merge key="input.x11_options.XAxisMapping" type="string">6 7</merge>
  <merge key="input.x11_options.Emulate3Buttons" type="string">true</merge>
  <merge key="input.x11_options.EmulateWheelTimeout" type="string">200</merge>
</match>

这样一来就中键和滚动两不误了!那么,既然在 Linux 下可以这么容易办到,那么在 Windows 下应该也是可以实现的。当然,自己定制一个驱动的念头立马被我打消了,然后我又想到了 AutoHotkey 这个 Windows 下的神兵利器。经过一番探索,最终得到了一个可用的 AHK 脚本。

其实原理非常简单,首先监听中键按下的事件,触发后等待一段时间,例如 200 毫秒,如果在 200 毫秒之内放开了中键,那么就模拟一个中键点击的行为,但是如果没有放开,那么就启动滚动行为。滚动行为就是每隔一段时间,例如 40 毫秒检查一次鼠标的位置,并计算与按下中键时的鼠标位置的位移,如果向下移动了就模拟一个鼠标滚轮 scrolldown 的事件,其它类似。当然,为了避免鼠标轻微漂移也会产生滚屏,可以设置一个 threshold ,当位移超过该 threshold 时才模拟滚轮事件。完整的代码如下:

1
2
3
4
5
6
7
8
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
59
60
61
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
;;
;; Trackpoint.ahk
;; Author: Chiyuan Zhang <pluskid@gmail.com>
;; Version: 1.0 (Sep. 03, 2009)
;;
;; Thinkpad trackpoint driver on Windows doesn't allow
;; to use both middle-click and scrolling simultaneously.
;; If you enable the scrolling, you'll not be able to
;; click the middle button (e.g. to open a link in the
;; background in Firefox). 
;;
;; However, on Linux, one can get a good behavior where
;; both middle-click and scrolling behaves well (see
;; www.thinkwiki.org/wiki/How_to_configure_the_TrackPoint).
;;
;; This script trys to make it behave similarly. When you
;; press the middle button and release in a short time, it
;; will be a regular middle-click. However, if you hold it
;; and move the cursor, it will do scrolling.
;;
 
;; Configuration
 
;#NoTrayIcon
 
; Milliseconds threshold, hold the middle button for some time
; exceeding this will start to detect scrolling.
tp_StartScrollTThreshold = 200
; Pixels threshold, for both X and Y. Only when the mouse movement
; exceed this threshold will we start scrolling. 
tp_StartScrollXThreshold = 7
tp_StartScrollYThreshold = 4
; Milliseconds interval to check further scrolling. Set this to a
; smaller value will make scrolling more fast, and vice versa.
tp_ScrollCheckInterval = 40
 
;; This key/Button activates scrolling
tp_TriggerKey = MButton
 
;; End of configuration
 
#Persistent
CoordMode, Mouse, Screen
Hotkey, %tp_TriggerKey%, tp_TriggerKeyDown
HotKey, %tp_TriggerKey% Up, tp_TriggerKeyUp
return
 
tp_TriggerKeyDown:
tp_Scroll = n
MouseGetPos, tp_OrigX, tp_OrigY
SetTimer, tp_CheckForScrollEventAndExecute, %tp_StartScrollTThreshold%
return
 
tp_TriggerKeyUp:
SetTimer, tp_CheckForScrollEventAndExecute, Off
;; Send a middle-click if we did not scroll
if tp_Scroll = n
    MouseClick, Middle
return
 
tp_CheckForScrollEventAndExecute:
tp_Scroll = y
SetTimer, tp_CheckForScrollEventAndExecute, %tp_ScrollCheckInterval%
 
MouseGetPos, tp_NewX, tp_NewY
tp_DistanceX := tp_NewX - tp_OrigX
tp_DistanceY := tp_NewY - tp_OrigY
 
if tp_DistanceY > %tp_StartScrollYThreshold%
    MouseClick, WheelDown
else if tp_DistanceY < -%tp_StartScrollYThreshold%
    MouseClick, WheelUp
 
; 0x114 is WM_HSCROLL
if tp_DistanceX > %tp_StartScrollXThreshold%
{
    ControlGetFocus, FocusedControl, A
    SendMessage, 0x114, 1, 0, %FocusedControl%, A
}
else if tp_DistanceX < -%tp_StartScrollXThreshold%
{
    ControlGetFocus, FocusedControl, A
    SendMessage, 0x114, 0, 0, %FocusedControl%, A
}
 
return

这样一来就可以踢飞官方的那个 trackpoint 驱动啦!修改 tp_ScrollCheckInterval 可以调节滚动的速度,不过如果把该值设置得太大的话滚动会看起来是一顿一顿的,最好是结合系统一次滚轮事件滚动的距离来进行修改(我感觉这个参数应该是可以在控制面板里设置的吧?但是好像找不到了)。

13 comments to 让 trackpoint 的 middle-click 与 scroll 共存

  • 你这里大部分文章我都看不懂,层次差距太大……飘走

  • imonyse

    办法是不错
    但是刚刚试验了一下,在我的ubuntu 8.04上没用。
    在8.10上应该也不行,参看:
    https://bugs.launchpad.net/ubuntu/+bug/258161
    https://bugs.launchpad.net/ubuntu/+source/xorg/+bug/251408

    为了玩chrome,从Fedora 11换成了Ubuntu 8.04,结果不能玩中键…囧

  • 调参数真是痛苦的一件事啊~

  • maxint

    感觉可以用autohotkey替代bat和按键精灵,不过这些也不常用

  • Mike

    这个在thinkwiki上好像有啊。。。

  • @Mike
    X11 的那个解决方案是早就有的。

  • Jasonx

    不错,谢谢!

  • babyking

    还是有些问题,就是在滚动的时候鼠标指针会移动,原来THINKPAD的是按住鼠标中键然后通过小红点进行上现滚动,鼠标指针在原地不动,小红点不受力是停止滚动

    • 嗯,我不太喜欢官方驱动的那种行为,所以用这个,你要是有需求可以尝试自己修改一下看能不能弄出来。

  • babyking

    在你的基础上我稍稍的修改了下,基本能做到原版驱动的效果了,有空再把鼠标指针的图标改一下就OK了

    1
    2
    3
    4
    5
    6
    7
    8
    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
    59
    60
    61
    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
    
    ;;
    ;; Trackpoint.ahk
    ;; Author: Chiyuan Zhang 
    ;; Version: 1.0 (Sep. 03, 2009)
    ;;
    ;; Thinkpad trackpoint driver on Windows doesn't allow
    ;; to use both middle-click and scrolling simultaneously.
    ;; If you enable the scrolling, you'll not be able to
    ;; click the middle button (e.g. to open a link in the
    ;; background in Firefox). 
    ;;
    ;; However, on Linux, one can get a good behavior where
    ;; both middle-click and scrolling behaves well (see
    ;; www.thinkwiki.org/wiki/How_to_configure_the_TrackPoint).
    ;;
    ;; This script trys to make it behave similarly. When you
    ;; press the middle button and release in a short time, it
    ;; will be a regular middle-click. However, if you hold it
    ;; and move the cursor, it will do scrolling.
    ;;
     
    ;; Configuration
     
    ;#NoTrayIcon
     
    ; Milliseconds threshold, hold the middle button for some time
    ; exceeding this will start to detect scrolling.
    tp_StartScrollTThreshold = 200
    ; Pixels threshold, for both X and Y. Only when the mouse movement
    ; exceed this threshold will we start scrolling. 
    tp_StartScrollXThreshold = 10
    tp_StartScrollYThreshold = 1
    ; Milliseconds interval to check further scrolling. Set this to a
    ; smaller value will make scrolling more fast, and vice versa.
    tp_ScrollCheckInterval = 10
     
    ;; This key/Button activates scrolling
    tp_TriggerKey = MButton
     
    ;; End of configuration
     
    #Persistent
    CoordMode, Mouse, Screen
    Hotkey, %tp_TriggerKey%, tp_TriggerKeyDown
    HotKey, %tp_TriggerKey% Up, tp_TriggerKeyUp
    return
     
    tp_TriggerKeyDown:
    tp_Scroll = n
    MouseGetPos, tp_OrigX, tp_OrigY
    SetTimer, tp_CheckForScrollEventAndExecute, %tp_StartScrollTThreshold%
    return
     
    tp_TriggerKeyUp:
    SetTimer, tp_CheckForScrollEventAndExecute, Off
    ;; Send a middle-click if we did not scroll
    if tp_Scroll = n
        MouseClick, Middle
    return
     
    tp_CheckForScrollEventAndExecute:
    tp_Scroll = y
    SetTimer, tp_CheckForScrollEventAndExecute, %tp_ScrollCheckInterval%
     
    MouseGetPos, tp_NewX, tp_NewY
    tp_DistanceX := tp_NewX - tp_OrigX
    tp_DistanceY := tp_NewY - tp_OrigY
     
    if tp_DistanceY &gt; %tp_StartScrollYThreshold%
    {
        MouseClick, WheelDown
    }
    else if tp_DistanceY  %tp_StartScrollYThreshold%
    {
        ControlGetFocus, FocusedControl, A
        SendMessage, 0x114, 1, 0, %FocusedControl%, A
     
        MouseMove,tp_OrigX,tp_OrigY	
     
    }
    else if tp_DistanceY &lt; -%tp_StartScrollYThreshold%
    {
        ControlGetFocus, FocusedControl, A
        SendMessage, 0x114, 0, 0, %FocusedControl%, A
     
     
        MouseMove,tp_OrigX,tp_OrigY
     
    }
    return
  • carbont

    google过来的。
    在Linux下面的时候,倒是滚动跟中键都能用,但是现在换回windows7,官方的驱动竟然还不能支持同时使用,搞得我还挺郁闷。
    不过,像这么搞起来,还挺有难度的说……

  • ghos

    谢谢分享,09年的文章18年还能为我解决问题谢谢了。