はじめに
GPD WINというデバイスが一部で人気です。
このデバイスには通常のポインティングデバイスはついていませんが、代わりにゲームパッドがついており、パッドのモードを切り替えることでマウスとしても使えます。
ですがデフォルトの挙動やボタン設定がしっくりこないので、AutoHotkeyでスクリプトを書きました。
パッドをポインティングデバイスにする方法としては、JoyToKeyを使う方法が一般的ですが、JoyToKeyはシェアウェア1なのと、AutoHotkeyのほうが細かい挙動がいじりやすいのでAutoHotkeyを使用しています。
ボタン配置(暫定)
とりあえず以下のように設定。使ってくうちにより使いやすい配置にしてきます。
L3/R3には無変換/変換を割り当てて、IMEのOFF/ONに使っています。
Start/Selectは押しづらいので未設定です。コピペとか割り当てると良いかも。
クリック(A,Bボタン)を押したときに、マウスポインタを一瞬停止するようにしています。これはスティックを操作しながらボタンを押したときに、予期せぬドラッグ操作になることを防ぐためです。この辺の挙動を自由にいじれるのがJoyToKeyではなくAutoHotkeyを使うメリットです。
ボタン | 機能 |
---|---|
左スティック | ポインタの移動 |
右スティック上下 | スクロール |
右スティック左右 | Shift+Tab/Tab |
方向ボタン | 矢印キー |
Aボタン | 左クリック |
Bボタン | 右クリック |
Xボタン | タスクビュー2 |
Yボタン | 中クリック |
L1ボタン | スローボタン (押してる間ポインタの動きが遅くなる) |
R1ボタン | 修飾キー |
L2/R2トリガー | 戻る/進む |
L3/R3 | 無変換/変換 |
R1+Aボタン | Enter |
R1+Bボタン | Esc |
R1+Xボタン | Alt+Tab |
R1+Yボタン | Win |
Win+J | スクリプトのON/OFF |
スクリプト
AutoHotkeyではキーラベルにスティックが使えません。GetKeyStateで状態は取得できるので、Loopで常に監視しています。
; GPD WIN用スクリプト
; ***XInputモードで使用のこと。***
# SingleInstance, FORCE
SetMouseDelay, 0
DeadMargin := 1 ; スティックの不感帯
SpeedNormal := 0.4 ; 通常時のマウスポインタ移動速度
SpeedSlow := 0.08 ; スローボタンを押したときのマウスポインタ移動速度
WheelWaitNormal := 50 ; 右スティックでのスクロール間隔
WheelWaitSlow := 250 ; スローボタンを押したときの右スティックでのスクロール間隔
SlowButton := "Joy5" ; ポインタの移動やスクロールを遅くするボタン
LClickButton := "Joy1" ; 左クリックに設定するボタン
RClickButton := "Joy2" ; 右クリックに設定するボタン
ShiftButton := "Joy6" ; 他のボタンの機能を変更する修飾ボタン
ButtonWait := 100 ; ボタン押下後に待つ場合の時間
isPause := 0
isLClickButtonDowned := 0
isRClickButtonDowned := 0
isL2ButtonDowned := 0
isR2ButtonDowned := 0
lastClick := A_TICKCOUNT
Gosub, JoyStickInit
Loop
{
while isPause ;PauseがSuspendと組み合わせたときに挙動不審なのでフラグで管理
sleep, 1
Gosub, GetJoyStickState
; ToolTip, X:%stateJoyX% Y:%stateJoyY% Z:%stateJoyZ% U:%stateJoyU% R:%stateJoyR% POV:%stateJoyPOV%
; マウスカーソルの移動
diffX := stateJoyX - defaultJoyX
diffY := stateJoyY - defaultJoyY
coef := GetKeyState(SlowButton,"P") ? SpeedSlow : SpeedNormal
if(Abs(diffX) > DeadMargin && A_TICKCOUNT - lastClick > ButtonWait)
x := diffX * coef
if(Abs(diffY) > DeadMargin && A_TICKCOUNT - lastClick > ButtonWait)
y := diffY * coef
if(x || y)
{
MouseMove, %x%, %Y%,, R
Sleep, 1
}
x := 0
y := 0
; スクロール
diffR := stateJoyR - defaultJoyR
if(Abs(diffR) > DeadMargin)
{
if(diffR < 0)
{
MouseClick, WheelUp
}
Else
{
MouseClick, WheelDown
}
wait := GetKeyState(SlowButton, "P") ? WheelWaitSlow : WheelWaitNormal
Sleep, %wait%
}
diffU := stateJoyU - defaultJoyU
if(diffU > 40){
Send, {Tab}
Sleep, %ButtonWait%
}
if(diffU < -40){
Send, +{Tab}
Sleep, %ButtonWait%
}
; L2, R2
diffZ := stateJoyZ - defaultJoyZ
if(diffZ > 40 && !isL2ButtonDowned){ ;L2 Down
isL2ButtonDowned := 1
Send, {Browser_Back}
}
if(diffZ < -40 && !isR2ButtonDowned){ ;R2 Down
isR2ButtonDowned :=1
Send, {Browser_Forward}
}
if(-10 < diffZ && diffZ < 10 && isL2ButtonDowned) ;L2 Up
isL2ButtonDowned := 0
if(-10 < diffZ && diffZ < 10 && isR2ButtonDowned) ;R2 Up
isR2ButtonDowned := 0
; 方向ボタン
if(stateJoyPOV != -1)
{
if(stateJoyPOV == 0)
Send, {Up}
if(stateJoyPOV == 9000)
Send, {Right}
if(stateJoyPOV == 18000)
Send, {Down}
if(stateJoyPOV == 27000)
Send, {Left}
Sleep, %ButtonWait%
}
; 左クリック
; Joy1 Upで拾えないのでLoop中に記述
If(GetKeyState(LClickButton, "P"))
{
If(ShiftButton())
{
Send, {Enter Down}
while GetKeyState(LClickButton, "P")
Sleep, 1
Send, {Enter Up}
}
else
{
If isLClickButtonDowned = 0
{
Click, LEFT, D
isLClickButtonDowned = 1
lastClick = %A_TICKCOUNT%
}
}
}
else
{
If isLClickButtonDowned = 1
{
Click, LEFT, U
isLClickButtonDowned = 0
}
}
; 右クリック
If(GetKeyState(RClickButton, "P"))
{
if(ShiftButton())
{
Send, {Esc Down}
while GetKeyState(RClickButton, "P")
Sleep, 1
Send, {Esc Up}
}
else
{
If isRClickButtonDowned = 0
{
Click, RIGHT, D
isRClickButtonDowned = 1
}
}
}
else
{
If isRClickButtonDowned = 1
{
Click, RIGHT, U
isRClickButtonDowned = 0
}
}
}
return
JoyStickInit:
Gosub, GetJoyStickState
defaultJoyX := stateJoyX
defaultJoyY := stateJoyY
defaultJoyZ := stateJoyZ
defaultJoyU := stateJoyU
defaultJoyR := stateJoyR
Return
GetJoyStickState:
GetKeyState, stateJoyX, JoyX, P
GetKeyState, stateJoyY, JoyY, P
GetKeyState, stateJoyZ, JoyZ, P
GetKeyState, stateJoyU, JoyU, P
GetKeyState, stateJoyR, JoyR, P
GetKeyState, stateJoyPOV, JoyPOV, P
Return
ShiftButton()
{
global ShiftButton
Return, GetKeyState(ShiftButton, "P")
}
Joy3::
if(ShiftButton())
{
Send, !{Tab}
}
else
{
IfWinActive, ahk_class MultitaskingViewFrame
Send, {Enter}
Else
Send, #{Tab}
}
Return
Joy4::
if(ShiftButton())
{
Send, {LWin}
}
else
{
IfWinActive, ahk_class MultitaskingViewFrame
Send, {Delete}
Else
Click, Middle
Sleep, %ButtonWait%
}
Return
; Start
Joy8::Gosub, JoyStickInit ; スティック初期化
; L3
Joy9::vk1Dsc07B ; 無変換
; R3
Joy10::vk1Csc079 ; 変換
; スクリプト一時停止トグル
# J::
Suspend
isPause := isPause ? 0 : 1
Return
行き当たりばったりで書いたので汚いコードだけど動くから良いよね!