# ConfigManager > **Relevant source files** > * [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java) ## Purpose and Scope The `ConfigManager` system is responsible for managing all persistent user preferences in the MouseMacros application. It handles loading, saving, and providing access to configuration settings that control application behavior across categories including appearance, storage, execution, and hotkey mappings. The configuration is persisted as a JSON file (`config.cfg`) in the platform-specific application data directory. For runtime state management such as window sizes and recent directories, see [CacheManager](CacheManager). For details on individual configuration categories and their effects, see [Configuration Files and Settings](Configuration-Files-and-Settings). **Sources:** [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L1-L133](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L1-L133) --- ## Configuration System Overview The following diagram shows how `ConfigManager` fits into the configuration persistence architecture: ```mermaid flowchart TD ConfigManager["ConfigManager"] ConfigClass["Config (inner class)"] GsonInstance["Gson (pretty-printed)"] FileUtil["FileUtil"] ConfigDir["CONFIG_DIR"] ConfigFile["config.cfg (JSON)"] SettingsDialog["SettingsDialog"] MacroSettingsDialog["MacroSettingsDialog"] MainFrame["MainFrame"] ComponentUtil["ComponentUtil"] Localizer["Localizer"] MacroManager["MacroManager"] StaticBlock["static { } block"] LoadConfig["loadConfig()"] StaticBlock --> FileUtil StaticBlock --> ConfigFile LoadConfig --> ConfigFile LoadConfig --> GsonInstance LoadConfig --> ConfigClass ConfigManager --> ConfigFile ConfigManager --> FileUtil SettingsDialog --> ConfigManager MacroSettingsDialog --> ConfigManager MainFrame --> ConfigManager ComponentUtil --> ConfigManager Localizer --> ConfigManager MacroManager --> ConfigManager subgraph Initialization ["Initialization"] StaticBlock LoadConfig StaticBlock --> LoadConfig end subgraph subGraph2 ["Consuming Components"] SettingsDialog MacroSettingsDialog MainFrame ComponentUtil Localizer MacroManager end subgraph subGraph1 ["Storage Layer"] FileUtil ConfigDir ConfigFile FileUtil --> ConfigDir end subgraph subGraph0 ["Configuration Management"] ConfigManager ConfigClass GsonInstance ConfigManager --> ConfigClass ConfigManager --> GsonInstance end ``` **Sources:** [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L14-L29](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L14-L29), [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L46-L76](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L46-L76) --- ## Config Data Structure The `Config` inner class [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L31-L44](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L31-L44) represents the complete configuration state. All fields have default values that are used when creating a new configuration. ### Configuration Fields | Field | Type | Default Value | Description | | --- | --- | --- | --- | | `followSystemSettings` | `boolean` | `true` | When enabled, language and theme follow OS settings | | `lang` | `String` | `"zh_cn"` | Language code (e.g., `en_us`, `zh_cn`, `ja_jp`) | | `enableDarkMode` | `boolean` | `false` | Dark theme toggle (only used when `followSystemSettings` is false) | | `enableDefaultStorage` | `boolean` | `false` | Use default path for macro file operations | | `defaultMmcStoragePath` | `String` | `""` | Default directory for saving/loading `.mmc` files | | `enableQuickMode` | `boolean` | `false` | Skip recorded delays during playback | | `allowLongStr` | `boolean` | `false` | Allow tooltips to display long strings | | `readjustFrameMode` | `String` | `RFM_STANDARDIZED` | Window resize behavior: `MIXED`, `STANDARDIZED`, or `MEMORIZED` | | `keyMap` | `Map` | `new HashMap<>()` | Hotkey mappings (e.g., `"keyRecord"` → `"F2"`) | | `enableCustomMacroSettings` | `boolean` | `false` | Use per-macro execution settings instead of global | | `repeatTime` | `int` | `1` | Number of times to repeat macro playback | | `repeatDelay` | `double` | `0` | Delay in seconds between macro repetitions | **Sources:** [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L31-L44](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L31-L44) --- ## Readjust Frame Mode Constants The `ConfigManager` defines three constants [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L21-L23](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L21-L23) for controlling window resizing behavior when language changes: | Constant | Value | Behavior | | --- | --- | --- | | `RFM_MIXED` | `"MIXED"` | Uses cached sizes when available, otherwise standardized sizes | | `RFM_STANDARDIZED` | `"STANDARDIZED"` | Always calculates new recommended size based on content | | `RFM_MEMORIZED` | `"MEMORIZED"` | Always uses cached historical window sizes | These constants are referenced by `ComponentUtil` when applying language changes to determine whether to resize windows. **Sources:** [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L21-L23](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L21-L23) --- ## Static Initialization and Path Resolution The `ConfigManager` initializes during class loading through a static block [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L25-L29](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L25-L29) : ```mermaid sequenceDiagram participant JVM participant ConfigManager participant FileUtil participant Filesystem JVM->>ConfigManager: "Load class" ConfigManager->>ConfigManager: "Enter static block" ConfigManager->>FileUtil: "getLocalStoragePath()" FileUtil->>Filesystem: "Detect OS, resolve path" Filesystem-->>FileUtil: "Platform-specific path" FileUtil-->>ConfigManager: "Path object" ConfigManager->>ConfigManager: "Set CONFIG_DIR" ConfigManager->>ConfigManager: "Construct CONFIG_PATH" ConfigManager->>ConfigManager: "Call loadConfig()" ConfigManager->>Filesystem: "Read config.cfg" Filesystem-->>ConfigManager: "JSON string or null" ConfigManager->>ConfigManager: "Deserialize or create default" ConfigManager->>ConfigManager: "Assign to config field" ``` The `CONFIG_DIR` field [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L15](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L15-L15) stores the platform-specific application data directory (e.g., `%LOCALAPPDATA%/MouseMacros` on Windows), while `CONFIG_PATH` [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L17](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L17-L17) points to the `config.cfg` file within that directory. **Sources:** [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L25-L29](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L25-L29), [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L15-L17](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L15-L17) --- ## Configuration Loading The `loadConfig()` method [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L49-L63](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L49-L63) implements the configuration loading logic with fallback behavior: ```mermaid flowchart TD Start["loadConfig()"] ReadFile["FileUtil.readFile(CONFIG_PATH)"] CheckNull["json == null or empty?"] ParseJson["gson.fromJson(json, Config.class)"] CreateDefault1["new Config()"] SaveDefault1["saveConfig(cfg)"] CreateDefault2["new Config()"] SaveDefault2["saveConfig(_config)"] Return1["Return cfg"] Return2["Return parsed Config"] Return3["Return _config"] Start --> ReadFile ReadFile --> CheckNull ReadFile --> CreateDefault2 CheckNull --> CreateDefault1 CheckNull --> ParseJson CreateDefault1 --> SaveDefault1 SaveDefault1 --> Return1 ParseJson --> Return2 CreateDefault2 --> SaveDefault2 SaveDefault2 --> Return3 ``` **Loading Logic:** 1. Attempts to read `config.cfg` using `FileUtil.readFile()` 2. If file is missing or empty, creates a new `Config` with defaults and saves it 3. If file exists, deserializes JSON using Gson 4. On any `IOException`, creates and saves a default configuration 5. Returns the loaded or newly created `Config` object The `reloadConfig()` method [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L46](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L46-L46) provides a way to refresh the static `config` field after external changes. **Sources:** [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L46-L63](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L46-L63) --- ## Configuration Saving The `saveConfig()` method [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L66-L76](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L66-L76) persists configuration changes to disk: ```mermaid flowchart TD Input["Config object"] EnsureDir["Create CONFIG_DIR if needed"] Serialize["gson.toJson(config)"] WriteFile["FileUtil.writeFile(CONFIG_PATH, json)"] HandleError["e.printStackTrace()"] Input --> EnsureDir EnsureDir --> Serialize Serialize --> WriteFile WriteFile --> HandleError ``` **Saving Process:** 1. Ensures the parent directory (`CONFIG_DIR`) exists, creating it if necessary [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L69-L70](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L69-L70) 2. Serializes the `Config` object to pretty-printed JSON using Gson [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L71](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L71-L71) 3. Writes the JSON string to `config.cfg` using `FileUtil.writeFile()` [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L72](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L72-L72) 4. Catches and prints any `IOException` that occurs [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L73-L75](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L73-L75) The Gson instance [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L18](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L18-L18) is configured with `.setPrettyPrinting()` to make the JSON file human-readable. **Sources:** [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L66-L76](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L66-L76), [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L18](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L18-L18) --- ## Available Languages Detection The `getAvailableLangs()` method [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L79-L132](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L79-L132) detects all available language files at runtime, supporting both development (source directory) and production (JAR file) environments. ### Detection Strategy ```mermaid flowchart TD Start["getAvailableLangs()"] DevMode["Localizer.isDevMode()"] DevPath["List files in 'lang' directory"] JarResource["Get lang/ resource URL"] CheckProtocol["dirURL protocol?"] JarMode["Read JAR entries"] FileMode["List directory files"] ExtractNames["Extract .json filenames"] ReturnArray["Return String[] array"] Start --> DevMode DevMode --> DevPath DevMode --> JarResource DevPath --> ExtractNames JarResource --> CheckProtocol CheckProtocol --> JarMode CheckProtocol --> FileMode JarMode --> ExtractNames FileMode --> ExtractNames ExtractNames --> ReturnArray ``` ### Development Mode When `Localizer.isDevMode()` returns `true` [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L81-L91](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L81-L91) : * Lists files in the `lang` directory using `FileUtil.listFileNames()` * Strips `.json` extensions to get language codes ### Production Mode (JAR) When running from a JAR [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L93-L129](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L93-L129) : **JAR Protocol Handling:** 1. Gets the `lang/` resource URL from the class loader [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L94](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L94-L94) 2. Checks if the protocol is `"jar"` [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L95](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L95-L95) 3. Extracts the JAR file path from the URL [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L96-L103](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L96-L103) 4. Opens the JAR file and enumerates all entries [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L104-L105](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L104-L105) 5. Filters entries starting with `"lang/"` and ending with `".json"` [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L108](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L108-L108) 6. Extracts the language code from each entry name [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L109](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L109-L109) **File Protocol Fallback:** * If the protocol is `"file"` [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L114](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L114-L114) lists files in the directory directly * Filters for `.json` files [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L116](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L116-L116) **Platform-Specific Path Handling:** * On Windows, removes leading `/` from JAR paths [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L101-L103](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L101-L103) * URL-decodes the path to handle special characters [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L100](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L100-L100) **Sources:** [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L79-L132](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L79-L132) --- ## Integration Points The following diagram shows how various components interact with `ConfigManager`: ```mermaid flowchart TD SettingsDialog["SettingsDialog"] MacroSettingsDialog["MacroSettingsDialog"] MainFrame["MainFrame"] ConfigField["ConfigManager.config"] LoadMethod["loadConfig()"] SaveMethod["saveConfig(Config)"] ReloadMethod["reloadConfig()"] LangsMethod["getAvailableLangs()"] AppearanceFields["followSystemSettings
lang
enableDarkMode
allowLongStr
readjustFrameMode"] StorageFields["enableDefaultStorage
defaultMmcStoragePath"] ExecutionFields["enableQuickMode
enableCustomMacroSettings
repeatTime
repeatDelay"] HotkeyFields["keyMap"] ThemeSystem["ComponentUtil
(Theme Application)"] LocalizationSystem["Localizer
(Language Loading)"] FileSystem["MacroManager
(File Operations)"] PlaybackSystem["MacroManager
(Playback Execution)"] HotkeySystem["GlobalMouseListener
(Hotkey Detection)"] SettingsDialog --> ConfigField MacroSettingsDialog --> ConfigField MainFrame --> ConfigField SettingsDialog --> SaveMethod MacroSettingsDialog --> SaveMethod SettingsDialog --> LangsMethod ConfigField --> AppearanceFields ConfigField --> StorageFields ConfigField --> ExecutionFields ConfigField --> HotkeyFields AppearanceFields --> ThemeSystem AppearanceFields --> LocalizationSystem StorageFields --> FileSystem ExecutionFields --> PlaybackSystem HotkeyFields --> HotkeySystem subgraph subGraph3 ["Consuming Systems"] ThemeSystem LocalizationSystem FileSystem PlaybackSystem HotkeySystem end subgraph subGraph2 ["Config Fields Groups"] AppearanceFields StorageFields ExecutionFields HotkeyFields end subgraph subGraph1 ["ConfigManager API"] ConfigField LoadMethod SaveMethod ReloadMethod LangsMethod end subgraph subGraph0 ["UI Components"] SettingsDialog MacroSettingsDialog MainFrame end ``` ### Read Access Patterns Components typically access configuration directly through the static `config` field: * `ConfigManager.config.followSystemSettings` * `ConfigManager.config.lang` * `ConfigManager.config.enableDarkMode` * etc. ### Write Access Patterns Components modify configuration and persist changes: 1. Read current config: `Config cfg = ConfigManager.config` 2. Modify fields: `cfg.lang = "en_us"` 3. Save changes: `ConfigManager.saveConfig(cfg)` 4. Optionally reload: `ConfigManager.reloadConfig()` **Sources:** [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L19](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L19-L19), [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L46](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L46-L46), [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L66-L76](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L66-L76) --- ## JSON File Format The `config.cfg` file uses JSON format with pretty-printing enabled. Example structure: ```json { "followSystemSettings": true, "lang": "zh_cn", "enableDarkMode": false, "enableDefaultStorage": false, "defaultMmcStoragePath": "", "enableQuickMode": false, "allowLongStr": false, "readjustFrameMode": "STANDARDIZED", "keyMap": { "keyRecord": "F2", "keyStop": "F3", "keyPlay": "F4", "keyAbort": "F5" }, "enableCustomMacroSettings": false, "repeatTime": 1, "repeatDelay": 0.0 } ``` The file is located at `CONFIG_DIR\config.cfg`, where `CONFIG_DIR` resolves to platform-specific paths (see [File and Path Utilities](File-and-Path-Utilities) for path resolution details). **Sources:** [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L18](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L18-L18), [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L71](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L71-L71) --- ## Usage Examples ### Reading Configuration ``` // Access appearance settings boolean useDarkMode = ConfigManager.config.enableDarkMode; String currentLang = ConfigManager.config.lang; // Access execution settings boolean quickMode = ConfigManager.config.enableQuickMode; int repeatCount = ConfigManager.config.repeatTime; // Access storage settings boolean useDefaultPath = ConfigManager.config.enableDefaultStorage; String defaultPath = ConfigManager.config.defaultMmcStoragePath; ``` ### Modifying Configuration ``` // Get current config Config cfg = ConfigManager.config; // Modify settings cfg.lang = "en_us"; cfg.enableDarkMode = true; cfg.repeatTime = 5; // Persist changes ConfigManager.saveConfig(cfg); // Reload if needed (updates static field) ConfigManager.reloadConfig(); ``` ### Detecting Available Languages ``` // Get all available language files String[] langs = ConfigManager.getAvailableLangs(); // Returns: ["en_us", "zh_cn", "ja_jp", "ko_kr", "ru_ru", "es_es", "fr_fr"] // Populate UI dropdown for (String lang : langs) { comboBox.addItem(lang); } ``` **Sources:** [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L19](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L19-L19), [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L66-L76](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L66-L76), [src/io/github/samera2022/mouse_macros/manager/ConfigManager.java L79-L132](https://github.com/Samera2022/MouseMacros/blob/1eb6620b/src/io/github/samera2022/mouse_macros/manager/ConfigManager.java#L79-L132)