MCRC=50647777
MVersion=1.3.8
StartModule(){
Global gameSectionStartTime,gameSectionStartHour,skipChecks,dbName,romPath,romName,romExtension,systemName,MEmu,MEmuV,MURL,MAuthor,MVersion,MCRC,iCRC,MSystem,romMapTable,romMappingLaunchMenuEnabled,romMenuRomName,sevenZEnabled,hideCursor,toggleCursorKey,servoStikEnabled,ledblinkyEnabled,winVer,setResolution,zz
Global mgEnabled,mgOnLaunch,mgCandidate,mgLaunchMenuActive,MultiGame_Running,keyboardEncoder,keyboardEncoderEnabled,ultraMapFullPath,winIPACFullPath
Global rIniIndex,globalPluginsFile,sysPluginsFile
Log("StartModule - Started")
Log("StartModule - MEmu: " . MEmu . "`r`n`t`t`t`t`tMEmuV: " . MEmuV . "`r`n`t`t`t`t`tMURL: " . MURL . "`r`n`t`t`t`t`tMAuthor: " . MAuthor . "`r`n`t`t`t`t`tMVersion: " . MVersion . "`r`n`t`t`t`t`tMCRC: " . MCRC . "`r`n`t`t`t`t`tiCRC: " . iCRC . "`r`n`t`t`t`t`tMID: " . MID . "`r`n`t`t`t`t`tMSystem: " . MSystem)
If InStr(MSystem,systemName)
Log("StartModule - You have a supported System Name for this module: """ . systemName . """")
Else
Log("StartModule - You have an unsupported System Name for this module: """ . systemName . """. Only the following System Names are suppported: """ . MSystem . """",2)
winVer := If A_Is64bitOS ? "64" : "32" ; get windows version
;-----------------------------------------------------------------------------------------------------------------------------------------
; Plugin Specific Settings from Settings \ Global Plugins.ini and Settings \ %systemName% \ Plugins.ini
;-----------------------------------------------------------------------------------------------------------------------------------------
rIniIndex := {} ; initialize the RIni array
globalPluginsFile := A_ScriptDir . "\Settings\Global Plugins.ini"
If !FileExist(globalPluginsFile)
FileAppend,, %globalPluginsFile% ; create blank ini
RIni_Read(8,globalPluginsFile)
rIniIndex[8] := globalPluginsFile ; assign to array
sysPluginsFile := A_ScriptDir . "\Settings\" . systemName . "\Plugins.ini"
If !FileExist(sysPluginsFile)
FileAppend,, %sysPluginsFile% ; create blank ini
RIni_Read(9,sysPluginsFile)
rIniIndex[9] := sysPluginsFile ; assign to array
Gosub, PluginInit ; initialize plugin vars
; Gosub, ReadFEGameInfo ; read plugin data
;-----------------------------------------------------------------------------------------------------------------------------------------
If (mgEnabled = "true" && mgOnLaunch = "true" && mgCandidate) { ; only if user has mgOnLaunch enabled
mgLaunchMenuActive := true
Log("StartModule - MultiGame_On_Launch execution started.",4)
Gosub, StartMulti
Sleep, 200
Loop {
If !MultiGame_Running
Break
}
mgLaunchMenuActive := false
Log("StartModule - MultiGame_On_Launch execution ended.",4)
}
If (romMappingLaunchMenuEnabled = "true" && romMapTable.MaxIndex()) ; && romMapMultiRomsFound)
CreateRomMappingLaunchMenu%zz%(romMapTable)
; msgbox dbName: %dbName%`nromName: %romName%`nromMenuRomName: %romMenuRomName%`nsevenZEnabled: %sevenZEnabled%`nskipChecks: %skipChecks%
If (skipChecks != "false" && romMenuRomName && sevenZEnabled = "false") ; this is to support the scenario where Rom Map Launch Menu can send a rom that does not exist on disk or in the archive (mame clones)
{ Log("StartModule - Setting romName to the game picked from the Launch Menu: " . romMenuRomName,4)
romName := romMenuRomName
} Else If romName && romMapTable.MaxIndex()
{ Log("StartModule - Leaving romName as is because Rom Mapping filled it with an Alternate_Rom_Name: " . romName,4)
romName := romName ; When Rom Mapping is used but no Alternate_Archive_Name key exists yet Alternate_Rom_Name key(s) were used.
} Else If romMapTable.MaxIndex()
{ Log("StartModule - Not setting romName because Launch Menu was used and 7z will take care of it.",4)
romName := "" ; If a romMapTable exists with roms, do not fill romName yet as 7z will take care of that.
} Else
{ Log("StartModule - Setting romName to the dbName sent to RocketLauncher: " . dbName,4)
romName := dbName ; Use dbName if previous checks are false
}
If (setResolution != "")
SetDisplaySettings(setResolution)
If RegExMatch(hideCursor,"i)true|do_not_restore")
SystemCursor("Off")
Else If RegExMatch(hideCursor,"i)custom|custom_do_not_restore") {
cursor := GetRLMediaFiles("Cursors","cur|ani") ;load cursor file for the system if they exist
If cursor
SetSystemCursor(Cursor) ; replace system cursors
}
If toggleCursorKey
XHotKeywrapper(toggleCursorKey,"ToggleCursor")
If (ledblinkyEnabled = "All")
LEDBlinky("START")
KeymapperProfileSelect("START", keyboardEncoder, %keyboardEncoder%FullPath, "ipc", "keyboard")
KeymapperProfileSelect("START", "UltraMap", ultraMapFullPath, "ugc")
If (servoStikEnabled = 4 || servoStikEnabled = 8)
ServoStik(servoStikEnabled) ; handle servostiks on start
; romName := If romName ? romName : If romMapTable.MaxIndex() ? "" : dbName ; OLD METHOD, keeping this here until the split apart conditionals have been tested enough. ; if romName was filled at some point, use it, Else If a romMapTable exists with roms, do not fill romName yet as 7z will take care of that. Use dbName if previous checks are false
Gui, show,Hide,RocketLauncherMessageReceiver ; creating hidden GUI to receive RocketLauncher messages
OnMessage(0x4a, "ReceiveMessage")
BroadcastMessage("RocketLauncher Message: Welcome! :)")
gameSectionStartTime := A_TickCount
gameSectionStartHour := A_Now
; msgbox % "romPath: " . romPath . "`nromName: " . romName . "`nromExtension: " . romExtension . "`nromMenuRomName: " . romMenuRomName . "`nromMapTable.MaxIndex(): " . romMapTable.MaxIndex()
Log("StartModule - Ended")
}
; ExitModule function in case we need to call anything on the module's exit routine, like UpdateStatistics for Pause or UnloadKeymapper
ExitModule(){
Global statisticsEnabled,keymapperEnabled,keymapper,keymapperAHKMethod,keymapperLoaded,logShowCommandWindow,pToken,cmdWindowObj,mouseCursorHidden,cursor,hideCursor,rocketLauncherIsExiting,servoStikExitMode,ledblinkyEnabled,zz
Global JoyIDsEnabled,JoyIDsPreferredControllersOnExit,keyboardEncoder,keyboardEncoderEnabled,ultraMapFullPath,winIPACFullPath
Log("ExitModule - Started")
rocketLauncherIsExiting := 1 ; notifies rest of the thread that the exit routine was triggered
If (statisticsEnabled = "true")
Gosub, UpdateStatistics
If (keymapperEnabled = "true" && keymapperLoaded)
RunKeyMapper%zz%("unload",keymapper)
If keymapperAHKMethod = External
RunAHKKeymapper%zz%("unload")
If (JoyIDsEnabled = "true" && JoyIDsPreferredControllersOnExit)
LoadPreferredControllers%zz%(JoyIDsPreferredControllersOnExit)
If (hideCursor = "custom" and cursor)
RestoreCursors() ; retore default system cursors
If mouseCursorHidden ; just in case
SystemCursor("On")
If (ledblinkyEnabled = "All")
LEDBlinky("END")
KeymapperProfileSelect("END", keyboardEncoder, %keyboardEncoder%FullPath, "ipc", "keyboard")
KeymapperProfileSelect("END", "UltraMap", ultraMapFullPath, "ugc")
If (servoStikExitMode = 4 || servoStikExitMode = 8)
ServoStik(servoStikExitMode) ; handle servostiks on exit
If logShowCommandWindow = true
Loop {
If !cmdWindowObj[A_Index,"Name"]
Break
Else {
Log("ExitModule - Closing command window: " . cmdWindowObj[A_Index,"Name"] . " PID: " . cmdWindowObj[A_Index,"PID"],4)
Process("Close", cmdWindowObj[A_Index,"Name"]) ; close each opened cmd.exe
}
}
BroadcastMessage("RocketLauncher Message: Goodbye! :(")
Gdip_Shutdown(pToken) ; gdi+ may now be shutdown on exiting the thread
Log("ExitModule - Ended")
Log("End of Module Logs",,,1)
ExitApp
}
WinWait(winTitle,winText="",secondsToWait=30,excludeTitle="",excludeText=""){
Global detectFadeErrorEnabled, logLevel
If logLevel > 3
GetActiveWindowStatus()
Log("WinWait - Waiting for """ . winTitle . """")
WinWait, %winTitle% ,%winText% , %secondsToWait% , %excludeTitle% ,%excludeText%
curErr := ErrorLevel ; have to store this because GetActiveWindowStatus will reset it
If logLevel > 3
GetActiveWindowStatus()
If (curErr and detectFadeErrorEnabled = "true")
ScriptError("There was an error waiting for the window """ . winTitle . """. Please check you have the correct version emulator installed for this module, followed any notes in the module, and have this emulator working outside your Frontend first. Also turn off Fade to see if you are hiding your problem.",10)
Else If (curErr and detectFadeErrorEnabled != "true")
Log("There was an error waiting for the window """ . winTitle . """. Please check you have the correct version emulator installed for this module, followed any notes in the module, and have this emulator working outside your Frontend first. Also turn off Fade to see if you are hiding your problem.",3)
Return curErr
}
WinWaitActive(winTitle,winText="",secondsToWait=30,excludeTitle="",excludeText=""){
Global detectFadeErrorEnabled, logLevel, emulatorProcessID, emulatorVolumeObject, emulatorInitialMuteState, fadeMuteEmulator, fadeIn
If (logLevel > 3)
GetActiveWindowStatus()
Log("WinWaitActive - Waiting for """ . winTitle . """")
WinWaitActive, %winTitle% ,%winText% , %secondsToWait% , %excludeTitle% ,%excludeText%
curErr := ErrorLevel ; have to store this because GetActiveWindowStatus will reset it
If (logLevel > 3)
GetActiveWindowStatus()
If (curErr and detectFadeErrorEnabled = "true")
ScriptError("There was an error waiting for the window """ . winTitle . """ to become active. Please check you have the correct version emulator installed for this module, followed any notes in the module, and have this emulator working outside your Frontend first. Also turn off Fade to see if you are hiding your problem.",10)
Else If (curErr and detectFadeErrorEnabled != "true")
Log("There was an error waiting for the window """ . winTitle . """ to become active. Please check you have the correct version emulator installed for this module, followed any notes in the module, and have this emulator working outside your Frontend first. Also turn off Fade to see if you are hiding your problem.",3)
If !curErr
{
WinGet emulatorProcessID, PID, %winTitle%
emulatorVolumeObject := GetVolumeObject(emulatorProcessID)
If ((fadeMuteEmulator = "true") and (fadeIn = "true")){
getMute(emulatorInitialMuteState, emulatorVolumeObject)
setMute(1, emulatorVolumeObject)
}
}
Return curErr
}
WinWaitClose(winTitle,winText="",secondsToWait="",excludeTitle="",excludeText=""){
Log("WinWaitClose - Waiting for """ . winTitle . """ to close")
WinWaitClose, %winTitle% ,%winText% , %secondsToWait% , %excludeTitle% ,%excludeText%
Return ErrorLevel
}
WinClose(winTitle,winText="",secondsToWait="",excludeTitle="",excludeText=""){
Log("WinClose - Closing: " . winTitle)
WinClose, %winTitle%, %winText% , %secondsToWait%, %excludeTitle%, %excludeText%
If (secondsToWait = "" || !secondsToWait)
secondsToWait := 2 ; need to always have some timeout for this command otherwise it will wait forever
WinWaitClose, %winTitle%, %winText% , %secondsToWait%, %excludeTitle%, %excludeText% ; only WinWaitClose reports an ErrorLevel
Return ErrorLevel
}
RunWait(target,workingDir="",options=0,ByRef outputVarPID=""){
Global errorLevelReporting
options := If options = 1 ? "useErrorLevel" : options ; enable or disable error level
Log("RunWait - Started - running: " . workingDir . "\" . target)
RunWait, %target%, %workingDir%, %options%, outputVarPID
curErr := ErrorLevel ; store error level immediately
Log("RunWait - """ . target . """ Process ID: " . outputVarPID . " and ErrorLevel reported as: " . curErr, 4)
Return curErr
}
; To disable inputBlocker on a specific Run call, set inputBlocker to 0, or to force it a specified amount of seconds (upto 30), set it to that amount.
; By default, options will enable all calls of Run() to return errorlevel within the function. However, it will only be returned if errorLevelReporting is true
; bypassCmdWindow - some apps will never work with the command window, like xpadder. enable this argument on these Run calls so it doesn't get caught here
Run(target,workingDir="",options=0,ByRef outputVarPID="",inputBlocker=1,bypassCmdWindow=0,disableLogging=0){
Static cmdWindowCount
Global logShowCommandWindow,logCommandWindow,cmdWindowObj,blockInputTime,blockInputFile,errorLevelReporting
options := If options = 1 ? "useErrorLevel" : options ; enable or disable error level
If disableLogging
Log("Run - Running hidden executable in " . workingDir)
Else
Log("Run - Running: " . workingDir . "\" . target)
If (blockInputTime && inputBlocker = 1) ; if user set a block time, use the user set length
blockTime := blockInputTime
Else If (inputBlocker > 1) ; if module called for a block, use that amount
blockTime := inputBlocker
Else ; do not block input
blockTime := ""
If blockTime
{ Log("Run - Blocking Input for: " . blockTime . " seconds")
Run, %blockInputFile% %blockTime%
}
If !cmdWindowObj
cmdWindowObj := Object() ; initialize object, this is used so all the command windows can be properly closed on exit
If (logShowCommandWindow = "true" && !bypassCmdWindow) {
Run, %ComSpec% /k, %workingDir%, %options%, outputVarPID ; open a command window (cmd.exe), starting in the directory of the target executable
curErr := ErrorLevel ; store error level immediately
If errorLevelReporting = true
{ Log("Run - Error Level for " . ComSpec . " reported as: " . curErr, 4)
errLvl := curErr ; allows the module to handle the error level
}
Log("Run - Showing Command Window to troubleshoot launching. ProcessID: " . outputVarPID)
WinWait, ahk_pid %outputVarPID%
WinActivate, ahk_pid %outputVarPID%
WinWaitActive, ahk_pid %outputVarPID%,,2
If ErrorLevel {
WinSet, AlwaysOnTop, On, ahk_pid %outputVarPID%
WinActivate, ahk_pid %outputVarPID%
WinWaitActive, ahk_pid %outputVarPID%,,2
If ErrorLevel
ScriptError("Could not put focus onto the command window. Please try turning off Fade In if you have it enabled in order to see it")
}
WinGet, procName, ProcessName, ahk_pid %outputVarPID% ; get the name of the process (which should usually be cmd.exe)
mapObjects[currentObj,"type"] := "database"
cmdWindowCount++
cmdWindowObj[cmdWindowCount,"Name"] := procName ; store the ProcessName being ran
cmdWindowObj[cmdWindowCount,"PID"] := outputVarPID ; store the PID of the application being ran
foundPos := RegExMatch(target,".*\.(exe|bat)",targetExeOnly) ; grab only the exe or bat file from the supplied target
exeLen := StrLen(targetExeOnly) ; get length of exe name
params := SubStr(target, exeLen+1) ; grab optional params out of supplied target
If InStr(targetExeOnly, A_Space)
target := """" . targetExeOnly . """" . params
If (logCommandWindow = "true")
SendInput, {Raw}%target% 1>"%A_ScriptDir%\command_%cmdWindowCount%_output.log" 2>"%A_ScriptDir%\command_%cmdWindowCount%_error.log" ; send the text to the command window and log the output to file
Else
SendInput, {Raw}%target% ; send the text to the command window and run it
Send, {Enter}
} Else {
Run, %target%, %workingDir%, %options%, outputVarPID
curErr := ErrorLevel ; store error level immediately
If errorLevelReporting = true
{ Log("Run - Error Level for " . target . " reported as: " . curErr, 4)
errLvl := curErr ; allows the module to handle the error level
}
}
If disableLogging
Log("Run - ""Hidden executable"" Process ID: " . outputVarPID, 4)
Else
Log("Run - """ . target . """ Process ID: " . outputVarPID, 4)
Return errLvl
}
Process(cmd,name,param=""){
Log("Process - " . cmd . A_Space . name . A_Space . param)
Process, %cmd%, %name%, %param%
Return ErrorLevel
}
SetKeyDelay(delay="",pressDur="",play="") {
Global pressDuration
If (delay = "") ; -1 is the default delay for play mode and 10 for event mode when none is supplied
delay := (If play = "" ? 10 : -1)
If (pressDur = "") ; -1 is the default pressDur when none is supplied
pressDur := -1
Log("SetKeyDelay - Current delay is " . A_KeyDelay . ". Current press duration is " . pressDuration . ". Delay will now be set to """ . delay . """ms for a press duration of """ . pressDur . """", 4)
SetKeyDelay, %delay%, %pressDur%, %play%
pressDuration := pressDur ; this is so the current pressDuration can be monitored outside the function
}
; Replaces standard ahk IniRead calls
; Will not let ERROR be returned, returns no value instead
; If errormsg is set, will trigger ScriptError instead of returning no or default value
IniRead(file,section,key,defaultvalue="",errorMsg="") {
Log("IniRead - SECTION: [" . section . "] - KEY: " . key . " - VALUE: " . value . " - FILE: " . file,4)
IniRead, v, %file%, %section%, %key%, %defaultvalue%
If (v = "ERROR" || v = A_Space) { ; if key does not exist or is a space, delete ERROR as the value
If errorMsg
ScriptError(errorMsg)
Else {
If defaultValue = %A_Space% ; this prevents the var from existing when it's actually blank
defaultValue := ""
Return defaultValue
}
}
Return v
}
; Replaces standard ahk IniWrite calls
; compare = if used, only writes new value if existing value differs
IniWrite(value,file,section,key,compare="") {
If compare {
IniRead, v, %file%, %section%, %key%
If (v != value) {
IniWrite, %value%, %file%, %section%, %key%
err := ErrorLevel
Log("IniWrite - ini updated due to differed value. SECTION: [" . section . "] - KEY: " . key . " - Old: " . v . " | New: " . value)
} Else
Log("IniWrite - ini value already correct. SECTION: [" . section . "] - KEY: " . key . " - Value: " . value,4)
} Else {
IniWrite, %value%, %file%, %section%, %key%
err := ErrorLevel
Log("IniWrite - SECTION: [" . section . "] - KEY: " . key . " - VALUE: " . value . " - FILE: " . file)
}
If err
Log("IniWrite - There was an error writing to the ini",3)
Return err ; returns 1 if there was an error
}
; Mainly used in modules to read module.ini settings so multiple sections of an ini can be read of the same key name
; section: Allows | separated values so multiple sections can be checked.
IniReadCheck(file,section,key,defaultvalue="",errorMsg="",logType="") {
Loop, Parse, section, |
{ section%A_Index% := A_LoopField ; keep each parsed section in its own var
If iniVar != "" ; if last loop's iniVar has a value, update this loop's default value with it
defaultValue := If A_Index = 1 ? defaultValue : iniVar ; on first loop, default value will be the one sent to the function, on following loops it gets the value from the previous loop
IniRead, iniVar, %file%, % section%A_Index%, %key%, %defaultvalue%
If (IniVar = "ERROR" || iniVar = A_Space) ; if key does not exist or is a space, delete ERROR as the value
iniVar := ""
If (A_Index = 1 && iniVar = "" and !logType) {
If errorMsg
ScriptError(errorMsg)
Else
IniWrite, %defaultValue%, %file%, % section%A_Index%, %key%
Return defaultValue
}
If logType ; only log if logType set
{ logAr := ["Module","Bezel"]
Log(logAr[logType] . " Setting - [" . section%A_Index% . "] - " . key . ": " . iniVar)
}
If (iniVar != "") ; if IniVar contains a value, update the lastIniVar
lastIniVar := iniVar
}
If defaultValue = %A_Space% ; this prevents the var from existing when it's actually blank
defaultValue := ""
Return If A_Index = 1 ? iniVar : If lastIniVar != "" ? lastIniVar : defaultValue ; if this is the first loop, always return the iniVar. If any other loop, return the lastinivar if it was filled, otherwise send the last updated defaultvalue
}
MaximizeWindow(WinTitle, keepAspectRatio="true", removeTitle="true", removeBorder="true", removeToggleMenu="true") {
If (removeTitle = "true")
WinSet, Style, -0xC00000, %WinTitle% ;Removes the titlebar of the game window
If (removeBorder = "true")
WinSet, Style, -0x40000, %WinTitle% ;Removes the border of the game window
If (removeToggleMenu = "true") {
WinGet, WinID, ID, %WinTitle%
ToggleMenu(WinID)
}
If (keepAspectRatio = "true") {
WinGetPos, appX, appY, appWidth, appHeight, %WinTitle%
widthMaxPercenty := ( A_ScreenWidth / appWidth )
heightMaxPercenty := ( A_ScreenHeight / appHeight )
If ( widthMaxPercenty < heightMaxPercenty )
percentToEnlarge := widthMaxPercenty
Else
percentToEnlarge := heightMaxPercenty
appWidthNew := appWidth * percentToEnlarge
appHeightNew := appHeight * percentToEnlarge
Transform, appY, Round, %appY%
Transform, appWidthNew, Round, %appWidthNew%, 2
Transform, appHeightNew, Round, %appHeightNew%, 2
appXPos := ( A_ScreenWidth / 2 ) - ( appWidthNew / 2 )
appYPos := ( A_ScreenHeight / 2 ) - ( appHeightNew / 2 )
}
Else {
appXPos := 0
appYPos := 0
appWidthNew := A_ScreenWidth
appHeightNew := A_ScreenHeight
}
MoveWindow(WinTitle,appXPos,appYPos,appWidthNew,appHeightNew)
}
MoveWindow(winTitle,X,Y,W,H,timeLimit=2000,ignoreWin=""){ ; assures that a window is moved to the desired position within a timeout
Log("MoveWindow - Moving window " . winTitle . " to X=" . X . ", Y=" . Y . ", W=" . W . " H=" . H, 4)
WinMove, % winTitle, , %X%, %Y%, %W%, %H%, %ignoreWin%
;check If window moved
timeout := A_TickCount
Loop
{ WinGetPos, Xgot, Ygot, Wgot, Hgot, %winTitle%,, %ignoreWin%
If ((Xgot=X) and (Ygot=Y) and (Wgot=W) and (Hgot=H)){
Log("MoveWindow - Successful: Window " . winTitle . " moved to X=" . X . ", Y=" . Y . ", W=" . W . " H=" . H, 4)
error := 0
Break
}
If (timeout<A_TickCount-timeLimit){
Log("MoveWindow - Failed: Window " . winTitle . " at X=" . Xgot . ", Y=" . Ygot . ", W=" . Wgot . " H=" . Hgot, 4)
error := 1
Break
}
Sleep, 200
WinMove, %winTitle%,, %X%, %Y%, %W%, %H%, %ignoreWin%
}
Return error
}
; Purpose: Handle an emulators Open Rom window when CLI is not an option
; Returns 1 when successful
OpenROM(windowName,selectedRomName) {
Log("OpenROM - Started")
Global MEmu,moduleName
WinWait(windowName)
WinWaitActive(windowName)
state := 0
Loop, 150 ; 15 seconds
{ ControlSetText, Edit1, %selectedRomName%, %windowName%
ControlGetText, edit1Text, Edit1, %windowName%
If (edit1Text = selectedRomName) {
state := 1
Log("OpenROM - Successfully set romName into """ . windowName . """ in " . A_Index . " " . (If A_Index = 1 ? "try." : "tries."),4)
Break
}
Sleep, 100
}
If (state != 1)
ScriptError("Tried for 15 seconds to send the romName to " . MEmu . " but was unsuccessful. Please try again with Fade and Bezel disabled and put the " . moduleName . " in windowed mode to see if the problem persists.", 10)
PostMessage, 0x111, 1,,, %windowName% ; Select Open
Log("OpenROM - Ended")
Return %state%
}
GetActiveWindowStatus(){
dWin := A_DetectHiddenWindows ; store current value to return later
DetectHiddenWindows, On
activeWinHWND := WinExist("A")
WinGet, procPath, ProcessPath, ahk_id %activeWinHWND%
WinGet, procID, PID, ahk_id %activeWinHWND%
WinGet, winState, MinMax, ahk_id %activeWinHWND%
WinGetClass, winClass, ahk_id %activeWinHWND%
WinGetTitle, winTitle, ahk_id %activeWinHWND%
WinGetPos, X, Y, W, H, ahk_id %activeWinHWND%
Log("GetActiveWindowStatus - Title: " . winTitle . " | Class: " . winClass . " | State: " . winState . " | X: " . X . " | Y: " . Y . " | Width: " . W . " | Height: " . H . " | Window HWND: " . activeWinHWND . " | Process ID: " . procID . " | Process Path: " . procPath, 4)
DetectHiddenWindows, %dWin% ; restore prior state
}
; CheckFile Usage:
; file = file to be checked if it exists
; msg = the error msg you want displayed on screen if you don't want the default "file not found"
; timeout = gets passed to ScriptError(), the amount of time you want the error to show on screen
; crc = If this is a an AHK library only, provide a crc so it can be validated
; crctype = default empty and crc is not checked. Use 0 for AHK libraries and RocketLauncher extension files. Use 1 for module crc checks..
; logerror = default empty will give a log error instead of stopping with a scripterror
; allowFolder = allows folders or files w/o an extension to be checked. By default a file must have an extension.
CheckFile(file,msg="",timeout=6,crc="",crctype="",logerror="",allowFolder=0){
Global RLObject,logIncludeFileProperties
exeFileInfo := "
( LTrim
FileDescription
FileVersion
InternalName
LegalCopyright
OriginalFilename
ProductName
ProductVersion
CompanyName
PrivateBuild
SpecialBuild
LegalTrademarks
)"
Log("CheckFile - Checking if " . file . " exists")
SplitPath, file, fileName, filePath, fileExt, fileNameNoExt
If !FileExist(filePath . "\" . fileName)
If FileExist(filePath . "\" . fileNameNoExt . " (Example)." . fileExt) {
FileCopy, %filePath%\%fileNameNoExt% (Example).%fileExt%, %filePath%\%fileName%
If ErrorLevel
Log("CheckFile - Found an example for this file, but did not have permissions to retore it: " . filePath . "\" . fileNameNoExt . " (Example)." . fileExt,3)
Else
Log("CheckFile - Restored this file from its example: " . filePath . "\" . fileNameNoExt . " (Example)." . fileExt,2)
} Else {
If msg
ScriptError(msg, timeout)
Else
ScriptError("Cannot find " . file, timeout)
}
If (!fileExt && !allowFolder)
ScriptError("This is a folder and must point to a file instead: " . file, timeout)
If (crctype = 0 Or crctype = 1) {
CRCResult := RL_checkModuleCRC("" . file . "",crc,crctype)
If (CRCResult = -1)
Log("CRC Check - " . (If crctype=1 ? "Module" : If (crctype=0 && crc) ? "Library" : "Extension") . " file not found.",3)
Else If (CRCResult = 0)
If (crctype = 1)
Log("CRC Check - CRC does not match official module and will not be supported. Continue using at your own risk.",2)
Else If logerror
Log("CRC Check - CRC does not match for this " . (If (crctype=0 && crc) ? "Library" : "Extension") . ". Please re-download this file to continue using RocketLauncher: " . file,3)
Else
ScriptError("CRC Check - CRC does not match for this " . (If (crctype=0 && crc) ? "Library" : "Extension") . ". Please re-download this file to continue using RocketLauncher: " . file)
Else If (CRCResult = 1)
Log("CRC Check - CRC matches, this is an official unedited " . (If crctype=1 ? "Module" : If (crctype=0 && crc) ? "Library" : "Extension") . ".",4)
Else If (CRCResult = 2)
Log("CRC Check - No CRC defined on the header for: " . file,3)
}
If (logIncludeFileProperties = "true")
{ If exeAtrib := FileGetVersionInfo_AW(file, exeFileInfo, "`n")
Loop, Parse, exeAtrib, `n
logTxt .= (If A_Index=1 ? "":"`n") . "`t`t`t`t`t" . A_LoopField
FileGetSize, fileSize, %file%
FileGetTime, fileTimeC, %file%, C
FormatTime, fileTimeC, %fileTimeC%, M/d/yyyy - h:mm:ss tt
FileGetTime, fileTimeM, %file%, M
FormatTime, fileTimeM, %fileTimeM%, M/d/yyyy - h:mm:ss tt
logTxt .= (If logTxt ? "`r`n":"") . "`t`t`t`t`tFile Size:`t`t`t" . fileSize . " bytes"
logTxt .= "`r`n`t`t`t`t`tCreated:`t`t`t" . fileTimeC
logTxt .= "`r`n`t`t`t`t`tModified:`t`t`t" . fileTimeM
Log("CheckFile - Attributes:`r`n" . logTxt,4)
}
Return %file%
}
CheckFolder(folder,msg="",timeout=6,crc="",crctype="",logerror="") {
Return CheckFile(folder,msg,timeout,crc,crctype,logerror,1)
}
; ScriptError usage:
; error = error text
; timeout = duration in seconds error will show
; w = width of error box
; h = height of error box
; txt = font size
ScriptError(error,timeout=6,w=800,h=225,txt=20,noexit=""){
Global RLMediaPath,exitEmulatorKey,RLFile,RLErrSoundPath,logShowCommandWindow,cmdWindowObj,scriptErrorTriggered
Global screenRotationAngle,baseScreenWidth,baseScreenHeight,xTranslation,yTranslation,XBaseRes,YBaseRes
XHotKeywrapper(exitEmulatorKey,"CloseProcess","OFF")
XHotKeywrapper(exitEmulatorKey,"CloseError","ON")
Hotkey, Esc, CloseError
Hotkey, Enter, CloseError
If !pToken := Gdip_Startup(){ ; Start gdi+
MsgBox % "Gdiplus failed to start. Please ensure you have gdiplus on your system"
ExitApp
}
timeout *= 1000 ; converting to seconds
;Acquiring screen info for dealing with rotated menu drawings
Gdip_Alt_GetRotatedDimensions(A_ScreenWidth, A_ScreenHeight, screenRotationAngle, baseScreenWidth, baseScreenHeight)
Gdip_GetRotatedTranslation(baseScreenWidth, baseScreenHeight, screenRotationAngle, xTranslation, yTranslation)
xTranslation:=round(xTranslation), yTranslation:=round(yTranslation)
XBaseRes := 1920, YBaseRes := 1080
If (((A_screenWidth < A_screenHeight) and ((screenRotationAngle=0) or (screenRotationAngle=180))) or ((A_screenWidth > A_screenHeight) and ((screenRotationAngle=90) or (screenRotationAngle=270))))
XBaseRes := 1080, YBaseRes := 1920
If !errorXScale
errorXScale := baseScreenWidth/XBaseRes
If !errorYScale
errorYScale := baseScreenHeight/YBaseRes
Error_Warning_Width := w
Error_Warning_Height := h
Error_Warning_Pen_Width := 7
Error_Warning_Rounded_Corner := 30
Error_Warning_Margin := 30
Error_Warning_Bitmap_Size := 125
Error_Warning_Text_Size := txt
OptionScale(Error_Warning_Width, errorXScale)
OptionScale(Error_Warning_Height, errorYScale)
OptionScale(Error_Warning_Pen_Width, errorXScale)
OptionScale(Error_Warning_Rounded_Corner, errorXScale)
OptionScale(Error_Warning_Margin, errorXScale)
OptionScale(Error_Warning_Bitmap_Size, errorXScale)
OptionScale(Error_Warning_Text_Size, errorYScale)
;Create error GUI
Gui, Error_GUI: +Disabled -Caption +E0x80000 +OwnDialogs +LastFound +ToolWindow +AlwaysOnTop
Gui, Error_GUI: Margin,0,0
Gui, Error_GUI: Show,, ErrorLayer
Error_hwnd := WinExist()
Error_hbm := CreateDIBSection(A_ScreenWidth, A_ScreenHeight)
Error_hdc := CreateCompatibleDC()
Error_obm := SelectObject(Error_hdc, Error_hbm)
Error_G := Gdip_GraphicsFromhdc(Error_hdc)
Gdip_SetSmoothingMode(Error_G, 4)
Gdip_TranslateWorldTransform(Error_G, xTranslation, yTranslation)
Gdip_RotateWorldTransform(Error_G, screenRotationAngle)
pGraphUpd(Error_G,baseScreenWidth, baseScreenHeight)
;Create GUI elements
pBrush := Gdip_BrushCreateSolid("0xFF000000") ; Painting the background color
Gdip_Alt_FillRectangle(Error_G, pBrush, -1, -1, baseScreenWidth+1, baseScreenHeight+1) ; draw the background first on layer 1 first, layer order matters!!
brushWarningBackground := Gdip_CreateLineBrushFromRect(0, 0, Error_Warning_Width, Error_Warning_Height, 0xff555555, 0xff050505)
penWarningBackground := Gdip_CreatePen(0xffffffff, Error_Warning_Pen_Width)
Gdip_Alt_FillRoundedRectangle(Error_G, brushWarningBackground, (baseScreenWidth - Error_Warning_Width)//2, (baseScreenHeight - Error_Warning_Height)//2, Error_Warning_Width, Error_Warning_Height, Error_Warning_Rounded_Corner)
Gdip_Alt_DrawRoundedRectangle(Error_G, penWarningBackground, (baseScreenWidth - Error_Warning_Width)//2, (baseScreenHeight - Error_Warning_Height)//2, Error_Warning_Width, Error_Warning_Height, Error_Warning_Rounded_Corner)
WarningBitmap := Gdip_CreateBitmapFromFile(RLMediaPath . "\Menu Images\RocketLauncher\Warning.png")
Gdip_Alt_DrawImage(Error_G,WarningBitmap, round((baseScreenWidth - Error_Warning_Width)//2 + Error_Warning_Margin),round(baseScreenHeight/2 - Error_Warning_Bitmap_Size/2),Error_Warning_Bitmap_Size,Error_Warning_Bitmap_Size)
Gdip_Alt_TextToGraphics(Error_G, error, "x" round((baseScreenWidth-Error_Warning_Width)//2+Error_Warning_Bitmap_Size+Error_Warning_Margin) " y" round((baseScreenHeight-Error_Warning_Height)//2+Error_Warning_Margin) " Left vCenter cffffffff r4 s" Error_Warning_Text_Size " Bold",, round((Error_Warning_Width - 2*Error_Warning_Margin - Error_Warning_Bitmap_Size)) , round((Error_Warning_Height - 2*Error_Warning_Margin)))
startTime := A_TickCount
Loop{ ; fade in
t := ((TimeElapsed := A_TickCount-startTime) < 300) ? (255*(timeElapsed/300)) : 255
Alt_UpdateLayeredWindow(Error_hwnd,Error_hdc, 0, 0, baseScreenWidth, baseScreenHeight,t)
If (t >= 255)
Break
}
; Generate a random sound to play on a script error
erSoundsAr:=[] ; initialize the array to store error sounds
Loop, %RLErrSoundPath%\error*.mp3
erSoundsAr.Insert(A_LoopFileName) ; insert each found error sound into an array
Random, erRndmSound, 1, % erSoundsAr.MaxIndex() ; randomize what sound to play
Log("ScriptError - Playing error sound: " . erSoundsAr[erRndmSound],4)
setMute(0,emulatorVolumeObject)
SoundPlay % If erSoundsAr.MaxIndex() ? (RLErrSoundPath . "\" . erSoundsAr[erRndmSound]):("*-64"), wait ; play the random sound if any exist, or default to the Asterisk windows sound
If noexit { ; do not close thread, continue with script and let it handle the exiting
scriptErrorTriggered := 1
Return
}
7zCleanUp() ; clean up 7z if necessary
Sleep, %timeout%
CloseError:
endTime := A_TickCount
Loop { ; fade out
t := ((TimeElapsed := A_TickCount-endTime) < 300) ? (255*(1-timeElapsed/300)) : 0
Alt_UpdateLayeredWindow(Error_hwnd,Error_hdc, 0, 0, baseScreenWidth, baseScreenHeight,t)
If (t <= 0)
Break
}
XHotKeywrapper(exitEmulatorKey,"CloseError","OFF")
XHotKeywrapper(exitEmulatorKey,"CloseProcess","ON")
Gdip_DeleteBrush(pBrush)
Gdip_DisposeImage(WarningBitmap), SelectObject(Error_hdc, Error_obm), DeleteObject(Error_hbm), DeleteDC(Error_hdc), Gdip_DeleteGraphics(Error_G)
Gui, ErrorGUI_10: Destroy
Log("ScriptError - " . error,3)
ExitModule() ; attempting to use this method which has the small chance to cause an infinite ScriptError loop, but no need to duplicate code to clean up on errors
; Below cleanup exists because we can't call other functions that may cause additional scripterrors and put the thread in an infinite loop
; If logShowCommandWindow = true
; { for index, element in cmdWindowObj
; Process, Close, % cmdWindowObj[A_Index,1] ; close each opened cmd.exe
; }
; ExitApp
}
; Log usage:
; text = text I want to log
; lvl = the lvl to log the text at
; notime = only used for 1st and last lines of the log so a time is not inserted when I inset the BBCode [code] tags. Do not use this param
; dump = tells the function to write the log file at the end. Do not use this param
; firstLog = tells the function to not insert a time when the first log is made, instead puts an N/A. Do not use this param
; Log() in the module thread requires `r`n at the end of each line, where it's not needed in the RocketLauncher thread
Log(text,lvl=1,notime="",dump="",firstLog=""){
Static log
Static lastLog
Global logFile,logLevel,logLabel,logShowDebugConsole
; Global executable
If (logLevel > 0)
{
If (lvl<=logLevel || lvl=3){ ; ensures errors are always logged
logDiff := A_TickCount - lastLog
lastLog := A_TickCount
log := log . (If notime?"" : A_Hour . ":" . A_Min ":" . A_Sec ":" . A_MSec . " | MD | " . logLabel[lvl] . A_Space . " | +" . AlignColumn(If firstLog ? "N/A" : logDiff) . "" . " | ") . text . "`r`n"
}
If (logShowDebugConsole = "true")
DebugMessage(log)
If (logLevel>=10 || dump){
FileAppend,%log%,%logFile%
log := ""
}
; Process, Exist, %executable%
; If ErrorLevel
; Log .= "mame exists`r`n"
Return log
}
}
; Inserts extra characters/spaces into sections of the Log file to keep it aligned.
; Usage: inserts char x number of times on the end of txt until pad is reached.
AlignColumn(txt,pad=9,char=" "){
x := If char=" "?2:1 ; if char is a space, let's only insert half as many so it looks slightly more even in notepad++
Loop {
n := StrLen(txt)
If (n*x >= pad)
Break
txt := txt . char
}
Return txt
}
; Rini returns -2 if section does not exist
; Rini returns -3 if key does not exist
; Rini returns -10 if an invalid reference var for the ini file was used
; Rini returns empty value if key exists with no value
; rIniIndex := Object(1,globalRLFile,2,sysRLFile,3,globalEmuFile,4,sysEmuFile,5,RLFile,6,gamesFile)
; preferDefault - On rare occasions we may want to set a default value w/o wanting rini to return an error value of -2 or -3. Used for JoyIDs_Preferred_Controllers
RIniLoadVar(gRIniVar,sRIniVar,section,key,gdefaultvalue="",sdefaultvalue="use_global",preferDefault="") {
Global rIniIndex
If (gRIniVar != 6) ; do not create missing sections or keys for games.ini
{ gValue := RIni_GetKeyValue(gRIniVar,section,key,If preferDefault ? gdefaultvalue : "")
gValue := gValue ; trims whitespace
If RegExMatch(gValue,"-2|-3") ; if global ini key does not exist, create the key
{ RIni_SetKeyValue(gRIniVar,section,key,gdefaultvalue)
RIni_Write(gRIniVar,rIniIndex[gRIniVar],"`r`n",1,1,1)
gValue := gdefaultvalue ; set to default value because it did not exist
Log("RIniLoadVar - Created missing Global ini key: """ . key . """ in section: """ . section . """ in """ . rIniIndex[gRIniVar] . """",2)
}
If sRIniVar ; != "" ; only create system sections or keys for inis that use them
{ sValue := RIni_GetKeyValue(sRIniVar,section,key,If preferDefault ? sdefaultvalue : "")
sValue := sValue ; trims whitespace
If RegExMatch(sValue,"-2|-3") ; if system ini key does not exist, create the key
{ RIni_SetKeyValue(sRIniVar,section,key,sdefaultvalue)
RIni_Write(sRIniVar,rIniIndex[sRIniVar],"`r`n",1,1,1)
sValue := sdefaultvalue ; set to default value because it did not exist
Log("RIniLoadVar - Created missing System ini key: """ . key . """ in section: """ . section . """ in """ . rIniIndex[sRIniVar] . """",2)
}
Return If sValue = "use_global" ? gValue : sValue ; now compare global & system keys to get final value
}
Return gValue ; return gValue when not using globa/system inis, like RLFile (rIniIndex 5)
}
iniVar := RIni_GetKeyValue(gRIniVar,section,key,gdefaultvalue) ; lookup key from ini and return it
iniVar := iniVar ; trims whitespace
Return iniVar
}
RIniReadCheck(rIniVar,section,key,defaultvalue="",errorMsg="") {
Global rIniIndex
iniVar := RIni_GetKeyValue(rIniVar,section,key) ; lookup key from ini and return it
iniVar := iniVar ; trims whitespace
If (iniVar = -2 or iniVar = -3 or iniVar = "") {
If (iniVar != "") { ; with rini, no need write to ini file if value is returned empty, we already know the section\key exists with no value
Log("RIniReadCheck - Created missing RocketLauncher ini key: """ . key . """ in section: """ . section . """ in """ . rIniIndex[rIniVar] . """",2)
RIni_SetKeyValue(rIniVar,section,key,defaultvalue)
RIni_Write(rIniVar,rIniIndex[rIniVar],"`r`n",1,1,1) ; write blank section, blank key, and space between sections
}
If errorMsg
ScriptError(errorMsg)
Return defaultValue
}
Return iniVar
}
CheckFont(font) {
If !(Gdip_FontFamilyCreate(font))
ScriptError("The Font """ . font . """ is not installed on your system. Please install the font or change it in RocketLauncherUI.")
}
; Toggles hiding/showing a MenuBar
; Usage: Provide the window's PID of the window you want to toggle the MenuBar
; used in nulldc module and bezel
ToggleMenu(hWin){
Static hMenu, visible
If (hMenu = "")
hMenu := DllCall("GetMenu", "uint", hWin) ; store the menubar ID so it can be restored later
hMenuCur := DllCall("GetMenu", "uint", hWin)
timeout := A_TickCount
If !hMenuCur
Loop {
;ToolTip, menubar is hidden`, bringing it back`nhMenuCur: %hMenuCur%`n%A_Index%
hMenuCur := DllCall("GetMenu", "uint", hWin)
If hMenuCur {
Log("ToggleMenu - MenuBar is now visible for " . hWin,4)
Break ; menubar is now visible, break out
}
DllCall("SetMenu", "uint", hWin, "uint", hMenu)
If (timeout < A_TickCount - 500) ; prevents an infinite loop and breaks after 2 seconds
Break
}
Else Loop { ; menubar is visible
;ToolTip, menubar is visible`, hiding it`nhMenuCur: %hMenuCur%`n%A_Index%
hMenuCur := DllCall("GetMenu", "uint", hWin)
If !hMenuCur {
Log("ToggleMenu - MenuBar is now hidden for " . hWin,4)
Break ; menubar is now hidden, break out
}
DllCall("SetMenu", "uint", hWin, "uint", 0)
If (timeout < A_TickCount - 500) ; prevents an infinite loop and breaks after 2 seconds
Break
}
}
; Original function but somestimes does not work, which is why the new function loops above
ToggleMenuOld(hWin){
Static hMenu, visible
If (hMenu = "")
hMenu := DllCall("GetMenu", "uint", hWin)
If !visible
DllCall("SetMenu", "uint", hWin, "uint", hMenu)
Else
DllCall("SetMenu", "uint", hWin, "uint", 0)
visible := !visible
}
; Function to pause and wait for a user to press any key to continue.
; IdleCheck usage:
; t = timeout in ms to break out of function
; m = the method - can be "P" (physical) or "L" (logical)
; s = sleep or how fast the function checks for idle state
; Exits when state is no longer idle or times out
IdleCheck(t="",m="L",s=200){
timeIdlePrev := 0
startTime := A_TickCount
While timeIdlePrev < (If m = "L" ? A_TimeIdle : A_TimeIdlePhysical){
timeIdlePrev := If m = "L" ? A_TimeIdle : A_TimeIdlePhysical
If (t && A_TickCount-startTime >= t)
Return "Timed Out"
Sleep s
}
Return A_PriorKey
}
; This function looks through all defined romPaths and romExtensions for the provided rom file
; Returns a path to the rom where it was found
; Returns nothing if not found
RomNameExistCheck(file,archivesOnly="") {
Global romPathFromIni,romExtensions,sevenZFormats
Loop, Parse, romPathFromIni, | ; for each rom path defined
{ tempRomPath := A_LoopField ; assigning this to a var so it can be accessed in the next loop
Loop, Parse, romExtensions, | ; for each extension defined
{ If (archivesOnly != "")
If !InStr(sevenZFormats,A_LoopField) ; if rom extension is not an archive type, skip this rom
Continue
; msgbox % tempRomPath . "\" . file . "." . tempRomExtension
Log("RomNameExistCheck - Looking for rom: " . tempRomPath . "\" . file . "." . A_LoopField,4)
If FileExist( tempRomPath . "\" . file . "." . A_LoopField ) {
Log("RomNameExistCheck - Found rom: " . tempRomPath . "\" . file . "." . A_LoopField)
Return tempRomPath . "\" . file . "." . A_LoopField ; return path if file exists
}
Log("RomNameExistCheck - Looking for rom: " . tempRomPath . "\" . file . "\" . file . "." . A_LoopField,4)
If FileExist( tempRomPath . "\" . file . "\" . file . "." . A_LoopField ) { ; check one folder deep of the rom's name in case user keeps each rom in a folder
Log("RomNameExistCheck - Found rom: " . tempRomPath . "\" . file . "\" . file . "." . A_LoopField)
Return tempRomPath . "\" . file . "\" . file . "." . A_LoopField ; return path if file exists
}
}
}
Log("RomNameExistCheck - Could not find """ . file . """ in any of your Rom Paths with any defined Rom Extensions",2)
Return
}
; Shared romTable function and label for Pause and MG which calculates what roms have multiple discs. Now available on every launch to support some custom uses for loading multiple disks on some older computer systems
CreateMGRomTable:
Log("CreateMGRomTable - Started")
If !mgCandidate {
Log("CreateMGRomTable - Ended - This rom does not qualify for MultiGame")
Return
}
If !IsObject(romTable)
{ Log("CreateMGRomTable - romTable does not exist, creating one for """ . dbName . """",4)
romTable := CreateRomTable(dbName)
} Else
Log("CreateMGRomTable - romTable already exists, skipping table creation.",4)
Log("CreateMGRomTable - Ended")
Return
CreateRomTable(table) {
Global romPathFromIni,dbName,romExtensionOrig,sevenZEnabled,romTableStarted,romTableComplete,romTableCanceled,rocketLauncherIsExiting,mgCandidate
romTableStarted := 1
romTableCanceled := ""
romTableComplete := ""
If rocketLauncherIsExiting {
romTableCanceled := 1 ; set this so the RomTableCheck is canceled and doesn't get stuck in an infinite loop
Log("CreateRomTable - RocketLauncher is currently exiting, skipping romTable creation")
Return
}
If !mgCandidate {
romTableCanceled := 1 ; set this so the RomTableCheck is canceled and doesn't get stuck in an infinite loop
Log("CreateRomTable - This rom does not qualify for MultiGame")
Return
}
Log("CreateRomTable - Started")
romCount := 0 ; initialize the var and reset it, needed in case GUI is used more then once in a session
table := [] ; initialize and empty the table
typeArray := ["(Disc","(Disk","(Cart","(Tape","(Cassette","(Part","(Side"]
regExCheck = i)\s\(Disc\s[^/]*|\s\(Disk\s[^/]*|\s\(Cart\s[^/]*|\s\(Tape\s[^/]*|\s\(Cassette\s[^/]*|\s\(Part\s[^/]*|\s\(Side\s[^/]*
dbNamePre := RegExReplace(dbName, regExCheck) ; removes the last set of parentheses if Disc,Tape, etc is in them. A Space must exist before the "(" and after the word Disc or Tape, followed by the number. This is the HS2 standard
Loop % typeArray.MaxIndex() ; loop each item in our array
{ If matchedRom ; Once we matched our game to the typeArray, no need to search for another. This allows the loop to break out.
Break
indexTotal ++
Log("CreateRomTable - Checking for match: """ . dbName . """ and """ . typeArray[A_Index] . """",4)
If dbName contains % typeArray[A_Index] ; find the item in our array that matches our rom
{ Log("CreateRomTable - """ . dbName . """ contains """ . typeArray[A_Index] . """",4)
typeArrayIndex := A_Index
Loop, Parse, romPathFromIni, |
{ indexTotal ++
currentPath := A_LoopField
Log("CreateRomTable - Checking New Rom path: " . currentPath,4)
Log("CreateRomTable - Now looping in: " . currentPath . "\" . dbNamePre . A_Space . typeArray[typeArrayIndex] . "*",4)
Loop, % currentPath . "\" . dbNamePre . A_Space . typeArray[typeArrayIndex] . "*", 1,1 ; we now know to only look for files & folders that have our rom & media type in them.
{ indexTotal ++
Log(A_LoopFileFullPath,4)
Log("CreateRomTable - Looking for: " . currentPath . "\" . dbNamePre . A_Space . typeArray[typeArrayIndex] . "*." . A_LoopFileExt,4)
If romExtensionOrig contains % A_LoopFileExt ; Now we narrow down to all matching files using our original extension. Next we use this data to build an array of our files to populate the GUI.
{ romCount += 1
matchedRom := 1 ; Allows to break out of the loops once we matched our rom
table[romCount,1] := A_LoopFileFullPath ; Store A_LoopFileFullPath (full file path and file) in column 1
table[romCount,2] := A_LoopFileName ; Store A_LoopFileName (the full filename and extension) in column 2
table[romCount,3] := RegExReplace(table[romCount, 2], "\..*") ; Store the filename with media type # but w/o an extension in column 3
pos := RegExMatch(table[romCount,2], regExCheck) ; finds position of our multi media type so we can trim away and generate the imageText and check if rom is part of a set. This pulls only the filenames out of the table in column 2.
uncleanTxt:= SubStr(table[romCount,2], pos + 1) ; remove everything but the media type and # and ext from our file name
table[romCount,4] := dbNamePre ; store dbName w/o the media type and #, used for Pause and updating statistics in column 4
table[romCount,5] := RegExReplace(uncleanTxt, "\(|\)|\..*") ; clean the remainder, removing () and ext, then store it as column 5 in our table to be used for our imageText, this is the media type and #
table[romCount,6] := SubStr(table[romCount,5],1,4) ; copies just the media type to column 6
Log("CreateRomTable - Adding found game to Rom Table: " . A_LoopFileFullPath,4)
}
}
}
}
}
romTableComplete := 1 ; flag to tell the RomTableCheck the function is complete in case no romTable was created for non-MG games
romTableStarted := ""
Log("CreateRomTable - Ended`, " . IndexTotal . " Loops to create table.")
Return table
}
; Function that gets called in some modules to wait for romTable creation if the module bases some conditionals off whether this table exists or not
RomTableCheck() {
Global systemName,mgEnabled,pauseEnabled,romTable,romTableStarted,romTableComplete,romTableCanceled,mgCandidate,dbName
If mgCandidate { ; && (pauseEnabled = "true" || mgEnabled = "true")) {
; If (!romTableStarted && !IsObject(romTable))
; romTable := CreateRomTable(dbName)
Log("RomTableCheck - Started")
; PauseGlobalIni := A_ScriptDir . "\Settings\Global Pause.ini" ; Pause keys have not been read into memory yet, so they must be read here so RocketLauncher knows whether to run the below loop or not
; PauseSystemIni := A_ScriptDir . "\Settings\" . systemName . "\Pause.ini"
; IniRead, changeDiscMenuG, %PauseGlobalIni%, General Options, ChangeDisc_Menu_Enabled
; IniRead, changeDiscMenuS, %PauseSystemIni%, General Options, ChangeDisc_Menu_Enabled
; changeDiscMenu := If changeDiscMenuS = "use_global" ? changeDiscMenuG : changeDiscMenuS ; calculate to use system or global setting
; If (mgEnabled = "true" || changeDiscMenu = "true") {
; Log("RomTableCheck - MultiGame and/or Pause's Change Disc Menu is enabled so checking if romTable exists yet.",4)
If !romTable.MaxIndex()
Log("RomTableCheck - romTable does not exist yet, waiting until it does to continue loading the module.",4)
Loop {
If romTableComplete { ; this var gets created when CreateRomTable is complete in case this is not an MG game
Log("RomTableCheck - Detected CreateRomTable is finished processing. Continuing with module thread.",4)
Break
} Else If romTableCanceled { ; this var gets created when CreateRomTable is cancelled in cases it is no longer needed
Log("RomTableCheck - Detected CreateRomTable is no longer needed. Continuing with module thread.",4)
Break
} Else If (A_Index > 200) { ; if 20 seconds pass by, log there was an issue and continue w/o romTable
Log("RomTableCheck - Creating the romTable took longer than 20 seconds. Continuing with module thread without waiting for the table's creation.",3)
Break
} Else
Sleep, 100
}
; }
Log("RomTableCheck - Ended")
} Else
Log("RomTableCheck - This game is not a candidate for MG or Change DIsc menu.")
}
; Allows changing LEDBlinky's active profile
; mode can be RL or Rom which tells LEDBlinky what profile to load
; Ledblinky's ini gets loaded on start, so this function will never touch it
LEDBlinky(mode) {
Global ledblinkyEnabled,ledblinkySystemName,ledblinkyFullPath,ledblinkyProfilePath,ledblinkyRLProfile,dbName,systemName,romName
Static ledblinkyExists,ledblinkyExe,ledblinkyPath
If (ledblinkyEnabled != "false")
{
If !ledblinkyExists { ; Make sure LEDBlinky exists first before trying to use it
If FileExist(ledblinkyFullPath) {
ledblinkyExists := 1
SplitPath,ledblinkyFullPath,ledblinkyExe,ledblinkyPath
} Else
ScriptError("You are trying to use LEDBlinky support but could not locate it here: " . ledblinkyFullPath)
}
Log("LEDBlinky - Started, sending mode " . mode)
If (mode = "START")
Run(ledblinkyExe . " """ . (If romName ? romName : dbName) . """ """ . (If ledblinkySystemName ? ledblinkySystemName : systemName) . """", ledblinkyPath) ; Game Start Event
Else If (mode = "END")
Run(ledblinkyExe . " 4" , ledblinkyPath) ; Game Stop Event
Else If (mode = "RL")
Run(ledblinkyExe . " 15 RocketLauncher RocketLauncher", ledblinkyPath) ; Load RocketLauncher profile. "15" Tells ledblinky to skip all game start options and only light the controls.
Else If (mode = "ROM")
Run(ledblinkyExe . " 15 """ . (If romName ? romName : dbName) . """ """ . (If ledblinkySystemName ? ledblinkySystemName : systemName) . """", ledblinkyPath) ; return to rom profile. If within the module, romName can be used, otherwise default to dbName.
Else
Log("LEDBlinky - Unsupported use of LEDBlinky - UNKNOWN MODE SUPPLIED: """ . mode . """",3)
Log("LEDBlinky - Ended")
}
}
; Allows changing WinIPAC's and UltraMap's active profile, among any other tools thrown at it that would utilize similar profile structure
; mode = can be START, END, RL or RESUME which represents what part of RL is called the function and what profiles will be loaded
; tool = the name of the tool or folder that will be searched in and checked if that setting is enabled. Ex: WinIPAC or UltraMap
; path = because of how the function supports multiple scenarios, the fullpath to the exe must be provided. Not through making it Global as variables like %prefix%FullPath cannot be made global
; ext = extension of the profiles to look for
; type = used to basically force special modes (only keyboard for now) so the function can support multiple scenarios that all use the same folder structures for profiles
KeymapperProfileSelect(mode,tool,path,ext,type="") {
Global keyboardEncoderEnabled,ultraMapEnabled,profilePath,keymapperFrontEndProfileName,systemName,emuName,dbName
Global keymapperProfiles
If !keymapperProfiles
keymapperProfiles := {} ; create initial object
If (type = "keyboard")
prefix := "keyboardEncoder"
Else
prefix := tool
If (%prefix%Enabled = "true") {
keymapperProfiles[tool,"Enabled"] := "true"
Log(tool . " - Started with mode: " . mode)
If !keymapperProfiles[tool,"Exist"] { ; Make sure the tool exists first before trying to use it
If FileExist(path) {
keymapperProfiles[tool,"Exist"] := 1
keymapperProfiles[tool,"FullPath"] := path
SplitPath,path,exe,path
keymapperProfiles[tool,"Exe"] := exe
keymapperProfiles[tool,"Path"] := path
keymapperProfiles[tool,"Ext"] := "." . ext
keymapperProfiles[tool,"ProfilePath"] := profilePath . "\" . tool
keymapperProfiles[tool,"RLProfile"] := keymapperProfiles[tool,"ProfilePath"] . "\RocketLauncher"
keymapperProfiles[tool,"FEProfile"] := keymapperProfiles[tool,"ProfilePath"] . "\" . keymapperFrontEndProfileName
keymapperProfiles[tool,"DefaultProfile"] := keymapperProfiles[tool,"ProfilePath"] . "\_Default"
keymapperProfiles[tool,"SystemProfile"] := keymapperProfiles[tool,"ProfilePath"] . "\" . systemName
keymapperProfiles[tool,"EmuProfile"] := keymapperProfiles[tool,"ProfilePath"] . "\" . emuName
keymapperProfiles[tool,"RomProfile"] := keymapperProfiles[tool,"ProfilePath"] . "\" . systemName . "\" . dbName
; msgbox % "fullPath: " . keymapperProfiles[tool,"FullPath"] . "`nexe: " . keymapperProfiles[tool,"Exe"] . "`npath: " . keymapperProfiles[tool,"Path"] . "`nExt: " . keymapperProfiles[tool,"Ext"] . "`nProfilePath: " . keymapperProfiles[tool,"ProfilePath"] . "`nRLProfile: " . keymapperProfiles[tool,"RLProfile"] . "`nFEProfile: " . keymapperProfiles[tool,"FEProfile"] . "`nDefaultProfile: " . keymapperProfiles[tool,"DefaultProfile"] . "`nSystemProfile: " . keymapperProfiles[tool,"SystemProfile"] . "`nEmuProfile: " . keymapperProfiles[tool,"EmuProfile"] . "`nRomProfile: " . keymapperProfiles[tool,"RomProfile"]
} Else {
Log(tool . " - You have your path set to " . %prefix% . " defined, but it could not be found here: " . path,2)
keymapperProfiles[tool,"Enabled"] := "false"
}
}
If (mode = "START")
{ Log(tool . " - Searching for profiles",4)
If FileExist(keymapperProfiles[tool,"RomProfile"] . keymapperProfiles[tool,"Ext"]) {
profile := keymapperProfiles[tool,"RomProfile"] . keymapperProfiles[tool,"Ext"]
} Else If FileExist(keymapperProfiles[tool,"EmuProfile"] . keymapperProfiles[tool,"Ext"]) {
profile := keymapperProfiles[tool,"EmuProfile"] . keymapperProfiles[tool,"Ext"]
} Else If FileExist(keymapperProfiles[tool,"SystemProfile"] . keymapperProfiles[tool,"Ext"]) {
profile := keymapperProfiles[tool,"SystemProfile"] . keymapperProfiles[tool,"Ext"]
} Else If FileExist(keymapperProfiles[tool,"DefaultProfile"] . keymapperProfiles[tool,"Ext"]) {
profile := keymapperProfiles[tool,"DefaultProfile"] . keymapperProfiles[tool,"Ext"]
} Else {
Log(tool . " - No profiles found",4)
Return
}
keymapperProfiles[tool,"LastProfile"] := profile
} Else If (mode = "END")
{ Log(tool . " - Searching for your Front End profile",4)
If FileExist(keymapperProfiles[tool,"FEProfile"] . keymapperProfiles[tool,"Ext"]) {
profile := keymapperProfiles[tool,"FEProfile"] . keymapperProfiles[tool,"Ext"]
} Else {
Log(tool . " - Profile not found",4)
Return
}
} Else If (mode = "RL")
{ Log(tool . " - Searching for your RocketLauncher profile",4)
If FileExist(keymapperProfiles[tool,"RLProfile"] . keymapperProfiles[tool,"Ext"]) {
profile := keymapperProfiles[tool,"RLProfile"] . keymapperProfiles[tool,"Ext"]
} Else {
Log(tool . " - Profile not found",4)
Return
}
} Else If (mode = "RESUME")
{ Log(tool . " - Restoring to your last profile",4)
If keymapperProfiles[tool,"LastProfile"] ; only restore to a previous profile if one was found on start
profile := keymapperProfiles[tool,"LastProfile"]
Else {
Log(tool . " - A profile was not loaded on start, skipping any profile loading",4)
Return
}
} Else
Log(tool . " - Unsupported mode: " . mode,2)
Log(tool . " - Loading found profile: " . profile,4)
Run, % keymapperProfiles[tool,"Exe"] . " " . profile . (If tool = "UltraMap" ? "/logerrors " . keymapperProfiles[tool,"Path"] . "\UltraMapLog.log" : ""), % keymapperProfiles[tool,"Path"] ; If there was a problem loading a profile, WinIPAC will pop up with a box saying so with this title/class: "WinIPAC - Downloading ahk_class ThunderRT6FormDC". It does not return any error codes unfortunately. UltraMap requires errors to be logged otherwise it pops up with an error dialog.
Log(tool . " - Ended")
}
}
; Function to measure the size of an text
MeasureText(Text,Options,Font="Arial",Width="", Height="", ReturnMode="W", ByRef H="", ByRef W="", ByRef X="", ByRef Y="", ByRef Chars="", ByRef Lines=""){
hdc_MeasureText := GetDC("MeasureText_hwnd")
G_MeasureText := Gdip_GraphicsFromHDC(hdc_MeasureText)
RECTF_STR := Gdip_TextToGraphics(G_MeasureText, Text, Options, Font, Width, Height, 1)
StringSplit,RCI,RECTF_STR, |
W := Ceil(RCI3)
H := Ceil(RCI4)
X := Ceil(RCI1)
Y := Ceil(RCI2)
Chars := Ceil(RCI5)
Lines := Ceil(RCI6)
DeleteDC(hdc_MeasureText), Gdip_DeleteGraphics(G_MeasureText)
Return (ReturnMode="X") ? X : (ReturnMode="Y") ? Y :(ReturnMode="W") ? W :(ReturnMode="H") ? H : (ReturnMode="Chars") ? Chars : Lines
}
; Function that allows making applications transparent so they can be hidden completely w/o moving them
FadeApp(title,direction,time=0){
startTime := A_TickCount
Loop{
t := ((TimeElapsed := A_TickCount-startTime) < time) ? (If direction="in" ? 255*(timeElapsed/time) : 255*(1-(timeElapsed/time))) : (If direction="in" ? 255 : 0)
WinSet, Transparent, %t%, %title%
If (direction = "in" && t >= 255) or (direction = "out" && t <= 0) {
If (direction = "in")
WinSet, Transparent, Off, %title%
Break
}
}
Log("HideFE - " . (If direction = "out" ? "Hiding Frontend by making it transparent" : "Showing Frontend and removing transparency"))
}
; SplitPath function with support for roms that contain multiple periods in their name. AHK SplitPath does not support this.
SplitPath(in,Byref outFileName,Byref outPath,Byref outExt,Byref outNameNoExt) {
regx := "(\\{2}|(^[\w]:\\))([\w].+\w\\)" ; return path on regexmath and file on regexreplace
regext := "((\.[^.\s]+)+)$" ; return extension with period (match literal period, match one or more at beginning any character and white space, one or more of all previous, and entire match must appear at end)
in := RegExReplace(in,"/","\") ; replace all occurences of / with \
RegExMatch(in, regx, outPathBSlash) ; path with backslash
pathLen := StrLen(outPathBSlash) ; get length of path with slash
outPath := SubStr(outPathBSlash, 1, pathLen - 1) ; grab path w/o slash
RegExMatch(in, regext, outExtP) ; get ext with period
outExt := SubStr(outExtP, 2) ; get ext and remove period
outFileName := RegExReplace(in, regx) ; get name with ext
nameLen := StrLen(outFileName) ; get length of name
extLen := StrLen(outExt) ; get length of ext
outNameNoExt := SubStr(outFileName, 1, nameLen - extLen - 1) ; get name w/o ext
}
; This function converts a relative path to absolute
GetFullName( fn ) {
; http://msdn.microsoft.com/en-us/library/Aa364963
Static buf ;, i ; removing i from static because it needs to be reset from one call to the next
; If !i
i := VarSetCapacity(buf, 512)
DllCall("GetFullPathNameA", "str", fn, "uint", 512, "str", buf, "str*", 0)
Return buf
}
; Converts a relative path to an absolute one after providing the base path
AbsoluteFromRelative(MasterPath, RelativePath)
{
VarSetCapacity(AbsP,260,0)
DllCall( "shlwapi\PathCombineA", Str,AbsP, Str,MasterPath, Str,RelativePath )
Return AbsP
}
; FileGetVersionInfo_AW which gets file attributes
FileGetVersionInfo_AW( peFile="", StringFileInfo="", Delimiter="|") {
Static CS, HexVal, Sps=" ", DLL="Version\"
If ( CS = "" )
CS := A_IsUnicode ? "W" : "A", HexVal := "msvcrt\s" (A_IsUnicode ? "w": "" ) "printf"
If ! FSz := DllCall( DLL "GetFileVersionInfoSize" CS , Str,peFile, UInt,0 )
Return "", DllCall( "SetLastError", UInt,1 )
VarSetCapacity( FVI, FSz, 0 ), VarSetCapacity( Trans,8 * ( A_IsUnicode ? 2 : 1 ) )
DllCall( DLL "GetFileVersionInfo" CS, Str,peFile, Int,0, UInt,FSz, UInt,&FVI )
If ! DllCall( DLL "VerQueryValue" CS, UInt,&FVI, Str,"\VarFileInfo\Translation", UIntP,Translation, UInt,0 )
Return "", DllCall( "SetLastError", UInt,2 )
If ! DllCall( HexVal, Str,Trans, Str,"%08X", UInt,NumGet(Translation+0) )
Return "", DllCall( "SetLastError", UInt,3 )
Loop, Parse, StringFileInfo, %Delimiter%
{ subBlock := "\StringFileInfo\" SubStr(Trans,-3) SubStr(Trans,1,4) "\" A_LoopField
If ! DllCall( DLL "VerQueryValue" CS, UInt,&FVI, Str,SubBlock, UIntP,InfoPtr, UInt,0 )
Continue
Value := DllCall( "MulDiv", UInt,InfoPtr, Int,1, Int,1, "Str" )
Info .= Value ? ( ( InStr( StringFileInfo,Delimiter ) ? SubStr( A_LoopField Sps,1,24 ) . A_Tab : "" ) . Value . Delimiter ) : ""
} StringTrimRight, Info, Info, 1
Return Info
}
GetOSVersion() {
VarSetCapacity(v,148), NumPut(148,v)
DllCall("GetVersionEx", "uint", &v)
; Return formatted version string similar to A_AhkVersion.
; Assume build number will never be more than 4 characters.
return NumGet(v,4) ; major
. "." NumGet(v,8) ; minor
. "." SubStr("0000" NumGet(v,12), -3) ; build
}
; Returns system paths
; For example, GetCommonPath("LOCAL_APPDATA") will return the full path to yout local appdata folder: C:\Users\NAME\AppData\Local
GetCommonPath(csidl) {
Static init
If !init
{
CSIDL_APPDATA := 0x001A ; Application Data, new for NT4
CSIDL_COMMON_APPDATA := 0x0023 ; All Users\Application Data
CSIDL_COMMON_DOCUMENTS := 0x002e ; All Users\Documents
CSIDL_DESKTOP := 0x0010 ; C:\Documents and Settings\username\Desktop
CSIDL_FONTS := 0x0014 ; C:\Windows\Fonts
CSIDL_LOCAL_APPDATA := 0x001C ; non roaming, user\Local Settings\Application Data
CSIDL_MYMUSIC := 0x000d ; "My Music" folder
CSIDL_MYPICTURES := 0x0027 ; My Pictures, new for Win2K
CSIDL_PERSONAL := 0x0005 ; My Documents
CSIDL_PROGRAM_FILES_COMMON := 0x002b ; C:\Program Files\Common
CSIDL_PROGRAM_FILES := 0x0026 ; C:\Program Files
CSIDL_PROGRAMS := 0x0002 ; C:\Documents and Settings\username\Start Menu\Programs
CSIDL_RESOURCES := 0x0038 ; %windir%\Resources\, For theme and other windows resources.
CSIDL_STARTMENU := 0x000b ; C:\Documents and Settings\username\Start Menu
CSIDL_STARTUP := 0x0007 ; C:\Documents and Settings\username\Start Menu\Programs\Startup.
CSIDL_SYSTEM := 0x0025 ; GetSystemDirectory()
CSIDL_WINDOWS := 0x0024 ; GetWindowsDirectory()
}
val := CSIDL_%csidl%
VarSetCapacity(fpath, 256)
DllCall("shell32\SHGetFolderPathA", "uint", 0, "int", val, "uint", 0, "int", 0, "str", fpath)
Return %fpath%
}
; StrX function because some modules use it and Pause needs it for XML reading
StrX( H, BS="",BO=0,BT=1, ES="",EO=0,ET=1, ByRef N="" ) {
Return SubStr(H,P:=(((Z:=StrLen(ES))+(X:=StrLen(H))+StrLen(BS)-Z-X)?((T:=InStr(H,BS,0,((BO
<0)?(1):(BO))))?(T+BT):(X+1)):(1)),(N:=P+((Z)?((T:=InStr(H,ES,0,((EO)?(P+1):(0))))?(T-P+Z
+(0-ET)):(X+P)):(X)))-P)
}
HexCompareWrite(file,Pos,Value){
If (value = "") {
Log("HexCompareWrite - NULL value supplied",2)
Return
}
curBin := BinRead(file,nvramData,1,Pos) ; read binary
Bin2Hex(curHex,nvramData,curBin) ; convert to hex
If (curHex != value) {
Log("HexCompareWrite - Changing " . curHex . " to " . value . " in: " . file,4)
Hex2Bin(binData,value)
BinWrite(file,binData,1,Pos)
}
}
i18n(key, defaultLocale = "English_United_States", p0 = "-0", p1 = "-0", p2 = "-0", p3 = "-0", p4 = "-0", p5 = "-0", p6 = "-0", p7 = "-0", p8 = "-0", p9 = "-0") {
Global sysLang,langFile
Log("i18n - Started",4)
IniRead, phrase, %langFile%, %sysLang%, %key%
If (phrase = "ERROR" || phrase = "")
{
; Nothing found, test with generic language
StringSplit, keyArray, sysLang, _
Log("i18n - Section """ . sysLang . """ & key """ . key . """ not found, trying section """ . keyArray1 . """",4)
IniRead, phrase, %langFile% , %keyArray1%, %key%
If (phrase = "ERROR" || phrase = "")
{
Log("i18n - Section """ . keyArray1 . """ & key """ . key . """ not found, trying section """ . defaultLocale . """",4)
; Nothing found, test with default locale if one is provided
If (defaultLocale != "")
{
IniRead, phrase, %langFile% , %defaultLocale%, %key%
If (phrase = "ERROR" || phrase = "")
{
; Nothing found, test with generic language for default locale as well
StringSplit, keyArray, defaultLocale, _
Log("i18n - Section """ . defaultLocale . """ & key """ . key . """ not found, trying section """ . keyArray1 . """",4)
IniRead, phrase, %langFile% , %keyArray1%, %key%
}
}
; Nothing found return original value
If (defaultLocale = "" || phrase = "ERROR" || phrase = "") {
Log("i18n - Ended, no phrase found for """ . key . """ in language """ . sysLang . """. Using default """ . key . """",2)
Return % key
}
}
}
StringReplace, phrase, phrase, `\n, `r`n, ALL
StringReplace, phrase, phrase, `\t, % A_Tab, ALL
Loop 10
{
idx := A_Index - 1
IfNotEqual, p%idx%, -0
phrase := RegExReplace(phrase, "\{" . idx . "\}", p%idx%)
}
Log("i18n - Ended, using """ . phrase . """ for """ . key . """",4)
Return % phrase
}
; Debug console handler
DebugMessage(str) {
Global rlTitle,rlVersion,rlDebugConsoleStdout
If !rlDebugConsoleStdout
DebugConsoleInitialize(rlDebugConsoleStdout, rlTitle . " v" . rlVersion . " Debug Console") ; start console window if not yet started
str .= "`n" ; add line feed
FileAppend %str%, CONOUT$
; FileAppend %str%`n, * ; Works with SciTE and similar editors.
; OutputDebug %str%`n ; Works with Visual Studio and DbgView.
WinSet, Bottom,, ahk_id %rlDebugConsoleStdout% ; keep console on bottom
}
DebugConsoleInitialize(ByRef handle, title="") {
; two calls to open, no error check (it's debug, so you know what you are doing)
DllCall("AttachConsole", int, -1, int)
DllCall("AllocConsole", int)
DllCall("SetConsoleTitle", "str", (If title ? title : a_scriptname)) ; Set the title
handle := DllCall("GetStdHandle", "int", -11) ; get the handle
WinSet, Bottom,, ahk_id %handle% ; make sure it's on the bottom
Return
}
;Sends a command to the active window using AHK key names. It will always send down/up keypresses for better compatibility
;A special command {Wait} can be used to force a sleep of the time defined by WaitTime
;WaitCommandOffset will affect all Wait events passed in the Command string by this amount
SendCommand(Command, SendCommandDelay=2000, WaitTime=500, WaitBetweenSends=0, Delay=50, PressDuration=-1, WaitCommandOffset=0) {
Log("SendCommand - Started")
Log("SendCommand - Command: " . Command . "`r`n`t`t`t`t`tSendCommandDelay: " . SendCommandDelay . "`r`n`t`t`t`t`tWaitTime: " . WaitTime . "`r`n`t`t`t`t`tWaitBetweenSends: " . WaitBetweenSends . "`r`n`t`t`t`t`tDelay: " . Delay . "`r`n`t`t`t`t`tPressDuration: " . PressDuration . "`r`n`t`t`t`t`tWaitCommandOffset: " . WaitCommandOffset,4)
ArrayCount := 0 ;Keeps track of how many items are in the array.
InsideBrackets := 0 ;If 1 it means the current array item starts with {
SavedKeyDelay := A_KeyDelay ;Saving previous key delay and setting the new one
SetKeyDelay, %Delay%, %PressDuration%
Sleep, %SendCommandDelay% ;Wait before starting to send any command
;Create an array with each command as an array element
Loop, % StrLen(Command)
{ StrValue := SubStr(Command,A_Index,1)
; { StringMid, StrValue, Command, A_Index, 1
If (StrValue != A_Space || InsideBrackets = 1) ; Spaces must be allowed when inside brackets so we can issue {Shift Down} for instance
{ If (InsideBrackets = 0)
ArrayCount += 1
If (StrValue = "{")
{ If (InsideBrackets = 1)
ScriptError("Non-Matching brackets detected in the SendCommand parameter, please correct it")
Else
InsideBrackets := 1
} Else If (StrValue = "}")
{ If (InsideBrackets = 0)
ScriptError("Non-Matching brackets detected in the SendCommand parameter, please correct it")
Else
InsideBrackets := 0
}
Array%ArrayCount% := Array%ArrayCount% . StrValue ;Update the array data
}
}
;Loop through the array and send the commands
Loop %ArrayCount%
{ element := Array%A_Index%
If (WaitBetweenSends = 1)
Sleep, %WaitTime%
;Particular cases check if the commands already come with down or up suffixes on them and if so send the commands directly without appending Up/Down
If RegExMatch(element,"i)Down}")
{ If (element != "{Down}")
{ Send, %element%
continue
}
}
Else If RegExMatch(element,"i)Up}")
{ If (element != "{Up}")
{ Send, %element%
Continue
}
}
Else If (element = "{Wait}") ;Special non-ahk tag to issue a sleep
{ NewWaitTime := WaitTime + WaitCommandOffset
Sleep, %NewWaitTime%
Continue
}
Else If RegExMatch(element,"i)\{Wait:")
{ ;Wait for a specified amount of time {Wait:xxx}
; StringMid, NewWaitTime, element, 7, StrLen(element) - 7
NewWaitTime := SubStr(element,7,StrLen(element) - 7)
NewWaitTime := NewWaitTime + WaitCommandOffset
Sleep, %NewWaitTime%
Continue
}
;the rest of the commands, send a keypress with down and up suffixes
If RegExMatch(element,"}")
{ StrElement := SubStr(element,1,StrLen(element) - 1)
; { StringLeft, StrElement, element, StrLen(element) - 1
Send, %StrElement% down}%StrElement% up}
} Else
Send, {%element% down}{%element% up}
}
;Restore key delay values
SetKeyDelay(SavedKeyDelay, -1)
Log("SendCommand - Ended")
}
; Purpose: Tell a ServoStik to transition to 4 or 8-way mode
; Parameters:
; direction = Can be 4 or 8, self-explanatory
ServoStik(direction) {
Log("ServoStik - Started")
Global PacDriveDllFile,servoStikEnabled
Static dllExists
If !RegExMatch(direction,"4|8")
{
Log("ServoStik - """ . direction . """ is not a supported direction for ServoSticks. Only 4 and 8 are supported. Leaving your ServoStik as is.",2)
Return
}
If !dllExists {
CheckFile(pacDrivedllFile, "Following file is required for RocketLauncher ServoStik support, but could not be found:`n" . pacDrivedllFile)
dllExists := 1 ; do not run this check again
}
pacDriveLoadModule := DllCall("LoadLibrary", "Str", PacDriveDllFile) ; Avoids the need for ahk to load and free the dll's library multiple times
pacInitialize := DllCall(PacDriveDllFile . "\PacInitialize") ; Initialize all PacDrive, PacLED64 and U-HID Devices and return the amount connected to system
If !pacInitialize {
Log("ServoStik - No devices found on system",2)
Log("ServoStik - Ended")
Return
} Else
Log("ServoStik - " . pacInitialize . " devices found on system. If you have multiple devices, this should list more than one and may not specifically mean a ServoStik was found")
result := DllCall(PacDriveDllFile . "\PacSetServoStik" . direction . "Way") ; Tell ServoStiks to change to desired direction
If !result
Log("ServoStik - There was a problem telling your ServoStik(s) to go " . direction . "-Way",3)
Else
Log("ServoStik - ServoStik(s) were told to go " . direction . "-Way")
; pacDriveUnloadModule := DllCall("FreeLibrary", "UInt", pacDriveLoadModule) ; To conserve memory, the DLL is unloaded after using it.
Log("ServoStik - Ended")
}
GetTimeString(time) {
If (time<0)
Return time
If time is not number
Return time
Days := time // 86400
Hours := Mod(time, 86400) // 3600
Minutes := Mod(time, 3600) // 60
Seconds := Mod(time, 60)
If (Days<>0) {
If Strlen(Hours) = 1
Hours = 0%Hours%
If Strlen(Minutes) = 1
Minutes = 0%Minutes%
If Strlen(Seconds) = 1
Seconds = 0%Seconds%
TimeString = %Days%d %Hours%h %Minutes%m %Seconds%s
} Else If (Hours<>0) {
If Strlen(Minutes) = 1
Minutes = 0%Minutes%
If Strlen(Seconds) = 1
Seconds = 0%Seconds%
TimeString = %Hours%h %Minutes%m %Seconds%s
} Else If (Minutes<>0) {
If Strlen(Seconds) = 1
Seconds = 0%Seconds%
TimeString = %Minutes%m %Seconds%s
} Else If (Seconds<>0)
TimeString = %Seconds%s
Else
TimeString := ""
Return TimeString
}
ReplaceFileNameInvalidChar(ByRef hastack,list,replaceChar){
Loop, Parse, list, `,
StringReplace, hastack, hastack, %a_loopfield%, %replaceChar%, All
Return hastack
}
;-------------------------------------------------------------------------------------------------------------
;-------------------------------------------- RL Media Functions ---------------------------------------------
;-------------------------------------------------------------------------------------------------------------
rndRLMediaLogoPath(assetType){
Global RLMedia, feMedia, gameInfo
If !(RLMedia)
RLMedia := loadRLMediaLogos(gameInfo)
LogoImageList := []
for index, element in RLMedia["Logos"]
If (element.Label)
If (element.AssetType=assetType)
Loop, % element.TotalItems
LogoImageList.Insert(element["Path" . a_index])
If !(LogoImageList[1])
for index, element in feMedia["Logos"]
If (element.Label)
If (element.AssetType=assetType)
Loop, % element.TotalItems
LogoImageList.Insert(element["Path" . a_index])
If (LogoImageList[1]) {
Random, RndmLogoImage, 1, % LogoImageList.MaxIndex()
Return LogoImageList[RndmLogoImage]
}
}
LoadRLMediaLogos(gameInfoObj){
Global RLMediaPath, RLMedia, systemname, dbname, romTable, mgCandidate
RLMedia := {}
LogoList := "Genre|Rating|Developer|Publisher|Year"
Loop, Parse, LogoList, |
{ If (gameInfoObj[A_LoopField].Value){
%A_LoopField% := gameInfoObj[A_LoopField].Value
If (A_LoopField = "Genre"){
ReplaceFileNameInvalidChar(%A_LoopField%,"/,|","\") ;Replacing invalid file name characters by folder separator ("\")
ReplaceFileNameInvalidChar(%A_LoopField%,"*","-") ;Replacing invalid file name characters by hippens ("-")
} Else
ReplaceFileNameInvalidChar(%A_LoopField%,"/,*,|","-") ;Replacing invalid file name characters by hippens ("-")
ReplaceFileNameInvalidChar(%A_LoopField%,":"," - ") ;Replacing invalid file name characters by hippens ("-")
ReplaceFileNameInvalidChar(%A_LoopField%,"?," . """" . ",<,>","") ;Replacing invalid file name characters by hippens ("-")
%A_LoopField% :=RegExReplace(%A_LoopField%,"^\s+|\s+(?=\s)|\s$") ;remove double white spaces
If (FileExist(RLMediaPath . "\" . A_LoopField . "\" . systemname . "\" . dbname . "\" . %A_LoopField% . ".*"))
%A_LoopField%Path := RLMediaPath . "\" . A_LoopField . "\" . systemname . "\" . dbname . "\" . %A_LoopField% . ".*"
Else If (FileExist(RLMediaPath . "\" . A_LoopField . "\" . systemname . "\_Default\" . %A_LoopField% . ".*"))
%A_LoopField%Path := RLMediaPath . "\" . A_LoopField . "\" . systemname . "\_Default\" . %A_LoopField% . ".*"
Else
%A_LoopField%Path := RLMediaPath . "\" . A_LoopField . "\_Default\" . %A_LoopField% . ".*"
}
}
RLMedia.Logos := BuildAssetsTable(GenrePath . "|" . RatingPath . "|" . DeveloperPath . "|" . PublisherPath . "|" . YearPath,"Genre Logo|Rating Logo|Developer Logo|Publisher Logo|Year Logo","genre|rating|developer|publisher|year","png|bmp|gif|jpg|tif")
systemLogoPath := RLMediaPath . "\Logos\" . systemname . "\_Default\"
gameLogoPath1 := RLMediaPath . "\Logos\" . systemname . "\" . dbname . "\"
;Description name without (Disc X)
If (!romTable && mgCandidate)
romTable := CreateRomTable(dbName)
Totaldiscsofcurrentgame := romTable.MaxIndex()
If (Totaldiscsofcurrentgame > 1) {
DescriptionNameWithoutDisc := romTable[1,4]
gameLogoPath2 := RLMediaPath . "\Logos\" . systemname . "\" . DescriptionNameWithoutDisc . "\"
}
RLMedia.Logos := BuildAssetsTable(systemLogoPath . "|" . gameLogoPath1 . "|" . gameLogoPath2,"System Logo|Game Logo|Game Logo","system|game|game","png|bmp|gif|jpg|tif",RLMedia.Logos)
Return RLMedia
}
; Inject a shared function for Pause and Fade which adjusts the background image positioning
; Usage, params 1-4 are byref so supply the var you want to be filled with the calculated positions and size. Next 2 are the original pics width and height. Last is the position the user wants.
GetBGPicPosition(ByRef retX,ByRef retY,ByRef retW,ByRef retH,w,h,pos){
Global baseScreenWidth, baseScreenHeight
widthMaxPercent := ( baseScreenWidth / w ) ; get the percentage needed to maximumise the image so it reaches the screen's width
heightMaxPercent := ( baseScreenHeight / h )
If (pos = "Stretch and Lose Aspect") { ; image is stretched to screen, loosing aspect
retW := baseScreenWidth
retH := baseScreenHeight
retX := 0
retY := 0
} Else If (pos = "Stretch and Keep Aspect") { ; image is stretched to Center screen, keeping aspect
percentToEnlarge := If (widthMaxPercent < heightMaxPercent) ? widthMaxPercent : heightMaxPercent ; this basicallys says if the width's max reaches the screen's width first, use the width's percentage instead of the height's
retW := Round(w * percentToEnlarge) ; multiply width by the percentage from above to reach as close to the edge as possible
retH := Round(h * percentToEnlarge) ; multiply height by the percentage from above to reach as close to the edge as possible
retX := ( baseScreenWidth / 2 ) - ( retW / 2 ) ; find where to place the X of the image
retY := ( baseScreenHeight / 2 ) - ( retH / 2 ) ; find where to place the Y of the image
} Else If (pos = "Center Width") { ; image is stretched to Center screen's width, keeping aspect
percentToEnlarge := widthMaxPercent ; increase the image size by the percentage it takes to reaches the screen's width, cropping may occur on top and bottom
retW := Round(w * percentToEnlarge) ; multiply width by the percentage from above to reach as close to the edge as possible
retH := Round(h * percentToEnlarge) ; multiply height by the percentage from above to reach as close to the edge as possible
retX := ( baseScreenWidth / 2 ) - ( retW / 2 ) ; find where to place the X of the image
retY := ( baseScreenHeight / 2 ) - ( retH / 2 ) ; find where to place the Y of the image
} Else If (pos = "Center Height") { ; image is stretched to Center screen's height, keeping aspect
percentToEnlarge := heightMaxPercent ; increase the image size by the percentage it takes to reaches the screen's height, cropping may occur on left and right
retW := Round(w * percentToEnlarge) ; multiply width by the percentage from above to reach as close to the edge as possible
retH := Round(h * percentToEnlarge) ; multiply height by the percentage from above to reach as close to the edge as possible
retX := ( baseScreenWidth / 2 ) - ( retW / 2 ) ; find where to place the X of the image
retY := ( baseScreenHeight / 2 ) - ( retH / 2 ) ; find where to place the Y of the image
} Else If (pos = "Center") { ; original image size and aspect
retX := ( baseScreenWidth / 2 ) - ( w / 2 ) ; find where to place the X of the image
retY := ( baseScreenHeight / 2 ) - ( h / 2 ) ; find where to place the Y of the image
} Else If (pos = "Align to Bottom Left") { ; place the pic so the bottom left corner matches the screen's bottom left corner
retH := baseScreenHeight
retW := Round( w / ( h / baseScreenHeight ))
If ( retW < baseScreenWidth ){
retW := baseScreenWidth
retH := Round( h / ( w / retW ))
}
retY := baseScreenHeight - retH
} Else If (pos = "Align to Bottom Right") { ; place the pic so the bottom right corner matches the screen's bottom right corner
retH := baseScreenHeight
retW := Round( w / ( h / baseScreenHeight ))
If ( retW < baseScreenWidth ){
retW := baseScreenWidth
retH := Round( h / ( w / retW ))
}
retX := baseScreenWidth - retW
retY := baseScreenHeight - retH
} Else If (pos = "Align to Top Right") { ; place the pic so the top right corner matches the screen's top right corner
retH := baseScreenHeight
retW := Round( w / ( h / baseScreenHeight ))
If ( retW < baseScreenWidth ){
retW := baseScreenWidth
retH := Round( h / ( w / retW ))
}
retX := baseScreenWidth - retW
} Else { ; place the pic so the top left corner matches the screen's top left corner, also the default
retH := baseScreenHeight
retW := Round( w / ( h / baseScreenHeight ))
If ( retW < baseScreenWidth ){
retW := baseScreenWidth
retH := Round( h / ( w / retW ))
}
}
}
; Usage, params 1&2 are byref so supply the var you want to be filled with the calculated positions. Next 4 are the original pics xy,w,h. Last is the position the user wants.
GetFadePicPosition(ByRef retX, ByRef retY,x,y,w,h,pos){
Global baseScreenWidth, baseScreenHeight
If (pos = "Stretch and Lose Aspect"){ ; image is stretched to screen, loosing aspect
retX := 0
retY := 0
} Else If (pos = "Stretch and Keep Aspect") { ; image is stretched to screen, keeping aspect
retX := round(( baseScreenWidth / 2 ) - ( w / 2 ))
retY := round(( baseScreenHeight / 2 ) - ( h / 2 ))
} Else If (pos = "Center") {
retX := round(( baseScreenWidth / 2 ) - ( w / 2 ))
retY := round(( baseScreenHeight / 2 ) - ( h / 2 ))
} Else If (pos = "Top Left Corner") {
retX := 0
retY := 0
} Else If (pos = "Top Right Corner") {
retX := baseScreenWidth - w
retY := 0
} Else If (pos = "Bottom Left Corner") {
retX := 0
retY := baseScreenHeight - h
} Else If (pos = "Bottom Right Corner") {
retX := baseScreenWidth - w
retY := baseScreenHeight - h
} Else If (pos = "Top Center") {
retX := round(( baseScreenWidth / 2 ) - ( w / 2 ))
retY := 0
} Else If (pos = "Bottom Center") {
retX := round(( baseScreenWidth / 2 ) - ( w / 2 ))
retY := baseScreenHeight - h
} Else If (pos = "Left Center") {
retX := 0
retY := round(( baseScreenHeight / 2 ) - ( h / 2 ))
} Else If (pos = "Right Center") {
retX := baseScreenWidth - w
retY := round(( baseScreenHeight / 2 ) - ( h / 2 ))
} Else {
retX := x
retY := y
}
}
GetRLMediaFiles(mediaType,supportedFileTypes,returnArray=0) {
Log("GetRLMediaFiles - Started",4)
Global RLMediaPath,dbName,systemName,romTable,mgCandidate
If (!romTable && mgCandidate)
romTable:=CreateRomTable(dbName)
DescriptionNameWithoutDisc := romTable[1,4]
romFolder := RLMediaPath . "\" . mediaType . "\" . systemName . "\" . dbName . "\"
romDisckLessFolder := RLMediaPath . "\" . mediaType . "\" . systemName . "\" . DescriptionNameWithoutDisc . "\"
systemFolder := RLMediaPath . "\" . mediaType . "\" . systemName . "\_Default\"
globalFolder := RLMediaPath . "\" . mediaType . "\_Default\"
imagesArray := []
Loop, Parse, supportedFileTypes, |
If FileExist(romFolder . "*." . A_LoopField) {
Loop % romFolder . "*." . A_LoopField
imagesArray[A_Index] := A_LoopFileFullPath
}
If imagesArray.MaxIndex() <= 0
Loop, Parse, supportedFileTypes, |
If FileExist(romDisckLessFolder . "*." . A_LoopField) {
Loop % romDisckLessFolder . "*." . A_LoopField
imagesArray[A_Index] := A_LoopFileFullPath
}
If imagesArray.MaxIndex() <= 0
Loop, Parse, supportedFileTypes, |
If FileExist(systemFolder . "*." . A_LoopField) {
Loop % systemFolder . "*." . A_LoopField
imagesArray[A_Index] := A_LoopFileFullPath
}
If imagesArray.MaxIndex() <= 0
Loop, Parse, supportedFileTypes, |
If FileExist(globalFolder . "*." . A_LoopField) {
Loop % globalFolder . "*." . A_LoopField
imagesArray[A_Index] := A_LoopFileFullPath
}
If returnArray {
Log("GetRLMediaFiles - Ended, returning array",4)
Return imagesArray
}
Else {
Random, RndmImagePic, 1, % imagesArray.MaxIndex()
file := imagesArray[RndmImagePic]
Log("GetRLMediaFiles - Ended, randomized RocketLauncher " . mediaType . " file selected: " . file)
Return file
}
}
;-------------------------------------------------------------------------------------------------------------
;----------------------------------------- DXWnd Functions -----------------------------------------
;-------------------------------------------------------------------------------------------------------------
; If you provide a value, DxwndIniRW assumes you want to write to the ini
; If no value is provided, DxwndIniRW assumes you want to read from the ini and returns the value
; DxwndIniRW is only used to read and write settings to dxwnd.ini
; DxwndRun is for launching dxwnd
; DxwndClose is for closing dxwnd
; DxwndUpdateIniPath is for updating the dxwndIni variable
DxwndIniRW(sec="",key="",val="", default="", cTarget="") {
Log("DxwndIniRW - Started")
Global dxwndIni,romName
Static pos,iniExists
If !iniExists {
CheckFile(dxwndIni)
iniExists := 1 ; do not run this check again
}
If !pos { ; the current romName or cTarget position has not been found, loop through the ini to find it first
targetGame := If cTarget ? cTarget : romName
Loop {
pos := a_index-1
IniRead, dxwndName, %dxwndIni%, target, title%pos%
If (dxwndName = targetGame)
Break
If (dxwndName = "ERROR")
ScriptError("There was a problem finding """ . targetGame . """ in the DXWnd Ini. Please make sure you have added this game to DXWnd before attempting to launch DXWnd through it.")
}
}
errLvl := Process("Exist", "dxwnd.exe") ; Make sure dxwnd is not running first so settings don't get reverted
If errLvl {
DxwndClose()
Process("WaitClose", "dxwnd.exe")
}
If val {
IniWrite, %val%, %dxwndIni%, %sec%, %key%%pos%
Log("DxwndIniRW - Wrote """ . val . """ to game #" . pos,4)
} Else {
IniRead, val, %dxwndIni%, %sec%, %key%%pos%
Log("DxwndIniRW - Read """ . val . """",4)
Log("DxwndIniRW - Ended")
Return val
}
Log("DxwndIniRW - Ended")
}
DxwndRun(ByRef outPID="") {
Log("DxwndRun - Started")
Global dxwndFullPath,dxwndExe,dxwndPath,dxwndIni
Static exeExists
If !exeExists {
CheckFile(dxwndFullPath, "Following file is required for DXWnd support, but its file could not be found:`n" . dxwndFullPath)
exeExists := 1 ; do not run this check again
}
If !dxwndExe
SplitPath, dxwndFullPath, dxwndExe, dxwndPath
SplitPath, dxwndIni, dxwndIniFile
Run(dxwndExe . " /T /C:""" . dxwndIniFile . """", dxwndPath, "Min", outPID)
errLvl := Process("Wait", dxwndExe, 10) ; waiting 10 seconds for dxwnd to start
If (errLvl = "")
ScriptError("DXWnd did not start after waiting for 10 seconds. Please check you can run it manually and try again.")
Else
Log("DxwndRun - DxwndRun is now running")
Log("DxwndRun - Ended")
}
DxwndClose() {
Log("DxwndClose - Started")
Global dxwndFullPath,dxwndExe,dxwndPath
If !dxwndExe
SplitPath, dxwndFullPath, dxwndExe, dxwndPath
PostMessage, 0x111, 32810,,,ahk_exe %dxwndExe% ; this tells dxwnd to close itself
Process("WaitClose", dxwndExe, 1) ; waits 1 second for dxwnd to close
errLvl := Process("Exist", dxwndExe) ; checks if dxwnd is still running
If errLvl
Process("Close", dxwndExe) ; only needed when RocketLauncher is not ran as admin or RocketLauncher cannot close dxwnd for some reason
Log("DxwndClose - Ended")
}
DxwndUpdateIniPath() {
Global dxwndFullPath,dxwndPath,dxwndIni,systemName
SplitPath,dxwndFullPath,,dxwndPath
If FileExist( dxwndPath . "\" . systemName . ".ini" )
dxwndIni := dxwndPath . "\" . systemName . ".ini"
Else
dxwndIni := dxwndPath . "\dxwnd.ini"
Log("DxwndUpdateIniPath - DxwndIni set to " . dxwndIni)
}
;-------------------------------------------------------------------------------------------------------------
;----------------------------------- Cursor Control Functions ------------------------------------
;-------------------------------------------------------------------------------------------------------------
ToggleCursor:
Log("ToggleCursor - Hotkey """ . toggleCursorKey . """ pressed, toggling cursor visibility")
SystemCursor("Toggle")
Return
; Function to hide/unhide the mouse cursor
SystemCursor(OnOff=1) ; INIT = "I","Init"; OFF = 0,"Off"; TOGGLE = -1,"T","Toggle"; ON = others
{ Global mouseCursorHidden
Static AndMask, XorMask, cursor, h_cursor
,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13 ; system cursors
, b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13 ; blank cursors
, h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11,h12,h13 ; handles of default cursors
If (OnOff = "Init" or OnOff = "I" or cursor = "") ; init when requested or at first call
{
cursor := "h" ; active default cursors
VarSetCapacity( h_cursor,4444, 1 )
VarSetCapacity( AndMask, 32*4, 0xFF )
VarSetCapacity( XorMask, 32*4, 0 )
system_cursors = 32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650
StringSplit c, system_cursors, `,
Loop %c0%
{
h_cursor := DllCall( "LoadCursor", "uint",0, "uint",c%A_Index% )
h%A_Index% := DllCall( "CopyImage", "uint",h_cursor, "uint",2, "int",0, "int",0, "uint",0 )
b%A_Index% := DllCall("CreateCursor","uint",0, "int",0, "int",0
, "int",32, "int",32, "uint",&AndMask, "uint",&XorMask )
}
}
If (OnOff = 0 or OnOff = "Off" or $ = "h" and (OnOff < 0 or OnOff = "Toggle" or OnOff = "T")){
cursor := "b" ; use blank cursors
Log("SystemCursor - Hiding mouse cursor")
CoordMode, Mouse ; Also lets move it to the side since some emu's flash a cursor real quick even if we hide it.
MouseMove, 0, 0, 0
} Else {
cursor := "h" ; use the saved cursors
SPI_SETCURSORS := 0x57 ; Emergency restore cursor, just in case something goes wrong
DllCall( "SystemParametersInfo", UInt,SPI_SETCURSORS, UInt,0, UInt,0, UInt,0 )
mouseCursorHidden := ""
Log("SystemCursor - Restoring mouse cursor")
}
Loop %c0%
{
h_cursor := DllCall( "CopyImage", "uint",%cursor%%A_Index%, "uint",2, "int",0, "int",0, "uint",0 )
DllCall( "SetSystemCursor", "uint",h_cursor, "uint",c%A_Index% )
}
}
SetSystemCursor( Cursor = "", cx = 0, cy = 0 ) {
BlankCursor := 0, SystemCursor := 0, FileCursor := 0 ; init
SystemCursors = 32512IDC_ARROW,32513IDC_IBEAM,32514IDC_WAIT,32515IDC_CROSS
,32516IDC_UPARROW,32640IDC_SIZE,32641IDC_ICON,32642IDC_SIZENWSE
,32643IDC_SIZENESW,32644IDC_SIZEWE,32645IDC_SIZENS,32646IDC_SIZEALL
,32648IDC_NO,32649IDC_HAND,32650IDC_APPSTARTING,32651IDC_HELP
If (Cursor = "") ; empty, so create blank cursor
{
Log("SetSystemCursor - Creating blank cursor",4)
VarSetCapacity( AndMask, 32*4, 0xFF ), VarSetCapacity( XorMask, 32*4, 0 )
BlankCursor := 1 ; flag for later
}
Else If SubStr( Cursor,1,4 ) = "IDC_" ; load system cursor
{
Log("SetSystemCursor - Loading system cursor",4)
Loop, Parse, SystemCursors, `,
{
CursorName := SubStr( A_Loopfield, 6, 15 ) ; get the cursor name, no trailing space with substr
CursorID := SubStr( A_Loopfield, 1, 5 ) ; get the cursor id
SystemCursor := 1
If ( CursorName = Cursor ) {
CursorHandle := DllCall( "LoadCursor", Uint,0, Int,CursorID )
Break
}
}
If (CursorHandle = "") ; invalid cursor name given
{
Log("SetSystemCursor - Invalid cursor name supplied: """ . CursorHandle . """",2)
; Msgbox,, SetCursor, Error: Invalid cursor name
CursorHandle := "Error"
}
}
Else If FileExist( Cursor )
{
Log("SetSystemCursor - Found this cursor: """ . Cursor . """",4)
SplitPath, Cursor,,, Ext ; auto-detect type
If (Ext = "ico")
uType := 0x1
Else If RegExMatch("cur|ani","i)" . Ext)
uType := 0x2
Else ; invalid file ext
{
Log("SetSystemCursor - Invalid cursor extension: """ . Ext . """",2)
; Msgbox,, SetCursor, Error: Invalid file type
CursorHandle := "Error"
}
FileCursor := 1
}
Else
{
Log("SetSystemCursor - Invalid cursor name or path: """ . Cursor . """",2)
; Msgbox,, SetCursor, Error: Invalid file path or cursor name
CursorHandle := "Error" ; raise for later
}
If (CursorHandle != "Error")
{
Loop, Parse, SystemCursors, `,
{
If (BlankCursor = 1)
{
Type := "BlankCursor"
%Type%%A_Index% := DllCall( "CreateCursor", Uint,0, Int,0, Int,0, Int,32, Int,32, Uint,&AndMask, Uint,&XorMask )
CursorHandle := DllCall( "CopyImage", Uint,%Type%%A_Index%, Uint,0x2, Int,0, Int,0, Int,0 )
DllCall( "SetSystemCursor", Uint,CursorHandle, Int,SubStr( A_Loopfield, 1, 5 ) )
}
Else If (SystemCursor = 1)
{
Type := "SystemCursor"
CursorHandle := DllCall( "LoadCursor", Uint,0, Int,CursorID )
%Type%%A_Index% := DllCall( "CopyImage", Uint,CursorHandle, Uint,0x2, Int,cx, Int,cy, Uint,0 )
CursorHandle := DllCall( "CopyImage", Uint,%Type%%A_Index%, Uint,0x2, Int,0, Int,0, Int,0 )
DllCall( "SetSystemCursor", Uint,CursorHandle, Int,SubStr( A_Loopfield, 1, 5 ) )
}
Else If (FileCursor = 1)
{
Type := "FileCursor"
%Type%%A_Index% := DllCall( "LoadImage", UInt,0, Str,Cursor, UInt,uType, Int,cx, Int,cy, UInt,0x10 )
DllCall( "SetSystemCursor", Uint,%Type%%A_Index%, Int,SubStr( A_Loopfield, 1, 5 ) )
}
}
}
}
RestoreCursors() {
SPI_SETCURSORS := 0x57
DllCall( "SystemParametersInfo", UInt,SPI_SETCURSORS, UInt,0, UInt,0, UInt,0 )
}
;-------------------------------------------------------------------------------------------------------------
;------------------ Read and Write Wrapper Functions for IniFileEdit ------------------
;-------------------------------------------------------------------------------------------------------------
; Usage - Read and Write to config files that are not valid inis with [sections], like RetroArch's cfg
; cfgFile - path to the file to read, only need to send this once, it stays in memory until SavePropertiesCfg is used
; Returns a reference number to the array where the cfg is stored in memory so multiple files can be edited at once
LoadProperties(cfgFile) {
Log("LoadProperties - Started and loading this cfg into memory: " . cfgFile,4)
cfgtable := Object()
Loop, Read, %cfgFile% ; This loop retrieves each line from the file, one at a time.
cfgtable.Insert(A_LoopReadLine) ; Append this line to the array.
Log("LoadProperties - Ended",4)
Return cfgtable
}
; cfgFile - path to the file to read, only need to send this once, it stays in memory until SavePropertiesCfg is used
; cfgArray - reference number of array in memory that should be saved to the cfgFile
SaveProperties(cfgFile,cfgArray) {
Log("SaveProperties - Started and saving this cfg to disk: " . cfgFile,4)
FileDelete, %cfgFile%
Loop % cfgArray.MaxIndex()
{ element := cfgArray[A_Index]
trimmedElement := LTrim(element)
finalCfg .= trimmedElement . "`n"
}
FileAppend, %finalCfg%, %cfgFile%
Log("SaveProperties - Ended",4)
}
; cfgArray - reference number of array in memory that you want to read
; keyName = key whose value you want to read
; Separator = the separator to use, defaults to =
ReadProperty(cfgArray,keyName,Separator="=") {
Log("ReadProperty - Started",4)
Loop % cfgArray.MaxIndex()
{ element := cfgArray[A_Index]
trimmedElement := Trim(element)
;MsgBox % "Element number " . A_Index . " is " . element
StringGetPos, pos, trimmedElement, [
If (pos = 0)
Break ; Section was found, do not search anymore, global section has ended
If element contains %Separator%
{ StringSplit, keyValues, element, %Separator%
CfgValue := Trim(keyValues1)
If (CfgValue = keyName)
Return Trim(keyValues2) ; Found it & trim any whitespace
}
}
Log("ReadProperty - Ended",4)
}
; cfgArray - reference number of array in memory that you want to read
; keyName = key whose value you want to write
; Value = value that you want to write to the keyName
; AddSpaces = If the seperator (=) has spaces on either side, set this parameter to 1 and it will wrap the seperator in spaces
; AddQuotes = If the Value needs to be wrapped in double quotes (like in retroarch's config), set this parameter to 1
; Separator = the separator to use, defaults to =
WriteProperty(cfgArray,keyName,Value,AddSpaces=0,AddQuotes=0,Separator="=") {
Log("WriteProperty - Started",4)
added := 0
Loop % cfgArray.MaxIndex()
{ lastIndex := A_Index
element := cfgArray[A_Index]
trimmedElement := Trim(element)
StringGetPos, pos, trimmedElement, [
If (pos = 0)
{ lastIndex := lastIndex - 1 ; Section was found, do not search anymore
Break
}
If element contains %Separator%
{ StringSplit, keyValues, element, %Separator%
CfgValue := Trim(keyValues1)
If (CfgValue = keyName)
{ cfgArray[A_Index] := CfgValue . (If AddSpaces=1 ? (" " . Separator . " ") : Separator) . (If AddQuotes=1 ? ("""" . Value . """") : Value) ; Found it
added := 1
Break
}
}
}
If (added = 0)
cfgArray.Insert(lastIndex+1, keyName . (If AddSpaces=1 ? (" " . Separator . " ") : Separator) . (If AddQuotes=1 ? ("""" . Value . """") : Value)) ; Add the new entry to the file
Log("WriteProperty - Ended",4)
}
;-------------------------------------------------------------------------------------------------------------
;----------------------------------------- Player Select Menu --------------------------------------
;-------------------------------------------------------------------------------------------------------------
; function to create a small menu with the number of players option
NumberOfPlayersSelectionMenu(maxPlayers=4) {
Global screenRotationAngle,baseScreenWidth,baseScreenHeight,xTranslation,yTranslation
Global navSelectKey,navUpKey,navDownKey,navP2SelectKey,navP2UpKey,navP2DownKey,exitEmulatorKey,exitEmulatorKey
Global keymapper,keymapperEnabled,keymapperRocketLauncherProfileEnabled
If !pToken
pToken := Gdip_Startup()
Gdip_Alt_GetRotatedDimensions(A_ScreenWidth, A_ScreenHeight, screenRotationAngle, baseScreenWidth, baseScreenHeight)
Gdip_GetRotatedTranslation(baseScreenWidth, baseScreenHeight, screenRotationAngle, xTranslation, yTranslation)
xTranslation:=round(xTranslation), yTranslation:=round(yTranslation)
Loop, 2 {
Gui, playersMenu_GUI%A_Index%: +Disabled -Caption +E0x80000 +OwnDialogs +LastFound +ToolWindow +AlwaysOnTop
Gui, playersMenu_GUI%A_Index%: Margin,0,0
Gui, playersMenu_GUI%A_Index%: Show,, playersMenuLayer%A_Index%
playersMenu_hwnd%A_Index% := WinExist()
playersMenu_hbm%A_Index% := CreateDIBSection(A_ScreenWidth, A_ScreenHeight)
playersMenu_hdc%A_Index% := CreateCompatibleDC()
playersMenu_obm%A_Index% := SelectObject(playersMenu_hdc%A_Index%, playersMenu_hbm%A_Index%)
playersMenu_G%A_Index% := Gdip_GraphicsFromhdc(playersMenu_hdc%A_Index%)
Gdip_SetSmoothingMode(playersMenu_G%A_Index%, 4)
Gdip_TranslateWorldTransform(playersMenu_G%A_Index%, xTranslation, yTranslation)
Gdip_RotateWorldTransform(playersMenu_G%A_Index%, screenRotationAngle)
}
;Initializing parameters
playersMenuTextFont := "Bebas Neue"
CheckFont(playersMenuTextFont)
playersMenuSelectedTextSize := 50
playersMenuSelectedTextColor := "FFFFFFFF"
playersMenuDisabledTextColor := "FFAAAAAA"
playersMenuDisabledTextSize := 30
playersMenuMargin := 50
playersMenuSpaceBtwText := 30
playersMenuCornerRadius := 10
;menu scalling factor
XBaseRes := 1920, YBaseRes := 1080
If (((A_screenWidth < A_screenHeight) and ((screenRotationAngle=0) or (screenRotationAngle=180))) or ((A_screenWidth > A_screenHeight) and ((screenRotationAngle=90) or (screenRotationAngle=270))))
XBaseRes := 1080, YBaseRes := 1920
If !playersMenuXScale
playersMenuXScale := baseScreenWidth/XBaseRes
If !playersMenuYScale
playersMenuYScale := baseScreenHeight/YBaseRes
OptionScale(playersMenuSelectedTextSize, playersMenuYScale)
OptionScale(playersMenuDisabledTextSize, playersMenuYScale)
OptionScale(playersMenuMargin, playersMenuXScale)
OptionScale(playersMenuSpaceBtwText, playersMenuYScale)
OptionScale(playersMenuCornerRadius, playersMenuXScale)
playersMenuW := MeasureText("X Players", "Left r4 s" . playersMenuSelectedTextSize . " Bold",playersMenuTextFont) + 2*playersMenuMargin
playersMenuH := maxPlayers*playersMenuSelectedTextSize + (maxPlayers-1)*playersMenuSpaceBtwText + 2*playersMenuMargin
playersMenuX := (baseScreenWidth-playersMenuW)//2
playersMenuY := (baseScreenHeight-playersMenuH)//2
playersMenuBackgroundBrush := Gdip_BrushCreateSolid("0xDD000000")
pGraphUpd(playersMenu_G1,playersMenuW,playersMenuH)
pGraphUpd(playersMenu_G2,playersMenuW,playersMenuH)
;Drawing Background
Gdip_Alt_FillRoundedRectangle(playersMenu_G1, playersMenuBackgroundBrush, 0, 0, playersMenuW, playersMenuH,playersMenuCornerRadius)
Alt_UpdateLayeredWindow(playersMenu_hwnd1, playersMenu_hdc1, playersMenuX, playersMenuY, playersMenuW, playersMenuH)
;Drawing choice list
SelectedNumberofPlayers := 1
gosub, DrawPlayersSelectionMenu
;Enabling Keys
If (keymapperEnabled = "true") and (keymapperRocketLauncherProfileEnabled = "true")
RunKeymapper%zz%("menu",keymapper)
If keymapperAHKMethod = External
RunAHKKeymapper%zz%("menu")
Gosub, EnablePlayersMenuKeys
LEDBlinky("RL") ; trigger ledblinky profile change if enabled
;Waiting for menu to exit
Loop
{ If PlayersMenuExit
Break
Sleep, 100
}
LEDBlinky("ROM") ; trigger ledblinky profile change if enabled
Return SelectedNumberofPlayers
;labels to treat menu changes
DrawPlayersSelectionMenu:
currentY := 0
Gdip_GraphicsClear(playersMenu_G2)
Loop, % maxPlayers
{
If (a_index=SelectedNumberofPlayers) {
currentTextSize := playersMenuSelectedTextSize
currentTextColor := playersMenuSelectedTextColor
currentTextStyle := "bold"
} Else {
currentTextSize := playersMenuDisabledTextSize
currentTextColor := playersMenuDisabledTextColor
currentTextStyle := "normal"
}
If (a_index=1)
currentText := "1 Player"
Else
currentText := a_index . " Players"
currentY := playersMenuMargin + (a_index-1)*(playersMenuSelectedTextSize+playersMenuSpaceBtwText)+(playersMenuSelectedTextSize-currentTextSize)//2
Gdip_Alt_TextToGraphics(playersMenu_G2, currentText, "x0 y" . currentY . " Center c" . currentTextColor . " r4 s" . currentTextSize . " " . currentTextStyle, playersMenuTextFont, playersMenuW, playersMenuSelectedTextSize)
}
Alt_UpdateLayeredWindow(playersMenu_hwnd2, playersMenu_hdc2, playersMenuX, playersMenuY, playersMenuW, playersMenuH)
Return
EnablePlayersMenuKeys:
XHotKeywrapper(navSelectKey,"PlayersMenuSelect","ON")
XHotKeywrapper(navUpKey,"PlayersMenuUP","ON")
XHotKeywrapper(navDownKey,"PlayersMenuDown","ON")
XHotKeywrapper(navP2SelectKey,"PlayersMenuSelect","ON")
XHotKeywrapper(navP2UpKey,"PlayersMenuUP","ON")
XHotKeywrapper(navP2DownKey,"PlayersMenuDown","ON")
XHotKeywrapper(exitEmulatorKey,"CloseProcess","OFF")
XHotKeywrapper(exitEmulatorKey,"ClosePlayersMenu","ON")
Return
DisablePlayersMenuKeys:
XHotKeywrapper(navSelectKey,"PlayersMenuSelect","OFF")
XHotKeywrapper(navUpKey,"PlayersMenuUP","OFF")
XHotKeywrapper(navDownKey,"PlayersMenuDown","OFF")
XHotKeywrapper(navP2SelectKey,"PlayersMenuSelect","OFF")
XHotKeywrapper(navP2UpKey,"PlayersMenuUP","OFF")
XHotKeywrapper(navP2DownKey,"PlayersMenuDown","OFF")
XHotKeywrapper(exitEmulatorKey,"ClosePlayersMenu","OFF")
XHotKeywrapper(exitEmulatorKey,"CloseProcess","ON")
Return
PlayersMenuUP:
SelectedNumberofPlayers--
If (SelectedNumberofPlayers<1)
SelectedNumberofPlayers:=maxPlayers
gosub, DrawPlayersSelectionMenu
Return
PlayersMenuDown:
SelectedNumberofPlayers++
If (SelectedNumberofPlayers>maxPlayers)
SelectedNumberofPlayers:=1
gosub, DrawPlayersSelectionMenu
Return
ClosePlayersMenu:
ClosedPlayerMenu := true
PlayersMenuSelect:
Gosub, DisablePlayersMenuKeys
Gdip_DeleteBrush(playersMenuBackgroundBrush)
Loop, 2 {
SelectObject(playersMenu_hdc%A_Index%, playersMenu_obm%A_Index%)
DeleteObject(playersMenu_hbm%A_Index%)
DeleteDC(playersMenu_hdc%A_Index%)
Gdip_DeleteGraphics(playersMenu_G%A_Index%)
Gui, playersMenu_GUI%A_Index%: Destroy
}
If ClosedPlayerMenu
{ Log("User cancelled the launch at the Player Select Menu")
PlayersMenuExit := true
ExitModule()
} Else
Log("Number of Players Selected: " . SelectedNumberofPlayers)
If (keymapperEnabled = "true") and (keymapperRocketLauncherProfileEnabled = "true")
RunKeymapper%zz%("load", keymapper)
If keymapperAHKMethod = External
RunAHKKeymapper%zz%("load")
PlayersMenuExit := true
Return
}
;-------------------------------------------------------------------------------------------------------------
;----------------------------------------- HideEmu Functions ---------------------------------------
;-------------------------------------------------------------------------------------------------------------
; Default is 2ms so it picks up windows as soon as possible
HideEmuStart(ms=2) {
Global hideEmu
Global hideEmuObj
If (hideEmu = "true")
{ Log("HideEmuStart - Starting HideEmuTimer, scanning for windows defined in hideEmuObj every " . ms . "ms")
; First rebuild the single line object into a better one that's easier to track and work with
newObject := Object()
For key, value in hideEmuObj
{ currentObj++
newObject[currentObj,"window"] := key
newObject[currentObj,"method"] := value
newObject[currentObj,"status"] := ; default is 0 (0 = not hidden yet, 1 = hidden already)
}
hideEmuObj := newObject ; overwrite hideEmuObj with the updated one
SetTimer, HideEmuTimer, %ms%
Log("HideEmuStart - Ended")
}
}
HideEmuEnd() {
Global hideEmu
Global hideEmuObj
If (hideEmu = "true")
{ Log("HideEmuEnd - Stopping HideEmuTimer and unhiding flagged windows",4)
SetTimer, HideEmuTimer, Off
For key, value in hideEmuObj
If (hideEmuObj[A_Index,"method"] && hideEmuObj[A_Index,"status"]) { ; if one of the windows was hidden and needs to be unhidden
WinSet, Transparent, Off, % hideEmuObj[A_Index,"window"]
Log("HideEmu - Revealed window: " . hideEmuObj[A_Index,"window"],4)
}
Log("HideEmuEnd - Ended",4)
}
}
HideEmuTimer:
For key, value in hideEmuObj
{ If !hideEmuObj[A_Index,"status"]
{ If (A_DetectHiddenWindows != "On")
DetectHiddenWindows, On
If WinExist(hideEmuObj[A_Index,"window"])
{ WinSet, Transparent, 0, % hideEmuObj[A_Index,"window"]
Log("HideEmu - Found a new window to hide: " . hideEmuObj[A_Index,"window"],4)
WinGet, currentTran, Transparent, % hideEmuObj[A_Index,"window"]
If (currentTran = 0)
hideEmuObj[A_Index,"status"] := 1 ; update object that this window is now hidden
}
}
}
Return
;-------------------------------------------------------------------------------------------------------------
;---------------------------------------- Decryption Functions -------------------------------------
;-------------------------------------------------------------------------------------------------------------
Decrypt(T,key) ; Text, key-name
{
Local p, i, L, u, v, k5, a, c
StringLeft p, T, 8
If p is not xdigit ; if no IV: Error
{
ErrorLevel := 1
Return
}
StringTrimLeft T, T, 8 ; remove IV from text (no separator)
k5 = 0x%p% ; set new IV
p := 0 ; counter to be Encrypted
i := 9 ; pad-index, force restart
L := "" ; processed text
k0 := %key%0
k1 := %key%1
k2 := %key%2
k3 := %key%3
Loop % StrLen(T)
{
i++
IfGreater i,8, { ; all 9 pad values exhausted
u := p
v := k5 ; IV
p++ ; increment counter
TEA(u,v, k0,k1,k2,k3)
Stream9(u,v) ; 9 pads from Encrypted counter
i := 0
}
StringMid c, T, A_Index, 1
a := Asc(c)
if a between 32 and 126
{ ; chars > 126 or < 31 unchanged
a -= s%i%
IfLess a, 32, SetEnv, a, % a+95
c := Chr(a)
}
L := L . c ; attach Encrypted character
}
Return L
}
TEA(ByRef y,ByRef z,k0,k1,k2,k3) ; (y,z) = 64-bit I/0 block
{ ; (k0,k1,k2,k3) = 128-bit key
IntFormat := A_FormatInteger
SetFormat Integer, D ; needed for decimal indices
s := 0
d := 0x9E3779B9
Loop 32
{
k := "k" . s & 3 ; indexing the key
y := 0xFFFFFFFF & (y + ((z << 4 ^ z >> 5) + z ^ s + %k%))
s := 0xFFFFFFFF & (s + d) ; simulate 32 bit operations
k := "k" . s >> 11 & 3
z := 0xFFFFFFFF & (z + ((y << 4 ^ y >> 5) + y ^ s + %k%))
}
SetFormat Integer, %IntFormat%
y += 0
z += 0 ; Convert to original ineger format
}
Stream9(x,y) ; Convert 2 32-bit words to 9 pad values
{ ; 0 <= s0, s1, ... s8 <= 94
Local z ; makes all s%i% global
s0 := Floor(x*0.000000022118911147) ; 95/2**32
Loop 8
{
z := (y << 25) + (x >> 7) & 0xFFFFFFFF
y := (x << 25) + (y >> 7) & 0xFFFFFFFF
x := z
s%A_Index% := Floor(x*0.000000022118911147)
}
}
;-------------------------------------------------------------------------------------------------------------
;------------------------------------ Registry Access Functions ----------------------------------
;-------------------------------------------------------------------------------------------------------------
RegRead(RootKey, SubKey, ValueName = "", RegistryVersion="32")
{ Global winVer
Log("RegRead - Reading from Registry : RootKey=" . RootKey . ", SubKey=" . SubKey . ", ValueName=" . ValueName . ",RegistryVersion=" . RegistryVersion, 4)
If (RegistryVersion = "Auto") ;Try finding the correct registry reading based on the windows version
{
If (winVer = "64")
If !OutputVar := RegRead(RootKey, SubKey, ValueName, "64")
OutputVar := RegRead(RootKey, SubKey, ValueName, "32")
Else
OutputVar := RegRead(RootKey, SubKey, ValueName)
}
Else If (RegistryVersion = "32")
RegRead, OutputVar, %RootKey%, %SubKey%, %ValueName%
Else
OutputVar := RegRead64(RootKey, SubKey, ValueName)
Log("RegRead - Registry Read finished, returning " . OutputVar, 4)
Return OutputVar
}
RegWrite(ValueType, RootKey, SubKey, ValueName = "", Value = "", RegistryVersion="32")
{
Log("RegWrite - Writing to Registry : RootKey=" . RootKey . ", SubKey=" . SubKey . ", ValueName=" . ValueName . ",Value=" . Value . ",ValueType=" . ValueType . ",RegistryVersion=" . RegistryVersion, 4)
If (RegistryVersion = "32")
RegWrite, %ValueType%, %RootKey%, %SubKey%, %ValueName%, %Value%
Else
RegWrite64(ValueType, RootKey, SubKey, ValueName, Value)
Log("RegWrite - Registry Write finished", 4)
}
;-------------------------------------------------------------------------------------------------------------
;----------------------------------------- Display Resolution Functions ----------------------------------------
;-------------------------------------------------------------------------------------------------------------
; Grab current display settings for each monitor
; Returns object:
; obj[#] = Display Number
; obj[#].Name = Display's Name as known in windows. Ex: \\.\DISPLAY1
; obj[#].Width = Display's Width
; obj[#].Height = Display's Height
; obj[#].BitDepth = Display's BitDepth
; obj[#].Frequency = Display's Frequency
; obj[#].Orientation = Display's Orientation
; obj[#].Left = Where this display's Left position starts
; obj[#].Right = Where this display's Right position ends
; obj[#].Top = Where this display's Top position starts
; obj[#].Bottom = Where this display's Bottom position ends
; obj[#].WorkingWidth = Display's Working Width. This is the usable space w/o the task bar
; obj[#].WorkingHeight = Display's Working Height
GetDisplaySettings() {
Global RLObject
obj := Object()
monOrientation := Object(0,"Landscape",1,"Portrait",2,"Landscape (Flipped)",3,"Portrait (Flipped)")
getDisplaySettingsObj := Object(1,"Width",2,"Height",3,"BitDepth",4,"Frequency",5,"Orientation")
SysGet, MonitorCount, 80 ; MonitorCount
SysGet, MonitorPrimary, MonitorPrimary
Loop, %MonitorCount% ; get each monitor's stats for the log
{
SysGet, MonitorName, MonitorName, %A_Index%
SysGet, Monitor, Monitor, %A_Index%
SysGet, MonitorWorkArea, MonitorWorkArea, %A_Index%
currentobj:={}
currentobj.Number := A_Index ; this is the monitor #, an integer
currentobj.Name := MonitorName ; store monitor's name as it is known as in Windows
monDetails := RL_getDisplaySettings(MonitorName) ; return 0 if something went wrong, like an invalid displayName is passed. Otherwise it returns a string with this format "width|height|bits|frequency|orientation"
Loop, Parse, monDetails, |
currentObj[getDisplaySettingsObj[A_Index]] := A_LoopField ; parse RLObject's return and store into the object
currentobj.Orientation := monOrientation[currentobj.Orientation] ; replace orientation integer with name from object instead
currentobj.Left := MonitorLeft ; store where this monitor's Left position starts
currentobj.Right := MonitorRight ; store where this monitor's Right position ends
currentobj.Top := MonitorTop ; store where this monitor's Top position starts
currentobj.Bottom := MonitorBottom ; store where this monitor's Bottom position ends
currentobj.WorkingWidth := MonitorWorkAreaRight - MonitorWorkAreaLeft ; store this monitor's working width
currentobj.WorkingHeight := MonitorWorkAreaBottom - MonitorWorkAreaTop ; store this monitor's working height
obj.Insert(currentobj["Number"], currentobj)
Log("GetDisplaySettings - Monitor #" . A_Index . " (" . MonitorName . "): " . MonitorRight - MonitorLeft . "x" . MonitorBottom - MonitorTop . " (" . MonitorWorkAreaRight - MonitorWorkAreaLeft . "x" . MonitorWorkAreaBottom - MonitorWorkAreaTop . " work) [" . currentobj.BitDepth . "bit] [" . currentobj.Frequency . "hz] [" . currentobj.Orientation . "] " . (If MonitorPrimary = A_Index ? " (Primary)" : ""),4)
}
Return obj
}
; This function will take the | delimited user settings from theses places:
; A) RLUI for all monitor/resolution settings and break it apart so it can be used in the various display functions then sent to the DLL
; B) Module when called to change the display setting(s)
; It supports multiple monitors and parameters for each
; array = | delimted string in this order where each monitor is delimted by ; monNumber|monWidth|monHeight|monBitDepth|monFrequency
; Example = 1|1600|1200|32|60&2|1024|768|32|60
ConvertToMonitorObject(array) {
Global monitorTable
displaySettingsObj := Object(1,"Name",2,"Width",3,"Height",4,"BitDepth",5,"Frequency")
obj := Object()
Loop, Parse, array, &
{
currentobj:={}
currentobj.Number := A_Index ; this is the monitor #, an integer
Loop, Parse, A_LoopField, |
{
If !A_LoopField {
Log("ConvertToMonitorObject - " . displaySettingsObj[A_Index] . " not supplied in array. Object creation terminated.",3)
Return
}
currentobj[displaySettingsObj[A_Index]] := If displaySettingsObj[A_Index] = "Name" && !InStr(A_LoopField,"DISPLAY") ? "\\.\DISPLAY" . A_LoopField : A_LoopField
}
obj.Insert(currentobj["Number"], currentobj)
}
Return obj
}
; Handle the supplied object by first checking if parameters are supported by the monitor, then setting them.
; This is the function that will be called in features and modules to change display settings.
SetDisplaySettings(monObj) {
Global monitorTable
Log("SetDisplaySettings - Started")
currentMon := GetDisplaySettings() ; get current parameters to see if res needs to be changed or it can be skipped
Loop % monObj.MaxIndex()
{
; msgbox % "SetDisplaySettings`n`nobj[" . A_Index . "].Name: " . monObj[A_Index].Name . "`nobj.Width: " . monObj[A_Index].Width . "`nobj.Height: " . monObj[A_Index].Height . "`nobj.BitDepth: " . monObj[A_Index].BitDepth . "`nobj.Frequency: " . monObj[A_Index].Frequency
x := CheckDisplaySettings(monObj[A_Index].Name,monObj[A_Index].Width,monObj[A_Index].Height,monObj[A_Index].BitDepth,monObj[A_Index].Frequency)
If x {
If ((monObj[A_Index].Width = currentMon[A_Index].Width) && (monObj[A_Index].Height = currentMon[A_Index].Height) && (monObj[A_Index].BitDepth = currentMon[A_Index].BitDepth) && (monObj[A_Index].Frequency = currentMon[A_Index].Frequency)) {
Log("SetDisplaySettings - Not changing " . monObj[A_Index].Name . " as it is already set to " . monObj[A_Index].Width . "x" . monObj[A_Index].Height . " " . monObj[A_Index].BitDepth . "bit " . monObj[A_Index].Frequency . "hz")
} Else {
Log("SetDisplaySettings - Changing " . monObj[A_Index].Name . " to " . monObj[A_Index].Width . "x" . monObj[A_Index].Height . " " . monObj[A_Index].BitDepth . "bit " . monObj[A_Index].Frequency . "hz")
ChangeDisplaySettings(monObj[A_Index].Name,monObj[A_Index].Width,monObj[A_Index].Height,monObj[A_Index].BitDepth,monObj[A_Index].Frequency)
; Update monitorTable with new settings so it stays current
SysGet, Monitor, Monitor, %A_Index%
SysGet, MonitorWorkArea, MonitorWorkArea, %A_Index%
monitorTable[A_Index].Width := monObj[A_Index].Width
monitorTable[A_Index].Height := monObj[A_Index].Height
monitorTable[A_Index].BitDepth := monObj[A_Index].BitDepth
monitorTable[A_Index].Frequency := monObj[A_Index].Frequency
monitorTable[A_Index].Left := MonitorLeft
monitorTable[A_Index].Right := MonitorRight
monitorTable[A_Index].Top := MonitorTop
monitorTable[A_Index].Bottom := MonitorBottom
monitorTable[A_Index].WorkingWidth := MonitorWorkAreaRight - MonitorWorkAreaLeft
monitorTable[A_Index].WorkingHeight := MonitorWorkAreaBottom - MonitorWorkAreaTop
}
} Else
Log("SetDisplaySettings - " . monObj[A_Index].Name . " does not support " . monObj[A_Index].Width . "x" . monObj[A_Index].Height . " " . monObj[A_Index].BitDepth . "bit " . monObj[A_Index].Frequency . "hz",2)
}
Log("SetDisplaySettings - Ended")
}
; Change screen resolution to supplied parameters
; Do not call this function directly, allow SetDisplaySettings to handle it
; n = Display Name
; w = Screen Width
; h = Screen Height
; b = Bit Depth
; f = Frequency
ChangeDisplaySettings(n,w,h,b,f) {
Global RLObject
Return RL_changeDisplaySettings(n,w,h,b,f)
}
; Check monitor if it can support the screen parameters supplied
; Do not call this function directly, allow SetDisplaySettings to handle it
; Use this before calling ChangeDisplaySettings
; n = Display Name
; w = Screen Width
; h = Screen Height
; b = Bit Depth
; f = Frequency
CheckDisplaySettings(n,w,h,b,f) {
Global RLObject
Return RL_checkDisplaySettings(n,w,h,b,f)
}
; http://www.autohotkey.com/forum/topic8355.html
; ChangeDisplaySettings( sW, sH, cD, rR ) { ; Change Screen Resolution
; VarSetCapacity(dM,156,0), NumPut(156,dM,36)
; DllCall( "EnumDisplaySettingsA", UInt,0, UInt,-1, UInt,&dM ), NumPut(0x5c0000,dM,40)
; NumPut(cD,dM,104), NumPut(sW,dM,108), NumPut(sH,dM,112), NumPut(rR,dM,120)
; Return DllCall( "ChangeDisplaySettingsA", UInt,&dM, UInt,0 )
; }
; Acquire display "index" screen resolution (index=0,1,...)
; GetDisplaySettings(Index) {
; VarSetCapacity(device_mode,156,0)
; success:=DllCall("EnumDisplaySettings","uint",0,"uint",Index-1,"uint",&device_mode)
; If (ErrorLevel or !success)
; Return "Break"
; Out_1:=NumGet(&device_mode,108,"uint4") ;width
; Out_2:=NumGet(&device_mode,112,"uint4") ;height
; Out_3:=NumGet(&device_mode,104,"uint4") ;quality
; Out_4:=NumGet(&device_mode,120,"uint4") ;frequency
; Return Out_1 "|" Out_2 "|" Out_3 "|" Out_4
; } ; out "Break"
; Acquire current display screen resolution (1=width 2=height 3=quality 4=frequency)
; CurrentDisplaySettings(in=0) {
; VarSetCapacity(device_mode,156,0),NumPut(156,2,&device_mode,36)
; success := DllCall("EnumDisplaySettings","uint",0,"uint",-1,"uint",&device_mode)
; Out_1:=NumGet(&device_mode,108,"uint4") ;width
; Out_2:=NumGet(&device_mode,112,"uint4") ;height
; Out_3:=NumGet(&device_mode,104,"uint4") ;quality
; Out_4:=NumGet(&device_mode,120,"uint4") ;frequency
; If in = 0
; Return Out_1 "|" Out_2 "|" Out_3 "|" Out_4
; Else Return (Out_%in%)
; }
; Check if a given screen resolution is supported by the monitor, and if not, choose the nearest one that is
; desiredResTable uses the object defined by ConvertToMonitorObject
CheckForNearestSupportedRes(monNumber,desiredResTable){
Log("CheckForNearestSupportedRes - Started")
If !desiredResTable {
Log("CheckForNearestSupportedRes - Supplied desired resolution does not contain any data.",3)
Return
}
listOfSupportedRes := EnumDisplaySettings(monNumber)
If !listOfSupportedRes
{ Log("CheckForNearestSupportedRes - Ended, was supplied a monitor number that is not attached to this system: " . monNumber,3)
Return
}
If RegExMatch(listOfSupportedRes, "i)" desiredResTable[monNumber].Width . "\|" . desiredResTable[monNumber].Height . "\|" . desiredResTable[monNumber].BitDepth . "\|" . desiredResTable[monNumber].Frequency)
{ Log("CheckForNearestSupportedRes - Ended, this resolution is already supported by this display: " . desiredResTable[monNumber].Width . "|" . desiredResTable[monNumber].Height . "|" . desiredResTable[monNumber].BitDepth . "|" . desiredResTable[monNumber].Frequency,4)
Return desiredResTable
}
Log("CheckForNearestSupportedRes - This resolution is not directly supported by your monitor, finding the closest match.",4)
SupportedResObj := {}
nearestSupportedRes := {}
Loop, Parse, listOfSupportedRes, `,
{
currentRes := A_Index
SupportedResObj[currentRes] := {}
StringSplit,curRes,A_LoopField,|
SupportedResObj[currentRes].Width := curRes1
SupportedResObj[currentRes].Height := curRes2
SupportedResObj[currentRes].BitDepth := curRes3
SupportedResObj[currentRes].Frequency := curRes4
SupportedResObj[currentRes]["Distance"] := {}
SupportedResObj[currentRes]["Distance"].Width := SupportedResObj[currentRes].Width - desiredResTable[monNumber].Width
SupportedResObj[currentRes]["Distance"].Height := SupportedResObj[currentRes].Height - desiredResTable[monNumber].Height
SupportedResObj[currentRes]["Distance"].BitDepth := SupportedResObj[currentRes].BitDepth - desiredResTable[monNumber].BitDepth
SupportedResObj[currentRes]["Distance"].Frequency := SupportedResObj[currentRes].Frequency - desiredResTable[monNumber].Frequency
}
previousDeviation := 10**9
Loop, %currentRes%
{
currentDeviation := 100*SupportedResObj[A_Index]["Distance"].Width*SupportedResObj[A_Index]["Distance"].Width + 100*SupportedResObj[A_Index]["Distance"].Height*SupportedResObj[A_Index]["Distance"].Height + 10*SupportedResObj[A_Index]["Distance"].BitDepth*SupportedResObj[A_Index]["Distance"].BitDepth + SupportedResObj[A_Index]["Distance"].Frequency*SupportedResObj[A_Index]["Distance"].Frequency
If (currentDeviation < previousDeviation) {
previousDeviation := currentDeviation
nearestSupportedRes.Width := SupportedResObj[A_Index].Width
nearestSupportedRes.Height := SupportedResObj[A_Index].Height
nearestSupportedRes.BitDepth := SupportedResObj[A_Index].BitDepth
nearestSupportedRes.Frequency := SupportedResObj[A_Index].Frequency
}
}
supportedRes := ConvertToMonitorObject(monNumber . "|" . nearestSupportedRes.Width . "|" . nearestSupportedRes.Height . "|" . nearestSupportedRes.BitDepth . "|" nearestSupportedRes.Frequency) ; convert to object
Log("CheckForNearestSupportedRes - Ended, closest match found is: " . supportedRes[monNumber].Width . "|" . supportedRes[monNumber].Height . "|" . supportedRes[monNumber].BitDepth . "|" supportedRes[monNumber].Frequency,4)
Return supportedRes
}
; Enumerate Supported Screen Resolutions
; display = the number of the monitor to enumerate supported resolutions for. 1 = Display 1, 2 = display 2, etc
; Returns | delimited list of all supported settings
EnumDisplaySettings(display) {
VarSetCapacity(DM,156,0), NumPut(156,&DM,36, "UShort")
DllCall( "EnumDisplaySettings", str,"\\.\DISPLAY" Display, UInt,-1, UInt,&DM )
CS:=NumGet(DM,108) "|" NumGet(DM,112) "|" NumGet(DM,104) "|" NumGet(DM,120)
Loop
If DllCall( "EnumDisplaySettings", str,"\\.\DISPLAY" Display, UInt,A_Index-1, UInt,&DM )
{ EDS:=NumGet(DM,108) "|" NumGet(DM,112) "|" NumGet(DM,104) "|" NumGet(DM,120)
DS.=(!InStr(DS,EDS) ? "," EDS : "")
} Else
Break
StringReplace, DS, DS, %CS%|, %CS%||, All
Return SubStr(DS,2)
}
OptionScale(ByRef option, scale){ ;selects portrait specifc option value if needed and scales variable to adjust to screen resolution
Global screenRotationAngle
If InStr(option,"|")
{
StringSplit, opt, option, |
If ((opt2) and (((A_screenWidth < A_screenHeight) and ((screenRotationAngle=0) or (screenRotationAngle=180))) or ((A_screenWidth > A_screenHeight) and ((screenRotationAngle=90) or (screenRotationAngle=270)))))
option := If (SubStr(opt2, 0)="p") ? opt2 : round(opt2 * scale)
Else
option := If (SubStr(opt1, 0)="p") ? opt1 : round(opt1 * scale)
} Else
option := If (SubStr(option, 0)="p") ? option : round(option * scale)
}
TextOptionScale(ByRef Option,XScale, YScale){
RegExMatch(Option, "i)X([\-\d\.]+)(p*)\|([\-\d\.]+)(p*)|X([\-\d\.]+)(p*)", xpos)
RegExMatch(Option, "i)Y([\-\d\.]+)(p*)\|([\-\d\.]+)(p*)|Y([\-\d\.]+)(p*)", ypos)
RegExMatch(Option, "i)W([\-\d\.]+)(p*)\|([\-\d\.]+)(p*)|W([\-\d\.]+)(p*)", Width)
RegExMatch(Option, "i)H([\-\d\.]+)(p*)\|([\-\d\.]+)(p*)|H([\-\d\.]+)(p*)", Height)
RegExMatch(Option, "i)S([\-\d\.]+)(p*)\|([\-\d\.]+)(p*)|S([\-\d\.]+)", Size)
xposValue := SubStr(xpos, 2), yposValue := SubStr(ypos, 2), WidthValue := SubStr(Width, 2), HeightValue := SubStr(Height, 2), SizeValue := SubStr(Size, 2)
OptionScale(xposValue, XScale)
OptionScale(yposValue, YScale)
OptionScale(WidthValue, XScale)
OptionScale(HeightValue, YScale)
OptionScale(SizeValue, YScale)
Option := RegExReplace(Option, "i)X([\-\d\.]+)(p*)\|([\-\d\.]+)(p*)|X([\-\d\.]+)(p*)", "x" . xposValue)
Option := RegExReplace(Option, "i)Y([\-\d\.]+)(p*)\|([\-\d\.]+)(p*)|Y([\-\d\.]+)(p*)", "y" . yposValue)
Option := RegExReplace(Option, "i)W([\-\d\.]+)(p*)\|([\-\d\.]+)(p*)|W([\-\d\.]+)(p*)", "w" . WidthValue)
Option := RegExReplace(Option, "i)H([\-\d\.]+)(p*)\|([\-\d\.]+)(p*)|H([\-\d\.]+)(p*)", "h" . HeightValue)
Option := RegExReplace(Option, "i)S([\-\d\.]+)(p*)\|([\-\d\.]+)(p*)|S([\-\d\.]+)", "s" . SizeValue)
}
;-------------------------------------------------------------------------------------------------------------
;---------------------------- Open And Close Process Functions ----------------------------
;-------------------------------------------------------------------------------------------------------------
ProcSus(PID_or_Name) {
Log("ProcSus - Started",4)
If InStr(PID_or_Name, ".") {
Process, Exist, %PID_or_Name%
PID_or_Name := ErrorLevel
}
If !(h := DllCall("OpenProcess", "uInt", 0x1F0FFF, "Int", 0, "Int", PID_or_Name)) {
Log("ProcSus - Ended, process """ . PID_or_Name . """ not found")
Return -1
}
Log("ProcSus - Suspending Process: " . PID_or_Name)
DllCall("ntdll.dll\NtSuspendProcess", "Int", h), DllCall("CloseHandle", "Int", h)
Log("ProcSus - Ended",4)
}
ProcRes(PID_or_Name) {
Log("ProcRes - Started",4)
If InStr(PID_or_Name, ".") {
Process, Exist, %PID_or_Name%
PID_or_Name := ErrorLevel
}
If !(h := DllCall("OpenProcess", "uInt", 0x1F0FFF, "Int", 0, "Int", PID_or_Name)) {
Log("ProcRes - Ended, process """ . PID_or_Name . """ not found")
Return -1
}
Log("ProcRes - Resuming Process: " . PID_or_Name)
DllCall("ntdll.dll\NtResumeProcess", "Int", h), DllCall("CloseHandle", "Int", h)
Log("ProcRes - Ended",4)
}
;-------------------------------------------------------------------------------------------------------------
;--------------------------------------- Validate IP Functions ---------------------------------------
;-------------------------------------------------------------------------------------------------------------
ValidIP(a) {
Loop, Parse, a, .
{
If A_LoopField is digit
If A_LoopField between 0 and 255
e++
c++
}
Return, e = 4 AND c = 4
}
ValidPort(a) {
If a is digit
If a between 0 and 65535
e++
Return e
}
GetPublicIP() {
UrlDownloadToFile, http://www.rlauncher.com/ipcheck/myip.php, %A_Temp%\myip.txt
FileRead, extIP, %A_Temp%\myip.txt
Return extIP
}
GetLocalIP() {
array := []
objWMIService := ComObjGet("winmgmts:{impersonationLevel = impersonate}!\\.\root\cimv2")
colItems := objWMIService.ExecQuery("Select * from Win32_NetworkAdapterConfiguration WHERE IPEnabled = True")._NewEnum
while colItems[objItem]
{
array[A_Index,1] := objItem.Description[0]
array[A_Index,2] := objItem.IPAddress[0]
array[A_Index,3] := objItem.IPSubnet[0]
array[A_Index,4] := objItem.DefaultIPGateway[0]
array[A_Index,5] := objItem.DNSServerSearchOrder[0]
array[A_Index,6] := objItem.MACAddress[0]
array[A_Index,7] := objItem.DHCPEnabled[0]
}
Return array
}
;-------------------------------------------------------------------------------------------------------------
;------------------------------------------- Rotate Screen Functions -------------------------------------------
;-------------------------------------------------------------------------------------------------------------
; Options:
; method = irotate, display, or shortcut
; degrees = 0, 90, 180, 270
Rotate(method="irotate", degrees=0) {
Log("Rotate - Started")
Global moduleExtensionsPath
arrowKeys := { 0: "Up", 1: "Right", 2: "Down", 3: "Left" }
If !RegExMatch(method,"i)irotate|display|shortcut")
ScriptError("""" . method . """ is not a valid rotate method, Please choose either ""irotate"" or ""display""")
If !RegExMatch(degrees,"0|90|180|270")
ScriptError("""" . degrees . """ is not a valid degree to rotate to, Please choose either 0, 90, 180, or 270")
rotateExe := CheckFile(moduleExtensionsPath . "\" . method . ".exe") ; check If the exe to our RotateMethod method exists
If (method = "irotate") {
Log("Rotate - Rotating display using irotate.exe to " . degrees . " degrees",4)
Run(rotateExe . " /rotate=" degrees " /exit", moduleExtensionsPath)
} Else If (method = "display") {
Log("Rotate - Rotating display using display.exe to " . degrees . " degrees",4)
Run(rotateExe . " /rotate:" degrees, moduleExtensionsPath)
} Else If (method = "shortcut") {
Log("Rotate - Rotating display using shortcut keys to " . degrees . " degrees",4)
Send, % "{LControl Down}{LAlt Down}{" . arrowKeys[degrees // 90] . " Down}{LControl Up}{LAlt Up}{" . arrowKeys[degrees // 90] . " Up}"
}
Log("Rotate - Ended")
}
;-------------------------------------------------------------------------------------------------------------
;-------------------------------------------- Database Asset Building ------------------------------------------
;-------------------------------------------------------------------------------------------------------------
; Builds an object filled with the FE's assets
BuildAssetsTable(list,label,AssetType,extensions="",obj=""){
Log("BuildAssetsTable - Started - Building Table for: " . label,4)
Global logLevel
StringReplace, extensionsReplaced, extensions, |, `,,All
If !(obj)
obj := {}
StringSplit, labelArray, label, |,
StringSplit, AssetTypeArray, AssetType, |,
Loop, Parse, list,|
{ If !(labelArray%A_Index% = "#disabled#")
{
Log("BuildAssetsTable - Searching for a " . labelArray%A_Index% . ": " . A_LoopField,4)
currentLabel := labelArray%A_Index%
currentAssetType := AssetTypeArray%A_index%
RASHNDOCT := FileExist(A_LoopField)
If InStr(RASHNDOCT, "D") { ; it is a folder
folderName := A_LoopFileName
Loop, % A_LoopField . "\*.*"
{ If RegExMatch(extensions,"i)" . A_LoopFileExt)
{ currentobj := {}
If (currentLabel="keepFileName")
currentobj["Label"] := folderName
Else
currentobj["Label"] := currentLabel
If obj[currentLabel].Label
{ currentobj := obj[currentLabel]
currentobj.TotalItems := currentobj.TotalItems+1
} Else {
currentobj.TotalItems := 1
obj.TotalLabels := if obj.TotalLabels ? obj.TotalLabels + 1 : 1
obj[obj.TotalLabels] := currentobj.Label
}
currentobj["Path" . currentobj.TotalItems] := A_LoopFileLongPath
currentobj["Ext" . currentobj.TotalItems] := A_LoopFileExt
currentobj["AssetType"] := currentAssetType
currentobj["Type"] := "ImageGroup"
obj.Insert(currentobj["Label"], currentobj)
}
}
} Else If InStr(RASHNDOCT, "A") { ; it is a file
SplitPath, A_LoopField, , currentDir,, FileNameWithoutExtension
Loop, Parse, extensionsReplaced,`,
{
If FileExist(currentDir . "\" . FileNameWithoutExtension . "." . A_LoopField)
{ currentobj := {}
If (currentLabel="keepFileName")
currentobj["Label"] := FileNameWithoutExtension
Else
currentobj["Label"] := currentLabel
If obj[FileNameWithoutExtension].Label
{ currentobj := obj[FileNameWithoutExtension]
currentobj.TotalItems := currentobj.TotalItems+1
} Else {
currentobj.TotalItems := 1
obj.TotalLabels := if obj.TotalLabels ? obj.TotalLabels + 1 : 1
obj[obj.TotalLabels] := currentobj.Label
}
currentobj["Path" . currentobj.TotalItems] := currentDir . "\" . FileNameWithoutExtension . "." . A_LoopField
currentobj["Ext" . currentobj.TotalItems] := A_LoopField
currentobj["AssetType"] := currentAssetType
obj.Insert(currentobj["Label"], currentobj)
}
}
}
} Else
Log("BuildAssetsTable - This asset has been disabled: " . labelArray%A_Index%,4)
}
If (logLevel>=5){
for index, element in obj
{ Loop, % obj[element.Label].TotalItems
mediaAssetsLog := % mediaAssetsLog . "`r`n`t`t`t`t`tAsset Label: " . element.Label . " | Asset Path" . a_index . ": " . element["Path" . a_index] . " | Asset Extension" . a_index . ": " . element["Ext" . a_index] . " | Asset Type" . a_index . ": " . element["AssetType"]
}
If mediaAssetsLog
Log("BuildAssetsTable - Media assets found: " . mediaAssetsLog,5)
}
Log("BuildAssetsTable - Ended",4)
Return obj
}
BuildAssetsTableOld(list,label,AssetType,extensions=""){
Log("BuildAssetsTable - Started - Building Table for: " . label,4)
Global logLevel
StringReplace, extensionsReplaced, extensions, |, `,,All
obj:={}
StringSplit, labelArray, label, |,
StringSplit, AssetTypeArray, AssetType, |,
Loop, Parse, list,|
{ labelIndex++
If !(labelArray%labelIndex% = "#disabled#")
{
Log("BuildAssetsTable - Searching for a " . labelArray%labelIndex% . ": " . A_LoopField,4)
currentLabel := labelArray%labelIndex%
currentAssetType := AssetTypeArray%A_index%
RASHNDOCT := FileExist(A_LoopField)
If InStr(RASHNDOCT, "D") { ; it is a folder
folderName := A_LoopFileName
Loop, % A_LoopField . "\*.*"
{ If RegExMatch(extensions,"i)" . A_LoopFileExt)
{ currentobj := {}
If (currentLabel="keepFileName")
currentobj["Label"] := folderName
Else
currentobj["Label"] := currentLabel
If obj[currentLabel].Label
{ currentobj := obj[currentLabel]
currentobj.TotalItems := currentobj.TotalItems+1
} Else {
currentobj.TotalItems := 1
obj.TotalLabels := if obj.TotalLabels ? obj.TotalLabels + 1 : 1
obj[obj.TotalLabels] := currentobj.Label
}
currentobj["Path" . currentobj.TotalItems] := A_LoopFileLongPath
currentobj["Ext" . currentobj.TotalItems] := A_LoopFileExt
currentobj["AssetType"] := currentAssetType
currentobj["Type"] := "ImageGroup"
obj.Insert(currentobj["Label"], currentobj)
}
}
} Else If InStr(RASHNDOCT, "A") { ; it is a file
SplitPath, A_LoopField, , currentDir,, FileNameWithoutExtension
Loop, Parse, extensionsReplaced,`,
{
If (InStr(extensionsReplaced , ",") && A_Index >= 2) {
labelIndex++ ; need to advance the label by one each time a new extension is used
currentLabel := labelArray%labelIndex%
}
If FileExist(currentDir . "\" . FileNameWithoutExtension . "." . A_LoopField)
{ currentobj := {}
If (currentLabel="keepFileName")
currentobj["Label"] := FileNameWithoutExtension
Else
currentobj["Label"] := currentLabel
If obj[FileNameWithoutExtension].Label
{ currentobj := obj[FileNameWithoutExtension]
currentobj.TotalItems := currentobj.TotalItems+1
} Else {
currentobj.TotalItems := 1
obj.TotalLabels := if obj.TotalLabels ? obj.TotalLabels + 1 : 1
obj[obj.TotalLabels] := currentobj.Label
}
currentobj["Path" . currentobj.TotalItems] := currentDir . "\" . FileNameWithoutExtension . "." . A_LoopField
currentobj["Ext" . currentobj.TotalItems] := A_LoopField
currentobj["AssetType"] := currentAssetType
obj.Insert(currentobj["Label"], currentobj)
}
}
}
} Else
Log("BuildAssetsTable - This asset has been disabled: " . labelArray%labelIndex%,4)
}
If (logLevel>=5){
for index, element in obj
{ Loop, % obj[element.Label].TotalItems
mediaAssetsLog := % mediaAssetsLog . "`r`n`t`t`t`t`tAsset Label: " . element.Label . " | Asset Path" . a_index . ": " . element["Path" . a_index] . " | Asset Extension" . a_index . ": " . element["Ext" . a_index] . " | Asset Type" . a_index . ": " . element["AssetType"]
}
If mediaAssetsLog
Log("BuildAssetsTable - Media assets found: " . mediaAssetsLog,5)
}
Log("BuildAssetsTable - Ended",4)
Return obj
}
;-------------------------------------------------------------------------------------------------------------
;-------------------------------------- Broadcast and Message Receiving --------------------------------------
;-------------------------------------------------------------------------------------------------------------
ReceiveMessage(wParam, lParam) ; receive messages from other programs
{ Global Pause_Active, Pause_Running, systemName, gameInfo
;Global ; it is necessary to use global if the var definition part is uncommented
StringAddress := NumGet(lParam + 8)
StringLength := DllCall("lstrlen", UInt, StringAddress)
If (StringLength <= 0)
Log("A blank string message was received by RocketLauncher or there was an error.")
Else
{ VarSetCapacity(CopyOfData, StringLength)
DllCall("lstrcpy", "str", CopyOfData, "uint", StringAddress)
StringSplit, Data, CopyOfData, |
If (Data1)
{
If (Data1="command") { ; predefined commands
If (Data2="RLPause") {
If (Pause_Active){
Gosub, TogglePauseMenuStatus
Log("RocketLauncher received the windows message to unpause the game: " . Data2)
} Else If !(Pause_Running) {
Gosub, TogglePauseMenuStatus
Log("RocketLauncher received the windows message to pause the game: " . Data2)
}
} Else If (Data2="RLSelect") {
If (Pause_Active){
Gosub, ToggleItemSelectStatus
}
} Else If (Data2="RLUp") {
If (Pause_Active){
Gosub, MoveUp
}
} Else If (Data2="RLDown") {
If (Pause_Active){
Gosub, MoveDown
}
} Else If (Data2="RLLeft") {
If (Pause_Active){
Gosub, MoveLeft
}
} Else If (Data2="RLRight") {
If (Pause_Active){
Gosub, MoveRight
}
} Else If (Data2="RLExit") {
Gosub, CloseProcess
} Else {
Log("RocketLauncher received the windows message to run a inexistent command: " . Data2)
}
} Else If (Data1="ping") {
BroadcastMessage("RocketLauncher Message System is Available.")
} Else If (Data1="Which system?") {
BroadcastMessage("RocketLauncher Message. Current System: " . systemName)
} Else If (Data1="Which game?") {
BroadcastMessage("RocketLauncher Message. Current Game: " . gameInfo["Name"].Value)
}
/*} if (Data1="runlabel") {
if IsLabel(Data2) {
Log("RocketLauncher received the windows message to run the label: " . Data2)
gosub, %Data2%
} Else {
Log("RocketLauncher received the windows message to run a inexistent label: " . Data2)
}
} Else If (Data1="setvar") {
Log("RocketLauncher received the windows message to set the variable named " . Data2 . " to the value = " . Data3)
%Data2% := Data3
*/
} Else
Log("RocketLauncher does not recognize the pure string message sent as a valid command: " . CopyOfData)
}
Return true
}
BroadcastMessage(StringToSend) {
Global broadcastWindowTitle
If broadcastWindowTitle {
VarSetCapacity(CopyDataStruct, 12, 0)
NumPut(StrLen(StringToSend) + 1, CopyDataStruct, 4)
NumPut(&StringToSend, CopyDataStruct, 8)
Prev_DetectHiddenWindows := A_DetectHiddenWindows
Prev_TitleMatchMode := A_TitleMatchMode
DetectHiddenWindows On
SetTitleMatchMode 2
; If (BroadcastWindowTitle="All"){
; Log("BroadcastMessage - Sending message """ . StringToSend . """ to all windows.")
; SendMessage, 0x4a, 0, &CopyDataStruct,, ahk_id 0xFFFF
If InStr(BroadcastWindowTitle, "|") {
Loop, Parse, BroadcastWindowTitle, |, %A_Space%
{ Log("BroadcastMessage - Sending message """ . StringToSend . """ to " . A_LoopField . " window.")
SendMessage, 0x4a, 0, &CopyDataStruct,, % BroadcastWindowTitle
}
} Else If (BroadcastWindowTitle){
If (WinExist(BroadcastWindowTitle) != "0x0") {
Log("BroadcastMessage - Sending message """ . StringToSend . """ to " . BroadcastWindowTitle . " window.")
SendMessage, 0x4a, 0, &CopyDataStruct,, % BroadcastWindowTitle
} Else
Log("BroadcastMessage - Could not broadcast message """ . StringToSend . """ to " . BroadcastWindowTitle . " because the window could not be found.",2)
} Else
Log("Message was not broadcasted because the lack of a valid window target.",4)
DetectHiddenWindows %Prev_DetectHiddenWindows%
SetTitleMatchMode %Prev_TitleMatchMode%
Return ErrorLevel ; Return SendMessage's reply back to our caller.
}
}
;-------------------------------------------------------------------------------------------------------------
;----------------------------------------- Split Screen Module Support ------------------------------------------
;-------------------------------------------------------------------------------------------------------------
; SplitScreenPos function
; Returns an object with the screen coordinates (posArray[screen number].x, posArray[screen number].y, posArray[screen number].w and posArray[screen number].h) for placing split screen emulator screens.
; Supports up to 8 screens
; splitScreen2PlayersMode can be Vertical or Horizontal
; splitScreen3PlayersMode can be P1top, P1left, P1right, P1bottom
; maxPlayersPerMonitor defines the maximun amount of player screens to be placed at each monitor. For example, "1|2|3" means that screen 1 will only have the player 1, screen 2 will have the player 2 and 3 and screen 3 will have the players 4, 5 and 6 screens. If the current available monitors is not able to show the selected number of players, the code will automatically increase the screen 1 amount of screens untill all players are displayed
SplitScreenPos(numberofPlayers,splitScreen2PlayersMode="Horizontal",splitScreen3PlayersMode="P1top",maxPlayersPerMonitor="4|4|4"){
Global monitorTable
Log("SplitScreenPos - Started")
;Making sure to distribute screens only on current available monitors and find out how many monitors are needed to show the selected number of players
monitor := []
StringSplit,playerPerMonitor,maxPlayersPerMonitor,|
Loop, % monitorTable.MaxIndex()
{ monitor[a_index] := {}
currentNumberOfPlayers := playerPerMonitor%a_index%
accumulatedPlayers += currentNumberOfPlayers
If (accumulatedPlayers>numberofPlayers)
currentNumberOfPlayers := numberofPlayers - (accumulatedPlayers-currentNumberOfPlayers)
monitor[a_index].numberOfPlayers := currentNumberOfPlayers
}
If (accumulatedPlayers<numberofPlayers){
Loop, % (numberofPlayers-accumulatedPlayers)
{ count1++
If ( count1 > monitorTable.MaxIndex() )
count1 := 1
monitor[count1].numberOfPlayers += 1
}
}
;Defining splitscreen positions
posArray := []
Loop, % numberofPlayers
posArray[a_index] := {}
count := 0
Loop, % monitor.MaxIndex()
{ currentMonitor := a_index
If (monitor[currentMonitor].numberOfPlayers = 1){
posArray[count+1].X := monitorTable[currentMonitor].Left , posArray[count+1].Y := monitorTable[currentMonitor].Top , posArray[count+1].W := monitorTable[currentMonitor].Width , posArray[count+1].H := monitorTable[currentMonitor].Height
} Else If (monitor[currentMonitor].numberOfPlayers = 2){
If (splitScreen2PlayersMode = "Vertical"){
posArray[count+1].X := monitorTable[currentMonitor].Left , posArray[count+1].Y := monitorTable[currentMonitor].Top , posArray[count+1].W := monitorTable[currentMonitor].Width//2 , posArray[count+1].H := monitorTable[currentMonitor].Height
posArray[count+2].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width//2 , posArray[count+2].Y := monitorTable[currentMonitor].Top , posArray[count+2].W := monitorTable[currentMonitor].Width//2 , posArray[count+2].H := monitorTable[currentMonitor].Height
} Else {
posArray[count+1].X := monitorTable[currentMonitor].Left , posArray[count+1].Y := monitorTable[currentMonitor].Top , posArray[count+1].W := monitorTable[currentMonitor].Width , posArray[count+1].H := monitorTable[currentMonitor].Height//2
posArray[count+2].X := monitorTable[currentMonitor].Left , posArray[count+2].Y := monitorTable[currentMonitor].Top+monitorTable[currentMonitor].Height//2 , posArray[count+2].W := monitorTable[currentMonitor].Width , posArray[count+2].H := monitorTable[currentMonitor].Height//2
}
} Else If (monitor[currentMonitor].numberOfPlayers = 3){
If (splitScreen3PlayersMode = "P1left"){
posArray[count+1].X := monitorTable[currentMonitor].Left , posArray[count+1].Y := monitorTable[currentMonitor].Top , posArray[count+1].W := monitorTable[currentMonitor].Width//2 , posArray[count+1].H := monitorTable[currentMonitor].Height
posArray[count+2].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width//2 , posArray[count+2].Y := monitorTable[currentMonitor].Top , posArray[count+2].W := monitorTable[currentMonitor].Width//2 , posArray[count+2].H := monitorTable[currentMonitor].Height//2
posArray[count+3].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width//2 , posArray[count+3].Y := monitorTable[currentMonitor].Top+monitorTable[currentMonitor].Height//2 , posArray[count+3].W := monitorTable[currentMonitor].Width//2 , posArray[count+3].H := monitorTable[currentMonitor].Height//2
} Else If (splitScreen3PlayersMode = "P1bottom") {
posArray[count+1].X := monitorTable[currentMonitor].Left , posArray[count+1].Y := monitorTable[currentMonitor].Top+monitorTable[currentMonitor].Height//2 , posArray[count+1].W := monitorTable[currentMonitor].Width , posArray[count+1].H := monitorTable[currentMonitor].Height//2
posArray[count+2].X := monitorTable[currentMonitor].Left , posArray[count+2].Y := monitorTable[currentMonitor].Top , posArray[count+2].W := monitorTable[currentMonitor].Width//2 , posArray[count+2].H := monitorTable[currentMonitor].Height//2
posArray[count+3].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width//2 , posArray[count+3].Y := monitorTable[currentMonitor].Top , posArray[count+3].W := monitorTable[currentMonitor].Width//2 , posArray[count+3].H := monitorTable[currentMonitor].Height//2
} Else If (splitScreen3PlayersMode = "P1right") {
posArray[count+1].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width//2 , posArray[count+1].Y := monitorTable[currentMonitor].Top , posArray[count+1].W := monitorTable[currentMonitor].Width//2 , posArray[count+1].H := monitorTable[currentMonitor].Height
posArray[count+2].X := monitorTable[currentMonitor].Left , posArray[count+2].Y := monitorTable[currentMonitor].Top , posArray[count+2].W := monitorTable[currentMonitor].Width//2 , posArray[count+2].H := monitorTable[currentMonitor].Height//2
posArray[count+3].X := monitorTable[currentMonitor].Left , posArray[count+3].Y := monitorTable[currentMonitor].Top+monitorTable[currentMonitor].Height//2 , posArray[count+3].W := monitorTable[currentMonitor].Width//2 , posArray[count+3].H := monitorTable[currentMonitor].Height//2
} Else { ;top
posArray[count+1].X := monitorTable[currentMonitor].Left , posArray[count+1].Y := monitorTable[currentMonitor].Top , posArray[count+1].W := monitorTable[currentMonitor].Width , posArray[count+1].H := monitorTable[currentMonitor].Height//2
posArray[count+2].X := monitorTable[currentMonitor].Left , posArray[count+2].Y := monitorTable[currentMonitor].Top+monitorTable[currentMonitor].Height//2 , posArray[count+2].W := monitorTable[currentMonitor].Width//2 , posArray[count+2].H := monitorTable[currentMonitor].Height//2
posArray[count+3].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width//2 , posArray[count+3].Y := monitorTable[currentMonitor].Top+monitorTable[currentMonitor].Height//2 , posArray[count+3].W := monitorTable[currentMonitor].Width//2 , posArray[count+3].H := monitorTable[currentMonitor].Height//2
}
} Else If (monitor[currentMonitor].numberOfPlayers = 4){
posArray[count+1].X := monitorTable[currentMonitor].Left , posArray[count+1].Y := monitorTable[currentMonitor].Top , posArray[count+1].W := monitorTable[currentMonitor].Width//2 , posArray[count+1].H := monitorTable[currentMonitor].Height//2
posArray[count+2].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width//2 , posArray[count+2].Y := monitorTable[currentMonitor].Top , posArray[count+2].W := monitorTable[currentMonitor].Width//2 , posArray[count+2].H := monitorTable[currentMonitor].Height//2
posArray[count+3].X := monitorTable[currentMonitor].Left , posArray[count+3].Y := monitorTable[currentMonitor].Top+monitorTable[currentMonitor].Height//2 , posArray[count+3].W := monitorTable[currentMonitor].Width//2 , posArray[count+3].H := monitorTable[currentMonitor].Height//2
posArray[count+4].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width//2 , posArray[count+4].Y := monitorTable[currentMonitor].Top+monitorTable[currentMonitor].Height//2 , posArray[count+4].W := monitorTable[currentMonitor].Width//2 , posArray[count+4].H := monitorTable[currentMonitor].Height//2
} Else If (monitor[currentMonitor].numberOfPlayers = 5){
posArray[count+1].X := monitorTable[currentMonitor].Left , posArray[count+1].Y := monitorTable[currentMonitor].Top , posArray[count+1].W := monitorTable[currentMonitor].Width//2 , posArray[count+1].H := monitorTable[currentMonitor].Height//2
posArray[count+2].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width//2 , posArray[count+2].Y := monitorTable[currentMonitor].Top , posArray[count+2].W := monitorTable[currentMonitor].Width//2 , posArray[count+2].H := monitorTable[currentMonitor].Height//2
posArray[count+3].X := monitorTable[currentMonitor].Left , posArray[count+3].Y := monitorTable[currentMonitor].Top+monitorTable[currentMonitor].Height//2 , posArray[count+3].W := monitorTable[currentMonitor].Width//3 , posArray[count+3].H := monitorTable[currentMonitor].Height//2
posArray[count+4].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width//3 , posArray[count+4].Y := monitorTable[currentMonitor].Top+monitorTable[currentMonitor].Height//2 , posArray[count+4].W := monitorTable[currentMonitor].Width//3 , posArray[count+4].H := monitorTable[currentMonitor].Height//2
posArray[count+5].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width*2//3 , posArray[count+5].Y := monitorTable[currentMonitor].Top+monitorTable[currentMonitor].Height//2 , posArray[count+5].W := monitorTable[currentMonitor].Width//3 , posArray[count+5].H := monitorTable[currentMonitor].Height//2
} Else If (monitor[currentMonitor].numberOfPlayers = 6){
posArray[count+1].X := monitorTable[currentMonitor].Left , posArray[count+1].Y := monitorTable[currentMonitor].Top , posArray[count+1].W := monitorTable[currentMonitor].Width//3 , posArray[count+1].H := monitorTable[currentMonitor].Height//2
posArray[count+2].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width//3 , posArray[count+2].Y := monitorTable[currentMonitor].Top , posArray[count+2].W := monitorTable[currentMonitor].Width//3 , posArray[count+2].H := monitorTable[currentMonitor].Height//2
posArray[count+3].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width*2//3 , posArray[count+3].Y := monitorTable[currentMonitor].Top , posArray[count+3].W := monitorTable[currentMonitor].Width//3 , posArray[count+3].H := monitorTable[currentMonitor].Height//2
posArray[count+4].X := monitorTable[currentMonitor].Left , posArray[count+4].Y := monitorTable[currentMonitor].Top+monitorTable[currentMonitor].Height//2 , posArray[count+4].W := monitorTable[currentMonitor].Width//3 , posArray[count+4].H := monitorTable[currentMonitor].Height//2
posArray[count+5].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width//3 , posArray[count+5].Y := monitorTable[currentMonitor].Top+monitorTable[currentMonitor].Height//2 , posArray[count+5].W := monitorTable[currentMonitor].Width//3 , posArray[count+5].H := monitorTable[currentMonitor].Height//2
posArray[count+6].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width*2//3 , posArray[count+6].Y := monitorTable[currentMonitor].Top+monitorTable[currentMonitor].Height//2 , posArray[count+6].W := monitorTable[currentMonitor].Width//3 , posArray[count+6].H := monitorTable[currentMonitor].Height//2
} Else If (monitor[currentMonitor].numberOfPlayers = 7){
posArray[count+1].X := monitorTable[currentMonitor].Left , posArray[count+1].Y := monitorTable[currentMonitor].Top , posArray[count+1].W := monitorTable[currentMonitor].Width//3 , posArray[count+1].H := monitorTable[currentMonitor].Height//2
posArray[count+2].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width//3 , posArray[count+2].Y := monitorTable[currentMonitor].Top , posArray[count+2].W := monitorTable[currentMonitor].Width//3 , posArray[count+2].H := monitorTable[currentMonitor].Height//2
posArray[count+3].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width*2//3 , posArray[count+3].Y := monitorTable[currentMonitor].Top , posArray[count+3].W := monitorTable[currentMonitor].Width//3 , posArray[count+3].H := monitorTable[currentMonitor].Height//2
posArray[count+4].X := monitorTable[currentMonitor].Left , posArray[count+4].Y := monitorTable[currentMonitor].Top+monitorTable[currentMonitor].Height//2 , posArray[count+4].W := monitorTable[currentMonitor].Width//4 , posArray[count+4].H := monitorTable[currentMonitor].Height//2
posArray[count+5].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width//4 , posArray[count+5].Y := monitorTable[currentMonitor].Top+monitorTable[currentMonitor].Height//2 , posArray[count+5].W := monitorTable[currentMonitor].Width//4 , posArray[count+5].H := monitorTable[currentMonitor].Height//2
posArray[count+6].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width*2//4 , posArray[count+6].Y := monitorTable[currentMonitor].Top+monitorTable[currentMonitor].Height//2 , posArray[count+6].W := monitorTable[currentMonitor].Width//4 , posArray[count+6].H := monitorTable[currentMonitor].Height//2
posArray[count+7].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width*3//4 , posArray[count+7].Y := monitorTable[currentMonitor].Top+monitorTable[currentMonitor].Height//2 , posArray[count+7].W := monitorTable[currentMonitor].Width//4 , posArray[count+7].H := monitorTable[currentMonitor].Height//2
} Else If (monitor[currentMonitor].numberOfPlayers = 8){
posArray[count+1].X := monitorTable[currentMonitor].Left , posArray[count+1].Y := monitorTable[currentMonitor].Top , posArray[count+1].W := monitorTable[currentMonitor].Width//4 , posArray[count+1].H := monitorTable[currentMonitor].Height//2
posArray[count+2].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width//4 , posArray[count+2].Y := monitorTable[currentMonitor].Top , posArray[count+2].W := monitorTable[currentMonitor].Width//4 , posArray[count+2].H := monitorTable[currentMonitor].Height//2
posArray[count+3].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width*2//4 , posArray[count+3].Y := monitorTable[currentMonitor].Top , posArray[count+3].W := monitorTable[currentMonitor].Width//4 , posArray[count+3].H := monitorTable[currentMonitor].Height//2
posArray[count+4].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width*3//4 , posArray[count+4].Y := monitorTable[currentMonitor].Top , posArray[count+4].W := monitorTable[currentMonitor].Width//4 , posArray[count+4].H := monitorTable[currentMonitor].Height//2
posArray[count+5].X := monitorTable[currentMonitor].Left , posArray[count+5].Y := monitorTable[currentMonitor].Top+monitorTable[currentMonitor].Height//2 , posArray[count+5].W := monitorTable[currentMonitor].Width//4 , posArray[count+5].H := monitorTable[currentMonitor].Height//2
posArray[count+6].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width//4 , posArray[count+6].Y := monitorTable[currentMonitor].Top+monitorTable[currentMonitor].Height//2 , posArray[count+6].W := monitorTable[currentMonitor].Width//4 , posArray[count+6].H := monitorTable[currentMonitor].Height//2
posArray[count+7].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width*2//4 , posArray[count+7].Y := monitorTable[currentMonitor].Top+monitorTable[currentMonitor].Height//2 , posArray[count+7].W := monitorTable[currentMonitor].Width//4 , posArray[count+7].H := monitorTable[currentMonitor].Height//2
posArray[count+8].X := monitorTable[currentMonitor].Left+monitorTable[currentMonitor].Width*3//4 , posArray[count+8].Y := monitorTable[currentMonitor].Top+monitorTable[currentMonitor].Height//2 , posArray[count+8].W := monitorTable[currentMonitor].Width//4 , posArray[count+8].H := monitorTable[currentMonitor].Height//2
} Else {
Log("SplitScreenPos - " . monitor[currentMonitor].numberOfPlayers . " is a nonsupported number of players for the split screen position calculation function.",2)
}
Loop, % monitor[currentMonitor].numberOfPlayers
Log("SplitScreenPos - Player " . count+a_index . " window position: X=" . posArray[count+a_index].X . ", Y=" . posArray[count+a_index].Y . ", W=" . posArray[count+a_index].W . ", H=" . posArray[count+a_index].H,5)
count += monitor[currentMonitor].numberOfPlayers
If (count >= numberofPlayers)
Break
}
Log("SplitScreenPos - Ended")
Return posArray
}
Comments