Can AHK detect when Action Center notifications occur?
Can AHK detect when Action Center notifications occur?
Hello! I've never used AutoHotkey before but have been told it might be helpful for something I've been wanting to do. Is it possible to set up AHK to run a command whenever the Action Center gets a notification from a given app? Thanks!
Re: Can AHK detect when Action Center notifications occur?
AFAICS, no. The only thing I found about that - probably offering some details for a conversion - is this: https://docs.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/notification-listener
Good luck
BTW, the majority of articles I've done some research on this topic have suggested to check out EventViewer instead.
Good luck
BTW, the majority of articles I've done some research on this topic have suggested to check out EventViewer instead.
Remember to use [code]CODE[/code]-tags for your multi-line scripts. Stay safe, stay inside, and remember washing your hands for 20 sec !
Re: Can AHK detect when Action Center notifications occur?
It looks like the link you gave applies when developing an app. To make sure my question isn't confusing, I'm asking about an already-created app (specifically, TextNow) which sends notifications to the Action Center. Is there a way I could create an event on my computer that can trigger whenever an already-developed app (as opposed to an app I'm programming) sends a notification to the Action Center? Thanks!BNOLI wrote: ↑19 May 2020, 00:50AFAICS, no. The only thing I found about that - probably offering some details for a conversion - is this: https://docs.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/notification-listener
Good luck
BTW, the majority of articles I've done some research on this topic have suggested to check out EventViewer instead.
Re: Can AHK detect when Action Center notifications occur?
Yep, that's what the linked content is about, how to become the (listening) man in the middle. There are a few fantastic members at this forum who might be able to translate/convert that code into something that can be used the way you've requested - or coming up with a completely different way .
So, get your fingers crossed & good luck
So, get your fingers crossed & good luck
Remember to use [code]CODE[/code]-tags for your multi-line scripts. Stay safe, stay inside, and remember washing your hands for 20 sec !
Re: Can AHK detect when Action Center notifications occur?
Kilk1, here is examples how to use Windows Runtime API in ahk:
https://www.autohotkey.com/boards/viewtopic.php?f=6&t=72674
https://www.autohotkey.com/boards/viewtopic.php?f=6&t=72797
https://www.autohotkey.com/boards/viewtopic.php?p=319141#p319141
I am sure that You can get notifications from action center in loop with UserNotificationListener.GetNotificationsAsync method and then parse them without any problem.
https://docs.microsoft.com/en-us/uwp/ap ... ationKinds_
But set event listener - it will be quite difficult.
https://www.autohotkey.com/boards/viewtopic.php?f=6&t=72674
https://www.autohotkey.com/boards/viewtopic.php?f=6&t=72797
https://www.autohotkey.com/boards/viewtopic.php?p=319141#p319141
I am sure that You can get notifications from action center in loop with UserNotificationListener.GetNotificationsAsync method and then parse them without any problem.
https://docs.microsoft.com/en-us/uwp/ap ... ationKinds_
But set event listener - it will be quite difficult.
Re: Can AHK detect when Action Center notifications occur?
Tried to do it but there is memory leaking, therefore I empty working set.
Memory leaking may be because I not correct send enumerations
https://docs.microsoft.com/en-us/uwp/api/windows.ui.notifications.notificationkinds?view=winrt-18362
But despite of that code is working.
Code shows notification send by autohotkey.
Notification send with this code:
Memory leaking may be because I not correct send enumerations
https://docs.microsoft.com/en-us/uwp/api/windows.ui.notifications.notificationkinds?view=winrt-18362
But despite of that code is working.
Code shows notification send by autohotkey.
Code: Select all
AppName := "Autohotkey"
setbatchlines -1
CreateClass("Windows.UI.Notifications.Management.UserNotificationListener", IUserNotificationListenerStatics := "{FF6123CF-4386-4AA3-B73D-B804E5B63B23}", UserNotificationListenerStatics)
DllCall(NumGet(NumGet(UserNotificationListenerStatics+0)+6*A_PtrSize), "ptr", UserNotificationListenerStatics, "ptr*", listener) ; get_Current
DllCall(NumGet(NumGet(listener+0)+6*A_PtrSize), "ptr", listener, "int*", accessStatus) ; RequestAccessAsync
WaitForAsync(accessStatus)
if (accessStatus != 1)
{
msgbox AccessStatus Denied
exitapp
}
loop
{
DllCall(NumGet(NumGet(listener+0)+10*A_PtrSize), "ptr", listener, "int", 1, "ptr*", UserNotificationReadOnlyList) ; GetNotificationsAsync
WaitForAsync(UserNotificationReadOnlyList)
DllCall(NumGet(NumGet(UserNotificationReadOnlyList+0)+7*A_PtrSize), "ptr", UserNotificationReadOnlyList, "int*", count) ; count
loop % count
{
DllCall(NumGet(NumGet(UserNotificationReadOnlyList+0)+6*A_PtrSize), "ptr", UserNotificationReadOnlyList, "int", A_Index-1, "ptr*", UserNotification) ; get_Item
DllCall(NumGet(NumGet(UserNotification+0)+8*A_PtrSize), "ptr", UserNotification, "uint*", id) ; get_Id
if InStr(idList, "|" id "|")
{
ObjRelease(UserNotification)
Continue
}
idList .= "|" id "|"
if !DllCall(NumGet(NumGet(UserNotification+0)+7*A_PtrSize), "ptr", UserNotification, "ptr*", AppInfo) ; get_AppInfo
{
DllCall(NumGet(NumGet(AppInfo+0)+8*A_PtrSize), "ptr", AppInfo, "ptr*", AppDisplayInfo) ; get_DisplayInfo
DllCall(NumGet(NumGet(AppDisplayInfo+0)+6*A_PtrSize), "ptr", AppDisplayInfo, "ptr*", hText) ; get_DisplayName
buffer := DllCall("Combase.dll\WindowsGetStringRawBuffer", "ptr", hText, "uint*", length, "ptr")
text := StrGet(buffer, "UTF-16")
DeleteHString(hText)
ObjRelease(AppDisplayInfo)
ObjRelease(AppInfo)
if (text != AppName)
{
ObjRelease(UserNotification)
Continue
}
}
else
{
ObjRelease(UserNotification)
Continue
}
DllCall(NumGet(NumGet(UserNotification+0)+6*A_PtrSize), "ptr", UserNotification, "ptr*", Notification) ; get_Notification
DllCall(NumGet(NumGet(Notification+0)+8*A_PtrSize), "ptr", Notification, "ptr*", NotificationVisual) ; get_Visual
DllCall(NumGet(NumGet(NotificationVisual+0)+8*A_PtrSize), "ptr", NotificationVisual, "ptr*", NotificationBindingList) ; get_Bindings
DllCall(NumGet(NumGet(NotificationBindingList+0)+7*A_PtrSize), "ptr", NotificationBindingList, "int*", count) ; count
loop % count
{
DllCall(NumGet(NumGet(NotificationBindingList+0)+6*A_PtrSize), "ptr", NotificationBindingList, "int", A_Index-1, "ptr*", NotificationBinding) ; get_Item
DllCall(NumGet(NumGet(NotificationBinding+0)+11*A_PtrSize), "ptr", NotificationBinding, "ptr*", AdaptiveNotificationTextReadOnlyList) ; GetTextElements
DllCall(NumGet(NumGet(AdaptiveNotificationTextReadOnlyList+0)+7*A_PtrSize), "ptr", AdaptiveNotificationTextReadOnlyList, "int*", count) ; count
loop % count
{
DllCall(NumGet(NumGet(AdaptiveNotificationTextReadOnlyList+0)+6*A_PtrSize), "ptr", AdaptiveNotificationTextReadOnlyList, "int", A_Index-1, "ptr*", AdaptiveNotificationText) ; get_Item
DllCall(NumGet(NumGet(AdaptiveNotificationText+0)+6*A_PtrSize), "ptr", AdaptiveNotificationText, "ptr*", hText) ; get_Text
buffer := DllCall("Combase.dll\WindowsGetStringRawBuffer", "ptr", hText, "uint*", length, "ptr")
if (A_Index = 1)
text := StrGet(buffer, "UTF-16")
else
text .= "`n" StrGet(buffer, "UTF-16")
DeleteHString(hText)
ObjRelease(AdaptiveNotificationText)
}
ObjRelease(AdaptiveNotificationTextReadOnlyList)
ObjRelease(NotificationBinding)
msgbox % text
}
ObjRelease(NotificationBindingList)
ObjRelease(NotificationVisual)
ObjRelease(Notification)
ObjRelease(UserNotification)
}
ObjRelease(UserNotificationReadOnlyList)
DllCall("psapi.dll\EmptyWorkingSet", "ptr", -1)
sleep 50
}
CreateClass(string, interface, ByRef Class)
{
CreateHString(string, hString)
VarSetCapacity(GUID, 16)
DllCall("ole32\CLSIDFromString", "wstr", interface, "ptr", &GUID)
result := DllCall("Combase.dll\RoGetActivationFactory", "ptr", hString, "ptr", &GUID, "ptr*", Class, "uint")
if (result != 0)
{
if (result = 0x80004002)
msgbox No such interface supported
else if (result = 0x80040154)
msgbox Class not registered
else
msgbox error: %result%
ExitApp
}
DeleteHString(hString)
}
CreateHString(string, ByRef hString)
{
DllCall("Combase.dll\WindowsCreateString", "wstr", string, "uint", StrLen(string), "ptr*", hString)
}
DeleteHString(hString)
{
DllCall("Combase.dll\WindowsDeleteString", "ptr", hString)
}
WaitForAsync(ByRef Object)
{
AsyncInfo := ComObjQuery(Object, IAsyncInfo := "{00000036-0000-0000-C000-000000000046}")
loop
{
DllCall(NumGet(NumGet(AsyncInfo+0)+7*A_PtrSize), "ptr", AsyncInfo, "uint*", status) ; IAsyncInfo.Status
if (status != 0)
{
if (status != 1)
{
DllCall(NumGet(NumGet(AsyncInfo+0)+8*A_PtrSize), "ptr", AsyncInfo, "uint*", ErrorCode) ; IAsyncInfo.ErrorCode
msgbox AsyncInfo status error: %ErrorCode%
ExitApp
}
ObjRelease(AsyncInfo)
break
}
sleep 10
}
DllCall(NumGet(NumGet(Object+0)+8*A_PtrSize), "ptr", Object, "ptr*", ObjectResult) ; GetResults
ObjRelease(Object)
Object := ObjectResult
}
Code: Select all
; Unlike TrayTip, this API does not require a tray icon:
#NoTrayIcon
; Toast notifications from desktop apps can only use local image files.
if !FileExist("sample.png")
URLDownloadToFile https://autohotkey.com/boards/styles/simplicity/theme/images/announce_unread.png
, % A_ScriptDir "\sample.png"
; The templates are described here:
; http://msdn.com/library/windows/apps/windows.ui.notifications.toasttemplatetype.aspx
toast_template := "toastImageAndText02"
; Image path/URL must be absolute, not relative.
toast_image := A_ScriptDir "\sample.png"
; Text is an array because some templates have multiple text elements.
toast_text := ["Hello, world!", "This is the sub-text."]
; For Windows 10.0.16299 (and possibly earlier or later versions), the AppID
; must identify an app which has a shortcut on the Start screen, otherwise
; the notification won't display. AppIDs for desktop apps seem to be the
; path of the executable, with system/known folders replaced with GUIDs.
; If this doesn't work, the Get-StartApps powershell command can be used to
; get a list of AppIDs on the system.
; This assumes AutoHotkey is installed in the default location:
toast_appid := (A_Is64bitOS ? "{6D809377-6AF0-444b-8957-A3773F02200E}"
: "{905e63b6-c1bf-494e-b29c-65b732d3d21a}")
. "\AutoHotkey\AutoHotkey.exe"
; Only the Edge version of JsRT supports WinRT.
js := new JsRT.Edge
js.AddObject("yesno", Func("yesno"))
yesno(s) {
return
}
; Enable use of WinRT. "Windows.UI" or "Windows" would also work.
js.ProjectWinRTNamespace("Windows.UI.Notifications")
code =
(
function toast(template, image, text, app) {
// Alias for convenience.
var N = Windows.UI.Notifications;
// Get the template XML as an XmlDocument.
var toastXml = N.ToastNotificationManager
.getTemplateContent(N.ToastTemplateType[template]);
// Insert our content.
var i = 0;
for (let el of toastXml.getElementsByTagName("text")) {
if (typeof text == 'string') {
el.innerText = text;
break;
}
el.innerText = text[++i];
}
toastXml.getElementsByTagName("image")[0]
.setAttribute("src", image);
// Show the notification.
var toastNotifier = N.ToastNotificationManager
.createToastNotifier(app || "AutoHotkey");
var notification = new N.ToastNotification(toastXml);
toastNotifier.show(notification);
// Unlike TrayTip, this API lets us hide the notification:
if (yesno("Hide the notification?")) {
toastNotifier.hide(notification);
}
}
)
try {
; Define the toast function.
js.Exec(code)
; Show a toast notification.
js.toast(toast_template, toast_image, toast_text, toast_appid)
}
catch ex {
try errmsg := ex.stack
if !errmsg
errmsg := "Error: " ex.message
MsgBox % errmsg
}
; Note: If the notification wasn't hidden, it will remain after we exit.
ExitApp
/*
* JsRT for AutoHotkey v1.1
*
* Utilizes the JavaScript engine that comes with IE11.
*
* License: Use, modify and redistribute without limitation, but at your own risk.
*/
class JsRT extends ActiveScript._base
{
__New()
{
throw Exception("This class is abstract. Use JsRT.IE or JSRT.Edge instead.", -1)
}
class IE extends JsRT
{
__New()
{
if !this._hmod := DllCall("LoadLibrary", "str", "jscript9", "ptr")
throw Exception("Failed to load jscript9.dll", -1)
if DllCall("jscript9\JsCreateRuntime", "int", 0, "int", -1
, "ptr", 0, "ptr*", runtime) != 0
throw Exception("Failed to initialize JsRT", -1)
DllCall("jscript9\JsCreateContext", "ptr", runtime, "ptr", 0, "ptr*", context)
this._Initialize("jscript9", runtime, context)
}
}
class Edge extends JsRT
{
__New()
{
if !this._hmod := DllCall("LoadLibrary", "str", "chakra", "ptr")
throw Exception("Failed to load chakra.dll", -1)
if DllCall("chakra\JsCreateRuntime", "int", 0
, "ptr", 0, "ptr*", runtime) != 0
throw Exception("Failed to initialize JsRT", -1)
DllCall("chakra\JsCreateContext", "ptr", runtime, "ptr*", context)
this._Initialize("chakra", runtime, context)
}
ProjectWinRTNamespace(namespace)
{
return DllCall("chakra\JsProjectWinRTNamespace", "wstr", namespace)
}
}
_Initialize(dll, runtime, context)
{
this._dll := dll
this._runtime := runtime
this._context := context
DllCall(dll "\JsSetCurrentContext", "ptr", context)
DllCall(dll "\JsGetGlobalObject", "ptr*", globalObject)
this._dsp := this._JsToVt(globalObject)
}
__Delete()
{
this._dsp := ""
if dll := this._dll
{
DllCall(dll "\JsSetCurrentContext", "ptr", 0)
DllCall(dll "\JsDisposeRuntime", "ptr", this._runtime)
}
DllCall("FreeLibrary", "ptr", this._hmod)
}
_JsToVt(valref)
{
VarSetCapacity(variant, 24, 0)
DllCall(this._dll "\JsValueToVariant", "ptr", valref, "ptr", &variant)
ref := ComObject(0x400C, &variant), val := ref[], ref[] := 0
return val
}
_ToJs(val)
{
VarSetCapacity(variant, 24, 0)
ref := ComObject(0x400C, &variant) ; VT_BYREF|VT_VARIANT
ref[] := val
DllCall(this._dll "\JsVariantToValue", "ptr", &variant, "ptr*", valref)
ref[] := 0
return valref
}
_JsEval(code)
{
e := DllCall(this._dll "\JsRunScript", "wstr", code, "uptr", 0, "wstr", "source.js"
, "ptr*", result)
if e
{
if DllCall(this._dll "\JsGetAndClearException", "ptr*", excp) = 0
throw this._JsToVt(excp)
throw Exception("JsRT error", -2, format("0x{:X}", e))
}
return result
}
Exec(code)
{
this._JsEval(code)
}
Eval(code)
{
return this._JsToVt(this._JsEval(code))
}
AddObject(name, obj, addMembers := false)
{
if addMembers
throw Exception("AddMembers=true is not supported", -1)
this._dsp[name] := obj
}
}
/*
* ActiveScript for AutoHotkey v1.1
*
* Provides an interface to Active Scripting languages like VBScript and JScript,
* without relying on Microsoft's ScriptControl, which is not available to 64-bit
* programs.
*
* License: Use, modify and redistribute without limitation, but at your own risk.
*/
class ActiveScript extends ActiveScript._base
{
__New(Language)
{
if this._script := ComObjCreate(Language, ActiveScript.IID)
this._scriptParse := ComObjQuery(this._script, ActiveScript.IID_Parse)
if !this._scriptParse
throw Exception("Invalid language", -1, Language)
this._site := new ActiveScriptSite(this)
this._SetScriptSite(this._site.ptr)
this._InitNew()
this._objects := {}
this.Error := ""
this._dsp := this._GetScriptDispatch() ; Must be done last.
try
if this.ScriptEngine() = "JScript"
this.SetJScript58()
}
SetJScript58()
{
static IID_IActiveScriptProperty := "{4954E0D0-FBC7-11D1-8410-006008C3FBFC}"
if !prop := ComObjQuery(this._script, IID_IActiveScriptProperty)
return false
VarSetCapacity(var, 24, 0), NumPut(2, NumPut(3, var, "short") + 6)
hr := DllCall(NumGet(NumGet(prop+0)+4*A_PtrSize), "ptr", prop, "uint", 0x4000
, "ptr", 0, "ptr", &var), ObjRelease(prop)
return hr >= 0
}
Eval(Code)
{
pvar := NumGet(ComObjValue(arr:=ComObjArray(0xC,1)) + 8+A_PtrSize)
this._ParseScriptText(Code, 0x20, pvar) ; SCRIPTTEXT_ISEXPRESSION := 0x20
return arr[0]
}
Exec(Code)
{
this._ParseScriptText(Code, 0x42, 0) ; SCRIPTTEXT_ISVISIBLE := 2, SCRIPTTEXT_ISPERSISTENT := 0x40
this._SetScriptState(2) ; SCRIPTSTATE_CONNECTED := 2
}
AddObject(Name, DispObj, AddMembers := false)
{
static a, supports_dispatch ; Test for built-in IDispatch support.
:= a := ((a:=ComObjArray(0xC,1))[0]:=[42]) && a[0][1]=42
if IsObject(DispObj) && !(supports_dispatch || ComObjType(DispObj))
throw Exception("Adding a non-COM object requires AutoHotkey v1.1.17+", -1)
this._objects[Name] := DispObj
this._AddNamedItem(Name, AddMembers ? 8 : 2) ; SCRIPTITEM_ISVISIBLE := 2, SCRIPTITEM_GLOBALMEMBERS := 8
}
_GetObjectUnk(Name)
{
return !IsObject(dsp := this._objects[Name]) ? dsp ; Pointer
: ComObjValue(dsp) ? ComObjValue(dsp) ; ComObject
: &dsp ; AutoHotkey object
}
class _base
{
__Call(Method, Params*)
{
if ObjHasKey(this, "_dsp")
try
return (this._dsp)[Method](Params*)
catch e
throw Exception(e.Message, -1, e.Extra)
}
__Get(Property, Params*)
{
if ObjHasKey(this, "_dsp")
try
return (this._dsp)[Property, Params*]
catch e
throw Exception(e.Message, -1, e.Extra)
}
__Set(Property, Params*)
{
if ObjHasKey(this, "_dsp")
{
Value := Params.Pop()
try
return (this._dsp)[Property, Params*] := Value
catch e
throw Exception(e.Message, -1, e.Extra)
}
}
}
_SetScriptSite(Site)
{
hr := DllCall(NumGet(NumGet((p:=this._script)+0)+3*A_PtrSize), "ptr", p, "ptr", Site)
if (hr < 0)
this._HRFail(hr, "IActiveScript::SetScriptSite")
}
_SetScriptState(State)
{
hr := DllCall(NumGet(NumGet((p:=this._script)+0)+5*A_PtrSize), "ptr", p, "int", State)
if (hr < 0)
this._HRFail(hr, "IActiveScript::SetScriptState")
}
_AddNamedItem(Name, Flags)
{
hr := DllCall(NumGet(NumGet((p:=this._script)+0)+8*A_PtrSize), "ptr", p, "wstr", Name, "uint", Flags)
if (hr < 0)
this._HRFail(hr, "IActiveScript::AddNamedItem")
}
_GetScriptDispatch()
{
hr := DllCall(NumGet(NumGet((p:=this._script)+0)+10*A_PtrSize), "ptr", p, "ptr", 0, "ptr*", pdsp)
if (hr < 0)
this._HRFail(hr, "IActiveScript::GetScriptDispatch")
return ComObject(9, pdsp, 1)
}
_InitNew()
{
hr := DllCall(NumGet(NumGet((p:=this._scriptParse)+0)+3*A_PtrSize), "ptr", p)
if (hr < 0)
this._HRFail(hr, "IActiveScriptParse::InitNew")
}
_ParseScriptText(Code, Flags, pvarResult)
{
VarSetCapacity(excp, 8 * A_PtrSize, 0)
hr := DllCall(NumGet(NumGet((p:=this._scriptParse)+0)+5*A_PtrSize), "ptr", p
, "wstr", Code, "ptr", 0, "ptr", 0, "ptr", 0, "uptr", 0, "uint", 1
, "uint", Flags, "ptr", pvarResult, "ptr", 0)
if (hr < 0)
this._HRFail(hr, "IActiveScriptParse::ParseScriptText")
}
_HRFail(hr, what)
{
if e := this.Error
{
this.Error := ""
throw Exception("`nError code:`t" this._HRFormat(e.HRESULT)
. "`nSource:`t`t" e.Source "`nDescription:`t" e.Description
. "`nLine:`t`t" e.Line "`nColumn:`t`t" e.Column
. "`nLine text:`t`t" e.LineText, -3)
}
throw Exception(what " failed with code " this._HRFormat(hr), -2)
}
_HRFormat(hr)
{
return Format("0x{1:X}", hr & 0xFFFFFFFF)
}
_OnScriptError(err) ; IActiveScriptError err
{
VarSetCapacity(excp, 8 * A_PtrSize, 0)
DllCall(NumGet(NumGet(err+0)+3*A_PtrSize), "ptr", err, "ptr", &excp) ; GetExceptionInfo
DllCall(NumGet(NumGet(err+0)+4*A_PtrSize), "ptr", err, "uint*", srcctx, "uint*", srcline, "int*", srccol) ; GetSourcePosition
DllCall(NumGet(NumGet(err+0)+5*A_PtrSize), "ptr", err, "ptr*", pbstrcode) ; GetSourceLineText
code := StrGet(pbstrcode, "UTF-16"), DllCall("OleAut32\SysFreeString", "ptr", pbstrcode)
if fn := NumGet(excp, 6 * A_PtrSize) ; pfnDeferredFillIn
DllCall(fn, "ptr", &excp)
wcode := NumGet(excp, 0, "ushort")
hr := wcode ? 0x80040200 + wcode : NumGet(excp, 7 * A_PtrSize, "uint")
this.Error := {HRESULT: hr, Line: srcline, Column: srccol, LineText: code}
static Infos := "Source,Description,HelpFile"
Loop Parse, % Infos, `,
if pbstr := NumGet(excp, A_Index * A_PtrSize)
this.Error[A_LoopField] := StrGet(pbstr, "UTF-16"), DllCall("OleAut32\SysFreeString", "ptr", pbstr)
return 0x80004001 ; E_NOTIMPL (let Exec/Eval get a fail result)
}
__Delete()
{
if this._script
{
DllCall(NumGet(NumGet((p:=this._script)+0)+7*A_PtrSize), "ptr", p) ; Close
ObjRelease(this._script)
}
if this._scriptParse
ObjRelease(this._scriptParse)
}
static IID := "{BB1A2AE1-A4F9-11cf-8F20-00805F2CD064}"
static IID_Parse := A_PtrSize=8 ? "{C7EF7658-E1EE-480E-97EA-D52CB4D76D17}" : "{BB1A2AE2-A4F9-11cf-8F20-00805F2CD064}"
}
class ActiveScriptSite
{
__New(Script)
{
ObjSetCapacity(this, "_site", 3 * A_PtrSize)
NumPut(&Script
, NumPut(ActiveScriptSite._vftable("_vft_w", "31122", 0x100)
, NumPut(ActiveScriptSite._vftable("_vft", "31125232211", 0)
, this.ptr := ObjGetAddress(this, "_site"))))
}
_vftable(Name, PrmCounts, EIBase)
{
if p := ObjGetAddress(this, Name)
return p
ObjSetCapacity(this, Name, StrLen(PrmCounts) * A_PtrSize)
p := ObjGetAddress(this, Name)
Loop Parse, % PrmCounts
{
cb := RegisterCallback("_ActiveScriptSite", "F", A_LoopField, A_Index + EIBase)
NumPut(cb, p + (A_Index-1) * A_PtrSize)
}
return p
}
}
_ActiveScriptSite(this, a1:=0, a2:=0, a3:=0, a4:=0, a5:=0)
{
Method := A_EventInfo & 0xFF
if A_EventInfo >= 0x100 ; IActiveScriptSiteWindow
{
if Method = 4 ; GetWindow
{
NumPut(0, a1+0) ; *phwnd := 0
return 0 ; S_OK
}
if Method = 5 ; EnableModeless
{
return 0 ; S_OK
}
this -= A_PtrSize ; Cast to IActiveScriptSite
}
;else: IActiveScriptSite
if Method = 1 ; QueryInterface
{
iid := _AS_GUIDToString(a1)
if (iid = "{00000000-0000-0000-C000-000000000046}" ; IUnknown
|| iid = "{DB01A1E3-A42B-11cf-8F20-00805F2CD064}") ; IActiveScriptSite
{
NumPut(this, a2+0)
return 0 ; S_OK
}
if (iid = "{D10F6761-83E9-11cf-8F20-00805F2CD064}") ; IActiveScriptSiteWindow
{
NumPut(this + A_PtrSize, a2+0)
return 0 ; S_OK
}
NumPut(0, a2+0)
return 0x80004002 ; E_NOINTERFACE
}
if Method = 5 ; GetItemInfo
{
a1 := StrGet(a1, "UTF-16")
, (a3 && NumPut(0, a3+0)) ; *ppiunkItem := NULL
, (a4 && NumPut(0, a4+0)) ; *ppti := NULL
if (a2 & 1) ; SCRIPTINFO_IUNKNOWN
{
if !(unk := Object(NumGet(this + A_PtrSize*2))._GetObjectUnk(a1))
return 0x8002802B ; TYPE_E_ELEMENTNOTFOUND
ObjAddRef(unk), NumPut(unk, a3+0)
}
return 0 ; S_OK
}
if Method = 9 ; OnScriptError
return Object(NumGet(this + A_PtrSize*2))._OnScriptError(a1)
; AddRef and Release don't do anything because we want to avoid circular references.
; The site and IActiveScript are both released when the AHK script releases its last
; reference to the ActiveScript object.
; All of the other methods don't require implementations.
return 0x80004001 ; E_NOTIMPL
}
_AS_GUIDToString(pGUID)
{
VarSetCapacity(String, 38*2)
DllCall("ole32\StringFromGUID2", "ptr", pGUID, "str", String, "int", 39)
return String
}
Last edited by malcev on 27 May 2020, 15:51, edited 2 times in total.
Re: Can AHK detect when Action Center notifications occur?
Thanks, @malcev! Since I never used AHK before, I could be confused. To make sure I understand, does this code trigger when a specific app of your choice sends an Action Center notification, or does it trigger whenever any app sends an Action Center notification? Thanks!
Re: Can AHK detect when Action Center notifications occur?
Code should trigger only appplication with display name "Autohotkey".
But some applications does not have AppInfo, You have to check it by Yourself.
PS I added sleep in loop.
Code: Select all
AppName := "Autohotkey"
PS I added sleep in loop.
Re: Can AHK detect when Action Center notifications occur?
Thanks for doing all this! To make sure I understand, if I 1) get AutoHotkey, 2) use the code you provided, and 3) change "Autohotkey" to the name of the app I want, then it should work?malcev wrote: ↑20 May 2020, 10:07Code should trigger only appplication with display name "Autohotkey".But some applications does not have AppInfo, You have to check it by Yourself.Code: Select all
AppName := "Autohotkey"
PS I added sleep in loop.
Re: Can AHK detect when Action Center notifications occur?
If Your application has AppInfo then yes.
Re: Can AHK detect when Action Center notifications occur?
@malcev Hello again! I copied and pasted the code to an AHK script, but it didn't work. I changed the AppName from "Autohotkey" to "TextNow - Unlimited Texts + Calls." Since that didn't work, I changed the AppName to just "TextNow" in case this would count as it's true name, but it still didn't work.
In case what I mean is confusing, I want AHK to work with an app known as TextNow. The Windows version that I use can be downloaded here: https://www.microsoft.com/en-us/p/textnow-unlimited-texts-calls/9n43spjlcxcv?activetab=pivot:overviewtab. This app can be opened in the background. Therefore, even when TextNow is closed, it can still send notifications to the Action Center.
What I want is for TextNow to open its app whenever it sends a notification to the Action Center. How can I do this? Thanks!
In case what I mean is confusing, I want AHK to work with an app known as TextNow. The Windows version that I use can be downloaded here: https://www.microsoft.com/en-us/p/textnow-unlimited-texts-calls/9n43spjlcxcv?activetab=pivot:overviewtab. This app can be opened in the background. Therefore, even when TextNow is closed, it can still send notifications to the Action Center.
What I want is for TextNow to open its app whenever it sends a notification to the Action Center. How can I do this? Thanks!
Re: Can AHK detect when Action Center notifications occur?
This code will show You appName if it exists.
Code: Select all
AppName := "Autohotkey"
setbatchlines -1
CreateClass("Windows.UI.Notifications.Management.UserNotificationListener", IUserNotificationListenerStatics := "{FF6123CF-4386-4AA3-B73D-B804E5B63B23}", UserNotificationListenerStatics)
DllCall(NumGet(NumGet(UserNotificationListenerStatics+0)+6*A_PtrSize), "ptr", UserNotificationListenerStatics, "ptr*", listener) ; get_Current
DllCall(NumGet(NumGet(listener+0)+6*A_PtrSize), "ptr", listener, "int*", accessStatus) ; RequestAccessAsync
WaitForAsync(accessStatus)
if (accessStatus != 1)
{
msgbox AccessStatus Denied
exitapp
}
loop
{
DllCall(NumGet(NumGet(listener+0)+10*A_PtrSize), "ptr", listener, "int", 1, "ptr*", UserNotificationReadOnlyList) ; GetNotificationsAsync
WaitForAsync(UserNotificationReadOnlyList)
DllCall(NumGet(NumGet(UserNotificationReadOnlyList+0)+7*A_PtrSize), "ptr", UserNotificationReadOnlyList, "int*", count) ; count
loop % count
{
DllCall(NumGet(NumGet(UserNotificationReadOnlyList+0)+6*A_PtrSize), "ptr", UserNotificationReadOnlyList, "int", A_Index-1, "ptr*", UserNotification) ; get_Item
DllCall(NumGet(NumGet(UserNotification+0)+8*A_PtrSize), "ptr", UserNotification, "uint*", id) ; get_Id
if InStr(idList, "|" id "|")
{
ObjRelease(UserNotification)
Continue
}
idList .= "|" id "|"
if !DllCall(NumGet(NumGet(UserNotification+0)+7*A_PtrSize), "ptr", UserNotification, "ptr*", AppInfo) ; get_AppInfo
{
DllCall(NumGet(NumGet(AppInfo+0)+8*A_PtrSize), "ptr", AppInfo, "ptr*", AppDisplayInfo) ; get_DisplayInfo
DllCall(NumGet(NumGet(AppDisplayInfo+0)+6*A_PtrSize), "ptr", AppDisplayInfo, "ptr*", hText) ; get_DisplayName
buffer := DllCall("Combase.dll\WindowsGetStringRawBuffer", "ptr", hText, "uint*", length, "ptr")
text := StrGet(buffer, "UTF-16")
DeleteHString(hText)
ObjRelease(AppDisplayInfo)
ObjRelease(AppInfo)
msgbox % text
if (text != AppName)
{
ObjRelease(UserNotification)
Continue
}
}
else
{
msgbox no AppInfo
ObjRelease(UserNotification)
Continue
}
DllCall(NumGet(NumGet(UserNotification+0)+6*A_PtrSize), "ptr", UserNotification, "ptr*", Notification) ; get_Notification
DllCall(NumGet(NumGet(Notification+0)+8*A_PtrSize), "ptr", Notification, "ptr*", NotificationVisual) ; get_Visual
DllCall(NumGet(NumGet(NotificationVisual+0)+8*A_PtrSize), "ptr", NotificationVisual, "ptr*", NotificationBindingList) ; get_Bindings
DllCall(NumGet(NumGet(NotificationBindingList+0)+7*A_PtrSize), "ptr", NotificationBindingList, "int*", count) ; count
loop % count
{
DllCall(NumGet(NumGet(NotificationBindingList+0)+6*A_PtrSize), "ptr", NotificationBindingList, "int", A_Index-1, "ptr*", NotificationBinding) ; get_Item
DllCall(NumGet(NumGet(NotificationBinding+0)+11*A_PtrSize), "ptr", NotificationBinding, "ptr*", AdaptiveNotificationTextReadOnlyList) ; GetTextElements
DllCall(NumGet(NumGet(AdaptiveNotificationTextReadOnlyList+0)+7*A_PtrSize), "ptr", AdaptiveNotificationTextReadOnlyList, "int*", count) ; count
loop % count
{
DllCall(NumGet(NumGet(AdaptiveNotificationTextReadOnlyList+0)+6*A_PtrSize), "ptr", AdaptiveNotificationTextReadOnlyList, "int", A_Index-1, "ptr*", AdaptiveNotificationText) ; get_Item
DllCall(NumGet(NumGet(AdaptiveNotificationText+0)+6*A_PtrSize), "ptr", AdaptiveNotificationText, "ptr*", hText) ; get_Text
buffer := DllCall("Combase.dll\WindowsGetStringRawBuffer", "ptr", hText, "uint*", length, "ptr")
if (A_Index = 1)
text := StrGet(buffer, "UTF-16")
else
text .= "`n" StrGet(buffer, "UTF-16")
DeleteHString(hText)
ObjRelease(AdaptiveNotificationText)
}
ObjRelease(AdaptiveNotificationTextReadOnlyList)
ObjRelease(NotificationBinding)
msgbox % text
}
ObjRelease(NotificationBindingList)
ObjRelease(NotificationVisual)
ObjRelease(Notification)
ObjRelease(UserNotification)
}
ObjRelease(UserNotificationReadOnlyList)
DllCall("psapi.dll\EmptyWorkingSet", "ptr", -1)
sleep 50
}
CreateClass(string, interface, ByRef Class)
{
CreateHString(string, hString)
VarSetCapacity(GUID, 16)
DllCall("ole32\CLSIDFromString", "wstr", interface, "ptr", &GUID)
result := DllCall("Combase.dll\RoGetActivationFactory", "ptr", hString, "ptr", &GUID, "ptr*", Class, "uint")
if (result != 0)
{
if (result = 0x80004002)
msgbox No such interface supported
else if (result = 0x80040154)
msgbox Class not registered
else
msgbox error: %result%
ExitApp
}
DeleteHString(hString)
}
CreateHString(string, ByRef hString)
{
DllCall("Combase.dll\WindowsCreateString", "wstr", string, "uint", StrLen(string), "ptr*", hString)
}
DeleteHString(hString)
{
DllCall("Combase.dll\WindowsDeleteString", "ptr", hString)
}
WaitForAsync(ByRef Object)
{
AsyncInfo := ComObjQuery(Object, IAsyncInfo := "{00000036-0000-0000-C000-000000000046}")
loop
{
DllCall(NumGet(NumGet(AsyncInfo+0)+7*A_PtrSize), "ptr", AsyncInfo, "uint*", status) ; IAsyncInfo.Status
if (status != 0)
{
if (status != 1)
{
DllCall(NumGet(NumGet(AsyncInfo+0)+8*A_PtrSize), "ptr", AsyncInfo, "uint*", ErrorCode) ; IAsyncInfo.ErrorCode
msgbox AsyncInfo status error: %ErrorCode%
ExitApp
}
ObjRelease(AsyncInfo)
break
}
sleep 10
}
DllCall(NumGet(NumGet(Object+0)+8*A_PtrSize), "ptr", Object, "ptr*", ObjectResult) ; GetResults
ObjRelease(Object)
Object := ObjectResult
}
Last edited by malcev on 27 May 2020, 15:53, edited 1 time in total.
Re: Can AHK detect when Action Center notifications occur?
When you say, "This code will show You appName if it exists," do you mean it will show me what TextNow's name is? That's not necessarily what I'm wanting to do. What I'm wanting is something that means this:malcev wrote: ↑25 May 2020, 14:20This code will show You appName if it exists.Code: Select all
AppName := "Autohotkey" setbatchlines -1 CreateClass("Windows.UI.Notifications.Management.UserNotificationListener", IUserNotificationListenerStatics := "{FF6123CF-4386-4AA3-B73D-B804E5B63B23}", UserNotificationListenerStatics) DllCall(NumGet(NumGet(UserNotificationListenerStatics+0)+6*A_PtrSize), "ptr", UserNotificationListenerStatics, "ptr*", listener) ; get_Current DllCall(NumGet(NumGet(listener+0)+6*A_PtrSize), "ptr", listener, "int*", accessStatus) ; RequestAccessAsync WaitForAsync(accessStatus) if (accessStatus != 1) { msgbox AccessStatus Denied exitapp } loop { DllCall(NumGet(NumGet(listener+0)+10*A_PtrSize), "ptr", listener, "int", 1, "ptr*", UserNotificationReadOnlyList) ; GetNotificationsAsync WaitForAsync(UserNotificationReadOnlyList) DllCall(NumGet(NumGet(UserNotificationReadOnlyList+0)+7*A_PtrSize), "ptr", UserNotificationReadOnlyList, "int*", count) ; count loop % count { DllCall(NumGet(NumGet(UserNotificationReadOnlyList+0)+6*A_PtrSize), "ptr", UserNotificationReadOnlyList, "int", A_Index-1, "ptr*", UserNotification) ; get_Item DllCall(NumGet(NumGet(UserNotification+0)+8*A_PtrSize), "ptr", UserNotification, "uint*", id) ; get_Id if InStr(idList, "|" id "|") { ObjRelease(UserNotification) Continue } idList .= "|" id "|" if !DllCall(NumGet(NumGet(UserNotification+0)+7*A_PtrSize), "ptr", UserNotification, "ptr*", AppInfo) ; get_AppInfo { DllCall(NumGet(NumGet(AppInfo+0)+8*A_PtrSize), "ptr", AppInfo, "ptr*", AppDisplayInfo) ; get_DisplayInfo DllCall(NumGet(NumGet(AppDisplayInfo+0)+6*A_PtrSize), "ptr", AppDisplayInfo, "ptr*", hText) ; get_DisplayName buffer := DllCall("Combase.dll\WindowsGetStringRawBuffer", "ptr", hText, "uint*", length, "ptr") text := StrGet(buffer, "UTF-16") DeleteHString(hText) ObjRelease(AppDisplayInfo) ObjRelease(AppInfo) msgbox % text if (text != AppName) Continue } else { msgbox no AppInfo Continue } DllCall(NumGet(NumGet(UserNotification+0)+6*A_PtrSize), "ptr", UserNotification, "ptr*", Notification) ; get_Notification DllCall(NumGet(NumGet(Notification+0)+8*A_PtrSize), "ptr", Notification, "ptr*", NotificationVisual) ; get_Visual DllCall(NumGet(NumGet(NotificationVisual+0)+8*A_PtrSize), "ptr", NotificationVisual, "ptr*", NotificationBindingList) ; get_Bindings DllCall(NumGet(NumGet(NotificationBindingList+0)+7*A_PtrSize), "ptr", NotificationBindingList, "int*", count) ; count loop % count { DllCall(NumGet(NumGet(NotificationBindingList+0)+6*A_PtrSize), "ptr", NotificationBindingList, "int", A_Index-1, "ptr*", NotificationBinding) ; get_Item DllCall(NumGet(NumGet(NotificationBinding+0)+11*A_PtrSize), "ptr", NotificationBinding, "ptr*", AdaptiveNotificationTextReadOnlyList) ; GetTextElements DllCall(NumGet(NumGet(AdaptiveNotificationTextReadOnlyList+0)+7*A_PtrSize), "ptr", AdaptiveNotificationTextReadOnlyList, "int*", count) ; count loop % count { DllCall(NumGet(NumGet(AdaptiveNotificationTextReadOnlyList+0)+6*A_PtrSize), "ptr", AdaptiveNotificationTextReadOnlyList, "int", A_Index-1, "ptr*", AdaptiveNotificationText) ; get_Item DllCall(NumGet(NumGet(AdaptiveNotificationText+0)+6*A_PtrSize), "ptr", AdaptiveNotificationText, "ptr*", hText) ; get_Text buffer := DllCall("Combase.dll\WindowsGetStringRawBuffer", "ptr", hText, "uint*", length, "ptr") if (A_Index = 1) text := StrGet(buffer, "UTF-16") else text .= "`n" StrGet(buffer, "UTF-16") DeleteHString(hText) ObjRelease(AdaptiveNotificationText) } ObjRelease(AdaptiveNotificationTextReadOnlyList) ObjRelease(NotificationBinding) msgbox % text } ObjRelease(NotificationBindingList) ObjRelease(NotificationVisual) ObjRelease(Notification) ObjRelease(UserNotification) } ObjRelease(UserNotificationReadOnlyList) DllCall("psapi.dll\EmptyWorkingSet", "ptr", -1) sleep 50 } CreateClass(string, interface, ByRef Class) { CreateHString(string, hString) VarSetCapacity(GUID, 16) DllCall("ole32\CLSIDFromString", "wstr", interface, "ptr", &GUID) result := DllCall("Combase.dll\RoGetActivationFactory", "ptr", hString, "ptr", &GUID, "ptr*", Class, "uint") if (result != 0) { if (result = 0x80004002) msgbox No such interface supported else if (result = 0x80040154) msgbox Class not registered else msgbox error: %result% ExitApp } DeleteHString(hString) } CreateHString(string, ByRef hString) { DllCall("Combase.dll\WindowsCreateString", "wstr", string, "uint", StrLen(string), "ptr*", hString) } DeleteHString(hString) { DllCall("Combase.dll\WindowsDeleteString", "ptr", hString) } WaitForAsync(ByRef Object) { AsyncInfo := ComObjQuery(Object, IAsyncInfo := "{00000036-0000-0000-C000-000000000046}") loop { DllCall(NumGet(NumGet(AsyncInfo+0)+7*A_PtrSize), "ptr", AsyncInfo, "uint*", status) ; IAsyncInfo.Status if (status != 0) { if (status != 1) { DllCall(NumGet(NumGet(AsyncInfo+0)+8*A_PtrSize), "ptr", AsyncInfo, "uint*", ErrorCode) ; IAsyncInfo.ErrorCode msgbox AsyncInfo status error: %ErrorCode% ExitApp } ObjRelease(AsyncInfo) break } sleep 10 } DllCall(NumGet(NumGet(Object+0)+8*A_PtrSize), "ptr", Object, "ptr*", ObjectResult) ; GetResults ObjRelease(Object) Object := ObjectResult }
If TextNow (which is in the background) sends a notification to the Action Center, then open Textnow.
Is there code that accomplishes this goal? If so, thanks!
Re: Can AHK detect when Action Center notifications occur?
I think You dont understand how this script works.
Script sends requests in loop for all notifications that are in Action Center panel.
Therefore to detect that current notification is from Your application You have to put its name instead of "Autohotkey".
To detect its name use the last script.
Script sends requests in loop for all notifications that are in Action Center panel.
Therefore to detect that current notification is from Your application You have to put its name instead of "Autohotkey".
To detect its name use the last script.
Re: Can AHK detect when Action Center notifications occur?
Okay, so the last script will give me the name, and the script before is intended for what I'm hoping for. I'll give it a try now.malcev wrote: ↑25 May 2020, 14:56I think You dont understand how this script works.
Script sends requests in loop for all notifications that are in Action Center panel.
Therefore to detect that current notification is from Your application You have to put its name instead of "Autohotkey".
To detect its name use the last script.
Re: Can AHK detect when Action Center notifications occur?
Okay, I ran the most recently posted script. Messages appeared saying "Outlook," "SupportAssist," and "Skype." While I do have these apps, I don't know why these three were mentioned but not other apps. What do I need to do from here? Thanks!
Re: Can AHK detect when Action Center notifications occur?
You have to remove all notifications from action center.
Then send notification from Your application.
Then run script and get its name.
Then send notification from Your application.
Then run script and get its name.
Re: Can AHK detect when Action Center notifications occur?
And now I put the app's name into the original script, and now it works! Whenever "TextNow - Unlimited Text + Calls" sends a notification to the Action Center, the same notification appears as a popup! I've been wanting something like this for a long time, and now I do. Thank you!
I have one more question: Is there code that could open "TextNow - Unlimited Text + Calls" whenever a notification appears, instead of making a popup? Again, thank you!
I have one more question: Is there code that could open "TextNow - Unlimited Text + Calls" whenever a notification appears, instead of making a popup? Again, thank you!