Last Updated on: 22nd November 2025, 06:12 pm
Introduction to Activity Tracking
Activity tracking software represents a fascinating intersection of system programming, user interface analysis, and data analytics. The Windows Activity Tracker is a Python application that monitors and records virtually every aspect of user interaction with a Windows 10/11 computer system.
This isn’t just a simple keylogger or basic activity monitor, it’s a sophisticated system that captures keyboard inputs, mouse interactions, window changes, file operations, and even clipboard activities with remarkable detail.
For students learning programming, this script serves as an excellent case study in several important areas:
- System-level programming with Windows APIs
- Multi-threading and real-time data processing
- Database management with SQLite
- Object-oriented design patterns
- Error handling in production-grade software
- Data analysis and reporting generation
The tracker operates by leveraging multiple Windows-specific APIs and libraries to capture low-level system events, then processes and stores this information in both human-readable and database formats for later analysis.
Note: This article is for only general information and use this ethically.
Complete Code: https://drive.google.com/file/d/1W8vlXYwohqh-Lk-_RtMRifndvbIsdxEa/view?usp=drive_link
Import Analysis & Dependencies
Let’s break down each import statement and understand its purpose in the application:
import os import time import sqlite3 import threading import psutil import ctypes from ctypes import wintypes from datetime import datetime from collections import defaultdict, deque from typing import Optional, Dict, Any, List, Tuple import shutil import tempfile import win32clipboard # pip install pywin32 import win32con import win32gui import win32process import re
Core Python Imports
import os – Provides operating system interface functionality. In this script, it’s used for:
- Getting current working directory:
os.getcwd() - File path operations:
os.path.join(),os.path.basename(),os.path.dirname() - Environment variable access:
os.environ.get()
import time – Handles time-related operations including:
- Adding delays:
time.sleep(3) - Interval-based checking in loops
- Timestamp calculations
import sqlite3 – Database management for storing all tracked activities:
- Creates and manages SQLite database connections
- Executes SQL queries to insert and retrieve activity data
- Handles database schema creation and migrations
import threading – Enables concurrent execution through threads:
- Runs multiple monitoring tasks simultaneously
- Prevents blocking operations in the main thread
- Manages thread lifecycle with
threading.Threadandthreading.Event
import psutil – Process and system utilities:
- Retrieves process information:
psutil.Process(pid.value) - Gets executable paths and process names
- Provides system monitoring capabilities
Windows-Specific Imports
import ctypes & from ctypes import wintypes – Python’s foreign function library for calling C functions:
- Accesses Windows API functions directly
- Defines Windows-specific data types
- Enables low-level system interaction
import win32clipboard, win32con, win32gui, win32process – Part of pywin32 package for Windows integration:
win32clipboard: Monitors clipboard content changeswin32con: Provides Windows constants (likeCF_HDROP)win32gui: Handles window management and GUI interactionswin32process: Accesses process-related information
Data Structure Imports
from collections import defaultdict, deque – Specialized container datatypes:
defaultdict: Creates dictionaries with default values for missing keysdeque: Double-ended queue for efficient appends and pops from both ends
from typing import Optional, Dict, Any, List, Tuple – Type hints for better code documentation and IDE support:
- Improves code readability
- Helps with static analysis
- Makes the code more maintainable
Optional Import Handling
try:
from pynput import keyboard, mouse # type: ignore
PYNPUT_AVAILABLE = True
except Exception:
PYNPUT_AVAILABLE = FalseThis try-except block demonstrates robust error handling for optional dependencies. The pynput library provides more reliable input monitoring but isn’t always available. The script gracefully falls back to alternative methods if pynput isn’t installed.
Virtual Key Mapping System
The script includes comprehensive virtual key code mapping to translate raw keyboard scan codes into human-readable key names:
# Map some virtual-key codes for fallback (not exhaustive but practical)
VK_CODE_ALPHA = {i: chr(i) for i in range(0x41, 0x5B)} # A-Z
VK_CODE_NUM = {i: str(i - 0x30) for i in range(0x30, 0x3A)} # 0-9
VK_SPECIAL = {
0x20: "Space", 0x0D: "Enter", 0x08: "Backspace", 0x09: "Tab",
0x1B: "Esc", 0x10: "Shift", 0x11: "Ctrl", 0x12: "Alt",
# ... and many more special keys
}Understanding Virtual Key Codes
Virtual Key Codes are numeric constants that represent physical keys on the keyboard, regardless of keyboard layout or language settings. For example:
0x41represents the ‘A’ key0x20represents the Spacebar0x0Drepresents the Enter key
The mapping dictionaries serve as translation tables that convert these numeric codes into meaningful string representations that users can understand.
Mouse Button Mapping
VK_LBUTTON = 0x01 VK_RBUTTON = 0x02 VK_MBUTTON = 0x04 VK_XBUTTON1 = 0x05 VK_XBUTTON2 = 0x06
These constants represent mouse button virtual key codes, allowing the script to detect and differentiate between left, right, middle, and extended mouse button clicks.
Dictionary Merging
VK_MAP = {**VK_CODE_ALPHA, **VK_CODE_NUM}
VK_MAP.update(VK_SPECIAL)
VK_MAP.update({
VK_LBUTTON: "Left Click",
VK_RBUTTON: "Right Click",
# ... mouse buttons
})This demonstrates dictionary unpacking and multiple update operations to create a comprehensive key mapping dictionary that includes alphabetic keys, numeric keys, special keys, and mouse buttons.
Core Class Architecture
The main tracking functionality is encapsulated in the UltraActivityTracker class, which demonstrates excellent object-oriented design principles:
Class Initialization
class UltraActivityTracker:
def __init__(self):
# Files & paths
self.current_dir = os.getcwd()
current_date = datetime.now().strftime("%Y-%m-%d")
self.db_path = os.path.join(self.current_dir, f"activity_{current_date}.db")
self.log_file = os.path.join(self.current_dir, f"activity_log_{current_date}.txt")
# ... more file paths
# State management
self.is_tracking = False
self.keyboard_listener = None
self.mouse_listener = None
self.threads: List[threading.Thread] = []
self.stop_event = threading.Event()
# Statistics tracking
self.key_count = 0
self.shortcut_count = 0
self.mouse_click_count = 0
self.file_operations_count = 0
# ... more statisticsKey Initialization Components
File Management:
- Creates date-stamped filenames for logs, databases, and reports
- Uses
os.path.join()for cross-platform path compatibility - Organizes output files systematically
State Management:
is_tracking: Boolean flag to control monitoring statestop_event: Threading event for graceful shutdown- Listener objects for keyboard and mouse monitoring
Data Structures:
defaultdictfor application usage statisticsdequeobjects for maintaining activity history with fixed sizes- Multiple dictionaries for configuration and mapping
Application Categorization System
self.app_categories = {
'Browsers': ['chrome.exe', 'firefox.exe', 'msedge.exe', 'opera.exe', 'brave.exe'],
'Code Editors': ['code.exe', 'pycharm.exe', 'notepad++.exe', 'sublime_text.exe', 'vim.exe'],
'Office Suite': ['winword.exe', 'excel.exe', 'powerpnt.exe', 'outlook.exe', 'onenote.exe'],
# ... more categories
}This categorization system allows the tracker to intelligently classify applications and provide more meaningful activity analysis. Each category has specific process names associated with it, enabling the system to determine whether a user is coding, browsing, working with office documents, etc.
Shortcut Key Mapping
self.shortcut_keys = {
'ctrl+c': 'Copy', 'ctrl+x': 'Cut', 'ctrl+v': 'Paste', 'ctrl+z': 'Undo',
'ctrl+y': 'Redo', 'ctrl+a': 'Select All', 'ctrl+s': 'Save', 'ctrl+p': 'Print',
# ... many more shortcuts
}This dictionary maps keyboard shortcut combinations to their common actions, allowing the tracker to recognize and log meaningful user actions rather than just random key presses.
Database & Logging System
Database Schema Setup
The setup_database() method creates a sophisticated SQLite database with multiple tables for different types of activities:
def setup_database(self):
"""Initialize SQLite database with advanced schema including mouse and file operations"""
try:
conn = sqlite3.connect(self.db_path, timeout=10)
cursor = conn.cursor()
# Create mouse_activities table
cursor.execute('''
CREATE TABLE IF NOT EXISTS mouse_activities (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT NOT NULL,
window_title TEXT,
process_name TEXT,
button TEXT,
action TEXT,
x_position INTEGER,
y_position INTEGER,
context TEXT,
target_file TEXT,
target_path TEXT
)
''')
# Create file_operations table
cursor.execute('''
CREATE TABLE IF NOT EXISTS file_operations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT NOT NULL,
operation_type TEXT,
source_path TEXT,
destination_path TEXT,
file_name TEXT,
file_size INTEGER,
application TEXT,
window_title TEXT,
success BOOLEAN,
details TEXT
)
''')
# ... more tablesDatabase Table Purposes
mouse_activities – Stores detailed mouse interaction data:
- Click coordinates (x_position, y_position)
- Button pressed and action type
- Context and target file information
- Timestamp for temporal analysis
file_operations – Tracks file management activities:
- Operation type (copy, cut, paste, delete, rename)
- Source and destination paths
- File names and sizes
- Application context
keyboard_activities – Records keyboard inputs:
- Individual key presses and shortcuts
- Application context
- Timestamp and key type classification
app_sessions – Tracks application usage sessions:
- Start and end times
- Duration calculations
- Activity metrics per application
Logging System
The script implements a dual logging system that writes to both the console and log files:
def _log_console(self, message: str, prefix: str = "π"):
ts = datetime.now().strftime("%H:%M:%S")
line = f"{prefix} [{ts}] {message}"
print(line)
try:
with open(self.log_file, 'a', encoding='utf-8') as f:
f.write(line + "\n")
except Exception:
passKey Features of the Logging System:
- Emoji prefixes for visual categorization
- Timestamp inclusion for chronological tracking
- Error resilience with try-except blocks
- Dual output to both console and file
- Unicode support for special characters
Database Migration Support
The script includes robust migration logic that checks for existing tables and adds missing columns:
cursor.execute("PRAGMA table_info(mouse_activities)")
columns = [column[1] for column in cursor.fetchall()]
if 'target_file' not in columns:
cursor.execute("ALTER TABLE mouse_activities ADD COLUMN target_file TEXT")This ensures that the database schema can evolve over time without losing existing data, demonstrating forward-thinking design for long-term application maintenance.
Window & Process Tracking
Active Window Detection
The get_active_window_info() method is crucial for understanding user context:
def get_active_window_info(self) -> Optional[Dict[str, Any]]:
"""Get info about the currently active (foreground) window with enhanced details"""
try:
hwnd = user32.GetForegroundWindow()
if not hwnd:
return None
pid = wintypes.DWORD()
user32.GetWindowThreadProcessId(hwnd, ctypes.byref(pid))
length = user32.GetWindowTextLengthW(hwnd)
buff = ctypes.create_unicode_buffer(length + 1)
user32.GetWindowTextW(hwnd, buff, length + 1)
window_title = buff.value or ""
# Process details
process_name = "Unknown"
process_path = "Unknown"
try:
proc = psutil.Process(pid.value)
process_name = proc.name()
process_path = proc.exe()
except Exception:
pass
category = self.categorize_application(process_name)
# ... return comprehensive window infoTechnical Breakdown of Window Detection
user32.GetForegroundWindow() – Windows API call that returns a handle to the currently active window
- Returns
HWND(Handle to a Window) - Returns
Noneif no window is active
user32.GetWindowThreadProcessId() – Retrieves the process ID that created the window
- Takes window handle and pointer to DWORD variable
- Fills the DWORD with the process ID
user32.GetWindowTextLengthW() & user32.GetWindowTextW() – Get the window title text
- First gets the length, then allocates a buffer
- Retrieves the actual text into the buffer
psutil.Process() – Gets detailed process information from the process ID
- Process name, executable path, and other details
- Wrapped in try-except for error handling
Smart Window Title Parsing
The extract_current_location_and_file_from_window() method demonstrates advanced text parsing:
def extract_current_location_and_file_from_window(self, window_title: str, process_name: str) -> Tuple[str, str]:
"""Extract current folder location and active file from window title"""
try:
current_file = "Unknown"
current_location = window_title
if process_name.lower() == 'explorer.exe':
# Remove " - File Explorer" suffix
if ' - File Explorer' in window_title:
content = window_title.replace(' - File Explorer', '')
if '\\' in content:
current_file = os.path.basename(content)
current_location = os.path.dirname(content)
else:
current_file = content
current_location = content
# ... handle other application typesThis method uses pattern recognition and string manipulation to extract meaningful information from window titles, transforming raw text like "C:\Projects\README.md - Notepad++" into structured data:
current_file: “README.md”current_location: “C:\Projects”
Application Categorization Logic
def categorize_application(self, process_name: Optional[str]) -> str:
if not process_name:
return "Other"
pname = process_name.lower()
for category, apps in self.app_categories.items():
if pname in (a.lower() for a in apps):
return category
return "Other"This method demonstrates efficient dictionary searching and case normalization to classify applications into predefined categories, enabling meaningful activity analysis and reporting.
Enhanced Mouse Tracking
Comprehensive Mouse Event Handling
The mouse tracking system goes beyond simple click counting to provide contextual understanding of user interactions:
def handle_mouse_click(self, button: str, pressed: bool, x: int = 0, y: int = 0):
"""Handle mouse click events with enhanced context detection"""
try:
window_info = self.get_active_window_info() or {'process_name': 'Unknown', 'window_title': '', 'category': 'Other', 'current_location': 'Unknown', 'current_file': 'Unknown'}
if pressed:
self.mouse_click_count += 1
proc = window_info.get('process_name', 'Unknown')
self.app_usage[proc]['clicks'] += 1
# Determine click context with file information
context, target_file, target_path = self.detect_click_context_with_files(window_info, button, x, y)
# Store context for file operations
if button == "right" or button == "left":
self.last_right_click_context = {
'context': context,
'target_file': target_file,
'target_path': target_path,
'window_info': window_info,
'timestamp': datetime.now()
}
self.last_selected_file = target_file
# Log mouse activity with file details
self.log_mouse_activity(window_info, button, "click", x, y, context, target_file, target_path)Context-Aware Click Detection
The detect_click_context_with_files() method provides intelligent context detection:
def detect_click_context_with_files(self, window_info: Dict[str, Any], button: str, x: int, y: int) -> Tuple[str, str, str]:
"""Detect the context of a mouse click with file information"""
try:
process_name = window_info.get('process_name', '').lower()
current_location = window_info.get('current_location', 'Unknown Location')
current_file = window_info.get('current_file', 'Unknown File')
# File Explorer context
if process_name == 'explorer.exe':
if current_file != current_location and current_file != "Unknown File":
target_file = current_file
target_path = current_location
else:
target_file = "Folder Area"
target_path = current_location
if button == "right":
return "File Context Menu", target_file, target_path
elif button == "left":
return "File Selection", target_file, target_path
# ... handle other application typesMouse Activity Database Logging
def log_mouse_activity(self, window_info: Dict[str, Any], button: str, action: str, x: int, y: int,
context: str, target_file: str, target_path: str):
"""Save mouse activity to database with file details"""
try:
conn = sqlite3.connect(self.db_path, timeout=10)
cursor = conn.cursor()
cursor.execute('''
INSERT INTO mouse_activities
(timestamp, window_title, process_name, button, action, x_position, y_position, context, target_file, target_path)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
''', (
datetime.now().isoformat(),
window_info.get('window_title', ''),
window_info.get('process_name', ''),
button,
action,
x,
y,
context,
target_file,
target_path
))
conn.commit()
conn.close()
except Exception as e:
self.log_to_file(f"Error saving mouse activity: {e}", "β", "ERROR")This method demonstrates complete error handling and database transaction management, ensuring that mouse activities are reliably recorded even in case of errors.
File Operations Monitoring
Advanced Clipboard Monitoring
The file operations tracking system uses clipboard monitoring to detect copy, cut, and paste operations:
def monitor_clipboard_for_file_operations(self):
"""Enhanced clipboard monitoring for detailed file operations"""
self.log_to_file("Advanced clipboard file operation monitor started", "π", "INFO")
while not self.stop_event.is_set() and self.is_tracking:
try:
win32clipboard.OpenClipboard()
try:
# Check for file operations in clipboard
if win32clipboard.IsClipboardFormatAvailable(win32con.CF_HDROP):
files = win32clipboard.GetClipboardData(win32con.CF_HDROP)
if files and files != self.last_clipboard_content:
self.last_clipboard_content = files
self.handle_detailed_file_operation_detection(files)
finally:
win32clipboard.CloseClipboard()
except Exception as e:
# Clipboard might be in use by another process
pass
time.sleep(self.clipboard_check_interval)Technical Details of Clipboard Monitoring
win32clipboard.OpenClipboard() – Opens the clipboard for examination
- Required before accessing clipboard contents
- May fail if another process has the clipboard open
win32clipboard.IsClipboardFormatAvailable(win32con.CF_HDROP) – Checks for file drop format
CF_HDROPindicates files are in the clipboard (from copy/cut operations)- Returns
Trueif files are available
win32clipboard.GetClipboardData(win32con.CF_HDROP) – Retrieves the file list
- Returns a list of file paths
- Used to detect what files are being copied or moved
File Operation Detection and Handling
def handle_detailed_file_operation_detection(self, files):
"""Handle detected file operations with detailed information"""
try:
window_info = self.get_active_window_info() or {'process_name': 'Unknown', 'window_title': '', 'current_location': 'Unknown', 'current_file': 'Unknown'}
# Determine operation type based on modifier keys and context
operation = "copy" if not self.modifier_keys.get('shift') else "cut"
# Get source information from context
source_path = self.get_source_path_from_context()
file_names = []
if isinstance(files, (list, tuple)):
file_names = [os.path.basename(f) for f in files]
if files:
source_path = os.path.dirname(files[0])
else:
file_names = [os.path.basename(files)]
source_path = os.path.dirname(files) if files else source_path
# Store pending operation with detailed info
self.pending_file_operations[operation] = {
'files': files,
'file_names': file_names,
'source_path': source_path,
'timestamp': datetime.now(),
'source_window': window_info
}This method demonstrates intelligent operation deduction by combining clipboard data with modifier key states and window context to determine whether the user is performing a copy or cut operation.
File Paste Operation Handling
def handle_file_paste_operation(self):
"""Handle file paste operations with destination tracking"""
try:
window_info = self.get_active_window_info() or {'process_name': 'Unknown', 'window_title': '', 'current_location': 'Unknown', 'current_file': 'Unknown'}
destination_path = window_info.get('current_location', 'Unknown Destination')
# Check for pending operations
for op_type in ['copy', 'cut']:
pending_op = self.pending_file_operations.get(op_type)
if pending_op:
# Calculate time since operation was prepared
time_since_op = (datetime.now() - pending_op['timestamp']).total_seconds()
# Only log if paste happened within a reasonable time (30 seconds)
if time_since_op < 30:
source_path = pending_op.get('source_path', 'Unknown Source')
file_names = pending_op.get('file_names', [])
if file_names:
for file_name in file_names:
# Log the completed file operation
self.log_file_operation(
operation_type=op_type,
source_path=source_path,
destination_path=destination_path,
file_name=file_name,
application=window_info.get('process_name', 'Unknown'),
window_title=window_info.get('window_title', ''),
success=True,
details=f"{op_type.upper()} operation completed"
)This method shows temporal correlation between copy/cut and paste operations, ensuring that file operations are only logged when they form complete sequences within a reasonable time window.
Keyboard Activity Tracking
Comprehensive Key Event Handling
The keyboard tracking system differentiates between regular keys, modifier keys, and shortcuts:
def handle_key_event(self, key_name: str, pressed: bool):
"""
Unified handler for key press/release events.
key_name: readable key string like 'a', 'Ctrl', 'F5', 'Enter'
pressed: True for press, False for release
"""
try:
# Map modifier name variants to our keys
kn = key_name.lower()
if kn in ('ctrl', 'control'):
self.modifier_keys['ctrl'] = pressed
return
if kn in ('alt',):
self.modifier_keys['alt'] = pressed
return
# ... handle other modifiers
# Only handle presses for non-modifier logging
if not pressed:
return
window_info = self.get_active_window_info() or {'process_name': 'Unknown', 'window_title': '', 'category': 'Other', 'current_location': 'Unknown', 'current_file': 'Unknown'}
active_mods = [m for m, v in self.modifier_keys.items() if v]
key_str = key_name # friendly string
# Detect if this constitutes a shortcut
combo = active_mods + [key_str]
shortcut_action = self.detect_shortcut(combo)
if shortcut_action:
combo_str = self.normalize_combo(combo)
self.log_shortcut(combo_str, shortcut_action, window_info)
self.log_keyboard_activity(window_info, key_str, "shortcut")
else:
# Normal key press - track all alphabets and numbers
if len(key_str) == 1 and key_str.isalnum():
self.key_count += 1
proc = window_info.get('process_name', 'Unknown')
self.app_usage[proc]['keystrokes'] += 1
self.keystroke_buffer.append(key_str)Shortcut Detection Logic
def normalize_combo(self, parts: List[str]) -> str:
"""Normalize combo like ['ctrl','shift','a'] -> 'ctrl+shift+a'"""
lower = [p.lower() for p in parts if p]
# place modifiers first in an expected order
order = ['ctrl', 'alt', 'shift', 'win']
mods = [m for m in order if m in lower]
others = sorted([p for p in lower if p not in mods])
combo = '+'.join(mods + others)
return combo
def detect_shortcut(self, key_combination: List[str]) -> Optional[str]:
combo = self.normalize_combo(key_combination)
return self.shortcut_keys.get(combo)These methods demonstrate consistent shortcut normalization by:
- Converting all keys to lowercase
- Sorting modifiers in a standard order
- Combining with regular keys
- Looking up in the shortcut dictionary
Keyboard Activity Logging
def log_keyboard_activity(self, window_info: Dict[str, Any], key_str: str, key_type: str):
"""Persist keyboard press to keyboard_activities table"""
try:
is_shortcut = (key_type == "shortcut")
shortcut_name = None
if is_shortcut:
mods = [k for k, v in self.modifier_keys.items() if v]
shortcut_name = self.detect_shortcut(mods + [key_str]) if mods else None
conn = sqlite3.connect(self.db_path, timeout=10)
cursor = conn.cursor()
cursor.execute('''
INSERT INTO keyboard_activities
(timestamp, window_title, process_name, keys_pressed, key_type, is_shortcut, shortcut_name, total_keys)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
''', (
datetime.now().isoformat(),
window_info.get('window_title', ''),
window_info.get('process_name', ''),
key_str,
key_type,
bool(is_shortcut),
shortcut_name,
1
))
conn.commit()
conn.close()
except Exception as e:
self.log_to_file(f"Error saving keyboard activity: {e}", "β", "ERROR")This method shows comprehensive data collection for keyboard activities, including context, key type classification, and shortcut recognition.
Threading & Real-time Monitoring
Multi-threaded Architecture
The tracker uses multiple threads to monitor different aspects of system activity simultaneously:
def start_tracking(self):
self.is_tracking = True
self.stop_event.clear()
# ... reset statistics
# Start keyboard monitoring
if PYNPUT_AVAILABLE:
try:
self.keyboard_listener = keyboard.Listener(on_press=self._pynput_on_press, on_release=self._pynput_on_release)
self.keyboard_listener.start()
self._log_console("pynput keyboard listener started", "π§")
# Start mouse monitoring with pynput
self.mouse_listener = mouse.Listener(on_click=self._pynput_mouse_on_click)
self.mouse_listener.start()
self._log_console("pynput mouse listener started", "π±οΈ")
except Exception as e:
# Fallback to polling method
self.log_to_file(f"pynput listeners failed, falling back: {e}", "β οΈ", "WARNING")
t_key = threading.Thread(target=self._fallback_key_poller, daemon=True)
t_key.start()
self.threads.append(t_key)
# Window tracker
t_win = threading.Thread(target=self.track_window_changes, daemon=True)
t_win.start()
self.threads.append(t_win)
# File operations monitoring
t_clipboard = threading.Thread(target=self.monitor_clipboard_for_file_operations, daemon=True)
t_clipboard.start()
self.threads.append(t_clipboard)
# Periodic reporter
t_rep = threading.Thread(target=self.generate_periodic_report, daemon=True)
t_rep.start()
self.threads.append(t_rep)Thread Management Features
Daemon Threads – All monitoring threads are created as daemon threads:
- Automatically terminate when main program exits
- Prevent hanging processes if main thread crashes
Graceful Shutdown – Uses threading.Event for coordinated stopping:
self.stop_event = threading.Event()
# In each monitoring thread:
while not self.stop_event.is_set() and self.is_tracking:
# monitoring logicFallback Mechanisms – Provides alternative monitoring methods:
- Prefers
pynputfor better performance - Falls back to
GetAsyncKeyStatepolling ifpynputfails - Ensures functionality across different environments
Fallback Polling Implementation
def _fallback_key_poller(self):
"""
Poll keys using GetAsyncKeyState. Detect transitions from up->down to simulate key press.
Runs in its own thread.
"""
self.log_to_file("Fallback keyboard poller started", "β οΈ", "INFO")
# Prepare a list of vk codes to watch
vk_codes = list(VK_MAP.keys())
# also monitor modifier virtual keys explicitly
vk_codes += [0x10, 0x11, 0x12, 0x5B] # shift, ctrl, alt, win
prev_states = {vk: False for vk in vk_codes}
while not self.stop_event.is_set() and self.is_tracking:
try:
for vk in vk_codes:
state = bool(user32.GetAsyncKeyState(vk) & 0x8000)
if state and not prev_states[vk]:
# Key down event
key_name = VK_MAP.get(vk, f"VK_{vk}")
self.handle_key_event(key_name, True)
elif not state and prev_states[vk]:
# Key up event (handle modifier releases)
key_name = VK_MAP.get(vk, f"VK_{vk}")
self.handle_key_event(key_name, False)
prev_states[vk] = state
time.sleep(0.006) # small sleep to avoid high CPU; tuned for responsiveness
except Exception as e:
self.log_to_file(f"Fallback poller error: {e}", "β", "ERROR")
time.sleep(0.05)This fallback method demonstrates efficient key state polling by:
- Monitoring virtual key state transitions
- Using bitmask operations to check key states
- Maintaining previous state for change detection
- Implementing CPU-friendly polling intervals
Reporting System
Comprehensive Report Generation
The tracker generates multiple report formats with detailed analytics:
def save_report(self):
try:
total_time = sum(usage['time'] for usage in self.app_usage.values()) or 1
current_time = datetime.now()
tracking_duration = (current_time - self.start_time).total_seconds() / 60 # minutes
with open(self.report_file, 'w', encoding='utf-8') as f:
f.write("π ULTRA ADVANCED ACTIVITY REPORT WITH DETAILED FILE OPERATIONS\n")
f.write("=" * 80 + "\n")
f.write(f"Generated: {current_time.strftime('%Y-%m-%d %H:%M:%S')}\n")
f.write(f"Tracking Duration: {tracking_duration:.1f} minutes\n")
f.write(f"Total Keystrokes: {self.key_count}\n")
f.write(f"Total Shortcuts: {self.shortcut_count}\n")
f.write(f"Total Mouse Clicks: {self.mouse_click_count}\n")
f.write(f"Total File Operations: {self.file_operations_count}\n")
f.write(f"Applications Used: {len(self.app_usage)}\n")
f.write("=" * 80 + "\n\n")
# Productivity calculations
productive_categories = ['Code Editors', 'Office Suite', 'Development']
productive_time = sum(usage['time'] for app, usage in self.app_usage.items()
if self.categorize_application(app) in productive_categories)
f.write(f"Productive Time: {productive_time/60:.1f} minutes ({productive_time/total_time*100:.1f}%)\n")
# Application usage ranking
f.write("π± APPLICATION USAGE RANKING:\n")
f.write("-" * 80 + "\n")
for i, (app, usage) in enumerate(sorted(self.app_usage.items(), key=lambda x: x[1]['time'], reverse=True), 1):
minutes = usage['time'] / 60
percent = (usage['time'] / total_time * 100) if total_time > 0 else 0
category = self.categorize_application(app)
f.write(f"{i:2d}. {app:<25} {category:<20} {minutes:5.1f}m ({percent:5.1f}%) | ")
f.write(f"β¨οΈ{usage['keystrokes']:4d} | π―{usage['shortcuts']:3d} | π±οΈ{usage['clicks']:3d} | π{usage['file_ops']:2d}\n")HTML Report Generation
def save_detailed_html_report(self):
try:
total_time = sum(usage['time'] for usage in self.app_usage.values()) or 1
html_content = f"""<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Ultra Advanced Activity Report - {datetime.now().strftime('%Y-%m-%d')}</title>
<style>
body {{ font-family: Arial, sans-serif; margin: 20px; background:#f5f5f5 }}
.container {{ max-width:1200px; margin:0 auto; background:white; padding:20px; border-radius:10px }}
.header {{ background:#2c3e50; color:white; padding:20px; border-radius:5px }}
.stats {{ display:grid; grid-template-columns:repeat(auto-fit,minmax(200px,1fr)); gap:15px; margin:20px 0 }}
.stat-card {{ background:#ecf0f1; padding:15px; border-radius:5px; text-align:center }}
.app-item {{ background:#f8f9fa; margin:5px 0; padding:10px; border-left:4px solid #3498db }}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>π Ultra Advanced Activity Report</h1>
<p>Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
</div>
<div class="stats">
<div class="stat-card"><h3>β° Tracking Time</h3><p>{(total_time/60):.1f} minutes</p></div>
<div class="stat-card"><h3>β¨οΈ Keystrokes</h3><p>{self.key_count}</p></div>
<div class="stat-card"><h3>π― Shortcuts</h3><p>{self.shortcut_count}</p></div>
<!-- ... more stat cards -->
</div>
<!-- ... more report sections -->
</div>
</body>
</html>
"""
with open(self.detailed_report_file, 'w', encoding='utf-8') as f:
f.write(html_content)
except Exception as e:
self.log_to_file(f"save_detailed_html_report error: {e}", "β", "ERROR")Analytics Features
Productivity Metrics – Calculates productive vs. non-productive time based on application categories
Usage Patterns – Shows application usage distribution and patterns
Activity Correlation – Correlates different types of activities (keystrokes, clicks, shortcuts)
Temporal Analysis – Provides time-based activity insights
Complete Usage Overview
How to Use the Tracker
The tracker is designed to be easy to use while providing powerful monitoring capabilities:
def main():
tracker = UltraActivityTracker()
print("π ULTRA ADVANCED WINDOWS ACTIVITY TRACKER WITH DETAILED FILE OPERATIONS")
print("=" * 60)
print("ENHANCED FEATURES:")
print("β’ Smart activity detection with clean page titles")
print("β’ Detailed mouse click tracking with file names and locations")
print("β’ Advanced file operations monitoring (copy, cut, paste, delete)")
print("β’ Source and destination path tracking for file operations")
print("β’ Enhanced shortcut key tracking with context")
print("β’ Keyboard alphabet and number tracking")
print("β’ Clipboard monitoring for precise file operation detection")
print("β’ Multiple report formats (TXT, HTML) with detailed file info")
print("=" * 60)
print("Starting in 3 seconds...")
time.sleep(3)
try:
tracker.start_tracking()
while True:
# Keep main thread alive; trap KeyboardInterrupt
time.sleep(1)
except KeyboardInterrupt:
tracker.stop_tracking()
print("\n\nπ Tracking completed! Files saved:")
print(f" π {tracker.log_file}")
print(f" π {tracker.report_file}")
print(f" π {tracker.detailed_report_file}")
print(f" ποΈ {tracker.db_path}")
print("\nThank you for using Ultra Activity Tracker! π")Installation and Setup
Requirements:
pip install psutil pywin32 pynput
Key Features in Action:
- Automatic Start – Begins monitoring immediately after 3-second countdown
- Real-time Feedback – Shows ongoing activities in console with emojis
- Graceful Shutdown – Ctrl+C stops tracking and generates final reports
- Multiple Outputs – Creates text, HTML, and database files
- Date-stamped Files – Organizes outputs by date for long-term tracking
Output Files Generated
activity_YYYY-MM-DD.db – SQLite database with complete activity recordsactivity_log_YYYY-MM-DD.txt – Detailed chronological log of all activitiesactivity_report_YYYY-MM-DD.txt – Formatted summary reportdetailed_report_YYYY-MM-DD.html – Visual HTML report with analytics
Educational Value
Learning Opportunities for Students
This script provides exceptional educational value across multiple programming domains:
System Programming:
- Windows API integration and system calls
- Process and window management
- Low-level input monitoring
- Clipboard interaction
Software Architecture:
- Object-oriented design patterns
- Multi-threaded application design
- Database schema design and management
- Configuration management
Data Analysis:
- Activity pattern recognition
- Productivity metrics calculation
- Temporal data analysis
- Report generation and visualization
Error Handling and Robustness:
- Comprehensive exception handling
- Graceful degradation features
- Resource management
- Data persistence reliability
This activity tracker represents a comprehensive example of modern Python development, combining system programming, data analysis, and user-friendly reporting in a single, cohesive application. It serves as an excellent codebase for students to study, understand, and extend with their own features and improvements.