; UsageStats.ahk — Compteurs d'usage et derniers choix de variables (architecture §15). ; Fichier usage.json à côté de la bibliothèque. Ne contient JAMAIS de valeurs 'password' ; ni le contenu des variables automatiques (sélection / presse-papiers). class UsageStats { Path := "" Data := Map() ; id -> Map(count, last_used, last_values: Map) __New(path) { this.Path := path this.Load() } Load() { this.Data := Map() if !FileExist(this.Path) return try { raw := FileRead(this.Path, "UTF-8") parsed := Json.Parse(raw) if (parsed is Map) this.Data := parsed } catch as e { Util.Log("usage.json illisible, reparti de zéro : " e.Message) this.Data := Map() } } Save() { try { f := FileOpen(this.Path, "w", "UTF-8") f.Write(Json.Stringify(this.Data, 1)) f.Close() } catch as e { Util.Log("Écriture usage.json impossible : " e.Message) } } RecordUse(id, manualValues := "") { if !this.Data.Has(id) this.Data[id] := Map("count", 0, "last_used", "", "last_values", Map()) entry := this.Data[id] entry["count"] := (entry.Has("count") ? Integer(entry["count"]) : 0) + 1 entry["last_used"] := A_Now ; format AHK YYYYMMDDHH24MISS (comparaisons et DateDiff) if (manualValues is Map) { if !entry.Has("last_values") || !(entry["last_values"] is Map) entry["last_values"] := Map() lv := entry["last_values"] for name, val in manualValues { ; Les mots de passe et les contextes ne sont jamais mémorisés (§10.4 / §15). if (name = "password" || name = "selection" || name = "clipboard") continue lv[name] := String(val) } } this.Save() } LastValues(id) { if (this.Data.Has(id) && this.Data[id].Has("last_values") && (this.Data[id]["last_values"] is Map)) return this.Data[id]["last_values"] return Map() } Count(id) { if (this.Data.Has(id) && this.Data[id].Has("count")) return Integer(this.Data[id]["count"]) return 0 } Reset() { this.Data := Map() this.Save() } }