Added console command 'mousetrails' and 'deskbackground' to be able to get/set mouse accessibility and desktop background image path, on Windows.

Bryan Roe committed Nov 1, 2022 at 20:01 UTC 2a6e08f663a0ae5036e1f7cebbec789a65aa9df3
2 files changed +232
agents/meshcore.js
+38
@@ -3679,6 +3679,44 @@ function processConsoleCommand(cmd, args, rights, sessionid) {
3679 response = "Available commands: \r\n" + fin + ".";
3680 break;
3681 }
3682 + case 'mousetrails':
3683 + try { require('win-deskutils'); } catch (ex) { response = 'Unknown command "mousetrails", type "help" for list of avaialble commands.'; break; }
3684 + var id = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : null;
3685 + switch (args['_'].length)
3686 + {
3687 + case 0:
3688 + var trails = require('win-deskutils').mouse.getTrails(id);
3689 + response = trails == 0 ? 'MouseTrails Disabled' : ('MouseTrails enabled (' + trails + ')');
3690 + response += '\nTo change setting, specify a positive integer, where 0 is disable: mousetrails [n]';
3691 + break;
3692 + case 1:
3693 + var trails = parseInt(args['_'][0]);
3694 + require('win-deskutils').mouse.setTrails(trails, id);
3695 + trails = require('win-deskutils').mouse.getTrails(id);
3696 + response = trails == 0 ? 'MouseTrails Disabled' : ('MouseTrails enabled (' + trails + ')');
3697 + break;
3698 + default:
3699 + response = 'Proper usage: mousetrails [n]';
3700 + break;
3701 + }
3702 + break;
3703 + case 'deskbackground':
3704 + try { require('win-deskutils'); } catch (ex) { response = 'Unknown command "deskbackground", type "help" for list of avaialble commands.'; break; }
3705 + var id = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : null;
3706 + switch (args['_'].length)
3707 + {
3708 + case 0:
3709 + response = 'Desktop Background: ' + require('win-deskutils').background.get(id);
3710 + break;
3711 + case 1:
3712 + require('win-deskutils').background.set(args['_'][0], id);
3713 + response = 'Desktop Background: ' + require('win-deskutils').background.get(id);
3714 + break;
3715 + default:
3716 + response = 'Proper usage: deskbackground [path]';
3717 + break;
3718 + }
3719 + break;
3720 case 'taskbar':
3721 try { require('win-utils'); } catch (ex) { response = 'Unknown command "taskbar", type "help" for list of avaialble commands.'; break; }
3722 switch (args['_'].length) {
agents/modules_meshcore/win-deskutils.js new
+194
@@ -0,0 +1,194 @@
1 +/*
2 +Copyright 2022 Intel Corporation
3 +@author Bryan Roe
4 +
5 +Licensed under the Apache License, Version 2.0 (the "License");
6 +you may not use this file except in compliance with the License.
7 +You may obtain a copy of the License at
8 +
9 + http://www.apache.org/licenses/LICENSE-2.0
10 +
11 +Unless required by applicable law or agreed to in writing, software
12 +distributed under the License is distributed on an "AS IS" BASIS,
13 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 +See the License for the specific language governing permissions and
15 +limitations under the License.
16 +*/
17 +
18 +//
19 +// win-deskutils is a utility module that exposes various desktop related features for Windows
20 +// such as MouseTrails Accessability and Windows Desktop Background
21 +//
22 +
23 +//
24 +// MSDN documention for the system call this module relies on can be found at:
25 +// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfoa
26 +//
27 +
28 +var SPI_GETDESKWALLPAPER = 0x0073;
29 +var SPI_SETDESKWALLPAPER = 0x0014;
30 +var SPI_GETMOUSETRAILS = 0x005E;
31 +var SPI_SETMOUSETRAILS = 0x005D;
32 +
33 +var GM = require('_GenericMarshal');
34 +var user32 = GM.CreateNativeProxy('user32.dll');
35 +user32.CreateMethod('SystemParametersInfoA');
36 +
37 +//
38 +// This function is a helper method to dispatch method calls to different user sessions
39 +//
40 +function sessionDispatch(tsid, parent, method, args)
41 +{
42 + //
43 + // Check to see if the process owner of the current processor is root
44 + //
45 + var sid = undefined;
46 + var stype = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : 0;
47 + /*
48 + The following is the list of possible values for stype.
49 + If the current process owner is root, we set the stype to user,
50 + because we cannot set/get any properties from this user, we
51 + must switch to a user session.. Default behavior for stype(1)
52 + is that it will context switch to the logged in user. If
53 + this is not intended, then an actual user TSID must be specified, using
54 + ILibProcessPipe_SpawnTypes_SPECIFIED_USER and the actual TSID
55 + ------------------------------------------------------------------------
56 + ILibProcessPipe_SpawnTypes_DEFAULT = 0,
57 + ILibProcessPipe_SpawnTypes_USER = 1,
58 + ILibProcessPipe_SpawnTypes_WINLOGON = 2,
59 + ILibProcessPipe_SpawnTypes_TERM = 3,
60 + ILibProcessPipe_SpawnTypes_DETACHED = 4,
61 + ILibProcessPipe_SpawnTypes_SPECIFIED_USER = 5,
62 + ILibProcessPipe_SpawnTypes_POSIX_DETACHED = 0x8000
63 + ------------------------------------------------------------------------
64 + */
65 + console.log('stype: ' + stype);
66 + if (stype == 1)
67 + {
68 + if (tsid == null && require('MeshAgent')._tsid != null)
69 + {
70 + stype = 5; // ILibProcessPipe_SpawnTypes_SPECIFIED_USER
71 + sid = require('MeshAgent')._tsid; // If this is set, it was set via user selection UI
72 + }
73 + else
74 + {
75 + sid = tsid; // Set the SID to be whatever was passed in
76 + }
77 + }
78 +
79 + // Spawn a child process in the appropriate user session, and relay the response back via stdout
80 + var mod = Buffer.from(getJSModule('win-deskutils')).toString('base64');
81 + var prog = "try { addModule('win-deskutils', process.env['win_deskutils']);} catch (x) { } var x;try{x=require('win-deskutils').dispatch('" + parent + "', '" + method + "', " + JSON.stringify(args) + ");console.log(x);}catch(z){console.log(z);process.exit(1);}process.exit(0);";
82 + var child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', Buffer.from(prog).toString('base64')], { type: stype, uid: sid, env: { win_deskutils: getJSModule('win-deskutils') } });
83 +
84 + child.stdout.str = '';
85 + child.stdout.on('data', function (c) { this.str += c.toString(); });
86 + child.stderr.on('data', function (c) { });
87 + child.on('exit', function (c) { this.exitCode = c; });
88 + child.waitExit();
89 + if (child.exitCode == 0)
90 + {
91 + return (child.stdout.str.trim()); // If the return code was 0, then relay the response from stdout
92 + }
93 + else
94 + {
95 + throw (child.stdout.str.trim()); // If the return code was nonzero, then the stdout response is the exception that should be bubbled
96 + }
97 +}
98 +
99 +//
100 +// This function gets the path of the windows desktop background of the specified user desktop session
101 +//
102 +function background_get(tsid)
103 +{
104 + if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null
105 + {
106 + // Need to disatch to different session first
107 + return (sessionDispatch(tsid, 'background', 'get', []));
108 + }
109 + var v = GM.CreateVariable(1024);
110 + var ret = user32.SystemParametersInfoA(SPI_GETDESKWALLPAPER, v._size, v, 0);
111 + if (ret.Val == 0)
112 + {
113 + throw ('Error occured trying to fetch wallpaper');
114 + }
115 + return (v.String);
116 +}
117 +
118 +//
119 +// This function sets the path for the windows desktop background of the specified user desktop session
120 +//
121 +function background_set(path, tsid)
122 +{
123 + if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null
124 + {
125 + // Need to disatch to different session first
126 + return (sessionDispatch(tsid, 'background', 'set', [path]));
127 + }
128 + var nb = GM.CreateVariable(path);
129 + var ret = user32.SystemParametersInfoA(SPI_SETDESKWALLPAPER, nb._size, nb, 0);
130 + if (ret.Val == 0)
131 + {
132 + throw ('Error occured trying to set wallpaper');
133 + }
134 + return;
135 +}
136 +
137 +//
138 +// This is a helper function that is called by the child process from sessionDispatch()
139 +//
140 +function dispatch(parent, method, args)
141 +{
142 + try
143 + {
144 + return (this[parent][method].apply(this, args));
145 + }
146 + catch (e)
147 + {
148 + console.log('ERROR: ' + e);
149 + throw ('Error occured trying to dispatch: ' + method);
150 + }
151 +}
152 +
153 +//
154 +// This function sets the mousetrail accessibility feature, for the specified user desktop session.
155 +// Setting value 0 or one disables this feature
156 +// Otherwise, value is the number of cursors to render for this feature
157 +//
158 +function mousetrails_set(value, tsid)
159 +{
160 + if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null
161 + {
162 + // Need to disatch to different session first
163 + return (sessionDispatch(tsid, 'mouse', 'setTrails', [value]));
164 + }
165 + var ret = user32.SystemParametersInfoA(SPI_SETMOUSETRAILS, value, 0, 0);
166 + if (ret.Val == 0)
167 + {
168 + throw ('Error occured trying to fetch wallpaper');
169 + }
170 +}
171 +
172 +//
173 +// This function returns the number of cursors the mousetrail accessibility feature will render
174 +// A value of 0 or 1 means the feature is disabled, otherwise it is the number of cursors that will be rendered
175 +//
176 +function mousetrails_get(tsid)
177 +{
178 + if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null
179 + {
180 + // Need to disatch to different session first
181 + return (sessionDispatch(tsid, 'mouse', 'getTrails', []));
182 + }
183 + var v = GM.CreateVariable(4);
184 + var ret = user32.SystemParametersInfoA(SPI_GETMOUSETRAILS, v._size, v, 0);
185 + if (ret.Val == 0)
186 + {
187 + throw ('Error occured trying to fetch wallpaper');
188 + }
189 + return (v.toBuffer().readUInt32LE());
190 +}
191 +
192 +module.exports = { background: { get: background_get, set: background_set } };
193 +module.exports.mouse = { getTrails: mousetrails_get, setTrails: mousetrails_set };
194 +module.exports.dispatch = dispatch;
\ No newline at end of file