라이트건 (LightGun, 건콘) 게임을 위해 Retrobat으로 게임과 에뮬레이터를 관리하고 있습니다.
라이트건 종류가 많아지다 보니 기기에 따른 설정이 복잡해졌습니다.
좀 더 손쉽게 게임환경을 설정할 수 있도록 AutoHotKey (이하 AHK)를 사용해 보았습니다.
Requirement는 다음과 같습니다.
- 연결된 건콘을 수동 또는 자동으로 선택해야 합니다.
- 자동으로 기기를 인식할때는 음성으로 선택된 기기를 알려줘야 합니다.
- Teknoparrot과 DemulShooter는 기기의 HID에 따라 설정을 자동으로 바꿔줘야 합니다.
- Retrobat이 실행될때 기기별 전용 프로그램을 실행해야 합니다.
- Retrobat이 종료될때 기기별 전용 프로그램을 종료해야 합니다.
- 마우스 커서를 조준선으로 변경하고, Retrobat 종료시 원복해야 합니다.

설정 파일 변경
방법1 – 심볼릭 링크
기기에 따른 Teknoparrot과 DemulShooter를 구분하여 설치하고, AHK를 통해 심볼릭 링크를 생성하는 방법을 사용할 수 있습니다.
심볼릭링크를 사용시 teknoparrot - Sinden 폴더가 teknoparrot 폴더로 인식됩니다.
단점은 심볼릭 링크를 생성하기 위해서는 관리자 권한으로 AHK를 실행해야 합니다.


방법 2 – 설정파일 복사
기기에 따른 설정파일만 따로 만들고 AHK를 통해 원하는 설정들을 덮어쓸 수 있습니다.teknoparrot - Sinden\UserProfiles\*.* 파일을 teknoparrot\UserProfiles\*.* 에 덮어쓰는 방식입니다.


기기별 전용 프로그램
Key Manager
현재 X-Gunner는 사용자 버튼 설정 기능이 없기 때문에 Key Manager를 통해 버튼을 변경하여 사용하고 있습니다.
저는 MP5와 Pistol의 매핑을 다르게 설정하였기 때문에 AHK를 통해 프로필을 변경하고 있습니다.


SindenLightgun
Sinden Lightgun을 사용하기 위해서는 전용 프로그램을 꼭 사용해야 합니다.

Retrobat Launcher
완성된 AHK 스크립트와 실행 예시는 다음과 같습니다.

#SingleInstance, Force
autoDetect := A_Args[1] == "auto"
global deviceIds := Object("Sinden", "HID\VID_16C0&PID_0F38&MI_02&Col02\a&325b90b&0&0001"
, "Gun4IR", "HID\VID_2341&PID_8042&MI_02&Col03\8&3a338b46&0&0002"
, "XGunner MP5", "HID\VID_1209&PID_0001&MI_02&Col02\8&231fee9e&0&0001"
, "XGunner Pistol", "HID\VID_1209&PID_0002&MI_02&Col02\8&335f4b7e&0&0001")
global cursorFile := "E:\Lightgun\crosshair\ico\blue_white_128.ico"
; -----------------------------------
if (autoDetect == false) {
OpenGui()
return
}
hid := FindGunName()
if (hid == "") {
OpenGui()
}
else {
Notify(hid)
Process(hid)
}
return
; -----------------------------------
FindGunName() {
PnPSignedDriver := FindPnPSignedDriver()
for i, v in PnPSignedDriver {
for k, v in deviceIds {
if (InStr(PnPSignedDriver[i].DeviceID, v)) {
; MsgBox, % "Id: " . PnPSignedDriver[i].DeviceID . "`rstatus: " . PnPSignedDriver[i].Status "`rk: " . k . "`rv: " . v
return k
}
}
}
MsgBox, "No guns detected, select one manually."
return ""
}
; ref: https://www.autohotkey.com/boards/viewtopic.php?t=90238
FindPnPSignedDriver()
{
try
{
PnPSignedDriver := []
for objItem in ComObjGet("winmgmts:").ExecQuery("SELECT * FROM Win32_PnPSignedDriver")
{
if (InStr(objItem.DeviceID, "HID\VID_")) {
PnPSignedDriver[A_Index, "Description"] := objItem.Description
PnPSignedDriver[A_Index, "DeviceID"] := objItem.DeviceID
PnPSignedDriver[A_Index, "Status"] := objItem.Status
}
}
return PnPSignedDriver
}
return ""
}
; ref : https://www.autohotkey.com/boards/viewtopic.php?t=114512
Notify(hid) {
pronunciation := StrReplace(hid, "Gun4IR", "Gun for IR")
sv := ComObjCreate("SAPI.SpVoice")
sv.Voice := sv.GetVoices().Item(1)
sv.Speak(pronunciation . " detected")
}
; -----------------------------------
OpenGui() {
Gui, Add, Button, w100 gOnPress, Sinden
Gui, Add, Button, x+5 yp wp gOnPress, Gun4IR
Gui, Add, Button, x+5 yp wp gOnPress, XGunner MP5
Gui, Add, Button, x+5 yp wp gOnPress, XGunner Pistol
Gui, Add, Button, x+5 yp wp gOnPress, None
Gui, Show,,Choose a lightgun to use.
}
GuiClose() {
ExitApp
}
OnPress() {
Gui, Hide
Process(A_GuiControl)
}
Process(gunName) {
switch
{
case InStr(gunName, "Sinden"):
PrepareTeknoparrot(gunName)
PrepareDemulShooter(gunName)
ExcuteSinden()
ExcuteRetrobat()
SetCrosshairCursor()
MonitorRetrobat()
return
case InStr(gunName, "XGunner"):
PrepareTeknoparrot(gunName)
PrepareDemulShooter(gunName)
ExcuteKeyManager(gunName)
ExcuteRetrobat()
SetCrosshairCursor()
MonitorRetrobat()
return
case InStr(gunName, "Gun4IR"):
PrepareTeknoparrot(gunName)
PrepareDemulShooter(gunName)
ExcuteRetrobat()
SetCrosshairCursor()
MonitorRetrobat()
return
default:
ExcuteRetrobat()
ExitApp
}
}
; -----------------------------------
ExcuteSinden() {
Run, E:\Lightgun\SindenLightgun V2.07\Lightgun.exe
}
ExcuteKeyManager(gunName) {
; app := % "E:\Lightgun\Key Manager - " . gunName . "\keymanager.exe"
; Run, %app%
Run, E:\Lightgun\Key Manager\keymanager.exe
sleep,1000
switch
{
case InStr(gunName, "XGunner MP5"):
SendRaw ^!1
return
case InStr(gunName, "XGunner Pistol"):
SendRaw ^!2
return
}
}
ExcuteRetrobat() {
Run, D:\RetroBat_Gun\retrobat.exe
sleep,1000
WinActivate, EmulationStation
}
MonitorRetrobat() {
WinTitle:= "EmulationStation"
loop, {
if not WinExist(WinTitle) {
Process, Close, keymanager.exe
Run, taskkill /im "keymanager.exe" /F
Process, Close, Lightgun.exe
Run, taskkill /im "Lightgun.exe" /F
RestoreCursors()
ExitApp
}
Sleep, 1000
}
}
; -----------------------------------
; Symbolic links - requires administrator privileges
/*
PrepareTeknoparrot(gunName) {
run, %comspec% /c rmdir "D:\RetroBat_Gun\emulators\teknoparrot",,hide
cmd := "mklink /d ""D:\RetroBat_Gun\emulators\teknoparrot"" ""D:\RetroBat_Gun\emulators\teknoparrot - " . gunName . """"
run, %comspec% /c %cmd%,,hide
}
PrepareDemulShooter(gunName) {
run, %comspec% /c rmdir "E:\Lightgun\DemulShooter",,hide
cmd := "mklink /d ""E:\Lightgun\DemulShooter"" ""E:\Lightgun\DemulShooter - " . gunName . """"
run, %comspec% /c %cmd%,,hide
}
*/
; Copy the configuration file
PrepareTeknoparrot(gunName) {
cmd := "copy ""E:\Lightgun\DemulShooter - " . gunName . "\config.ini"" ""E:\Lightgun\DemulShooter\"" /Y"
run, %comspec% /c %cmd%,,hide
cmd := "echo " . gunName . " > ""E:\Lightgun\DemulShooter\__marker__.txt"""
run, %comspec% /c %cmd%,,hide
}
PrepareDemulShooter(gunName) {
cmd := "xcopy ""D:\RetroBat_Gun\emulators\teknoparrot - " . gunName . "\UserProfiles"" ""D:\RetroBat_Gun\emulators\teknoparrot\UserProfiles"" /e /h /k /y"
run, %comspec% /c %cmd%,,hide
cmd := "echo " . gunName . " > ""D:\RetroBat_Gun\emulators\teknoparrot\__marker__.txt"""
run, %comspec% /c %cmd%,,hide
}
; -----------------------------------
; ref : https://www.autohotkey.com/board/topic/32608-changing-the-system-cursor/
SetCrosshairCursor() {
Cursors = 32512,32513,32514,32515,32516,32640,32641,32642,32643,32644,32645,32646,32648,32649,32650,32651
Loop, Parse, Cursors, `,
{
DllCall( "SetSystemCursor", Uint, DllCall("LoadCursorFromFile", Str, cursorFile), Int, A_Loopfield )
; DllCall("SystemParametersInfo", "Int", 0x2029, "Int", 0, "Ptr", 48, "Int", 0x01)
}
}
RestoreCursors() {
SPI_SETCURSORS := 0x57
DllCall("SystemParametersInfo", UInt, SPI_SETCURSORS, UInt, 0, UInt, 0, UInt, 0 )
; DllCall("SystemParametersInfo", "Int", 0x2029, "Int", 0, "Ptr", 30, "Int", 0x01)
}






