Skip to content

Commit 1c57bed

Browse files
committed
Add console sampler sample
1 parent f9c2bf5 commit 1c57bed

8 files changed

Lines changed: 110 additions & 9 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44

55
- Prepare the first public NuGet package for `Ph0rd.ColorSampler`.
66
- Add complete package metadata, README packaging, license metadata, and package icon.
7-
- Add WPF, WinForms, and WinUI 3 samples.
7+
- Add console, WPF, WinForms, and WinUI 3 samples.
88
- Document the render-thread event contract and Windows-only implementation requirements.
99
- Hide the normal, I-beam, and hand system cursors during sampling, then restore Windows defaults on stop, dispose, or process exit.

‎ColorSampler.sln‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColorSampler", "src\ColorSa
99
EndProject
1010
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{5D20AA90-6969-D8BD-9DCD-8634F4692FDA}"
1111
EndProject
12+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColorSampler.ConsoleSample", "samples\ColorSampler.ConsoleSample\ColorSampler.ConsoleSample.csproj", "{D929E416-18E2-495D-8E54-3D5E176D5726}"
13+
EndProject
1214
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColorSampler.WpfSample", "samples\ColorSampler.WpfSample\ColorSampler.WpfSample.csproj", "{688CC018-38D6-4259-88E8-B340E7B533A8}"
1315
EndProject
1416
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColorSampler.WinFormsSample", "samples\ColorSampler.WinFormsSample\ColorSampler.WinFormsSample.csproj", "{A094AE0B-4F73-4E83-B605-46F88963A7F4}"
@@ -37,6 +39,18 @@ Global
3739
{582E16AB-470E-496C-AFA0-3B9BEA06917D}.Release|x64.Build.0 = Release|Any CPU
3840
{582E16AB-470E-496C-AFA0-3B9BEA06917D}.Release|x86.ActiveCfg = Release|Any CPU
3941
{582E16AB-470E-496C-AFA0-3B9BEA06917D}.Release|x86.Build.0 = Release|Any CPU
42+
{D929E416-18E2-495D-8E54-3D5E176D5726}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
43+
{D929E416-18E2-495D-8E54-3D5E176D5726}.Debug|Any CPU.Build.0 = Debug|Any CPU
44+
{D929E416-18E2-495D-8E54-3D5E176D5726}.Debug|x64.ActiveCfg = Debug|Any CPU
45+
{D929E416-18E2-495D-8E54-3D5E176D5726}.Debug|x64.Build.0 = Debug|Any CPU
46+
{D929E416-18E2-495D-8E54-3D5E176D5726}.Debug|x86.ActiveCfg = Debug|Any CPU
47+
{D929E416-18E2-495D-8E54-3D5E176D5726}.Debug|x86.Build.0 = Debug|Any CPU
48+
{D929E416-18E2-495D-8E54-3D5E176D5726}.Release|Any CPU.ActiveCfg = Release|Any CPU
49+
{D929E416-18E2-495D-8E54-3D5E176D5726}.Release|Any CPU.Build.0 = Release|Any CPU
50+
{D929E416-18E2-495D-8E54-3D5E176D5726}.Release|x64.ActiveCfg = Release|Any CPU
51+
{D929E416-18E2-495D-8E54-3D5E176D5726}.Release|x64.Build.0 = Release|Any CPU
52+
{D929E416-18E2-495D-8E54-3D5E176D5726}.Release|x86.ActiveCfg = Release|Any CPU
53+
{D929E416-18E2-495D-8E54-3D5E176D5726}.Release|x86.Build.0 = Release|Any CPU
4054
{688CC018-38D6-4259-88E8-B340E7B533A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
4155
{688CC018-38D6-4259-88E8-B340E7B533A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
4256
{688CC018-38D6-4259-88E8-B340E7B533A8}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -79,6 +93,7 @@ Global
7993
EndGlobalSection
8094
GlobalSection(NestedProjects) = preSolution
8195
{582E16AB-470E-496C-AFA0-3B9BEA06917D} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
96+
{D929E416-18E2-495D-8E54-3D5E176D5726} = {5D20AA90-6969-D8BD-9DCD-8634F4692FDA}
8297
{688CC018-38D6-4259-88E8-B340E7B533A8} = {5D20AA90-6969-D8BD-9DCD-8634F4692FDA}
8398
{A094AE0B-4F73-4E83-B605-46F88963A7F4} = {5D20AA90-6969-D8BD-9DCD-8634F4692FDA}
8499
{24288966-857E-4D2A-B655-E57D958BCFA8} = {5D20AA90-6969-D8BD-9DCD-8634F4692FDA}

‎ColorSampler.slnx‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<Solution>
22
<Project Path="src/ColorSampler/ColorSampler.csproj" />
3+
<Project Path="samples/ColorSampler.ConsoleSample/ColorSampler.ConsoleSample.csproj" />
34
<Project Path="samples/ColorSampler.WpfSample/ColorSampler.WpfSample.csproj" />
45
<Project Path="samples/ColorSampler.WinFormsSample/ColorSampler.WinFormsSample.csproj" />
56
<Project Path="samples/ColorSampler.WinUISample/ColorSampler.WinUISample.csproj" />

‎README.md‎

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Ph0rd.ColorSampler
22

3-
`Ph0rd.ColorSampler` is a performant Windows desktop eyedropper for .NET apps (WinUI 3, WPF, WinForms).
3+
`Ph0rd.ColorSampler` is a performant Windows desktop eyedropper for .NET apps (WinUI 3, WPF, WinForms, console).
44
It shows a click-through crosshair, a zoomed pixel preview, and raises simple events as the sampled color changes, is confirmed, or is cancelled.
55

66
It is the color sampling component used by [Instant Syntax Styler](https://www.ph0rd.com/instant-syntax-styler/), the Visual Studio 2026 extension for changing syntax
@@ -80,22 +80,28 @@ Supported target frameworks:
8080

8181
Expected limitations:
8282

83-
- It is not for web, service, console-only, macOS, or Linux apps.
83+
- It is not for web, service, macOS, or Linux apps.
84+
- Console apps are supported when they run in an interactive Windows desktop session.
8485
- Security tools, RDP sessions, UAC prompts, lock screens, or secure desktops may block or interrupt sampling.
8586
- The sampler captures normal desktop pixels. It is not designed to bypass protected content.
8687

8788
## Samples
8889

89-
The repository includes three small samples:
90+
The repository includes four small samples:
9091

9192
```powershell
93+
dotnet run --project samples/ColorSampler.ConsoleSample/ColorSampler.ConsoleSample.csproj
9294
dotnet run --project samples/ColorSampler.WpfSample/ColorSampler.WpfSample.csproj
9395
dotnet run --project samples/ColorSampler.WinFormsSample/ColorSampler.WinFormsSample.csproj
9496
dotnet run --project samples/ColorSampler.WinUISample/ColorSampler.WinUISample.csproj
9597
```
9698

97-
Each sample shows the same pattern: create a `Sampler`, subscribe to `ColorChanged`, `Confirmed`, and `Cancelled`,
98-
marshal back to the UI thread, and dispose the sampler when finished.
99+
The console sample is intentionally script-friendly: it launches sampling immediately, writes the confirmed
100+
color to stdout as `#RRGGBB`, returns exit code `0` when a color is selected, returns `1` when cancelled,
101+
and returns `2` for unexpected sampler errors.
102+
103+
The GUI samples show the same UI pattern: create a `Sampler`, subscribe to `ColorChanged`, `Confirmed`,
104+
and `Cancelled`, marshal back to the UI thread, and dispose the sampler when finished.
99105

100106
## Build
101107

‎docs/COLORSAMPLER_PUBLIC_RELEASE_PLAN.md‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Goal
44

5-
Prepare `Ph0rd.ColorSampler` as a clean public GitHub repository and NuGet package. The repository should be understandable to a stranger, build from a clean clone, pack into a professional NuGet package, and include small WPF, WinForms, and WinUI 3 samples.
5+
Prepare `Ph0rd.ColorSampler` as a clean public GitHub repository and NuGet package. The repository should be understandable to a stranger, build from a clean clone, pack into a professional NuGet package, and include small console, WPF, WinForms, and WinUI 3 samples.
66

77
## Ground Rules
88

@@ -41,6 +41,7 @@ Prepare `Ph0rd.ColorSampler` as a clean public GitHub repository and NuGet packa
4141
- Document the render-thread event contract.
4242

4343
3. Samples
44+
- Console sample: immediate launch, one-line stdout output, and clear exit codes.
4445
- WPF sample: simple dispatcher-marshaled UI.
4546
- WinForms sample: simple `BeginInvoke` marshaling UI.
4647
- WinUI 3 sample: simple `DispatcherQueue` marshaling UI.
@@ -63,7 +64,7 @@ Prepare `Ph0rd.ColorSampler` as a clean public GitHub repository and NuGet packa
6364
- A pretty sample is worse than a tiny sample if it hides threading behavior.
6465
- The sampler owns a global mouse hook. Public docs must say concurrent sampling sessions are not supported.
6566
- The events fire off the UI thread. Every sample must demonstrate marshaling.
66-
- Do not add console, web, MAUI, Avalonia, or VS extension samples right now. They distract from the package.
67+
- Do not add web, MAUI, Avalonia, or VS extension samples right now. They distract from the package.
6768
- Do not claim macOS/Linux/browser support.
6869
- Publish only after maintainer review of the generated package and samples.
6970

@@ -75,6 +76,7 @@ Prepare `Ph0rd.ColorSampler` as a clean public GitHub repository and NuGet packa
7576
- [x] README written for GitHub and NuGet.
7677
- [x] License and changelog added.
7778
- [x] Package icon added.
79+
- [x] Console sample added.
7880
- [x] WPF sample updated.
7981
- [x] WinForms sample added.
8082
- [x] WinUI 3 sample added.

‎docs/RELEASE_CHECKLIST.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ This repository is prepared for public release, but publishing must remain a del
2828
- `lib/net48/Ph0rd.ColorSampler.dll`
2929
- `lib/net8.0-windows7.0/Ph0rd.ColorSampler.dll`
3030

31-
7. Run at least the WPF and WinForms samples locally.
31+
7. Run the console, WPF, and WinForms samples locally.
3232
8. Run the WinUI 3 sample locally if Windows App SDK tooling is installed.
3333

3434
## Publish
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net8.0-windows</TargetFramework>
6+
<UseWPF>true</UseWPF>
7+
<LangVersion>12</LangVersion>
8+
<Nullable>enable</Nullable>
9+
<RootNamespace>Ph0rd.ColorSampler.ConsoleSample</RootNamespace>
10+
<AssemblyName>Ph0rd.ColorSampler.ConsoleSample</AssemblyName>
11+
</PropertyGroup>
12+
13+
<ItemGroup>
14+
<ProjectReference Include="..\..\src\ColorSampler\ColorSampler.csproj" />
15+
</ItemGroup>
16+
17+
</Project>
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using Ph0rd.ColorSampler;
2+
3+
using System;
4+
using System.Threading;
5+
6+
var completed = new ManualResetEventSlim(false);
7+
var exitCode = 1;
8+
string? selectedColor = null;
9+
Exception? samplerError = null;
10+
11+
using var sampler = new Sampler(onError: ex =>
12+
{
13+
samplerError = ex;
14+
exitCode = 2;
15+
completed.Set();
16+
});
17+
18+
sampler.Confirmed += color =>
19+
{
20+
selectedColor = $"#{color.R:X2}{color.G:X2}{color.B:X2}";
21+
exitCode = 0;
22+
completed.Set();
23+
};
24+
25+
sampler.Cancelled += () =>
26+
{
27+
if (samplerError == null)
28+
exitCode = 1;
29+
30+
completed.Set();
31+
};
32+
33+
Console.CancelKeyPress += (_, e) =>
34+
{
35+
e.Cancel = true;
36+
sampler.Stop();
37+
};
38+
39+
try
40+
{
41+
sampler.Start();
42+
completed.Wait();
43+
}
44+
catch (Exception ex)
45+
{
46+
Console.Error.WriteLine(ex);
47+
return 2;
48+
}
49+
finally
50+
{
51+
sampler.Stop();
52+
}
53+
54+
if (samplerError != null)
55+
Console.Error.WriteLine(samplerError);
56+
57+
if (exitCode == 0 && selectedColor != null)
58+
Console.WriteLine(selectedColor);
59+
60+
return exitCode;

0 commit comments

Comments
 (0)