; Enhancements for using various bits of emulation software with an XBox 360 controller, using AutoHotKey ; This currently contains tweaks for: ; MAMEwah - a front-end for multiple systems ; JNES - a NES emulator ; ; Features provided everywhere: ; - the D-pad sends up/down/left/right keys ; - left bumper => save checkpoint (in all emulators that support it) ; - right bumper => load checkpoint (in all emulators that support it) ; ; MAMEwah features provided: ; - A button sends "1" ; - B button sends "2" ; - TODO: the A/B buttons don't seem to... always work? ; ; MAME features provided: ; - the analog stick (as well as the D-pad) press the up/down/left/right keys ; - TODO: get robotron working (with both the left and right analog sticks working) ; - TODO: maybe get Super Sprint working with the mouse for turning? or is that too crazy? ; ; JNES features provided: ; - escape key => exit (just to be consistent with other front-endable emulators) ; - TODO: the save/load doesn't... always work? ; - TODO: get pause/reset/exit working from the controller too ; - TODO: maybe change the checkpoint save be required to be held down so it's not accidentally pressed? ala: ; http://www.upup.us/log/ahkscripts/HoldEscape.ahk ; ; Gens features provided: ; - TODO: get the left/right bumpers working for save/load checkpoint ; - TODO: get the left/right triggres working for C/Z (since I can only map A/B/X/Y on the normal face buttons) ; ; generally: ; - TODO: get a pop-up menu working, at least for things like exit/reset... ; - have a "PauseGame" gosub, which, when called, figures out the appropriate key to press to pause (and probably unpause?) the game ; - when the user clicks down on the left joystick, pause the game, and display an OSD popup menu ; - in the OSD popup, the left analog stick allows the user to scroll up/down/left/right. clicking "A" selects the item (eg. reset, or exit). clicking on the left analog stick ; Decrease the following value to require less joystick displacement-from-center ; to start moving the mouse. However, you may need to calibrate your joystick ; -- ensuring it's properly centered -- to avoid cursor drift. A perfectly tight ; and centered joystick could use a value of 1: JoyDeadzone := 100 #SingleInstance force DetectHiddenWindows, On SetKeyDelay,,100 ; for the default/dumbest key handling, hold keys down for at least 0.1 second ;SetTimer, AutoMaxJNES, 500 ; 500 = two times a second SetTimer, WatchJoystickPOV, 5 SetTimer, ZTriggers, 5 return ; ---- JNES keymaps ----- #IfWinActive Jnes Joy5::Send {F5} Joy6::Send {F7} Escape::Send {Alt down}{F4}{Alt up} ; ---- MAMEWAH keymaps ----- #IfWinActive MAMEWAH Joy1:: Send {1} return Joy2:: SetKeyDelay,,100 Send {2} return ; ---- MAME keymaps ---- #IfWinActive ahk_class MAME Joy7:: ; -- select -- SetKeyDelay,,100 Send, {5} return Joy8:: ; -- start -- SetKeyDelay,,100 Send, {1} return Joy5::Send {LShift down}{F7}{LShift up}{1} ; left bumper: save Joy6::Send {F7}{1} ; right bumper: load Joy1:: ; -- button A -- Send {LCtrl down} ; see "Method #3" of the "Remapping a Joystick" part of the AutoHotKey manual SetTimer, MAME_up_fire1, 10 return MAME_up_fire1: if GetKeyState("Joy1") ; The button is still, down, so keep waiting. return Send {LCtrl up} ; Release the left mouse button. SetTimer, MAME_up_fire1, off return Joy2:: ; -- button B -- Send {LAlt down} SetTimer, MAME_up_fire2, 10 return MAME_up_fire2: if GetKeyState("Joy2") ; The button is still, down, so keep waiting. return Send {LAlt up} ; Release the left mouse button. SetTimer, MAME_up_fire2, off return ; ---- Project64 keymaps ---- #IfWinActive Project64 Joy5::Send {F5} Joy6::Send {F7} ; ---- VisualBoyAdvance keymaps ---- #IfWinActive VisualBoyAdvance Joy1:: SendInput {Z down} SetTimer, VBA_fire1, 10 return VBA_fire1: if GetKeyState("Joy1") ; The button is still, down, so keep waiting. return SendInput {Z up} SetTimer, VBA_fire1, off return Joy2:: SendInput {X down} SetTimer, VBA_fire2, 10 return VBA_fire2: if GetKeyState("Joy2") ; The button is still, down, so keep waiting. return SendInput {X up} SetTimer, VBA_fire2, off return Joy3:: SendInput {A down} SetTimer, VBA_fire3, 10 return VBA_fire3: GetKeyState, joyz, 1JoyZ if (joyz > 60) or (GetKeyState("Joy3")) ; The button is still, down, so keep waiting. return SendInput {A up} SetTimer, VBA_fire3, off return Joy4:: SendInput {S down} SetTimer, VBA_fire4, 10 return VBA_fire4: GetKeyState, joyz, 1JoyZ if (joyz < 40) or (GetKeyState("Joy4")) ; The button is still, down, so keep waiting. return SendInput {S up} SetTimer, VBA_fire4, off return ; Joy3::SendInput {A} ; Joy4::SendInput {S} Joy5::Send {Shift down}{F2}{Shift up} Joy6::Send {F2} Joy7:: SendInput {BS down} Sleep 40 SendInput {BS up} return Joy8:: SendInput {Enter down} Sleep 40 SendInput {Enter up} return ; ....... bomb-jump timing for metroid (hasn't been tested to working state) .............. M:: SendInput {X} SetTimer, MetroidBombJump, 2000 return MetroidBombJump: SendInput {X} if GetKeyState("M") ;The button is still down, so keep jumping. return SetTimer, MetroidBombJump, off return ; ============================ auto-fullscreen JNES when it starts up =========================== AutoMaxJNES: IfWinNotActive, Jnes return ; Keep waiting. WinGetPos, , , W if (W < A_ScreenWidth) { ;MsgBox, %W% %A_ScreenWidth% Send {Alt down}{Enter}{Alt up} } return ; ============================ press keyboard arrow keys when the D-pad is used =========================== WatchJoystickPOV: GetKeyState, POV, JoyPOV ; Get position of the POV control. Key1ToHoldDownPrev = %Key1ToHoldDown% Key2ToHoldDownPrev = %Key2ToHoldDown% ; Each "Prev" variable now holds the key that was down before (if any). if POV < 0 Gosub, WatchJoystickMain ; Some joysticks might have a smooth/continous POV rather than one in fixed increments. ; To support them all, check for ranges: if POV < 0 ; No angle to report { Key1ToHoldDown = Key2ToHoldDown = } else if POV > 33750 ; 337.5 to 360 degrees: Forward { Key1ToHoldDown = Up Key2ToHoldDown = } else if POV between 0 and 2250 ; 0 to 22.5 degrees: Forward { Key1ToHoldDown = Up Key2ToHoldDown = } else if POV between 2251 and 6750 ; Up+Right { Key1ToHoldDown = Up Key2ToHoldDown = Right } else if POV between 6751 and 11250 ; Right { Key1ToHoldDown = Key2ToHoldDown = Right } else if POV between 11251 and 15750 ; Down+Right { Key1ToHoldDown = Down Key2ToHoldDown = Right } else if POV between 15751 and 20250 ; Down { Key1ToHoldDown = Down Key2ToHoldDown = } else if POV between 20251 and 24750 ; Down+Left { Key1ToHoldDown = Down Key2ToHoldDown = Left } else if POV between 24751 and 29250 ; Left { Key1ToHoldDown = Key2ToHoldDown = Left } else if POV between 29251 and 33750 ; Up+Left { Key1ToHoldDown = Up Key2ToHoldDown = Left } SetKeyDelay -1 ; Avoid delays between keystrokes. if Key1ToHoldDown <> %Key1ToHoldDownPrev% ; Key #1 needs adjusting. { if Key1ToHoldDownPrev <> ; There is a previous key to release. SendInput, {%Key1ToHoldDownPrev% up} ; Release it. if Key1ToHoldDown <> ; There is a key to press down. SendInput, {%Key1ToHoldDown% down} ; Press it down. } if Key2ToHoldDown <> %Key2ToHoldDownPrev% ; Key #2 needs adjusting. { if Key2ToHoldDownPrev <> ; There is a previous key to release. SendInput, {%Key2ToHoldDownPrev% up} ; Release it. if Key2ToHoldDown <> ; There is a key to press down. SendInput, {%Key2ToHoldDown% down} ; Press it down. } return ; ============================ press keyboard arrow keys when the analog stick is used under MAME =========================== WatchJoystickMain: ;IfWinNotActive, ahk_class MAME IfWinNotActive, VisualBoyAdvance return ; see http://www.autohotkey.com/docs/scripts/JoystickMouse.htm GetKeyState, joyx, 1JoyX GetKeyState, joyy, 1JoyY joydist := (joyx-50)*(joyx-50) + (joyy-50)*(joyy-50) if joydist > %JoyDeadzone% { if joyx between 49 and 51 { slope := 0 } else { slope := (joyy-50)/(joyx-50) } ; atan, then radians => degrees*100 POV := atan(slope)*5729.74 if joyx < 50 POV := POV + 18000 POV := Mod(Round(POV)+9000,36000) } else { POV = -1 } return ; ============================ Watch for the triggers =========================== ZTriggers: GetKeyState, joyz, 1JoyZ IfWinActive VisualBoyAdvance { ; In VisualBoyAdvance, make the triggers be equivalent to the X and Y keys if joyz < 40 { SendInput {S down} SetTimer, VBA_fire4, 10 } if joyz > 60 { SendInput {A down} SetTimer, VBA_fire3, 10 } } return