From 2a6e08f663a0ae5036e1f7cebbec789a65aa9df3 Mon Sep 17 00:00:00 2001 From: Bryan Roe Date: Tue, 1 Nov 2022 20:01:26 -0700 Subject: [PATCH] Added console command 'mousetrails' and 'deskbackground' to be able to get/set mouse accessibility and desktop background image path, on Windows. --- agents/meshcore.js | 38 +++++ agents/modules_meshcore/win-deskutils.js | 194 +++++++++++++++++++++++ 2 files changed, 232 insertions(+) create mode 100644 agents/modules_meshcore/win-deskutils.js diff --git a/agents/meshcore.js b/agents/meshcore.js index afebe454..bdd5864e 100644 --- a/agents/meshcore.js +++ b/agents/meshcore.js @@ -3679,6 +3679,44 @@ function processConsoleCommand(cmd, args, rights, sessionid) { response = "Available commands: \r\n" + fin + "."; break; } + case 'mousetrails': + try { require('win-deskutils'); } catch (ex) { response = 'Unknown command "mousetrails", type "help" for list of avaialble commands.'; break; } + var id = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : null; + switch (args['_'].length) + { + case 0: + var trails = require('win-deskutils').mouse.getTrails(id); + response = trails == 0 ? 'MouseTrails Disabled' : ('MouseTrails enabled (' + trails + ')'); + response += '\nTo change setting, specify a positive integer, where 0 is disable: mousetrails [n]'; + break; + case 1: + var trails = parseInt(args['_'][0]); + require('win-deskutils').mouse.setTrails(trails, id); + trails = require('win-deskutils').mouse.getTrails(id); + response = trails == 0 ? 'MouseTrails Disabled' : ('MouseTrails enabled (' + trails + ')'); + break; + default: + response = 'Proper usage: mousetrails [n]'; + break; + } + break; + case 'deskbackground': + try { require('win-deskutils'); } catch (ex) { response = 'Unknown command "deskbackground", type "help" for list of avaialble commands.'; break; } + var id = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : null; + switch (args['_'].length) + { + case 0: + response = 'Desktop Background: ' + require('win-deskutils').background.get(id); + break; + case 1: + require('win-deskutils').background.set(args['_'][0], id); + response = 'Desktop Background: ' + require('win-deskutils').background.get(id); + break; + default: + response = 'Proper usage: deskbackground [path]'; + break; + } + break; case 'taskbar': try { require('win-utils'); } catch (ex) { response = 'Unknown command "taskbar", type "help" for list of avaialble commands.'; break; } switch (args['_'].length) { diff --git a/agents/modules_meshcore/win-deskutils.js b/agents/modules_meshcore/win-deskutils.js new file mode 100644 index 00000000..44e92f47 --- /dev/null +++ b/agents/modules_meshcore/win-deskutils.js @@ -0,0 +1,194 @@ +/* +Copyright 2022 Intel Corporation +@author Bryan Roe + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +// win-deskutils is a utility module that exposes various desktop related features for Windows +// such as MouseTrails Accessability and Windows Desktop Background +// + +// +// MSDN documention for the system call this module relies on can be found at: +// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfoa +// + +var SPI_GETDESKWALLPAPER = 0x0073; +var SPI_SETDESKWALLPAPER = 0x0014; +var SPI_GETMOUSETRAILS = 0x005E; +var SPI_SETMOUSETRAILS = 0x005D; + +var GM = require('_GenericMarshal'); +var user32 = GM.CreateNativeProxy('user32.dll'); +user32.CreateMethod('SystemParametersInfoA'); + +// +// This function is a helper method to dispatch method calls to different user sessions +// +function sessionDispatch(tsid, parent, method, args) +{ + // + // Check to see if the process owner of the current processor is root + // + var sid = undefined; + var stype = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : 0; + /* + The following is the list of possible values for stype. + If the current process owner is root, we set the stype to user, + because we cannot set/get any properties from this user, we + must switch to a user session.. Default behavior for stype(1) + is that it will context switch to the logged in user. If + this is not intended, then an actual user TSID must be specified, using + ILibProcessPipe_SpawnTypes_SPECIFIED_USER and the actual TSID + ------------------------------------------------------------------------ + ILibProcessPipe_SpawnTypes_DEFAULT = 0, + ILibProcessPipe_SpawnTypes_USER = 1, + ILibProcessPipe_SpawnTypes_WINLOGON = 2, + ILibProcessPipe_SpawnTypes_TERM = 3, + ILibProcessPipe_SpawnTypes_DETACHED = 4, + ILibProcessPipe_SpawnTypes_SPECIFIED_USER = 5, + ILibProcessPipe_SpawnTypes_POSIX_DETACHED = 0x8000 + ------------------------------------------------------------------------ + */ + console.log('stype: ' + stype); + if (stype == 1) + { + if (tsid == null && require('MeshAgent')._tsid != null) + { + stype = 5; // ILibProcessPipe_SpawnTypes_SPECIFIED_USER + sid = require('MeshAgent')._tsid; // If this is set, it was set via user selection UI + } + else + { + sid = tsid; // Set the SID to be whatever was passed in + } + } + + // Spawn a child process in the appropriate user session, and relay the response back via stdout + var mod = Buffer.from(getJSModule('win-deskutils')).toString('base64'); + 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);"; + 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') } }); + + child.stdout.str = ''; + child.stdout.on('data', function (c) { this.str += c.toString(); }); + child.stderr.on('data', function (c) { }); + child.on('exit', function (c) { this.exitCode = c; }); + child.waitExit(); + if (child.exitCode == 0) + { + return (child.stdout.str.trim()); // If the return code was 0, then relay the response from stdout + } + else + { + throw (child.stdout.str.trim()); // If the return code was nonzero, then the stdout response is the exception that should be bubbled + } +} + +// +// This function gets the path of the windows desktop background of the specified user desktop session +// +function background_get(tsid) +{ + if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null + { + // Need to disatch to different session first + return (sessionDispatch(tsid, 'background', 'get', [])); + } + var v = GM.CreateVariable(1024); + var ret = user32.SystemParametersInfoA(SPI_GETDESKWALLPAPER, v._size, v, 0); + if (ret.Val == 0) + { + throw ('Error occured trying to fetch wallpaper'); + } + return (v.String); +} + +// +// This function sets the path for the windows desktop background of the specified user desktop session +// +function background_set(path, tsid) +{ + if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null + { + // Need to disatch to different session first + return (sessionDispatch(tsid, 'background', 'set', [path])); + } + var nb = GM.CreateVariable(path); + var ret = user32.SystemParametersInfoA(SPI_SETDESKWALLPAPER, nb._size, nb, 0); + if (ret.Val == 0) + { + throw ('Error occured trying to set wallpaper'); + } + return; +} + +// +// This is a helper function that is called by the child process from sessionDispatch() +// +function dispatch(parent, method, args) +{ + try + { + return (this[parent][method].apply(this, args)); + } + catch (e) + { + console.log('ERROR: ' + e); + throw ('Error occured trying to dispatch: ' + method); + } +} + +// +// This function sets the mousetrail accessibility feature, for the specified user desktop session. +// Setting value 0 or one disables this feature +// Otherwise, value is the number of cursors to render for this feature +// +function mousetrails_set(value, tsid) +{ + if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null + { + // Need to disatch to different session first + return (sessionDispatch(tsid, 'mouse', 'setTrails', [value])); + } + var ret = user32.SystemParametersInfoA(SPI_SETMOUSETRAILS, value, 0, 0); + if (ret.Val == 0) + { + throw ('Error occured trying to fetch wallpaper'); + } +} + +// +// This function returns the number of cursors the mousetrail accessibility feature will render +// A value of 0 or 1 means the feature is disabled, otherwise it is the number of cursors that will be rendered +// +function mousetrails_get(tsid) +{ + if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null + { + // Need to disatch to different session first + return (sessionDispatch(tsid, 'mouse', 'getTrails', [])); + } + var v = GM.CreateVariable(4); + var ret = user32.SystemParametersInfoA(SPI_GETMOUSETRAILS, v._size, v, 0); + if (ret.Val == 0) + { + throw ('Error occured trying to fetch wallpaper'); + } + return (v.toBuffer().readUInt32LE()); +} + +module.exports = { background: { get: background_get, set: background_set } }; +module.exports.mouse = { getTrails: mousetrails_get, setTrails: mousetrails_set }; +module.exports.dispatch = dispatch; \ No newline at end of file