Add archived Siemens software
This commit is contained in:
+24
-1
@@ -80,6 +80,9 @@ public static class ScreenshotWindowApi {
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool PostMessage(IntPtr hWnd, uint message, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool PrintWindow(IntPtr hWnd, IntPtr hdc, uint flags);
|
||||
|
||||
}
|
||||
"@
|
||||
|
||||
@@ -434,7 +437,27 @@ try {
|
||||
|
||||
$screenshotPath = Join-Path $OutputDirectory "$Name.png"
|
||||
$borderInset = 2
|
||||
if ($ScreenshotTool.Length -gt 0 -and (Test-Path -LiteralPath $ScreenshotTool)) {
|
||||
if ($ScreenshotTool -eq "printwindow") {
|
||||
$bitmap = [System.Drawing.Bitmap]::new($window.Width, $window.Height, [System.Drawing.Imaging.PixelFormat]::Format32bppArgb)
|
||||
try {
|
||||
$graphics = [System.Drawing.Graphics]::FromImage($bitmap)
|
||||
$deviceContext = $graphics.GetHdc()
|
||||
try {
|
||||
if (-not [ScreenshotWindowApi]::PrintWindow($window.Handle, $deviceContext, 2)) {
|
||||
throw "PrintWindow failed for window '$($window.Title)'."
|
||||
}
|
||||
}
|
||||
finally {
|
||||
$graphics.ReleaseHdc($deviceContext)
|
||||
$graphics.Dispose()
|
||||
}
|
||||
$bitmap.Save($screenshotPath, [System.Drawing.Imaging.ImageFormat]::Png)
|
||||
}
|
||||
finally {
|
||||
$bitmap.Dispose()
|
||||
}
|
||||
}
|
||||
elseif ($ScreenshotTool.Length -gt 0 -and (Test-Path -LiteralPath $ScreenshotTool)) {
|
||||
$screenshotToolName = [System.IO.Path]::GetFileName($ScreenshotTool)
|
||||
if ($screenshotToolName -ieq "winapp.exe") {
|
||||
$winappExitCode = 1
|
||||
|
||||
@@ -38,6 +38,9 @@ function Get-CandidateScore {
|
||||
if ($stem -eq $slugName) {
|
||||
$score += 100
|
||||
}
|
||||
if ($ProgramSlug -eq "qpst" -and $File.BaseName -eq "QPSTConfig") {
|
||||
$score += 200
|
||||
}
|
||||
foreach ($token in ($ProgramSlug -split '[-_]')) {
|
||||
if ($token.Length -ge 3 -and $stem.Contains((Get-NormalizedName $token))) {
|
||||
$score += 15
|
||||
@@ -138,7 +141,15 @@ try {
|
||||
exit 1
|
||||
}
|
||||
$winapp = "C:\codex\winapp\winapp.exe"
|
||||
$screenshotTool = if (Test-Path -LiteralPath $winapp) {
|
||||
$builtInCapturePrograms = @("u10-u15-update-software")
|
||||
$printWindowCapturePrograms = @("jadmaker")
|
||||
$screenshotTool = if ($builtInCapturePrograms -contains $Slug) {
|
||||
""
|
||||
}
|
||||
elseif ($printWindowCapturePrograms -contains $Slug) {
|
||||
"printwindow"
|
||||
}
|
||||
elseif (Test-Path -LiteralPath $winapp) {
|
||||
$winapp
|
||||
}
|
||||
else {
|
||||
|
||||
+86
-16
@@ -55,7 +55,10 @@ type Options = {
|
||||
host: string;
|
||||
importDirectory?: string;
|
||||
limit?: number;
|
||||
program?: string;
|
||||
programs: Set<string>;
|
||||
sshConfig?: string;
|
||||
sshControl?: string;
|
||||
sshPort?: number;
|
||||
replace: boolean;
|
||||
waitSeconds: number;
|
||||
write: boolean;
|
||||
@@ -86,13 +89,16 @@ const initialKeys = new Map([
|
||||
"ENTER,TEXT=C:\\codex\\catalog-screenshots\\work\\brew-graphicpatch-creator\\brewrc.exe,ENTER",
|
||||
],
|
||||
["brew-apploader", "CLOSE-SMALL,CLOSE-SMALL"],
|
||||
["cl50-dinghy-downloader", "ENTER"],
|
||||
["efs-explorer-lite", "ENTER"],
|
||||
["flash-imager", "ENTER"],
|
||||
["flex-table-edit", "ENTER"],
|
||||
["gagin", "CLOSE-SMALL,CLOSE-SMALL"],
|
||||
["freia", "SELECT-TITLE=Engine"],
|
||||
["initmap", "CLOSE-LARGEST"],
|
||||
["mobilechat", "ALT+N"],
|
||||
["s65-key-definer", "ENTER"],
|
||||
["s80-user-download-tool", "ENTER"],
|
||||
["siemens-screenshot", "ENTER"],
|
||||
]);
|
||||
|
||||
@@ -102,8 +108,12 @@ function usage(): void {
|
||||
Capture one screenshot for each Windows program.
|
||||
|
||||
--host HOST Windows SSH host (default: win)
|
||||
--ssh-config PATH use an alternate OpenSSH configuration file
|
||||
--ssh-control PATH
|
||||
use an existing OpenSSH control socket
|
||||
--ssh-port PORT connect to a specific SSH port
|
||||
--import DIR import reviewed SLUG.png files without connecting to Windows
|
||||
--program SLUG process one program directory
|
||||
--program SLUG process a program directory; may be repeated
|
||||
--limit COUNT stop after COUNT programs
|
||||
--replace recapture only existing img/SLUG.png screenshots
|
||||
--wait SECONDS wait for a program window (default: 8)
|
||||
@@ -116,7 +126,10 @@ function parseArguments(args: string[]): Options {
|
||||
let host = "win";
|
||||
let importDirectory: string | undefined;
|
||||
let limit: number | undefined;
|
||||
let program: string | undefined;
|
||||
const programs = new Set<string>();
|
||||
let sshConfig: string | undefined;
|
||||
let sshControl: string | undefined;
|
||||
let sshPort: number | undefined;
|
||||
let replace = false;
|
||||
let waitSeconds = 8;
|
||||
let write = false;
|
||||
@@ -125,12 +138,18 @@ function parseArguments(args: string[]): Options {
|
||||
const argument = args[index];
|
||||
if (argument === "--host") {
|
||||
host = args[++index] ?? "";
|
||||
} else if (argument === "--ssh-config") {
|
||||
sshConfig = path.resolve(args[++index] ?? "");
|
||||
} else if (argument === "--ssh-control") {
|
||||
sshControl = path.resolve(args[++index] ?? "");
|
||||
} else if (argument === "--ssh-port") {
|
||||
sshPort = Number(args[++index]);
|
||||
} else if (argument === "--import") {
|
||||
importDirectory = path.resolve(args[++index] ?? "");
|
||||
} else if (argument === "--limit") {
|
||||
limit = Number(args[++index]);
|
||||
} else if (argument === "--program") {
|
||||
program = args[++index];
|
||||
programs.add(args[++index] ?? "");
|
||||
} else if (argument === "--replace") {
|
||||
replace = true;
|
||||
} else if (argument === "--wait") {
|
||||
@@ -159,19 +178,48 @@ function parseArguments(args: string[]): Options {
|
||||
if (!Number.isInteger(waitSeconds) || waitSeconds < 1 || waitSeconds > 60) {
|
||||
throw new Error("--wait must be an integer between 1 and 60");
|
||||
}
|
||||
if (programs.has("")) {
|
||||
throw new Error("--program must not be empty");
|
||||
}
|
||||
if (sshPort !== undefined && (!Number.isInteger(sshPort) || sshPort < 1 || sshPort > 65535)) {
|
||||
throw new Error("--ssh-port must be an integer between 1 and 65535");
|
||||
}
|
||||
|
||||
return {
|
||||
catalogDirectory: path.resolve(targets[0] ?? "catalog"),
|
||||
host,
|
||||
importDirectory,
|
||||
limit,
|
||||
program,
|
||||
programs,
|
||||
sshConfig,
|
||||
sshControl,
|
||||
sshPort,
|
||||
replace,
|
||||
waitSeconds,
|
||||
write,
|
||||
};
|
||||
}
|
||||
|
||||
function sshArguments(options: Options, remoteCommand: string): string[] {
|
||||
return [
|
||||
...(options.sshConfig !== undefined ? ["-F", options.sshConfig] : []),
|
||||
...(options.sshControl !== undefined ? ["-S", options.sshControl] : []),
|
||||
...(options.sshPort !== undefined ? ["-p", String(options.sshPort)] : []),
|
||||
options.host,
|
||||
remoteCommand,
|
||||
];
|
||||
}
|
||||
|
||||
function scpArguments(options: Options, sources: string[], destination: string): string[] {
|
||||
return [
|
||||
...(options.sshConfig !== undefined ? ["-F", options.sshConfig] : []),
|
||||
...(options.sshControl !== undefined ? ["-o", `ControlPath=${options.sshControl}`] : []),
|
||||
...(options.sshPort !== undefined ? ["-P", String(options.sshPort)] : []),
|
||||
...sources,
|
||||
destination,
|
||||
];
|
||||
}
|
||||
|
||||
async function run(command: string, args: string[], allowFailure = false): Promise<string> {
|
||||
return await new Promise((resolve, reject) => {
|
||||
const child = spawn(command, args, { stdio: ["ignore", "pipe", "pipe"] });
|
||||
@@ -239,7 +287,7 @@ async function collectPrograms(options: Options): Promise<{ programs: Program[];
|
||||
if (programsWithoutStandaloneGui.has(slug)) {
|
||||
continue;
|
||||
}
|
||||
if (options.program !== undefined && slug !== options.program) {
|
||||
if (options.programs.size > 0 && !options.programs.has(slug)) {
|
||||
continue;
|
||||
}
|
||||
if (typeof metadata.name !== "string" || metadata.name.length === 0) {
|
||||
@@ -308,18 +356,30 @@ function failureReason(result: RemoteResult, program: Program): { reason: string
|
||||
if (failedTitle !== undefined) {
|
||||
return { reason: "Error window", details: failedTitle };
|
||||
}
|
||||
const setupTitle = program.slug === "java-midlet-installer" ? undefined : titles.find((title) => installerTitle.test(title));
|
||||
const programsWithSetupInMainWindowTitle = new Set([
|
||||
"ifwd-flashtool-e2",
|
||||
"java-midlet-installer",
|
||||
"kp500-flashing-tool",
|
||||
]);
|
||||
const setupTitle = programsWithSetupInMainWindowTitle.has(program.slug)
|
||||
? undefined
|
||||
: titles.find((title) => installerTitle.test(title));
|
||||
if (setupTitle !== undefined) {
|
||||
return { reason: "Installer opened", details: setupTitle };
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async function addScreenshot(program: Program, screenshotPath: string, replace: boolean): Promise<void> {
|
||||
async function addScreenshot(
|
||||
options: Options,
|
||||
program: Program,
|
||||
screenshotPath: string,
|
||||
replace: boolean,
|
||||
): Promise<void> {
|
||||
const imageDirectory = path.join(program.directory, "img");
|
||||
const imagePath = path.join(imageDirectory, `${program.slug}.png`);
|
||||
await mkdir(imageDirectory, { recursive: true });
|
||||
await run("scp", [`${screenshotPath}`, imagePath]);
|
||||
await run("scp", scpArguments(options, [screenshotPath], imagePath));
|
||||
|
||||
if (replace) {
|
||||
return;
|
||||
@@ -380,18 +440,23 @@ async function main(): Promise<void> {
|
||||
}
|
||||
let captured = 0;
|
||||
const tools = ["screenshotApp.ps1", "runScreenshotTask.ps1", "screenshotArchive.ps1"];
|
||||
await run("ssh", [
|
||||
options.host,
|
||||
await run("ssh", sshArguments(options,
|
||||
`powershell -NoProfile -Command "New-Item -ItemType Directory -Force -Path '${remoteRoot}\\input','${remoteRoot}\\results' | Out-Null"`,
|
||||
]);
|
||||
await run("scp", tools.map((file) => path.resolve("tools", file)).concat(`${options.host}:${remoteScpRoot}/`));
|
||||
));
|
||||
await run(
|
||||
"scp",
|
||||
scpArguments(options, tools.map((file) => path.resolve("tools", file)), `${options.host}:${remoteScpRoot}/`),
|
||||
);
|
||||
|
||||
console.log(`Programs to process: ${programs.length}`);
|
||||
for (const [index, program] of programs.entries()) {
|
||||
const prefix = `[${index + 1}/${programs.length}] ${program.name}`;
|
||||
const remoteArchive = `${remoteRoot}\\input\\${program.slug}.zip`;
|
||||
try {
|
||||
await run("scp", [program.archive, `${options.host}:${remoteScpRoot}/input/${program.slug}.zip`]);
|
||||
await run(
|
||||
"scp",
|
||||
scpArguments(options, [program.archive], `${options.host}:${remoteScpRoot}/input/${program.slug}.zip`),
|
||||
);
|
||||
const remoteCommand = [
|
||||
"powershell",
|
||||
"-NoProfile",
|
||||
@@ -403,7 +468,7 @@ async function main(): Promise<void> {
|
||||
`-WaitSeconds ${options.waitSeconds}`,
|
||||
...(initialKeys.has(program.slug) ? [`-InitialKeys ${initialKeys.get(program.slug)}`] : []),
|
||||
].join(" ");
|
||||
const output = await run("ssh", [options.host, remoteCommand], true);
|
||||
const output = await run("ssh", sshArguments(options, remoteCommand), true);
|
||||
const result = parseRemoteResult(output);
|
||||
const failure = failureReason(result, program);
|
||||
if (failure !== undefined) {
|
||||
@@ -417,7 +482,12 @@ async function main(): Promise<void> {
|
||||
}
|
||||
|
||||
if (options.write) {
|
||||
await addScreenshot(program, `${options.host}:${remoteScpRoot}/results/${program.slug}.png`, options.replace);
|
||||
await addScreenshot(
|
||||
options,
|
||||
program,
|
||||
`${options.host}:${remoteScpRoot}/results/${program.slug}.png`,
|
||||
options.replace,
|
||||
);
|
||||
}
|
||||
captured += 1;
|
||||
console.log(`${prefix}: ${options.write ? "saved" : "captured"} (${result.title ?? result.selected ?? "window"})`);
|
||||
|
||||
Reference in New Issue
Block a user