WinRT JS Toast notifications

Get help with using AutoHotkey and its commands and hotkeys
User avatar
kczx3
Posts: 1143
Joined: 06 Oct 2015, 21:39

WinRT JS Toast notifications

19 Aug 2016, 12:12

I have been playing with the toast notification's and found that with recent versions of Windows 10, we can now define custom templates outside of the legacy template catalog. It took me a while to figure out exactly what var types the constructors were asking for but the below code gives a pretty good representation. We should be able to get the content of the input "buttons" by looking at a.arguments in our JS callback. The problem I've ran into is determining which option from the selection was picked. Hoping someone else may have some thoughts. Below are links I've found helpful and then my sample code.

It all began here: https://autohotkey.com/boards/viewtopic.php?f=5&t=12080
https://msdn.microsoft.com/en-au/librar ... mldocument
https://msdn.microsoft.com/en-au/library/dn554295
https://msdn.microsoft.com/en-au/librar ... ssalreason

Code: Select all

#NoEnv
#Include ActiveScript.ahk
#Include JsRT.ahk

; 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"
toast_template =
(
    <toast>
      <visual>
        <binding template="ToastGeneric">
          <text></text>
          <text></text>
          <image />
        </binding>
      </visual>
      <actions>
        <input id="time" type="selection" defaultInput="2" >
          <selection id="1" content="Breakfast" />
          <selection id="2" content="Lunch" />
          <selection id="3" content="Dinner" />
        </input>
        <action content="Reserve" arguments="reserve" />
        <action content="Call Restaurant" arguments="call" />
      </actions>
    </toast>
)

; 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."]

; Only the Edge version of JsRT supports WinRT.
js := new JsRT.Edge
js.AddObject("MsgBox", Func("test"))

; Enable use of WinRT.  "Windows.UI" or "Windows" would also work.
js.ProjectWinRTNamespace("Windows.UI.Notifications")

code =
(
    function toast(template, image, text, duration, silent, app) {
        // Alias for convenience.
        var N = Windows.UI.Notifications;
        // Get the template XML as an XmlDocument.
	   // MsgBox(template);
        // var toastXml = N.ToastNotificationManager.getTemplateContent(N.ToastTemplateType[template]);
	   var toastXml = new Windows.Data.Xml.Dom.XmlDocument();
	   toastXml.loadXml(template);
	   // MsgBox(toastXml.getXml());
	   var toastNode = toastXml.selectSingleNode('/toast');
	   // Set our duration
	   if (duration == 'long')
		toastNode.setAttribute('duration', duration);
	   if (silent == 'true') {
	     var audio = toastXml.createElement('audio');
	     audio.setAttribute('silent', silent);
		toastNode.appendChild(audio);
	   }
	   var args = {'prop1':'val1', 'prop2':'val2'};
	   toastNode.setAttribute('launch', '{"test1":"1234"}');
        // 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];
        }
	   if (image) {
		toastXml.getElementsByTagName("image")[0].setAttribute("src", image);
		toastXml.getElementsByTagName("image")[0].setAttribute("placement", 'appLogoOverride');
	   }
	   // var actions = toastXml.createElement('actions');
	   // var input = toastXml.createElement('input');;
	   // input.setAttribute('id', 'time');
	   // input.setAttribute('type', 'selection');
	   // var selection1 = toastXml.createElement('selection');
	   // selection1.setAttribute('id', 'sel1');
	   // selection1.setAttribute('content', 'Breakfast');
	   // selection1.setAttribute('arguments3', 'Breakfast_args3');
	   // var selection2 = toastXml.createElement('selection');
	   // selection2.setAttribute('id', 'sel2');
	   // selection2.setAttribute('content', 'Lunch');
	   // input.appendChild(selection1);
	   // input.appendChild(selection2);
	   // var action1 = toastXml.createElement('action');
	   // action1.setAttribute('activationType', 'foreground');
	   // action1.setAttribute('id', 'action1_ID');
	   // action1.setAttribute('content', 'Action 1');
	   // action1.setAttribute('arguments', 'test arguments1');
	   // actions.appendChild(action1);
	   // var action2 = toastXml.createElement('action');
	   // action2.setAttribute('activationType', 'foreground');
	   // action2.setAttribute('id', 'action2_ID');
	   // action2.setAttribute('content', 'Action 2');
	   // action2.setAttribute('arguments', 'test arguments2');
	   // actions.appendChild(input);
	   // actions.appendChild(action1);
	   // actions.appendChild(action2);
	   // toastNode.appendChild(actions);
        // Show the notification.
        var toastNotifier = N.ToastNotificationManager.createToastNotifier(app || "AutoHotkey");
	   var toastNotification = new N.ToastNotification(toastXml);
	   // MsgBox(toastNotification.content.getXml());
	   toastNotification.onactivated = toastActivated;
	   toastNotification.ondismissed = toastDismissed;
        toastNotifier.show(toastNotification);
    }
    
    function toastActivated(a) {
	MsgBox(print_r(a));
	if (a.type == 'activated') {
		MsgBox(a.arguments);
	}
    }
    
    function toastDismissed(a) {
	if (a.reason === 0)
		MsgBox(print_r(a));
    }
    
/**
 * PHP-like print_r() & var_dump() equivalent for JavaScript Object
 *
 * @author Faisalman <[email protected]>
 * @license http://www.opensource.org/licenses/mit-license.php
 * @link http://gist.github.com/879208
 */
var print_r = function(obj,t){

    // define tab spacing
    var tab = t || '';
	
    // check if it's array
    var isArr = Object.prototype.toString.call(obj) === '[object Array]' ? true : false;
	
    // use {} for object, [] for array
    var str = isArr ? ('Array\n' + tab + '[\n') : ('Object\n' + tab + '{\n');

    // walk through it's properties
    for(var prop in obj){
        // if (obj.hasOwnProperty(prop)) {
            var val1 = obj[prop];
            var val2 = '';
            var type = Object.prototype.toString.call(val1);
            switch(type){
			
                // recursive if object/array
			 case '[object String]':
                    val2 = '\'' + val1 + '\'';
                    break;
                case '[object Array]':
                case '[object Object]':
                    val2 = print_r(val1, (tab + '\t'));
                    break;
			case '[object Windows.UI.Notifications.ToastNotification]':
                    val2 = print_r(val1, (tab + '\t'));
                    break;
			case '[object Windows.UI.Notifications.ToastActivatedEventArgs]':
                    val2 = print_r(val1, (tab + '\t'));
                    break;
                default:
                    val2 = val1;
            }
            str += tab + '\t' + prop + ' => ' + val2 + ',\n';
        // }
    }
	
    // remove extra comma for last property
    str = str.substring(0, str.length-2) + '\n' + tab;
	
    return isArr ? (str + ']') : (str + '}');
};
)

; Define the toast function.
js.Exec(code)
Return

#q::
js.toast(toast_template, toast_Image, toast_Text, "", "")
Return

test(a) {
	msgbox, %a%
}

; Note: If the notification wasn't hidden, it will remain after we exit.
ExitApp
DanielToward13
Posts: 71
Joined: 18 May 2017, 10:56

Re: WinRT JS Toast notifications

06 Dec 2017, 20:02

Thank you for taking the time to share it. I could not get response by clicking on the Call and Reserve buttons for the first few seconds right after launching the toast. Do you have the same problem?

How time input event (e.g. Breakfast, Lunch, Dinner) can be detected from notifications and then run three different functions for each of them? What I see is that there is only one function test(a) { msgbox, %a% } to be called by js.AddObject("MsgBox", Func("test")). How can we call AHK TestTime(b) function to retrieve the time input value?

Return to “Ask For Help”

Who is online

Users browsing this forum: Bing [Bot], Chiefkes, electrone77, mikeyww, RubbeH and 52 guests