完善了双指缩放,优化了截图

This commit is contained in:
snltty
2023-10-25 16:43:22 +08:00
parent 04cf6a1f97
commit 570ab3e60f
32 changed files with 628 additions and 358 deletions

View File

@@ -3,8 +3,8 @@ import { sendWebsocketMsg } from './request'
export const reportUpdate = (names, reportType) => { export const reportUpdate = (names, reportType) => {
return sendWebsocketMsg('report/update', { return sendWebsocketMsg('report/update', {
names, reportType names, reportType
}); }, false, 1000);
} }
export const reportPing = (names) => { export const reportPing = (names) => {
return sendWebsocketMsg('report/ping', names); return sendWebsocketMsg('report/ping', names, false, 1000);
} }

View File

@@ -1,18 +1,35 @@
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
let requestId = 0, ws = null, wsUrl = ''; let requestId = 0, ws = null, wsUrl = '', index = 1;
//请求缓存,等待回调 //请求缓存,等待回调
const requests = {}; const requests = {};
const queues = []; const queues = [];
export const websocketState = { connected: false }; export const websocketState = { connected: false };
const sendQueueMsg = () => { const sendQueueMsg = () => {
if (queues.length > 0 && websocketState.connected) { if (queues.length > 0 && websocketState.connected && ws && ws.readyState == 1) {
ws.send(queues.shift()); try {
ws.send(queues.shift());
} catch (e) { }
} }
setTimeout(sendQueueMsg, 1000 / 60); setTimeout(sendQueueMsg, 1000 / 60);
} }
sendQueueMsg(); //sendQueueMsg();
const sendTimeout = () => {
const time = Date.now();
for (let j in requests) {
const item = requests[j];
if (time - item.time > item.timeout) {
item.reject('超时~');
delete requests[j];
}
}
setTimeout(sendTimeout, 1000);
}
sendTimeout();
//发布订阅 //发布订阅
export const pushListener = { export const pushListener = {
@@ -100,6 +117,7 @@ export const initWebsocket = (url = wsUrl) => {
} }
wsUrl = url; wsUrl = url;
ws = new WebSocket(wsUrl); ws = new WebSocket(wsUrl);
ws.iddd = ++index;
ws.onopen = onWebsocketOpen; ws.onopen = onWebsocketOpen;
ws.onclose = onWebsocketClose ws.onclose = onWebsocketClose
ws.onmessage = onWebsocketMsg ws.onmessage = onWebsocketMsg
@@ -107,24 +125,24 @@ export const initWebsocket = (url = wsUrl) => {
//发送消息 //发送消息
export const sendWebsocketMsg = (path, msg = {}, errHandle = false) => { export const sendWebsocketMsg = (path, msg = {}, errHandle = false, timeout = 15000) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let id = ++requestId; let id = ++requestId;
try { try {
requests[id] = { resolve, reject, errHandle, path }; requests[id] = { resolve, reject, errHandle, path, time: Date.now(), timeout: timeout };
let str = JSON.stringify({ let str = JSON.stringify({
Path: path, Path: path,
RequestId: id, RequestId: id,
Content: typeof msg == 'string' ? msg : JSON.stringify(msg) Content: typeof msg == 'string' ? msg : JSON.stringify(msg)
}); });
if (websocketState.connected) { if (websocketState.connected && ws.readyState == 1) {
ws.send(str); ws.send(str);
} else { } else {
queues.push(str); reject('网络错误~');
//queues.push(str);
} }
} catch (e) { } catch (e) {
reject('网络错误~'); reject('网络错误~');
ElMessage.error('网络错误~');
delete requests[id]; delete requests[id];
} }
}); });
@@ -141,3 +159,10 @@ export const subNotifyMsg = (path, callback) => {
export const unsubNotifyMsg = (path, callback) => { export const unsubNotifyMsg = (path, callback) => {
pushListener.remove(path, callback); pushListener.remove(path, callback);
} }
export const closeWebsocket = () => {
if (ws) {
ws.close();
}
}

View File

@@ -3,16 +3,14 @@ import { sendWebsocketMsg } from './request'
export const screenUpdateFull = (names, type) => { export const screenUpdateFull = (names, type) => {
return sendWebsocketMsg('screen/full', { return sendWebsocketMsg('screen/full', {
names, type names, type
}); }, false, 1000);
} }
export const screenUpdateRegion = (names) => { export const screenUpdateRegion = (names) => {
return sendWebsocketMsg('screen/region', names); return sendWebsocketMsg('screen/region', names, false, 1000);
} }
export const screenClip = (name, x, y, scale) => { export const screenClip = (name, data) => {
return sendWebsocketMsg('screen/clip', { return sendWebsocketMsg('screen/clip', {
name, name,
clip: { clip: data
x, y, scale }, false, 1000);
}
});
} }

View File

@@ -21,7 +21,6 @@ import FootMenu from './wraps/FootMenu.vue'
import FootOptions from './wraps/FootOptions.vue' import FootOptions from './wraps/FootOptions.vue'
import Items from './wraps/Items.vue' import Items from './wraps/Items.vue'
import { providePluginState } from './provide' import { providePluginState } from './provide'
import { provide, ref, watch } from 'vue'
export default { export default {
components: { Items, FootMenu, FootOptions }, components: { Items, FootMenu, FootOptions },
setup() { setup() {

View File

@@ -66,7 +66,9 @@ export default {
{ label: '设置静音', func: setVolumeMute, value: true }, { label: '设置静音', func: setVolumeMute, value: true },
{ label: '取消静音', func: setVolumeMute, value: false }, { label: '取消静音', func: setVolumeMute, value: false },
{ label: '开任务管理器', value: 'reg add HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System /v DisableTaskMgr /t REG_DWORD /f /d 0' }, { label: '开任务管理器', value: 'reg add HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System /v DisableTaskMgr /t REG_DWORD /f /d 0' },
{ label: '禁资源管理器', value: 'reg add HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System /v DisableTaskMgr /t REG_DWORD /f /d 1' }, { label: '禁任务管理器', value: 'reg add HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System /v DisableTaskMgr /t REG_DWORD /f /d 1' },
//{ label: '开图标拖拽', value: 'reg add HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer /v NoSaveSettings /t REG_DWORD /f /d 0' },
//{ label: '禁图标拖拽', value: 'reg add HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer /v NoSaveSettings /t REG_DWORD /f /d 1' },
], ],
loading: false loading: false
}); });

View File

@@ -27,6 +27,10 @@ export default {
}); });
this.fpsInterval(); this.fpsInterval();
}, },
uninit() {
clearTimeout(this.reportTimer);
clearTimeout(this.reportPingTimer);
},
reportTimer: 0, reportTimer: 0,
reported: true, reported: true,
@@ -35,9 +39,10 @@ export default {
this.reported = false; this.reported = false;
const names = this.globalData.value.reportNames; const names = this.globalData.value.reportNames;
let reportType = 1; const devices = this.globalData.value.devices;
this.globalData.value.devices.filter(c => names.indexOf(c.MachineName) >= 0).forEach(item => { let reportType = 2;
reportType &&= Number(item.Report.updated); devices.filter(c => names.indexOf(c.MachineName) >= 0).forEach(item => {
reportType &&= (Number(item.Report.updated) + 1);
item.Report.updated = true; item.Report.updated = true;
}); });
reportUpdate(names, reportType).then(() => { reportUpdate(names, reportType).then(() => {

View File

@@ -5,9 +5,10 @@ export default {
field() { field() {
return { return {
Screen: { Screen: {
regions: [], regionImgs: [], //局部图
img: null, fullImg: null, //全图
fullUpdated: false, fullUpdated: false, //第一次进来先获取一次全图
width: 0, height: 0, //系统宽高
draw(canvas, ctx) { draw(canvas, ctx) {
this.drawFps(canvas, ctx); this.drawFps(canvas, ctx);
@@ -15,28 +16,28 @@ export default {
this.drawTouch(canvas, ctx); this.drawTouch(canvas, ctx);
}, },
lastInput: 0, lastInput: 0, //最后活动时间 ms
captureTime: 0, captureTime: 0, //截图花费时间 ms
fps: 0, fps: { value: 0, temp: 0 }, //帧数累计
fpsTimes: 0,
drawFps(canvas, ctx) { drawFps(canvas, ctx) {
ctx.lineWidth = 5; ctx.lineWidth = 5;
ctx.font = 'bold 60px Arial'; ctx.font = 'bold 60px Arial';
ctx.fillStyle = 'rgba(0,0,0,0.5)'; ctx.fillStyle = 'rgba(0,0,0,0.5)';
ctx.fillText(`FPS : ${this.fps}${this.captureTime}ms、LT : ${this.lastInput}ms`, 50, 70); ctx.fillText(`FPS : ${this.fps.value}${this.captureTime}ms、LT : ${this.lastInput}ms`, 50, 70);
ctx.lineWidth = 2; ctx.lineWidth = 2;
ctx.strokeStyle = '#fff'; ctx.strokeStyle = '#fff';
ctx.strokeText(`FPS : ${this.fps}${this.captureTime}ms 、LT : ${this.lastInput}ms`, 50, 70); ctx.strokeText(`FPS : ${this.fps.value}${this.captureTime}ms 、LT : ${this.lastInput}ms`, 50, 70);
}, },
rectangles: [], rectangles: [],
drawRectangle(canvas, ctx) { drawRectangle(canvas, ctx) {
const rectangles = this.rectangles;
if (this.rectangles.length > 0 && this.touch.scale == 1) { if (this.rectangles.length > 0 && this.touch.scale == 1) {
ctx.lineWidth = 5; ctx.lineWidth = 5;
ctx.strokeStyle = 'rgba(255,0,0,1)'; ctx.strokeStyle = 'rgba(255,0,0,1)';
for (let i = 0; i < this.rectangles.length; i++) { for (let i = 0; i < rectangles.length; i++) {
const rectangle = this.rectangles[i]; const rectangle = rectangles[i];
ctx.rect(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height); ctx.rect(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
ctx.stroke(); ctx.stroke();
@@ -50,18 +51,20 @@ export default {
touch: { touch: {
//上次位置 //上次位置
lastTouch: { x1: 0, y1: 0, x2: 0, y2: 0, dist: 0, }, lastTouch: { x1: 0, y1: 0, x2: 0, y2: 0, dist: 0, },
clip: { x: 0, y: 0, w: 0, h: 0 },
//原点(缩放点,位置不变,四周扩散)
origin: { x: 0, y: 0, x1: 0, y1: 0 },
updated: false,
//缩放比例 //缩放比例
scale: 1, scale: 1,
//原点(缩放点,位置不变,四周扩散)
origin: { x: 0, y: 0, x1: 0, y1: 0, distX: 0, distY: 0 },
updated: false,
type: 0 type: 0
}, },
drawTouch(canvas, ctx) { drawTouch(canvas, ctx) {
if (this.touch.type == 2) { if (this.touch.type == 2) {
ctx.fillStyle = 'red';
ctx.fillStyle = 'yellow';
ctx.strokeStyle = 'yellow'; ctx.strokeStyle = 'yellow';
ctx.rect(this.touch.origin.x - 50, this.touch.origin.y - 50, 100, 100); ctx.arc(this.touch.origin.x, this.touch.origin.y, 50, 0, Math.PI * 2);
ctx.fill(); ctx.fill();
ctx.lineWidth = 5; ctx.lineWidth = 5;
@@ -78,13 +81,18 @@ export default {
reset() { reset() {
this.touch.origin.x = 0; this.touch.origin.x = 0;
this.touch.origin.y = 0; this.touch.origin.y = 0;
this.touch.origin.x1 = 0;
this.touch.origin.y1 = 0;
this.touch.origin.distX = 0;
this.touch.origin.distY = 0;
this.touch.scale = 1; this.touch.scale = 1;
this.touch.clip.x = 0;
this.touch.clip.y = 0;
this.touch.clip.w = 0;
this.touch.clip.h = 0;
this.touch.type = 0;
this.touch.updated = true; this.touch.updated = true;
this.fullUpdated = false;
}, },
getScalePosition(event) { getScalePosition(event) {
const bound = event.srcElement.getBoundingClientRect(); const bound = event.srcElement.getBoundingClientRect();
@@ -106,23 +114,31 @@ export default {
y1: (event.touches[0].clientY - top) / event.srcElement.offsetHeight * event.srcElement.height, y1: (event.touches[0].clientY - top) / event.srcElement.offsetHeight * event.srcElement.height,
}; };
}, },
getDist(x1, y1, x2, y2) {
const distX = Math.abs(x1 - x2);
const distY = Math.abs(y1 - y2);
return Math.sqrt(distX * distX + distY * distY);
},
transPosition() {
this.touch.origin.x1 = this.touch.clip.x + parseInt(this.touch.origin.x / this.width * (this.touch.clip.w || this.width));
this.touch.origin.y1 = this.touch.clip.y + parseInt(this.touch.origin.y / this.height * (this.touch.clip.h || this.height));
},
touchstart(event) { touchstart(event) {
if (event.touches.length == 2) { if (event.touches.length == 2) {
this.touch.type = 2; this.touch.type = 2;
const { x1, y1, x2, y2 } = this.getScalePosition(event); const { x1, y1, x2, y2 } = this.getScalePosition(event);
const dist = this.getDist(x1, y1, x2, y2);
this.touch.origin.x = parseInt((x1 + x2) / 2);
this.touch.origin.y = parseInt((y1 + y2) / 2);
this.transPosition();
this.touch.lastTouch.x1 = x1; this.touch.lastTouch.x1 = x1;
this.touch.lastTouch.y1 = y1; this.touch.lastTouch.y1 = y1;
this.touch.lastTouch.x2 = x2; this.touch.lastTouch.x2 = x2;
this.touch.lastTouch.y2 = y2; this.touch.lastTouch.y2 = y2;
const distX = Math.abs(this.touch.lastTouch.x1 - this.touch.lastTouch.x2);
const distY = Math.abs(this.touch.lastTouch.y1 - this.touch.lastTouch.y2);
const dist = Math.sqrt(distX * distX + distY * distY);
this.touch.lastTouch.dist = dist; this.touch.lastTouch.dist = dist;
if (this.touch.origin.x == 0) {
this.touch.origin.x1 = this.touch.origin.x = parseInt((this.touch.lastTouch.x1 + this.touch.lastTouch.x2) / 2);
this.touch.origin.y1 = this.touch.origin.y = parseInt((this.touch.lastTouch.y1 + this.touch.lastTouch.y2) / 2);
};
} else if (event.touches.length == 1) { } else if (event.touches.length == 1) {
if (this.touch.scale == 1) return; if (this.touch.scale == 1) return;
@@ -135,43 +151,31 @@ export default {
touchmove(event) { touchmove(event) {
if (event.touches.length == 2) { if (event.touches.length == 2) {
if (this.touch.type != 2) return; if (this.touch.type != 2) return;
const { x1, y1, x2, y2 } = this.getScalePosition(event); const { x1, y1, x2, y2 } = this.getScalePosition(event);
const dist = this.getDist(x1, y1, x2, y2);
const distX = Math.abs(x1 - x2); this.touch.scale += (dist - this.touch.lastTouch.dist) / 500;
const distY = Math.abs(y1 - y2); this.touch.scale = Math.max(this.touch.scale, 1);
const dist = Math.sqrt(distX * distX + distY * distY);
this.touch.scale += parseInt((dist - this.touch.lastTouch.dist) / 500 * 100) / 100;
if (this.touch.scale <= 1) this.touch.scale = 1;
this.touch.lastTouch.dist = dist;
this.touch.lastTouch.x1 = x1; this.touch.lastTouch.x1 = x1;
this.touch.lastTouch.y1 = y1; this.touch.lastTouch.y1 = y1;
this.touch.lastTouch.x2 = x2; this.touch.lastTouch.x2 = x2;
this.touch.lastTouch.y2 = y2; this.touch.lastTouch.y2 = y2;
this.touch.lastTouch.dist = dist;
this.calcClip();
this.touch.updated = true; this.touch.updated = true;
} else if (event.touches.length == 1) { } else if (event.touches.length == 1) {
if (this.touch.type != 1 || this.touch.scale == 1) return; if (this.touch.type != 1 || this.touch.scale == 1) {
return;
}
const { x1, y1 } = this.getPosition(event); const { x1, y1 } = this.getPosition(event);
const distX = x1 - this.touch.lastTouch.x1; this.touch.clip.x -= (x1 - this.touch.lastTouch.x1) / this.touch.scale;
const distY = y1 - this.touch.lastTouch.y1; this.touch.clip.y -= (y1 - this.touch.lastTouch.y1) / this.touch.scale;
this.touch.origin.distX = distX;
this.touch.origin.distY = distY;
this.touch.origin.x1 -= distX;
if (this.touch.origin.x1 <= 0) this.touch.origin.x1 = 0;
else if (this.touch.origin.x1 >= event.srcElement.width) this.touch.origin.x1 = event.srcElement.width;
this.touch.origin.x = parseInt(this.touch.origin.x1);
this.touch.origin.y1 -= distY;
if (this.touch.origin.y1 <= 0) this.touch.origin.y1 = 0;
else if (this.touch.origin.y1 >= event.srcElement.height) this.touch.origin.y1 = event.srcElement.height;
this.touch.origin.y = parseInt(this.touch.origin.y1);
this.touch.lastTouch.x1 = x1; this.touch.lastTouch.x1 = x1;
this.touch.lastTouch.y1 = y1; this.touch.lastTouch.y1 = y1;
@@ -179,91 +183,113 @@ export default {
this.touch.updated = true; this.touch.updated = true;
} }
}, },
calcClip() {
const width = this.width, height = this.height, scale = this.touch.scale, origin = this.touch.origin;
if (width == 0 || height == 0) {
return;
}
const clipWidth = (width * scale - width) / scale;
const clipHeight = (height * scale - height) / scale;
const x = clipWidth * (origin.x1 / width);
const y = clipHeight * (origin.y1 / height);
this.touch.clip.x = x;
this.touch.clip.y = y;
this.touch.clip.w = width - clipWidth;
this.touch.clip.h = height - clipHeight;
}
} }
}; };
}, },
globalData: null, globalData: null,
reported: true,
init() { init() {
this.globalData = injectGlobalData(); this.globalData = injectGlobalData();
this.reportInterval(0);
this.subMessage(); this.subMessage();
this.reportInterval();
this.fpsInterval(); this.fpsInterval();
this.clipInterver(); this.clipInterver();
this.draw(); this.draw();
}, },
uninit() {
clearTimeout(this.reportTimer);
clearTimeout(this.clipTimer);
},
subMessage() { imgOnload(url, param) {
const imgOnload = (url, param) => { return new Promise((resolve, reject) => {
return new Promise((resolve, reject) => { const img = new Image();
const img = new Image(); img.param = param;
img.param = param; img.src = url;
img.src = url; img.onload = function () {
img.onload = function () { resolve(img);
resolve(img); };
};
});
}
subNotifyMsg('/notify/report/screen/full', (res, param) => {
const name = res.Name;
if (this.globalData.value.reportNames.indexOf(name) == -1) return;
let item = this.globalData.value.devices.filter(c => c.MachineName == name)[0];
if (item) {
item.Screen.fpsTimes++;
if (typeof res.Img == 'string') {
imgOnload(`data:image/jpg;base64,${res.Img}`).then((img) => {
item.Screen.img = img;
});
} else {
imgOnload(URL.createObjectURL(res.Img)).then((img) => {
item.Screen.img = img;
});
}
}
}); });
},
subNotifyMsg('/notify/report/screen/region', (res, param) => { handleScreenFull(res, param) {
const name = res.Name; const name = res.Name;
if (this.globalData.value.reportNames.indexOf(name) == -1) return; if (this.globalData.value.reportNames.indexOf(name) == -1) return;
let item = this.globalData.value.devices.filter(c => c.MachineName == name)[0]; let item = this.globalData.value.devices.filter(c => c.MachineName == name)[0];
if (item) { if (item) {
item.Screen.fpsTimes++; item.Screen.fps.temp++;
res.Img.arrayBuffer().then((arrayBuffer) => { if (typeof res.Img == 'string') {
const dataView = new DataView(arrayBuffer); this.imgOnload(`data:image/jpg;base64,${res.Img}`).then((img) => {
let index = 0; item.Screen.fullImg = img;
const images = []; });
while (index < arrayBuffer.byteLength) { } else {
this.imgOnload(URL.createObjectURL(res.Img)).then((img) => {
const length = dataView.getUint32(index, true); item.Screen.fullImg = img;
index += 4;
const x = dataView.getUint32(index, true);
index += 4;
const w = dataView.getUint32(index, true);
index += 4;
const y = dataView.getUint32(index, true);
index += 4;
const h = dataView.getUint32(index, true);
index += 4;
images.push(imgOnload(URL.createObjectURL(res.Img.slice(index, index + length)), { x: x, y: y, w: w, h: h }));
index += length;
}
Promise.all(images).then((images) => {
item.Screen.regions = images;
});
}); });
} }
}); }
subNotifyMsg('/notify/report/screen/rectangles', (res, param) => { },
const name = res.Name; handleScreenRegion(res, param) {
if (this.globalData.value.reportNames.indexOf(name) == -1) return; const name = res.Name;
let item = this.globalData.value.devices.filter(c => c.MachineName == name)[0]; if (this.globalData.value.reportNames.indexOf(name) == -1) return;
if (item) { let item = this.globalData.value.devices.filter(c => c.MachineName == name)[0];
item.Screen.rectangles = res.Rectangles; if (item) {
item.Screen.fps.temp++;
res.Img.arrayBuffer().then((arrayBuffer) => {
const dataView = new DataView(arrayBuffer);
let index = 0;
const images = [];
while (index < arrayBuffer.byteLength) {
} const length = dataView.getUint32(index, true);
}); index += 4;
const x = dataView.getUint32(index, true);
index += 4;
const w = dataView.getUint32(index, true);
index += 4;
const y = dataView.getUint32(index, true);
index += 4;
const h = dataView.getUint32(index, true);
index += 4;
images.push(this.imgOnload(URL.createObjectURL(res.Img.slice(index, index + length)), { x: x, y: y, w: w, h: h }));
index += length;
}
Promise.all(images).then((images) => {
item.Screen.regionImgs = images;
});
});
}
},
handleScreenRectangles(res, param) {
const name = res.Name;
if (this.globalData.value.reportNames.indexOf(name) == -1) return;
let item = this.globalData.value.devices.filter(c => c.MachineName == name)[0];
if (item) {
item.Screen.rectangles = res.Rectangles;
}
},
subMessage() {
subNotifyMsg('/notify/report/screen/full', (res, param) => this.handleScreenFull(res, param));
subNotifyMsg('/notify/report/screen/region', (res, param) => this.handleScreenRegion(res, param));
subNotifyMsg('/notify/report/screen/rectangles', (res, param) => this.handleScreenRectangles(res, param));
}, },
draw() { draw() {
@@ -292,13 +318,13 @@ export default {
if (item.ctx) { if (item.ctx) {
item.infoCtx.clearRect(0, 0, item.infoCanvas.width, item.infoCanvas.height); item.infoCtx.clearRect(0, 0, item.infoCanvas.width, item.infoCanvas.height);
const img = item.Screen.img; const img = item.Screen.fullImg;
if (img) { if (img) {
//item.Screen.img = null; //item.Screen.img = null;
item.ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, item.canvas.width, item.canvas.height); item.ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, item.canvas.width, item.canvas.height);
} }
const regions = item.Screen.regions; const regions = item.Screen.regionImgs;
for (let i = 0; i < regions.length; i++) { for (let i = 0; i < regions.length; i++) {
const { x, y, w, h } = regions[i].param; const { x, y, w, h } = regions[i].param;
item.infoCtx.drawImage(regions[i], 0, 0, regions[i].width, regions[i].height, x, y, w, h); item.infoCtx.drawImage(regions[i], 0, 0, regions[i].width, regions[i].height, x, y, w, h);
@@ -324,8 +350,8 @@ export default {
fpsInterval() { fpsInterval() {
this.globalData.value.devices.forEach(item => { this.globalData.value.devices.forEach(item => {
item.Screen.fps = item.Screen.fpsTimes; item.Screen.fps.value = item.Screen.fps.temp;
item.Screen.fpsTimes = 0; item.Screen.fps.temp = 0;
}); });
setTimeout(() => { setTimeout(() => {
this.fpsInterval(); this.fpsInterval();
@@ -336,7 +362,12 @@ export default {
clipInterver() { clipInterver() {
this.globalData.value.devices.forEach(item => { this.globalData.value.devices.forEach(item => {
if (item.Screen.touch.updated) { if (item.Screen.touch.updated) {
screenClip(item.MachineName, item.Screen.touch.origin.x, item.Screen.touch.origin.y, item.Screen.touch.scale).then(() => { screenClip(item.MachineName, {
x: parseInt(item.Screen.touch.clip.x),
y: parseInt(item.Screen.touch.clip.y),
w: parseInt(item.Screen.touch.clip.w),
h: parseInt(item.Screen.touch.clip.h),
}).then(() => {
item.Screen.touch.updated = false; item.Screen.touch.updated = false;
}).catch(() => { }).catch(() => {
item.Screen.touch.updated = false; item.Screen.touch.updated = false;
@@ -352,9 +383,10 @@ export default {
reportTimer: 0, reportTimer: 0,
updateFull() { updateFull() {
const names = this.globalData.value.reportNames; const names = this.globalData.value.reportNames;
let reportType = 1; const devices = this.globalData.value.devices;
this.globalData.value.devices.filter(c => names.indexOf(c.MachineName) >= 0).forEach(item => { let reportType = 2;
reportType &&= Number(item.Screen.fullUpdated); devices.filter(c => names.indexOf(c.MachineName) >= 0).forEach(item => {
reportType &&= (Number(item.Screen.fullUpdated) + 1);
item.Screen.fullUpdated = true; item.Screen.fullUpdated = true;
}); });
return screenUpdateFull(names, reportType); return screenUpdateFull(names, reportType);
@@ -363,17 +395,17 @@ export default {
const names = this.globalData.value.reportNames; const names = this.globalData.value.reportNames;
return screenUpdateRegion(names); return screenUpdateRegion(names);
}, },
reportInterval(times) { reportInterval(times = 0) {
if (this.reported) { if (this.reported) {
this.reported = false; this.reported = false;
//const fn = times < 2 ? this.updateFull() : this.updateRegion();
const fn = this.updateFull(); const fn = this.updateFull();
fn.then(() => { fn.then(() => {
this.reported = true; this.reported = true;
this.reportTimer = setTimeout(() => { this.reportTimer = setTimeout(() => {
this.reportInterval(++times); this.reportInterval(++times);
}, 300); }, 300);
}).catch(() => { }).catch((e) => {
console.log(e);
this.reported = true; this.reported = true;
this.reportTimer = setTimeout(() => { this.reportTimer = setTimeout(() => {
this.reportInterval(++times); this.reportInterval(++times);
@@ -391,5 +423,7 @@ export default {
item.Screen.lastInput = report.Screen.LT || 0; item.Screen.lastInput = report.Screen.LT || 0;
item.Screen.captureTime = report.Screen.CT || 0; item.Screen.captureTime = report.Screen.CT || 0;
item.Screen.width = report.Screen.W || 0;
item.Screen.height = report.Screen.H || 0;
} }
} }

View File

@@ -18,7 +18,7 @@
</dt> </dt>
<dd class="img"> <dd class="img">
<div class="inner"> <div class="inner">
<canvas v-if="data.Connected" width="1920" height="1080" :id="`canvas-${data.MachineName}`" @dblclick="handleCanvasReset" @touchstart="handleCanvasTouchstart" @touchend="handleCanvasTouchend" @touchmove="handleCanvasTouchmove"></canvas> <canvas v-if="data.Connected && data.Screen.width>0 && data.Screen.height>0" :width="data.Screen.width" :height="data.Screen.height" :id="`canvas-${data.MachineName}`" @dblclick="handleCanvasReset" @touchstart="handleCanvasTouchstart" @touchend="handleCanvasTouchend" @touchmove="handleCanvasTouchmove"></canvas>
<template v-for="(item,index) in screenModules" :key="index"> <template v-for="(item,index) in screenModules" :key="index">
<component :is="item" :data="data"></component> <component :is="item" :data="data"></component>
</template> </template>
@@ -114,7 +114,7 @@ export default {
// background-color: #fff; // background-color: #fff;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.05); box-shadow: 0 0 4px rgba(0, 0, 0, 0.05);
width: 100%; width: 100%;
margin: 0 auto .6rem auto; margin: 0 auto 0.6rem auto;
position: relative; position: relative;
transition: 0.3s; transition: 0.3s;
background-color: rgba(255, 255, 255, 0.5); background-color: rgba(255, 255, 255, 0.5);

View File

@@ -23,7 +23,11 @@ export default {
const files = require.context('../plugins/', true, /index\.js/); const files = require.context('../plugins/', true, /index\.js/);
const pluginSettings = files.keys().map(c => files(c).default); const pluginSettings = files.keys().map(c => files(c).default);
pluginSettings.forEach((item) => { pluginSettings.forEach((item) => {
item.init && item.init(); try {
item.init && item.init();
} catch (e) {
console.log(e);
}
}); });
const globalData = injectGlobalData(); const globalData = injectGlobalData();
@@ -119,6 +123,7 @@ export default {
} }
} }
let getListTimer = 0;
const updateListInterver = () => { const updateListInterver = () => {
if (websocketState.connected) { if (websocketState.connected) {
getList().then((res) => { getList().then((res) => {
@@ -132,7 +137,7 @@ export default {
}); });
} }
setTimeout(() => { getListTimer = setTimeout(() => {
updateListInterver(); updateListInterver();
}, 1000); }, 1000);
} }
@@ -146,6 +151,11 @@ export default {
}); });
onUnmounted(() => { onUnmounted(() => {
listWrapRemoveScrollListener(); listWrapRemoveScrollListener();
clearTimeout(getListTimer);
pluginSettings.forEach((item) => {
item.uninit && item.uninit();
});
}); });
return { return {

View File

@@ -17,6 +17,7 @@ export const provideGlobalData = () => {
} }
return []; return [];
}), }),
latestReportNames: [],
reportNames: [] reportNames: []
}); });
provide(globalDataSymbol, globalData); provide(globalDataSymbol, globalData);

View File

@@ -1,4 +1,5 @@
using cmonitor.server.service; using cmonitor.server.client.reports.hijack;
using cmonitor.server.service;
using cmonitor.server.service.messengers.hijack; using cmonitor.server.service.messengers.hijack;
using cmonitor.server.service.messengers.sign; using cmonitor.server.service.messengers.sign;
using common.libs.extends; using common.libs.extends;

View File

@@ -26,6 +26,7 @@ namespace cmonitor.server.api.services
{ {
bool connectionRes = signCaching.Get(report.Names[i], out SignCacheInfo cache) && cache.Connected; bool connectionRes = signCaching.Get(report.Names[i], out SignCacheInfo cache) && cache.Connected;
bool reportRes = cache.GetScreen(config.ScreenDelay) && Interlocked.CompareExchange(ref cache.ScreenFlag, 0, 1) == 1; bool reportRes = cache.GetScreen(config.ScreenDelay) && Interlocked.CompareExchange(ref cache.ScreenFlag, 0, 1) == 1;
if (connectionRes && reportRes) if (connectionRes && reportRes)
{ {
cache.UpdateScreen(); cache.UpdateScreen();
@@ -86,6 +87,7 @@ namespace cmonitor.server.api.services
return true; return true;
} }
} }
public sealed class ScreenReportInfo public sealed class ScreenReportInfo

View File

@@ -15,7 +15,7 @@ namespace cmonitor.server.api.services
this.messengerSender = messengerSender; this.messengerSender = messengerSender;
this.signCaching = signCaching; this.signCaching = signCaching;
} }
public async Task<bool> Update(ClientServiceParamsInfo param) public bool Update(ClientServiceParamsInfo param)
{ {
WallpaperLockInfo info = param.Content.DeJson<WallpaperLockInfo>(); WallpaperLockInfo info = param.Content.DeJson<WallpaperLockInfo>();
byte[] bytes = MemoryPackSerializer.Serialize(new WallpaperUpdateInfo byte[] bytes = MemoryPackSerializer.Serialize(new WallpaperUpdateInfo
@@ -27,7 +27,7 @@ namespace cmonitor.server.api.services
{ {
if (signCaching.Get(info.Names[i], out SignCacheInfo cache) && cache.Connected) if (signCaching.Get(info.Names[i], out SignCacheInfo cache) && cache.Connected)
{ {
await messengerSender.SendOnly(new MessageRequestWrap _ = messengerSender.SendOnly(new MessageRequestWrap
{ {
Connection = cache.Connection, Connection = cache.Connection,
MessengerId = (ushort)WallpaperMessengerIds.Update, MessengerId = (ushort)WallpaperMessengerIds.Update,

View File

@@ -1,4 +1,5 @@
using common.libs.database; using cmonitor.hijack;
using common.libs.database;
using System; using System;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
@@ -14,15 +15,87 @@ namespace cmonitor.server.client
{ {
this.configDataProvider = configDataProvider; this.configDataProvider = configDataProvider;
ClientConfig config = configDataProvider.Load().Result ?? new ClientConfig(); ClientConfig config = configDataProvider.Load().Result ?? new ClientConfig();
Lock = config.Lock; LLock = config.LLock;
Wallpaper = config.Wallpaper; Wallpaper = config.Wallpaper;
Usb = config.Usb; WallpaperUrl = config.WallpaperUrl;
Save(); HijackConfig = config.HijackConfig;
WindowNames = config.WindowNames;
SaveTask();
}
private void SaveTask()
{
Task.Factory.StartNew(() =>
{
while (true)
{
try
{
if (updated)
{
Save();
}
}
catch (Exception)
{
}
System.Threading.Thread.Sleep(5000);
}
}, TaskCreationOptions.LongRunning);
}
private bool updated = false;
private bool _llock;
public bool LLock
{
get => _llock; set
{
_llock = value;
updated = true;
}
}
private bool _wallpaper;
public bool Wallpaper
{
get => _wallpaper; set
{
_wallpaper = value;
updated = true;
}
}
private string _wallpaperUrl;
public string WallpaperUrl
{
get => _wallpaperUrl; set
{
_wallpaperUrl = value;
updated = true;
}
}
private HijackConfig _hijackConfig = new HijackConfig();
public HijackConfig HijackConfig
{
get => _hijackConfig; set
{
_hijackConfig = value;
updated = true;
}
}
private string[] _windowNames = Array.Empty<string>();
public string[] WindowNames
{
get => _windowNames; set
{
_windowNames = value;
updated = true;
}
} }
public bool Lock { get; set; }
public bool Wallpaper { get; set; }
public bool Usb { get; set; }
public void Save() public void Save()
{ {

View File

@@ -58,8 +58,8 @@ namespace cmonitor.server.client
{ {
IPAddress[] ips = new IPAddress[] { config.Server }; IPAddress[] ips = new IPAddress[] { config.Server };
//if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG) if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
Logger.Instance.Info($"get ip:{ips.ToJson()}"); Logger.Instance.Info($"get ip:{ips.ToJson()}");
if (ips.Length == 0) return; if (ips.Length == 0) return;
foreach (IPAddress ip in ips) foreach (IPAddress ip in ips)

View File

@@ -27,7 +27,7 @@ namespace cmonitor.server.client.reports
private List<IReport> reports; private List<IReport> reports;
private Dictionary<string, object> reportObj; private Dictionary<string, object> reportObj;
private ReportType reportType = ReportType.Full; private ReportType reportType = ReportType.Full | ReportType.Trim;
public ReportTransfer(ClientSignInState clientSignInState, MessengerSender messengerSender, ServiceProvider serviceProvider, Config config) public ReportTransfer(ClientSignInState clientSignInState, MessengerSender messengerSender, ServiceProvider serviceProvider, Config config)
{ {
@@ -57,7 +57,7 @@ namespace cmonitor.server.client.reports
private long ticks = 0; private long ticks = 0;
public void Update(ReportType reportType) public void Update(ReportType reportType)
{ {
this.reportType = reportType; this.reportType |= reportType;
ticks = DateTime.UtcNow.Ticks; ticks = DateTime.UtcNow.Ticks;
Interlocked.CompareExchange(ref reportFlag, 1, 0); Interlocked.CompareExchange(ref reportFlag, 1, 0);
} }
@@ -93,13 +93,15 @@ namespace cmonitor.server.client.reports
{ {
if (string.IsNullOrWhiteSpace(item.Name) == false) if (string.IsNullOrWhiteSpace(item.Name) == false)
{ {
object val = item.GetReports(reportType); object val = item.GetReports(reportType & ReportType.Full);
if (val != null) if (val != null)
{ {
reportObj[item.Name] = val; reportObj[item.Name] = val;
} }
} }
} }
reportType &= ~reportType;
if (reportObj.Count > 0) if (reportObj.Count > 0)
{ {
@@ -117,6 +119,6 @@ namespace cmonitor.server.client.reports
public enum ReportType : byte public enum ReportType : byte
{ {
Full = 0, Trim = 1 Full = 1, Trim = 2
} }
} }

View File

@@ -14,28 +14,37 @@ namespace cmonitor.server.client.reports.active
{ {
public string Name => "ActiveWindow"; public string Name => "ActiveWindow";
private readonly ClientConfig clientConfig;
private readonly ActiveWindowTimeManager activeWindowTimeManager = new ActiveWindowTimeManager(); private readonly ActiveWindowTimeManager activeWindowTimeManager = new ActiveWindowTimeManager();
private ActiveReportInfo report = new ActiveReportInfo(); private ActiveReportInfo report = new ActiveReportInfo();
private uint lastPid = 0; private uint lastPid = 0;
private string lastTitle = string.Empty; private string lastTitle = string.Empty;
public ActiveWindowReport(Config config) private int count = 0;
public ActiveWindowReport(Config config, ClientConfig clientConfig)
{ {
this.clientConfig = clientConfig;
if (config.IsCLient) if (config.IsCLient)
{ {
Timers(); Timers();
DisallowInit(); DisallowInit();
DisallowRun(clientConfig.WindowNames);
AppDomain.CurrentDomain.ProcessExit += (s, e) => DisallowRun(Array.Empty<string>()); AppDomain.CurrentDomain.ProcessExit += (s, e) => DisallowRun(Array.Empty<string>());
Console.CancelKeyPress += (s, e) => DisallowRun(Array.Empty<string>()); Console.CancelKeyPress += (s, e) => DisallowRun(Array.Empty<string>());
} }
} }
public object GetReports(ReportType reportType) public object GetReports(ReportType reportType)
{ {
if (reportType == ReportType.Full || report.Pid != lastPid || report.Title != lastTitle) if (reportType == ReportType.Full || report.Pid != lastPid || report.Title != lastTitle || report.Count != count)
{ {
lastPid = report.Pid; lastPid = report.Pid;
lastTitle = report.Title; lastTitle = report.Title;
count = report.Count;
return report; return report;
} }
return null; return null;
@@ -75,7 +84,6 @@ namespace cmonitor.server.client.reports.active
} }
const int nChars = 256; const int nChars = 256;
private StringBuilder buff = new StringBuilder(nChars); private StringBuilder buff = new StringBuilder(nChars);
private void GetActiveWindow() private void GetActiveWindow()
@@ -118,17 +126,19 @@ namespace cmonitor.server.client.reports.active
private string[] disallowNames = Array.Empty<string>(); private string[] disallowNames = Array.Empty<string>();
public void DisallowRun(string[] names) public void DisallowRun(string[] names)
{ {
clientConfig.WindowNames = names;
DisallowRun(false); DisallowRun(false);
DisallowRunClear(); DisallowRunClear();
report.Count = names.Length; report.Count = names.Length;
disallowNames = names; disallowNames = names;
if (names.Length > 0)
{
DisallowRun(true);
DisallowRunFileNames(names);
}
Task.Run(() => Task.Run(() =>
{ {
if (names.Length > 0)
{
DisallowRun(true);
DisallowRunFileNames(names);
}
CommandHelper.Windows(string.Empty, new string[] { "gpupdate /force" }); CommandHelper.Windows(string.Empty, new string[] { "gpupdate /force" });
}); });
} }

View File

@@ -1,26 +1,39 @@
using cmonitor.hijack; using cmonitor.hijack;
using common.libs; using common.libs;
using MemoryPack;
namespace cmonitor.server.client.reports.hijack namespace cmonitor.server.client.reports.hijack
{ {
internal sealed class HijackReport : IReport public sealed class HijackReport : IReport
{ {
public string Name => "Hijack"; public string Name => "Hijack";
private readonly HijackEventHandler hijackEventHandler; private readonly HijackEventHandler hijackEventHandler;
private readonly HijackConfig hijackConfig; private readonly HijackConfig hijackConfig;
private readonly ClientConfig clientConfig;
private readonly HijackController hijackController;
private ulong[] array = new ulong[3]; private ulong[] array = new ulong[3];
private ulong[] lastArray = new ulong[3]; private ulong[] lastArray = new ulong[3];
private long ticks = DateTime.UtcNow.Ticks; private long ticks = DateTime.UtcNow.Ticks;
public HijackReport(HijackEventHandler hijackEventHandler, HijackController hijackController, HijackConfig hijackConfig) public HijackReport(HijackEventHandler hijackEventHandler, HijackController hijackController, HijackConfig hijackConfig, ClientConfig clientConfig,Config config)
{ {
this.hijackEventHandler = hijackEventHandler; this.hijackEventHandler = hijackEventHandler;
this.hijackController = hijackController;
this.hijackConfig = hijackConfig; this.hijackConfig = hijackConfig;
if (OperatingSystem.IsWindows()) this.clientConfig = clientConfig;
if (OperatingSystem.IsWindows() && config.IsCLient)
{ {
try try
{ {
hijackConfig.DeniedProcesss = clientConfig.HijackConfig.DeniedProcesss;
hijackConfig.AllowProcesss = clientConfig.HijackConfig.AllowProcesss;
hijackConfig.DeniedDomains = clientConfig.HijackConfig.DeniedDomains;
hijackConfig.AllowDomains = clientConfig.HijackConfig.AllowDomains;
hijackConfig.DeniedIPs = clientConfig.HijackConfig.DeniedIPs;
hijackConfig.AllowIPs = clientConfig.HijackConfig.AllowIPs;
hijackController.Start(); hijackController.Start();
} }
catch (Exception ex) catch (Exception ex)
@@ -30,6 +43,20 @@ namespace cmonitor.server.client.reports.hijack
} }
} }
public void Update(SetRuleInfo info)
{
hijackConfig.AllowDomains = info.AllowDomains;
hijackConfig.DeniedDomains = info.DeniedDomains;
hijackConfig.AllowProcesss = info.AllowProcesss;
hijackConfig.DeniedProcesss = info.DeniedProcesss;
hijackConfig.AllowIPs = info.AllowIPs;
hijackConfig.DeniedIPs = info.DeniedIPs;
clientConfig.HijackConfig = hijackConfig;
hijackController.SetRules();
}
public object GetReports(ReportType reportType) public object GetReports(ReportType reportType)
{ {
array[0] = hijackEventHandler.UdpSend + hijackEventHandler.TcpSend; array[0] = hijackEventHandler.UdpSend + hijackEventHandler.TcpSend;
@@ -49,4 +76,35 @@ namespace cmonitor.server.client.reports.hijack
return null; return null;
} }
} }
[MemoryPackable]
public sealed partial class SetRuleInfo
{
/// <summary>
/// 进程白名单
/// </summary>
public string[] AllowProcesss { get; set; } = Array.Empty<string>();
/// <summary>
/// 进程黑名单
/// </summary>
public string[] DeniedProcesss { get; set; } = Array.Empty<string>();
/// <summary>
/// 域名白名单
/// </summary>
public string[] AllowDomains { get; set; } = Array.Empty<string>();
/// <summary>
/// 域名黑名单
/// </summary>
public string[] DeniedDomains { get; set; } = Array.Empty<string>();
/// <summary>
/// ip白名单
/// </summary>
public string[] AllowIPs { get; set; } = Array.Empty<string>();
/// <summary>
/// ip黑名单
/// </summary>
public string[] DeniedIPs { get; set; } = Array.Empty<string>();
}
} }

View File

@@ -12,11 +12,15 @@ namespace cmonitor.server.client.reports.llock
private readonly Config config; private readonly Config config;
private readonly ShareReport shareReport; private readonly ShareReport shareReport;
private readonly ClientConfig clientConfig;
public LLockReport(Config config, ShareReport shareReport) public LLockReport(Config config, ShareReport shareReport, ClientConfig clientConfig)
{ {
this.config = config; this.config = config;
this.shareReport = shareReport; this.shareReport = shareReport;
this.clientConfig = clientConfig;
Update(clientConfig.LLock);
} }
DateTime startTime = new DateTime(1970, 1, 1); DateTime startTime = new DateTime(1970, 1, 1);
@@ -26,7 +30,7 @@ namespace cmonitor.server.client.reports.llock
{ {
report.Value = (long)(DateTime.UtcNow.Subtract(startTime)).TotalMilliseconds - time < 1000; report.Value = (long)(DateTime.UtcNow.Subtract(startTime)).TotalMilliseconds - time < 1000;
} }
if(reportType == ReportType.Full || report.Value != lastValue) if (reportType == ReportType.Full || report.Value != lastValue)
{ {
lastValue = report.Value; lastValue = report.Value;
return report; return report;
@@ -36,6 +40,7 @@ namespace cmonitor.server.client.reports.llock
public void Update(bool open) public void Update(bool open)
{ {
clientConfig.LLock = open;
Task.Run(() => Task.Run(() =>
{ {
CommandHelper.Windows(string.Empty, new string[] { "taskkill /f /t /im \"llock.win.exe\"" }); CommandHelper.Windows(string.Empty, new string[] { "taskkill /f /t /im \"llock.win.exe\"" });

View File

@@ -24,6 +24,7 @@ namespace cmonitor.server.client.reports.screen
private Texture2D desktopImageTexture = null; private Texture2D desktopImageTexture = null;
private Texture2D smallerTexture = null; private Texture2D smallerTexture = null;
private Texture2D tempTexture;
private ShaderResourceView smallerTextureView = null; private ShaderResourceView smallerTextureView = null;
private OutputDuplicateFrameInformation frameInfo = new OutputDuplicateFrameInformation(); private OutputDuplicateFrameInformation frameInfo = new OutputDuplicateFrameInformation();
@@ -248,6 +249,14 @@ namespace cmonitor.server.client.reports.screen
SharpDX.DXGI.Resource desktopResource = null; SharpDX.DXGI.Resource desktopResource = null;
try try
{ {
if (mDeskDupl == null)
{
InitDesk();
}
if (mDeskDupl == null)
{
return false;
}
Result result = mDeskDupl.TryAcquireNextFrame(100, out frameInfo, out desktopResource); Result result = mDeskDupl.TryAcquireNextFrame(100, out frameInfo, out desktopResource);
if (desktopResource == null) if (desktopResource == null)
@@ -271,7 +280,12 @@ namespace cmonitor.server.client.reports.screen
return false; return false;
} }
using Texture2D tempTexture = desktopResource.QueryInterface<Texture2D>(); if (tempTexture != null)
{
tempTexture.Dispose();
tempTexture = null;
}
tempTexture = desktopResource.QueryInterface<Texture2D>();
mDevice.ImmediateContext.CopySubresourceRegion(tempTexture, 0, null, smallerTexture, 0); mDevice.ImmediateContext.CopySubresourceRegion(tempTexture, 0, null, smallerTexture, 0);
desktopResource.Dispose(); desktopResource.Dispose();
@@ -282,9 +296,9 @@ namespace cmonitor.server.client.reports.screen
if (frameInfo.TotalMetadataBufferSize > 0) if (frameInfo.TotalMetadataBufferSize > 0)
{ {
OutputDuplicateMoveRectangle[] movedRectangles = new OutputDuplicateMoveRectangle[frameInfo.TotalMetadataBufferSize*2]; OutputDuplicateMoveRectangle[] movedRectangles = new OutputDuplicateMoveRectangle[frameInfo.TotalMetadataBufferSize];
mDeskDupl.GetFrameMoveRects(movedRectangles.Length, movedRectangles, out int movedRegionsLength); mDeskDupl.GetFrameMoveRects(movedRectangles.Length, movedRectangles, out int movedRegionsLength);
//Console.WriteLine($"movedRegionsLength:{movedRegionsLength}->"); //Console.WriteLine($"TotalMetadataBufferSize:{frameInfo.TotalMetadataBufferSize}->movedRegionsLength:{movedRegionsLength}->");
frame.MovedRegions = new MovedRegion[movedRegionsLength / Marshal.SizeOf(typeof(OutputDuplicateMoveRectangle))]; frame.MovedRegions = new MovedRegion[movedRegionsLength / Marshal.SizeOf(typeof(OutputDuplicateMoveRectangle))];
for (int i = 0; i < frame.MovedRegions.Length; i++) for (int i = 0; i < frame.MovedRegions.Length; i++)
{ {
@@ -335,17 +349,13 @@ namespace cmonitor.server.client.reports.screen
private byte[] fullImageBytes = Helper.EmptyArray; private byte[] fullImageBytes = Helper.EmptyArray;
private Memory<byte> fullImageMemory = Helper.EmptyArray;
public DesktopFrame GetLatestFullFrame(ScreenReportFullType screenReportFullType, float configScale) public DesktopFrame GetLatestFullFrame(float configScale)
{ {
DesktopFrame frame = new DesktopFrame() { FullImage = Helper.EmptyArray, RegionImage = Helper.EmptyArray }; DesktopFrame frame = new DesktopFrame() { FullImage = Helper.EmptyArray, RegionImage = Helper.EmptyArray };
bool success = RetrieveFrame(); bool success = RetrieveFrame();
if (success == false) if (success == false)
{ {
if (screenReportFullType == ScreenReportFullType.Full && fullImageMemory.Length > 0)
{
frame.FullImage = fullImageMemory;
}
return frame; return frame;
} }
@@ -358,7 +368,7 @@ namespace cmonitor.server.client.reports.screen
} }
ProcessFrameFull(frame, configScale); ProcessFrameFull(frame, configScale);
} }
catch(Exception ex) catch (Exception ex)
{ {
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG) if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{ {
@@ -463,8 +473,7 @@ namespace cmonitor.server.client.reports.screen
fullImageBytes = new byte[length]; fullImageBytes = new byte[length];
} }
ms.Read(fullImageBytes.AsSpan(0, length)); ms.Read(fullImageBytes.AsSpan(0, length));
fullImageMemory = fullImageBytes.AsMemory(0, length); frame.FullImage = fullImageBytes.AsMemory(0, length);
frame.FullImage = fullImageMemory;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -571,7 +580,7 @@ namespace cmonitor.server.client.reports.screen
mDevice.ImmediateContext.UnmapSubresource(desktopImageTexture, 0); mDevice.ImmediateContext.UnmapSubresource(desktopImageTexture, 0);
*/ */
Rectangle[] updatedRegions = frame.UpdatedRegions; Rectangle[] updatedRegions = frame.UpdatedRegions;
int index = 0; int index = 0;
for (int i = 0; i < updatedRegions.Length; i++) for (int i = 0; i < updatedRegions.Length; i++)
{ {
@@ -642,7 +651,7 @@ namespace cmonitor.server.client.reports.screen
index += msLength; index += msLength;
} }
frame.RegionImage = regionImageBytes.AsMemory(0, index); frame.RegionImage = regionImageBytes.AsMemory(0, index);
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@@ -8,14 +8,14 @@ namespace cmonitor.server.client.reports.screen
{ {
public GdiDesktop() { } public GdiDesktop() { }
ScreenClipInfo screenClipInfo = new ScreenClipInfo { X = 0, Y = 0, Scale = 1 }; ScreenClipInfo screenClipInfo = new ScreenClipInfo { X = 0, Y = 0, W = 0, H = 0 };
public void Clip(ScreenClipInfo _screenClipInfo) public void Clip(ScreenClipInfo _screenClipInfo)
{ {
screenClipInfo = _screenClipInfo; screenClipInfo = _screenClipInfo;
} }
public bool IsClip() public bool IsClip()
{ {
return screenClipInfo.Scale != 1; return screenClipInfo.W > 0 && screenClipInfo.H > 0;
} }
public bool IsLockScreen() public bool IsLockScreen()
{ {
@@ -27,82 +27,75 @@ namespace cmonitor.server.client.reports.screen
{ {
DesktopFrame frame = new DesktopFrame { FullImage = Helper.EmptyArray, MovedRegions = new MovedRegion[0], RegionImage = Helper.EmptyArray, UpdatedRegions = new Rectangle[0] }; DesktopFrame frame = new DesktopFrame { FullImage = Helper.EmptyArray, MovedRegions = new MovedRegion[0], RegionImage = Helper.EmptyArray, UpdatedRegions = new Rectangle[0] };
if (OperatingSystem.IsWindows()) if (OperatingSystem.IsWindows())
{ {
IntPtr hdc = WinApi.GetDC(IntPtr.Zero); try
if (hdc == IntPtr.Zero) return frame;
GetSystemScale(out float scaleX, out float scaleY, out int sourceWidth, out int sourceHeight);
Rect sourceRect = new Rect(sourceWidth, sourceHeight);
CalcClip(sourceRect, out Rectangle clipRectangle);
GetNewSize(sourceRect, scaleX, scaleY, configScale, out Rect distRect);
using Bitmap image = new Bitmap(clipRectangle.Width, clipRectangle.Height);
using (Graphics g = Graphics.FromImage(image))
{ {
g.CopyFromScreen(clipRectangle.X, clipRectangle.Y, 0, 0, image.Size, CopyPixelOperation.SourceCopy); IntPtr hdc = WinApi.GetDC(IntPtr.Zero);
g.Dispose(); if (hdc == IntPtr.Zero) return frame;
}
WinApi.ReleaseDC(IntPtr.Zero, hdc);
Bitmap bmp = image; GetSystemScale(out float scaleX, out float scaleY, out int sourceWidth, out int sourceHeight);
if (clipRectangle.Width - distRect.Width > 50) Rect sourceRect = new Rect(sourceWidth, sourceHeight);
CalcClip(out Rectangle clipRectangle);
if (screenClipInfo.W == 0 || screenClipInfo.H == 0)
{
clipRectangle.Width = sourceWidth;
clipRectangle.Height = sourceHeight;
}
GetNewSize(sourceRect, scaleX, scaleY, configScale, out Rect distRect);
using Bitmap image = new Bitmap(clipRectangle.Width, clipRectangle.Height);
using (Graphics g = Graphics.FromImage(image))
{
g.CopyFromScreen(clipRectangle.X, clipRectangle.Y, 0, 0, image.Size, CopyPixelOperation.SourceCopy);
g.Dispose();
}
WinApi.ReleaseDC(IntPtr.Zero, hdc);
Bitmap bmp = image;
if (clipRectangle.Width - distRect.Width > 50)
{
bmp = new Bitmap(distRect.Width, distRect.Height);
using Graphics graphic = Graphics.FromImage(bmp);
graphic.DrawImage(image, new System.Drawing.Rectangle(0, 0, distRect.Width, distRect.Height), 0, 0, clipRectangle.Width, clipRectangle.Height, GraphicsUnit.Pixel);
}
using Image image1 = bmp;
using MemoryStream ms = new MemoryStream();
image1.Save(ms, ImageFormat.Jpeg);
ms.Seek(0, SeekOrigin.Begin);
int length = (int)ms.Length;
if (length > fullImageBytes.Length)
{
fullImageBytes = new byte[length];
}
ms.Read(fullImageBytes.AsSpan(0, length));
frame.FullImage = fullImageBytes.AsMemory(0, length);
}
catch (Exception ex)
{ {
bmp = new Bitmap(distRect.Width, distRect.Height); if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
using Graphics graphic = Graphics.FromImage(bmp); {
graphic.DrawImage(image, new System.Drawing.Rectangle(0, 0, distRect.Width, distRect.Height), 0, 0, clipRectangle.Width, clipRectangle.Height, GraphicsUnit.Pixel); Logger.Instance.Error(ex);
}
} }
using Image image1 = bmp;
using MemoryStream ms = new MemoryStream();
image1.Save(ms, ImageFormat.Jpeg);
ms.Seek(0, SeekOrigin.Begin);
int length = (int)ms.Length;
if (length > fullImageBytes.Length)
{
fullImageBytes = new byte[length];
}
ms.Read(fullImageBytes.AsSpan(0, length));
frame.FullImage = fullImageBytes.AsMemory(0, length);
} }
return frame; return frame;
} }
private void CalcClip(Rect sourceRect, out Rectangle rectangle) private void CalcClip(out Rectangle rectangle)
{ {
Scale scale = new Scale(screenClipInfo.X, screenClipInfo.Y, screenClipInfo.Scale); rectangle = new Rectangle(screenClipInfo.X, screenClipInfo.Y, screenClipInfo.W, screenClipInfo.H);
CalcClip(sourceRect, scale, out rectangle);
}
private void CalcClip(Rect sourceRect, Scale scale, out Rectangle rectangle)
{
//缩放后宽高
int newSourceWidth = (int)(sourceRect.Width * scale.Value);
int newSourceHeight = (int)(sourceRect.Height * scale.Value);
//减去的宽高
int clipWidth = (int)((newSourceWidth - sourceRect.Width) * 1.0 / newSourceWidth * sourceRect.Width);
int clipHeight = (int)((newSourceHeight - sourceRect.Height) * 1.0 / newSourceHeight * sourceRect.Height);
//留下的宽高
int width = sourceRect.Width - clipWidth;
int height = sourceRect.Height - clipHeight;
float scaleX = scale.X * 1.0f / sourceRect.Width;
float scaleY = scale.Y * 1.0f / sourceRect.Height;
int left = (int)(clipWidth * scaleX);
int top = (int)(clipHeight * scaleY);
rectangle = new Rectangle(left, top, width, height);
} }
private bool GetSystemScale(out float x, out float y, out int sourceWidth, out int sourceHeight) public bool GetSystemScale(out float x, out float y, out int sourceWidth, out int sourceHeight)
{ {
x = 1; x = 1;
y = 1; y = 1;

View File

@@ -3,6 +3,7 @@ using common.libs;
using cmonitor.server.service.messengers.screen; using cmonitor.server.service.messengers.screen;
using MemoryPack; using MemoryPack;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.InteropServices;
namespace cmonitor.server.client.reports.screen namespace cmonitor.server.client.reports.screen
{ {
@@ -16,7 +17,6 @@ namespace cmonitor.server.client.reports.screen
private ScreenReportInfo report = new ScreenReportInfo(); private ScreenReportInfo report = new ScreenReportInfo();
private uint lastInput; private uint lastInput;
private uint captureTime;
private readonly DxgiDesktop dxgiDesktop; private readonly DxgiDesktop dxgiDesktop;
private readonly GdiDesktop gdiDesktop; private readonly GdiDesktop gdiDesktop;
@@ -31,16 +31,24 @@ namespace cmonitor.server.client.reports.screen
WinApi.InitLastInputInfo(); WinApi.InitLastInputInfo();
dxgiDesktop = new DxgiDesktop(0); dxgiDesktop = new DxgiDesktop(0);
gdiDesktop = new GdiDesktop(); gdiDesktop = new GdiDesktop();
InitSise();
} }
} }
private void InitSise()
{
if (gdiDesktop.GetSystemScale(out _, out _, out int w, out int h))
{
report.W = w;
report.H = h;
}
}
public object GetReports(ReportType reportType) public object GetReports(ReportType reportType)
{ {
report.LT = WinApi.GetLastInputInfo(); report.LT = WinApi.GetLastInputInfo();
if (report.LT < lastInput || report.LT - lastInput > 1000) if (reportType == ReportType.Full || report.LT < lastInput || report.LT - lastInput > 1000)
{ {
lastInput = report.LT; lastInput = report.LT;
captureTime = report.CT;
return report; return report;
} }
return null; return null;
@@ -48,13 +56,13 @@ namespace cmonitor.server.client.reports.screen
private ScreenReportType screenReportType = ScreenReportType.Full; private ScreenReportType screenReportType = ScreenReportType.Full;
private ScreenReportFullType screenReportFullType = ScreenReportFullType.Trim; private ScreenReportFullType screenReportFullType = ScreenReportFullType.Full | ScreenReportFullType.Trim;
private long ticks = 0; private long ticks = 0;
public void Full(ScreenReportFullType screenReportFullType) public void Full(ScreenReportFullType screenReportFullType)
{ {
ticks = DateTime.UtcNow.Ticks; ticks = DateTime.UtcNow.Ticks;
screenReportType = ScreenReportType.Full; screenReportType = ScreenReportType.Full;
this.screenReportFullType = screenReportFullType; this.screenReportFullType |= screenReportFullType;
} }
public void Clip(ScreenClipInfo screenClipInfo) public void Clip(ScreenClipInfo screenClipInfo)
{ {
@@ -84,7 +92,7 @@ namespace cmonitor.server.client.reports.screen
try try
{ {
long start = DateTime.UtcNow.Ticks; long start = DateTime.UtcNow.Ticks;
await SendScreenCapture(); await ScreenCapture();
delayms = (int)((DateTime.UtcNow.Ticks - start) / TimeSpan.TicksPerMillisecond); delayms = (int)((DateTime.UtcNow.Ticks - start) / TimeSpan.TicksPerMillisecond);
} }
catch (Exception ex) catch (Exception ex)
@@ -104,9 +112,17 @@ namespace cmonitor.server.client.reports.screen
} }
}, TaskCreationOptions.LongRunning); }, TaskCreationOptions.LongRunning);
} }
private async Task SendScreenCapture()
private Memory<byte> fullImageMemory = Helper.EmptyArray;
private async Task ScreenCapture()
{
DesktopFrame frame = GetFrame();
await SendFrame(frame);
}
private DesktopFrame GetFrame()
{ {
DesktopFrame frame = null; DesktopFrame frame = null;
long ticks = DateTime.UtcNow.Ticks; long ticks = DateTime.UtcNow.Ticks;
if (gdiDesktop.IsClip()) if (gdiDesktop.IsClip())
{ {
@@ -114,7 +130,20 @@ namespace cmonitor.server.client.reports.screen
} }
else if (screenReportType == ScreenReportType.Full) else if (screenReportType == ScreenReportType.Full)
{ {
frame = dxgiDesktop.GetLatestFullFrame(screenReportFullType, config.ScreenScale); frame = dxgiDesktop.GetLatestFullFrame(config.ScreenScale);
if (frame.FullImage.Length > 0)
{
fullImageMemory = frame.FullImage;
}
else if ((screenReportFullType & ScreenReportFullType.Full) == ScreenReportFullType.Full)
{
if (fullImageMemory.Length > 0)
{
frame.FullImage = fullImageMemory;
}
RandomCursorPos();
}
screenReportFullType &= ~ScreenReportFullType.Full;
} }
else if (screenReportType == ScreenReportType.Region) else if (screenReportType == ScreenReportType.Region)
{ {
@@ -122,52 +151,83 @@ namespace cmonitor.server.client.reports.screen
} }
report.CT = (uint)((DateTime.UtcNow.Ticks - ticks) / TimeSpan.TicksPerMillisecond); report.CT = (uint)((DateTime.UtcNow.Ticks - ticks) / TimeSpan.TicksPerMillisecond);
if (frame != null) return frame;
}
private async Task SendFrame(DesktopFrame frame)
{
if (frame == null)
{
return;
}
if (frame.FullImage.Length > 0)
{ {
if (frame.FullImage.Length > 0)
{
await messengerSender.SendOnly(new MessageRequestWrap
{
Connection = clientSignInState.Connection,
MessengerId = (ushort)ScreenMessengerIds.FullReport,
Payload = frame.FullImage,
});
}
else if (frame.RegionImage.Length > 0)
{
await messengerSender.SendOnly(new MessageRequestWrap
{
Connection = clientSignInState.Connection,
MessengerId = (ushort)ScreenMessengerIds.RegionReport,
Payload = frame.RegionImage,
});
}
await messengerSender.SendOnly(new MessageRequestWrap await messengerSender.SendOnly(new MessageRequestWrap
{ {
Connection = clientSignInState.Connection, Connection = clientSignInState.Connection,
MessengerId = (ushort)ScreenMessengerIds.Rectangles, MessengerId = (ushort)ScreenMessengerIds.FullReport,
Payload = MemoryPackSerializer.Serialize(frame.UpdatedRegions), Payload = frame.FullImage,
}); });
} }
else if (frame.RegionImage.Length > 0)
{
await messengerSender.SendOnly(new MessageRequestWrap
{
Connection = clientSignInState.Connection,
MessengerId = (ushort)ScreenMessengerIds.RegionReport,
Payload = frame.RegionImage,
});
}
await messengerSender.SendOnly(new MessageRequestWrap
{
Connection = clientSignInState.Connection,
MessengerId = (ushort)ScreenMessengerIds.Rectangles,
Payload = MemoryPackSerializer.Serialize(frame.UpdatedRegions),
});
} }
private void RandomCursorPos()
{
try
{
if (WinApi.GetCursorPosition(out int x, out int y))
{
x = x <= 0 ? x + 1 : x - 1;
y = y <= 0 ? y + 1 : y - 1;
SetCursorPos(x, y);
}
}
catch (Exception ex)
{
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
Logger.Instance.Error(ex);
}
}
}
[DllImport("user32.dll")]
private static extern bool SetCursorPos(int X, int Y);
} }
public sealed class ScreenReportInfo public sealed class ScreenReportInfo
{ {
public uint CT { get; set; } public uint CT { get; set; }
public uint LT { get; set; } public uint LT { get; set; }
public int W { get; set; }
public int H { get; set; }
} }
public enum ScreenReportType : byte public enum ScreenReportType : byte
{ {
Full = 0, Full = 1,
Region = 1 Region = 2
}; };
public enum ScreenReportFullType : byte public enum ScreenReportFullType : byte
{ {
Full = 0, Full = 1,
Trim = 1 Trim = 2
}; };
[MemoryPackable] [MemoryPackable]
@@ -175,7 +235,7 @@ namespace cmonitor.server.client.reports.screen
{ {
public int X { get; set; } public int X { get; set; }
public int Y { get; set; } public int Y { get; set; }
public float Scale { get; set; } public int W { get; set; }
public int H { get; set; }
} }
} }

View File

@@ -42,6 +42,22 @@ namespace cmonitor.server.client.reports.screen
} }
} }
} }
public static bool GetCursorPosition(out int x, out int y)
{
x = 0;
y = 0;
CURSORINFO pci;
pci.cbSize = Marshal.SizeOf(typeof(CURSORINFO));
bool res = GetCursorInfo(out pci);
if (res)
{
x = pci.ptScreenPos.x;
y = pci.ptScreenPos.y;
}
return res;
}
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
private struct CURSORINFO private struct CURSORINFO

View File

@@ -14,10 +14,10 @@ namespace cmonitor.server.client.reports.llock
{ {
if (config.IsCLient) if (config.IsCLient)
{ {
UnLockUsb(); //UnLockUsb();
report.Value = GetHasUSBDisabled(); report.Value = GetHasUSBDisabled();
AppDomain.CurrentDomain.ProcessExit += (s, e) => UnLockUsb(); //AppDomain.CurrentDomain.ProcessExit += (s, e) => UnLockUsb();
Console.CancelKeyPress += (s, e) => UnLockUsb(); //Console.CancelKeyPress += (s, e) => UnLockUsb();
} }
} }

View File

@@ -11,10 +11,15 @@ namespace cmonitor.server.client.reports.llock
private bool lastValue; private bool lastValue;
private readonly Config config; private readonly Config config;
private readonly ShareReport shareReport; private readonly ShareReport shareReport;
public WallpaperReport(Config config, ShareReport shareReport) private readonly ClientConfig clientConfig;
public WallpaperReport(Config config, ShareReport shareReport, ClientConfig clientConfig)
{ {
this.config = config; this.config = config;
this.shareReport = shareReport; this.shareReport = shareReport;
this.clientConfig = clientConfig;
Update(clientConfig.Wallpaper, clientConfig.WallpaperUrl);
} }
DateTime startTime = new DateTime(1970, 1, 1); DateTime startTime = new DateTime(1970, 1, 1);
@@ -34,6 +39,8 @@ namespace cmonitor.server.client.reports.llock
public void Update(bool open, string url) public void Update(bool open, string url)
{ {
clientConfig.Wallpaper = open;
clientConfig.WallpaperUrl = url;
Task.Run(() => Task.Run(() =>
{ {
CommandHelper.Windows(string.Empty, new string[] { "taskkill /f /t /im \"wallpaper.win.exe\"" }); CommandHelper.Windows(string.Empty, new string[] { "taskkill /f /t /im \"wallpaper.win.exe\"" });

View File

@@ -1,63 +1,22 @@
using cmonitor.hijack; using cmonitor.server.client.reports.hijack;
using MemoryPack; using MemoryPack;
namespace cmonitor.server.service.messengers.hijack namespace cmonitor.server.service.messengers.hijack
{ {
public sealed class HijackMessenger : IMessenger public sealed class HijackMessenger : IMessenger
{ {
private readonly HijackConfig hijackConfig; private readonly HijackReport hijackReport;
private readonly HijackController hijackController;
public HijackMessenger(HijackConfig hijackConfig, HijackController hijackController) public HijackMessenger(HijackReport hijackReport)
{ {
this.hijackConfig = hijackConfig; this.hijackReport = hijackReport;
this.hijackController = hijackController;
} }
[MessengerId((ushort)HijackMessengerIds.Update)] [MessengerId((ushort)HijackMessengerIds.Update)]
public void Update(IConnection connection) public void Update(IConnection connection)
{ {
SetRuleInfo info = MemoryPackSerializer.Deserialize<SetRuleInfo>(connection.ReceiveRequestWrap.Payload.Span); SetRuleInfo info = MemoryPackSerializer.Deserialize<SetRuleInfo>(connection.ReceiveRequestWrap.Payload.Span);
hijackReport.Update(info);
hijackConfig.AllowDomains = info.AllowDomains;
hijackConfig.DeniedDomains = info.DeniedDomains;
hijackConfig.AllowProcesss = info.AllowProcesss;
hijackConfig.DeniedProcesss = info.DeniedProcesss;
hijackConfig.AllowIPs = info.AllowIPs;
hijackConfig.DeniedIPs = info.DeniedIPs;
hijackController.SetRules();
} }
}
[MemoryPackable]
public sealed partial class SetRuleInfo
{
/// <summary>
/// 进程白名单
/// </summary>
public string[] AllowProcesss { get; set; } = Array.Empty<string>();
/// <summary>
/// 进程黑名单
/// </summary>
public string[] DeniedProcesss { get; set; } = Array.Empty<string>();
/// <summary>
/// 域名白名单
/// </summary>
public string[] AllowDomains { get; set; } = Array.Empty<string>();
/// <summary>
/// 域名黑名单
/// </summary>
public string[] DeniedDomains { get; set; } = Array.Empty<string>();
/// <summary>
/// ip白名单
/// </summary>
public string[] AllowIPs { get; set; } = Array.Empty<string>();
/// <summary>
/// ip黑名单
/// </summary>
public string[] DeniedIPs { get; set; } = Array.Empty<string>();
} }
} }

View File

@@ -1,4 +1,5 @@
using cmonitor.server.api; using cmonitor.server.api;
using cmonitor.server.client.reports;
using cmonitor.server.client.reports.screen; using cmonitor.server.client.reports.screen;
using cmonitor.server.service.messengers.sign; using cmonitor.server.service.messengers.sign;
using MemoryPack; using MemoryPack;
@@ -23,12 +24,12 @@ namespace cmonitor.server.service.messengers.screen
[MessengerId((ushort)ScreenMessengerIds.Full)] [MessengerId((ushort)ScreenMessengerIds.Full)]
public void Full(IConnection connection) public void Full(IConnection connection)
{ {
ScreenReportFullType screenReportFullType = ScreenReportFullType.Trim; ScreenReportFullType reportType = ScreenReportFullType.Trim;
if(connection.ReceiveRequestWrap.Payload.Length > 0) if (connection.ReceiveRequestWrap.Payload.Length > 0)
{ {
screenReportFullType = (ScreenReportFullType)connection.ReceiveRequestWrap.Payload.Span[0]; reportType = (ScreenReportFullType)connection.ReceiveRequestWrap.Payload.Span[0];
} }
screenReport.Full(screenReportFullType); screenReport.Full(reportType);
} }
[MessengerId((ushort)ScreenMessengerIds.FullReport)] [MessengerId((ushort)ScreenMessengerIds.FullReport)]
public void FullReport(IConnection connection) public void FullReport(IConnection connection)

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=0"><link rel="icon" href="/favicon.ico"><title>cmonitor.web</title><script defer="defer" src="/js/chunk-vendors.9b0dc62c.js"></script><script defer="defer" src="/js/app.eda51872.js"></script><link href="/css/chunk-vendors.faad7142.css" rel="stylesheet"><link href="/css/app.9c6b579f.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but cmonitor.web doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html> <!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=0"><link rel="icon" href="/favicon.ico"><title>cmonitor.web</title><script defer="defer" src="/js/chunk-vendors.9b0dc62c.js"></script><script defer="defer" src="/js/app.ee33a46f.js"></script><link href="/css/chunk-vendors.faad7142.css" rel="stylesheet"><link href="/css/app.9c6b579f.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but cmonitor.web doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long