Advertisement
djvj

shared.ahk rlui crash test

Feb 12th, 2016
301
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 164.87 KB | None | 0 0
  1. MCRC=93430C5C
  2. MVersion=1.4.0
  3.  
  4. StartModule(){
  5. Global gameSectionStartTime,gameSectionStartHour,skipChecks,dbName,romPath,romPathOrig,romName,romExtension,systemName,MEmu,MEmuV,MURL,MAuthor,MVersion,MCRC,iCRC,MSystem,romMapTable,romMappingLaunchMenuEnabled,romMenuRomName,sevenZEnabled,hideCursor,toggleCursorKey,servoStikEnabled,ledblinkyEnabled,winVer,setResolution,zz
  6. Global mgEnabled,mgOnLaunch,mgCandidate,mgLaunchMenuActive,MultiGame_Running,keyboardEncoder,keyboardEncoderEnabled,ultraMapFullPath,winIPACFullPath
  7. Global rIniIndex,globalPluginsFile,sysPluginsFile
  8. Log("StartModule - Started")
  9. 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)
  10. If InStr(MSystem,systemName)
  11. Log("StartModule - You have a supported System Name for this module: """ . systemName . """")
  12. Else
  13. Log("StartModule - You have an unsupported System Name for this module: """ . systemName . """. Only the following System Names are suppported: """ . MSystem . """",2)
  14.  
  15. winVer := If A_Is64bitOS ? "64" : "32" ; get windows version
  16.  
  17. ;-----------------------------------------------------------------------------------------------------------------------------------------
  18. ; Plugin Specific Settings from Settings \ Global Plugins.ini and Settings \ %systemName% \ Plugins.ini
  19. ;-----------------------------------------------------------------------------------------------------------------------------------------
  20. rIniIndex := {} ; initialize the RIni array
  21. globalPluginsFile := A_ScriptDir . "\Settings\Global Plugins.ini"
  22. If !FileExist(globalPluginsFile)
  23. FileAppend,, %globalPluginsFile% ; create blank ini
  24. RIni_Read(8,globalPluginsFile)
  25. rIniIndex[8] := globalPluginsFile ; assign to array
  26.  
  27. sysPluginsFile := A_ScriptDir . "\Settings\" . systemName . "\Plugins.ini"
  28. If !FileExist(sysPluginsFile)
  29. FileAppend,, %sysPluginsFile% ; create blank ini
  30. RIni_Read(9,sysPluginsFile)
  31. rIniIndex[9] := sysPluginsFile ; assign to array
  32.  
  33. Gosub, PluginInit ; initialize plugin vars
  34. ; Gosub, ReadFEGameInfo ; read plugin data
  35. ;-----------------------------------------------------------------------------------------------------------------------------------------
  36.  
  37. If (mgEnabled = "true" && mgOnLaunch = "true" && mgCandidate) { ; only if user has mgOnLaunch enabled
  38. mgLaunchMenuActive := true
  39. Log("StartModule - MultiGame_On_Launch execution started.",4)
  40. Gosub, StartMulti
  41. Sleep, 200
  42. Loop {
  43. If !MultiGame_Running
  44. Break
  45. }
  46. mgLaunchMenuActive := false
  47. Log("StartModule - MultiGame_On_Launch execution ended.",4)
  48. }
  49. If (romMappingLaunchMenuEnabled = "true" && romMapTable.MaxIndex()) ; && romMapMultiRomsFound)
  50. CreateRomMappingLaunchMenu%zz%(romMapTable)
  51. ; msgbox dbName: %dbName%`nromName: %romName%`nromMenuRomName: %romMenuRomName%`nsevenZEnabled: %sevenZEnabled%`nskipChecks: %skipChecks%
  52. 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)
  53. { Log("StartModule - Setting romName to the game picked from the Launch Menu: " . romMenuRomName,4)
  54. romName := romMenuRomName
  55. } Else If romName && romMapTable.MaxIndex()
  56. { Log("StartModule - Leaving romName as is because Rom Mapping filled it with an Alternate_Rom_Name: " . romName,4)
  57. romName := romName ; When Rom Mapping is used but no Alternate_Archive_Name key exists yet Alternate_Rom_Name key(s) were used.
  58. } Else If romMapTable.MaxIndex()
  59. { Log("StartModule - Not setting romName because Launch Menu was used and 7z will take care of it.",4)
  60. romName := "" ; If a romMapTable exists with roms, do not fill romName yet as 7z will take care of that.
  61. } Else
  62. { Log("StartModule - Setting romName to the dbName sent to RocketLauncher: " . dbName,4)
  63. romName := dbName ; Use dbName if previous checks are false
  64. }
  65.  
  66. romPathOrig := romPath ; storing original rom path for any modules or features that need this before 7z updates it.
  67.  
  68. If (setResolution != "")
  69. SetDisplaySettings(setResolution)
  70.  
  71. If RegExMatch(hideCursor,"i)true|do_not_restore")
  72. SystemCursor("Off")
  73. Else If RegExMatch(hideCursor,"i)custom|custom_do_not_restore") {
  74. cursor := GetRLMediaFiles("Cursors","cur|ani") ;load cursor file for the system if they exist
  75. If cursor
  76. SetSystemCursor(Cursor) ; replace system cursors
  77. }
  78. If toggleCursorKey
  79. XHotKeywrapper(toggleCursorKey,"ToggleCursor")
  80. If (ledblinkyEnabled = "All")
  81. LEDBlinky("START")
  82. KeymapperProfileSelect("START", keyboardEncoder, %keyboardEncoder%FullPath, "ipc", "keyboard")
  83. KeymapperProfileSelect("START", "UltraMap", ultraMapFullPath, "ugc")
  84. If (servoStikEnabled = 4 || servoStikEnabled = 8)
  85. ServoStik(servoStikEnabled) ; handle servostiks on start
  86.  
  87. ; 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
  88. Gui, show,Hide,RocketLauncherMessageReceiver ; creating hidden GUI to receive RocketLauncher messages
  89. OnMessage(0x4a, "ReceiveMessage")
  90. BroadcastMessage("RocketLauncher Message: Welcome! :)")
  91. gameSectionStartTime := A_TickCount
  92. gameSectionStartHour := A_Now
  93. ; msgbox % "romPath: " . romPath . "`nromName: " . romName . "`nromExtension: " . romExtension . "`nromMenuRomName: " . romMenuRomName . "`nromMapTable.MaxIndex(): " . romMapTable.MaxIndex()
  94. Log("StartModule - Ended")
  95. }
  96.  
  97. ; ExitModule function in case we need to call anything on the module's exit routine, like UpdateStatistics for Pause or UnloadKeymapper
  98. ExitModule(){
  99. Global statisticsEnabled,keymapperEnabled,keymapper,keymapperAHKMethod,keymapperLoaded,logShowCommandWindow,pToken,cmdWindowObj,mouseCursorHidden,cursor,hideCursor,rocketLauncherIsExiting,servoStikExitMode,ledblinkyEnabled,zz
  100. Global JoyIDsEnabled,JoyIDsPreferredControllersOnExit,keyboardEncoder,keyboardEncoderEnabled,ultraMapFullPath,winIPACFullPath
  101. Log("ExitModule - Started")
  102. rocketLauncherIsExiting := 1 ; notifies rest of the thread that the exit routine was triggered
  103. If (statisticsEnabled = "true")
  104. Gosub, UpdateStatistics
  105. If (keymapperEnabled = "true" && keymapperLoaded)
  106. RunKeyMapper%zz%("unload",keymapper)
  107. If keymapperAHKMethod = External
  108. RunAHKKeymapper%zz%("unload")
  109. If (JoyIDsEnabled = "true" && JoyIDsPreferredControllersOnExit)
  110. LoadPreferredControllers%zz%(JoyIDsPreferredControllersOnExit)
  111. If (hideCursor = "custom" and cursor)
  112. RestoreCursors() ; retore default system cursors
  113. If mouseCursorHidden ; just in case
  114. SystemCursor("On")
  115. If (ledblinkyEnabled = "All")
  116. LEDBlinky("END")
  117. KeymapperProfileSelect("END", keyboardEncoder, %keyboardEncoder%FullPath, "ipc", "keyboard")
  118. KeymapperProfileSelect("END", "UltraMap", ultraMapFullPath, "ugc")
  119. If (servoStikExitMode = 4 || servoStikExitMode = 8)
  120. ServoStik(servoStikExitMode) ; handle servostiks on exit
  121. If logShowCommandWindow = true
  122. Loop {
  123. If !cmdWindowObj[A_Index,"Name"]
  124. Break
  125. Else {
  126. Log("ExitModule - Closing command window: " . cmdWindowObj[A_Index,"Name"] . " PID: " . cmdWindowObj[A_Index,"PID"],4)
  127. Process("Close", cmdWindowObj[A_Index,"Name"]) ; close each opened cmd.exe
  128. }
  129. }
  130. BroadcastMessage("RocketLauncher Message: Goodbye! :(")
  131. Gdip_Shutdown(pToken) ; gdi+ may now be shutdown on exiting the thread
  132. Log("ExitModule - Ended")
  133. Log("End of Module Logs",,,1)
  134. ExitApp
  135. }
  136.  
  137. WinWait(winTitle,winText="",secondsToWait=30,excludeTitle="",excludeText=""){
  138. Global detectFadeErrorEnabled, logLevel
  139. If logLevel > 3
  140. GetActiveWindowStatus()
  141. Log("WinWait - Waiting for """ . winTitle . """")
  142. WinWait, %winTitle% ,%winText% , %secondsToWait% , %excludeTitle% ,%excludeText%
  143. curErr := ErrorLevel ; have to store this because GetActiveWindowStatus will reset it
  144. If logLevel > 3
  145. GetActiveWindowStatus()
  146. If (curErr and detectFadeErrorEnabled = "true")
  147. 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)
  148. Else If (curErr and detectFadeErrorEnabled != "true")
  149. 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)
  150. Return curErr
  151. }
  152.  
  153. WinWaitActive(winTitle,winText="",secondsToWait=30,excludeTitle="",excludeText=""){
  154. Global detectFadeErrorEnabled, logLevel, emulatorProcessID, emulatorVolumeObject, emulatorInitialMuteState, fadeMuteEmulator, fadeIn
  155. If (logLevel > 3)
  156. GetActiveWindowStatus()
  157. Log("WinWaitActive - Waiting for """ . winTitle . """")
  158. WinWaitActive, %winTitle% ,%winText% , %secondsToWait% , %excludeTitle% ,%excludeText%
  159. curErr := ErrorLevel ; have to store this because GetActiveWindowStatus will reset it
  160. If (logLevel > 3)
  161. GetActiveWindowStatus()
  162. If (curErr and detectFadeErrorEnabled = "true")
  163. 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)
  164. Else If (curErr and detectFadeErrorEnabled != "true")
  165. 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)
  166. If !curErr
  167. {
  168. WinGet emulatorProcessID, PID, %winTitle%
  169. emulatorVolumeObject := GetVolumeObject(emulatorProcessID)
  170. If ((fadeMuteEmulator = "true") and (fadeIn = "true")){
  171. getMute(emulatorInitialMuteState, emulatorVolumeObject)
  172. setMute(1, emulatorVolumeObject)
  173. }
  174. }
  175. Return curErr
  176. }
  177.  
  178. WinWaitClose(winTitle,winText="",secondsToWait="",excludeTitle="",excludeText=""){
  179. Log("WinWaitClose - Waiting for """ . winTitle . """ to close")
  180. WinWaitClose, %winTitle% ,%winText% , %secondsToWait% , %excludeTitle% ,%excludeText%
  181. Return ErrorLevel
  182. }
  183.  
  184. WinClose(winTitle,winText="",secondsToWait="",excludeTitle="",excludeText=""){
  185. Log("WinClose - Closing: " . winTitle)
  186. WinClose, %winTitle%, %winText% , %secondsToWait%, %excludeTitle%, %excludeText%
  187. If (secondsToWait = "" || !secondsToWait)
  188. secondsToWait := 2 ; need to always have some timeout for this command otherwise it will wait forever
  189. WinWaitClose, %winTitle%, %winText% , %secondsToWait%, %excludeTitle%, %excludeText% ; only WinWaitClose reports an ErrorLevel
  190. Return ErrorLevel
  191. }
  192.  
  193. WinActivate(WinTitle,WinText="",ExcludeTitle="",ExcludeText="")
  194. {
  195. Log("WinActivate - Selecting " . Menu . " -> " . SubMenu1 . (SubMenu2 ? " -> " . SubMenu2 : "") . (SubMenu3 ? " -> " . SubMenu3 : "") . (SubMenu4 ? " -> " . SubMenu4 : "") . (SubMenu5 ? " -> " . SubMenu5 : "") . (SubMenu6 ? " -> " . SubMenu6 : ""),4)
  196. WinActivate,%WinTitle%,%WinText%,%Menu%,%SubMenu1%,%SubMenu2%,%SubMenu3%,%SubMenu4%,%SubMenu5%,%SubMenu6%,%ExcludeTitle%,%ExcludeText%
  197. Return ErrorLevel
  198. }
  199.  
  200. WinGet(cmd,WinTitle,WinText="",ExcludeTitle="",ExcludeText="",log=1)
  201. {
  202. WinGet,OutputVar,%cmd%,%WinTitle%,%WinText%,%ExcludeTitle%,%ExcludeText%
  203. If log
  204. Log("WinGet - Retrieved """ . OutputVar . """ from " . WinTitle . A_Space . WinText,4)
  205. Return OutputVar
  206. }
  207.  
  208. WinGetTitle(WinTitle,WinText="",ExcludeTitle="",ExcludeText="",log=1)
  209. {
  210. WinGetTitle,OutputVar,%WinTitle%,%WinText%,%ExcludeTitle%,%ExcludeText%
  211. If log
  212. Log("WinGetTitle - Retrieved """ . OutputVar . """ from " . WinTitle . A_Space . WinText,4)
  213. Return OutputVar
  214. }
  215.  
  216. WinGetPos(ByRef x,ByRef y,ByRef w,ByRef h,WinTitle,WinText="",ExcludeTitle="",ExcludeText="",log=1)
  217. {
  218. WinGetPos,x,y,w,h,%WinTitle%,%WinText%,%ExcludeTitle%,%ExcludeText%
  219. If log
  220. Log("WinGetPos - Retrieved x:" . x . " y:" . y . " w: " . w . " h: " . h . " from " . WinTitle . A_Space . WinText,4)
  221. Return
  222. }
  223.  
  224. WinHide(WinTitle,WinText="",ExcludeTitle="",ExcludeText="")
  225. {
  226. Log("WinHide - Hiding window " . WinTitle . A_Space . WinText,4)
  227. WinHide,%WinTitle%,%WinText%,%ExcludeTitle%,%ExcludeText%
  228. Return ErrorLevel
  229. }
  230.  
  231. WinMenuSelectItem(WinTitle,WinText="",Menu="",SubMenu1="",SubMenu2="",SubMenu3="",SubMenu4="",SubMenu5="",SubMenu6="",ExcludeTitle="",ExcludeText="")
  232. {
  233. If (!Menu || !SubMenu1)
  234. ScriptError("Menu and SubMenu are required for RL.WinMenuSelectItem")
  235. Log("WinMenuSelectItem - Selecting " . Menu . " -> " . SubMenu1 . (SubMenu2 ? " -> " . SubMenu2 : "") . (SubMenu3 ? " -> " . SubMenu3 : "") . (SubMenu4 ? " -> " . SubMenu4 : "") . (SubMenu5 ? " -> " . SubMenu5 : "") . (SubMenu6 ? " -> " . SubMenu6 : ""),4)
  236. WinMenuSelectItem,%WinTitle%,%WinText%,%Menu%,%SubMenu1%,%SubMenu2%,%SubMenu3%,%SubMenu4%,%SubMenu5%,%SubMenu6%,%ExcludeTitle%,%ExcludeText%
  237. Return ErrorLevel
  238. }
  239.  
  240. WinMove(x,y,w="",h="",WinTitle="",WinText="",ExcludeTitle="",ExcludeText="",log=1)
  241. {
  242. If WinTitle
  243. WinMove,%WinTitle%,%WinText%,%x%,%y%,%w%,%h%,%ExcludeTitle%,%ExcludeText%
  244. Else
  245. WinMove,%x%,%y%
  246. If log
  247. Log("WinMove - Moved " . WinTitle . A_Space . WinText . " to x:" . x . " y:" . y . " w: " . w . " h: " . h,4)
  248. Return
  249. }
  250.  
  251. WinRestore(WinTitle,WinText="",ExcludeTitle="",ExcludeText="")
  252. {
  253. Log("WinRestore - Restoring window " . WinTitle . A_Space . WinText,4)
  254. WinRestore,%WinTitle%,%WinText%,%ExcludeTitle%,%ExcludeText%
  255. Return ErrorLevel
  256. }
  257.  
  258. WinSet(Attribute,Value,WinTitle,WinText="",ExcludeTitle="",ExcludeText="")
  259. {
  260. Log("WinSet - Setting " . Attribute . " to " . Value . " on window " . WinTitle . A_Space . WinText,4)
  261. WinSet,%Attribute%,%Value%,%WinTitle%,%WinText%,%ExcludeTitle%,%ExcludeText%
  262. Return ErrorLevel
  263. }
  264.  
  265. WinShow(WinTitle,WinText="",ExcludeTitle="",ExcludeText="")
  266. {
  267. Log("WinShow - Unhiding window " . WinTitle . A_Space . WinText,4)
  268. WinShow,%WinTitle%,%WinText%,%ExcludeTitle%,%ExcludeText%
  269. Return ErrorLevel
  270. }
  271.  
  272. RunWait(target,workingDir="",options=0,ByRef outputVarPID=""){
  273. Global errorLevelReporting
  274. options := If options = 1 ? "useErrorLevel" : options ; enable or disable error level
  275. Log("RunWait - Started - running: " . workingDir . "\" . target)
  276. RunWait, %target%, %workingDir%, %options%, outputVarPID
  277. curErr := ErrorLevel ; store error level immediately
  278. Log("RunWait - """ . target . """ Process ID: " . outputVarPID . " and ErrorLevel reported as: " . curErr, 4)
  279. Return curErr
  280. }
  281.  
  282. ; 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.
  283. ; 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
  284. ; 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
  285. Run(target,workingDir="",options=0,ByRef outputVarPID="",inputBlocker=1,bypassCmdWindow=0,disableLogging=0){
  286. Static cmdWindowCount
  287. Global logShowCommandWindow,logCommandWindow,cmdWindowObj,blockInputTime,blockInputFile,errorLevelReporting
  288. options := If options = 1 ? "useErrorLevel" : options ; enable or disable error level
  289. If disableLogging
  290. Log("Run - Running hidden executable in " . workingDir)
  291. Else
  292. Log("Run - Running: " . workingDir . "\" . target)
  293. If (blockInputTime && inputBlocker = 1) ; if user set a block time, use the user set length
  294. blockTime := blockInputTime
  295. Else If (inputBlocker > 1) ; if module called for a block, use that amount
  296. blockTime := inputBlocker
  297. Else ; do not block input
  298. blockTime := ""
  299. If blockTime
  300. { Log("Run - Blocking Input for: " . blockTime . " seconds")
  301. Run, %blockInputFile% %blockTime%
  302. }
  303. If !cmdWindowObj
  304. cmdWindowObj := Object() ; initialize object, this is used so all the command windows can be properly closed on exit
  305. If (logShowCommandWindow = "true" && !bypassCmdWindow) {
  306. Run, %ComSpec% /k, %workingDir%, %options%, outputVarPID ; open a command window (cmd.exe), starting in the directory of the target executable
  307. curErr := ErrorLevel ; store error level immediately
  308. If errorLevelReporting = true
  309. { Log("Run - Error Level for " . ComSpec . " reported as: " . curErr, 4)
  310. errLvl := curErr ; allows the module to handle the error level
  311. }
  312. Log("Run - Showing Command Window to troubleshoot launching. ProcessID: " . outputVarPID)
  313. WinWait, ahk_pid %outputVarPID%
  314. WinActivate, ahk_pid %outputVarPID%
  315. WinWaitActive, ahk_pid %outputVarPID%,,2
  316. If ErrorLevel {
  317. WinSet, AlwaysOnTop, On, ahk_pid %outputVarPID%
  318. WinActivate, ahk_pid %outputVarPID%
  319. WinWaitActive, ahk_pid %outputVarPID%,,2
  320. If ErrorLevel
  321. 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")
  322. }
  323. WinGet, procName, ProcessName, ahk_pid %outputVarPID% ; get the name of the process (which should usually be cmd.exe)
  324. mapObjects[currentObj,"type"] := "database"
  325. cmdWindowCount++
  326. cmdWindowObj[cmdWindowCount,"Name"] := procName ; store the ProcessName being ran
  327. cmdWindowObj[cmdWindowCount,"PID"] := outputVarPID ; store the PID of the application being ran
  328. foundPos := RegExMatch(target,".*\.(exe|bat)",targetExeOnly) ; grab only the exe or bat file from the supplied target
  329. exeLen := StrLen(targetExeOnly) ; get length of exe name
  330. params := SubStr(target, exeLen+1) ; grab optional params out of supplied target
  331. If InStr(targetExeOnly, A_Space)
  332. target := """" . targetExeOnly . """" . params
  333. If (logCommandWindow = "true")
  334. 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
  335. Else
  336. SendInput, {Raw}%target% ; send the text to the command window and run it
  337. Send, {Enter}
  338. } Else {
  339. Run, %target%, %workingDir%, %options%, outputVarPID
  340. curErr := ErrorLevel ; store error level immediately
  341. If errorLevelReporting = true
  342. { Log("Run - Error Level for " . target . " reported as: " . curErr, 4)
  343. errLvl := curErr ; allows the module to handle the error level
  344. }
  345. }
  346. If disableLogging
  347. Log("Run - ""Hidden executable"" Process ID: " . outputVarPID, 4)
  348. Else
  349. Log("Run - """ . target . """ Process ID: " . outputVarPID, 4)
  350. Return errLvl
  351. }
  352.  
  353. ; Replaces standard ahk IniRead calls
  354. ; Will not let ERROR be returned, returns no value instead
  355. ; If errormsg is set, will trigger ScriptError instead of returning no or default value
  356. IniRead(file,section,key,defaultvalue="",errorMsg="") {
  357. IniRead, v, %file%, %section%, %key%, %defaultvalue%
  358. ; msgbox % v
  359. Log("IniRead - SECTION: [" . section . "] - KEY: " . key . " - VALUE: " . v . " - FILE: " . file,4)
  360. If (v = "ERROR" || v = A_Space) { ; if key does not exist or is a space, delete ERROR as the value
  361. If errorMsg
  362. ScriptError(errorMsg)
  363. Else {
  364. If (defaultValue := A_Space) ; this prevents the var from existing when it's actually blank
  365. defaultValue := ""
  366. Return defaultValue
  367. }
  368. }
  369. Return v
  370. }
  371.  
  372. ; Replaces standard ahk IniWrite calls
  373. ; compare = if used, only writes new value if existing value differs
  374. IniWrite(value,file,section,key,compare="") {
  375. If compare {
  376. IniRead, v, %file%, %section%, %key%
  377. If (v != value) {
  378. IniWrite, %value%, %file%, %section%, %key%
  379. err := ErrorLevel
  380. Log("IniWrite - ini updated due to differed value. SECTION: [" . section . "] - KEY: " . key . " - Old: " . v . " | New: " . value)
  381. } Else
  382. Log("IniWrite - ini value already correct. SECTION: [" . section . "] - KEY: " . key . " - Value: " . value,4)
  383. } Else {
  384. IniWrite, %value%, %file%, %section%, %key%
  385. err := ErrorLevel
  386. Log("IniWrite - SECTION: [" . section . "] - KEY: " . key . " - VALUE: " . value . " - FILE: " . file)
  387. }
  388. If err
  389. Log("IniWrite - There was an error writing to the ini",3)
  390. Return err ; returns 1 if there was an error
  391. }
  392.  
  393. Process(cmd,name,param=""){
  394. Log("Process - " . cmd . A_Space . name . A_Space . param)
  395. Process, %cmd%, %name%, %param%
  396. Return ErrorLevel
  397. }
  398.  
  399. SetKeyDelay(delay="",pressDur="",play="") {
  400. Global pressDuration
  401. If (delay = "") ; -1 is the default delay for play mode and 10 for event mode when none is supplied
  402. delay := (If play = "" ? 10 : -1)
  403. If (pressDur = "") ; -1 is the default pressDur when none is supplied
  404. pressDur := -1
  405.  
  406. 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)
  407. SetKeyDelay, %delay%, %pressDur%, %play%
  408. pressDuration := pressDur ; this is so the current pressDuration can be monitored outside the function
  409. }
  410.  
  411. ; Mainly used in modules to read module.ini settings so multiple sections of an ini can be read of the same key name
  412. ; section: Allows | separated values so multiple sections can be checked.
  413. IniReadCheck(file,section,key,defaultvalue="",errorMsg="",logType="") {
  414. Loop, Parse, section, |
  415. { section%A_Index% := A_LoopField ; keep each parsed section in its own var
  416. If iniVar != "" ; if last loop's iniVar has a value, update this loop's default value with it
  417. 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
  418. IniRead, iniVar, %file%, % section%A_Index%, %key%, %defaultvalue%
  419. If (IniVar = "ERROR" || iniVar = A_Space) ; if key does not exist or is a space, delete ERROR as the value
  420. iniVar := ""
  421. If (A_Index = 1 && iniVar = "" and !logType) {
  422. If errorMsg
  423. ScriptError(errorMsg)
  424. Else
  425. IniWrite, %defaultValue%, %file%, % section%A_Index%, %key%
  426. Return defaultValue
  427. }
  428. If logType ; only log if logType set
  429. { logAr := ["Module","Bezel"]
  430. Log(logAr[logType] . " Setting - [" . section%A_Index% . "] - " . key . ": " . iniVar)
  431. }
  432. If (iniVar != "") ; if IniVar contains a value, update the lastIniVar
  433. lastIniVar := iniVar
  434. }
  435. If defaultValue = %A_Space% ; this prevents the var from existing when it's actually blank
  436. defaultValue := ""
  437. 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
  438. }
  439.  
  440. MaximizeWindow(WinTitle, keepAspectRatio="true", removeTitle="true", removeBorder="true", removeToggleMenu="true") {
  441. Log("MaximizeWindow - Started to process window """ . winTitle . """", 4)
  442. If (removeTitle = "true")
  443. RL.WinSet("Style", "-0xC00000", WinTitle) ;Removes the titlebar of the game window
  444. If (removeBorder = "true")
  445. RL.WinSet("Style", "-0x40000", WinTitle) ;Removes the border of the game window
  446. If (removeToggleMenu = "true") {
  447. WinID := RL.WinGet( "ID", WinTitle)
  448. ToggleMenu(WinID)
  449. }
  450.  
  451. If (keepAspectRatio = "true") {
  452. RL.WinGetPos(appX, appY, appWidth, appHeight, WinTitle)
  453. widthMaxPercenty := ( A_ScreenWidth / appWidth )
  454. heightMaxPercenty := ( A_ScreenHeight / appHeight )
  455.  
  456. If ( widthMaxPercenty < heightMaxPercenty )
  457. percentToEnlarge := widthMaxPercenty
  458. Else
  459. percentToEnlarge := heightMaxPercenty
  460.  
  461. appWidthNew := appWidth * percentToEnlarge
  462. appHeightNew := appHeight * percentToEnlarge
  463.  
  464. appY := RL.Transform("Round", appY)
  465. appWidthNew := RL.Transform("Round", appWidthNew, 2)
  466. appHeightNew := RL.Transform("Round", appHeightNew, 2)
  467. appXPos := ( A_ScreenWidth / 2 ) - ( appWidthNew / 2 )
  468. appYPos := ( A_ScreenHeight / 2 ) - ( appHeightNew / 2 )
  469. }
  470. Else {
  471. appXPos := 0
  472. appYPos := 0
  473. appWidthNew := A_ScreenWidth
  474. appHeightNew := A_ScreenHeight
  475. }
  476. MoveWindow(WinTitle,appXPos,appYPos,appWidthNew,appHeightNew)
  477. Log("MaximizeWindow - Ended", 4)
  478. }
  479.  
  480. MoveWindow(winTitle,X,Y,W,H,timeLimit=2000,ignoreWin=""){ ; assures that a window is moved to the desired position within a timeout
  481. Log("MoveWindow - Moving window " . winTitle . " to X=" . X . ", Y=" . Y . ", W=" . W . " H=" . H, 4)
  482. RL.WinMove(winTitle,"", X, Y, W, H, ignoreWin)
  483. ;check If window moved
  484. timeout := A_TickCount
  485. Loop
  486. { RL.WinGetPos(Xgot, Ygot, Wgot, Hgot, winTitle,"", ignoreWin)
  487.  
  488. If ((Xgot=X) and (Ygot=Y) and (Wgot=W) and (Hgot=H)){
  489. Log("MoveWindow - Successful: Window " . winTitle . " moved to X=" . X . ", Y=" . Y . ", W=" . W . " H=" . H, 4)
  490. error := 0
  491. Break
  492. }
  493. If (timeout<A_TickCount-timeLimit){
  494. Log("MoveWindow - Failed: Window " . winTitle . " at X=" . Xgot . ", Y=" . Ygot . ", W=" . Wgot . " H=" . Hgot, 4)
  495. error := 1
  496. Break
  497. }
  498. Sleep, 200
  499. RL.WinMove(winTitle,"", X, Y, W, H, ignoreWin)
  500. }
  501. Return error
  502. }
  503.  
  504. ; Purpose: Handle an emulators Open Rom window when CLI is not an option
  505. ; Returns 1 when successful
  506. OpenROM(windowName,selectedRomName) {
  507. Log("OpenROM - Started")
  508. Global MEmu,moduleName
  509. RL.WinWait(windowName)
  510. RL.WinWaitActive(windowName)
  511. state := 0
  512. Loop, 150 ; 15 seconds
  513. { RL.ControlSetText("Edit1", selectedRomName, windowName)
  514. edit1Text := RL.ControlGetText(Edit1, windowName)
  515. If (edit1Text = selectedRomName) {
  516. state := 1
  517. Log("OpenROM - Successfully set romName into """ . windowName . """ in " . A_Index . " " . (If A_Index = 1 ? "try." : "tries."),4)
  518. Break
  519. }
  520. Sleep, 100
  521. }
  522. If (state != 1)
  523. 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)
  524. RL.PostMessage("0x111", 1,"","", windowName) ; Select Open
  525. Log("OpenROM - Ended")
  526. Return %state%
  527. }
  528.  
  529. GetActiveWindowStatus(){
  530. dWin := A_DetectHiddenWindows ; store current value to return later
  531. DetectHiddenWindows, On
  532. activeWinHWND := WinExist("A")
  533. WinGet, procPath, ProcessPath, ahk_id %activeWinHWND%
  534. WinGet, procID, PID, ahk_id %activeWinHWND%
  535. WinGet, winState, MinMax, ahk_id %activeWinHWND%
  536. WinGetClass, winClass, ahk_id %activeWinHWND%
  537. WinGetTitle, winTitle, ahk_id %activeWinHWND%
  538. WinGetPos, X, Y, W, H, ahk_id %activeWinHWND%
  539. 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)
  540. DetectHiddenWindows, %dWin% ; restore prior state
  541. }
  542.  
  543. ; CheckFile Usage:
  544. ; file = file to be checked if it exists
  545. ; msg = the error msg you want displayed on screen if you don't want the default "file not found"
  546. ; timeout = gets passed to ScriptError(), the amount of time you want the error to show on screen
  547. ; crc = If this is a an AHK library only, provide a crc so it can be validated
  548. ; crctype = default empty and crc is not checked. Use 0 for AHK libraries and RocketLauncher extension files. Use 1 for module crc checks..
  549. ; logerror = default empty will give a log error instead of stopping with a scripterror
  550. ; allowFolder = allows folders or files w/o an extension to be checked. By default a file must have an extension.
  551. CheckFile(file,msg="",timeout=6,crc="",crctype="",logerror="",allowFolder=0){
  552. Global RLObject,logIncludeFileProperties
  553. exeFileInfo := "
  554. ( LTrim
  555. FileDescription
  556. FileVersion
  557. InternalName
  558. LegalCopyright
  559. OriginalFilename
  560. ProductName
  561. ProductVersion
  562. CompanyName
  563. PrivateBuild
  564. SpecialBuild
  565. LegalTrademarks
  566. )"
  567.  
  568. Log("CheckFile - Checking if " . file . " exists")
  569. SplitPath, file, fileName, filePath, fileExt, fileNameNoExt
  570. If !FileExist(filePath . "\" . fileName)
  571. If FileExist(filePath . "\" . fileNameNoExt . " (Example)." . fileExt) {
  572. FileCopy, %filePath%\%fileNameNoExt% (Example).%fileExt%, %filePath%\%fileName%
  573. If ErrorLevel
  574. Log("CheckFile - Found an example for this file, but did not have permissions to retore it: " . filePath . "\" . fileNameNoExt . " (Example)." . fileExt,3)
  575. Else
  576. Log("CheckFile - Restored this file from its example: " . filePath . "\" . fileNameNoExt . " (Example)." . fileExt,2)
  577. } Else {
  578. If msg
  579. ScriptError(msg, timeout)
  580. Else
  581. ScriptError("Cannot find " . file, timeout)
  582. }
  583. If (!fileExt && !allowFolder)
  584. ScriptError("This is a folder and must point to a file instead: " . file, timeout)
  585.  
  586. If (crctype = 0 Or crctype = 1) {
  587. CRCResult := RL_checkModuleCRC("" . file . "",crc,crctype)
  588. If (CRCResult = -1)
  589. Log("CRC Check - " . (If crctype=1 ? "Module" : If (crctype=0 && crc) ? "Library" : "Extension") . " file not found.",3)
  590. Else If (CRCResult = 0)
  591. If (crctype = 1)
  592. Log("CRC Check - CRC does not match official module and will not be supported. Continue using at your own risk.",2)
  593. Else If logerror
  594. 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)
  595. Else
  596. 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)
  597. Else If (CRCResult = 1)
  598. Log("CRC Check - CRC matches, this is an official unedited " . (If crctype=1 ? "Module" : If (crctype=0 && crc) ? "Library" : "Extension") . ".",4)
  599. Else If (CRCResult = 2)
  600. Log("CRC Check - No CRC defined on the header for: " . file,3)
  601. }
  602.  
  603. If (logIncludeFileProperties = "true")
  604. { If exeAtrib := FileGetVersionInfo_AW(file, exeFileInfo, "`n")
  605. Loop, Parse, exeAtrib, `n
  606. logTxt .= (If A_Index=1 ? "":"`n") . "`t`t`t`t`t" . A_LoopField
  607. FileGetSize, fileSize, %file%
  608. FileGetTime, fileTimeC, %file%, C
  609. FormatTime, fileTimeC, %fileTimeC%, M/d/yyyy - h:mm:ss tt
  610. FileGetTime, fileTimeM, %file%, M
  611. FormatTime, fileTimeM, %fileTimeM%, M/d/yyyy - h:mm:ss tt
  612. logTxt .= (If logTxt ? "`r`n":"") . "`t`t`t`t`tFile Size:`t`t`t" . fileSize . " bytes"
  613. logTxt .= "`r`n`t`t`t`t`tCreated:`t`t`t" . fileTimeC
  614. logTxt .= "`r`n`t`t`t`t`tModified:`t`t`t" . fileTimeM
  615. Log("CheckFile - Attributes:`r`n" . logTxt,4)
  616. }
  617. Return %file%
  618. }
  619.  
  620. CheckFolder(folder,msg="",timeout=6,crc="",crctype="",logerror="") {
  621. Return CheckFile(folder,msg,timeout,crc,crctype,logerror,1)
  622. }
  623.  
  624. ; ScriptError usage:
  625. ; error = error text
  626. ; timeout = duration in seconds error will show
  627. ; w = width of error box
  628. ; h = height of error box
  629. ; txt = font size
  630. ScriptError(error,timeout=6,w=800,h=225,txt=20,noexit=""){
  631. Global RLMediaPath,exitEmulatorKey,RLFile,RLErrSoundPath,logShowCommandWindow,cmdWindowObj,scriptErrorTriggered
  632. Global screenRotationAngle,baseScreenWidth,baseScreenHeight,xTranslation,yTranslation,XBaseRes,YBaseRes
  633.  
  634. XHotKeywrapper(exitEmulatorKey,"CloseProcess","OFF")
  635. XHotKeywrapper(exitEmulatorKey,"CloseError","ON")
  636. Hotkey, Esc, CloseError
  637. Hotkey, Enter, CloseError
  638.  
  639. If !pToken := Gdip_Startup(){ ; Start gdi+
  640. MsgBox % "Gdiplus failed to start. Please ensure you have gdiplus on your system"
  641. ExitApp
  642. }
  643.  
  644. timeout *= 1000 ; converting to seconds
  645. ;Acquiring screen info for dealing with rotated menu drawings
  646. Gdip_Alt_GetRotatedDimensions(A_ScreenWidth, A_ScreenHeight, screenRotationAngle, baseScreenWidth, baseScreenHeight)
  647. Gdip_GetRotatedTranslation(baseScreenWidth, baseScreenHeight, screenRotationAngle, xTranslation, yTranslation)
  648. xTranslation:=round(xTranslation), yTranslation:=round(yTranslation)
  649. XBaseRes := 1920, YBaseRes := 1080
  650. If (((A_screenWidth < A_screenHeight) and ((screenRotationAngle=0) or (screenRotationAngle=180))) or ((A_screenWidth > A_screenHeight) and ((screenRotationAngle=90) or (screenRotationAngle=270))))
  651. XBaseRes := 1080, YBaseRes := 1920
  652. If !errorXScale
  653. errorXScale := baseScreenWidth/XBaseRes
  654. If !errorYScale
  655. errorYScale := baseScreenHeight/YBaseRes
  656. Error_Warning_Width := w
  657. Error_Warning_Height := h
  658. Error_Warning_Pen_Width := 7
  659. Error_Warning_Rounded_Corner := 30
  660. Error_Warning_Margin := 30
  661. Error_Warning_Bitmap_Size := 125
  662. Error_Warning_Text_Size := txt
  663. OptionScale(Error_Warning_Width, errorXScale)
  664. OptionScale(Error_Warning_Height, errorYScale)
  665. OptionScale(Error_Warning_Pen_Width, errorXScale)
  666. OptionScale(Error_Warning_Rounded_Corner, errorXScale)
  667. OptionScale(Error_Warning_Margin, errorXScale)
  668. OptionScale(Error_Warning_Bitmap_Size, errorXScale)
  669. OptionScale(Error_Warning_Text_Size, errorYScale)
  670.  
  671. ;Create error GUI
  672. Gui, Error_GUI: +Disabled -Caption +E0x80000 +OwnDialogs +LastFound +ToolWindow +AlwaysOnTop
  673. Gui, Error_GUI: Margin,0,0
  674. Gui, Error_GUI: Show,, ErrorLayer
  675. Error_hwnd := WinExist()
  676. Error_hbm := CreateDIBSection(A_ScreenWidth, A_ScreenHeight)
  677. Error_hdc := CreateCompatibleDC()
  678. Error_obm := SelectObject(Error_hdc, Error_hbm)
  679. Error_G := Gdip_GraphicsFromhdc(Error_hdc)
  680. Gdip_SetSmoothingMode(Error_G, 4)
  681. Gdip_TranslateWorldTransform(Error_G, xTranslation, yTranslation)
  682. Gdip_RotateWorldTransform(Error_G, screenRotationAngle)
  683. pGraphUpd(Error_G,baseScreenWidth, baseScreenHeight)
  684.  
  685. ;Create GUI elements
  686. pBrush := Gdip_BrushCreateSolid("0xFF000000") ; Painting the background color
  687. Gdip_Alt_FillRectangle(Error_G, pBrush, -1, -1, baseScreenWidth+1, baseScreenHeight+1) ; draw the background first on layer 1 first, layer order matters!!
  688. brushWarningBackground := Gdip_CreateLineBrushFromRect(0, 0, Error_Warning_Width, Error_Warning_Height, 0xff555555, 0xff050505)
  689. penWarningBackground := Gdip_CreatePen(0xffffffff, Error_Warning_Pen_Width)
  690. 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)
  691. 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)
  692. WarningBitmap := Gdip_CreateBitmapFromFile(RLMediaPath . "\Menu Images\RocketLauncher\Warning.png")
  693. 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)
  694. 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)))
  695.  
  696. startTime := A_TickCount
  697. Loop{ ; fade in
  698. t := ((TimeElapsed := A_TickCount-startTime) < 300) ? (255*(timeElapsed/300)) : 255
  699. Alt_UpdateLayeredWindow(Error_hwnd,Error_hdc, 0, 0, baseScreenWidth, baseScreenHeight,t)
  700. If (t >= 255)
  701. Break
  702. }
  703.  
  704. ; Generate a random sound to play on a script error
  705. erSoundsAr:=[] ; initialize the array to store error sounds
  706. Loop, %RLErrSoundPath%\error*.mp3
  707. erSoundsAr.Insert(A_LoopFileName) ; insert each found error sound into an array
  708. Random, erRndmSound, 1, % erSoundsAr.MaxIndex() ; randomize what sound to play
  709. Log("ScriptError - Playing error sound: " . erSoundsAr[erRndmSound],4)
  710. setMute(0,emulatorVolumeObject)
  711. SoundPlay % If erSoundsAr.MaxIndex() ? (RLErrSoundPath . "\" . erSoundsAr[erRndmSound]):("*-64"), wait ; play the random sound if any exist, or default to the Asterisk windows sound
  712. If noexit { ; do not close thread, continue with script and let it handle the exiting
  713. scriptErrorTriggered := 1
  714. Return
  715. }
  716. 7zCleanUp() ; clean up 7z if necessary
  717. Sleep, %timeout%
  718.  
  719. CloseError:
  720. endTime := A_TickCount
  721. Loop { ; fade out
  722. t := ((TimeElapsed := A_TickCount-endTime) < 300) ? (255*(1-timeElapsed/300)) : 0
  723. Alt_UpdateLayeredWindow(Error_hwnd,Error_hdc, 0, 0, baseScreenWidth, baseScreenHeight,t)
  724. If (t <= 0)
  725. Break
  726. }
  727.  
  728. XHotKeywrapper(exitEmulatorKey,"CloseError","OFF")
  729. XHotKeywrapper(exitEmulatorKey,"CloseProcess","ON")
  730. Gdip_DeleteBrush(pBrush)
  731. Gdip_DisposeImage(WarningBitmap), SelectObject(Error_hdc, Error_obm), DeleteObject(Error_hbm), DeleteDC(Error_hdc), Gdip_DeleteGraphics(Error_G)
  732. Gui, ErrorGUI_10: Destroy
  733. Log("ScriptError - " . error,3)
  734.  
  735. 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
  736. ; Below cleanup exists because we can't call other functions that may cause additional scripterrors and put the thread in an infinite loop
  737. ; If logShowCommandWindow = true
  738. ; { for index, element in cmdWindowObj
  739. ; Process, Close, % cmdWindowObj[A_Index,1] ; close each opened cmd.exe
  740. ; }
  741. ; ExitApp
  742. }
  743.  
  744. ; Log usage:
  745. ; text = text I want to log
  746. ; lvl = the lvl to log the text at
  747. ; 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
  748. ; dump = tells the function to write the log file at the end. Do not use this param
  749. ; 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
  750. ; Log() in the module thread requires `r`n at the end of each line, where it's not needed in the RocketLauncher thread
  751. Log(text,lvl=1,notime="",dump="",firstLog=""){
  752. Static log
  753. Static lastLog
  754. Global logFile,logLevel,logLabel,logShowDebugConsole
  755. ; Global executable
  756. If (logLevel > 0)
  757. {
  758. If (lvl<=logLevel || lvl=3){ ; ensures errors are always logged
  759. logDiff := A_TickCount - lastLog
  760. lastLog := A_TickCount
  761. 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"
  762. }
  763. If (logShowDebugConsole = "true")
  764. DebugMessage(log)
  765. If (logLevel>=10 || dump){
  766. FileAppend,%log%,%logFile%
  767. log := ""
  768. }
  769. ; Process, Exist, %executable%
  770. ; If ErrorLevel
  771. ; Log .= "mame exists`r`n"
  772. Return log
  773. }
  774. }
  775.  
  776. ; Inserts extra characters/spaces into sections of the Log file to keep it aligned.
  777. ; Usage: inserts char x number of times on the end of txt until pad is reached.
  778. AlignColumn(txt,pad=9,char=" "){
  779. 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++
  780. Loop {
  781. n := StrLen(txt)
  782. If (n*x >= pad)
  783. Break
  784. txt := txt . char
  785. }
  786. Return txt
  787. }
  788.  
  789. ; Rini returns -2 if section does not exist
  790. ; Rini returns -3 if key does not exist
  791. ; Rini returns -10 if an invalid reference var for the ini file was used
  792. ; Rini returns empty value if key exists with no value
  793. ; rIniIndex := Object(1,globalRLFile,2,sysRLFile,3,globalEmuFile,4,sysEmuFile,5,RLFile,6,gamesFile)
  794. ; 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
  795. RIniLoadVar(gRIniVar,sRIniVar,section,key,gdefaultvalue="",sdefaultvalue="use_global",preferDefault="") {
  796. Global rIniIndex
  797. If (gRIniVar != 6) ; do not create missing sections or keys for games.ini
  798. { gValue := RIni_GetKeyValue(gRIniVar,section,key,If preferDefault ? gdefaultvalue : "")
  799. gValue := gValue ; trims whitespace
  800. If RegExMatch(gValue,"-2|-3") ; if global ini key does not exist, create the key
  801. { RIni_SetKeyValue(gRIniVar,section,key,gdefaultvalue)
  802. RIni_Write(gRIniVar,rIniIndex[gRIniVar],"`r`n",1,1,1)
  803. gValue := gdefaultvalue ; set to default value because it did not exist
  804. Log("RIniLoadVar - Created missing Global ini key: """ . key . """ in section: """ . section . """ in """ . rIniIndex[gRIniVar] . """",2)
  805. }
  806. If sRIniVar ; != "" ; only create system sections or keys for inis that use them
  807. { sValue := RIni_GetKeyValue(sRIniVar,section,key,If preferDefault ? sdefaultvalue : "")
  808. sValue := sValue ; trims whitespace
  809. If RegExMatch(sValue,"-2|-3") ; if system ini key does not exist, create the key
  810. { RIni_SetKeyValue(sRIniVar,section,key,sdefaultvalue)
  811. RIni_Write(sRIniVar,rIniIndex[sRIniVar],"`r`n",1,1,1)
  812. sValue := sdefaultvalue ; set to default value because it did not exist
  813. Log("RIniLoadVar - Created missing System ini key: """ . key . """ in section: """ . section . """ in """ . rIniIndex[sRIniVar] . """",2)
  814. }
  815. Return If sValue = "use_global" ? gValue : sValue ; now compare global & system keys to get final value
  816. }
  817. Return gValue ; return gValue when not using globa/system inis, like RLFile (rIniIndex 5)
  818. }
  819. iniVar := RIni_GetKeyValue(gRIniVar,section,key,gdefaultvalue) ; lookup key from ini and return it
  820. iniVar := iniVar ; trims whitespace
  821. Return iniVar
  822. }
  823.  
  824. RIniReadCheck(rIniVar,section,key,defaultvalue="",errorMsg="") {
  825. Global rIniIndex
  826. iniVar := RIni_GetKeyValue(rIniVar,section,key) ; lookup key from ini and return it
  827. iniVar := iniVar ; trims whitespace
  828. If (iniVar = -2 or iniVar = -3 or iniVar = "") {
  829. 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
  830. Log("RIniReadCheck - Created missing RocketLauncher ini key: """ . key . """ in section: """ . section . """ in """ . rIniIndex[rIniVar] . """",2)
  831. RIni_SetKeyValue(rIniVar,section,key,defaultvalue)
  832. RIni_Write(rIniVar,rIniIndex[rIniVar],"`r`n",1,1,1) ; write blank section, blank key, and space between sections
  833. }
  834. If errorMsg
  835. ScriptError(errorMsg)
  836. Return defaultValue
  837. }
  838. Return iniVar
  839. }
  840.  
  841. CheckFont(font) {
  842. If !(Gdip_FontFamilyCreate(font))
  843. ScriptError("The Font """ . font . """ is not installed on your system. Please install the font or change it in RocketLauncherUI.")
  844. }
  845.  
  846. ; Toggles hiding/showing a MenuBar
  847. ; Usage: Provide the window's PID of the window you want to toggle the MenuBar
  848. ; used in nulldc module and bezel
  849. ToggleMenu(hWin){
  850. Static hMenu, visible
  851. If (hMenu = "")
  852. hMenu := DllCall("GetMenu", "uint", hWin) ; store the menubar ID so it can be restored later
  853. hMenuCur := DllCall("GetMenu", "uint", hWin)
  854. timeout := A_TickCount
  855. If !hMenuCur
  856. Loop {
  857. ;ToolTip, menubar is hidden`, bringing it back`nhMenuCur: %hMenuCur%`n%A_Index%
  858. hMenuCur := DllCall("GetMenu", "uint", hWin)
  859. If hMenuCur {
  860. Log("ToggleMenu - MenuBar is now visible for " . hWin,4)
  861. Break ; menubar is now visible, break out
  862. }
  863. DllCall("SetMenu", "uint", hWin, "uint", hMenu)
  864. If (timeout < A_TickCount - 500) ; prevents an infinite loop and breaks after 2 seconds
  865. Break
  866. }
  867. Else Loop { ; menubar is visible
  868. ;ToolTip, menubar is visible`, hiding it`nhMenuCur: %hMenuCur%`n%A_Index%
  869. hMenuCur := DllCall("GetMenu", "uint", hWin)
  870. If !hMenuCur {
  871. Log("ToggleMenu - MenuBar is now hidden for " . hWin,4)
  872. Break ; menubar is now hidden, break out
  873. }
  874. DllCall("SetMenu", "uint", hWin, "uint", 0)
  875. If (timeout < A_TickCount - 500) ; prevents an infinite loop and breaks after 2 seconds
  876. Break
  877. }
  878. }
  879. ; Original function but somestimes does not work, which is why the new function loops above
  880. ToggleMenuOld(hWin){
  881. Static hMenu, visible
  882. If (hMenu = "")
  883. hMenu := DllCall("GetMenu", "uint", hWin)
  884. If !visible
  885. DllCall("SetMenu", "uint", hWin, "uint", hMenu)
  886. Else
  887. DllCall("SetMenu", "uint", hWin, "uint", 0)
  888. visible := !visible
  889. }
  890.  
  891. ; Function to pause and wait for a user to press any key to continue.
  892. ; IdleCheck usage:
  893. ; t = timeout in ms to break out of function
  894. ; m = the method - can be "P" (physical) or "L" (logical)
  895. ; s = sleep or how fast the function checks for idle state
  896. ; Exits when state is no longer idle or times out
  897. IdleCheck(t="",m="L",s=200){
  898. timeIdlePrev := 0
  899. startTime := A_TickCount
  900. While timeIdlePrev < (If m = "L" ? A_TimeIdle : A_TimeIdlePhysical){
  901. timeIdlePrev := If m = "L" ? A_TimeIdle : A_TimeIdlePhysical
  902. If (t && A_TickCount-startTime >= t)
  903. Return "Timed Out"
  904. Sleep s
  905. }
  906. Return A_PriorKey
  907. }
  908.  
  909. ; This function looks through all defined romPaths and romExtensions for the provided rom file
  910. ; Returns a path to the rom where it was found
  911. ; Returns nothing if not found
  912. RomNameExistCheck(file,archivesOnly="") {
  913. Global romPathFromIni,romExtensions,sevenZFormats
  914. Loop, Parse, romPathFromIni, | ; for each rom path defined
  915. { tempRomPath := A_LoopField ; assigning this to a var so it can be accessed in the next loop
  916. Loop, Parse, romExtensions, | ; for each extension defined
  917. { If (archivesOnly != "")
  918. If !InStr(sevenZFormats,A_LoopField) ; if rom extension is not an archive type, skip this rom
  919. Continue
  920. ; msgbox % tempRomPath . "\" . file . "." . tempRomExtension
  921. Log("RomNameExistCheck - Looking for rom: " . tempRomPath . "\" . file . "." . A_LoopField,4)
  922. If FileExist( tempRomPath . "\" . file . "." . A_LoopField ) {
  923. Log("RomNameExistCheck - Found rom: " . tempRomPath . "\" . file . "." . A_LoopField)
  924. Return tempRomPath . "\" . file . "." . A_LoopField ; return path if file exists
  925. }
  926. Log("RomNameExistCheck - Looking for rom: " . tempRomPath . "\" . file . "\" . file . "." . A_LoopField,4)
  927. 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
  928. Log("RomNameExistCheck - Found rom: " . tempRomPath . "\" . file . "\" . file . "." . A_LoopField)
  929. Return tempRomPath . "\" . file . "\" . file . "." . A_LoopField ; return path if file exists
  930. }
  931. }
  932. }
  933. Log("RomNameExistCheck - Could not find """ . file . """ in any of your Rom Paths with any defined Rom Extensions",2)
  934. Return
  935. }
  936.  
  937. ; 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
  938. CreateMGRomTable:
  939. Log("CreateMGRomTable - Started")
  940. If !mgCandidate {
  941. Log("CreateMGRomTable - Ended - This rom does not qualify for MultiGame")
  942. Return
  943. }
  944. If !IsObject(romTable)
  945. { Log("CreateMGRomTable - romTable does not exist, creating one for """ . dbName . """",4)
  946. romTable := CreateRomTable(dbName)
  947. } Else
  948. Log("CreateMGRomTable - romTable already exists, skipping table creation.",4)
  949. Log("CreateMGRomTable - Ended")
  950. Return
  951.  
  952. CreateRomTable(table) {
  953. Global romPathFromIni,dbName,romExtensionOrig,sevenZEnabled,romTableStarted,romTableComplete,romTableCanceled,rocketLauncherIsExiting,mgCandidate
  954. romTableStarted := 1
  955. romTableCanceled := ""
  956. romTableComplete := ""
  957. If rocketLauncherIsExiting {
  958. romTableCanceled := 1 ; set this so the RomTableCheck is canceled and doesn't get stuck in an infinite loop
  959. Log("CreateRomTable - RocketLauncher is currently exiting, skipping romTable creation")
  960. Return
  961. }
  962. If !mgCandidate {
  963. romTableCanceled := 1 ; set this so the RomTableCheck is canceled and doesn't get stuck in an infinite loop
  964. Log("CreateRomTable - This rom does not qualify for MultiGame")
  965. Return
  966. }
  967. Log("CreateRomTable - Started")
  968.  
  969. romCount := 0 ; initialize the var and reset it, needed in case GUI is used more then once in a session
  970. table := [] ; initialize and empty the table
  971. typeArray := ["(Disc","(Disk","(Cart","(Tape","(Cassette","(Part","(Side"]
  972. regExCheck = i)\s\(Disc\s[^/]*|\s\(Disk\s[^/]*|\s\(Cart\s[^/]*|\s\(Tape\s[^/]*|\s\(Cassette\s[^/]*|\s\(Part\s[^/]*|\s\(Side\s[^/]*
  973. 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
  974. Loop % typeArray.MaxIndex() ; loop each item in our array
  975. { If matchedRom ; Once we matched our game to the typeArray, no need to search for another. This allows the loop to break out.
  976. Break
  977. indexTotal ++
  978. Log("CreateRomTable - Checking for match: """ . dbName . """ and """ . typeArray[A_Index] . """",4)
  979. If dbName contains % typeArray[A_Index] ; find the item in our array that matches our rom
  980. { Log("CreateRomTable - """ . dbName . """ contains """ . typeArray[A_Index] . """",4)
  981. typeArrayIndex := A_Index
  982. Loop, Parse, romPathFromIni, |
  983. { indexTotal ++
  984. currentPath := A_LoopField
  985. Log("CreateRomTable - Checking New Rom path: " . currentPath,4)
  986. Log("CreateRomTable - Now looping in: " . currentPath . "\" . dbNamePre . A_Space . typeArray[typeArrayIndex] . "*",4)
  987. 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.
  988. { indexTotal ++
  989. Log(A_LoopFileFullPath,4)
  990. Log("CreateRomTable - Looking for: " . currentPath . "\" . dbNamePre . A_Space . typeArray[typeArrayIndex] . "*." . A_LoopFileExt,4)
  991. 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.
  992. { romCount += 1
  993. matchedRom := 1 ; Allows to break out of the loops once we matched our rom
  994. table[romCount,1] := A_LoopFileFullPath ; Store A_LoopFileFullPath (full file path and file) in column 1
  995. table[romCount,2] := A_LoopFileName ; Store A_LoopFileName (the full filename and extension) in column 2
  996. table[romCount,3] := RegExReplace(table[romCount, 2], "\..*") ; Store the filename with media type # but w/o an extension in column 3
  997. 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.
  998. uncleanTxt:= SubStr(table[romCount,2], pos + 1) ; remove everything but the media type and # and ext from our file name
  999. table[romCount,4] := dbNamePre ; store dbName w/o the media type and #, used for Pause and updating statistics in column 4
  1000. 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 #
  1001. table[romCount,6] := SubStr(table[romCount,5],1,4) ; copies just the media type to column 6
  1002. Log("CreateRomTable - Adding found game to Rom Table: " . A_LoopFileFullPath,4)
  1003. }
  1004. }
  1005. }
  1006. }
  1007. }
  1008. romTableComplete := 1 ; flag to tell the RomTableCheck the function is complete in case no romTable was created for non-MG games
  1009. romTableStarted := ""
  1010. Log("CreateRomTable - Ended`, " . IndexTotal . " Loops to create table.")
  1011. Return table
  1012. }
  1013.  
  1014. ; 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
  1015. RomTableCheck() {
  1016. Global systemName,mgEnabled,pauseEnabled,romTable,romTableStarted,romTableComplete,romTableCanceled,mgCandidate,dbName
  1017. If mgCandidate { ; && (pauseEnabled = "true" || mgEnabled = "true")) {
  1018. ; If (!romTableStarted && !IsObject(romTable))
  1019. ; romTable := CreateRomTable(dbName)
  1020.  
  1021. Log("RomTableCheck - Started")
  1022. ; 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
  1023. ; PauseSystemIni := A_ScriptDir . "\Settings\" . systemName . "\Pause.ini"
  1024. ; IniRead, changeDiscMenuG, %PauseGlobalIni%, General Options, ChangeDisc_Menu_Enabled
  1025. ; IniRead, changeDiscMenuS, %PauseSystemIni%, General Options, ChangeDisc_Menu_Enabled
  1026. ; changeDiscMenu := If changeDiscMenuS = "use_global" ? changeDiscMenuG : changeDiscMenuS ; calculate to use system or global setting
  1027.  
  1028. ; If (mgEnabled = "true" || changeDiscMenu = "true") {
  1029. ; Log("RomTableCheck - MultiGame and/or Pause's Change Disc Menu is enabled so checking if romTable exists yet.",4)
  1030. If !romTable.MaxIndex()
  1031. Log("RomTableCheck - romTable does not exist yet, waiting until it does to continue loading the module.",4)
  1032. Loop {
  1033. If romTableComplete { ; this var gets created when CreateRomTable is complete in case this is not an MG game
  1034. Log("RomTableCheck - Detected CreateRomTable is finished processing. Continuing with module thread.",4)
  1035. Break
  1036. } Else If romTableCanceled { ; this var gets created when CreateRomTable is cancelled in cases it is no longer needed
  1037. Log("RomTableCheck - Detected CreateRomTable is no longer needed. Continuing with module thread.",4)
  1038. Break
  1039. } Else If (A_Index > 200) { ; if 20 seconds pass by, log there was an issue and continue w/o romTable
  1040. Log("RomTableCheck - Creating the romTable took longer than 20 seconds. Continuing with module thread without waiting for the table's creation.",3)
  1041. Break
  1042. } Else
  1043. Sleep, 100
  1044. }
  1045. ; }
  1046. Log("RomTableCheck - Ended")
  1047. } Else
  1048. Log("RomTableCheck - This game is not a candidate for MG or Change DIsc menu.")
  1049. }
  1050.  
  1051. ; Allows changing LEDBlinky's active profile
  1052. ; mode can be RL or Rom which tells LEDBlinky what profile to load
  1053. ; Ledblinky's ini gets loaded on start, so this function will never touch it
  1054. LEDBlinky(mode) {
  1055. Global ledblinkyEnabled,ledblinkySystemName,ledblinkyFullPath,ledblinkyProfilePath,ledblinkyRLProfile,dbName,systemName,romName
  1056. Static ledblinkyExists,ledblinkyExe,ledblinkyPath
  1057. If (ledblinkyEnabled != "false")
  1058. {
  1059. If !ledblinkyExists { ; Make sure LEDBlinky exists first before trying to use it
  1060. If FileExist(ledblinkyFullPath) {
  1061. ledblinkyExists := 1
  1062. SplitPath,ledblinkyFullPath,ledblinkyExe,ledblinkyPath
  1063.  
  1064. } Else
  1065. ScriptError("You are trying to use LEDBlinky support but could not locate it here: " . ledblinkyFullPath)
  1066. }
  1067. Log("LEDBlinky - Started, sending mode " . mode)
  1068.  
  1069. If (mode = "START")
  1070. Run(ledblinkyExe . " """ . (If romName ? romName : dbName) . """ """ . (If ledblinkySystemName ? ledblinkySystemName : systemName) . """", ledblinkyPath) ; Game Start Event
  1071. Else If (mode = "END")
  1072. Run(ledblinkyExe . " 4" , ledblinkyPath) ; Game Stop Event
  1073. Else If (mode = "RL")
  1074. Run(ledblinkyExe . " 15 RocketLauncher RocketLauncher", ledblinkyPath) ; Load RocketLauncher profile. "15" Tells ledblinky to skip all game start options and only light the controls.
  1075. Else If (mode = "ROM")
  1076. 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.
  1077. Else
  1078. Log("LEDBlinky - Unsupported use of LEDBlinky - UNKNOWN MODE SUPPLIED: """ . mode . """",3)
  1079. Log("LEDBlinky - Ended")
  1080. }
  1081. }
  1082.  
  1083. ; Allows changing WinIPAC's and UltraMap's active profile, among any other tools thrown at it that would utilize similar profile structure
  1084. ; mode = can be START, END, RL or RESUME which represents what part of RL is called the function and what profiles will be loaded
  1085. ; tool = the name of the tool or folder that will be searched in and checked if that setting is enabled. Ex: WinIPAC or UltraMap
  1086. ; 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
  1087. ; ext = extension of the profiles to look for
  1088. ; 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
  1089. KeymapperProfileSelect(mode,tool,path,ext,type="") {
  1090. Global keyboardEncoderEnabled,ultraMapEnabled,profilePath,keymapperFrontEndProfileName,systemName,emuName,dbName
  1091. Global keymapperProfiles
  1092.  
  1093. If !keymapperProfiles
  1094. keymapperProfiles := {} ; create initial object
  1095.  
  1096. If (type = "keyboard")
  1097. prefix := "keyboardEncoder"
  1098. Else
  1099. prefix := tool
  1100.  
  1101. If (%prefix%Enabled = "true") {
  1102. keymapperProfiles[tool,"Enabled"] := "true"
  1103. Log(tool . " - Started with mode: " . mode)
  1104. If !keymapperProfiles[tool,"Exist"] { ; Make sure the tool exists first before trying to use it
  1105. If FileExist(path) {
  1106. keymapperProfiles[tool,"Exist"] := 1
  1107. keymapperProfiles[tool,"FullPath"] := path
  1108. SplitPath,path,exe,path
  1109. keymapperProfiles[tool,"Exe"] := exe
  1110. keymapperProfiles[tool,"Path"] := path
  1111. keymapperProfiles[tool,"Ext"] := "." . ext
  1112. keymapperProfiles[tool,"ProfilePath"] := profilePath . "\" . tool
  1113. keymapperProfiles[tool,"RLProfile"] := keymapperProfiles[tool,"ProfilePath"] . "\RocketLauncher"
  1114. keymapperProfiles[tool,"FEProfile"] := keymapperProfiles[tool,"ProfilePath"] . "\" . keymapperFrontEndProfileName
  1115. keymapperProfiles[tool,"DefaultProfile"] := keymapperProfiles[tool,"ProfilePath"] . "\_Default"
  1116. keymapperProfiles[tool,"SystemProfile"] := keymapperProfiles[tool,"ProfilePath"] . "\" . systemName
  1117. keymapperProfiles[tool,"EmuProfile"] := keymapperProfiles[tool,"ProfilePath"] . "\" . emuName
  1118. keymapperProfiles[tool,"RomProfile"] := keymapperProfiles[tool,"ProfilePath"] . "\" . systemName . "\" . dbName
  1119. ; 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"]
  1120. } Else {
  1121. Log(tool . " - You have your path set to " . %prefix% . " defined, but it could not be found here: " . path,2)
  1122. keymapperProfiles[tool,"Enabled"] := "false"
  1123. }
  1124. }
  1125.  
  1126. If (mode = "START")
  1127. { Log(tool . " - Searching for profiles",4)
  1128. If FileExist(keymapperProfiles[tool,"RomProfile"] . keymapperProfiles[tool,"Ext"]) {
  1129. profile := keymapperProfiles[tool,"RomProfile"] . keymapperProfiles[tool,"Ext"]
  1130. } Else If FileExist(keymapperProfiles[tool,"EmuProfile"] . keymapperProfiles[tool,"Ext"]) {
  1131. profile := keymapperProfiles[tool,"EmuProfile"] . keymapperProfiles[tool,"Ext"]
  1132. } Else If FileExist(keymapperProfiles[tool,"SystemProfile"] . keymapperProfiles[tool,"Ext"]) {
  1133. profile := keymapperProfiles[tool,"SystemProfile"] . keymapperProfiles[tool,"Ext"]
  1134. } Else If FileExist(keymapperProfiles[tool,"DefaultProfile"] . keymapperProfiles[tool,"Ext"]) {
  1135. profile := keymapperProfiles[tool,"DefaultProfile"] . keymapperProfiles[tool,"Ext"]
  1136. } Else {
  1137. Log(tool . " - No profiles found",4)
  1138. Return
  1139. }
  1140. keymapperProfiles[tool,"LastProfile"] := profile
  1141. } Else If (mode = "END")
  1142. { Log(tool . " - Searching for your Front End profile",4)
  1143. If FileExist(keymapperProfiles[tool,"FEProfile"] . keymapperProfiles[tool,"Ext"]) {
  1144. profile := keymapperProfiles[tool,"FEProfile"] . keymapperProfiles[tool,"Ext"]
  1145. } Else {
  1146. Log(tool . " - Profile not found",4)
  1147. Return
  1148. }
  1149. } Else If (mode = "RL")
  1150. { Log(tool . " - Searching for your RocketLauncher profile",4)
  1151. If FileExist(keymapperProfiles[tool,"RLProfile"] . keymapperProfiles[tool,"Ext"]) {
  1152. profile := keymapperProfiles[tool,"RLProfile"] . keymapperProfiles[tool,"Ext"]
  1153. } Else {
  1154. Log(tool . " - Profile not found",4)
  1155. Return
  1156. }
  1157. } Else If (mode = "RESUME")
  1158. { Log(tool . " - Restoring to your last profile",4)
  1159. If keymapperProfiles[tool,"LastProfile"] ; only restore to a previous profile if one was found on start
  1160. profile := keymapperProfiles[tool,"LastProfile"]
  1161. Else {
  1162. Log(tool . " - A profile was not loaded on start, skipping any profile loading",4)
  1163. Return
  1164. }
  1165. } Else
  1166. Log(tool . " - Unsupported mode: " . mode,2)
  1167.  
  1168. Log(tool . " - Loading found profile: " . profile,4)
  1169. 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.
  1170. Log(tool . " - Ended")
  1171. }
  1172. }
  1173.  
  1174. ; Function to measure the size of an text
  1175. MeasureText(Text,Options,Font="Arial",Width="", Height="", ReturnMode="W", ByRef H="", ByRef W="", ByRef X="", ByRef Y="", ByRef Chars="", ByRef Lines=""){
  1176. hdc_MeasureText := GetDC("MeasureText_hwnd")
  1177. G_MeasureText := Gdip_GraphicsFromHDC(hdc_MeasureText)
  1178. RECTF_STR := Gdip_TextToGraphics(G_MeasureText, Text, Options, Font, Width, Height, 1)
  1179. StringSplit,RCI,RECTF_STR, |
  1180. W := Ceil(RCI3)
  1181. H := Ceil(RCI4)
  1182. X := Ceil(RCI1)
  1183. Y := Ceil(RCI2)
  1184. Chars := Ceil(RCI5)
  1185. Lines := Ceil(RCI6)
  1186. DeleteDC(hdc_MeasureText), Gdip_DeleteGraphics(G_MeasureText)
  1187. Return (ReturnMode="X") ? X : (ReturnMode="Y") ? Y :(ReturnMode="W") ? W :(ReturnMode="H") ? H : (ReturnMode="Chars") ? Chars : Lines
  1188. }
  1189.  
  1190.  
  1191. ; Function that allows making applications transparent so they can be hidden completely w/o moving them
  1192. FadeApp(title,direction,time=0){
  1193. startTime := A_TickCount
  1194. Loop{
  1195. t := ((TimeElapsed := A_TickCount-startTime) < time) ? (If direction="in" ? 255*(timeElapsed/time) : 255*(1-(timeElapsed/time))) : (If direction="in" ? 255 : 0)
  1196. WinSet, Transparent, %t%, %title%
  1197. If (direction = "in" && t >= 255) or (direction = "out" && t <= 0) {
  1198. If (direction = "in")
  1199. WinSet, Transparent, Off, %title%
  1200. Break
  1201. }
  1202. }
  1203. Log("HideFE - " . (If direction = "out" ? "Hiding Frontend by making it transparent" : "Showing Frontend and removing transparency"))
  1204. }
  1205.  
  1206. ; SplitPath function with support for roms that contain multiple periods in their name. AHK SplitPath does not support this.
  1207. SplitPath(in,Byref outFileName,Byref outPath,Byref outExt,Byref outNameNoExt) {
  1208. regx := "(\\{2}|(^[\w]:\\))([\w].+\w\\)" ; return path on regexmath and file on regexreplace
  1209. 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)
  1210. in := RegExReplace(in,"/","\") ; replace all occurences of / with \
  1211. RegExMatch(in, regx, outPathBSlash) ; path with backslash
  1212. pathLen := StrLen(outPathBSlash) ; get length of path with slash
  1213. outPath := SubStr(outPathBSlash, 1, pathLen - 1) ; grab path w/o slash
  1214. RegExMatch(in, regext, outExtP) ; get ext with period
  1215. outExt := SubStr(outExtP, 2) ; get ext and remove period
  1216. outFileName := RegExReplace(in, regx) ; get name with ext
  1217. nameLen := StrLen(outFileName) ; get length of name
  1218. extLen := StrLen(outExt) ; get length of ext
  1219. outNameNoExt := SubStr(outFileName, 1, nameLen - extLen - 1) ; get name w/o ext
  1220. }
  1221.  
  1222. ; This function converts a relative path to absolute
  1223. GetFullName( fn ) {
  1224. ; http://msdn.microsoft.com/en-us/library/Aa364963
  1225. Static buf ;, i ; removing i from static because it needs to be reset from one call to the next
  1226. ; If !i
  1227. i := VarSetCapacity(buf, 512)
  1228. DllCall("GetFullPathNameA", "str", fn, "uint", 512, "str", buf, "str*", 0)
  1229. Return buf
  1230. }
  1231.  
  1232. ; Converts a relative path to an absolute one after providing the base path
  1233. AbsoluteFromRelative(MasterPath, RelativePath)
  1234. {
  1235. VarSetCapacity(AbsP,260,0)
  1236. DllCall( "shlwapi\PathCombineA", Str,AbsP, Str,MasterPath, Str,RelativePath )
  1237. Return AbsP
  1238. }
  1239.  
  1240. ; FileGetVersionInfo_AW which gets file attributes
  1241. FileGetVersionInfo_AW( peFile="", StringFileInfo="", Delimiter="|") {
  1242. Static CS, HexVal, Sps=" ", DLL="Version\"
  1243. If ( CS = "" )
  1244. CS := A_IsUnicode ? "W" : "A", HexVal := "msvcrt\s" (A_IsUnicode ? "w": "" ) "printf"
  1245. If ! FSz := DllCall( DLL "GetFileVersionInfoSize" CS , Str,peFile, UInt,0 )
  1246. Return "", DllCall( "SetLastError", UInt,1 )
  1247. VarSetCapacity( FVI, FSz, 0 ), VarSetCapacity( Trans,8 * ( A_IsUnicode ? 2 : 1 ) )
  1248. DllCall( DLL "GetFileVersionInfo" CS, Str,peFile, Int,0, UInt,FSz, UInt,&FVI )
  1249. If ! DllCall( DLL "VerQueryValue" CS, UInt,&FVI, Str,"\VarFileInfo\Translation", UIntP,Translation, UInt,0 )
  1250. Return "", DllCall( "SetLastError", UInt,2 )
  1251. If ! DllCall( HexVal, Str,Trans, Str,"%08X", UInt,NumGet(Translation+0) )
  1252. Return "", DllCall( "SetLastError", UInt,3 )
  1253. Loop, Parse, StringFileInfo, %Delimiter%
  1254. { subBlock := "\StringFileInfo\" SubStr(Trans,-3) SubStr(Trans,1,4) "\" A_LoopField
  1255. If ! DllCall( DLL "VerQueryValue" CS, UInt,&FVI, Str,SubBlock, UIntP,InfoPtr, UInt,0 )
  1256. Continue
  1257. Value := DllCall( "MulDiv", UInt,InfoPtr, Int,1, Int,1, "Str" )
  1258. Info .= Value ? ( ( InStr( StringFileInfo,Delimiter ) ? SubStr( A_LoopField Sps,1,24 ) . A_Tab : "" ) . Value . Delimiter ) : ""
  1259. } StringTrimRight, Info, Info, 1
  1260. Return Info
  1261. }
  1262.  
  1263. GetOSVersion() {
  1264. VarSetCapacity(v,148), NumPut(148,v)
  1265. DllCall("GetVersionEx", "uint", &v)
  1266. ; Return formatted version string similar to A_AhkVersion.
  1267. ; Assume build number will never be more than 4 characters.
  1268. return NumGet(v,4) ; major
  1269. . "." NumGet(v,8) ; minor
  1270. . "." SubStr("0000" NumGet(v,12), -3) ; build
  1271. }
  1272.  
  1273. ; Returns system paths
  1274. ; For example, GetCommonPath("LOCAL_APPDATA") will return the full path to yout local appdata folder: C:\Users\NAME\AppData\Local
  1275. GetCommonPath(csidl) {
  1276. Static init
  1277. If !init
  1278. {
  1279. CSIDL_APPDATA := 0x001A ; Application Data, new for NT4
  1280. CSIDL_COMMON_APPDATA := 0x0023 ; All Users\Application Data
  1281. CSIDL_COMMON_DOCUMENTS := 0x002e ; All Users\Documents
  1282. CSIDL_DESKTOP := 0x0010 ; C:\Documents and Settings\username\Desktop
  1283. CSIDL_FONTS := 0x0014 ; C:\Windows\Fonts
  1284. CSIDL_LOCAL_APPDATA := 0x001C ; non roaming, user\Local Settings\Application Data
  1285. CSIDL_MYMUSIC := 0x000d ; "My Music" folder
  1286. CSIDL_MYPICTURES := 0x0027 ; My Pictures, new for Win2K
  1287. CSIDL_PERSONAL := 0x0005 ; My Documents
  1288. CSIDL_PROGRAM_FILES_COMMON := 0x002b ; C:\Program Files\Common
  1289. CSIDL_PROGRAM_FILES := 0x0026 ; C:\Program Files
  1290. CSIDL_PROGRAMS := 0x0002 ; C:\Documents and Settings\username\Start Menu\Programs
  1291. CSIDL_RESOURCES := 0x0038 ; %windir%\Resources\, For theme and other windows resources.
  1292. CSIDL_STARTMENU := 0x000b ; C:\Documents and Settings\username\Start Menu
  1293. CSIDL_STARTUP := 0x0007 ; C:\Documents and Settings\username\Start Menu\Programs\Startup.
  1294. CSIDL_SYSTEM := 0x0025 ; GetSystemDirectory()
  1295. CSIDL_WINDOWS := 0x0024 ; GetWindowsDirectory()
  1296. }
  1297. val := CSIDL_%csidl%
  1298. VarSetCapacity(fpath, 256)
  1299. DllCall("shell32\SHGetFolderPathA", "uint", 0, "int", val, "uint", 0, "int", 0, "str", fpath)
  1300. Return %fpath%
  1301. }
  1302.  
  1303. ; StrX function because some modules use it and Pause needs it for XML reading
  1304. StrX( H, BS="",BO=0,BT=1, ES="",EO=0,ET=1, ByRef N="" ) {
  1305. Return SubStr(H,P:=(((Z:=StrLen(ES))+(X:=StrLen(H))+StrLen(BS)-Z-X)?((T:=InStr(H,BS,0,((BO
  1306. <0)?(1):(BO))))?(T+BT):(X+1)):(1)),(N:=P+((Z)?((T:=InStr(H,ES,0,((EO)?(P+1):(0))))?(T-P+Z
  1307. +(0-ET)):(X+P)):(X)))-P)
  1308. }
  1309.  
  1310. HexCompareWrite(file,Pos,Value){
  1311. If (value = "") {
  1312. Log("HexCompareWrite - NULL value supplied",2)
  1313. Return
  1314. }
  1315. curBin := BinRead(file,nvramData,1,Pos) ; read binary
  1316. Bin2Hex(curHex,nvramData,curBin) ; convert to hex
  1317. If (curHex != value) {
  1318. Log("HexCompareWrite - Changing " . curHex . " to " . value . " in: " . file,4)
  1319. Hex2Bin(binData,value)
  1320. BinWrite(file,binData,1,Pos)
  1321. }
  1322. }
  1323.  
  1324. 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") {
  1325. Global sysLang,langFile
  1326. Log("i18n - Started",4)
  1327. IniRead, phrase, %langFile%, %sysLang%, %key%
  1328. If (phrase = "ERROR" || phrase = "")
  1329. {
  1330. ; Nothing found, test with generic language
  1331. StringSplit, keyArray, sysLang, _
  1332. Log("i18n - Section """ . sysLang . """ & key """ . key . """ not found, trying section """ . keyArray1 . """",4)
  1333. IniRead, phrase, %langFile% , %keyArray1%, %key%
  1334. If (phrase = "ERROR" || phrase = "")
  1335. {
  1336. Log("i18n - Section """ . keyArray1 . """ & key """ . key . """ not found, trying section """ . defaultLocale . """",4)
  1337. ; Nothing found, test with default locale if one is provided
  1338. If (defaultLocale != "")
  1339. {
  1340. IniRead, phrase, %langFile% , %defaultLocale%, %key%
  1341. If (phrase = "ERROR" || phrase = "")
  1342. {
  1343. ; Nothing found, test with generic language for default locale as well
  1344. StringSplit, keyArray, defaultLocale, _
  1345. Log("i18n - Section """ . defaultLocale . """ & key """ . key . """ not found, trying section """ . keyArray1 . """",4)
  1346. IniRead, phrase, %langFile% , %keyArray1%, %key%
  1347. }
  1348. }
  1349. ; Nothing found return original value
  1350. If (defaultLocale = "" || phrase = "ERROR" || phrase = "") {
  1351. Log("i18n - Ended, no phrase found for """ . key . """ in language """ . sysLang . """. Using default """ . key . """",2)
  1352. Return % key
  1353. }
  1354. }
  1355. }
  1356.  
  1357. StringReplace, phrase, phrase, `\n, `r`n, ALL
  1358. StringReplace, phrase, phrase, `\t, % A_Tab, ALL
  1359. Loop 10
  1360. {
  1361. idx := A_Index - 1
  1362. IfNotEqual, p%idx%, -0
  1363. phrase := RegExReplace(phrase, "\{" . idx . "\}", p%idx%)
  1364. }
  1365. Log("i18n - Ended, using """ . phrase . """ for """ . key . """",4)
  1366. Return % phrase
  1367. }
  1368.  
  1369. ; Debug console handler
  1370. DebugMessage(str) {
  1371. Global rlTitle,rlVersion,rlDebugConsoleStdout
  1372. If !rlDebugConsoleStdout
  1373. DebugConsoleInitialize(rlDebugConsoleStdout, rlTitle . " v" . rlVersion . " Debug Console") ; start console window if not yet started
  1374. str .= "`n" ; add line feed
  1375. FileAppend %str%, CONOUT$
  1376. ; FileAppend %str%`n, * ; Works with SciTE and similar editors.
  1377. ; OutputDebug %str%`n ; Works with Visual Studio and DbgView.
  1378. WinSet, Bottom,, ahk_id %rlDebugConsoleStdout% ; keep console on bottom
  1379. }
  1380.  
  1381. DebugConsoleInitialize(ByRef handle, title="") {
  1382. ; two calls to open, no error check (it's debug, so you know what you are doing)
  1383. DllCall("AttachConsole", int, -1, int)
  1384. DllCall("AllocConsole", int)
  1385.  
  1386. DllCall("SetConsoleTitle", "str", (If title ? title : a_scriptname)) ; Set the title
  1387. handle := DllCall("GetStdHandle", "int", -11) ; get the handle
  1388. WinSet, Bottom,, ahk_id %handle% ; make sure it's on the bottom
  1389. Return
  1390. }
  1391.  
  1392. ;Sends a command to the active window using AHK key names. It will always send down/up keypresses for better compatibility
  1393. ;A special command {Wait} can be used to force a sleep of the time defined by WaitTime
  1394. ;WaitCommandOffset will affect all Wait events passed in the Command string by this amount
  1395. SendCommand(Command, SendCommandDelay=2000, WaitTime=500, WaitBetweenSends=0, Delay=50, PressDuration=-1, WaitCommandOffset=0) {
  1396. Log("SendCommand - Started")
  1397. 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)
  1398. ArrayCount := 0 ;Keeps track of how many items are in the array.
  1399. InsideBrackets := 0 ;If 1 it means the current array item starts with {
  1400. SavedKeyDelay := A_KeyDelay ;Saving previous key delay and setting the new one
  1401. SetKeyDelay, %Delay%, %PressDuration%
  1402. Sleep, %SendCommandDelay% ;Wait before starting to send any command
  1403.  
  1404. ;Create an array with each command as an array element
  1405. Loop, % StrLen(Command)
  1406. { StrValue := SubStr(Command,A_Index,1)
  1407. ; { StringMid, StrValue, Command, A_Index, 1
  1408. If (StrValue != A_Space || InsideBrackets = 1) ; Spaces must be allowed when inside brackets so we can issue {Shift Down} for instance
  1409. { If (InsideBrackets = 0)
  1410. ArrayCount += 1
  1411. If (StrValue = "{")
  1412. { If (InsideBrackets = 1)
  1413. ScriptError("Non-Matching brackets detected in the SendCommand parameter, please correct it")
  1414. Else
  1415. InsideBrackets := 1
  1416. } Else If (StrValue = "}")
  1417. { If (InsideBrackets = 0)
  1418. ScriptError("Non-Matching brackets detected in the SendCommand parameter, please correct it")
  1419. Else
  1420. InsideBrackets := 0
  1421. }
  1422. Array%ArrayCount% := Array%ArrayCount% . StrValue ;Update the array data
  1423. }
  1424. }
  1425.  
  1426. ;Loop through the array and send the commands
  1427. Loop %ArrayCount%
  1428. { element := Array%A_Index%
  1429.  
  1430. If (WaitBetweenSends = 1)
  1431. Sleep, %WaitTime%
  1432.  
  1433. ;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
  1434. If RegExMatch(element,"i)Down}")
  1435. { If (element != "{Down}")
  1436. { Send, %element%
  1437. continue
  1438. }
  1439. }
  1440. Else If RegExMatch(element,"i)Up}")
  1441. { If (element != "{Up}")
  1442. { Send, %element%
  1443. Continue
  1444. }
  1445. }
  1446. Else If (element = "{Wait}") ;Special non-ahk tag to issue a sleep
  1447. { NewWaitTime := WaitTime + WaitCommandOffset
  1448. Sleep, %NewWaitTime%
  1449. Continue
  1450. }
  1451. Else If RegExMatch(element,"i)\{Wait:")
  1452. { ;Wait for a specified amount of time {Wait:xxx}
  1453. ; StringMid, NewWaitTime, element, 7, StrLen(element) - 7
  1454. NewWaitTime := SubStr(element,7,StrLen(element) - 7)
  1455. NewWaitTime := NewWaitTime + WaitCommandOffset
  1456. Sleep, %NewWaitTime%
  1457. Continue
  1458. }
  1459.  
  1460. ;the rest of the commands, send a keypress with down and up suffixes
  1461. If RegExMatch(element,"}")
  1462. { StrElement := SubStr(element,1,StrLen(element) - 1)
  1463. ; { StringLeft, StrElement, element, StrLen(element) - 1
  1464. Send, %StrElement% down}%StrElement% up}
  1465. } Else
  1466. Send, {%element% down}{%element% up}
  1467. }
  1468. ;Restore key delay values
  1469. SetKeyDelay(SavedKeyDelay, -1)
  1470. Log("SendCommand - Ended")
  1471. }
  1472.  
  1473. ; Purpose: Tell a ServoStik to transition to 4 or 8-way mode
  1474. ; Parameters:
  1475. ; direction = Can be 4 or 8, self-explanatory
  1476. ServoStik(direction) {
  1477. Log("ServoStik - Started")
  1478. Global PacDriveDllFile,servoStikEnabled
  1479. Static dllExists
  1480. If !RegExMatch(direction,"4|8")
  1481. {
  1482. Log("ServoStik - """ . direction . """ is not a supported direction for ServoSticks. Only 4 and 8 are supported. Leaving your ServoStik as is.",2)
  1483. Return
  1484. }
  1485. If !dllExists {
  1486. CheckFile(pacDrivedllFile, "Following file is required for RocketLauncher ServoStik support, but could not be found:`n" . pacDrivedllFile)
  1487. dllExists := 1 ; do not run this check again
  1488. }
  1489. pacDriveLoadModule := DllCall("LoadLibrary", "Str", PacDriveDllFile) ; Avoids the need for ahk to load and free the dll's library multiple times
  1490. pacInitialize := DllCall(PacDriveDllFile . "\PacInitialize") ; Initialize all PacDrive, PacLED64 and U-HID Devices and return the amount connected to system
  1491. If !pacInitialize {
  1492. Log("ServoStik - No devices found on system",2)
  1493. Log("ServoStik - Ended")
  1494. Return
  1495. } Else
  1496. 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")
  1497.  
  1498. result := DllCall(PacDriveDllFile . "\PacSetServoStik" . direction . "Way") ; Tell ServoStiks to change to desired direction
  1499. If !result
  1500. Log("ServoStik - There was a problem telling your ServoStik(s) to go " . direction . "-Way",3)
  1501. Else
  1502. Log("ServoStik - ServoStik(s) were told to go " . direction . "-Way")
  1503. ; pacDriveUnloadModule := DllCall("FreeLibrary", "UInt", pacDriveLoadModule) ; To conserve memory, the DLL is unloaded after using it.
  1504. Log("ServoStik - Ended")
  1505. }
  1506.  
  1507. GetTimeString(time) {
  1508. If (time<0)
  1509. Return time
  1510. If time is not number
  1511. Return time
  1512. Days := time // 86400
  1513. Hours := Mod(time, 86400) // 3600
  1514. Minutes := Mod(time, 3600) // 60
  1515. Seconds := Mod(time, 60)
  1516. If (Days<>0) {
  1517. If Strlen(Hours) = 1
  1518. Hours = 0%Hours%
  1519. If Strlen(Minutes) = 1
  1520. Minutes = 0%Minutes%
  1521. If Strlen(Seconds) = 1
  1522. Seconds = 0%Seconds%
  1523. TimeString = %Days%d %Hours%h %Minutes%m %Seconds%s
  1524. } Else If (Hours<>0) {
  1525. If Strlen(Minutes) = 1
  1526. Minutes = 0%Minutes%
  1527. If Strlen(Seconds) = 1
  1528. Seconds = 0%Seconds%
  1529. TimeString = %Hours%h %Minutes%m %Seconds%s
  1530. } Else If (Minutes<>0) {
  1531. If Strlen(Seconds) = 1
  1532. Seconds = 0%Seconds%
  1533. TimeString = %Minutes%m %Seconds%s
  1534. } Else If (Seconds<>0)
  1535. TimeString = %Seconds%s
  1536. Else
  1537. TimeString := ""
  1538. Return TimeString
  1539. }
  1540.  
  1541. ReplaceFileNameInvalidChar(ByRef hastack,list,replaceChar){
  1542. Loop, Parse, list, `,
  1543. StringReplace, hastack, hastack, %a_loopfield%, %replaceChar%, All
  1544. Return hastack
  1545. }
  1546.  
  1547.  
  1548. ;-------------------------------------------------------------------------------------------------------------
  1549. ;-------------------------------------------- RL Media Functions ---------------------------------------------
  1550. ;-------------------------------------------------------------------------------------------------------------
  1551. rndRLMediaLogoPath(assetType){
  1552. Global RLMedia, feMedia, gameInfo
  1553. If !(RLMedia)
  1554. RLMedia := loadRLMediaLogos(gameInfo)
  1555. LogoImageList := []
  1556. for index, element in RLMedia["Logos"]
  1557. If (element.Label)
  1558. If (element.AssetType=assetType)
  1559. Loop, % element.TotalItems
  1560. LogoImageList.Insert(element["Path" . a_index])
  1561. If !(LogoImageList[1])
  1562. for index, element in feMedia["Logos"]
  1563. If (element.Label)
  1564. If (element.AssetType=assetType)
  1565. Loop, % element.TotalItems
  1566. LogoImageList.Insert(element["Path" . a_index])
  1567. If (LogoImageList[1]) {
  1568. Random, RndmLogoImage, 1, % LogoImageList.MaxIndex()
  1569. Return LogoImageList[RndmLogoImage]
  1570. }
  1571. }
  1572.  
  1573. LoadRLMediaLogos(gameInfoObj){
  1574. Global RLMediaPath, RLMedia, systemname, dbname, romTable, mgCandidate
  1575. RLMedia := {}
  1576. LogoList := "Genre|Rating|Developer|Publisher|Year"
  1577. Loop, Parse, LogoList, |
  1578. { If (gameInfoObj[A_LoopField].Value){
  1579. %A_LoopField% := gameInfoObj[A_LoopField].Value
  1580. If (A_LoopField = "Genre"){
  1581. ReplaceFileNameInvalidChar(%A_LoopField%,"/,|","\") ;Replacing invalid file name characters by folder separator ("\")
  1582. ReplaceFileNameInvalidChar(%A_LoopField%,"*","-") ;Replacing invalid file name characters by hippens ("-")
  1583. } Else
  1584. ReplaceFileNameInvalidChar(%A_LoopField%,"/,*,|","-") ;Replacing invalid file name characters by hippens ("-")
  1585. ReplaceFileNameInvalidChar(%A_LoopField%,":"," - ") ;Replacing invalid file name characters by hippens ("-")
  1586. ReplaceFileNameInvalidChar(%A_LoopField%,"?," . """" . ",<,>","") ;Replacing invalid file name characters by hippens ("-")
  1587. %A_LoopField% :=RegExReplace(%A_LoopField%,"^\s+|\s+(?=\s)|\s$") ;remove double white spaces
  1588. If (FileExist(RLMediaPath . "\" . A_LoopField . "\" . systemname . "\" . dbname . "\" . %A_LoopField% . ".*"))
  1589. %A_LoopField%Path := RLMediaPath . "\" . A_LoopField . "\" . systemname . "\" . dbname . "\" . %A_LoopField% . ".*"
  1590. Else If (FileExist(RLMediaPath . "\" . A_LoopField . "\" . systemname . "\_Default\" . %A_LoopField% . ".*"))
  1591. %A_LoopField%Path := RLMediaPath . "\" . A_LoopField . "\" . systemname . "\_Default\" . %A_LoopField% . ".*"
  1592. Else
  1593. %A_LoopField%Path := RLMediaPath . "\" . A_LoopField . "\_Default\" . %A_LoopField% . ".*"
  1594. }
  1595. }
  1596. 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")
  1597. systemLogoPath := RLMediaPath . "\Logos\" . systemname . "\_Default\"
  1598. gameLogoPath1 := RLMediaPath . "\Logos\" . systemname . "\" . dbname . "\"
  1599. ;Description name without (Disc X)
  1600. If (!romTable && mgCandidate)
  1601. romTable := CreateRomTable(dbName)
  1602. Totaldiscsofcurrentgame := romTable.MaxIndex()
  1603. If (Totaldiscsofcurrentgame > 1) {
  1604. DescriptionNameWithoutDisc := romTable[1,4]
  1605. gameLogoPath2 := RLMediaPath . "\Logos\" . systemname . "\" . DescriptionNameWithoutDisc . "\"
  1606. }
  1607. RLMedia.Logos := BuildAssetsTable(systemLogoPath . "|" . gameLogoPath1 . "|" . gameLogoPath2,"System Logo|Game Logo|Game Logo","system|game|game","png|bmp|gif|jpg|tif",RLMedia.Logos)
  1608. Return RLMedia
  1609. }
  1610.  
  1611. ; Inject a shared function for Pause and Fade which adjusts the background image positioning
  1612. ; 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.
  1613. GetBGPicPosition(ByRef retX,ByRef retY,ByRef retW,ByRef retH,w,h,pos){
  1614. Global baseScreenWidth, baseScreenHeight
  1615. widthMaxPercent := ( baseScreenWidth / w ) ; get the percentage needed to maximumise the image so it reaches the screen's width
  1616. heightMaxPercent := ( baseScreenHeight / h )
  1617. If (pos = "Stretch and Lose Aspect") { ; image is stretched to screen, loosing aspect
  1618. retW := baseScreenWidth
  1619. retH := baseScreenHeight
  1620. retX := 0
  1621. retY := 0
  1622. } Else If (pos = "Stretch and Keep Aspect") { ; image is stretched to Center screen, keeping aspect
  1623. 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
  1624. retW := Round(w * percentToEnlarge) ; multiply width by the percentage from above to reach as close to the edge as possible
  1625. retH := Round(h * percentToEnlarge) ; multiply height by the percentage from above to reach as close to the edge as possible
  1626. retX := ( baseScreenWidth / 2 ) - ( retW / 2 ) ; find where to place the X of the image
  1627. retY := ( baseScreenHeight / 2 ) - ( retH / 2 ) ; find where to place the Y of the image
  1628. } Else If (pos = "Center Width") { ; image is stretched to Center screen's width, keeping aspect
  1629. percentToEnlarge := widthMaxPercent ; increase the image size by the percentage it takes to reaches the screen's width, cropping may occur on top and bottom
  1630. retW := Round(w * percentToEnlarge) ; multiply width by the percentage from above to reach as close to the edge as possible
  1631. retH := Round(h * percentToEnlarge) ; multiply height by the percentage from above to reach as close to the edge as possible
  1632. retX := ( baseScreenWidth / 2 ) - ( retW / 2 ) ; find where to place the X of the image
  1633. retY := ( baseScreenHeight / 2 ) - ( retH / 2 ) ; find where to place the Y of the image
  1634. } Else If (pos = "Center Height") { ; image is stretched to Center screen's height, keeping aspect
  1635. percentToEnlarge := heightMaxPercent ; increase the image size by the percentage it takes to reaches the screen's height, cropping may occur on left and right
  1636. retW := Round(w * percentToEnlarge) ; multiply width by the percentage from above to reach as close to the edge as possible
  1637. retH := Round(h * percentToEnlarge) ; multiply height by the percentage from above to reach as close to the edge as possible
  1638. retX := ( baseScreenWidth / 2 ) - ( retW / 2 ) ; find where to place the X of the image
  1639. retY := ( baseScreenHeight / 2 ) - ( retH / 2 ) ; find where to place the Y of the image
  1640. } Else If (pos = "Center") { ; original image size and aspect
  1641. retX := ( baseScreenWidth / 2 ) - ( w / 2 ) ; find where to place the X of the image
  1642. retY := ( baseScreenHeight / 2 ) - ( h / 2 ) ; find where to place the Y of the image
  1643. } Else If (pos = "Align to Bottom Left") { ; place the pic so the bottom left corner matches the screen's bottom left corner
  1644. retH := baseScreenHeight
  1645. retW := Round( w / ( h / baseScreenHeight ))
  1646. If ( retW < baseScreenWidth ){
  1647. retW := baseScreenWidth
  1648. retH := Round( h / ( w / retW ))
  1649. }
  1650. retY := baseScreenHeight - retH
  1651. } Else If (pos = "Align to Bottom Right") { ; place the pic so the bottom right corner matches the screen's bottom right corner
  1652. retH := baseScreenHeight
  1653. retW := Round( w / ( h / baseScreenHeight ))
  1654. If ( retW < baseScreenWidth ){
  1655. retW := baseScreenWidth
  1656. retH := Round( h / ( w / retW ))
  1657. }
  1658. retX := baseScreenWidth - retW
  1659. retY := baseScreenHeight - retH
  1660. } Else If (pos = "Align to Top Right") { ; place the pic so the top right corner matches the screen's top right corner
  1661. retH := baseScreenHeight
  1662. retW := Round( w / ( h / baseScreenHeight ))
  1663. If ( retW < baseScreenWidth ){
  1664. retW := baseScreenWidth
  1665. retH := Round( h / ( w / retW ))
  1666. }
  1667. retX := baseScreenWidth - retW
  1668. } Else { ; place the pic so the top left corner matches the screen's top left corner, also the default
  1669. retH := baseScreenHeight
  1670. retW := Round( w / ( h / baseScreenHeight ))
  1671. If ( retW < baseScreenWidth ){
  1672. retW := baseScreenWidth
  1673. retH := Round( h / ( w / retW ))
  1674. }
  1675. }
  1676. }
  1677.  
  1678. ; 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.
  1679. GetFadePicPosition(ByRef retX, ByRef retY,x,y,w,h,pos){
  1680. Global baseScreenWidth, baseScreenHeight
  1681. If (pos = "Stretch and Lose Aspect"){ ; image is stretched to screen, loosing aspect
  1682. retX := 0
  1683. retY := 0
  1684. } Else If (pos = "Stretch and Keep Aspect") { ; image is stretched to screen, keeping aspect
  1685. retX := round(( baseScreenWidth / 2 ) - ( w / 2 ))
  1686. retY := round(( baseScreenHeight / 2 ) - ( h / 2 ))
  1687. } Else If (pos = "Center") {
  1688. retX := round(( baseScreenWidth / 2 ) - ( w / 2 ))
  1689. retY := round(( baseScreenHeight / 2 ) - ( h / 2 ))
  1690. } Else If (pos = "Top Left Corner") {
  1691. retX := 0
  1692. retY := 0
  1693. } Else If (pos = "Top Right Corner") {
  1694. retX := baseScreenWidth - w
  1695. retY := 0
  1696. } Else If (pos = "Bottom Left Corner") {
  1697. retX := 0
  1698. retY := baseScreenHeight - h
  1699. } Else If (pos = "Bottom Right Corner") {
  1700. retX := baseScreenWidth - w
  1701. retY := baseScreenHeight - h
  1702. } Else If (pos = "Top Center") {
  1703. retX := round(( baseScreenWidth / 2 ) - ( w / 2 ))
  1704. retY := 0
  1705. } Else If (pos = "Bottom Center") {
  1706. retX := round(( baseScreenWidth / 2 ) - ( w / 2 ))
  1707. retY := baseScreenHeight - h
  1708. } Else If (pos = "Left Center") {
  1709. retX := 0
  1710. retY := round(( baseScreenHeight / 2 ) - ( h / 2 ))
  1711. } Else If (pos = "Right Center") {
  1712. retX := baseScreenWidth - w
  1713. retY := round(( baseScreenHeight / 2 ) - ( h / 2 ))
  1714. } Else {
  1715. retX := x
  1716. retY := y
  1717. }
  1718. }
  1719.  
  1720. GetRLMediaFiles(mediaType,supportedFileTypes,returnArray=0) {
  1721. Log("GetRLMediaFiles - Started",4)
  1722. Global RLMediaPath,dbName,systemName,romTable,mgCandidate
  1723. If (!romTable && mgCandidate)
  1724. romTable:=CreateRomTable(dbName)
  1725. DescriptionNameWithoutDisc := romTable[1,4]
  1726. romFolder := RLMediaPath . "\" . mediaType . "\" . systemName . "\" . dbName . "\"
  1727. romDisckLessFolder := RLMediaPath . "\" . mediaType . "\" . systemName . "\" . DescriptionNameWithoutDisc . "\"
  1728. systemFolder := RLMediaPath . "\" . mediaType . "\" . systemName . "\_Default\"
  1729. globalFolder := RLMediaPath . "\" . mediaType . "\_Default\"
  1730. imagesArray := []
  1731. Loop, Parse, supportedFileTypes, |
  1732. If FileExist(romFolder . "*." . A_LoopField) {
  1733. Loop % romFolder . "*." . A_LoopField
  1734. imagesArray[A_Index] := A_LoopFileFullPath
  1735. }
  1736. If imagesArray.MaxIndex() <= 0
  1737. Loop, Parse, supportedFileTypes, |
  1738. If FileExist(romDisckLessFolder . "*." . A_LoopField) {
  1739. Loop % romDisckLessFolder . "*." . A_LoopField
  1740. imagesArray[A_Index] := A_LoopFileFullPath
  1741. }
  1742. If imagesArray.MaxIndex() <= 0
  1743. Loop, Parse, supportedFileTypes, |
  1744. If FileExist(systemFolder . "*." . A_LoopField) {
  1745. Loop % systemFolder . "*." . A_LoopField
  1746. imagesArray[A_Index] := A_LoopFileFullPath
  1747. }
  1748. If imagesArray.MaxIndex() <= 0
  1749. Loop, Parse, supportedFileTypes, |
  1750. If FileExist(globalFolder . "*." . A_LoopField) {
  1751. Loop % globalFolder . "*." . A_LoopField
  1752. imagesArray[A_Index] := A_LoopFileFullPath
  1753. }
  1754. If returnArray {
  1755. Log("GetRLMediaFiles - Ended, returning array",4)
  1756. Return imagesArray
  1757. }
  1758. Else {
  1759. Random, RndmImagePic, 1, % imagesArray.MaxIndex()
  1760. file := imagesArray[RndmImagePic]
  1761. Log("GetRLMediaFiles - Ended, randomized RocketLauncher " . mediaType . " file selected: " . file)
  1762. Return file
  1763. }
  1764. }
  1765.  
  1766.  
  1767. ;-------------------------------------------------------------------------------------------------------------
  1768. ;----------------------------------------- DXWnd Functions -----------------------------------------
  1769. ;-------------------------------------------------------------------------------------------------------------
  1770.  
  1771. ; If you provide a value, DxwndIniRW assumes you want to write to the ini
  1772. ; If no value is provided, DxwndIniRW assumes you want to read from the ini and returns the value
  1773. ; DxwndIniRW is only used to read and write settings to dxwnd.ini
  1774. ; DxwndRun is for launching dxwnd
  1775. ; DxwndClose is for closing dxwnd
  1776. ; DxwndUpdateIniPath is for updating the dxwndIni variable
  1777. DxwndIniRW(sec="",key="",val="", default="", cTarget="") {
  1778. Log("DxwndIniRW - Started")
  1779. Global dxwndIni,romName
  1780. Static pos,iniExists
  1781. If !iniExists {
  1782. CheckFile(dxwndIni)
  1783. iniExists := 1 ; do not run this check again
  1784. }
  1785. If !pos { ; the current romName or cTarget position has not been found, loop through the ini to find it first
  1786. targetGame := If cTarget ? cTarget : romName
  1787. Loop {
  1788. pos := a_index-1
  1789. IniRead, dxwndName, %dxwndIni%, target, title%pos%
  1790. If (dxwndName = targetGame)
  1791. Break
  1792. If (dxwndName = "ERROR")
  1793. 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.")
  1794. }
  1795. }
  1796. errLvl := Process("Exist", "dxwnd.exe") ; Make sure dxwnd is not running first so settings don't get reverted
  1797. If errLvl {
  1798. DxwndClose()
  1799. Process("WaitClose", "dxwnd.exe")
  1800. }
  1801. If val {
  1802. IniWrite, %val%, %dxwndIni%, %sec%, %key%%pos%
  1803. Log("DxwndIniRW - Wrote """ . val . """ to game #" . pos,4)
  1804. } Else {
  1805. IniRead, val, %dxwndIni%, %sec%, %key%%pos%
  1806. Log("DxwndIniRW - Read """ . val . """",4)
  1807. Log("DxwndIniRW - Ended")
  1808. Return val
  1809. }
  1810. Log("DxwndIniRW - Ended")
  1811. }
  1812.  
  1813. DxwndRun(ByRef outPID="") {
  1814. Log("DxwndRun - Started")
  1815. Global dxwndFullPath,dxwndExe,dxwndPath,dxwndIni
  1816. Static exeExists
  1817. If !exeExists {
  1818. CheckFile(dxwndFullPath, "Following file is required for DXWnd support, but its file could not be found:`n" . dxwndFullPath)
  1819. exeExists := 1 ; do not run this check again
  1820. }
  1821. If !dxwndExe
  1822. SplitPath, dxwndFullPath, dxwndExe, dxwndPath
  1823. SplitPath, dxwndIni, dxwndIniFile
  1824.  
  1825. Run(dxwndExe . " /T /C:""" . dxwndIniFile . """", dxwndPath, "Min", outPID)
  1826. errLvl := Process("Wait", dxwndExe, 10) ; waiting 10 seconds for dxwnd to start
  1827. If (errLvl = "")
  1828. ScriptError("DXWnd did not start after waiting for 10 seconds. Please check you can run it manually and try again.")
  1829. Else
  1830. Log("DxwndRun - DxwndRun is now running")
  1831. Log("DxwndRun - Ended")
  1832. }
  1833.  
  1834. DxwndClose() {
  1835. Log("DxwndClose - Started")
  1836. Global dxwndFullPath,dxwndExe,dxwndPath
  1837. If !dxwndExe
  1838. SplitPath, dxwndFullPath, dxwndExe, dxwndPath
  1839. PostMessage, 0x111, 32810,,,ahk_exe %dxwndExe% ; this tells dxwnd to close itself
  1840. Process("WaitClose", dxwndExe, 1) ; waits 1 second for dxwnd to close
  1841. errLvl := Process("Exist", dxwndExe) ; checks if dxwnd is still running
  1842. If errLvl
  1843. Process("Close", dxwndExe) ; only needed when RocketLauncher is not ran as admin or RocketLauncher cannot close dxwnd for some reason
  1844. Log("DxwndClose - Ended")
  1845. }
  1846.  
  1847. DxwndUpdateIniPath() {
  1848. Global dxwndFullPath,dxwndPath,dxwndIni,systemName
  1849. SplitPath,dxwndFullPath,,dxwndPath
  1850.  
  1851. If FileExist( dxwndPath . "\" . systemName . ".ini" )
  1852. dxwndIni := dxwndPath . "\" . systemName . ".ini"
  1853. Else
  1854. dxwndIni := dxwndPath . "\dxwnd.ini"
  1855.  
  1856. Log("DxwndUpdateIniPath - DxwndIni set to " . dxwndIni)
  1857. }
  1858.  
  1859. ;-------------------------------------------------------------------------------------------------------------
  1860. ;----------------------------------- Cursor Control Functions ------------------------------------
  1861. ;-------------------------------------------------------------------------------------------------------------
  1862.  
  1863. ToggleCursor:
  1864. Log("ToggleCursor - Hotkey """ . toggleCursorKey . """ pressed, toggling cursor visibility")
  1865. SystemCursor("Toggle")
  1866. Return
  1867.  
  1868. ; Function to hide/unhide the mouse cursor
  1869. SystemCursor(OnOff=1) ; INIT = "I","Init"; OFF = 0,"Off"; TOGGLE = -1,"T","Toggle"; ON = others
  1870. { Global mouseCursorHidden
  1871. Static AndMask, XorMask, cursor, h_cursor
  1872. ,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13 ; system cursors
  1873. , b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13 ; blank cursors
  1874. , h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11,h12,h13 ; handles of default cursors
  1875. If (OnOff = "Init" or OnOff = "I" or cursor = "") ; init when requested or at first call
  1876. {
  1877. cursor := "h" ; active default cursors
  1878. VarSetCapacity( h_cursor,4444, 1 )
  1879. VarSetCapacity( AndMask, 32*4, 0xFF )
  1880. VarSetCapacity( XorMask, 32*4, 0 )
  1881. system_cursors = 32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650
  1882. StringSplit c, system_cursors, `,
  1883. Loop %c0%
  1884. {
  1885. h_cursor := DllCall( "LoadCursor", "uint",0, "uint",c%A_Index% )
  1886. h%A_Index% := DllCall( "CopyImage", "uint",h_cursor, "uint",2, "int",0, "int",0, "uint",0 )
  1887. b%A_Index% := DllCall("CreateCursor","uint",0, "int",0, "int",0
  1888. , "int",32, "int",32, "uint",&AndMask, "uint",&XorMask )
  1889. }
  1890. }
  1891. If (OnOff = 0 or OnOff = "Off" or cursor = "h" and (OnOff < 0 or OnOff = "Toggle" or OnOff = "T")){
  1892. cursor := "b" ; use blank cursors
  1893. Log("SystemCursor - Hiding mouse cursor")
  1894. CoordMode, Mouse ; Also lets move it to the side since some emu's flash a cursor real quick even if we hide it.
  1895. MouseMove, 0, 0, 0
  1896. } Else {
  1897. cursor := "h" ; use the saved cursors
  1898. SPI_SETCURSORS := 0x57 ; Emergency restore cursor, just in case something goes wrong
  1899. DllCall( "SystemParametersInfo", UInt,SPI_SETCURSORS, UInt,0, UInt,0, UInt,0 )
  1900. mouseCursorHidden := ""
  1901. Log("SystemCursor - Restoring mouse cursor")
  1902. }
  1903.  
  1904. Loop %c0%
  1905. {
  1906. h_cursor := DllCall( "CopyImage", "uint",%cursor%%A_Index%, "uint",2, "int",0, "int",0, "uint",0 )
  1907. DllCall( "SetSystemCursor", "uint",h_cursor, "uint",c%A_Index% )
  1908. }
  1909. }
  1910.  
  1911. SetSystemCursor( Cursor = "", cx = 0, cy = 0 ) {
  1912. BlankCursor := 0, SystemCursor := 0, FileCursor := 0 ; init
  1913.  
  1914. SystemCursors = 32512IDC_ARROW,32513IDC_IBEAM,32514IDC_WAIT,32515IDC_CROSS
  1915. ,32516IDC_UPARROW,32640IDC_SIZE,32641IDC_ICON,32642IDC_SIZENWSE
  1916. ,32643IDC_SIZENESW,32644IDC_SIZEWE,32645IDC_SIZENS,32646IDC_SIZEALL
  1917. ,32648IDC_NO,32649IDC_HAND,32650IDC_APPSTARTING,32651IDC_HELP
  1918.  
  1919. If (Cursor = "") ; empty, so create blank cursor
  1920. {
  1921. Log("SetSystemCursor - Creating blank cursor",4)
  1922. VarSetCapacity( AndMask, 32*4, 0xFF ), VarSetCapacity( XorMask, 32*4, 0 )
  1923. BlankCursor := 1 ; flag for later
  1924. }
  1925. Else If SubStr( Cursor,1,4 ) = "IDC_" ; load system cursor
  1926. {
  1927. Log("SetSystemCursor - Loading system cursor",4)
  1928. Loop, Parse, SystemCursors, `,
  1929. {
  1930. CursorName := SubStr( A_Loopfield, 6, 15 ) ; get the cursor name, no trailing space with substr
  1931. CursorID := SubStr( A_Loopfield, 1, 5 ) ; get the cursor id
  1932. SystemCursor := 1
  1933. If ( CursorName = Cursor ) {
  1934. CursorHandle := DllCall( "LoadCursor", Uint,0, Int,CursorID )
  1935. Break
  1936. }
  1937. }
  1938. If (CursorHandle = "") ; invalid cursor name given
  1939. {
  1940. Log("SetSystemCursor - Invalid cursor name supplied: """ . CursorHandle . """",2)
  1941. ; Msgbox,, SetCursor, Error: Invalid cursor name
  1942. CursorHandle := "Error"
  1943. }
  1944. }
  1945. Else If FileExist( Cursor )
  1946. {
  1947. Log("SetSystemCursor - Found this cursor: """ . Cursor . """",4)
  1948. SplitPath, Cursor,,, Ext ; auto-detect type
  1949. If (Ext = "ico")
  1950. uType := 0x1
  1951. Else If RegExMatch("cur|ani","i)" . Ext)
  1952. uType := 0x2
  1953. Else ; invalid file ext
  1954. {
  1955. Log("SetSystemCursor - Invalid cursor extension: """ . Ext . """",2)
  1956. ; Msgbox,, SetCursor, Error: Invalid file type
  1957. CursorHandle := "Error"
  1958. }
  1959. FileCursor := 1
  1960. }
  1961. Else
  1962. {
  1963. Log("SetSystemCursor - Invalid cursor name or path: """ . Cursor . """",2)
  1964. ; Msgbox,, SetCursor, Error: Invalid file path or cursor name
  1965. CursorHandle := "Error" ; raise for later
  1966. }
  1967. If (CursorHandle != "Error")
  1968. {
  1969. Loop, Parse, SystemCursors, `,
  1970. {
  1971. If (BlankCursor = 1)
  1972. {
  1973. Type := "BlankCursor"
  1974. %Type%%A_Index% := DllCall( "CreateCursor", Uint,0, Int,0, Int,0, Int,32, Int,32, Uint,&AndMask, Uint,&XorMask )
  1975. CursorHandle := DllCall( "CopyImage", Uint,%Type%%A_Index%, Uint,0x2, Int,0, Int,0, Int,0 )
  1976. DllCall( "SetSystemCursor", Uint,CursorHandle, Int,SubStr( A_Loopfield, 1, 5 ) )
  1977. }
  1978. Else If (SystemCursor = 1)
  1979. {
  1980. Type := "SystemCursor"
  1981. CursorHandle := DllCall( "LoadCursor", Uint,0, Int,CursorID )
  1982. %Type%%A_Index% := DllCall( "CopyImage", Uint,CursorHandle, Uint,0x2, Int,cx, Int,cy, Uint,0 )
  1983. CursorHandle := DllCall( "CopyImage", Uint,%Type%%A_Index%, Uint,0x2, Int,0, Int,0, Int,0 )
  1984. DllCall( "SetSystemCursor", Uint,CursorHandle, Int,SubStr( A_Loopfield, 1, 5 ) )
  1985. }
  1986. Else If (FileCursor = 1)
  1987. {
  1988. Type := "FileCursor"
  1989. %Type%%A_Index% := DllCall( "LoadImage", UInt,0, Str,Cursor, UInt,uType, Int,cx, Int,cy, UInt,0x10 )
  1990. DllCall( "SetSystemCursor", Uint,%Type%%A_Index%, Int,SubStr( A_Loopfield, 1, 5 ) )
  1991. }
  1992. }
  1993. }
  1994. }
  1995.  
  1996. RestoreCursors() {
  1997. SPI_SETCURSORS := 0x57
  1998. DllCall( "SystemParametersInfo", UInt,SPI_SETCURSORS, UInt,0, UInt,0, UInt,0 )
  1999. }
  2000.  
  2001. ;-------------------------------------------------------------------------------------------------------------
  2002. ;------------------ Read and Write Wrapper Functions for IniFileEdit ------------------
  2003. ;-------------------------------------------------------------------------------------------------------------
  2004.  
  2005. ; Usage - Read and Write to config files that are not valid inis with [sections], like RetroArch's cfg
  2006.  
  2007. ; cfgFile - path to the file to read, only need to send this once, it stays in memory until SavePropertiesCfg is used
  2008. ; Returns a reference number to the array where the cfg is stored in memory so multiple files can be edited at once
  2009. LoadProperties(cfgFile) {
  2010. Log("LoadProperties - Started and loading this cfg into memory: " . cfgFile,4)
  2011. cfgtable := Object()
  2012. Loop, Read, %cfgFile% ; This loop retrieves each line from the file, one at a time.
  2013. cfgtable.Insert(A_LoopReadLine) ; Append this line to the array.
  2014. Log("LoadProperties - Ended",4)
  2015. Return cfgtable
  2016. }
  2017.  
  2018. ; cfgFile - path to the file to read, only need to send this once, it stays in memory until SavePropertiesCfg is used
  2019. ; cfgArray - reference number of array in memory that should be saved to the cfgFile
  2020. SaveProperties(cfgFile,cfgArray) {
  2021. Log("SaveProperties - Started and saving this cfg to disk: " . cfgFile,4)
  2022. FileDelete, %cfgFile%
  2023. Loop % cfgArray.MaxIndex()
  2024. { element := cfgArray[A_Index]
  2025. trimmedElement := LTrim(element)
  2026. finalCfg .= trimmedElement . "`n"
  2027. }
  2028. FileAppend, %finalCfg%, %cfgFile%
  2029. Log("SaveProperties - Ended",4)
  2030. }
  2031.  
  2032. ; cfgArray - reference number of array in memory that you want to read
  2033. ; keyName = key whose value you want to read
  2034. ; Separator = the separator to use, defaults to =
  2035. ReadProperty(cfgArray,keyName,Separator="=") {
  2036. Log("ReadProperty - Started",4)
  2037. Loop % cfgArray.MaxIndex()
  2038. { element := cfgArray[A_Index]
  2039. trimmedElement := Trim(element)
  2040. ;MsgBox % "Element number " . A_Index . " is " . element
  2041.  
  2042. StringGetPos, pos, trimmedElement, [
  2043. If (pos = 0)
  2044. Break ; Section was found, do not search anymore, global section has ended
  2045.  
  2046. If element contains %Separator%
  2047. { StringSplit, keyValues, element, %Separator%
  2048. CfgValue := Trim(keyValues1)
  2049. If (CfgValue = keyName)
  2050. Return Trim(keyValues2) ; Found it & trim any whitespace
  2051. }
  2052. }
  2053. Log("ReadProperty - Ended",4)
  2054. }
  2055.  
  2056. ; cfgArray - reference number of array in memory that you want to read
  2057. ; keyName = key whose value you want to write
  2058. ; Value = value that you want to write to the keyName
  2059. ; AddSpaces = If the seperator (=) has spaces on either side, set this parameter to 1 and it will wrap the seperator in spaces
  2060. ; AddQuotes = If the Value needs to be wrapped in double quotes (like in retroarch's config), set this parameter to 1
  2061. ; Separator = the separator to use, defaults to =
  2062. WriteProperty(cfgArray,keyName,Value,AddSpaces=0,AddQuotes=0,Separator="=") {
  2063. added := 0
  2064. Loop % cfgArray.MaxIndex()
  2065. { lastIndex := A_Index
  2066. element := cfgArray[A_Index]
  2067. trimmedElement := Trim(element)
  2068.  
  2069. StringGetPos, pos, trimmedElement, [
  2070. If (pos = 0)
  2071. { lastIndex := lastIndex - 1 ; Section was found, do not search anymore
  2072. Break
  2073. }
  2074.  
  2075. If element contains %Separator%
  2076. { StringSplit, keyValues, element, %Separator%
  2077. CfgValue := Trim(keyValues1)
  2078. If (CfgValue = keyName)
  2079. { cfgArray[A_Index] := CfgValue . (If AddSpaces=1 ? (" " . Separator . " ") : Separator) . (If AddQuotes=1 ? ("""" . Value . """") : Value) ; Found it
  2080. added := 1
  2081. Break
  2082. }
  2083. }
  2084. }
  2085. If (added = 0)
  2086. cfgArray.Insert(lastIndex+1, keyName . (If AddSpaces=1 ? (" " . Separator . " ") : Separator) . (If AddQuotes=1 ? ("""" . Value . """") : Value)) ; Add the new entry to the file
  2087. Log("WriteProperty - Writing - " . keyName . ": " . value,4)
  2088. }
  2089.  
  2090. ;-------------------------------------------------------------------------------------------------------------
  2091. ;----------------------------------------- Player Select Menu --------------------------------------
  2092. ;-------------------------------------------------------------------------------------------------------------
  2093.  
  2094. ; function to create a small menu with the number of players option
  2095. NumberOfPlayersSelectionMenu(maxPlayers=4) {
  2096. Global screenRotationAngle,baseScreenWidth,baseScreenHeight,xTranslation,yTranslation
  2097. Global navSelectKey,navUpKey,navDownKey,navP2SelectKey,navP2UpKey,navP2DownKey,exitEmulatorKey,exitEmulatorKey
  2098. Global keymapper,keymapperEnabled,keymapperRocketLauncherProfileEnabled
  2099. If !pToken
  2100. pToken := Gdip_Startup()
  2101. Gdip_Alt_GetRotatedDimensions(A_ScreenWidth, A_ScreenHeight, screenRotationAngle, baseScreenWidth, baseScreenHeight)
  2102. Gdip_GetRotatedTranslation(baseScreenWidth, baseScreenHeight, screenRotationAngle, xTranslation, yTranslation)
  2103. xTranslation:=round(xTranslation), yTranslation:=round(yTranslation)
  2104. Loop, 2 {
  2105. Gui, playersMenu_GUI%A_Index%: +Disabled -Caption +E0x80000 +OwnDialogs +LastFound +ToolWindow +AlwaysOnTop
  2106. Gui, playersMenu_GUI%A_Index%: Margin,0,0
  2107. Gui, playersMenu_GUI%A_Index%: Show,, playersMenuLayer%A_Index%
  2108. playersMenu_hwnd%A_Index% := WinExist()
  2109. playersMenu_hbm%A_Index% := CreateDIBSection(A_ScreenWidth, A_ScreenHeight)
  2110. playersMenu_hdc%A_Index% := CreateCompatibleDC()
  2111. playersMenu_obm%A_Index% := SelectObject(playersMenu_hdc%A_Index%, playersMenu_hbm%A_Index%)
  2112. playersMenu_G%A_Index% := Gdip_GraphicsFromhdc(playersMenu_hdc%A_Index%)
  2113. Gdip_SetSmoothingMode(playersMenu_G%A_Index%, 4)
  2114. Gdip_TranslateWorldTransform(playersMenu_G%A_Index%, xTranslation, yTranslation)
  2115. Gdip_RotateWorldTransform(playersMenu_G%A_Index%, screenRotationAngle)
  2116. }
  2117. ;Initializing parameters
  2118. playersMenuTextFont := "Bebas Neue"
  2119. CheckFont(playersMenuTextFont)
  2120. playersMenuSelectedTextSize := 50
  2121. playersMenuSelectedTextColor := "FFFFFFFF"
  2122. playersMenuDisabledTextColor := "FFAAAAAA"
  2123. playersMenuDisabledTextSize := 30
  2124. playersMenuMargin := 50
  2125. playersMenuSpaceBtwText := 30
  2126. playersMenuCornerRadius := 10
  2127. ;menu scalling factor
  2128. XBaseRes := 1920, YBaseRes := 1080
  2129. If (((A_screenWidth < A_screenHeight) and ((screenRotationAngle=0) or (screenRotationAngle=180))) or ((A_screenWidth > A_screenHeight) and ((screenRotationAngle=90) or (screenRotationAngle=270))))
  2130. XBaseRes := 1080, YBaseRes := 1920
  2131. If !playersMenuXScale
  2132. playersMenuXScale := baseScreenWidth/XBaseRes
  2133. If !playersMenuYScale
  2134. playersMenuYScale := baseScreenHeight/YBaseRes
  2135. OptionScale(playersMenuSelectedTextSize, playersMenuYScale)
  2136. OptionScale(playersMenuDisabledTextSize, playersMenuYScale)
  2137. OptionScale(playersMenuMargin, playersMenuXScale)
  2138. OptionScale(playersMenuSpaceBtwText, playersMenuYScale)
  2139. OptionScale(playersMenuCornerRadius, playersMenuXScale)
  2140. playersMenuW := MeasureText("X Players", "Left r4 s" . playersMenuSelectedTextSize . " Bold",playersMenuTextFont) + 2*playersMenuMargin
  2141. playersMenuH := maxPlayers*playersMenuSelectedTextSize + (maxPlayers-1)*playersMenuSpaceBtwText + 2*playersMenuMargin
  2142. playersMenuX := (baseScreenWidth-playersMenuW)//2
  2143. playersMenuY := (baseScreenHeight-playersMenuH)//2
  2144. playersMenuBackgroundBrush := Gdip_BrushCreateSolid("0xDD000000")
  2145. pGraphUpd(playersMenu_G1,playersMenuW,playersMenuH)
  2146. pGraphUpd(playersMenu_G2,playersMenuW,playersMenuH)
  2147. ;Drawing Background
  2148. Gdip_Alt_FillRoundedRectangle(playersMenu_G1, playersMenuBackgroundBrush, 0, 0, playersMenuW, playersMenuH,playersMenuCornerRadius)
  2149. Alt_UpdateLayeredWindow(playersMenu_hwnd1, playersMenu_hdc1, playersMenuX, playersMenuY, playersMenuW, playersMenuH)
  2150. ;Drawing choice list
  2151. SelectedNumberofPlayers := 1
  2152. gosub, DrawPlayersSelectionMenu
  2153. ;Enabling Keys
  2154. If (keymapperEnabled = "true") and (keymapperRocketLauncherProfileEnabled = "true")
  2155. RunKeymapper%zz%("menu",keymapper)
  2156. If keymapperAHKMethod = External
  2157. RunAHKKeymapper%zz%("menu")
  2158. Gosub, EnablePlayersMenuKeys
  2159. LEDBlinky("RL") ; trigger ledblinky profile change if enabled
  2160. ;Waiting for menu to exit
  2161. Loop
  2162. { If PlayersMenuExit
  2163. Break
  2164. Sleep, 100
  2165. }
  2166. LEDBlinky("ROM") ; trigger ledblinky profile change if enabled
  2167. Return SelectedNumberofPlayers
  2168. ;labels to treat menu changes
  2169. DrawPlayersSelectionMenu:
  2170. currentY := 0
  2171. Gdip_GraphicsClear(playersMenu_G2)
  2172. Loop, % maxPlayers
  2173. {
  2174. If (a_index=SelectedNumberofPlayers) {
  2175. currentTextSize := playersMenuSelectedTextSize
  2176. currentTextColor := playersMenuSelectedTextColor
  2177. currentTextStyle := "bold"
  2178. } Else {
  2179. currentTextSize := playersMenuDisabledTextSize
  2180. currentTextColor := playersMenuDisabledTextColor
  2181. currentTextStyle := "normal"
  2182. }
  2183. If (a_index=1)
  2184. currentText := "1 Player"
  2185. Else
  2186. currentText := a_index . " Players"
  2187. currentY := playersMenuMargin + (a_index-1)*(playersMenuSelectedTextSize+playersMenuSpaceBtwText)+(playersMenuSelectedTextSize-currentTextSize)//2
  2188. Gdip_Alt_TextToGraphics(playersMenu_G2, currentText, "x0 y" . currentY . " Center c" . currentTextColor . " r4 s" . currentTextSize . " " . currentTextStyle, playersMenuTextFont, playersMenuW, playersMenuSelectedTextSize)
  2189. }
  2190. Alt_UpdateLayeredWindow(playersMenu_hwnd2, playersMenu_hdc2, playersMenuX, playersMenuY, playersMenuW, playersMenuH)
  2191. Return
  2192. EnablePlayersMenuKeys:
  2193. XHotKeywrapper(navSelectKey,"PlayersMenuSelect","ON")
  2194. XHotKeywrapper(navUpKey,"PlayersMenuUP","ON")
  2195. XHotKeywrapper(navDownKey,"PlayersMenuDown","ON")
  2196. XHotKeywrapper(navP2SelectKey,"PlayersMenuSelect","ON")
  2197. XHotKeywrapper(navP2UpKey,"PlayersMenuUP","ON")
  2198. XHotKeywrapper(navP2DownKey,"PlayersMenuDown","ON")
  2199. XHotKeywrapper(exitEmulatorKey,"CloseProcess","OFF")
  2200. XHotKeywrapper(exitEmulatorKey,"ClosePlayersMenu","ON")
  2201. Return
  2202. DisablePlayersMenuKeys:
  2203. XHotKeywrapper(navSelectKey,"PlayersMenuSelect","OFF")
  2204. XHotKeywrapper(navUpKey,"PlayersMenuUP","OFF")
  2205. XHotKeywrapper(navDownKey,"PlayersMenuDown","OFF")
  2206. XHotKeywrapper(navP2SelectKey,"PlayersMenuSelect","OFF")
  2207. XHotKeywrapper(navP2UpKey,"PlayersMenuUP","OFF")
  2208. XHotKeywrapper(navP2DownKey,"PlayersMenuDown","OFF")
  2209. XHotKeywrapper(exitEmulatorKey,"ClosePlayersMenu","OFF")
  2210. XHotKeywrapper(exitEmulatorKey,"CloseProcess","ON")
  2211. Return
  2212. PlayersMenuUP:
  2213. SelectedNumberofPlayers--
  2214. If (SelectedNumberofPlayers<1)
  2215. SelectedNumberofPlayers:=maxPlayers
  2216. gosub, DrawPlayersSelectionMenu
  2217. Return
  2218. PlayersMenuDown:
  2219. SelectedNumberofPlayers++
  2220. If (SelectedNumberofPlayers>maxPlayers)
  2221. SelectedNumberofPlayers:=1
  2222. gosub, DrawPlayersSelectionMenu
  2223. Return
  2224. ClosePlayersMenu:
  2225. ClosedPlayerMenu := true
  2226. PlayersMenuSelect:
  2227. Gosub, DisablePlayersMenuKeys
  2228. Gdip_DeleteBrush(playersMenuBackgroundBrush)
  2229. Loop, 2 {
  2230. SelectObject(playersMenu_hdc%A_Index%, playersMenu_obm%A_Index%)
  2231. DeleteObject(playersMenu_hbm%A_Index%)
  2232. DeleteDC(playersMenu_hdc%A_Index%)
  2233. Gdip_DeleteGraphics(playersMenu_G%A_Index%)
  2234. Gui, playersMenu_GUI%A_Index%: Destroy
  2235. }
  2236. If ClosedPlayerMenu
  2237. { Log("User cancelled the launch at the Player Select Menu")
  2238. PlayersMenuExit := true
  2239. ExitModule()
  2240. } Else
  2241. Log("Number of Players Selected: " . SelectedNumberofPlayers)
  2242. If (keymapperEnabled = "true") and (keymapperRocketLauncherProfileEnabled = "true")
  2243. RunKeymapper%zz%("load", keymapper)
  2244. If keymapperAHKMethod = External
  2245. RunAHKKeymapper%zz%("load")
  2246. PlayersMenuExit := true
  2247. Return
  2248. }
  2249.  
  2250.  
  2251. ;-------------------------------------------------------------------------------------------------------------
  2252. ;----------------------------------------- HideEmu Functions ---------------------------------------
  2253. ;-------------------------------------------------------------------------------------------------------------
  2254.  
  2255. ; Default is 2ms so it picks up windows as soon as possible
  2256. HideEmuStart(ms=2) {
  2257. Global hideEmu
  2258. Global hideEmuObj
  2259. If (hideEmu = "true")
  2260. { Log("HideEmuStart - Starting HideEmuTimer, scanning for windows defined in hideEmuObj every " . ms . "ms")
  2261. ; First rebuild the single line object into a better one that's easier to track and work with
  2262. newObject := Object()
  2263. For key, value in hideEmuObj
  2264. { currentObj++
  2265. newObject[currentObj,"window"] := key
  2266. newObject[currentObj,"method"] := value
  2267. newObject[currentObj,"status"] := "" ; default is 0 (0 = not hidden yet, 1 = hidden already)
  2268. }
  2269. hideEmuObj := newObject ; overwrite hideEmuObj with the updated one
  2270. ; SetTimer, HideEmuTimer, %ms%
  2271. SetTimerF("HideEmuTimer",ms,hideEmuObj,10) ;create a higher priority timer
  2272. Log("HideEmuStart - Ended")
  2273. }
  2274. }
  2275.  
  2276. HideEmuEnd() {
  2277. Global hideEmu
  2278. Global hideEmuObj
  2279. If (hideEmu = "true")
  2280. { Log("HideEmuEnd - Stopping HideEmuTimer and unhiding flagged windows",4)
  2281. ; SetTimer, HideEmuTimer, Off
  2282. SetTimerF("HideEmuTimer","off")
  2283. For key, value in hideEmuObj
  2284. If (hideEmuObj[A_Index,"method"] && hideEmuObj[A_Index,"status"]) { ; if one of the windows was hidden and needs to be unhidden
  2285. WinSet, Transparent, Off, % hideEmuObj[A_Index,"window"]
  2286. Log("HideEmu - Revealed window: " . hideEmuObj[A_Index,"window"],4)
  2287. }
  2288. Log("HideEmuEnd - Ended",4)
  2289. }
  2290. }
  2291.  
  2292. HideEmuTimer(obj) {
  2293. Log("HideEmuTimer",3)
  2294. For key, value in obj
  2295. { If !obj[A_Index,"status"]
  2296. { If (A_DetectHiddenWindows != "On")
  2297. DetectHiddenWindows, On
  2298. ; msgbox % obj[A_Index,"window"]
  2299. If WinExist(obj[A_Index,"window"])
  2300. { WinSet, Transparent, 0, % obj[A_Index,"window"]
  2301. Log("HideEmu - Found a new window to hide: " . obj[A_Index,"window"],4)
  2302. WinGet, currentTran, Transparent, % obj[A_Index,"window"]
  2303. If (currentTran = 0)
  2304. obj[A_Index,"status"] := 1 ; update object that this window is now hidden
  2305. }
  2306. }
  2307. }
  2308. Return
  2309. }
  2310. HideEmuTimer:
  2311. For key, value in hideEmuObj
  2312. { If !hideEmuObj[A_Index,"status"]
  2313. { If (A_DetectHiddenWindows != "On")
  2314. DetectHiddenWindows, On
  2315. If WinExist(hideEmuObj[A_Index,"window"])
  2316. { WinSet, Transparent, 0, % hideEmuObj[A_Index,"window"]
  2317. Log("HideEmu - Found a new window to hide: " . hideEmuObj[A_Index,"window"],4)
  2318. WinGet, currentTran, Transparent, % hideEmuObj[A_Index,"window"]
  2319. If (currentTran = 0)
  2320. hideEmuObj[A_Index,"status"] := 1 ; update object that this window is now hidden
  2321. }
  2322. }
  2323. }
  2324. Return
  2325.  
  2326. SetTimerF( Function, Period=0, ParmObject=0, Priority=0 ) {
  2327. Static current,tmrs:=[] ;current will hold timer that is currently running
  2328. If IsFunc( Function ) {
  2329. If IsObject(tmr:=tmrs[Function]) ;destroy timer before creating a new one
  2330. ret := DllCall( "KillTimer", UInt,0, PTR, tmr.tmr)
  2331. , DllCall("GlobalFree", PTR, tmr.CBA)
  2332. , tmrs.Remove(Function)
  2333. If (Period = 0 || Period = "off")
  2334. Return ret ;Return as we want to turn off timer
  2335. ; create object that will hold information for timer, it will be passed trough A_EventInfo when Timer is launched
  2336. tmr:=tmrs[Function]:={func:Function,Period:Period="on" ? 250 : Period,Priority:Priority
  2337. ,OneTime:Period<0,params:IsObject(ParmObject)?ParmObject:Object()
  2338. ,Tick:A_TickCount}
  2339. tmr.CBA := RegisterCallback(A_ThisFunc,"F",4,&tmr)
  2340. Return !!(tmr.tmr := DllCall("SetTimer", PTR,0, PTR,0, UInt
  2341. , (Period && Period!="On") ? Abs(Period) : (Period := 250)
  2342. , PTR,tmr.CBA,"PTR")) ;Create Timer and return true if a timer was created
  2343. , tmr.Tick:=A_TickCount
  2344. }
  2345. tmr := Object(A_EventInfo) ;A_Event holds object which contains timer information
  2346. If IsObject(tmr) {
  2347. DllCall("KillTimer", PTR,0, PTR,tmr.tmr) ;deactivate timer so it does not run again while we are processing the function
  2348. If (current && tmr.Priority<current.priority) ;Timer with higher priority is already current so return
  2349. Return (tmr.tmr:=DllCall("SetTimer", PTR,0, PTR,0, UInt, 100, PTR,tmr.CBA,"PTR")) ;call timer again asap
  2350. current:=tmr
  2351. ,tmr.tick:=ErrorLevel :=Priority ;update tick to launch function on time
  2352. ,tmr.func(tmr.params*) ;call function
  2353. If (tmr.OneTime) ;One time timer, deactivate and delete it
  2354. Return DllCall("GlobalFree", PTR,tmr.CBA)
  2355. ,tmrs.Remove(tmr.func)
  2356. tmr.tmr:= DllCall("SetTimer", PTR,0, PTR,0, UInt ;reset timer
  2357. ,((A_TickCount-tmr.Tick) > tmr.Period) ? 0 : (tmr.Period-(A_TickCount-tmr.Tick)), PTR,tmr.CBA,"PTR")
  2358. current= ;reset timer
  2359. }
  2360. }
  2361.  
  2362.  
  2363. ;-------------------------------------------------------------------------------------------------------------
  2364. ;---------------------------------------- Decryption Functions -------------------------------------
  2365. ;-------------------------------------------------------------------------------------------------------------
  2366.  
  2367. Decrypt(T,key) ; Text, key-name
  2368. {
  2369. Local p, i, L, u, v, k5, a, c
  2370.  
  2371. StringLeft p, T, 8
  2372. If p is not xdigit ; if no IV: Error
  2373. {
  2374. ErrorLevel := 1
  2375. Return
  2376. }
  2377. StringTrimLeft T, T, 8 ; remove IV from text (no separator)
  2378. k5 = 0x%p% ; set new IV
  2379. p := 0 ; counter to be Encrypted
  2380. i := 9 ; pad-index, force restart
  2381. L := "" ; processed text
  2382. k0 := %key%0
  2383. k1 := %key%1
  2384. k2 := %key%2
  2385. k3 := %key%3
  2386. Loop % StrLen(T)
  2387. {
  2388. i++
  2389. IfGreater i,8, { ; all 9 pad values exhausted
  2390. u := p
  2391. v := k5 ; IV
  2392. p++ ; increment counter
  2393. TEA(u,v, k0,k1,k2,k3)
  2394. Stream9(u,v) ; 9 pads from Encrypted counter
  2395. i := 0
  2396. }
  2397. StringMid c, T, A_Index, 1
  2398. a := Asc(c)
  2399. if a between 32 and 126
  2400. { ; chars > 126 or < 31 unchanged
  2401. a -= s%i%
  2402. IfLess a, 32, SetEnv, a, % a+95
  2403. c := Chr(a)
  2404. }
  2405. L := L . c ; attach Encrypted character
  2406. }
  2407. Return L
  2408. }
  2409.  
  2410. TEA(ByRef y,ByRef z,k0,k1,k2,k3) ; (y,z) = 64-bit I/0 block
  2411. { ; (k0,k1,k2,k3) = 128-bit key
  2412. IntFormat := A_FormatInteger
  2413. SetFormat Integer, D ; needed for decimal indices
  2414. s := 0
  2415. d := 0x9E3779B9
  2416. Loop 32
  2417. {
  2418. k := "k" . s & 3 ; indexing the key
  2419. y := 0xFFFFFFFF & (y + ((z << 4 ^ z >> 5) + z ^ s + %k%))
  2420. s := 0xFFFFFFFF & (s + d) ; simulate 32 bit operations
  2421. k := "k" . s >> 11 & 3
  2422. z := 0xFFFFFFFF & (z + ((y << 4 ^ y >> 5) + y ^ s + %k%))
  2423. }
  2424. SetFormat Integer, %IntFormat%
  2425. y += 0
  2426. z += 0 ; Convert to original ineger format
  2427. }
  2428.  
  2429. Stream9(x,y) ; Convert 2 32-bit words to 9 pad values
  2430. { ; 0 <= s0, s1, ... s8 <= 94
  2431. Local z ; makes all s%i% global
  2432. s0 := Floor(x*0.000000022118911147) ; 95/2**32
  2433. Loop 8
  2434. {
  2435. z := (y << 25) + (x >> 7) & 0xFFFFFFFF
  2436. y := (x << 25) + (y >> 7) & 0xFFFFFFFF
  2437. x := z
  2438. s%A_Index% := Floor(x*0.000000022118911147)
  2439. }
  2440. }
  2441.  
  2442.  
  2443. ;-------------------------------------------------------------------------------------------------------------
  2444. ;------------------------------------ Registry Access Functions ----------------------------------
  2445. ;-------------------------------------------------------------------------------------------------------------
  2446.  
  2447. RegRead(RootKey, SubKey, ValueName = "", RegistryVersion="32")
  2448. { Global winVer
  2449. Log("RegRead - Reading from Registry : RootKey=" . RootKey . ", SubKey=" . SubKey . ", ValueName=" . ValueName . ",RegistryVersion=" . RegistryVersion, 4)
  2450. If (RegistryVersion = "Auto") ;Try finding the correct registry reading based on the windows version
  2451. {
  2452. If (winVer = "64")
  2453. If !OutputVar := RegRead(RootKey, SubKey, ValueName, "64")
  2454. OutputVar := RegRead(RootKey, SubKey, ValueName, "32")
  2455. Else
  2456. OutputVar := RegRead(RootKey, SubKey, ValueName)
  2457. }
  2458. Else If (RegistryVersion = "32")
  2459. RegRead, OutputVar, %RootKey%, %SubKey%, %ValueName%
  2460. Else
  2461. OutputVar := RegRead64(RootKey, SubKey, ValueName)
  2462. Log("RegRead - Registry Read finished, returning " . OutputVar, 4)
  2463. Return OutputVar
  2464. }
  2465.  
  2466. RegWrite(ValueType, RootKey, SubKey, ValueName = "", Value = "", RegistryVersion="32")
  2467. {
  2468. Log("RegWrite - Writing to Registry : RootKey=" . RootKey . ", SubKey=" . SubKey . ", ValueName=" . ValueName . ",Value=" . Value . ",ValueType=" . ValueType . ",RegistryVersion=" . RegistryVersion, 4)
  2469. If (RegistryVersion = "32")
  2470. RegWrite, %ValueType%, %RootKey%, %SubKey%, %ValueName%, %Value%
  2471. Else
  2472. RegWrite64(ValueType, RootKey, SubKey, ValueName, Value)
  2473. Log("RegWrite - Registry Write finished", 4)
  2474. }
  2475.  
  2476. ;-------------------------------------------------------------------------------------------------------------
  2477. ;----------------------------------------- Display Resolution Functions ----------------------------------------
  2478. ;-------------------------------------------------------------------------------------------------------------
  2479.  
  2480. ; Grab current display settings for each monitor
  2481. ; Returns object:
  2482. ; obj[#] = Display Number
  2483. ; obj[#].Name = Display's Name as known in windows. Ex: \\.\DISPLAY1
  2484. ; obj[#].Width = Display's Width
  2485. ; obj[#].Height = Display's Height
  2486. ; obj[#].BitDepth = Display's BitDepth
  2487. ; obj[#].Frequency = Display's Frequency
  2488. ; obj[#].Orientation = Display's Orientation
  2489. ; obj[#].Left = Where this display's Left position starts
  2490. ; obj[#].Right = Where this display's Right position ends
  2491. ; obj[#].Top = Where this display's Top position starts
  2492. ; obj[#].Bottom = Where this display's Bottom position ends
  2493. ; obj[#].WorkingWidth = Display's Working Width. This is the usable space w/o the task bar
  2494. ; obj[#].WorkingHeight = Display's Working Height
  2495. GetDisplaySettings() {
  2496. Global RLObject
  2497. obj := Object()
  2498. monOrientation := Object(0,"Landscape",1,"Portrait",2,"Landscape (Flipped)",3,"Portrait (Flipped)")
  2499. getDisplaySettingsObj := Object(1,"Width",2,"Height",3,"BitDepth",4,"Frequency",5,"Orientation")
  2500. SysGet, MonitorCount, 80 ; MonitorCount
  2501. SysGet, MonitorPrimary, MonitorPrimary
  2502. Loop, %MonitorCount% ; get each monitor's stats for the log
  2503. {
  2504. SysGet, MonitorName, MonitorName, %A_Index%
  2505. SysGet, Monitor, Monitor, %A_Index%
  2506. SysGet, MonitorWorkArea, MonitorWorkArea, %A_Index%
  2507. currentobj:={}
  2508. currentobj.Number := A_Index ; this is the monitor #, an integer
  2509. currentobj.Name := MonitorName ; store monitor's name as it is known as in Windows
  2510. 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"
  2511. Loop, Parse, monDetails, |
  2512. currentObj[getDisplaySettingsObj[A_Index]] := A_LoopField ; parse RLObject's return and store into the object
  2513. currentobj.Orientation := monOrientation[currentobj.Orientation] ; replace orientation integer with name from object instead
  2514. currentobj.Left := MonitorLeft ; store where this monitor's Left position starts
  2515. currentobj.Right := MonitorRight ; store where this monitor's Right position ends
  2516. currentobj.Top := MonitorTop ; store where this monitor's Top position starts
  2517. currentobj.Bottom := MonitorBottom ; store where this monitor's Bottom position ends
  2518. currentobj.WorkingWidth := MonitorWorkAreaRight - MonitorWorkAreaLeft ; store this monitor's working width
  2519. currentobj.WorkingHeight := MonitorWorkAreaBottom - MonitorWorkAreaTop ; store this monitor's working height
  2520. obj.Insert(currentobj["Number"], currentobj)
  2521. 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)
  2522. }
  2523. Return obj
  2524. }
  2525.  
  2526. ; This function will take the | delimited user settings from theses places:
  2527. ; 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
  2528. ; B) Module when called to change the display setting(s)
  2529. ; It supports multiple monitors and parameters for each
  2530. ; array = | delimted string in this order where each monitor is delimted by ; monNumber|monWidth|monHeight|monBitDepth|monFrequency
  2531. ; Example = 1|1600|1200|32|60&2|1024|768|32|60
  2532. ConvertToMonitorObject(array) {
  2533. Global monitorTable
  2534. displaySettingsObj := Object(1,"Name",2,"Width",3,"Height",4,"BitDepth",5,"Frequency")
  2535. obj := Object()
  2536. Loop, Parse, array, &
  2537. {
  2538. currentobj:={}
  2539. currentobj.Number := A_Index ; this is the monitor #, an integer
  2540. Loop, Parse, A_LoopField, |
  2541. {
  2542. If !A_LoopField {
  2543. Log("ConvertToMonitorObject - " . displaySettingsObj[A_Index] . " not supplied in array. Object creation terminated.",3)
  2544. Return
  2545. }
  2546. currentobj[displaySettingsObj[A_Index]] := If displaySettingsObj[A_Index] = "Name" && !InStr(A_LoopField,"DISPLAY") ? "\\.\DISPLAY" . A_LoopField : A_LoopField
  2547. }
  2548. obj.Insert(currentobj["Number"], currentobj)
  2549. }
  2550. Return obj
  2551. }
  2552.  
  2553. ; Handle the supplied object by first checking if parameters are supported by the monitor, then setting them.
  2554. ; This is the function that will be called in features and modules to change display settings.
  2555. SetDisplaySettings(monObj) {
  2556. Global monitorTable
  2557. Log("SetDisplaySettings - Started")
  2558. currentMon := GetDisplaySettings() ; get current parameters to see if res needs to be changed or it can be skipped
  2559. Loop % monObj.MaxIndex()
  2560. {
  2561. ; 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
  2562. x := CheckDisplaySettings(monObj[A_Index].Name,monObj[A_Index].Width,monObj[A_Index].Height,monObj[A_Index].BitDepth,monObj[A_Index].Frequency)
  2563. If x {
  2564. 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)) {
  2565. 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")
  2566. } Else {
  2567. 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")
  2568. ChangeDisplaySettings(monObj[A_Index].Name,monObj[A_Index].Width,monObj[A_Index].Height,monObj[A_Index].BitDepth,monObj[A_Index].Frequency)
  2569. ; Update monitorTable with new settings so it stays current
  2570. SysGet, Monitor, Monitor, %A_Index%
  2571. SysGet, MonitorWorkArea, MonitorWorkArea, %A_Index%
  2572. monitorTable[A_Index].Width := monObj[A_Index].Width
  2573. monitorTable[A_Index].Height := monObj[A_Index].Height
  2574. monitorTable[A_Index].BitDepth := monObj[A_Index].BitDepth
  2575. monitorTable[A_Index].Frequency := monObj[A_Index].Frequency
  2576. monitorTable[A_Index].Left := MonitorLeft
  2577. monitorTable[A_Index].Right := MonitorRight
  2578. monitorTable[A_Index].Top := MonitorTop
  2579. monitorTable[A_Index].Bottom := MonitorBottom
  2580. monitorTable[A_Index].WorkingWidth := MonitorWorkAreaRight - MonitorWorkAreaLeft
  2581. monitorTable[A_Index].WorkingHeight := MonitorWorkAreaBottom - MonitorWorkAreaTop
  2582. }
  2583. } Else
  2584. 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)
  2585. }
  2586. Log("SetDisplaySettings - Ended")
  2587. }
  2588.  
  2589. ; Change screen resolution to supplied parameters
  2590. ; Do not call this function directly, allow SetDisplaySettings to handle it
  2591. ; n = Display Name
  2592. ; w = Screen Width
  2593. ; h = Screen Height
  2594. ; b = Bit Depth
  2595. ; f = Frequency
  2596. ChangeDisplaySettings(n,w,h,b,f) {
  2597. Global RLObject
  2598. Return RL_changeDisplaySettings(n,w,h,b,f)
  2599. }
  2600.  
  2601. ; Check monitor if it can support the screen parameters supplied
  2602. ; Do not call this function directly, allow SetDisplaySettings to handle it
  2603. ; Use this before calling ChangeDisplaySettings
  2604. ; n = Display Name
  2605. ; w = Screen Width
  2606. ; h = Screen Height
  2607. ; b = Bit Depth
  2608. ; f = Frequency
  2609. CheckDisplaySettings(n,w,h,b,f) {
  2610. Global RLObject
  2611. Return RL_checkDisplaySettings(n,w,h,b,f)
  2612. }
  2613.  
  2614. ; http://www.autohotkey.com/forum/topic8355.html
  2615. ; ChangeDisplaySettings( sW, sH, cD, rR ) { ; Change Screen Resolution
  2616. ; VarSetCapacity(dM,156,0), NumPut(156,dM,36)
  2617. ; DllCall( "EnumDisplaySettingsA", UInt,0, UInt,-1, UInt,&dM ), NumPut(0x5c0000,dM,40)
  2618. ; NumPut(cD,dM,104), NumPut(sW,dM,108), NumPut(sH,dM,112), NumPut(rR,dM,120)
  2619. ; Return DllCall( "ChangeDisplaySettingsA", UInt,&dM, UInt,0 )
  2620. ; }
  2621.  
  2622. ; Acquire display "index" screen resolution (index=0,1,...)
  2623. ; GetDisplaySettings(Index) {
  2624. ; VarSetCapacity(device_mode,156,0)
  2625. ; success:=DllCall("EnumDisplaySettings","uint",0,"uint",Index-1,"uint",&device_mode)
  2626. ; If (ErrorLevel or !success)
  2627. ; Return "Break"
  2628. ; Out_1:=NumGet(&device_mode,108,"uint4") ;width
  2629. ; Out_2:=NumGet(&device_mode,112,"uint4") ;height
  2630. ; Out_3:=NumGet(&device_mode,104,"uint4") ;quality
  2631. ; Out_4:=NumGet(&device_mode,120,"uint4") ;frequency
  2632. ; Return Out_1 "|" Out_2 "|" Out_3 "|" Out_4
  2633. ; } ; out "Break"
  2634.  
  2635. ; Acquire current display screen resolution (1=width 2=height 3=quality 4=frequency)
  2636. ; CurrentDisplaySettings(in=0) {
  2637. ; VarSetCapacity(device_mode,156,0),NumPut(156,2,&device_mode,36)
  2638. ; success := DllCall("EnumDisplaySettings","uint",0,"uint",-1,"uint",&device_mode)
  2639. ; Out_1:=NumGet(&device_mode,108,"uint4") ;width
  2640. ; Out_2:=NumGet(&device_mode,112,"uint4") ;height
  2641. ; Out_3:=NumGet(&device_mode,104,"uint4") ;quality
  2642. ; Out_4:=NumGet(&device_mode,120,"uint4") ;frequency
  2643. ; If in = 0
  2644. ; Return Out_1 "|" Out_2 "|" Out_3 "|" Out_4
  2645. ; Else Return (Out_%in%)
  2646. ; }
  2647.  
  2648. ; Check if a given screen resolution is supported by the monitor, and if not, choose the nearest one that is
  2649. ; desiredResTable uses the object defined by ConvertToMonitorObject
  2650. CheckForNearestSupportedRes(monNumber,desiredResTable){
  2651. Log("CheckForNearestSupportedRes - Started")
  2652. If !desiredResTable {
  2653. Log("CheckForNearestSupportedRes - Supplied desired resolution does not contain any data.",3)
  2654. Return
  2655. }
  2656. listOfSupportedRes := EnumDisplaySettings(monNumber)
  2657. If !listOfSupportedRes
  2658. { Log("CheckForNearestSupportedRes - Ended, was supplied a monitor number that is not attached to this system: " . monNumber,3)
  2659. Return
  2660. }
  2661. If RegExMatch(listOfSupportedRes, "i)" desiredResTable[monNumber].Width . "\|" . desiredResTable[monNumber].Height . "\|" . desiredResTable[monNumber].BitDepth . "\|" . desiredResTable[monNumber].Frequency)
  2662. { Log("CheckForNearestSupportedRes - Ended, this resolution is already supported by this display: " . desiredResTable[monNumber].Width . "|" . desiredResTable[monNumber].Height . "|" . desiredResTable[monNumber].BitDepth . "|" . desiredResTable[monNumber].Frequency,4)
  2663. Return desiredResTable
  2664. }
  2665. Log("CheckForNearestSupportedRes - This resolution is not directly supported by your monitor, finding the closest match.",4)
  2666. SupportedResObj := {}
  2667. nearestSupportedRes := {}
  2668. Loop, Parse, listOfSupportedRes, `,
  2669. {
  2670. currentRes := A_Index
  2671. SupportedResObj[currentRes] := {}
  2672. StringSplit,curRes,A_LoopField,|
  2673. SupportedResObj[currentRes].Width := curRes1
  2674. SupportedResObj[currentRes].Height := curRes2
  2675. SupportedResObj[currentRes].BitDepth := curRes3
  2676. SupportedResObj[currentRes].Frequency := curRes4
  2677. SupportedResObj[currentRes]["Distance"] := {}
  2678. SupportedResObj[currentRes]["Distance"].Width := SupportedResObj[currentRes].Width - desiredResTable[monNumber].Width
  2679. SupportedResObj[currentRes]["Distance"].Height := SupportedResObj[currentRes].Height - desiredResTable[monNumber].Height
  2680. SupportedResObj[currentRes]["Distance"].BitDepth := SupportedResObj[currentRes].BitDepth - desiredResTable[monNumber].BitDepth
  2681. SupportedResObj[currentRes]["Distance"].Frequency := SupportedResObj[currentRes].Frequency - desiredResTable[monNumber].Frequency
  2682. }
  2683. previousDeviation := 10**9
  2684. Loop, %currentRes%
  2685. {
  2686. 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
  2687. If (currentDeviation < previousDeviation) {
  2688. previousDeviation := currentDeviation
  2689. nearestSupportedRes.Width := SupportedResObj[A_Index].Width
  2690. nearestSupportedRes.Height := SupportedResObj[A_Index].Height
  2691. nearestSupportedRes.BitDepth := SupportedResObj[A_Index].BitDepth
  2692. nearestSupportedRes.Frequency := SupportedResObj[A_Index].Frequency
  2693. }
  2694. }
  2695. supportedRes := ConvertToMonitorObject(monNumber . "|" . nearestSupportedRes.Width . "|" . nearestSupportedRes.Height . "|" . nearestSupportedRes.BitDepth . "|" nearestSupportedRes.Frequency) ; convert to object
  2696. Log("CheckForNearestSupportedRes - Ended, closest match found is: " . supportedRes[monNumber].Width . "|" . supportedRes[monNumber].Height . "|" . supportedRes[monNumber].BitDepth . "|" supportedRes[monNumber].Frequency,4)
  2697. Return supportedRes
  2698. }
  2699.  
  2700. ; Enumerate Supported Screen Resolutions
  2701. ; display = the number of the monitor to enumerate supported resolutions for. 1 = Display 1, 2 = display 2, etc
  2702. ; Returns | delimited list of all supported settings
  2703. EnumDisplaySettings(display) {
  2704. VarSetCapacity(DM,156,0), NumPut(156,&DM,36, "UShort")
  2705. DllCall( "EnumDisplaySettings", str,"\\.\DISPLAY" Display, UInt,-1, UInt,&DM )
  2706. CS:=NumGet(DM,108) "|" NumGet(DM,112) "|" NumGet(DM,104) "|" NumGet(DM,120)
  2707. Loop
  2708. If DllCall( "EnumDisplaySettings", str,"\\.\DISPLAY" Display, UInt,A_Index-1, UInt,&DM )
  2709. { EDS:=NumGet(DM,108) "|" NumGet(DM,112) "|" NumGet(DM,104) "|" NumGet(DM,120)
  2710. DS.=(!InStr(DS,EDS) ? "," EDS : "")
  2711. } Else
  2712. Break
  2713. StringReplace, DS, DS, %CS%|, %CS%||, All
  2714. Return SubStr(DS,2)
  2715. }
  2716.  
  2717. OptionScale(ByRef option, scale){ ;selects portrait specifc option value if needed and scales variable to adjust to screen resolution
  2718. Global screenRotationAngle
  2719. If InStr(option,"|")
  2720. {
  2721. StringSplit, opt, option, |
  2722. If ((opt2) and (((A_screenWidth < A_screenHeight) and ((screenRotationAngle=0) or (screenRotationAngle=180))) or ((A_screenWidth > A_screenHeight) and ((screenRotationAngle=90) or (screenRotationAngle=270)))))
  2723. option := If (SubStr(opt2, 0)="p") ? opt2 : round(opt2 * scale)
  2724. Else
  2725. option := If (SubStr(opt1, 0)="p") ? opt1 : round(opt1 * scale)
  2726. } Else
  2727. option := If (SubStr(option, 0)="p") ? option : round(option * scale)
  2728. }
  2729.  
  2730.  
  2731.  
  2732. TextOptionScale(ByRef Option,XScale, YScale){
  2733. RegExMatch(Option, "i)X([\-\d\.]+)(p*)\|([\-\d\.]+)(p*)|X([\-\d\.]+)(p*)", xpos)
  2734. RegExMatch(Option, "i)Y([\-\d\.]+)(p*)\|([\-\d\.]+)(p*)|Y([\-\d\.]+)(p*)", ypos)
  2735. RegExMatch(Option, "i)W([\-\d\.]+)(p*)\|([\-\d\.]+)(p*)|W([\-\d\.]+)(p*)", Width)
  2736. RegExMatch(Option, "i)H([\-\d\.]+)(p*)\|([\-\d\.]+)(p*)|H([\-\d\.]+)(p*)", Height)
  2737. RegExMatch(Option, "i)S([\-\d\.]+)(p*)\|([\-\d\.]+)(p*)|S([\-\d\.]+)", Size)
  2738. xposValue := SubStr(xpos, 2), yposValue := SubStr(ypos, 2), WidthValue := SubStr(Width, 2), HeightValue := SubStr(Height, 2), SizeValue := SubStr(Size, 2)
  2739. OptionScale(xposValue, XScale)
  2740. OptionScale(yposValue, YScale)
  2741. OptionScale(WidthValue, XScale)
  2742. OptionScale(HeightValue, YScale)
  2743. OptionScale(SizeValue, YScale)
  2744. Option := RegExReplace(Option, "i)X([\-\d\.]+)(p*)\|([\-\d\.]+)(p*)|X([\-\d\.]+)(p*)", "x" . xposValue)
  2745. Option := RegExReplace(Option, "i)Y([\-\d\.]+)(p*)\|([\-\d\.]+)(p*)|Y([\-\d\.]+)(p*)", "y" . yposValue)
  2746. Option := RegExReplace(Option, "i)W([\-\d\.]+)(p*)\|([\-\d\.]+)(p*)|W([\-\d\.]+)(p*)", "w" . WidthValue)
  2747. Option := RegExReplace(Option, "i)H([\-\d\.]+)(p*)\|([\-\d\.]+)(p*)|H([\-\d\.]+)(p*)", "h" . HeightValue)
  2748. Option := RegExReplace(Option, "i)S([\-\d\.]+)(p*)\|([\-\d\.]+)(p*)|S([\-\d\.]+)", "s" . SizeValue)
  2749. }
  2750.  
  2751. ;-------------------------------------------------------------------------------------------------------------
  2752. ;---------------------------- Open And Close Process Functions ----------------------------
  2753. ;-------------------------------------------------------------------------------------------------------------
  2754.  
  2755. ProcSus(PID_or_Name) {
  2756. Log("ProcSus - Started",4)
  2757. If InStr(PID_or_Name, ".") {
  2758. Process, Exist, %PID_or_Name%
  2759. PID_or_Name := ErrorLevel
  2760. }
  2761. If !(h := DllCall("OpenProcess", "uInt", 0x1F0FFF, "Int", 0, "Int", PID_or_Name)) {
  2762. Log("ProcSus - Ended, process """ . PID_or_Name . """ not found")
  2763. Return -1
  2764. }
  2765. Log("ProcSus - Suspending Process: " . PID_or_Name)
  2766. DllCall("ntdll.dll\NtSuspendProcess", "Int", h), DllCall("CloseHandle", "Int", h)
  2767. Log("ProcSus - Ended",4)
  2768. }
  2769.  
  2770. ProcRes(PID_or_Name) {
  2771. Log("ProcRes - Started",4)
  2772. If InStr(PID_or_Name, ".") {
  2773. Process, Exist, %PID_or_Name%
  2774. PID_or_Name := ErrorLevel
  2775. }
  2776. If !(h := DllCall("OpenProcess", "uInt", 0x1F0FFF, "Int", 0, "Int", PID_or_Name)) {
  2777. Log("ProcRes - Ended, process """ . PID_or_Name . """ not found")
  2778. Return -1
  2779. }
  2780. Log("ProcRes - Resuming Process: " . PID_or_Name)
  2781. DllCall("ntdll.dll\NtResumeProcess", "Int", h), DllCall("CloseHandle", "Int", h)
  2782. Log("ProcRes - Ended",4)
  2783. }
  2784.  
  2785. ;-------------------------------------------------------------------------------------------------------------
  2786. ;--------------------------------------- Validate IP Functions ---------------------------------------
  2787. ;-------------------------------------------------------------------------------------------------------------
  2788.  
  2789. ValidIP(a) {
  2790. Loop, Parse, a, .
  2791. {
  2792. If A_LoopField is digit
  2793. If A_LoopField between 0 and 255
  2794. e++
  2795. c++
  2796. }
  2797. Return, e = 4 AND c = 4
  2798. }
  2799.  
  2800. ValidPort(a) {
  2801. If a is digit
  2802. If a between 0 and 65535
  2803. e++
  2804. Return e
  2805. }
  2806.  
  2807. GetPublicIP() {
  2808. UrlDownloadToFile, http://www.rlauncher.com/ipcheck/myip.php, %A_Temp%\myip.txt
  2809. FileRead, extIP, %A_Temp%\myip.txt
  2810. Return extIP
  2811. }
  2812.  
  2813. GetLocalIP() {
  2814. array := []
  2815. objWMIService := ComObjGet("winmgmts:{impersonationLevel = impersonate}!\\.\root\cimv2")
  2816. colItems := objWMIService.ExecQuery("Select * from Win32_NetworkAdapterConfiguration WHERE IPEnabled = True")._NewEnum
  2817. while colItems[objItem]
  2818. {
  2819. array[A_Index,1] := objItem.Description[0]
  2820. array[A_Index,2] := objItem.IPAddress[0]
  2821. array[A_Index,3] := objItem.IPSubnet[0]
  2822. array[A_Index,4] := objItem.DefaultIPGateway[0]
  2823. array[A_Index,5] := objItem.DNSServerSearchOrder[0]
  2824. array[A_Index,6] := objItem.MACAddress[0]
  2825. array[A_Index,7] := objItem.DHCPEnabled[0]
  2826. }
  2827. Return array
  2828. }
  2829.  
  2830.  
  2831. ;-------------------------------------------------------------------------------------------------------------
  2832. ;------------------------------------------- Rotate Screen Functions -------------------------------------------
  2833. ;-------------------------------------------------------------------------------------------------------------
  2834.  
  2835. ; Options:
  2836. ; method = irotate, display, or shortcut
  2837. ; degrees = 0, 90, 180, 270
  2838.  
  2839. Rotate(method="irotate", degrees=0) {
  2840. Log("Rotate - Started")
  2841. Global moduleExtensionsPath
  2842. arrowKeys := { 0: "Up", 1: "Right", 2: "Down", 3: "Left" }
  2843. If !RegExMatch(method,"i)irotate|display|shortcut")
  2844. ScriptError("""" . method . """ is not a valid rotate method, Please choose either ""irotate"" or ""display""")
  2845. If !RegExMatch(degrees,"0|90|180|270")
  2846. ScriptError("""" . degrees . """ is not a valid degree to rotate to, Please choose either 0, 90, 180, or 270")
  2847. rotateExe := CheckFile(moduleExtensionsPath . "\" . method . ".exe") ; check If the exe to our RotateMethod method exists
  2848. If (method = "irotate") {
  2849. Log("Rotate - Rotating display using irotate.exe to " . degrees . " degrees",4)
  2850. Run(rotateExe . " /rotate=" degrees " /exit", moduleExtensionsPath)
  2851. } Else If (method = "display") {
  2852. Log("Rotate - Rotating display using display.exe to " . degrees . " degrees",4)
  2853. Run(rotateExe . " /rotate:" degrees, moduleExtensionsPath)
  2854. } Else If (method = "shortcut") {
  2855. Log("Rotate - Rotating display using shortcut keys to " . degrees . " degrees",4)
  2856. Send, % "{LControl Down}{LAlt Down}{" . arrowKeys[degrees // 90] . " Down}{LControl Up}{LAlt Up}{" . arrowKeys[degrees // 90] . " Up}"
  2857. }
  2858. Log("Rotate - Ended")
  2859. }
  2860.  
  2861.  
  2862. ;-------------------------------------------------------------------------------------------------------------
  2863. ;-------------------------------------------- Database Asset Building ------------------------------------------
  2864. ;-------------------------------------------------------------------------------------------------------------
  2865.  
  2866. ; Builds an object filled with the FE's assets
  2867. BuildAssetsTable(list,label,AssetType,extensions="",obj=""){
  2868. Log("BuildAssetsTable - Started - Building Table for: " . label,4)
  2869. Global logLevel
  2870. StringReplace, extensionsReplaced, extensions, |, `,,All
  2871. If !(obj)
  2872. obj := {}
  2873. StringSplit, labelArray, label, |,
  2874. StringSplit, AssetTypeArray, AssetType, |,
  2875. Loop, Parse, list,|
  2876. { If !(labelArray%A_Index% = "#disabled#")
  2877. {
  2878. Log("BuildAssetsTable - Searching for a " . labelArray%A_Index% . ": " . A_LoopField,4)
  2879. currentLabel := labelArray%A_Index%
  2880. currentAssetType := AssetTypeArray%A_index%
  2881. RASHNDOCT := FileExist(A_LoopField)
  2882. If InStr(RASHNDOCT, "D") { ; it is a folder
  2883. folderName := A_LoopFileName
  2884. Loop, % A_LoopField . "\*.*"
  2885. { If RegExMatch(extensions,"i)" . A_LoopFileExt)
  2886. { currentobj := {}
  2887. If (currentLabel="keepFileName")
  2888. currentobj["Label"] := folderName
  2889. Else
  2890. currentobj["Label"] := currentLabel
  2891. If obj[currentLabel].Label
  2892. { currentobj := obj[currentLabel]
  2893. currentobj.TotalItems := currentobj.TotalItems+1
  2894. } Else {
  2895. currentobj.TotalItems := 1
  2896. obj.TotalLabels := if obj.TotalLabels ? obj.TotalLabels + 1 : 1
  2897. obj[obj.TotalLabels] := currentobj.Label
  2898. }
  2899. currentobj["Path" . currentobj.TotalItems] := A_LoopFileLongPath
  2900. currentobj["Ext" . currentobj.TotalItems] := A_LoopFileExt
  2901. currentobj["AssetType"] := currentAssetType
  2902. currentobj["Type"] := "ImageGroup"
  2903. obj.Insert(currentobj["Label"], currentobj)
  2904. }
  2905. }
  2906. } Else If InStr(RASHNDOCT, "A") { ; it is a file
  2907. SplitPath, A_LoopField, , currentDir,, FileNameWithoutExtension
  2908. Loop, Parse, extensionsReplaced,`,
  2909. {
  2910. If FileExist(currentDir . "\" . FileNameWithoutExtension . "." . A_LoopField)
  2911. { currentobj := {}
  2912. If (currentLabel="keepFileName")
  2913. currentobj["Label"] := FileNameWithoutExtension
  2914. Else
  2915. currentobj["Label"] := currentLabel
  2916. If obj[FileNameWithoutExtension].Label
  2917. { currentobj := obj[FileNameWithoutExtension]
  2918. currentobj.TotalItems := currentobj.TotalItems+1
  2919. } Else {
  2920. currentobj.TotalItems := 1
  2921. obj.TotalLabels := if obj.TotalLabels ? obj.TotalLabels + 1 : 1
  2922. obj[obj.TotalLabels] := currentobj.Label
  2923. }
  2924. currentobj["Path" . currentobj.TotalItems] := currentDir . "\" . FileNameWithoutExtension . "." . A_LoopField
  2925. currentobj["Ext" . currentobj.TotalItems] := A_LoopField
  2926. currentobj["AssetType"] := currentAssetType
  2927. obj.Insert(currentobj["Label"], currentobj)
  2928. }
  2929. }
  2930. }
  2931. } Else
  2932. Log("BuildAssetsTable - This asset has been disabled: " . labelArray%A_Index%,4)
  2933.  
  2934. }
  2935. If (logLevel>=5){
  2936. for index, element in obj
  2937. { Loop, % obj[element.Label].TotalItems
  2938. 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"]
  2939. }
  2940. If mediaAssetsLog
  2941. Log("BuildAssetsTable - Media assets found: " . mediaAssetsLog,5)
  2942. }
  2943. Log("BuildAssetsTable - Ended",4)
  2944. Return obj
  2945. }
  2946.  
  2947. BuildAssetsTableOld(list,label,AssetType,extensions=""){
  2948. Log("BuildAssetsTable - Started - Building Table for: " . label,4)
  2949. Global logLevel
  2950. StringReplace, extensionsReplaced, extensions, |, `,,All
  2951. obj:={}
  2952. StringSplit, labelArray, label, |,
  2953. StringSplit, AssetTypeArray, AssetType, |,
  2954. Loop, Parse, list,|
  2955. { labelIndex++
  2956. If !(labelArray%labelIndex% = "#disabled#")
  2957. {
  2958. Log("BuildAssetsTable - Searching for a " . labelArray%labelIndex% . ": " . A_LoopField,4)
  2959. currentLabel := labelArray%labelIndex%
  2960. currentAssetType := AssetTypeArray%A_index%
  2961. RASHNDOCT := FileExist(A_LoopField)
  2962. If InStr(RASHNDOCT, "D") { ; it is a folder
  2963. folderName := A_LoopFileName
  2964. Loop, % A_LoopField . "\*.*"
  2965. { If RegExMatch(extensions,"i)" . A_LoopFileExt)
  2966. { currentobj := {}
  2967. If (currentLabel="keepFileName")
  2968. currentobj["Label"] := folderName
  2969. Else
  2970. currentobj["Label"] := currentLabel
  2971. If obj[currentLabel].Label
  2972. { currentobj := obj[currentLabel]
  2973. currentobj.TotalItems := currentobj.TotalItems+1
  2974. } Else {
  2975. currentobj.TotalItems := 1
  2976. obj.TotalLabels := if obj.TotalLabels ? obj.TotalLabels + 1 : 1
  2977. obj[obj.TotalLabels] := currentobj.Label
  2978. }
  2979. currentobj["Path" . currentobj.TotalItems] := A_LoopFileLongPath
  2980. currentobj["Ext" . currentobj.TotalItems] := A_LoopFileExt
  2981. currentobj["AssetType"] := currentAssetType
  2982. currentobj["Type"] := "ImageGroup"
  2983. obj.Insert(currentobj["Label"], currentobj)
  2984. }
  2985. }
  2986. } Else If InStr(RASHNDOCT, "A") { ; it is a file
  2987. SplitPath, A_LoopField, , currentDir,, FileNameWithoutExtension
  2988. Loop, Parse, extensionsReplaced,`,
  2989. {
  2990. If (InStr(extensionsReplaced , ",") && A_Index >= 2) {
  2991. labelIndex++ ; need to advance the label by one each time a new extension is used
  2992. currentLabel := labelArray%labelIndex%
  2993. }
  2994. If FileExist(currentDir . "\" . FileNameWithoutExtension . "." . A_LoopField)
  2995. { currentobj := {}
  2996. If (currentLabel="keepFileName")
  2997. currentobj["Label"] := FileNameWithoutExtension
  2998. Else
  2999. currentobj["Label"] := currentLabel
  3000. If obj[FileNameWithoutExtension].Label
  3001. { currentobj := obj[FileNameWithoutExtension]
  3002. currentobj.TotalItems := currentobj.TotalItems+1
  3003. } Else {
  3004. currentobj.TotalItems := 1
  3005. obj.TotalLabels := if obj.TotalLabels ? obj.TotalLabels + 1 : 1
  3006. obj[obj.TotalLabels] := currentobj.Label
  3007. }
  3008. currentobj["Path" . currentobj.TotalItems] := currentDir . "\" . FileNameWithoutExtension . "." . A_LoopField
  3009. currentobj["Ext" . currentobj.TotalItems] := A_LoopField
  3010. currentobj["AssetType"] := currentAssetType
  3011. obj.Insert(currentobj["Label"], currentobj)
  3012. }
  3013. }
  3014. }
  3015. } Else
  3016. Log("BuildAssetsTable - This asset has been disabled: " . labelArray%labelIndex%,4)
  3017.  
  3018. }
  3019. If (logLevel>=5){
  3020. for index, element in obj
  3021. { Loop, % obj[element.Label].TotalItems
  3022. 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"]
  3023. }
  3024. If mediaAssetsLog
  3025. Log("BuildAssetsTable - Media assets found: " . mediaAssetsLog,5)
  3026. }
  3027. Log("BuildAssetsTable - Ended",4)
  3028. Return obj
  3029. }
  3030.  
  3031.  
  3032. ;-------------------------------------------------------------------------------------------------------------
  3033. ;-------------------------------------- Broadcast and Message Receiving --------------------------------------
  3034. ;-------------------------------------------------------------------------------------------------------------
  3035. ReceiveMessage(wParam, lParam) ; receive messages from other programs
  3036. { Global Pause_Active, Pause_Running, systemName, gameInfo
  3037. ;Global ; it is necessary to use global if the var definition part is uncommented
  3038. StringAddress := NumGet(lParam + 8)
  3039. StringLength := DllCall("lstrlen", UInt, StringAddress)
  3040. If (StringLength <= 0)
  3041. Log("A blank string message was received by RocketLauncher or there was an error.")
  3042. Else
  3043. { VarSetCapacity(CopyOfData, StringLength)
  3044. DllCall("lstrcpy", "str", CopyOfData, "uint", StringAddress)
  3045. StringSplit, Data, CopyOfData, |
  3046. If (Data1)
  3047. {
  3048. If (Data1="command") { ; predefined commands
  3049. If (Data2="RLPause") {
  3050. If (Pause_Active){
  3051. Gosub, TogglePauseMenuStatus
  3052. Log("RocketLauncher received the windows message to unpause the game: " . Data2)
  3053. } Else If !(Pause_Running) {
  3054. Gosub, TogglePauseMenuStatus
  3055. Log("RocketLauncher received the windows message to pause the game: " . Data2)
  3056. }
  3057. } Else If (Data2="RLSelect") {
  3058. If (Pause_Active){
  3059. Gosub, ToggleItemSelectStatus
  3060. }
  3061. } Else If (Data2="RLUp") {
  3062. If (Pause_Active){
  3063. Gosub, MoveUp
  3064. }
  3065. } Else If (Data2="RLDown") {
  3066. If (Pause_Active){
  3067. Gosub, MoveDown
  3068. }
  3069. } Else If (Data2="RLLeft") {
  3070. If (Pause_Active){
  3071. Gosub, MoveLeft
  3072. }
  3073. } Else If (Data2="RLRight") {
  3074. If (Pause_Active){
  3075. Gosub, MoveRight
  3076. }
  3077. } Else If (Data2="RLExit") {
  3078. Gosub, CloseProcess
  3079. } Else {
  3080. Log("RocketLauncher received the windows message to run a inexistent command: " . Data2)
  3081. }
  3082. } Else If (Data1="ping") {
  3083. BroadcastMessage("RocketLauncher Message System is Available.")
  3084. } Else If (Data1="Which system?") {
  3085. BroadcastMessage("RocketLauncher Message. Current System: " . systemName)
  3086. } Else If (Data1="Which game?") {
  3087. BroadcastMessage("RocketLauncher Message. Current Game: " . gameInfo["Name"].Value)
  3088. }
  3089. /*} if (Data1="runlabel") {
  3090. if IsLabel(Data2) {
  3091. Log("RocketLauncher received the windows message to run the label: " . Data2)
  3092. gosub, %Data2%
  3093. } Else {
  3094. Log("RocketLauncher received the windows message to run a inexistent label: " . Data2)
  3095. }
  3096. } Else If (Data1="setvar") {
  3097. Log("RocketLauncher received the windows message to set the variable named " . Data2 . " to the value = " . Data3)
  3098. %Data2% := Data3
  3099. */
  3100. } Else
  3101. Log("RocketLauncher does not recognize the pure string message sent as a valid command: " . CopyOfData)
  3102. }
  3103. Return true
  3104. }
  3105.  
  3106. BroadcastMessage(StringToSend) {
  3107. Global broadcastWindowTitle
  3108. If broadcastWindowTitle {
  3109. VarSetCapacity(CopyDataStruct, 12, 0)
  3110. NumPut(StrLen(StringToSend) + 1, CopyDataStruct, 4)
  3111. NumPut(&StringToSend, CopyDataStruct, 8)
  3112. Prev_DetectHiddenWindows := A_DetectHiddenWindows
  3113. Prev_TitleMatchMode := A_TitleMatchMode
  3114. DetectHiddenWindows On
  3115. SetTitleMatchMode 2
  3116. ; If (BroadcastWindowTitle="All"){
  3117. ; Log("BroadcastMessage - Sending message """ . StringToSend . """ to all windows.")
  3118. ; SendMessage, 0x4a, 0, &CopyDataStruct,, ahk_id 0xFFFF
  3119. If InStr(BroadcastWindowTitle, "|") {
  3120. Loop, Parse, BroadcastWindowTitle, |, %A_Space%
  3121. { Log("BroadcastMessage - Sending message """ . StringToSend . """ to " . A_LoopField . " window.")
  3122. SendMessage, 0x4a, 0, &CopyDataStruct,, % BroadcastWindowTitle
  3123. }
  3124. } Else If (BroadcastWindowTitle){
  3125. If (WinExist(BroadcastWindowTitle) != "0x0") {
  3126. Log("BroadcastMessage - Sending message """ . StringToSend . """ to " . BroadcastWindowTitle . " window.")
  3127. SendMessage, 0x4a, 0, &CopyDataStruct,, % BroadcastWindowTitle
  3128. } Else
  3129. Log("BroadcastMessage - Could not broadcast message """ . StringToSend . """ to " . BroadcastWindowTitle . " because the window could not be found.",2)
  3130. } Else
  3131. Log("Message was not broadcasted because the lack of a valid window target.",4)
  3132. DetectHiddenWindows %Prev_DetectHiddenWindows%
  3133. SetTitleMatchMode %Prev_TitleMatchMode%
  3134. Return ErrorLevel ; Return SendMessage's reply back to our caller.
  3135. }
  3136. }
  3137.  
  3138.  
  3139. ;-------------------------------------------------------------------------------------------------------------
  3140. ;----------------------------------------- Split Screen Module Support ------------------------------------------
  3141. ;-------------------------------------------------------------------------------------------------------------
  3142.  
  3143. ; SplitScreenPos function
  3144. ; 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.
  3145. ; Supports up to 8 screens
  3146. ; splitScreen2PlayersMode can be Vertical or Horizontal
  3147. ; splitScreen3PlayersMode can be P1top, P1left, P1right, P1bottom
  3148. ; 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
  3149. SplitScreenPos(numberofPlayers,splitScreen2PlayersMode="Horizontal",splitScreen3PlayersMode="P1top",maxPlayersPerMonitor="4|4|4"){
  3150. Global monitorTable
  3151. Log("SplitScreenPos - Started")
  3152. ;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
  3153. monitor := []
  3154. StringSplit,playerPerMonitor,maxPlayersPerMonitor,|
  3155. Loop, % monitorTable.MaxIndex()
  3156. { monitor[a_index] := {}
  3157. currentNumberOfPlayers := playerPerMonitor%a_index%
  3158. accumulatedPlayers += currentNumberOfPlayers
  3159. If (accumulatedPlayers>numberofPlayers)
  3160. currentNumberOfPlayers := numberofPlayers - (accumulatedPlayers-currentNumberOfPlayers)
  3161. monitor[a_index].numberOfPlayers := currentNumberOfPlayers
  3162. }
  3163. If (accumulatedPlayers<numberofPlayers){
  3164. Loop, % (numberofPlayers-accumulatedPlayers)
  3165. { count1++
  3166. If ( count1 > monitorTable.MaxIndex() )
  3167. count1 := 1
  3168. monitor[count1].numberOfPlayers += 1
  3169. }
  3170. }
  3171. ;Defining splitscreen positions
  3172. posArray := []
  3173. Loop, % numberofPlayers
  3174. posArray[a_index] := {}
  3175. count := 0
  3176. Loop, % monitor.MaxIndex()
  3177. { currentMonitor := a_index
  3178. If (monitor[currentMonitor].numberOfPlayers = 1){
  3179. 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
  3180. } Else If (monitor[currentMonitor].numberOfPlayers = 2){
  3181. If (splitScreen2PlayersMode = "Vertical"){
  3182. 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
  3183. 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
  3184. } Else {
  3185. 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
  3186. 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
  3187. }
  3188. } Else If (monitor[currentMonitor].numberOfPlayers = 3){
  3189. If (splitScreen3PlayersMode = "P1left"){
  3190. 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
  3191. 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
  3192. 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
  3193. } Else If (splitScreen3PlayersMode = "P1bottom") {
  3194. 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
  3195. 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
  3196. 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
  3197. } Else If (splitScreen3PlayersMode = "P1right") {
  3198. 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
  3199. 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
  3200. 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
  3201. } Else { ;top
  3202. 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
  3203. 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
  3204. 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
  3205. }
  3206. } Else If (monitor[currentMonitor].numberOfPlayers = 4){
  3207. 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
  3208. 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
  3209. 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
  3210. 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
  3211. } Else If (monitor[currentMonitor].numberOfPlayers = 5){
  3212. 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
  3213. 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
  3214. 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
  3215. 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
  3216. 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
  3217. } Else If (monitor[currentMonitor].numberOfPlayers = 6){
  3218. 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
  3219. 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
  3220. 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
  3221. 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
  3222. 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
  3223. 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
  3224. } Else If (monitor[currentMonitor].numberOfPlayers = 7){
  3225. 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
  3226. 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
  3227. 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
  3228. 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
  3229. 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
  3230. 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
  3231. 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
  3232. } Else If (monitor[currentMonitor].numberOfPlayers = 8){
  3233. 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
  3234. 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
  3235. 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
  3236. 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
  3237. 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
  3238. 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
  3239. 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
  3240. 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
  3241. } Else {
  3242. Log("SplitScreenPos - " . monitor[currentMonitor].numberOfPlayers . " is a nonsupported number of players for the split screen position calculation function.",2)
  3243. }
  3244. Loop, % monitor[currentMonitor].numberOfPlayers
  3245. 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)
  3246. count += monitor[currentMonitor].numberOfPlayers
  3247. If (count >= numberofPlayers)
  3248. Break
  3249. }
  3250. Log("SplitScreenPos - Ended")
  3251. Return posArray
  3252. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement