Skip to content

Joe4NYC/TypingCounter

Repository files navigation

TypingCounter Icon

TypingCounter

A lightweight macOS Menu Bar app that silently counts your keystrokes — privately, locally, and with minimal resource usage.


Screenshots

7-Day History View    Today by Hour View

Menu Bar Icon


What It Does

TypingCounter lives quietly in your macOS Menu Bar and counts every keydown event in real time. No text is captured — only the count.

  • 📊 1 Day view — See your keystroke breakdown by hour for today
  • 📅 7 Days / 30 Days view — Track your daily keystroke totals over the past week or month
  • 🔒 Privacy-first — Zero text capture, zero network calls, fully local
  • Lightweight — Counts are batched to disk every 10s instead of on every keystroke
  • 🚀 Launch at Login — Optional toggle to start automatically on sign-in
  • 🛡️ Reset confirmation — Clearing today's count requires a second confirmation

Privacy

What TypingCounter does What it does NOT do
✅ Counts keydown events ❌ Capture or log typed text
✅ Stores history locally on your Mac ❌ Send any data over the network
✅ Shows count in Menu Bar ❌ Access clipboard or app content

Getting Started

Option 1 — Download (Recommended)

Download the latest .app from Releases and drag it to your Applications folder.

Option 2 — Build from Source (VSCode + swiftc)

This project uses swiftc + Charts directly, without an Xcode project.

  1. Open the folder in VSCode
  2. Run the existing swiftc-based build script
  3. Launch the generated macOS app bundle
  4. Rebuild after any source changes

Option 3 — Xcode Setup

  1. Open Xcode → File → New → Project
  2. Choose macOS → App (SwiftUI, Swift)
  3. Set deployment target to macOS 13.0+
  4. Add all source files (TypingCounterApp.swift, AppDelegate.swift, Core/*, Models/*, Views/*) to the app target
  5. Ensure @main is set in TypingCounterApp.swift with @NSApplicationDelegateAdaptor(AppDelegate.self)

Permissions Required

TypingCounter only needs Accessibility to function — the global keydown monitor is built on an API that doesn't require Input Monitoring.

System Settings → Privacy & Security → Accessibility → Enable TypingCounter

The app polls for this permission automatically, so counting starts on its own once granted — but if you enable it while the app is already running, quitting and relaunching once is the most reliable way to pick it up.

⚠️ If running from Xcode during development, grant permission to Xcode instead.


Required Info.plist Keys

<key>LSUIElement</key>
<true/>
<key>NSInputMonitoringUsageDescription</key>
<string>TypingCounter needs Input Monitoring permission to count keydown events globally.</string>
<key>NSAppleEventsUsageDescription</key>
<string>TypingCounter may use Apple Events for accessibility-related automation support.</string>
  • LSUIElement = true hides the Dock icon and keeps the app in the Menu Bar only.
  • NSInputMonitoringUsageDescription is present for informational purposes but isn't actually gated on — see Permissions Required above.

Project Structure

TypingCounter/
├─ AppDelegate.swift          # Menu bar status item + popover lifecycle
├─ TypingCounterApp.swift     # SwiftUI app entry point
├─ Core/
│  ├─ CounterManager.swift    # Main counting/state orchestration
│  ├─ KeyboardMonitor.swift   # Global keydown monitoring
│  ├─ HistoryStore.swift      # Local history persistence (batched writes)
│  └─ DateUtil.swift          # Shared date formatting helper
├─ Models/
│  ├─ DailyRecord.swift       # Daily count data model
│  └─ HourlyRecord.swift      # Hourly count data model
├─ Views/
│  ├─ PopoverView.swift        # Main popover UI
│  ├─ StatsView.swift          # Stats chart UI
│  └─ HistoryChartView.swift   # 1-day/7-day/30-day chart rendering
└─ README.md

FAQ & Troubleshooting

Counter doesn't increase
  • Check Accessibility is enabled for TypingCounter in System Settings
  • If using Xcode, grant permission to Xcode too
  • Relaunch the app after granting permission — it also polls automatically every few seconds, so it should pick this up on its own without a relaunch in most cases
Some keypresses don't count
  • Arrow keys, function keys, media keys, and shortcut keys are intentionally ignored
  • Some apps don't expose a focused text element clearly, so the keypress is skipped
Menu bar icon not visible
  • Confirm LSUIElement is true in Info.plist
  • Verify NSStatusItem is created inside applicationDidFinishLaunching
Popover doesn't open
  • Ensure the status item button has action and target set
  • Confirm the popover content view/controller is initialized
Works once, then stops counting
  • Check event monitor lifecycle — make sure the monitor reference is retained and not deallocated
  • Re-check permissions if the app bundle ID changed

Limitations

  • Counts keydown events only — no awareness of what was typed
  • Requires user-granted macOS privacy permissions
  • Local and single-device only (no sync)
  • Keyboard layout / IME behavior may affect event semantics

Roadmap

  • Per-app keystroke breakdown (still text-free)
  • Weekly/monthly stats — 7-day and 30-day views
  • Export anonymized count metrics (local file only)
  • Better onboarding flow for permissions — auto-poll + direct link to Accessibility settings
  • Health indicator for monitoring state — green/orange status label in the popover

License

MIT © Joe NG

About

A lightweight macOS Menu Bar app that silently monitors global keyboard input in the background, tracks daily keystroke count in real time, and displays it in the Menu Bar. Built as a personal productivity tool focused on low resource usage, privacy, and simplicity.

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages