The application generates a MMOGO_Core.ini file which contains some default settings and is used to track what other profiles you have created and their names. You can edit this file and any other .ini files it generates or create your own, with any text editor.
The list of profiles is at the top of MMOGO_Core.ini, along with an entry for specifying which one to load automatically (if any).
Each profile .ini file can specify a “parent” Profile with a line like:
ParentProfile = MyBaseProfile
This system is intended to allow for having a “base” profile for a particular game, and then multiple profiles for different characters that use that same base for common settings. You can set up as long of a chain of parent profiles as you desire. The “Core” profile is always used as the ultimate parent of all profiles, and this does not need to be specified.
Profile .ini files are read in order from parent to child, and any duplicate properties are overwritten as they are encountered. That means the specific profile you are loading will take priority over its parent base, which itself will take priority over any parent it has, and all other files will take priority over “Core”.
All of this is set up automatically with the default example profiles generated on first launch.
You can edit MMOGO_Core.ini yourself to add more profiles, or use the menu option File->Profile from within the application to do so with a GUI.
Each profile .ini text file contains a list of Properties. Each property is identified by a property section and a property name with an associated property value.
If the same section+property name is encountered more than once, the most recent one will override any previous ones (which is what allows for profiles to override properties of their parent/core profile). However, the same property name can be used in more than one section and will be considered a different property. There is also a special unnamed “root” section at the top of each file before the first section label is encountered, where certain special properties like the aforementioned ParentProfile property go.
The .ini files are formatted as follows:
RootPropertyName = Property Value
[SectionName1]
PropertyName1 = Property Value 1
PropertyName2 = Property Value 2
# Comment type 1
[SectionName1.SubSectionA]
PropertyName1 = Property Value 1
PropertyName2 = Property Value 2
[SectionName2]
; Comment type 2
;PropertyName1 = Property Value 1 - commented out
PropertyName2 = Property Value 2
NOTE: Comments are only supported by placing # and ; at the beginning of a line. You can NOT add comments at the end of a line - it will instead be considered part of the Property Value. Also, spaces are allowed in property names, but they are ignored, as are differences is casing (i.e. Property Name 1 is treated as the same as PROPERTYNAME1).
This is the main section for determining how gamepad input is translated into keyboard and mouse input. With a couple of special exceptions, each property name in this section represents a gamepad button (and optionally an action associated with that button like press, tap, release, etc), and each property value represents a Command for the application to execute when that button is used.
Commands are usually input to send to the game, such as keyboard keys, mouse buttons, and mouse movement. For example, to assign R2 to act as the right mouse button, you could include:
[Scheme]
R2 = RMB
There are various ways supported of specifying gamepad buttons and keys, so you could instead use:
[Scheme]
RT = Right-click
If you want the full list, check Source\GlobalConstants.cpp in the source code.
When the property name is simply the button name by itself, like in the above examples, it is treated as the action “press and hold”. So in the earlier R2 = RMB example, the right mouse button will be pressed when R2 is first pressed, held for as long as R2 is held, and released when R2 is released.
Other “button actions” can be specified instead, and each button can have multiple commands assigned to it at once such as for a “tap” vs a “hold.” For example:
[Scheme]
R2 = A
Press R2 = B
Tap R2 = C
Release R2 = D
Hold R2 400 = E
This example demonstrates the maximum number of commands that could be assigned to a single button. When R2 is first pressed the ‘B’, and ‘A’ keyboard keys would be sent to the game in that order (’‘B’ would just be tapped and immediately released, but A’ would continue to be held down). If R2 was quickly released, a single tap of the ‘C’ key would be sent. If R2 was held for at least 400 milliseconds, an ‘E’ tap would be sent once. No matter how long it is held, even if just briefly tapped, once let go of R2 a single tap of ‘D’ would be sent to the game (as well as finally releasing ‘A’).
If no number is specified for the Hold action, the default value [System]/ButtonHoldTime will be used. This time is in milliseconds.
Notice how only the base R2= property can actually hold a key down for more than a split second, since that is the only action where your input can specify a duration (i.e. how long you hold the gamepad button down is how long to hold the key down).
You can assign 4 buttons at once in the case of the D-pad, analog sticks, and the “face buttons” (ABXY or X/Square/Triangle/Circle). For example:
[Scheme]
DPad = MoveTurn
LStick = MoveStrafe
RStick = Mouse
; Below treats face buttons like a D-pad
FPad = Move
Each of these (including the analog sticks) are otherwise treated as 4 separate buttons like “LStickUp” or “DPadDown”, etc. when want to assign each direction to a separate command.
Pro tip - note that non-directional commands become assigned to the directional input as a whole rather than each of the 4 individual directions when using this setup. For example, RStick=A will cause the keyboard ‘A’ key to be sent to the game when any direction is pressed on the right analog stick, with releasing ‘A’ being sent only once the right analog stick returns to center position. In other words, spinning the stick will NOT cause multiple ‘A’ key presses to be sent if you use RStick=A, but would be if you individually assigned RStickUp=A, RStickLeft=A, etc.
As mentioned above, commands assigned to buttons can be as simple as the name of a keyboard key or mouse button, as well as mouse movement (such as =Mouse Up or =Mouse Left).
Not mentioned yet is mouse wheel movement, which can be set with commands such as =MouseWheel Up Smooth or =MouseWheel Down Stepped or MouseWheel Down 1. “Smooth” vs “Stepped” affects whether or not movement of less than one ‘notch’ at a time is sent to the application (stepped is the default if unspecified). Specifying a number instead means only want the wheel to move one time (by the number of “notches” specified) even when the button assigned to the command is held continuously.
A command can also be a keyboard key or mouse button combined with a modifier key - Shift, Ctrl, Alt, or the Windows key - such as:
R2 = Shift+A
L2 = Ctrl X
L1 = Ctrl-Alt-R
R1 = Win-Plus
These can still be “held” as if they are single keys.
WARNING: Modifier keys should be used sparingly, as they can interfere with or delay other keys. For example, if you are holding Shift+A and then want to press just ‘X’, since the Shift key is still being held down, the game would normally interpret it as you pressing ‘Shift+X’, which may have a totally different meaning to the game. This application specifically avoids this by briefly releasing Shift before pressing X and then re-pressing Shift again as needed, but this can make the controls seem less responsive due to the delays needed to make sure each release and re-press are processed in the correct order. Consider re-mapping controls for the game to use Shift/Ctrl/Alt as little as possible for best results!
You can also specify a sequence of keys to be pressed. For example, you could have a single button press the sequence Shift+2 (let’s say to switch to hotbar #2), then 1 (to use hotbutton #1), then Shift+1 (to switch back to hotbar #1), like so:
R2 = Shift+2, 1, Shift+1
Key sequences can NOT be “held” so Press R2 and just plain R2 work the same way for them. They do not auto-repeat either by holding the button - you must release and re-press the button each time you want to execute the sequence.
You can also add pauses (specified in milliseconds) into the sequence if needed, such as this sequence to automatically “consider” a target when changing targets (assuming Tab cycles targets and C is for “consider”):
; 'Delay' or 'Wait' also work
R1 = Tab, pause 100, C
WARNING: Do NOT use this to fully automate complex tasks, or you’re likely to get banned from whichever game you are using this app with!
You can request in a key sequence to jump the mouse cursor to a named Hotspot location (defined in [Hotspots] and covered in detail later) to click on it, such as:
[Hotspots]
CenterScreen = 50%, 50%
[Scheme]
R1 = Point to CenterScreen, LClick
R2 = LClick at CenterScreen -> RClick
L1 = Jump cursor cursor to CenterScreen
You can also request the mouse move to a specific hotspot with a smooth motion over time by using “move” instead of “jump” or “point” or “click”. This form is not supported during key sequences - only as a standalone command - and thus doesn’t support actually clicking at the location. It is intended more for use as a visual “hint” or convenience to prepare for a likely future click. Example:
L1 = Move mouse to LootWindow1
While a key sequence could technically be used to type a message directly into the game’s chat box, it is easier to directly use a Slash Command or Say String command to do this.
Slash Commands start with / and Say Strings start with > (the ‘>’ is replaced with the Return key to switch to the chat box when the command is actually executed). These commands will send the text to the chat box after initially opening it with Return or /, then press Return to send the message or command and close the chat box. Some examples:
[Scheme]
R1 = /who
R2 = /g Roll for loot please!
L1 = >Would you like to group?
L2 = /shout TRAIN TO ZONE!!\n/say Run for it!
Everything after the / or > is entered into the chat box as-is, except for the key sequence \n which symbolizes a line break for multi-line macros. Instead of typing \n, Return is pressed once to send the message up to that point, then Return (or /) again to re-open the chat box and continue the rest of the macro after the \n. Thus L2 in the example above sends two messages.
Most other keyboard input will be locked out by the game client while the chat box is in use, so to send messages and commands as quickly as possible they will be copied into your system clipboard and then pasted into the game by using the PasteText= Key Bind (next section explains Key Binds). If PasteText= is not set to anything (such as for games that do not support pasting text into the chat box) the app will instead type the text in manually character-by-character.
In general it is better to instead create macros using any in-game interface provided and just activate them via key sequences, such as the earlier example for activating hotbar buttons, to reduce the effect the chat box will have of locking out other controls while it is in use.
Key Binds are mostly just aliases or shortcuts for any of the above commands. Using Key Binds, instead of using:
[Scheme]
XB_A = Space
Hold R1 = /who
Hold R2 = /g Roll for loot please!
XB_X = LClick at CenterScreen->RClick
You would instead use:
[KeyBinds]
Jump = Space
Who = /who
RollForLootPls = /g Roll for loot please!
UseCenterScreen = LClick at CenterScreen->RClick
[Scheme]
XB_A = Jump
Hold R1 = Who
Hold R2 = RollForLootPls
XB_X = UseCenterScreen
Key binds can also be used within key sequences, including in other key bind assignments (as long as they don’t reference each other in an infinite loop). For instance, instead of the earlier example of the key sequence assignment R1 = Tab, pause 100, C you could use:
[KeyBinds]
TargetCycleNPC = Tab
Consider = C
TargetAndCheckNPC = TargetCycleNPC, pause 100, Consider
[Scheme]
R1 = TargetAndCheckNPC
Using Key Binds instead of directly assigning keys has many other uses beyond readability, as covered in later sections.
A few Key Bind names are specifically checked for by the program and used directly as more than just aliases. These include (with examples of possible settings, but these will differ by game):
; Needed if employ the advanced system feature
; [System]/ForceFullScreenWindow = Yes (and optionally
; StartInFullScreenWindow), necessary for certain games to work with overlays
SwapWindowMode = Alt+Enter
; Used to significantly speed up Slash Command and Say String entry
PasteText = Ctrl-V
; Used for improved movement code over just raw key assignments for movement,
; including the [Gamepad] properties MoveDeadzone=, MoveStraightBias=,
; and CancelAutoRunDeadzone=
AutoRun = NumLock
MoveForward = W
MoveBack = S
TurnLeft = A
TurnRight = D
StrafeLeft = Q
StrafeRight = E
The Move/Turn/Strafe key binds are used when assign buttons to commands such as Move, MoveTurn, MoveStrafe, MoveAndLook, etc.
Note that assigning a button to a Move command or any of the above movement-related Key Binds is different than assigning it directly to the actual keyboard key the game uses for movement. Assigning directly to a movement keyboard key bypasses extra functionality used to improve responsiveness to movement input, particularly when assigning movement to analog sticks. It is thus recommended when assigning gamepad input to control character movement to always use the MoveTurn/Strafe/etc commands and =AutoRun instead of direct key assignment.
A set of related key binds can be tied into a Key Bind Cycle which allows multiple keys to be pressed via the same single command, one at a time. When a gamepad button is assigned to a Key Bind Cycle, every time the button is pressed the next Key Bind in the sequence is used (and loops back to the start after the last one, unless specify NoWrap). The most common use for this is cycling group member targets for games that have a different key bind for each group member and none for cycling through all members. Key Bind Cycles are specified as follows:
[KeyBindCycles]
MyKeyBindCycle = KeyBind1, KeyBind2, KeyBind3
Once set up, you can simply assign the Key Bind Cycle itself as you would a single Key Bind:
[KeyBindCycles]
TargetCycleGroup = TargetSelf, TargetGroup1-5
[Scheme]
L1 = TargetCycleGroup
In the above example, the first time L1 is pressed it would send the key assigned to TargetSelf to the game, then TargetGroup1, then TargetGroup2, etc until TargetGroup5, after which it would wrap back to TargetSelf again the 7th time you pressed L1.
Shortcut tip - also shown above is that if you have multiple Key Binds that all end in a number that you want in the cycle you can add them using the format KeyBindName#-# instead of typing them all out individually.
You can employ finer control by using additional key words along with the Key Bind Cycle name. Examples:
; Same as just TargetCycleGroup
L1 = TargetCycleGroup Next
; Would keep using TargetGroup 5 once get there
; instead of wrapping back to TargetSelf
L1 = TargetCycleGroup Next NoWrap
; Cycles in reverse direction (can also use NoWrap)
L1 = TargetCycleGroup Previous
; Re-sends the last key used in the cycle again
; (often used to target group member's pet)
L1 = Repeat last in TargetCycleGroup
; Doesn't send a key, but causes all above to send the default key (TargetSelf)
; next time they are used
L1 = Reset TargetCycleGroup
; Doesn't send a key, but causes future Resets to reset to a different default
; (whichever key in the cycle was sent last becomes the new default)
L1 = Set TargetCycleGroup default to last
Note that using any Key Bind that’s in a cycle will also update the cycle to treat that it as the last used. For example, using the command =TargetGroup4 then =TargetCycleGroup right after would trigger the TargetGroup5 key bind, regardless of the previous state of the cycle. This does not apply if directly use the input the Key Bind is assigned to - only using the key bind name itself.
When using this for the above example of relative group targeting, visual indicators may be helpful to know what will happen the next time a button assigned to a Key Bind Cycle is pressed. There are special Menu Styles covered later to help with this - Style=KeyBindCycle and Style=KeyBindCycleDefault.
Hotspots are positions (or sometimes regions) on the game screen of significance, such as where a mouse click should occur in a Key Sequence. They usually represent an in-game UI button or icon. They are specified via X then Y coordinate separated by a comma, with Y=0 representing the top and X=0 representing the left side of the game`s window.
Each of the coordinates can have one of 3 formats - an Anchor, one or more Offsets, or both.
The anchor represents the starting point as a relative position of the target game’s window, and is expressed as either percent (like 50%, or 0.5 if you prefer) or by special shortcuts like L/T/R/B/C/CX/CY instead of numbers. If no anchor is specified, it is assumed to be 0% (the top-left corner). This value must be between 0 and 100% (or 0 and 1.0).
An offset is expressed as pixels and can be negative or positive, and any decimal values after all offsets are added up are rounded off to whole numbers. The app decides the first number given must be an offset instead of an anchor if the number does not include a % sign or any of the shortcut letters specified above, or is out of range for a valid anchor value (negative or greater than 1.0).
To completely avoid ambiguity on if a value is an anchor or offset, you can always just specify both anchor plus offset(s) for each coordinate, done by first giving the anchor followed by a ‘+’ or ‘-’ for each offset following (i.e. 30% + 10 - 2.5). The final coordinate will be the anchor position calculated according to the target window size, and then with the pixel offset(s) added to that.
Some examples of valid hotspots for reference:
[Hotspots]
; Center of the screen/window
CenterScreen = 50% x 50%
CenterScreen = 0.5, CY
; Pixel position 200x by 100y
MyHotspot = 200 x 100
; 10 pixels to the left of right edge, and
; 5 pixels down from 30.5% of the game window's height
MyHotspot = R - 10, 30.5% + 5
; BR corner offset -50x and -75y
MyHotspot = R-50, B-75
In addition to direct named Hotspots in the [Hotspots] section, some other positions also use Hotspot formatting, such as the Position= property of Menus.
Hotspots can be used as more than points, but represent a rectangular region, for certain specific menu styles and other advanced features. To define a hotspot with a width and/or height greater than 0, add said width and height, separated by commas, after the x and y position:
[Hotspots]
; Width and height both 10
MyHotspot = 200 x 100, 10, 10
; Width of 40 and height of 20
MyHotspot = R - 10, 30.5% + 5, 40, 15+5
The hotspot itself is considered at the center of the region, but the full width and height are specified in this section. So a width of 10 would mean the actual region would be the area between 5 pixels to the left and 5 pixels to the right of the hotspot (195 to 205 in the first example above).
Hotspot offset values are not directly affected by the size of the target screen/window like the hotspot anchor is, but will instead be multiplied by a global UI Scale value. Size-related properties, such as ItemSize, BorderSize, FontSize, TitleHeight, and the above HotspotSizes, are also multiplied by this global UI Scale value. The initial value for this can be configured by setting the [System] property UIScale=, which defaults to 100% if undefined.
For games that adjust their own UI scale automatically according to window size, such as Pantheon, set the [System] property UIScaleBaseHeight= to a default value like =1080. The app will then compare the actual window height to this value and multiply the UIScale property by the difference. For example, with this property set to 1080 but the game window being 4K (2,160 height), the specified UIScale will automatically be multiplied by 2.0 (2160 / 1080 = 2.0).
For games that allow setting a scale for individual windows, Hotspot Arrays (a group of hotspots sharing the same name but just ending in a different sequential numbers) can have their offsets and size further multiplied by these per-window scales. See Hotspot Array scaling under Other Commands and Features for more details.
The UI Layout Editor can be accessed from the Edit menu of the main app window, or by adding a =Edit UI Layout command to a button or menu in your profile somewhere.
This option will bring up a dialog listing all the hotspots (and some other positions such as Menus) found in your profile that can be repositioned. Select one and click the Reposition button. You can then see a visual indicator of the position in question overlayed over the game (and any menus from this app), to see how they line up. A pop-up dialog will also appear showing the actual values from the .ini file. You can use the buttons and edit fields in that dialog to move the item, or just drag it around directly on the screen with a mouse. The game and app will continue running while you are doing this, to allow checking the position against different in-game menus and such. Simply click OK in the dialog box when done positioning the item to save the change to your profile .ini file automatically.
Note that you can not add or remove hotspots or anything else with this editor, only change positions (and size and alignment in some cases). You will need to edit the .ini file manually to add or remove anything.
To really unlock the full range of actions in an MMO using a Gamepad, you will almost certainly need to assign more than one function to a single button through the use of button combinations or different “modes” of control. This can be accomplished through the use of Controls Layers. These layers change what Commands are assigned to what buttons while the layer is active.
You can have multiple Controls Layers added at once. They can be thought of as stacked on top of each other, and for any given button, the top-most layer’s assignments will take priority by “covering up” the button assignments from the layers below it. If the top-most layer has nothing assigned to a button, the next layer below it will be checked for an assignment for that button, and so on.
Layers can be added with the =Add <LayerName> command and removed with the =Remove this layer (removes layer containing the command) or Remove <LayerName> command.
Layers are defined the same as [Scheme], with just the section name [Layer.LayerName] instead. Here is a simple example of how to utilize adding and removing a layer:
[Scheme]
Square = Jump
Triangle = Consider
L2 = Add Alternate layer
[Layer.Alternate]
Square = Duck
R2 = Remove this layer
In this example, Square will jump by default. Pressing L2 will add the “Alternate” layer. At that point, Square will Duck instead, but since it doesn’t assign anything to Triangle, Triangle will continue to Consider. Pressing R2 will remove the Layer, meaning Square will once again jump from then on.
You can remove one layer while adding another in a single command using Replace this layer with <LayerName> or Replace <LayerName> with <LayerName>. You can also both add or remove a layer in a single command, depending on if it is already active or not, with the single command =Toggle <LayerName> layer.
Extra tip - If you want a button to literally do nothing, including blocking lower layers’ assignments for that button, set it to = Do nothing. Above you could set Triangle = Do Nothing in the Alternate layer to prevent Triangle from using Consider while that layer is active. Leaving the button assignment blank (just Triangle=) is the same as not mentioning the button at all and would still just allow Triangle to use Consider.
NOTE: There can only be one of each named layer active at once, so trying to add a layer with the same name again will at most update its position as if it was newly added, but not actually remove or re-add it or add another copy of it!
By default, assigning any action to a button on a layer blocks all commands assigned to that button from lower layers.
For example:
[Scheme]
Tap R1 = TargetNPC
Hold R1 = Consider
L2 = Add Alternate layer
[Layer.Alternate]
Tap R1 = TargetPC
R2 = Remove this layer
Once the Alternate layer is added, holding R1 will no longer trigger “Consider”—even though only Tap was reassigned—because the layer now fully overrides all of R1’s actions.
To override only specific actions for a button while allowing others to pass through, use the Defer command:
[Layer.Alternate]
Tap R1 = TargetPC
Hold R1 = Defer to lower layers
R2 = Remove this layer
In this setup, Tap is overridden, but Hold will still execute the Consider command from [Scheme].
Using the Defer command for any action will automatically apply it to all other actions for that button. You can combine this with explicit blocks using the = Do nothing command if this auto-propagation is undesired.
[Layer.Alternate]
Tap R1 = TargetPC
R1 = Defer to lower layers
Hold R1 = Do nothing
Here, Tap overrides the command, Hold is blocked (will now do nothing), and all other actions (Press, Release, and the default press-and-hold action) defer to lower layers’ assignments for those actions.
Rather than manually removing a layer with Remove/Toggle/Replace, you can have a layer that is added when you first press a button and then automatically removed once you stop holding that button. A layer added in this way is considered a Held Layer while active.
Held Layers are most useful for allowing button combinations by holding some kind of “modifier button” to temporarily change what other buttons do.
Here is a modification of the earlier example but using a held layer instead:
[Scheme]
Square = Jump
L2 = Hold Alternate layer
[Layer.Alternate]
Square = Duck
In this case to duck instead of jump you can just press and hold L2, tap Square to duck, then release L2. In other words, L2+Square = Duck in this control scheme.
Note that, similar to held keys, a held layer can ONLY be assigned to the button without any actions specified, like the above L2= example. It is not valid to assign something like Tap L2=Hold layer.
Extra tip - The only way to remove a layer being held active with this command before the button is released is to use the =Force Remove <LayerName> command
Each layer has a special ‘virtual button’ unique to it, that can be assigned commands like any real gamepad button. This button is called “Auto”. It is “pressed” whenever the layer is added, then is “held” and finally “released” whenever the layer is removed.
This Auto Button can be particularly useful in order to assign a gamepad button to simultaneously ‘hold’ a layer while also holding a key, by having the held layer hold the key down using its Auto Button.
For example, let’s say you wanted to make pressing and holding Circle on a PS controller act the same as holding the left mouse button, but you also want to make it so while holding Circle, you could use your left thumb on the D-pad to move the cursor around to “drag” the mouse, even though normally the D-pad is used for character movement. You could accomplish this as follows:
[Scheme]
D-Pad = Move
Circle = Hold MouseDrag layer
[Layer.MouseDrag]
Auto = LMB
D-Pad = Mouse
With this setup, pressing Circle will add the MouseDrag layer, which will click and hold the left mouse button for as long as the layer is active via Auto, while also changing the D-Pad to control the mouse. Releasing Circle will remove the layer, restoring the D-Pad to character movement instead and releasing the left mouse button (since Auto is “released” when the Layer is removed).
You can even assign commands to Press Auto=, Release Auto=, Tap Auto = and so on, like any real button. Even Hold Auto = triggers once the layer has been active long enough.
Layers (and the root [Scheme]) can change how the mouse is treated by using Mouse=Cursor (normal), Mouse=LookTurn (holding the right-mouse button down to keep standard MouseLook mode active), Mouse=LookOnly (holding the left-mouse button down for alternate MouseLook in games that support it), or Mouse=Hide (“hide” the cursor by jumping it to the corner of the screen). The top-most layer with a Mouse= property specified dictates the mouse mode used, with the special exception of Mouse=HideOrLook which changes what it does based on the layers beneath it.
There are also some more advanced/experimental Mouse modes covered in the Other Commands and Features sections.
Each layer (including [Scheme]) specifies which Menus should be visible while that Layer in active. Layers can also specifically hide menus that were requested to be shown by lower layers, stopping them from being shown (unless yet another, higher layer overrides it back to being shown). This is done via the ShowMenus= (or just Menus=) property including a list of (root) Menus to show (and optionally the ‘Show’ and ‘Hide’ key words), such as:
[Layer.MainMenu]
ShowMenus = MainMenu
[Layer.MouseLook]
Mouse = Look
Menus = Show Reticle
[Layer.TopMost]
Menus = Hide MainMenu, Show TargetGroupLast
Similar to the ShowMenus= property, each layer can enable or disable Hotspot Arrays that can be used via the =Select Hotspot <direction> command. Each layer can also disable Hotspot Arrays enabled in the layers below it, though layers above can override that yet again.
Hotspot Arrays are defined as a list of Hotspots with the same name but just different number on the end, starting with 1, like so:
[Layer.LootMode]
Hotspots = LootWindow, Disable Standard
[Hotspots]
LootWindow1=32, 240
LootWindow2=32, 281
LootWindow3=32, 322
...
Shortcut tip - Multiple hotspots in an array can be defined at once to make it easier to add or adjust a whole array quickly. More on this in the later section “Hotspot Array ranges”.
The =Select Hotspot <direction> command will quickly move the mouse cursor to the next nearby enabled hotspot in the direction given. If none are found the mouse will be moved the amount of the [Mouse] section property DefaultHotspotDistance= (multiplied by the UIScale properly) instead. Using Dpad = Select Hotspot in your control scheme is a good way to allow a quick and accurate mouse movement method to navigate in-game windows and menus using defined hotspots.
This property is similar to ShowMenus= and Hotspots= but with a list of Layer names (and optional “Add” and “Remove” key words) of other layers that should be automatically added or removed whenever this layer is added:
[Layer.LootMode]
AutoLayers = CameraMode, Remove CursorMode
It is just an alternative to using the ‘Auto’ button with Auto=Add <LayerName> layer or Auto=Remove <LayerName> layer, but leaves the Auto button free for other things.
Note: If more than one layer is listed then the order they are added in is essentially random (so make use of Priority= property when order matters), but they will all be added/removed just after this layer is added but before its Auto button commands are run.
A layer can optionally set a parent layer with the Parent= property, followed by the name of another layer. This makes the layer a child layer of the specified parent. Parent and child layers have the following properties:
These special layers can not be manually added, but are instead automatically added and removed whenever a combination of other layers is active or not. They can be used for more complex button combinations.
For example, let’s say you want Circle to send a different key for pressing Circle by itself, L2+Circle, R2+Circle, or L2+R2+Circle. That last one can be done with a combo layer, such as:
[Scheme]
Circle=A
L2 = Hold LeftShortcuts layer
R2 = Hold RightShortcuts layer
[Layer.LeftShortcuts]
Circle=B
[Layer.RightShortcuts]
Circle=C
[Layer.LeftShortcuts+RightShortcuts]
Circle=D
With this setup, when hold both L2 and R2, causing both shortcut layers to be active, the LeftShortcuts+RightShortcuts layer is automatically added, causing Circle to press “D” instead of “C”, “B”, or “A”. The combo layer will be removed as soon as let go of either L2 or R2, thus removing one of the two base layers keeping the combo layer active.
Here’s some other technical details about combo layers:
[Layer. prefix, referred to here as their “base layers”.AutoLayers= to prevent this being a problem).Layers can be thought of as being stacked on top of each other in a specific order. This order determines what button assignments are active as well as other properties like Mouse, ShowMenus, and Hotspots, with higher layer properties and button assignments taking priority. The order of layers in the stack is thus very important for determining app behavior and appearance at any time.
Layers use specific sorting rules, outlined below, but some of those are heavily affected by adding a Priority=# property to a layer, with a value from -100 to 100. If this property is not set, a layer has a default value of 0.
Taking this extra property into account, layers follow these rules when determining order:
Parenting (when sorting)
Layers use their parent layer (specified by Parent= property) during sorting.
Since Combo layers can not have a parent specified, they treat their highest-positioned base layer as their sorting parent.
All other layers that do not have a Parent= property treat [Scheme] (which is always the bottom-most layer) as their sorting parent.
Parent-Child Positioning
A layer is always placed directly above its sorting parent (but below any layers that don’t share the same parent) regardless of any other sorting rules.
[Layer.C]
[Layer.BChild]
[Layer.B]
[Layer.A]
[Scheme]
In the above example, ‘A’, ‘B’, and ‘C’ have no parent specified, so are treated as siblings with [Scheme] as their parent. BChild has ‘B’ set as its parent. Thus it is placed above its parent (‘B’), but below the next sibling of its parent (B’s sibling, ‘C’).
Sibling Layers
“Sibling” layers (those sharing a sorting parent) use the following sorting rules with respect to each other:
Priority Property - sibling layers with a higher Priority= value are placed above those with lower.
NOTE: Before sorting begins, Held layers with priority value 0 (i.e. none specified) have their priority changed to maximum value. Therefore by default a Held layer will always be above all non-held sibling layers unless its priority is manually set to a lower, yet non-zero, value!
Layer Type - With the same priority value and parent, Held layers are placed above normal layers which are placed above Combo layers.
Combo Layer tie-breaking - if multiple combo layers would otherwise have the same position, they use the relative position of their other base layers to determine order.
Added Order - If all else is equal, the more recently-added layer is placed on top of its older siblings. If attempt to add a layer that’s already active, it will be re-sorted as if it was just barely added and may change positions (even though other events that happen when adding an already-active layer are skipped).
Now that layers and the importance of their order is covered, it is time for the exception to the rule - Signal Commands. These commands run whenever a “signal” is sent out, and ignore layer order. The layer containing the command must still be actively added to the stack, but it doesn’t need to be higher than any other layers to respond to a signal…
To add a Signal Command to a layer (or the root [Scheme]), use the syntax When Signal = Command. Most commands can be used, though not ones that must be “held” (since signals have no duration associated with them).
There are two types of signals that are sent out to activate these commands - initially pressing a Gamepad button, or using a Key Bind by name (including as part of a Key Sequence or Key Bind Cycle).
To run a command when a button is pressed, even when another, higher layer has something assigned to that button, use the syntax When Press ButtonName = Command. Example: When press L2 = Remove this layer.
To run a command when a Key Bind is used, use the syntax When KeyBindName = Command. Examples: When Sit = Remove this layer or When MoveForward = Remove this layer. As you may be able to tell, a layer removing itself is the most common use for signal commands.
Some other things to note:
Signal Commands are lower priority than other command assignments and may be slightly delayed depending on how many other actions may take priority. They should not be depended on when order of execution is important.
You can actually make a Key Bind that does nothing other than act as a signal for other commands by setting it to be =Signal Only (or just leaving it blank).
You can assign a signal for multiple Key Binds at once if they all share a name aside from just a different number at the end, by using the hash # character at the end of the property name. For example, When TargetParty# = would assign the signal to fire when use any of TargetParty1, TargetParty2, TargetParty3, etc.
A key bind only sends out a signal when it is referenced by its name, not by the command/key it is assigned to. For example, if you have the key bind “Jump = Space”, any command assigned to “When Jump=” will run when you press a button assigned to “= Jump”, but will not run when you press a button assigned directly to “= Space”!
The app will not check and warn you if you set up an infinite loop of Key Binds signalling each other. For example, if you added both “When Camp = Sit” and “When Sit = Camp”, then using either Sit or Camp could lead to an infinite loop alternating between sitting and camping (at least until a layer owning one of those signal commands is removed). So watch out for that!
While it is possible to use layers alone to send all the input needed to an MMO, it would require a lot of complex button combinations and sequences you’d need to memorize. Menus can make things a lot easier, by instead assigning buttons to add/remove/control menus and then having the menus include a large number of commands.
Menus must be made visible by the ShowMenus= property an an actively added Controls Layer to actually see it.
Each menu has a Style= property that determines its basic organizational structure and functionality. Available Menu Styles include List, Slots, Bar, 4Dir, Grid (plus GridWidth= property), Columns (plus ColumnHeight= property), Hotspots, Highlight, HUD, KeyBindCycle, and KeyBindCycleDefault.
Menus are defined using the section name [Menu.MenuName]. For most menu styles, each Menu Item is defined by a property name of just the Menu Item number starting with 1. The property value for each Menu Item contains a name/label to be displayed followed by colon : followed by a command to execute when that menu item is chosen. Here’s an example of a basic menu:
[Menu.MainMenu]
Style = List
Position = L+10, 25%
Alignment = L, T
1=Inventory: Inventory
2=Book: Book
3=TBD:
4=Settings
; Below is optional in this case
Default = 1
The Default= property determines which menu item will be initially selected when the menu is first activated (or reset with the =Reset <MenuName> command (with no menu item number specified). If unspecified then item # 1 is used as the default.
Notice how Menu Item #3 in the above examlpe has no Command, but still contains :, so the label will be shown but nothing will happen if it is used (alternatively could set it to TBD: Do nothing to make this clearer).
If you want a menu item that does do something but has no label, just start with : with nothing before it. You still need to include the : and not just a command by itself though, because the absense of : is used to indicate that menu item opens a Sub-Menu, as shown in Menu Item #4 above.
Pro tip - f you want to include a colon character in the actual label text, surround the entire label with double-quotes, i.e. 1 = "Label: MoreLabel" : Command
Shortcut tip - you can actually specify multiple menu items at once if they have commands and labels that only differ by a number value that matches the menu item number. For example, to have a menu with 10 items, each with a label that has the number 1 through 10 in it, and/or a command such as a numbered KeyBind numbered 1 through 10, you could specify all the menu items in a single line using something like 1-10 = Ability#: UseAbility#. The # symbols are replaced by the menu item number in the property value as each individual number menu item is created.
A sub-menu is created by having a menu item property value without any : character, which then has the label double as the sub-menu’s name. The sub-menu is defined by the section name [Menu.MenuName.SubMenuName]. In the earlier example, 4=Settings specified a sub-menu named “Settings”. Here is an example setup for that sub-menu:
[Menu.MainMenu.Settings]
1=Profile: Change Profile
2=Close Overlay
[Menu.MainMenu.Settings.Close Overlay]
1=Cancel Quit: ..
2=Confirm Quit: Quit App
Sub-menus can have their own Style, Position, and other visual properties, or just contain nothing but the menu items as shown above. Besides menu items, any properties that aren’t specified will use the properties of their “root” menu ([Menu.MainMenu] in this example).
Note the special .. command, which just backs out of the sub-menu to one less “menu depth”.
You can also set up a jump directly to any other sub-menu that shares the same root menu by specifying the path to that sub-menu starting with the . right after the root menu’s name (or just . by itself for the root menu itself). A separate label must be manually set in this case (if desire one). Example:
[Menu.Root]
; Goes to Root.SubA (label is "SubA")
1 = SubA
; Goes to Root.SubA.SubB (no label!)
2 = .SubA.SubB
[Menu.Root.SubA]
; Goes to Root.SubA.SubB1 (label is "SubB1")
1 = SubB1
; Goes to Root.SubA.SubB2 (label is "SubB2")
2 = SubB2
[Menu.Root.SubA.SubB1]
; Always goes to Root.SubA regardless of how got here (label is "Back")
1 = Back: ..
; Goes to Root.SubA.SubB2 (label is "Switch to SubB2")
2 = Switch to SubB2: .SubA.SubB2
[Menu.Root.SubA.SubB2]
; Goes back to Root (label is "Start Over")
1 = Start Over: .
Pro tip - you can also use this second method to jump directly to a specific menu item being selected in the requested menu by adding a comma and the menu item number (or hotspot name for menu styles that use those) after, such as Label: .SubA.SubB2, 3.
To actually use a menu, you will need to assign menu-controlling commands to gamepad buttons in [Scheme] or a [Layer.LayerName] section. These commands must specify the name of the root menu they are referring to (you can not directly assign controls to a specific sub-menu). Below is an example of controlling the MainMenu example from earlier, including showing/hiding it with the Start button.
[Scheme]
Start = Toggle Layer MainMenu
[Layer.MainMenu]
ShowMenus = MainMenu
; Reset exits all sub-menus and selects default menu item
Auto = Reset MainMenu
DPad = Select MainMenu Wrap
PS_X = Confirm MainMenu
Circle = Back MainMenu
Technically, menus are never actually opened, closed, or disabled. They are always there, it is just a matter of whether or not they are visible (via the ShowMneus= property on an active layer) and whether any buttons currently are assigned to control them. This is why when you want to “open” a menu, it makes sense to use =Reset <MenuName> as the first command on it, as it will otherwise still be in whatever state it was last left in.
You can give the appearance of a menu being closed or disabled by hiding the menu and/or making sure no buttons are assigned to control it (in fact, a menu will automatically fade to its InactiveAlpha= transparency level if it is visible yet detects no buttons are currently assigned to control it, to help indicate it is effectively disabled).
In order to simulate closing a menu when trying to back out of one via the =Back <MenuName> command, you can take advantage of a special command property you can add to any menu or sub-menu - Back=. This command is run whenever the Back command is used on that menu.
For the earlier example of MainMenu being controlled by Layer.MainMenu, when the user presses Circle from the root menu, the menu could appear to close by removing the MainMenu layer, which will hide the menu (because the ShowMenus= property making it visible will be gone) and stop controlling it (because the various button assignments related to it will also be gone):
[Menu.MainMenu]
Style = List
Position = L+10, 25%
Alignment = L, T
Back = Remove MainMenu layer
1=Inventory: Inventory
...
Similar to the “Auto” button for each Controls Layer, and a counterpoint to the Back property above, you can add an Auto= property to a menu or sub-menu which can be set to a direct input command to be used whenever that sub-menu becomes active. This command will trigger when changing sub-menus (including returning to one from using “Back” or “Reset”) or when a menu has just been made visible/enabled when it previously was not.
In addition to the normal, numbered menu items, each menu can have 4 directional menu items specified, labeled as L=, R=, U=, and D= and tied to using =Select <MenuName> Left, Right, Up, and Down respectively. These special menu items have their commands run directly via the =Select <MenuName> command rather than the =Confirm <MenuName> command, but only when there is no menu item in the direction pressed!
For example, in a basic list-style menu, normally =Select Left and =Select Right doesn’t do anything since all of the menu items are in a single vertical list, but if a L= and/or R= property is included, then =Select Left and/or =Select Rightwill immediately execute the L/R= commands.
Even in a list-style menu, the U= and D= menu items can also still be used, but only if use Up while the first menu item is currently selected, or Down when the last item is currently selected. Similar logic applies to other menu styles, but may be slightly different for each one. Note that these will still run from pushing up from the top item or down from the bottom item when using wrapping with the Select command!, even though the selection will also wrap around to the other end of the menu at the same time!
One key use of these is allowing for side menus such as in a List or Slots style menu, by usingL= and R= to instantly swap to a different selection of menu items without needing to add visible sub-menu items. Here is an example of how to use these in an EQOA-like abilities menu:
[Menu.Abilities]
Style = Slots
L=.Hotbar
R=.Spells
1=Abil1: Ability1
2=Abil2: Ability2
...
[Menu.Abilities.Spells]
L=..
R=.Hotbar
1=Abil6: Ability6
2=Abil7: Ability7
...
[Menu.Abilities.Hotbar]
L=.Spells
R=..
1=HB1: Hotbar1
2=HB2: Hotbar2
...
This menu style is designed to emulate EQOA’s “Ability List” and “Tool Bar” and is a great candidate for “side menus” as explained above. It is basically a list-style menu, but the current selection is always listed first and the entire menu “rotates” as you select Up or Down, like the reels in old slot machines (hence the name).
In order to help better keep track of what item is actually selected when the entire menu is moving, this style of menu allows for an alternate, second label for each item. This alternate label is only displayed for the currently-selected item and is drawn off to one side of the rest of the menu. You can control the size of this alternate label area by adding the property AltLabelWidth= to this menu’s section.
To specify what label should be displayed in the alternate label, when setting the menu item properties, start with the alternate label first, then the pipe (|) symbol, then the normal label, then colon (:), and then the command. Like this:
[Menu.Abilities]
AltLabelWidth = 108
1 = SpellName1 | Spell1: CastSpell1
2 = SpellName2 | Spell2: CastSpell2
...
The alternate label can be replaced with an image, including possibly one copied from the game’s window dynamically, just like normal labels, as covered later.
This special Menu style is designed after the “Quick Chat” menu in EQOA, which allows for quickly selecting a menu item through a series of direction presses without needing to ever use press a confirm button. For this menu, no numbered menu items are specified, only the directional menu items discussed above are used. So for macros in the style of EQOA, you could define a Menu like this:
[Menu.Macros]
Style = 4Dir
Position = 50%, 10
U = Responses
L = Options
R = Group
D = Communicate
[Menu.Macros.Group]
U = Attacking
L = Creation
R = Readiness
D = Important!
[Menu.Macros.Group.Creation]
U = Invite: /invite
L = Organization
R = Need Group: /ooc Looking for group!
D = Hunting
[Menu.Macros.Group.Creation.Organization]
U = Request Roll: /g Roll for loot please!
L = Loot up!: /g Loot up if you want this.
R = Want Group?: >Would you like to group?
D = Roll 100: /rand
...
When defining buttons to control such a menu, no =Confirm <MenuName> is needed, since the commands will be executed with the =Select <MenuName> command directly. =Back <MenuName> can still be set to back out to the previous menu though.
This special Menu style does not use a preset arrangement of menu item positions, nor numbered menu items. Instead, each menu item is specified by a Hotspot name for the property name, and that hotspot is used for positioning the menu item. This allows for highly customized menu layouts.
Since hotspots are used instead of numbers for the menu items, the default selected menu item can end up being essentially random, so be sure when using this style to set the default menu item using Default= property (but set to the hotspot name rather than a number).
[Menu.Custom]
Style = Hotspots
Default = WindowButton1
WindowButton1 = WB1: UseWB1
WindowButton2 = WB2: UseWB2
WindowButton3 = HB3: UseWB3
...
If the associated hotspot has a non-zero size specified in the [HotspotSizes] section, than that menu item will use the hotspot’s size instead of the ItemSize= property, meaning that this menu style can even have different menu items using different sizes.
Shortcut tip - the above example could have a single line for all of the menu items - WindowButton1-15 = WB#: UseWB#. This only works when the hotspots in the given range end in numbers themselves (i.e. are part of a Hotspot Array).
This menu style is very similar to the Hotspots style above - using Hotspots for menu items instead of numbers - except instead of displaying the entire menu at once, it only displays the currently-selected item - and only draws the border of that menu item (in SelectedBorderRGB= color) and nothing else.
The idea behind this menu style is to use it over top of an in-game menu or other HUD element, with the simple border highlighting which in-game item you have selected. This can give more of a feel of interacting directly with the game while limiting how much the overlay obscures in-game UI, yet still be using a gamepad for selecting items instead of a mouse.
For example, if the game features a Hotbar, you could make a menu like below to select hotbar buttons to use without obscuring or having to duplicate the in-game hotbar button icons:
[Menu.Hotbar]
Style = Highlight
Default = Hotbar1
Hotbar1-9 = : UseHotbar#
...
NOTE: Even though the label is not drawn anyway, the : is still required to differentiate between a command and a sub-menu.
As you navigate the menu using a controller, all that will be shown is a border box around the currently-selected hotbar button in the in-game UI, which you could then activate the selected hotbar button (via the UseHotbar# Key Binds) by using the = Confirm Hotbar menu command assigned to a gamepad button.
This style also pairs well with setting Mouse=<MenuName> as well if want to actually show the cursor pointing at each item as navigate (or if you want the cursor to be the ONLY thing shown then set SelectedBorderSize=0). If you want to just have the mouse click at the game’s UI, set a gamepad button to the command = Confirm with Click and simply set each menu item to just : by itself if don’t want it to do anything else besides the click.
If the target game has a UI window with clickable options you want to activate via controller, you can align an overlay menu with it and then have the mouse click on the screen position of the center of each menu item in the overlay. Since overlay menus don’t respond to mouse clicks themselves, the click will pass through to the aligned in-game UI. This work especially well with the Highlight Menu Style above.
Each menu can have 3 settings for affecting the mouse by setting a Mouse= property for that menu:
[Menu.MainMenu]
; Default if not specified - no effect on mouse
Mouse = Do nothing
; Move mouse cursor to center of selected item whenever selection changes
; NOTE: Ignored for any Mouse modes set by layers except Mouse=Cursor!
Mouse = Move
; Click mouse at center of selected item when confirm menu item
; Also acts like Mouse = Point, but click still happens regardless of mouse mode
Mouse = Click
Note that when a menu item is confirmed with Mouse = Click, any command assigned to that menu item will still occur alongside the mouse click.
You may want to have a menu “close” immediately after an item is selected, instead of requiring additional button presses to get out of the menu. For most menu styles, this can be done by adding “and Close” to the Confirm command in the menu-controlling layer, i.e. =Confirm and Close <MenuName> (for 4Dir style menus, which don’t use the Confirm command, you would instead add it to the selection command such as =Select in <MenuName> then close it).
This auto-close only happens when selecting a menu item that does NOT open a sub-menu.
Since overlay menus don’t truly “close” at all, what this actually does is execute the assigned Back= command for the (root) menu, expecting that to be assigned to remove the layer that is controlling & displaying the menu. Note that this auto-close does not by itself reset the menu - current selection and active sub-menus remain - nor does it run the Back command for any sub-menus.
It can be helpful to allow changing menu contents while playing the game, such as for quickly creating macros in a 4Dir style menu. You can do this by assigning the Command =Edit <MenuName> to a button action, which will edit whichever menu item is currently selected, or =Edit <MenuName> Up/Down/Left/Right for editing directional menu items. For example, to work like the Quick Chat menu in EQOA from the above example, where holding the D-Pad for a while allows editing the macros, you could use:
[Layer.Macros]
ShowMenus = Macros
Auto = Reset Macros
Tap DPad = Select and Close Macros
Hold DPad 800 = Edit Macros
Tap L2 = Remove this layer
When the =Edit <MenuName> command is executed, a dialog box pops up that allows changing the label or command, adding new menu items or sub-menus or deleting or replacing them, with instructions included in the dialog. You will need to employ your actual keyboard to type in the new macro though.
Having menus be visible is of course the entire reason this app is referred to as an “overlay” and not just a remapper. Menus are drawn in transparent overlay windows on top of the target game’s window. There are various properties that can be set on each menu to change how it should look.
Default properties used by all menus can be defined in the base [Appearance] section. For any property not defined for a sub-menu, the root menu’s property will be used, and for any not defined in a root menu, the property in [Appearance] will be used. The generated MMOGO_Core.ini file includes some basic defaults as a starting point with comments on what each property does.
For most menu styles, where it is drawn is determined primarily by the Position= and Priority= properties. Position uses Hotspot formatting and defines an “origin point” of the menu - though certain menu styles like Hotspots and Highlight ignore this property. Priority determines draw order (higher priority are drawn on top of lower priority, allowed range is -100 to 100 and default is 0).
The actual region of the screen the menu will draw to is offset from this origin according to the Alignment= property, which uses the same relative position shortcuts - L/R/T/B/C - used for Hotspots. For example, if you specified R-10 for a menu’s X Position, but the menu is 50 pixels wide, most of it would end up cut off by the right edge of the screen (only the left 10 pixels of the menu would be shown). Instead, you can use the following to make the right edge of the menu be 10 pixels to the left of the right edge of the screen, and exactly centered on the Y axis:
[Menu.Macros]
Position = R-10, CY
Alignment = R, C
Note that the alignment property is ignored for menus that use hotspots for positions, such as the Hotspot and Highlight styles, which always position each item with the given hotspot as the center point of the item.
Each menu item’s shape is affected by an ItemType= property. Available types include: Rectangle (default), Rounded Rectangle (needs Radius= as well), Circle, Bitmap (needs Bitmap= as well), ArrowL/R/U/D, and Label (nothing drawn for background).
Various properties can be defined that set the size and colors used, including ItemSize=, Font=, FontSize=, FontWeight=, BorderSize=, LabelRGB=, ItemRGB=, BorderRGB=, and TransRGB= (which color is treated as a fully-transparent “mask” color). Menus can optionally include a title bar with the TitleHeight= property and a gap between menu items (or overlap by using a negative value) with the GapSize= property.
Note that the menu’s overall size isn’t specified as a property - it is determined by a combination of ItemSize=, Style=, and how many menu items that particular menu or sub-menu has.
In order to visually show current selection and possibly “flash” a menu item when it is activated, alternate colors (or Bitmaps) can be set for menus starting with the word “Selected” or “Flash” or the combination “FlashSelected”, such as SelectedItemRGB=, FlashBorderRGB=, FlashSelectedLabelRGB=, SelectedBitmap=, and so on.
Menus can also fade in and out when shown or hidden, or be partially faded out when they haven’t been used for a while or are currently disabled (by virtue of having no active buttons assigned that can control the menu), all of which can be controlled with the properties MaxAlpha=, FadeInDelay=, FadeInTime=, FadeOutDelay=, FadeOutTime=, InactiveDelay=, and InactiveAlpha=. All alpha values should be in the range of 0 to 255 (0 fully invisible, 255 fully opaque), and delay times are in milliseconds (1/1000th of a second).
A bitmap is an uncompressed pixel image format, generally with the file extension .bmp. As mentioned above, menu items can be set to ItemType=Bitmap , which require specifying the region of a .bmp file to use with Bitmap= (and optionally SelectedBitmap= etc in the case of a menu to make selected item distinctive).
First, any Bitmaps to be used must be named in the [Bitmaps] section, with each having a name (the property name), a path to a file, and optionally a transparent/mask color, like so:
[Bitmaps]
MyImage1 = "C:\Images\MyBitmap1.bmp", 255, 0, 255
MyImage2 = Bitmaps\MyBitmap2.bmp
The path specified can be a full path or relative to the location of the overlay’s .exe file. At this time, only actual .bmp files are supported, not .png’s etc).
Once a Bitmap is set properly, set the menu to use ItemType = Bitmap and then set Bitmap= to the bitmap name chosen above (or a portion of it specified by X, Y, Width, Height with 0, 0 being the top-left pixel), like so:
[Menu.MyMenu]
Style = List
ItemType = Bitmap
Bitmap = MyImage1
SelectedBitap = MyImage2: 64, 96, 32, 32
FlashBitmap = MyImage2: 96, 96, 32, 32
The bitmap or bitmap region will be scaled as needed to fit into the menu’s ItemSize dimensions if they do not match.
In addition to the backdrop of a menu item, a bitmap can be used to entirely replace a text label.
The [LabelIcons] section is used to link each menu item’s label text to what should be drawn in place of it. For example:
[Menu.MyMenu]
Style = List
1 = Spell1: Alt-1
2 = Spell2: Alt-2
...
[Bitmaps]
MyIcons = Bitmaps\MyIcons.bmp
[LabelIcons]
Spell2 = MyIcons: 0, 0, 32, 32
Would have a menu where the first Menu Item would have the text label “Spell1”, but the second Menu Item would instead show a copy of the (l=0, t=0, w=32, h=32) region of Bitmaps\MyIcons.bmp displayed instead of text.
Note that linking a label to an icon is case-insensitive and ignores spaces, so “SPELL 2” would link to the same icon as “Spell2”.
While icons from bitmaps stored on your hard drive might look better and be clearer than text labels, they can’t dynamically display information that might change during play. In the above example, the “Spell2” label would always show the same icon regardless of what spell is actually assigned to that slot. So what if you want it to display an icon that matches the in-game icon of the spell in that slot?
To do this, you can specify a hotspot representing a rectangular region of the game’s window (i.e. has a size specified in the [HotspotSizes] section) to be copied and act as an icon, which will then be continuously updated to match the game’s UI (at least once every [System]CopyIconFrameTime= milliseconds). For example:
[Hotspots]
SpellBar1 = R-100, 20
SpellBar2 = R-100, 52
[HotspotSizes]
SpellBar = 32, 32
[LabelIcons]
Spell1 = SpellBar1
Spell2 = SpellBar2
Shortcut tip - to set up multiple related label icons quickly, you can use the format Spell1-8 = SpellBar#. This will expand to the same as Spell1 = SpellBar1, Spell2 = SpellBar2, etc up to Spell8 = SpellBar8. This only works for label text that ends in a number!
Pro tip - when using this feature, it may be desirable to have the copied-from area of the game’s window be covered up by a HUD style overlay to avoid having the same icon show up in two places at once on your screen (the copy in the overlay + the original icon in the game’s built-in UI). This requires an alternate copy method that avoids copying from the overlay itself, fetching the icon from the game window hidden underneath it instead. Which copy method works may differ from game to game. You can set the method using the [System] property “IconCopyMethod”. See the comments in MMOGO_Core.ini for details on possible values for this property.
The Style=HUD setting can be used for visual indicators, an aiming reticle, help text/labels, backdrops for other menus, or means of blocking out sections of the screen, and means the menu does not react to any menu control commands. Thus strictly speaking it isn’t really a “menu” at all.
This style is treated as having a single static menu item (that should not be manually defined - it is created automatically). Thus the ItemType= property and everything else setting up how a menu item looks will affect the overall look of this “menu”. It use the Title= property, if set, for the label of this single menu item (including using it to reference a Label Icon replacing the text if one is set up), but does not display an actual title bar (ignores the TitleHeight= property).
Since these are technically never “active”, they are instead treated as always active, and thus also ignore the InactiveDelay= and InactiveAlpha= properties. They are not considered to ever have a “selected” or “flashing” menu item either, so colors/etc related to selected or flashing items are also ignored.
The settings Style = KeyBindCycle and Style = KeyBindCycleDefault are special variations of the HUD style above used to help give a visual indicator for what will happen when using a button assigned to a Key Bind Cycle (such as which party member was just targeted, and thus which will be targeted next, when using a Key Bind Cycle set up for that).
The difference between these and the HUD style is just the position they are displayed in - their position is set to a Hotspot matching the name of a Key Bind from a Key Bind Cycle (the actual Position= property is then applied as an offset from that hotspot).
They must have a special property set to specify which Key Bind Cycle to use - KeyBindCycle=<CycleName> - with the name being one of the property names in the [KeyBindCycles] section.
To work properly, each Key Bind in the cycle must have a Hotspot that exists with the exact same name, used for positioning this menu. For example:
[KeyBinds]
TargetSelf = F1
TargetGroup1 = F2
...
[Hotspots]
TargetSelf = 100, 100
TargetGroup1 = 100, 200
...
[KeyBindCycles]
TargetCycleGroup = TargetSelf, TargetGroup1-5
[Menu.TargetGroupLast]
Style = KeyBindCycle
KeyBindCycle = TargetCycleGroup
Position = +0, +0
...
For =KeyBindCycle, the menu will reposition itself to the Hotspot matching the name of the last Key Bind in the cycle that was used. For =KeyBindCycleDefault, it will instead use whatever Key Bind is set as the default for its position (the first one in the cycle until changed via the command =Set <KeyBindCycleName> default).
This final section covers various extra features that don’t fit into the main categories above.
These commands affect the overlay app directly rather than the game you are using it with, and can be assigned to menu items or gamepad buttons like any other command.
=Change Profile - brings up profile select dialog=Edit layout - brings up layout editor dialog=Quit App - closes the overlay application=Change target config file - see Auto-sync variables to game config files=Set <VariableName> to - see Variables section belowWhen defining Hotspot Arrays, it can be a pain to change every individual hotspot associated with an in-game UI window when you want to move that UI window in the game, even with the help of the runtime UI Layout Editor. To assist with this, these elements can use a base anchor hotspots with the other hotspots defined as just offsets to the anchor, meaning they can all be moved at once by only moving the anchor.
To create an anchor, define a hotspot with no number after its name. At that point, any hotspots with the same name but with a number at the end of the name will be treated as an offset. For example:
[Hotspots]
LootWindow = 32, 240
; Below will actually be at 32, 250
LootWindow1 = +0, +10
; Below will actually be at 32, 291
LootWindow2 = +0, +41
In addition, you can specify multiple hotspot offsets in a single line by using the format Name##-##, with the first number being the first index in the array and the number after the - being the last index in the array. When using this format, each hotspot in the range (including the first) will be offset from the previous hotspot in the array, and ignore the base anchor position (in fact, you do not need to define a base anchor position at all in this case). For example:
[Hotspots]
LootWindow = 32, 240
; Define 8-tall left column starting at 32x240 then each 41 apart in Y
LootWindow1 = +0, +0
LootWindow2-8 = +0, +41
; Define right column @ 73x240 then 41 each in Y
LootWindow9 = +41, +0
LootWindow10-16 = +0, +41
Note that the + signs in front of each number for the offsets don’t do anything and are optional - it is just a handy way to make it clearer that these are offsets rather than direct positions. The offsets can be negative values as well.
Hotspot width and height can be set for any offset hotspot or for all hotspots in a specific range (but act as a replacement value and not an additional offset like positions do). If they are not specified, single numbered hotspots will use the width and height set for the anchor hotspot, and for ranges, they will use the width and height of the previous hotspot in the array. Example:
[Hotspots]
; Sets default size of each hotspot in the LootWindow array to 10x10
LootWindow = 32, 240, 10, 10
; Will have default 10x10 size from the anchor above
LootWindow1 = +0, +0
; Will override default and have 16 w 8 h
LootWindow2-8 = +0, +41, 16, 4
; Will override anchor LootWindow and have 40 w 12 h
LootWindow9 = +41, +0, 20, 10
; Will use LootWindow9's 40w 12h
LootWindow10-16 = +0, +41
; Overrides from above don't matter!
; Below will still have default 10 x 10 from anchor
LootWindow17 = +82, +0
LootWindow18-24 = +0, +41
A Hotspot Array using an anchor + offsets (as described above) can also have all the offsets scaled by a single scale value. This works the same as the global UI Scale and is combined with it, but only applies to the hotspots in that specific array. The scale value will also apply to any associated entry in the [HotspotSizes] section as well for these hotspots.
This is useful in games that allow scaling individual UI windows, by setting a Hotspot array associated with that window and than scaling all the offsets and sizes with a single change. Simply add * scaleValue to the end of the anchor hotspot’s property value to do this.
To use the above example, let’s say the LootWindow is separately set to 1.5x scale. You could then set the LootWindow= entry as follows, without needing to make any other adjustments to the rest of the LootWindow hotspots:
[Hotspots]
LootWindow = 32, 240 * 2.5
; 32, 240 * 250% is also a valid format
Note that the 2.5 scaling will not be applied to the anchor’s base 32, 240 values in the above example, which would represent the “origin” of the game’s UI window. It just scales the offsets from that point for the remaining hotspots in the LootWindow array.
Setting something to =MoveAndLook functions mostly the same as =MoveStrafe, except it also automatically rotates the camera during left and right strafing motion (using the mouse of course, which means it only does this while in Mouse Look mode).
The rotation speed depends on how far to the left or right the analog stick is pressed (if this command is set to an analog input). This is an option seen in some games called “Auto Rotate Camera” or “Camera Follow” or some such, and is pretty common in 3D 3rd-person console games. It allows for steering with only one stick and being able to see where you are going, but you can still strafe by holding one direction on the left stick and the opposite on the right stick to counter the auto-rotation.
You can modify how this command functions with the [Mouse] settings MoveLookDeadzone=, MoveLookSaturation=, and MoveLookSpeed=.
This acts a potential alternative to =AutoRun that allows continuous movement in other directions - namely strafing or walking backwards. You could think of it as “Auto-Strafe-Run”. It looks at what movement commands are currently being held active by other buttons (analog sticks) at the same time the command is executed to “lock” the same movement direction to be automatically held after that point - until cancelled.
For MoveForward, or when not holding any directions, it will use the standard AutoRun key bind (unless there is none defined, then it will hold down the MoveForward key continuously). For turning left/right, it will not lock them (so as not to just spin in circles) unless are also in right-click Mouse Look mode at the time (where it assumes the turn keys will cause strafing instead).
This locked movement mode will cancel once release and re-press any direction on the same axis as any locked direction. In other words, if you lock walking backwards, you can press left or right to strafe while continuing to move back automatically, but pressing forward or back again will cancel it. If you lock moving slant, re-pressing any direction will cancel it entirely.
WARNING: For directions that can’t just use the AutoRun key, the game itself may stop you from continuing to move in the direction desired while using the chat message box - particularly if type one of the movement keys (i.e. WASD) as part of your message. To help avoid this, consider re-mapping your movement keys to ones you aren’t likely to use while typing, like the arrow keys or num pad. Some games will stop any movement from held keys as soon as the chat box opens regardless though.
This mouse mode can be used by setting Mouse = LookAuto in a layer (and no higher layers having a different Mouse mode set). It swaps between =LookTurn and =LookOnly functionality based on character movement. Obviously only useful for a game that supports LookOnly mode (left-click to rotate camera without turning character) and while in a 3rd-person camera view.
With this mode the left mouse button will be held while no movement commands are being sent, and the right mouse button will be held while movement commands are also being sent. This allows panning the camera around and viewing your own character from different angles while stationary, yet steering your character while moving, just like in most modern 3rd-person action games on consoles.
The tricky part is while using auto run, which the app has no way of knowing for sure your character is still doing or not (there are multiple ways to cancel auto run that the app won’t necessarily know about). Therefore it assumes that any time you send the AutoRun keybind that your character begins moving forward, and that your character will continue moving forward until you send MoveBack or release and re-send MoveForward commands, and will hold the right mouse button during this to allow for steering.
You may want to override this with another layer that sets Mouse = LookOnly - such as while holding a modifier key - so that you can use this other layer to freely look around without changing your run direction during auto-run.
Variables can be used to define settings that can be changed and remembered across profile loads by using simple text replacement. You can define variables in the [Variables] section along with their default values like so:
[Variables]
MoveType = MoveStrafe
CamSteer = On
These can be referenced in any property value throughout the file (including other variables!) using a variable expansion block in the format${...}.
LStick = ${MoveType}
NOTE: Does not work for property names or section names, only property values!
Basic math operations are supported within a block. Consider the example of Var = 10:
| Syntax | Description |
|---|---|
${Var} |
Replaced with 10 |
${Var + 1} |
Replaced with 11 |
${Var - 2} |
Replaced with 8 |
${Var * 7} |
Replaced with 70 |
${Var / 2} |
Replaced with 5 |
A ternary-style conditional operator ?: is also supported to insert different values:
LStick = ${CamSteer = On ? MoveAndLook : MoveStrafe}
If the expression before the ? is true, the text just after it is used, otherwise, the text just after the : symbol is used instead. Supported comparison operators are = or ==, != or ~= (not equals), <, <=, >, and >=. These comparison operators, and the “else” (:) section, are optional when using the ? operator. Without a comparison operator, the variable is evaluated directly for “truthiness” (anything besides blank, 0, “no”, “false”, or “off” is considered “true”). Without the else (:) section, if the condition is evaluated to false, the entire block is just replaced with nothing.
Variable expansion blocks can themselves be nested within other blocks. Inner-most blocks are evaluated first, so:
= ${OuterVar = ${InnerVar} ? Yes : No}
would substitute InnerVar’s value first. Therefore if InnerVar was set to 5, the text would temporarily become:
= ${OuterVar = 5 ? Yes : No}
The text would then be evaluated again before being used, replacing the full block with just “Yes” or “No” depending on OuterVar’s value. There is no limit to nesting depth, and everything from the values to the variable names and even the operator characters can be a nested variable block, allowing for complex evaluation logic.
Variables can be changed at runtime using the command =Set VarName to Value, with “Value” being whatever you want (including another variable name). For example, you could have a settings menu item like so:
[Menu.Settings]
1 = "Cam Steer: ${CamSteer}": Set CamSteer to ${CamSteer ? Off : On}
Which would make it so using this menu item would toggle CamSteer on or off, and change how the LStick behaves in the earlier example, as well as how the label appears for this menu item (saying either “Cam Steer: On” or “Cam Steer: Off”).
Setting a variable with this command will save the variable’s new value to your profile’s .ini file, so it will still be in effect the next time this profile is loaded. This can be used to quickly change configuration settings without needing to edit the .ini file every time. If you do NOT want the new value to be saved to your profile, but only be set that way until you exit the app or change profiles, use “Temp” or “Temporarily” as in =Temporarily Set VarName to Value.*
This property allows swapping your button assignments around without having to go through your entire profile and change every instance of one button to be another. For a global change, add this to [Scheme] like so:
[Scheme]
ButtonSwap = Circle with Triangle, PS-X with Square
This will make all commands assigned to Circle be assigned to Triangle instead, and vice versa, and then the same for PS-X and Square.
You could have this swap activate via a variable, thus supporting multiple control layouts with something like:
[Scheme]
ButtonSwap = ${ButtonMap = 2 ? Circle with Triangle : None}
“None” can be used to specify no button swaps.
You may want to only conditionally swap buttons. For example, perhaps the above swaps make sense for basic gameplay, but you don’t want them swapped in menu-controlling layers. Each layer can have its own ButtonSwap property. Specifying one will completely override all other ButtonSwap settings for that layer.
[Layer.MainMenuControls]
ButtonSwap = None
If a layer does not have a ButtonSwap property set (or it is set to empty/null/blank), it will use the same setting as its parent layer (combo layers will treat their first-named base layer as their parent in this case). This is why setting a swap in [Scheme] makes it a global change - all other layers are ultimately children/grandchildren/etc of [Scheme].
Variables can be automatically set to values read in from game configuration files, and will even automatically update if said files are modified during play. These automatic changes behave like the =Temp Set VarName to Value command and thus will NOT be written out to your profile .ini files.
First, any game configuration file that should be parsed needs to be set as a property in the [TargetConfigFiles] section, with a name given to each file. Environment variables such as %USERPROFILE% can be used in the file path, such as Settings=%USERPROFILE%\AppData\LocalLow\Company\Game\settings.json
NOTE: Currently only .json format is supported for this feature!
For games that store their config file contents directly in a system registry value in binary format, such as AOA, a registry path can also be used and its contents read as if it was a text file, such as HKEY_CURRENT_USER\Software\Company\Game\uiWindows*_h*
Paths also support * acting as a wildcard character, if you don’t want to have separate profiles for each config file (i.e. each of your characters for games that use different files for each). If more than one file (or registry value) is found that matches a path using wildcards, one will need to be selected. This can be manually done via a dialog box by using the command =Change target config file, or automatically prompted at profile load if needed by setting the [System] property PromptForTargetConfigSyncFiles = True. Otherwise the most-recently-modified file matching the wildcard pattern will be automatically selected.
Next, use the [TargetConfigVariables] section to assign a variable to be synced and where to read its new value from. The property name should match the name of one of the properties in the [Variables] section.
The property values in this section should contain a path through the game’s config file to the value to read in, with each step on the path separated by periods. The first step of the path should be the name of a [TargetConfigFiles] property for which file to read from, followed by section names, key names, value names, etc, depending on the configuration file layout. For example, Monsters and Memories UIScale can be read and apply automatically with this setup:
[Variables]
UIScale = 1.0
[System]
UIScale = ${UIScale}
[TargetConfigFiles]
Settings=%USERPROFILE%\AppData\LocalLow\Niche Worlds Cult\Monsters and Memories\settings.json
[TargetConfigVariables]
UIScale = Settings.GameSettingUIScale
NOTE: The paths in the [TargetConfigVariables] section ARE case-sensitive! Also, in the above example, if the Settings property or the settings.json file can’t be found or opened, you will NOT see an error message appear on-screen - to allow a quick disabling of this feature by commenting out the Settings= line. Check MMOGO_ErrorLog.txt if the feature isn’t working when expected to see if this is the problem.
For added convenience and to reduce the number of variables needed for more complex values - namely the positions of in-game UI windows - the property value may instead contain a built-in “function name” followed by a colon : followed by a comma-separated list of parameters to send to that function. Each provided function may use multiple values from the game’s config file to calculate the final variable value.
For example, to align a hotspot to the top left corner of the window a game identifies by the key “inventory”, you could use:
[TargetConfigVariables]
InventoryX = Left : inventory
InventoryY = Top: inventory
Notice how ‘inventory’ is just a name, not a path. This is because it actually represents multiple paths. To accomplish this, the actual paths are specified by properties in the [TargetConfigFormat] section.
Each property in this section has a special property name and a property value of a config file path. This path should contain one or more numbered tags in the format <1>, <2>, etc for where to insert the names passed in from the above FunctionName: Param1, Param2, ... to create the full path. So for the above Inventory hotspot example, you might use:
[TargetConfigFormat]
PositionX = Windows.SaveData.<1>.position.x
PositionY = Windows.SaveData.<1>.position.y
AlignmentX = Windows.SaveData.<1>.anchorMin.x
AlignmentY = Windows.SaveData.<1>.anchorMin.y
Width = Windows.SaveData.<1>.sizeDelta.x
Height = Windows.SaveData.<1>.sizeDelta.y
InvertPositionY = Yes
InvertAlignmentY = Yes
This means that the earlier InventoryX = Left : inventory will actually insert “inventory” where <1> is and thus read in the paths Windows.SaveData.inventory.position.x as well as Windows.SaveData.inventory.anchorMin.x from “Windows” config file, and then combine them using the “left” function.
Available functions like left, top, right, cx cy, etc typically evaluate to a hotspot X or Y coordinate, and most will use multiple properties in [TargetConfigFormat]. For example, “Left” uses PositionX and then offsets it according to AlignmentX to represent the left side of a window. “Right” would add Width to that to get the right edge. If other properties are set they may also be used in the calculation, such as PivotX or Scale. Which ones to include will depend on how the specific game stores and calculates its window positions.
These functions (and the properties they use in [TargetConfigFormat]) are hard-coded and can not themselves be customized. Check the generated default profiles for different games (usually near the bottom of the MMOGO_Game_Base.ini file) for what is available and examples of their use. If you find need for a function that is not included, you will unfortunately need to use multiple variables along with arithmetic and conditional operators within variable expansion blocks to achieve the same effect.
You can have the application automatically launch a game along with whichever Profile you first load. You can also set the Window name for the target game, so the menus will be moved and resized along with the game window, and force the game window to be a full-screen window instead of “true” full screen if needed so the menus can actually show up over top of the game.
There are various other system options you can set like how long a “tap” vs a “short hold” is, mouse cursor/wheel speed, gamepad deadzones and thresholds, whether this app should automatically quit when done playing the game, and what the name of this application’s window should be (so you could set Discord to believe it is a game, which is nice if you want to let people know you are playing EQ emus since Discord doesn’t recognize old EQ clients for some reason). Check the comments in the generated MMOGO_Core.ini for more information on these and other settings.