;--------------------------------------------------------------------------------------------------------------- ; CHANGELOG: ; ; Oct 07 2023: Initial release by Glisense ltd ; ; Current script is designed for use together with KeyboardExtension® (https://keyboardextension.com) ; ; For the latest version, description and licensing terms go to https://keyboardextension.com/plugins/63a2a50f ; ;--------------------------------------------------------------------------------------------------------------- #Requires AutoHotkey v2 #NoTrayIcon Persistent CoordMode 'ToolTip' GetCoresLoad() SetTimer TrackCoresLoad.Bind(&sLabels := '', &sValues := '', &sFullLoad := ''), 1000 TrackCoresLoad(&sLabels, &sValues, &sFullLoad) { cpuUsage := GetCoresLoad() names := [], values := [], fullLoad := 0 for k, v in cpuUsage { names.Push({ id: A_Index, value: k }) values.Push({ id: A_Index, value: Round(v) . '%' }) fullLoad += v } sLabels := AhkToJSON(names) sValues := AhkToJSON(values) sFullLoad := Round( fullLoad/cpuUsage.Count ) . '%' ; ToolTip sLabels . '`n' . sValues . '`n' . sFullLoad, 3, 3, 1 } GetCoresLoad() { static sppi := SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION := 0x8, lastInfo := [], first := false DllCall('ntdll\NtQuerySystemInformation', 'Int', sppi, 'Ptr', 0, 'UInt', 0, 'UInt*', &retSize := 0) systemProcPerfInfo := Buffer(size := retSize, 0) DllCall('ntdll\NtQuerySystemInformation', 'Int', sppi, 'Ptr', systemProcPerfInfo, 'UInt', size, 'UInt*', &retSize) currentInfo := [], offset := 0, cpuCount := size//48, (first && cpuUsage := OrderedMap()) Loop cpuCount { i := A_Index IdleTime := NumGet(systemProcPerfInfo, offset , 'UInt64') KernelTime := NumGet(systemProcPerfInfo, offset + 8, 'UInt64') UserTime := NumGet(systemProcPerfInfo, offset + 16, 'UInt64') currentInfo.Push({it: IdleTime, kt: KernelTime, ut: UserTime}) if first { cpuUsage['Thread ' . i] := Round(100 * (1 - (IdleTime - lastInfo[i].it) / (KernelTime - lastInfo[i].kt + UserTime - lastInfo[i].ut))) } offset += 48 } lastInfo := currentInfo first := true return IsSet(cpuUsage) ? cpuUsage : '' } AhkToJSON(obj, indent := '') { static document := '', JS if !document { document := ComObject('HTMLFILE') document.write('') JS := document.parentWindow (document.documentMode < 9 && JS.execScript()) } if indent = true { if IsObject(obj) { isArray := Type(obj) = 'Array' enumerable := Type(obj) = 'Object' ? obj.OwnProps() : obj str := '' for k, v in enumerable str .= (A_Index = 1 ? '' : ',') . (isArray ? '' : %A_ThisFunc%(k, true) . ':') . %A_ThisFunc%(v, true) return isArray ? '[' str ']' : '{' str '}' } if IsNumber(obj) && Type(obj) != 'String' return obj for k, v in [['\', '\\'], [A_Tab, '\t'], ['"', '\"'], ['/', '\/'], ['`n', '\n'], ['`r', '\r'], [Chr(12), '\f'], [Chr(8), '\b']] obj := StrReplace(obj, v[1], v[2]) return '"' obj '"' } sObj := %A_ThisFunc%(obj, true) return JS.eval('JSON.stringify(' . sObj . ',"","' . indent . '")') } class OrderedMap { Default := unset _entrySet_ := [] _entrySet_.CaseSense := 'On' __New(keyValueList*) => this.Set(keyValueList*) CaseSense { ; 'On', 'Off', true, false get => this._entrySet_.CaseSense set { if this._entrySet_.Length { throw ValueError('Map must be empty') } return this._entrySet_.CaseSense := value } } Count => this._entrySet_.Length Clear() => (this._entrySet_ := [], '') Has(key) => (this._FindKey(key, &found := 0), !!found) Delete(key) { this._FindKey(key, &found := 0) if found { return this._entrySet_.RemoveAt(found)[2] } throw UnsetItemError('Map has no such key',, key) } Get(key, default?) { res := this._FindKey(key, &found := 0) if found return res else if IsSet(default) return default else if this.HasOwnProp('Default') return this.Default throw UnsetItemError('Map has no such key',, key) } Set(keyValueList*) { if Mod(keyValueList.Length, 2) { throw ValueError('Incorrect keyValueList: the number of elements must be even!') } for k, v in keyValueList { Mod(k, 2) ? (_v := v) : this[_v] := v } } __Enum(*) { this._entrySet_.i := 0 return (&a, &b?) => ( i := ++this._entrySet_.i, i > this._entrySet_.Length ? false : ( a := this._entrySet_[i][1], b := this._entrySet_[i][2], true ) ) } __Item[key] { get { res := this._FindKey(key, &found := 0) if found { return res } if this.HasOwnProp('Default') return this.Default throw UnsetItemError('Map has no such key',, key) } set { this._FindKey(key, &found := 0, value) if !found { this._entrySet_.Push([key, value]) } return value } } _FindKey(key, &found, assign?) { for k, v in this._entrySet_ { t := Type(v[1]) if (t = 'String' && !StrCompare(key, v[1], this._entrySet_.CaseSense)) || (t != 'String' && key = v[1]) { found := k return IsSet(assign) ? (v[2] := assign) : v[2] } } } }