improves Windows terminal support.

Ylian Saint-Hilaire committed Dec 15, 2018 at 16:17 UTC 286ee89f363049b1de94384a495fac0ad2d1eddd
3 files changed +183 -244
MeshCentralServer.njsproj
+1
@@ -54,6 +54,7 @@
54 <Compile Include="agents\modules_meshcore\win-console.js" />
55 <Compile Include="agents\modules_meshcore\win-message-pump.js" />
56 <Compile Include="agents\modules_meshcore\win-registry.js" />
57 + <Compile Include="agents\modules_meshcore\win-terminal.js" />
58 <Compile Include="agents\testsuite.js" />
59 <Compile Include="agents\tinycore.js" />
60 <Compile Include="amtevents.js" />
agents/modules_meshcore/win-terminal.js
+181 -243
@@ -46,8 +46,7 @@ si.Deref(GM.PointerSize == 4 ? 44 : 60, 4).toBuffer().writeUInt32LE(STARTF_USESH
46
47 var MSG = GM.CreateVariable(GM.PointerSize == 4 ? 28 : 48);
48
49 -function windows_terminal()
50 -{
49 +function windows_terminal() {
50 this._ObjectID = 'windows_terminal';
51 this._user32 = GM.CreateNativeProxy('User32.dll');
52 this._user32.CreateMethod('DispatchMessageA');
@@ -60,7 +59,7 @@ function windows_terminal()
59 this._user32.CreateMethod('UnhookWinEvent');
60 this._user32.CreateMethod('VkKeyScanA');
61 this._user32.terminal = this;
63 -
62 +
63 this._kernel32 = GM.CreateNativeProxy('Kernel32.dll');
64 this._kernel32.CreateMethod('AllocConsole');
65 this._kernel32.CreateMethod('CreateProcessA');
@@ -79,137 +78,119 @@ function windows_terminal()
78 this._kernel32.CreateMethod('TerminateProcess');
79 this._kernel32.CreateMethod('WaitForSingleObject');
80 this._kernel32.CreateMethod('WriteConsoleInputA');
82 -
81 +
82 var currentX = 0;
83 var currentY = 0;
85 -
84 +
85 this._scrx = 0;
86 this._scry = 0;
88 -
89 - this.SendCursorUpdate = function()
90 - {
91 - var newCsbi = GM.CreateVariable(22);
92 -
93 - if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, newCsbi).Val == 0) { return; }
94 - if (newCsbi.Deref(4,2).toBuffer().readUInt16LE() != this.currentX || newCsbi.Deref(6,2).toBuffer().readUInt16LE() != this.currentY)
95 - {
87 +
88 + this.SendCursorUpdate = function () {
89 + var newCsbi = GM.CreateVariable(22);
90 +
91 + if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, newCsbi).Val == 0) { return; }
92 + if (newCsbi.Deref(4, 2).toBuffer().readUInt16LE() != this.currentX || newCsbi.Deref(6, 2).toBuffer().readUInt16LE() != this.currentY) {
93 //wchar_t mywbuf[512];
94 //swprintf(mywbuf, 512, TEXT("csbi.dwCursorPosition.X = %d, csbi.dwCursorPosition.Y = %d, newCsbi.dwCursorPosition.X = %d, newCsbi.dwCursorPosition.Y = %d\r\n"), csbi.dwCursorPosition.X, csbi.dwCursorPosition.Y, newCsbi.dwCursorPosition.X, newCsbi.dwCursorPosition.Y);
95 //OutputDebugString(mywbuf);
99 -
96 +
97 //m_viewOffset = newCsbi.srWindow.Top;
98 //WriteMoveCursor((SerialAgent *)this->sa, (char)(newCsbi.dwCursorPosition.Y - m_viewOffset), (char)(newCsbi.dwCursorPosition.X - m_viewOffset));
99 //LowStackSendData((SerialAgent *)(this->sa), "", 0);
103 -
104 - this.currentX = newCsbi.Deref(4,2).toBuffer().readUInt16LE();
105 - this.currentY = newCsbi.Deref(6,2).toBuffer().readUInt16LE();
100 +
101 + this.currentX = newCsbi.Deref(4, 2).toBuffer().readUInt16LE();
102 + this.currentY = newCsbi.Deref(6, 2).toBuffer().readUInt16LE();
103 }
104 }
108 - this.ClearScreen = function()
109 - {
110 - var CONSOLE_SCREEN_BUFFER_INFO = GM.CreateVariable(22);
111 - if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, CONSOLE_SCREEN_BUFFER_INFO).Val == 0) { return; }
105
106 + this.ClearScreen = function () {
107 + var CONSOLE_SCREEN_BUFFER_INFO = GM.CreateVariable(22);
108 + if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, CONSOLE_SCREEN_BUFFER_INFO).Val == 0) { return; }
109 +
110 var coordScreen = GM.CreateVariable(4);
114 - var dwConSize = CONSOLE_SCREEN_BUFFER_INFO.Deref(0,2).toBuffer().readUInt16LE(0) * CONSOLE_SCREEN_BUFFER_INFO.Deref(2,2).toBuffer().readUInt16LE(0);
111 + var dwConSize = CONSOLE_SCREEN_BUFFER_INFO.Deref(0, 2).toBuffer().readUInt16LE(0) * CONSOLE_SCREEN_BUFFER_INFO.Deref(2, 2).toBuffer().readUInt16LE(0);
112 var cCharsWritten = GM.CreateVariable(4);
116 -
113 +
114 // Fill the entire screen with blanks.
118 - if (this._kernel32.FillConsoleOutputCharacterA(this._stdoutput, 32, dwConSize, coordScreen.Deref(0,4).toBuffer().readUInt32LE(), cCharsWritten).Val == 0) { return; }
115 + if (this._kernel32.FillConsoleOutputCharacterA(this._stdoutput, 32, dwConSize, coordScreen.Deref(0, 4).toBuffer().readUInt32LE(), cCharsWritten).Val == 0) { return; }
116
117 // Get the current text attribute.
118 if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, CONSOLE_SCREEN_BUFFER_INFO).Val == 0) { return; }
122 -
119 +
120 // Set the buffer's attributes accordingly.
121 if (this._kernel32.FillConsoleOutputAttribute(this._stdoutput, CONSOLE_SCREEN_BUFFER_INFO.Deref(8, 2).toBuffer().readUInt16LE(0), dwConSize, coordScreen.Deref(0, 4).toBuffer().readUInt32LE(), cCharsWritten).Val == 0) { return; }
125 -
122 +
123 // Put the cursor at its home coordinates.
124 this._kernel32.SetConsoleCursorPosition(this._stdoutput, coordScreen.Deref(0, 4).toBuffer().readUInt32LE());
128 -
125 +
126 // Put the window to top-left.
127 var rect = GM.CreateVariable(8);
131 - var srWindow = CONSOLE_SCREEN_BUFFER_INFO.Deref(10,8).toBuffer();
132 - rect.Deref(4,2).toBuffer().writeUInt16LE(srWindow.readUInt16LE(4) - srWindow.readUInt16LE(0));
133 - rect.Deref(6,2).toBuffer().writeUInt16LE(srWindow.readUInt16LE(6) - srWindow.readUInt16LE(2));
134 -
128 + var srWindow = CONSOLE_SCREEN_BUFFER_INFO.Deref(10, 8).toBuffer();
129 + rect.Deref(4, 2).toBuffer().writeUInt16LE(srWindow.readUInt16LE(4) - srWindow.readUInt16LE(0));
130 + rect.Deref(6, 2).toBuffer().writeUInt16LE(srWindow.readUInt16LE(6) - srWindow.readUInt16LE(2));
131 +
132 this._kernel32.SetConsoleWindowInfo(this._stdoutput, 1, rect);
133 }
137 -
138 - this.Start = function Start(CONSOLE_SCREEN_WIDTH, CONSOLE_SCREEN_HEIGHT)
139 - {
140 - if(this._kernel32.GetConsoleWindow().Val == 0)
141 - {
142 - if(this._kernel32.AllocConsole().Val == 0)
143 - {
134 +
135 + this.Start = function Start(CONSOLE_SCREEN_WIDTH, CONSOLE_SCREEN_HEIGHT) {
136 + if (this._kernel32.GetConsoleWindow().Val == 0) {
137 + if (this._kernel32.AllocConsole().Val == 0) {
138 throw ('AllocConsole failed with: ' + this._kernel32.GetLastError().Val);
139 }
140 }
147 -
141 +
142 this._stdinput = this._kernel32.GetStdHandle(STD_INPUT_HANDLE);
143 this._stdoutput = this._kernel32.GetStdHandle(STD_OUTPUT_HANDLE);
144 this._connected = false;
145 var coordScreen = GM.CreateVariable(4);
146 coordScreen.Deref(0, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_WIDTH);
147 coordScreen.Deref(2, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_HEIGHT);
154 -
148 +
149 var rect = GM.CreateVariable(8);
150 rect.Deref(4, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_WIDTH - 1);
151 rect.Deref(6, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_HEIGHT - 1);
158 -
159 - if(this._kernel32.SetConsoleWindowInfo(this._stdoutput, 1, rect).Val == 0)
160 - {
152 +
153 + if (this._kernel32.SetConsoleWindowInfo(this._stdoutput, 1, rect).Val == 0) {
154 throw ('Failed to set Console Screen Size');
155 }
163 - if(this._kernel32.SetConsoleScreenBufferSize(this._stdoutput, coordScreen.Deref(0,4).toBuffer().readUInt32LE()).Val == 0)
164 - {
156 + if (this._kernel32.SetConsoleScreenBufferSize(this._stdoutput, coordScreen.Deref(0, 4).toBuffer().readUInt32LE()).Val == 0) {
157 throw ('Failed to set Console Buffer Size');
158 }
159 this.ClearScreen();
168 - this._hookThread().then(function ()
169 - {
160 + this._hookThread().then(function () {
161 // Hook Ready
162 this.terminal.StartCommand();
163 }, console.log);
164 this._stream = new duplex({
174 - 'write': function (chunk, flush)
175 - {
176 - if (!this.terminal.connected)
177 - {
165 + 'write': function (chunk, flush) {
166 + if (!this.terminal.connected) {
167 //console.log('_write: ' + chunk);
179 - if (!this._promise.chunk)
180 - {
168 + if (!this._promise.chunk) {
169 this._promise.chunk = [];
170 }
183 - if (typeof (chunk) == 'string')
184 - {
171 + if (typeof (chunk) == 'string') {
172 this._promise.chunk.push(chunk);
186 - }
187 - else
188 - {
173 + } else {
174 this._promise.chunk.push(Buffer.alloc(chunk.length));
175 chunk.copy(this._promise.chunk.peek());
176 }
177 this._promise.chunk.peek().flush = flush;
193 - this._promise.then(function ()
194 - {
178 + this._promise.then(function () {
179 var buf;
196 - while(this.chunk.length > 0)
197 - {
180 + while (this.chunk.length > 0) {
181 buf = this.chunk.shift();
182 this.terminal._WriteBuffer(buf);
183 buf.flush();
184 }
185 });
186 }
204 - else
205 - {
187 + else {
188 //console.log('writeNOW: ' + chunk);
189 this.terminal._WriteBuffer(chunk);
190 flush();
191 }
192 },
211 - 'final': function (flush)
212 - {
193 + 'final': function (flush) {
194 var p = this.terminal._stop();
195 p.__flush = flush;
196 p.then(function () { this.__flush(); });
@@ -220,19 +201,17 @@ function windows_terminal()
201 this._stream._promise.terminal = this;
202 return (this._stream);
203 };
223 - this._stop = function()
224 - {
204 + this._stop = function () {
205 if (this.stopping) { return (this.stopping); }
206 console.log('Stopping Terminal...');
207 this.stopping = new promise(function (res, rej) { this._res = res; this._rej = rej; });
228 -
208 +
209 var threadID = this._kernel32.GetThreadId(this._user32.SetWinEventHook.async.thread()).Val;
210 this._user32.PostThreadMessageA(threadID, WM_QUIT, 0, 0);
211 return (this.stopping);
212 }
233 -
234 - this._hookThread = function ()
235 - {
213 +
214 + this._hookThread = function () {
215 var ret = new promise(function (res, rej) { this._res = res; this._rej = rej; });
216 ret.terminal = this;
217 this._ConsoleWinEventProc = GM.GetGenericGlobalCallback(7);
@@ -240,44 +219,37 @@ function windows_terminal()
219 var p = this._user32.SetWinEventHook.async(EVENT_CONSOLE_CARET, EVENT_CONSOLE_END_APPLICATION, 0, this._ConsoleWinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
220 p.ready = ret;
221 p.terminal = this;
243 - p.then(function (hwinEventHook)
244 - {
245 - if (hwinEventHook.Val == 0)
246 - {
222 + p.then(function (hwinEventHook) {
223 + if (hwinEventHook.Val == 0) {
224 this.ready._rej('Error calling SetWinEventHook');
248 - }
249 - else
250 - {
225 + } else {
226 this.terminal.hwinEventHook = hwinEventHook;
227 this.ready._res();
228 this.terminal._GetMessage();
229 }
230 });
256 - this._ConsoleWinEventProc.on('GlobalCallback', function (hhook, dwEvent, hwnd, idObject, idChild, idEventThread, swmsEventTime)
257 - {
231 +
232 + this._ConsoleWinEventProc.on('GlobalCallback', function (hhook, dwEvent, hwnd, idObject, idChild, idEventThread, swmsEventTime) {
233 if (!this.terminal.hwinEventHook || this.terminal.hwinEventHook.Val != hhook.Val) { return; }
234 var buffer = null;
260 -
261 - switch (dwEvent.Val)
262 - {
235 +
236 + switch (dwEvent.Val) {
237 case EVENT_CONSOLE_CARET:
238 break;
239 case EVENT_CONSOLE_UPDATE_REGION:
266 - if (!this.terminal.connected)
267 - {
268 - this.terminal.connected = true; this.terminal._stream._promise._res();
240 + if (!this.terminal.connected) {
241 + this.terminal.connected = true;
242 + this.terminal._stream._promise._res();
243 }
270 - if (this.terminal._scrollTimer == null)
271 - {
244 + if (this.terminal._scrollTimer == null) {
245 buffer = this.terminal._GetScreenBuffer(LOWORD(idObject.Val), HIWORD(idObject.Val), LOWORD(idChild.Val), HIWORD(idChild.Val));
246 //console.log('UPDATE REGION: [Left: ' + LOWORD(idObject.Val) + ' Top: ' + HIWORD(idObject.Val) + ' Right: ' + LOWORD(idChild.Val) + ' Bottom: ' + HIWORD(idChild.Val) + ']');
274 -
247 this.terminal._SendDataBuffer(buffer);
248 }
249 break;
250 case EVENT_CONSOLE_UPDATE_SIMPLE:
251 //console.log('UPDATE SIMPLE: [X: ' + LOWORD(idObject.Val) + ' Y: ' + HIWORD(idObject.Val) + ' Char: ' + LOWORD(idChild.Val) + ' Attr: ' + HIWORD(idChild.Val) + ']');
280 - var simplebuffer = { data: [Buffer.alloc(1, LOWORD(idChild.Val))], attributes: [HIWORD(idChild.Val)], width: 1, height: 1, x: LOWORD(idObject.Val)+1, y: HIWORD(idObject.Val) };
252 + var simplebuffer = { data: [Buffer.alloc(1, LOWORD(idChild.Val))], attributes: [HIWORD(idChild.Val)], width: 1, height: 1, x: LOWORD(idObject.Val) + 1, y: HIWORD(idObject.Val) };
253 this.terminal._SendDataBuffer(simplebuffer);
254 break;
255 case EVENT_CONSOLE_UPDATE_SCROLL:
@@ -295,8 +267,7 @@ function windows_terminal()
267 //SendConsoleEvent(dwEvent, idObject, idChild);
268 break;
269 case EVENT_CONSOLE_END_APPLICATION:
298 - if(idObject.Val == this.terminal._hProcessID)
299 - {
270 + if (idObject.Val == this.terminal._hProcessID) {
271 //console.log('END APPLICATION: [PID: ' + idObject.Val + ' CID: ' + idChild.Val + ']');
272 this.terminal._stop().then(function () { console.log('STOPPED'); });
273 }
@@ -313,219 +284,172 @@ function windows_terminal()
284 });
285 return (ret);
286 }
316 -
317 - this._GetMessage = function()
318 - {
287 +
288 + this._GetMessage = function () {
289 if (this._user32.abort) { console.log('aborting loop'); return; }
320 - this._user32.GetMessageA.async(this._user32.SetWinEventHook.async, MSG, 0, 0, 0).then(function (ret)
321 - {
290 + this._user32.GetMessageA.async(this._user32.SetWinEventHook.async, MSG, 0, 0, 0).then(function (ret) {
291 //console.log('GetMessage Response');
323 - if(ret.Val != 0)
324 - {
325 - if (ret.Val == -1)
326 - {
292 + if (ret.Val != 0) {
293 + if (ret.Val == -1) {
294 // handle the error and possibly exit
328 - }
329 - else
330 - {
295 + } else {
296 //console.log('TranslateMessage');
332 - this.nativeProxy._user32.TranslateMessage.async(this.nativeProxy.user32.SetWinEventHook.async, MSG).then(function ()
333 - {
297 + this.nativeProxy._user32.TranslateMessage.async(this.nativeProxy.user32.SetWinEventHook.async, MSG).then(function () {
298 //console.log('DispatchMessage');
335 - this.nativeProxy._user32.DispatchMessageA.async(this.nativeProxy.user32.SetWinEventHook.async, MSG).then(function ()
336 - {
299 + this.nativeProxy._user32.DispatchMessageA.async(this.nativeProxy.user32.SetWinEventHook.async, MSG).then(function () {
300 this.nativeProxy.terminal._GetMessage();
301 }, console.log);
302 }, console.log);
303 }
341 - }
342 - else
343 - {
304 + } else {
305 this.nativeProxy.UnhookWinEvent.async(this.nativeProxy.terminal._user32.SetWinEventHook.async, this.nativeProxy.terminal.hwinEventHook)
345 - .then(function ()
346 - {
347 - this.nativeProxy.terminal.stopping._res();
348 - if(this.nativeProxy.terminal._kernel32.TerminateProcess(this.nativeProxy.terminal._hProcess, 1067).Val == 0)
349 - {
350 - var e = this.nativeProxy.terminal._kernel32.GetLastError().Val;
351 - console.log('Unable to kill Terminal Process, error: ' + e);
352 - }
353 - this.nativeProxy.terminal.stopping = null;
354 - }, function (err)
355 - {
356 - console.log('REJECTED_UnhookWinEvent: ' + err);
357 - });
306 + .then(function () {
307 + this.nativeProxy.terminal.stopping._res();
308 + if (this.nativeProxy.terminal._kernel32.TerminateProcess(this.nativeProxy.terminal._hProcess, 1067).Val == 0) {
309 + var e = this.nativeProxy.terminal._kernel32.GetLastError().Val;
310 + console.log('Unable to kill Terminal Process, error: ' + e);
311 + }
312 + this.nativeProxy.terminal.stopping = null;
313 + }, function (err) {
314 + console.log('REJECTED_UnhookWinEvent: ' + err);
315 + });
316 }
359 - }, function (err)
360 - {
317 + }, function (err) {
318 // Get Message Failed
319 console.log('REJECTED_GETMessage: ' + err);
320 });
321 }
365 - this._WriteBuffer = function(buf)
366 - {
367 - for (var i = 0; i < buf.length; ++i)
368 - {
369 - if (typeof (buf) == 'string')
370 - {
322 + this._WriteBuffer = function (buf) {
323 + for (var i = 0; i < buf.length; ++i) {
324 + if (typeof (buf) == 'string') {
325 this._WriteCharacter(buf.charCodeAt(i), false);
372 - }
373 - else
374 - {
326 + } else {
327 this._WriteCharacter(buf[i], false);
328 }
329 }
330 }
379 - this._WriteCharacter = function(key, bControlKey)
380 - {
331 + this._WriteCharacter = function (key, bControlKey) {
332 var rec = GM.CreateVariable(20);
382 - rec.Deref(0,2).toBuffer().writeUInt16LE(KEY_EVENT); // rec.EventType
383 - rec.Deref(4,4).toBuffer().writeUInt16LE(1); // rec.Event.KeyEvent.bKeyDown
333 + rec.Deref(0, 2).toBuffer().writeUInt16LE(KEY_EVENT); // rec.EventType
334 + rec.Deref(4, 4).toBuffer().writeUInt16LE(1); // rec.Event.KeyEvent.bKeyDown
335 rec.Deref(16, 4).toBuffer().writeUInt32LE(bControlKey); // rec.Event.KeyEvent.dwControlKeyState
336 rec.Deref(14, 1).toBuffer()[0] = key; // rec.Event.KeyEvent.uChar.AsciiChar
337 rec.Deref(8, 2).toBuffer().writeUInt16LE(1); // rec.Event.KeyEvent.wRepeatCount
338 rec.Deref(10, 2).toBuffer().writeUInt16LE(this._user32.VkKeyScanA(key).Val); // rec.Event.KeyEvent.wVirtualKeyCode
339 rec.Deref(12, 2).toBuffer().writeUInt16LE(this._user32.MapVirtualKeyA(this._user32.VkKeyScanA(key).Val, MAPVK_VK_TO_VSC).Val);
389 -
340 +
341 var dwWritten = GM.CreateVariable(4);
391 - if(this._kernel32.WriteConsoleInputA(this._stdinput, rec, 1, dwWritten).Val == 0) { return(false); }
392 -
393 - rec.Deref(4,4).toBuffer().writeUInt16LE(0); // rec.Event.KeyEvent.bKeyDown
394 - return(this._kernel32.WriteConsoleInputA(this._stdinput, rec, 1, dwWritten).Val != 0);
342 + if (this._kernel32.WriteConsoleInputA(this._stdinput, rec, 1, dwWritten).Val == 0) { return (false); }
343 +
344 + rec.Deref(4, 4).toBuffer().writeUInt16LE(0); // rec.Event.KeyEvent.bKeyDown
345 + return (this._kernel32.WriteConsoleInputA(this._stdinput, rec, 1, dwWritten).Val != 0);
346 }
396 -
397 - this._GetScreenBuffer = function(sx, sy, ex, ey)
398 - {
347 +
348 + this._GetScreenBuffer = function (sx, sy, ex, ey) {
349 // get the current visible screen buffer
400 -
401 - var info = GM.CreateVariable(22);
402 - if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, info).Val == 0) { throw('Error getting screen buffer info'); }
403 -
404 - var nWidth = info.Deref(14,2).toBuffer().readUInt16LE() - info.Deref(10,2).toBuffer().readUInt16LE() + 1;
405 - var nHeight = info.Deref(16,2).toBuffer().readUInt16LE() - info.Deref(12,2).toBuffer().readUInt16LE() + 1;
406 -
407 - if (arguments[3] == null)
408 - {
350 +
351 + var info = GM.CreateVariable(22);
352 + if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, info).Val == 0) { throw ('Error getting screen buffer info'); }
353 +
354 + var nWidth = info.Deref(14, 2).toBuffer().readUInt16LE() - info.Deref(10, 2).toBuffer().readUInt16LE() + 1;
355 + var nHeight = info.Deref(16, 2).toBuffer().readUInt16LE() - info.Deref(12, 2).toBuffer().readUInt16LE() + 1;
356 +
357 + if (arguments[3] == null) {
358 // Use Default Parameters
359 sx = 0;
360 sy = 0;
412 - ex = nWidth-1;
413 - ey = nHeight-1;
414 - }
415 - else
416 - {
417 - if(this._scrx != 0)
418 - {
419 - sx += this._scrx;
420 - ex += this._scrx;
421 - }
422 - if(this._scry != 0)
423 - {
424 - sy += this._scry;
425 - ey += this._scry;
426 - }
361 + ex = nWidth - 1;
362 + ey = nHeight - 1;
363 + } else {
364 + if (this._scrx != 0) { sx += this._scrx; ex += this._scrx; }
365 + if (this._scry != 0) { sy += this._scry; ey += this._scry; }
366 this._scrx = this._scry = 0;
367 }
429 -
430 -
431 - var nBuffer = GM.CreateVariable((ex-sx+1) * (ey-sy+1) * 4);
368 +
369 +
370 + var nBuffer = GM.CreateVariable((ex - sx + 1) * (ey - sy + 1) * 4);
371 var size = GM.CreateVariable(4);
433 - size.Deref(0,2).toBuffer().writeUInt16LE(ex-sx+1, 0);
434 - size.Deref(2, 2).toBuffer().writeUInt16LE(ey-sy+1, 0);
435 -
372 + size.Deref(0, 2).toBuffer().writeUInt16LE(ex - sx + 1, 0);
373 + size.Deref(2, 2).toBuffer().writeUInt16LE(ey - sy + 1, 0);
374 +
375 var startCoord = GM.CreateVariable(4);
376 startCoord.Deref(0, 2).toBuffer().writeUInt16LE(0, 0);
377 startCoord.Deref(2, 2).toBuffer().writeUInt16LE(0, 0);
439 -
378 +
379 var region = GM.CreateVariable(8);
380 region.buffer = region.toBuffer();
381 region.buffer.writeUInt16LE(sx, 0);
382 region.buffer.writeUInt16LE(sy, 2);
383 region.buffer.writeUInt16LE(ex, 4);
384 region.buffer.writeUInt16LE(ey, 6);
446 -
447 - if (this._kernel32.ReadConsoleOutputA(this._stdoutput, nBuffer, size.Deref(0, 4).toBuffer().readUInt32LE(), startCoord.Deref(0, 4).toBuffer().readUInt32LE(), region).Val == 0)
448 - {
449 - throw('Unable to read Console Output');
385 +
386 + if (this._kernel32.ReadConsoleOutputA(this._stdoutput, nBuffer, size.Deref(0, 4).toBuffer().readUInt32LE(), startCoord.Deref(0, 4).toBuffer().readUInt32LE(), region).Val == 0) {
387 + throw ('Unable to read Console Output');
388 }
451 -
389 +
390 // Lets convert the buffer into something simpler
391 //var retVal = { data: Buffer.alloc((dw - dx + 1) * (dh - dy + 1)), attributes: Buffer.alloc((dw - dx + 1) * (dh - dy + 1)), width: dw - dx + 1, height: dh - dy + 1, x: dx, y: dy };
454 -
392 +
393 var retVal = { data: [], attributes: [], width: ex - sx + 1, height: ey - sy + 1, x: sx, y: sy };
456 - var x, y, line, ifo;
457 - var tmp;
458 - var lineWidth = ex - sx + 1;
459 -
460 - for (y = 0; y <= (ey - sy) ; ++y)
461 - {
394 + var x, y, line, ifo, tmp, lineWidth = ex - sx + 1;
395 +
396 + for (y = 0; y <= (ey - sy) ; ++y) {
397 retVal.data.push(Buffer.alloc(lineWidth));
398 retVal.attributes.push(Buffer.alloc(lineWidth));
464 -
399 +
400 line = nBuffer.Deref(y * lineWidth * 4, lineWidth * 4).toBuffer();
466 - for(x = 0; x < lineWidth; ++x)
467 - {
401 + for (x = 0; x < lineWidth; ++x) {
402 retVal.data.peek()[x] = line[x * 4];
403 retVal.attributes.peek()[x] = line[2 + (x * 4)];
404 }
405 }
472 -
406 +
407 return (retVal);
408 }
475 -
476 - this._SendDataBuffer = function(data)
477 - {
409 +
410 + this._SendDataBuffer = function (data) {
411 // { data, attributes, width, height, x, y }
479 -
412 +
413 var dy, line, attr;
481 - for(dy = 0; dy < data.height; ++dy)
482 - {
414 + for (dy = 0; dy < data.height; ++dy) {
415 line = data.data[dy];
416 attr = data.attributes[dy];
417 line.s = line.toString();
418 +
419 //line = data.data.slice(data.width * dy, (data.width * dy) + data.width);
420 //attr = data.attributes.slice(data.width * dy, (data.width * dy) + data.width);
488 - this._stream.push(TranslateLine(data.x, data.y + dy, line, attr));
489 - }
490 - }
491 - this._SendScroll = function _SendScroll(dx, dy)
492 - {
493 - if (this._scrollTimer)
494 - {
495 - return;
421 + this._stream.push(TranslateLine(data.x, data.y + dy + 1, line, attr));
422 }
423 + }
424
425 + this._SendScroll = function _SendScroll(dx, dy) {
426 + if (this._scrollTimer) { return; }
427 +
428 var info = GM.CreateVariable(22);
429 if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, info).Val == 0) { throw ('Error getting screen buffer info'); }
500 -
430 +
431 var nWidth = info.Deref(14, 2).toBuffer().readUInt16LE() - info.Deref(10, 2).toBuffer().readUInt16LE() + 1;
432 var nHeight = info.Deref(16, 2).toBuffer().readUInt16LE() - info.Deref(12, 2).toBuffer().readUInt16LE() + 1;
503 -
504 - this._stream.push(GetEsc('H', nHeight-1, 0));
505 - for (var i = 0; i > nHeight; ++i)
506 - {
507 - this._stream.push(Buffer.from('\r\n'));
508 - }
509 -
433 +
434 + this._stream.push(GetEsc('H', [nHeight - 1, 0]));
435 + for (var i = 0; i > nHeight; ++i) { this._stream.push(Buffer.from('\r\n')); }
436 +
437 var buffer = this._GetScreenBuffer(0, 0, nWidth - 1, nHeight - 1);
438 this._SendDataBuffer(buffer);
512 -
513 - this._scrollTimer = setTimeout(function (self, nw, nh)
514 - {
439 +
440 + this._scrollTimer = setTimeout(function (self, nw, nh) {
441 var buffer = self._GetScreenBuffer(0, 0, nw - 1, nh - 1);
442 self._SendDataBuffer(buffer);
443 self._scrollTimer = null;
444 }, 250, this, nWidth, nHeight);
445 }
520 -
521 - this.StartCommand = function StartCommand()
522 - {
523 - if(this._kernel32.CreateProcessA(GM.CreateVariable(process.env['windir'] + '\\system32\\cmd.exe'), 0, 0, 0, 1, CREATE_NEW_PROCESS_GROUP, 0, 0, si, pi).Val == 0)
524 - {
446 +
447 + this.StartCommand = function StartCommand() {
448 + if (this._kernel32.CreateProcessA(GM.CreateVariable(process.env['windir'] + '\\system32\\cmd.exe'), 0, 0, 0, 1, CREATE_NEW_PROCESS_GROUP, 0, 0, si, pi).Val == 0) {
449 console.log('Error Spawning CMD');
450 return;
451 }
528 -
452 +
453 this._kernel32.CloseHandle(pi.Deref(GM.PointerSize, GM.PointerSize).Deref()); // pi.hThread
454 this._hProcess = pi.Deref(0, GM.PointerSize).Deref(); // pi.hProcess
455 this._hProcessID = pi.Deref(GM.PointerSize == 4 ? 8 : 16, 4).toBuffer().readUInt32LE(); // pi.dwProcessId
@@ -533,23 +457,37 @@ function windows_terminal()
457 }
458 }
459
536 -function LOWORD(val)
537 -{
538 - return (val & 0xFFFF);
539 -}
540 -function HIWORD(val)
541 -{
542 - return ((val >> 16) & 0xFFFF);
543 -}
544 -
545 -function GetEsc(CodeCharStr, arg1, arg2)
546 -{
547 - return (Buffer.from('\x1B[' + arg1 + ';' + arg2 + CodeCharStr));
548 - //return (Buffer.from('*[' + arg1 + ';' + arg2 + CodeCharStr));
460 +function LOWORD(val) { return (val & 0xFFFF); }
461 +function HIWORD(val) { return ((val >> 16) & 0xFFFF); }
462 +function GetEsc(op, args) { return (Buffer.from('\x1B[' + args.join(';') + op)); }
463 +//function MeshConsole(msg) { require('MeshAgent').SendCommand({ "action": "msg", "type": "console", "value": JSON.stringify(msg) }); }
464 +function TranslateLine(x, y, data, attributes) {
465 + var i, fcolor, bcolor, rcolor, fbright, bbright, lastAttr, fc, bc, rc, fb, bb, esc = [], output = [GetEsc('H', [y, x])];
466 + if (typeof attributes == 'number') { attributes = [ attributes ]; } // If we get a single attribute, turn it into an array.
467 +
468 + for (i = 0; i < data.length; i++) {
469 + if (lastAttr != attributes[i]) { // To boost performance, if the attribute is the same as the last one, skip this entire part.
470 + fc = (attributes[i] & 0x0007);
471 + fc = ((fc & 0x0001) << 2) + (fc & 0x0002) + ((fc & 0x0004) >> 2); // Foreground color
472 + bc = (attributes[i] & 0x0070) >> 4;
473 + bc = ((bc & 0x0001) << 2) + (bc & 0x0002) + ((bc & 0x0004) >> 2); // Background color
474 + rc = (attributes[i] & 0x4000); // Reverse color set
475 + fb = (attributes[i] & 0x0008) >> 3; // Bright foreground set
476 + bb = (attributes[i] & 0x0080); // Bright background set
477 +
478 + if (rc != rcolor) { if (rc != 0) { esc.push(7); } else { esc.push(0); fcolor = 7; bcolor = 0; fbright = 0; bbright = 0; } rcolor = rc; } // Reverse Color
479 + if (fc != fcolor) { esc.push(fc + 30); fcolor = fc; } // Set the foreground color if needed
480 + if (bc != bcolor) { esc.push(bc + 40); bcolor = bc; } // Set the background color if needed
481 + if (fb != fbright) { esc.push(2 - fb); fbright = fb; } // Set the bright foreground color if needed
482 + if (bb != bbright) { if (bb == 0) { esc.push(bcolor + 40); } else { esc.push(bcolor + 100); bbright = bb; } } // Set bright Background color if needed
483 +
484 + if (esc.length > 0) { output.push(GetEsc('m', esc)); esc = []; }
485 + lastAttr = attributes[i];
486 + }
487 + output.push(Buffer.from(String.fromCharCode(data[i])));
488 + }
489 +
490 + return Buffer.concat(output);
491 }
492
551 -function TranslateLine(x, y, data, attributes)
552 -{
553 - return (Buffer.concat([GetEsc('H', y, x), data]));
554 -}
493 module.exports = new windows_terminal();
\ No newline at end of file
package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.2.4-n",
3 + "version": "0.2.4-p",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",