Введение

Однажды я заметил, что большая часть рабочего/учебного времени за компьютером проходит незаметно. Кажется, что ты "немного посидел" в IDE, "на пару минут" открыл браузер, а в итоге половина дня куда-то исчезла.

Существующие решения для отслеживания активности есть, но мне было интересно не просто установить готовую программу, а разобраться, как подобный инструмент работает изнутри.

Так появился проект ProcessTimeWatcher — небольшое WPF-приложение на C#, которое отслеживает активное окно пользователя и показывает, сколько времени было проведено в разных приложениях.

В этой статье расскажу, как устроено приложение, какие проблемы возникли во время разработки и чему удалось научиться.

Идея проекта

Основная задача была простой:

Определять, какое приложение сейчас находится в фокусе, и считать время его использования.

Например:

Visual Studio       02:34:12
Google Chrome       01:20:45
Telegram            00:45:10
Spotify             00:30:05

Но за этой простой задачей скрывается несколько проблем:

  • Windows не предоставляет готовый удобный список "текущего активного приложения";

  • название процесса не всегда совпадает с названием программы;

  • некоторые процессы нельзя прочитать без дополнительных прав;

  • нужно правильно учитывать время переключения между окнами.

Используемые технологии

В проекте используются:

  • C#

  • WPF (.NET)

  • Windows API

  • Process API

  • XAML для интерфейса

Почему именно WPF?

Для небольшого Windows-приложения WPF оказался удобным вариантом:

  • простой интерфейс через XAML;

  • хорошая работа с окнами Windows;

  • возможность использовать нативные возможности платформы;

  • быстрый результат без лишнего количества зависимостей.

Как приложение получает активное окно

Главная часть программы — определение окна, которое сейчас находится в фокусе.

Для этого используются функции Windows API:

[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();

[DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd,out uint processId);

Она возвращает дескриптор активного окна.

После этого через:

GetWindowThreadProcessId()

можно получить идентификатор процесса.

Примерный алгоритм:

Пользователь переключился на приложение  
        |        
        v
Получаем активное окно        
        |        
        v
Получаем ID процесса        
        |
        v
Получаем информацию о процессе   
        |
        v
Добавляем время активности

Получение информации о приложении

Первоначально я использовал имя процесса.

Например:

Code.exe
devenv.exe
chrome.exe

Но быстро стало понятно, что этого недостаточно.

Пользователь видит не:

devenv

а:

Visual Studio

Поэтому пришлось получать дополнительную информацию:

process.MainModule.FileVersionInfo.FileDescription

Она позволяет получить более привычное название приложения.

Visual Studio

Подсчёт времени

Изначально время отображалось просто:

61 сек

Но такой вариант быстро стал неудобным.

Поэтому формат был изменён:

00:01:01

где:

  • первые два значения — часы;

  • следующие — минуты;

  • последние — секунды.

Так статистика стала гораздо удобнее для чтения.

Работа с историей активности

Каждое приложение получает собственный счётчик.

Например:

{"Visual Studio": 5400,    "Chrome": 1800,    "Telegram": 600}

При переключении окна:

  1. определяется новое приложение;

  2. предыдущему добавляется время;

  3. запускается отслеживание нового процесса.

Экспорт отчётов

Одной из дополнительных функций стал экспорт результатов.

Сейчас можно сохранить отчёт для дальнейшего анализа.

Идея была сделать данные удобными не только внутри приложения, но и вне его. Большую часть всей информации я храню в Obsidian, поэтому было логично сделать экспорт отчета именно под Markdown файлы. По итогу я добился создание нового .md файла и/или возможность записать данные в уже существующий файл.

Это позволило:

  • хранить историю в Obsidian;

  • анализировать свою продуктивность.

Интерфейс приложения

Основной интерфейс показывает:

  • список приложений;

  • потраченное время;

  • состояние отслеживания;

  • кнопки управления.

В будущем планируется:

  • графики активности;

  • статистика по дням;

  • категории приложений.

    P.S. Для создания интерфейса я использовал помощь ИИ при разработке концепции дизайна, после чего адаптировал результат под нужды приложения.

Что оказалось сложнее, чем казалось

1. Получение информации о процессах

На первый взгляд кажется:

"Ну просто получить название программы"

Но на практике:

  • некоторые процессы защищены;

  • некоторые не имеют нормального описания;

  • некоторые запускаются через дополнительные оболочки.

2. Правильный подсчёт времени

Сначала приложение больше напоминало секундомер.

Оно просто увеличивало значение.

Но настоящий трекер времени должен учитывать:

  • переключения;

  • паузы;

  • закрытие приложения;

  • перезапуск программы.

3. Разница между процессом и приложением

Windows мыслит процессами.

Пользователь мыслит программами.

Это две разные вещи.

Например:

chrome.exe
chrome.exe
chrome.exe

может означать несколько вкладок и процессов одного браузера.

Что дальше

План развития ProcessTimeWatcher:

  • автозапуск вместе с Windows;

  • сохранение истории между запусками;

  • графики активности;

  • система целей;

  • категории приложений;

  • уведомления при слишком долгом использовании программы;

  • улучшение определения названий приложений;

  • Работа в фоновом режиме

  • Создание таймера, который будет следить, чтобы пользователь оставался в выбранном приложении и напоминал, если пользователь на что-то отвлекаться.

Итоги

ProcessTimeWatcher начинался как небольшая идея:

"А сколько времени я реально провожу в программах?"

Но в процессе разработки он превратился в полноценный учебный проект, который позволил разобраться с:

  • Windows API;

  • процессами;

  • WPF;

  • обработкой событий;

  • работой с пользовательским интерфейсом.

Главный вывод после разработки:

Даже простая идея может оказаться намного сложнее внутри, чем кажется снаружи.

Именно такие проекты лучше всего показывают, как работает разработка настоящего программного обеспечения.

Исходный код проекта доступен на GitHub.

Скачать последнюю актуальную версию приложения можно тут.

Сейчас ProcessTimeWatcher остаётся небольшим open-source проектом, но уже позволил мне лучше понять взаимодействие C# с Windows API и работу приложений под Windows. В дальнейшем планирую развивать проект и добавлять новые возможности.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Как часто вы задумывались о времени, потраченным на «отвлекающие» приложения?
20%Никогда не думал об этом, мне комфортно.1
60%Задумывался, но лень что-то предпринимать.3
0%Пробовал готовые трекеры, но они не прижились.0
20%Писал свой софт/скрипты для учета времени (коллега!).1
0%Активно отслеживаю и анализирую рабочее/учебное время.0
Проголосовали 5 пользователей. Воздержались 2 пользователя.