# Changelog Все заметные изменения проекта. Формат — [Keep a Changelog](https://keepachangelog.com/ru/1.1.0/), версии — [SemVer](https://semver.org/lang/ru/). ## [Unreleased] ## [0.11.0] — 2026-08-03 ### Добавлено - **Лимит яркости экрана** (Настройки → Экран) — два независимых лимита, для сети и для батареи: яркость выше лимита плавно (за ~10 с, без скачка) сводится обратно. Бережёт OLED-панель от выгорания. Заблокировать сам ползунок Windows невозможно — только вернуть после факта, о чём честно написано в настройке. Вместо ультиматума — вежливый торг: раз в минуту разрыв сокращается вдвое, а если пользователь после нашего шага снова поднял яркость — приложение уступает и не трогает её 2 часа (пауза сбрасывается блокировкой, сном, сменой питания и перезапуском). Понижение ниже лимита не трогается вовсе — приложение никогда не поднимает яркость. При включённой адаптивной яркости Windows фича не работает и объясняет причину прямо в настройках. Опция «Запоминать яркость» при этом хранит намерение пользователя: превышение лимита не запоминается вообще (а не обрезается), восстановление клампится к текущему лимиту. Тайминги правятся в config.json (`BrightnessRampMs`, `BrightnessConvergeMs`, `BrightnessBackoffMin` и др.) (XIC-29). ### Изменено - **Вкладка «Экран» видна всегда** — на ней поселилась яркость (лимиты + переехавший из «Общих» тумблер «Запоминать яркость экрана»), поэтому фича «Управление частотой» теперь скрывает только раздел частоты внутри вкладки, а не вкладку целиком (XIC-29). - **Сведения о железе на вкладке «О программе»** — рядом с моделью появились версия BIOS с датой выпуска и серийный номер. Модель теперь показывается вместе с кодом платы («Xiaomi Book Pro 14 (TM2424)») — в отчётах о совместимости важен именно код. **Серийный номер закрыт по умолчанию**, видны только последние четыре знака: скриншот этой вкладки люди отправляют в тему совместимости, и уникальный идентификатор устройства там ни к чему. Клик по нему раскрывает значение — до следующего открытия окна. Поля, которых прошивка не отдаёт, просто не показываются (XIC-3). - **Мультимедиа и калькулятор в действиях клавиш** — на любой слот (Mi-кнопка, AI-клавиша, «Настройки», «Проекция») теперь можно назначить воспроизведение/паузу, следующий и предыдущий трек, остановку и калькулятор. Работает с любым плеером: медиа-клавишу получает владелец медиа-сессии Windows, отдельной интеграции не требуется. Громкость намеренно не добавляли — для неё на клавиатуре есть отдельные физические кнопки (XIC-27). - **Удержание Mi-кнопки стало настраиваемым** — раньше долгое нажатие всегда открывало быструю панель, теперь это обычный слот с тем же списком действий, что клик и двойной клик. Можно, например, повесить панель на одиночный клик, а «В дорогу» — на удержание. Существующие настройки не меняются: у кого удержание не задано, оно по-прежнему открывает панель. Значение «Ничего» гасит жест целиком — долгое нажатие тогда отрабатывает как обычный клик, а не пропадает впустую (XIC-28). ## [0.10.0] — 2026-08-02 ### Добавлено - **Кнопка «Buy me a coffee»** на вкладке «О программе», после ссылки «Все релизы» — официальный фирменный ассет, клик открывает страницу автора. Никаких сборов внутри приложения, только внешняя ссылка (XIC-26). - **Проверка обновлений** — раз в сутки приложение спрашивает у GitHub, вышла ли новая версия, и показывает тост со ссылкой на страницу релиза; отметка о новой версии появляется и на вкладке «О программе». Обновление **не устанавливается само**: запущенный exe нельзя перезаписать, а приложение и есть тот файл, который заменяют, поэтому любое «обновить сейчас» потребовало бы сторожевого процесса — мы такое не берём. Обновиться можно со страницы релиза или командой `winget upgrade Oksion.XiControl`. Тумблер «Проверять обновления» (Настройки → Общие, по умолчанию включён) гасит фичу целиком: выключен — приложение **не делает ни одного сетевого запроса**, а на «О программе» появляется кнопка «Проверить обновления» для разовой проверки по нажатию. Тост показывается один раз на версию: про пропущенную больше не напоминаем, про следующую — напомним (XIC-20). - **Пояснение к порогу «беречь батарею»** — под выбором уровня в Настройки → Батарея появилась заметка «для кого этот уровень», меняющаяся вместе с выбором: 40–50% («ноутбук вместо десктопа»), 60–70% («компромисс»), 80% («баланс»). Раньше пользователь видел только голый список процентов и выбирал наугад. Часы автономной работы намеренно не обещаем — они зависят от яркости, режима и нагрузки (XIC-25). - **Мёртвая зона у нижнего края тачпада** — новая вкладка настроек «Тачпад»: тумблер и высота полосы (8/10/12/15/20 мм, по умолчанию 12). Лечит ложные срабатывания от лежащей ладони. Driver-free: штатная «curtain zone» Windows Precision Touchpad (`SuperCurtainBottom`, единицы — сотые доли миллиметра), одна машинная настройка в реестре, никакого фильтр-драйвера и перехвата ввода. Что именно делает опция — сказано в UI прямо: гасится **начало** касания, то есть если палец коснулся панели сразу в этой полосе, курсор не сдвинется и тапа не будет, а жест, начатый выше, работает до самого низа; **нажатие в зоне по-прежнему срабатывает** (проверено на TM2424). Настройка применяется сразу — перезапуском узла тачпада, без перезахода в сеанс. Зона живёт внутри защиты от ладони, поэтому при «максимальной чувствительности» тачпада в параметрах Windows она не работает — приложение об этом честно предупреждает. По умолчанию выключена, реестр правится только по явному переключению; выключение **удаляет** значение, а не пишет ноль (XIC-24). - **«Удерживать частоту»** — авто-герцовка теперь возвращает заданную частоту, если режим экрана сменил кто-то извне: пользователь руками в параметрах Windows, чужая утилита, драйвер после сброса. Раньше `RefreshRateGuard` просыпался только на события питания (`Resume`/`StatusChange`), и настройка тихо переставала держаться до следующего втыкания зарядки. Опроса не добавлено — только событие `SystemEvents.DisplaySettingsChanged` через тот же дебаунс 1.5 с, что и питание. Тумблер — Настройки → Экран, под авто-частотой; работает поверх неё (без авто-частоты возвращать нечего), поэтому пока она выключена — тумблер погашен. По умолчанию `HoldRefreshRate: false`: поведение существующих установок не меняется. Ожидаемый побочный эффект — пока опция включена, сменить частоту через параметры Windows не выйдет (вернём быстрее, чем Windows спросит «Сохранить изменения?»); для ручной смены тумблер надо выключить (XIC-22). ### Исправлено - **Автозапуск ломался на машине с несколькими учётками.** Задача Планировщика называлась просто `XiControl` — одна на всю машину, поэтому второй пользователь, включив автозапуск, перезаписывал задачу первого, и у того она молча начинала стартовать чужой сеанс. Теперь имя включает SID (`XiControl_S-1-5-21-…`), у каждой учётки своя задача. Существующая задача старого образца распознаётся как включённый автозапуск и при следующем переключении переносится на новое имя — двух задач разом не остаётся. Чужая задача не читается как наша и не удаляется никогда. - **Самопочинка автозапуска не замечала обновление.** Раньше задача чинилась, только если exe пропал; типовой для portable случай — старая копия на месте, а запускаетесь уже из новой папки — проходил мимо, и Windows поднимала прежнюю версию («обновление не применилось»). Теперь сверяется ещё и версия файла из задачи с версией текущей сборки. Дев-сборки (`0.0.0`) в сверке не участвуют — иначе запуск локальной сборки переписывал бы пользовательскую задачу на себя. - **Приложение не поднималось при быстром переключении пользователей** — возврат в сеанс не является входом, а триггер был только на вход. Добавлен `SessionStateChangeTrigger` с `ConsoleConnect` (`SessionUnlock` намеренно не берём: он срабатывал бы на каждую разблокировку экрана) (XIC-23). - **Авто-герцовка меняла частоту основного экрана, а не панели ноутбука.** `EnumDisplaySettings`/ `ChangeDisplaySettings` с `null` адресуют ОСНОВНОЙ дисплей: стоило назначить основным внешний монитор, и отключение зарядки уводило на пониженную частоту его, а панель ноутбука оставалась на 120 Гц — то есть батарея не экономилась, а картинка портилась там, где не просили. Теперь встроенная панель ищется явно через CCD (`QueryDisplayConfig` по активным путям, признак `DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL`), её GDI-имя передаётся в `EnumDisplaySettingsEx`/ `ChangeDisplaySettingsEx`, и внешние мониторы больше не затрагиваются. Имя перечитывается при каждом применении — при переподключении монитора GDI-имена перетасовываются, и кэш дал бы тот же класс багов. Если панели нет среди активных путей (крышка закрыта, «только второй экран»), не меняется ничего: отката на «основной экран» намеренно нет, он вернул бы исходную ошибку. Driver-free, чистый Win32 (XIC-21). ### Изменено - `SystemPowerEvents` переименован в **`SystemEventsSource`** и отдаёт два узких шва — `IPowerEvents` (питание) и новый `IDisplayEvents` (смена режима экрана). Скрытое окно-маршалер внутри нужно ровно одно, поэтому в DI это один синглтон под двумя интерфейсами, а `Dispose` сделан идемпотентным. `DisplaySettingsChanged` маршалится в UI-поток по той же причине, что и события питания: WinForms-таймер дебаунса, стартованный с фонового потока `SystemEvents`, не тикает никогда. ## [0.9.0] — 2026-08-01 ### Добавлено - **Загрузка GPU в «Мониторе»** — новый ряд между CPU и RAM: процент + график, под ним частота и мощность (`2450 МГц · 21.4 Вт`), в мини-виде только процент. Данные — через **Intel IGCL**, user-mode API графического драйвера (`ControlLib.dll` приезжает со штатным драйвером Intel и лежит в System32): driver-free, прав администратора для чтения не нужно, опрос стоит 47 мкс и живёт в том же таймере 1 Гц, что и остальные графики. Загрузка сверена с собственным счётчиком Windows (`\GPU Engine(*)\Utilization Percentage`) — сходится. Температуру и обороты вентиляторов IGCL на встроенном GPU не даёт (пути только для дискретных Arc), поэтому в ряду их нет. Инициализация ленивая: пока виджет не открыт, IGCL в процесс не подгружается. Не Intel (в т.ч. AMD-модели) — ряд просто не появляется, виджет остаётся прежним. Разбор раскладки телеметрии и замеры — [docs/09-power-monitoring.md](docs/09-power-monitoring.md) (XIC-18). - **`OwlIgnoreDisplay` в config.json** — «Режим совы» умеет держать бодрой только систему, отпуская экран: с `true` он больше не выставляет `ES_DISPLAY_REQUIRED`, и экран гаснет по обычному таймауту схемы питания. Для сценария «комп не должен уснуть ради удалённого доступа», где подсвеченная матрица горит впустую. Крышку опция не затрагивает — закрытая крышка на сети всё так же не усыпляет; медиаплееры запрашивают удержание экрана сами, так что фильмы не прерываются. По умолчанию `false` — поведение существующих установок не меняется, пока поле не добавят руками. ### Исправлено - **Реакции на смену питания снова работают: авто-герцовка, профили питания, ре-арм заряда, «в дорогу».** .NET доставляет `SystemEvents.PowerModeChanged` с фонового MTA-потока без насоса сообщений, а дебаунс guard-ов — WinForms-таймер: стартованный с такого потока, он не тикает никогда. Симптом выглядел парадоксально: OSD «От сети/От батареи» показывался (его путь единственный маршалился в UI-поток), а частота экрана, режим по питанию и ре-арм лимита заряда после сна/смены питания молча не срабатывали. Теперь `SystemPowerEvents` маршалит Resume/StatusChange в UI-поток скрытым окном (паттерн «все события — в UI-поток», как у клавиш прошивки); Suspend и SessionEnding намеренно остаются синхронными — после них насос может не успеть, а ре-арм EC перед сном должен случиться немедленно. Прямые пути (`Reapply()` на старте и при включении опций) работали всегда — сломана была именно реакция на событие. - **Статус питания `Unknown` больше не считается батареей.** Все проверки «сеть или батарея» сведены в `PowerLine.IsOnline`: батарея — только явный `Offline`. Раньше редкий `Unknown` (бывает сразу после resume) трактовался как батарея и мог зря уронить экран на батарейную частоту при воткнутом зарядном. - **Порог заряда в панели и меню больше не расходится с железом.** Если порог менял кто-то снаружи (Xiaomi PC Manager, чужая утилита), быстрая панель продолжала показывать старое значение — она рисовала из конфига и прошивку не перечитывала вовсе. Теперь порог подтягивается из прошивки в момент показа панели и пересборки меню трея (`AppController.SyncCareFromFirmware()`): фонового опроса не добавилось, читаем только когда UI открывают. Принимается только валидный порог < 100 %: показание «100» неотличимо от транзиента после сна/смены питания (EC теряет лимит до ре-арма `ChargeGuard`) и не принимается — иначе панель, открытая сразу после resume, молча выключала бы защиту. Прошивка не ответила → остаётся значение конфига; при активном «В дорогу» примирение не выполняется. Заодно исправлена та же ошибка в меню трея: галочка считалась от живого значения, а процент в подписи брался из конфига, из-за чего меню могло показать «беречь 60 %» при 50 % в железе. Разбор — [docs/12-charge-levels.md](docs/12-charge-levels.md) (XIC-17). ## [0.8.0] — 2026-07-29 ### Добавлено - **Выбор порога заряда 40/50/60/70/80/100%** — команда защиты заряда `MIFS 0x10/0x02` оказалась многоуровневой, а не бинарной (переоткрыто 2026-07-29, разбор — [docs/12-charge-levels.md](docs/12-charge-levels.md)): пикер порога в Настройки → Батарея; панель/меню/OSD показывают реальный выбранный %, тумблер в панели остаётся бинарным «X% ↔ 100%»; `ChargeGuard` переармливает выбранный порог. Старые `config.json` мигрируются сами (дефолт 80 = прежнее поведение). На моделях без granular-уровней прошивка отвергает код — выбор откатывается с честной ошибкой, 80/100 работают всегда (XIC-4). ### Изменено - Локальная сборка помечается версией `0.0.0-dev` (реальную версию в релизные билды подставляет CI из тега) — самосборный билд больше не выдаёт себя за релизный. ### Исправлено - **Иконки режимов «Эко» и «Тихий» были перепутаны местами** с самых первых версий: Эко рисовался луной со звёздами, Тихий — листом. Теперь как задумано: **лист — Эко** (экономия), **луна — Тихий** (тишина). Поменялись местами и рисунок, и анимация (покачивание листа ↔ мерцание звёзд), и акцент ячейки в панели (зелёный ↔ сизый) — в панели, OSD и трее. Первопричина была в двусмысленной строке спецификации иконок «лист (эко/тихий)» — она переписана однозначно (XIC-14). - **Окно настроек не переживало смену разрешения или масштаба экрана**: размеры шрифтов оставались от старого DPI и расходились с разметкой — заметнее всего обрезался пояснительный текст под названиями опций (высота карточки считается под него один раз при постройке). Частый сценарий — удалённое подключение, которое подгоняет разрешение под клиента. Теперь окно пересобирается под новый масштаб: ловим и `WM_DPICHANGED` (как это давно делают панель и «Монитор»), и смену разрешения через `DisplaySettingsChanged`. Заодно шрифт окна переведён на `ScaledFonts` — раньше он один задавался в пунктах мимо общего масштабирования (XIC-15). ## [0.7.0] — 2026-07-28 ### Добавлено - **HTTP API для локальной сети** — опциональный веб-API для управления с телефона или из автоматизаций Home Assistant (по умолчанию **выключен**). Маршруты: `GET /status` (режим, защита заряда, «В дорогу», сова, % заряда, зарядка, ватты, здоровье) и `POST /mode|care|travel|owl`. Хост на `HttpListener` (http.sys, без ASP.NET Core) поднимается только при включённой фиче — выключено = 0 нагрузки на CPU. Bind `127.0.0.1` по умолчанию; доступ из сети — отдельным тумблером с правилом брандмауэра `LocalSubnet`. Авторизация Bearer-токеном (хранится только SHA-256, constant-time сверка), жёсткий белый список команд (настройки/автозапуск/запуск программ через API невозможны). Настройки — в `%ProgramData%\XiControl\api.json` под ACL «запись только администраторам» + проверка владельца при чтении: включить API или подменить токен правкой `config.json` нельзя. Новая вкладка настроек «HTTP API» (порт, генерация токена, пер-командные разрешения) (XIC-13). - **Кнопка «Настройки» в шапке быстрой панели** — шестерёнка слева от «Монитора» и крестика: открывает окно настроек прямо с панели, не заходя в меню трея. Заодно значок «Общие» в навигации настроек и эта кнопка перерисованы честной шестерёнкой (силуэт с зубьями вместо «солнышка» из лучей), рисуются общим примитивом (XIC-12). - **«В дорогу» с заблокированного экрана — теперь с обратной связью** — кнопка и раньше работала под блокировкой (OSD просто не виден на локскрине), теперь при заблокированной сессии переключение подтверждается коротким джинглом (восходящий — включено, нисходящий — выключено) и toast-уведомлением, которое Windows показывает прямо на экране блокировки. В обычном режиме — по-прежнему только OSD, без звука и уведомлений. Рисовать на самом локскрине driver-free нельзя (secure desktop) — выбран штатный канал (XIC-11). - **Подсказки на панели и «Мониторе»** — наведи и задержи курсор на иконочной ячейке панели (в дорогу, герцовка, тачпад, сенсорный экран, сова, «Монитор», крестик) или кнопке заголовка «Монитора» — всплывёт подсказка в тон палитры флайаутов (уважает светлую/тёмную тему, задержка ~0.5 с как у системных). Плюс окна панели и «Монитора» теперь пересчитывают геометрию при переносе на монитор с другим масштабом (`WM_DPICHANGED`, PerMonitorV2) (XIC-8). - **Настраиваемые тайминги в config.json** — три новых поля `AppConfig` (правятся вручную, применяются при следующем запуске): `MiHoldMs` (порог удержания Mi-кнопки, дефолт 400), `MiDoubleClickMs` (окно двойного клика, дефолт 300), `OsdDurationMs` (сколько висит OSD, дефолт 2800; «Авто»-режим — на 600 мс дольше). Значения клэмпятся снизу, чтобы кривой ввод не сломал жест / не сделал всплывашку мгновенной. Дефолты = прежним константам — поведение «из коробки» не меняется (XIC-1). - **Вкладка «Функции» в настройках** — отдельная группа «что показывать»: сюда переехали переключатели доступности «Режима совы», тачпада и сенсорного экрана (были в «Общих»), и добавлен новый — **«Управление частотой экрана»**. Выключишь — авто-герцовка и весь UI вокруг неё (пункт меню, ячейка панели, вкладка «Экран») исчезают целиком: для тех, кому герцовка не нужна. Активная авто-герцовка при этом гасится (как скрытие «совы» гасит активный «Не спать»): сначала возвращаем сеть-частоту, если «батарейная» успела примениться — чтобы не остаться на 60 Гц без UI, — затем снимаем флаг. - **Тачпад вкл/выкл** — новое действие для любой клавиши (Настройки → Клавиши), ячейка в быстрой панели (левее авто-герцовки, подсвечивается когда тачпад выключен) и OSD с перечёркнутой иконкой в стиле микрофона. Driver-free: чистый SetupAPI/CfgMgr32 — отключается родительский узел тачпада («HID на шине I2C»), ровно как «Отключить устройство» в Диспетчере; прошивочный TPLock (WMI 0x0C) на TM2424 к железу не подключён. Отключение **не переживает перезагрузку** (без флага PERSIST) — намеренно: тачпад всегда возвращается сам. - **Окно «Настройки»** в стиле Windows 11 (слева навигация по группам, справа прокручиваемые опции) — заменяет длинное подменю в трее пунктом «Настройки…». Вкладки: Общие (язык, автозапуск, «Запоминать яркость», «Режим совы»), Батарея (звук готовности «В дорогу» + свой WAV), Экран (авто-герцовка + значения Гц), Производительность (видимость Эко/Полной, «Режим при старте» с профилями), Клавиши (Mi-кнопка, клавиша «настройки», AI-клавиша), О программе (версия, модель, пути, ссылки). Часть опций, что раньше правились только в config.json (частоты Гц, программа AI-клавиши), теперь есть в UI. Быстрые тумблеры (заряд, «в дорогу», сова, герцовка, монитор, режим) остаются в трее. Обычный WinForms + ручная отрисовка, тёмная/светлая тема по системе; окно создаётся лениво и между открытиями прячется — в фоне не работает. - **Сенсорный экран вкл/выкл** — то же, что тачпад, для тач-экрана ноутбука: действие для клавиши, ячейка в панели (левее тачпада, только если тачскрин присутствует) и OSD. Общая база `HidNodeToggle` (тачпад `U:0005`, тачскрин `U:0004`), без PERSIST. Вклад контрибьютора **@39ma** (PR #4). - **Мониторинг температуры** в «Мониторе» — строка-график «горячей точки», driver-free через Intel DPTF (WMI `EsifDeviceInformation`, максимум активных доменов). Горячая зона подсвечивается вишнёвым (порог от ACPI `CriticalTripPoint`). Тема раньше числилась закрытой как «невозможно» — переоткрыта. - **Мощность зарядника** — прошивка отдаёт номинал PD-адаптера в Вт (MIFS `0x10/06`, ADPW): ватты в зарядном OSD и строкой в «Мониторе». Плюс **бейдж-оверлей** поверх иконки заряда — красный «!» для слабого блока (ниже настраиваемого порога), серый «?» для не-PD (`ADPW=0`, напр. обычный 5 В); база иконки при этом продолжает нести лимит 80/100. Раньше «авто-детект слабой зарядки» был закрыт — ADPW его открыл. - **Здоровье батареи** — панель в Настройках → Батарея: износ (текущая/проектная ёмкость), число циклов, ёмкость Вт·ч. Штатные WMI-классы ACPI (`BatteryStaticData`/`BatteryFullChargedCapacity`/`BatteryCycleCount`) + прошивочный SOH1 (`0x10/01`) как фолбэк. Driver-free, только чтение. ### Изменено - **Переназначение клавиш переработано**: каждой клавише — своё действие независимо (Настройки → Клавиши). Слоты: одиночный и двойной клик Mi-кнопки, «Настройки», AI, «Проекция». Действия: цикл режимов, заряд 80/100, быстрая панель, сова, «Монитор», «В дорогу», системные Win+P / Параметры Windows / Copilot, запуск своей программы (путь + аргументы, `%ПЕРЕМЕННЫЕ%`), «Ничего». Двойной клик Mi = «Ничего» — жест отключён, одиночный мгновенный; удержание Mi всегда панель. Старые опции (`MiShortPress`, `MiDoubleClick`, `SettingsKey`, `AiKeyProgram`) мигрируют автоматически. - **«Запоминать яркость экрана» больше не требует «Профилей питания»** — стала самостоятельной опцией в «Общих»: яркость запоминается и восстанавливается по питанию сама по себе, а профили её по-прежнему используют, если включены. Держит тот же `PowerProfileGuard`. - **Мощность в «Мониторе» — через штатный Battery API** (`IOCTL_BATTERY_QUERY_STATUS`) вместо WMI `BatteryStatus`: IOCTL опрашивает ACPI `_BST` в момент вызова, поэтому показания больше не «застывают» без стороннего поллера (HWiNFO). Знаковый `Rate`. WMI остался мягким фолбэком (десктоп без батареи). - **Иконки заряда стали гибридными** — база несёт лимит (80 / 100 / «В дорогу»), а маленький SVG-бейдж поверх — качество зарядника (медленно / не-PD). Раньше «слабый зарядник» подменял всю иконку, теряя лимит; теперь видно оба измерения. Бейджи — отдельные SVG (правятся как иконки, не код). - **Проекция экрана** запускает `DisplaySwitch.exe` (тот же выбор, что Win+P) вместо синтетического Win+P, который из процесса с админ-правами Explorer молча глотал. - **OSD показываются дольше** (≈2.8 с, «Авто» — 3.4 с) — успеть прочитать. - **Панель быстрых настроек расширена ~на 10 %** — чтобы новая ячейка тачскрина не теснила ряд. - **Фирменная палитра** вынесена в [docs/10-colors.md](docs/10-colors.md); иконки тачскрина перерисованы под неё (монитор с подставкой, отличается от тачпада). ### Исправлено - **Прокрутка окна настроек** — полоса прокрутки теперь в тон тёмной/светлой темы (была всегда классическая светлая, чужеродная на тёмном окне); на вкладке «Производительность» больше не выскакивает горизонтальная полоса от строк профилей питания; колесо мыши над закрытым выпадающим списком прокручивает страницу, а не меняет значение (язык/частоту). - **Отключение сенсорного экрана валило контроллер шины** — на Meteor Lake (TM2424) HID-коллекция тачскрина подцеплена прямо к PCI-контроллеру (Intel Serial IO I2C / Touch Host Controller), и `HidNodeToggle` слепо гасил родителя коллекции — то есть весь контроллер, а не «сенсор»: тачскрин пропадал из системы «совсем». Теперь родитель гасим только если он не шина/контроллер (`PCI\…`), иначе целимся в саму HID-коллекцию; плюс жёсткая страховка в `Disable()` и игнор `PCI\…`-ID из кэша старой версии (на случай уже «отравленного» `TouchscreenDeviceId` в конфиге). Тачпада не касается — его родитель ACPI. - **Выбор действия клавиши «не сохранялся»** — комбо в «Клавишах» пересобирало окно на каждом шаге выбора (колёсико мыши, стрелки клавиатуры), дропдаун закрывался, и до дальних пунктов списка было не добраться. Теперь окно пересобирается только когда нужно показать/убрать поле команды у «Запустить программу…». Плюс необработанные коды клавиш других моделей теперь пишутся в `log.txt` — тестерам проще слать отчёты. - **Отключение тачпада не срабатывало на части моделей** — «мягкое» отключение узла (query-remove) другой софт с открытым хэндлом может заветировать; на TM2424 это не проявлялось. Теперь схема многоуровневая: мягкое отключение (с подавлением UI) → проверка фактического состояния → фолбэк через путь Диспетчера устройств (SetupAPI `DIF_PROPERTYCHANGE`, персистентный и вето не подверженный) — тогда приложение на старте само включает тачпад после перезагрузки (обещание «не залипает» сохраняется). Включение тоже по нарастающей: CM_Enable → SetupAPI → пересканирование PnP. Все развилки пишутся в `log.txt` — по нему видно, где именно не срослось на чужой машине (в т.ч. «тачпад не Precision — коллекция UP:000D_U:0005 не найдена»). - **Батарея заряжалась до 100% в выключенном/спящем ноутбуке при включённом «Беречь батарею»** — EC сбрасывает защиту на переходах питания, а гард переармливал её только после пробуждения. Теперь лимит переармливается и на входе в сон/гибернацию («Выключение» Windows 11 с быстрым запуском — это тоже гибернация) и при завершении сеанса (shutdown/restart) — EC уходит в «выключено» с уже взведённой защитой, как у оригинального MIControl. - **Автозапуск молча переставал работать после обновления/переноса exe** — задача планировщика указывала на старый путь. Теперь при старте приложение проверяет задачу и, если она смотрит на пропавший exe, пересоздаёт её на текущий. - **Первый клик по значку в трее ничего не делал** — самый первый показ `ContextMenuStrip` после старта проглатывался (ленивая инициализация хэндла/WMI/переднего плана). Теперь меню «прогревается» за экраном на первом холостом ходу цикла сообщений — первый настоящий клик открывает его сразу. - **Шрифты в OSD «разъезжались» после смены разрешения/масштаба экрана** — размеры брались от старого DPI. Переведены на пиксельные шрифты от текущего `DeviceDpi` (общий `ScaledFonts`), пропорции с геометрией держатся. ### Добавлено - **Режим «В дорогу»** — временно зарядить до 100% поверх «беречь 80%»: ячейка-чемоданчик в панели (слева от 80/100) и пункт меню. По достижении 100% — OSD «можно в дорогу» и джингл (переключатель «Звук готовности» в Настройках). При отключении зарядника режим сам сбрасывается — следующее подключение снова 80%; ручной выбор лимита тоже отменяет режим. При постоянном 100% кнопка неактивна. Иконка двухстатусная (без молнии / с мигающей молнией), driver-free (тот же WMI-канал заряда). Пилюли 80/100 показывают базовую настройку, «В дорогу» — оверрайд. - **Профили питания** — «Настройки → Режим при старте → Профили питания» (взаимоисключающе с «Восстанавливать последний» / «Закрепить текущий»). Отдельный режим производительности при зарядке и от батареи выбирается в меню («При зарядке» / «От батареи», пункт «Не менять»); применяется на старте и при каждой смене питания. Опционально (переключатель «Запоминать яркость», по умолчанию **выкл**) яркость экрана запоминается и восстанавливается для каждого состояния — выставил 80 % на зарядке, при следующем подключении вернётся 80 %. Driver-free: режим — WMI прошивки (`0x08`), яркость — WMI `WmiMonitorBrightness*` (ACPI-подсветка, тот же канал, что у Windows). Паттерн гарда (событие питания + дебаунс + окно «затишья» для захвата яркости), WMI-вызовы — в фоне, UI не блокируется. Мягко деградирует на панели без WMI-яркости. - **Авто-герцовка** — переключатель в меню трея и ячейка в быстрой панели: при подключении зарядки экран переводится на 120 Гц, при отключении — на 60 Гц (чистый Win32 `ChangeDisplaySettings`, прошивка не нужна). Частоты настраиваются в config.json (`AcRefreshRate`/`BatteryRefreshRate`); если точной частоты у панели нет — берётся ближайшая поддерживаемая при текущем разрешении. Держится после сна и смены питания (`RefreshRateGuard` по образцу ChargeGuard), применяется и на старте приложения; сама смена видеорежима — в фоновом потоке, UI не блокируется. OSD смены питания дописывает фактическую частоту («Заряд 85% • 120 Гц»). - **Компактные виды «Монитора»** — кнопка «вид» рядом с крестиком (или двойной клик по виджету) переключает по кругу: полный (графики) → мини (три индикатора Power / CPU / RAM в строку, без графиков) → только ватты («12 Вт», направление тока — цветом). В мини-виде рядом с кнопкой «вид» — кнопка «развернуть» сразу в полный. Выбранный вид запоминается (`MonitorView` в config.json), Esc закрывает виджет в любом виде. - **Pre-release сборки из main** — каждый push в main (и ручной запуск workflow «release») собирает оба exe и обновляет скользящий pre-release с тегом `pre`: всегда доступна свежая сборка, не дожидаясь релиза. Релизы по тегам `v*` и winget — как раньше. ### Безопасность - **Системные утилиты — абсолютным путём**: `netsh` (правило брандмауэра API) запускается полным путём из системной папки, а не через `PATH` — устойчивость к подмене (SonarCloud S4036). - **Таймаут на regex** разбора XML задачи автозапуска — ReDoS-гард (S6444). ### Разработка - **Публикация в winget** — теперь ставится одной командой: `winget install Oksion.XiControl`. - **Интеграция SonarCloud** (статический анализ + покрытие в CI, Quality Gate зелёный). - **README разделён** на английский (по умолчанию) и русский с переключателем языков; добавлен раздел про ложные срабатывания антивирусов. ## [0.7.0-pre] — 2026-07-13 ### Добавлено - **«Монитор»** — плавающий виджет (пункт меню): живые графики с момента открытия — **энергопотребление в ваттах** (датчик батареи: на разряде — полное потребление системы, на зарядке — мощность в батарею со знаком «+», от сети — «—»), CPU % и RAM % (с цифрами занято/всего ГБ). Сетка 20% + вертикали каждые 30 с, автошкала ватт с подписью (кратно 5). Перетаскивается мышью, позиция запоминается, не прячется при потере фокуса. Пока виджет закрыт — не семплирует ничего. - Кнопка-график в быстрой панели (слева от крестика) — открывает «Монитор» без похода в меню трея. - **Режим производительности при старте** — подменю «Настройки → Режим при старте» с двумя взаимоисключающими переключателями: «Восстанавливать последний» (помнит выбранный режим и возвращает после перезагрузки) и «Закрепить текущий режим» (фиксированный режим на каждый старт; повторный клик снимает). Недоступный режим (напр. Full-speed на батарее) → Авто. Закреплённый режим правится и в config.json (`ForceStartMode`). Прошивка сбрасывает режим на перезагрузке — это и лечит. - **Иконка языка** (文A) на пункте «Язык» в меню трея — визуальный якорь, чтобы найти переключение языка, не читая подписей (напр. если случайно выбран незнакомый язык). - **Язык при первом старте — по языку Windows** (ru → русский, zh → китайский, всё остальное → английский) вместо всегда-русского. Сохранённый выбор не трогается. ### Исправлено - Быстрая панель не закрывалась по клику вне неё после наведения на иконку/проигрыша анимации — закрытие переведено на глобальный хук мыши (`WH_MOUSE_LL`), не зависит от фокуса окна. - «Закрепить текущий режим» теперь снимается повторным кликом (раньше — только заходом в Авто). ### Изменено - Формулировки про Full-speed: «требует питания от сети» вместо привязки к DC-разъёму (разъём зависит от модели; у TM2424 — только USB-C). ## [0.6.0] — 2026-07-10 ### Добавлено - **«Режим совы» (не спать)** — сова-переключатель в панели (спит/бодрствует) и галочка в меню: экран не гаснет и система не засыпает (`SetThreadExecutionState`), а закрытие крышки на питании от сети не уводит в сон — только гасит экран (действие крышки AC → «ничего не делать», Power Management API; на батарее крышка работает штатно). Тайминги электропитания пользователя не изменяются; исходное действие крышки сохраняется в конфиге и восстанавливается при выключении/выходе/сбое. Фича отключается целиком параметром `OwlMode: false`. ## [0.5.3] — 2026-07-10 ### Добавлено - **OSD для Fn-Lock** (Fn+Esc, код `0x07`): прошивка переключает состояние сама, но Windows никак его не показывает — теперь всплывает замок с подписью «Классические F1–F12» / «Мультимедийные клавиши». ### Изменено - По итогам перф-ревью (кадр анимации панели ~0.8 мс ≈ 2.7% одного ядра при 33 fps, в простое 0% CPU): два таймера анимации панели слиты в один, шрифты панели больше не создаются на каждый кадр, неудача регистрации Esc-хоткея пишется в лог. - Документация протокола: команда `0x0C` исследована и закрыта (рудиментный слот TPLock игровой линейки), добавлено сравнение таблиц функций MIFS двух линеек, порог заряда помечен как зависящий от модели (на TM2424 ≈ 80%). ### В планах См. [ROADMAP.md](ROADMAP.md). ## [0.5.2] — 2026-07-10 ### Исправлено - **Esc снова закрывает панель** — теперь через системный хоткей на время показа: панель открывается из события WMI-клавиши, и Windows может не отдать ей фокус, из-за чего обычная обработка клавиш не срабатывала. ## [0.5.1] — 2026-07-10 ### Изменено - Клавиша «настройки» при открытой панели всегда переключает заряд 80/100 в ней — даже если ремапом назначено открытие Параметров Windows (оно осталось для нажатий вне панели). ## [0.5.0] — 2026-07-10 ### Добавлено - **Двойной клик Mi-кнопки**: одинарный — цикл режимов, двойной — заряд 80/100, удержание — панель. Цена: одинарный срабатывает после окна двойного (~300 мс). Отключается параметром `MiDoubleClick: false` — тогда одинарный мгновенный. - **Подменю «Настройки»** в меню трея — язык и автозапуск переехали туда, плюс галочки (всё применяется сразу, без перезапуска; дублируют параметры конфига): - «Показывать „Эко“» / «Показывать „Полную мощность“» (`EcoMode`/`FullSpeedMode`); - «Клик Mi — производительность» (`MiShortPress`): галочка — клик переключает режимы, двойной — заряд; снята — наоборот; - «Двойной клик Mi» (`MiDoubleClick`): снята — жест отключён, одинарный мгновенный; - «Клавиша настроек — заряд» (`SettingsKey`): галочка — переключение заряда 80/100, снята — открытие Параметров Windows. - **Переназначение клавиш через config.json**: `SettingsKey` («настройки»: заряд 80/100 или Параметры Windows) и `MiShortPress` («modes»/«charge» — меняет местами действия одинарного и двойного клика Mi). ### Изменено - Акценты панели: «Полная мощность» — красный (вместо оранжевого, чтобы отличалась от Турбо), Эко — сизый. ## [0.4.1] — 2026-07-09 ### Добавлено - Параметр `FullSpeedMode` в config.json (по умолчанию `true`) — скрывает режим «Полная мощность» из меню, панели и цикла Mi-кнопки (симметрично `EcoMode`). ### Изменено - Режим Эко подтверждён на TM2424 (гасит подсветку клавиатуры, снижает яркость экрана — самый экономный профиль); документация обновлена. ## [0.4.0] — 2026-07-09 ### Добавлено - **Китайский язык интерфейса (中文)** — третий в переключателе языков; терминология выровнена по китайскому софту Xiaomi (性能模式, 电池保护 и т.д.). - **Алгоритмические анимации иконок** (без Lottie и новых зависимостей — трансформации кэшированных SVG-битмапов; в простое таймеры не работают, CPU 0%): - **Авто** — спидометр разделён на слои (циферблат + стрелка): стрелка медленно «настраивается» (±30°, период ~4.5 с); OSD «Авто» показывается дольше (3.4 с); - **Тихий** — лист покачивается вокруг черешка, как от ветерка; - **Турбо** — молния пульсирует яркостью; - **Полная мощность** — ракета плавно покачивается, пламя (отдельный слой) подрагивает по размеру и мерцает; - **Эко** — звёзды у луны мерцают в противофазе; - **Зарядка** — молния внутри батареи мягко пульсирует (OSD подключения питания); - панель Mi: иконки при наведении плавно подрастают и наливаются цветом, активная ячейка анимируется всё время, пока панель открыта. ### Изменено - Короткое нажатие Mi при открытой панели «оживляет» выбранную иконку сразу (анимация активной ячейки не зависит от наведения мыши). ## [0.3.3] — 2026-07-09 ### Изменено - Клавиша «настройки» при **открытой панели** переключает пилюлю заряда 80/100 прямо в ней, без OSD поверх панели (как Mi-кнопка с режимами). ## [0.3.2] — 2026-07-09 ### Изменено - Короткое нажатие Mi при **открытой панели** перелистывает режим прямо в ней (подсветка ячейки переезжает), без OSD поверх панели. ## [0.3.1] — 2026-07-09 ### Добавлено - Параметр `EcoMode` в config.json (по умолчанию `true`) — скрывает режим Эко из меню, панели и цикла Mi-кнопки, если выставить `false`. ## [0.3.0] — 2026-07-09 ### Изменено - **Клавиша «настройки»** теперь переключает лимит заряда 80% ↔ 100% с OSD (раньше открывала Параметры Windows). Удержание не различимо — клавиша шлёт одиночное событие без пары нажатие/отпускание. ### Добавлено - **Пятый режим производительности — Эко (`0x0A`)**: скрытый режим прошивки, найден по EC-референсу и подтверждён пробой на TM2424. В меню, панели Mi, цикле Mi-кнопки, с иконкой-полумесяцем (OSD + трей). Отличие профиля от «Тихого» пока не измерено. - **Настраиваемая AI-клавиша**: параметры `AiKeyProgram`/`AiKeyArgs` в config.json — запуск своей программы/файла/URL (с раскрытием %ПЕРЕМЕННЫХ%); пусто → Copilot (Win+C). ## [0.2.0] — 2026-07-09 ### Добавлено - **OSD подсветки клавиатуры — 4 варианта иконки по уровню**: выкл (без «лучей», потухшая клавиша), 50% (короткие лучи), 100% (полные лучи), авто («A» над клавиатурой). - **README, LICENSE (GPL-3.0)** и GitHub Actions: автосборка релиза по тегу `v*` (self-contained ~70 МБ + framework-dependent ~2 МБ). ### Исправлено (по итогам ревью кода) - **OSD масштабируется под DPI** — иконка, отступы и скругления считаются от `DeviceDpi` (раньше — сырые пиксели, на HiDPI карточка была непропорциональной). - Двойная перестройка меню (и лишние WMI-вызовы) по левому клику на значке трея. - Опрос режима для значка трея: 3 с → 30 с (свои изменения и так обновляют значок сразу). - Проверка автозапуска (`schtasks /query`) убрана со старта в фон — не задерживает появление значка. - Утечка GDI-хэндлов `Region` при каждом показе OSD/панели; недиспоузнутые пункты меню. - Пункт «Беречь батарею» читает состояние в момент клика (а не при открытии меню). - Слушатель клавиш переподключается после рестарта WMI-сервиса. - Тёмная/светлая тема меню переключается на лету вместе с темой Windows. - Мини-лог ошибок в `%APPDATA%\XiControl\log.txt` (ротация по 256 КБ) вместо молчаливых `catch`. - Микро: кэш `JsonSerializerOptions`, вынос `Rounded()` в `Draw`, мёртвый процедурный код иконок переехал в `tools/IconPreview`, fallback для показа меню без приватного API. ### Изменено - **Иконки — авторские SVG-ассеты** (`assets/svg`) вместо процедурной отрисовки GDI+: - OSD и панель Mi — цветные плоские иконки (Material-стиль, 128×128); «полная мощность» теперь ракета, «беречь батарею» — батарея с листом. - Трей — монохромный контурный набор (`tray-*`, 24×24, `currentColor`), перекраска под тему панели задач на лету; Авто/база — «два тумблера». - Рендер через Svg.NET, ассеты встроены в exe как ресурсы, растры кэшируются по (иконка × размер × цвет). В панели Mi неактивные режимы приглушаются прозрачностью. - **Значок приложения** (`app.ico`, 16–256 px) собран из `settings.svg`; генерация: `dotnet run --project tools/IconPreview -- ico`. ## [0.1.0] — 2026-07-08 Первая рабочая версия. Управление ноутбуками Xiaomi/Redmi (проверено на Xiaomi Book Pro 14, TM2424) **полностью через штатный WMI-интерфейс прошивки (MIFS)** — без WinRing0 и без стороннего драйвера. ### Добавлено - **WMI-клиент MIFS** (`MifsClient`) — обёртка над `MiCommonInterface.MiInterface`: чтение/запись режима производительности и защиты заряда. - **Защита заряда** «беречь батарею (~80%) / полный (100%)» через WMI (cmd `0x10`). - **ChargeGuard** — переустановка лимита после сна и смены питания (AC↔батарея), т.к. EC сбрасывает защиту на этих событиях. - **Режимы производительности** (cmd `0x08`): Тихий / Авто / Турбо / Полная мощность. - **Иконка в трее** + всплывающее меню (заряд, режимы, язык, автозапуск, выход). - **Динамический значок трея** по режиму (Авто/база — «два тумблера», Тихий — лист, Турбо — молния, Полная — две молнии), монохром под тему панели задач. - **OSD-оверлей**: при подключении/отключении зарядки («Зарядка до 80%» / «Работа от батареи» + %), при смене режима и переключении заряда. Тематические векторные иконки, плавное затухание. - **Mi-кнопка**: короткое нажатие — циклическое переключение режимов + OSD; удержание — интерактивная панель (режимы + заряд 80/100 + закрытие по X/Esc/клику вне окна). - **Слушатель событий прошивки** (`HID_EVENT20`) для Mi-кнопки. - **Автозапуск при входе** через Планировщик заданий (`HighestAvailable`, работает на батарее, без UAC). - **Тёмное меню** (авто по теме Windows) со светлой галочкой. - **Локализация** RU / EN. - Единственный экземпляр (mutex), манифест `requireAdministrator`, Per-Monitor V2 DPI. ### Технически - C# / .NET 8 / WinForms, WMI через `System.Management`. - Лёгкий опрос режима (3 c) — значок трея всегда соответствует реальному состоянию. - Исследование интерфейса и решения задокументированы в `docs/` и `reference/probe-log.md`. [Unreleased]: #в-планах [0.1.0]: #010--2026-07-08