├── .gitignore
├── Images
├── HexInspector.dark.png
├── HexInspector.light.png
└── examples
│ ├── ep1.png
│ └── ep2.png
├── LICENSE
├── PowerHexInspector.csproj
├── PowerHexInspector.sln
├── README.md
├── README_ZH-CN.md
├── plugin.json
└── src
├── ConvertHelper.cs
├── Enum.cs
├── HexInspector.cs
├── QueryInterpretHelper.cs
├── SettingsHelper.cs
└── Utils.cs
/.gitignore:
--------------------------------------------------------------------------------
1 | obj/
2 | bin/
3 |
4 | .vs/
5 | .vscode/
--------------------------------------------------------------------------------
/Images/HexInspector.dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NaroZeol/PowerHexInspector/6342aa27d970fe9288f2dc79524b9d43220c4f97/Images/HexInspector.dark.png
--------------------------------------------------------------------------------
/Images/HexInspector.light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NaroZeol/PowerHexInspector/6342aa27d970fe9288f2dc79524b9d43220c4f97/Images/HexInspector.light.png
--------------------------------------------------------------------------------
/Images/examples/ep1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NaroZeol/PowerHexInspector/6342aa27d970fe9288f2dc79524b9d43220c4f97/Images/examples/ep1.png
--------------------------------------------------------------------------------
/Images/examples/ep2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NaroZeol/PowerHexInspector/6342aa27d970fe9288f2dc79524b9d43220c4f97/Images/examples/ep2.png
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 NaroZeol
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/PowerHexInspector.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0-windows10.0.22621.0
5 | enable
6 | true
7 | false
8 | false
9 | Community.PowerToys.Run.Plugin.HexInspector
10 | ARM64;x64
11 | 0.4.0
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/PowerHexInspector.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.5.002.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerHexInspector", "PowerHexInspector.csproj", "{2105FA8A-5A2E-4D99-B0C8-20D96C9470D8}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Debug|ARM64 = Debug|ARM64
12 | Debug|x64 = Debug|x64
13 | Release|Any CPU = Release|Any CPU
14 | Release|ARM64 = Release|ARM64
15 | Release|x64 = Release|x64
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {2105FA8A-5A2E-4D99-B0C8-20D96C9470D8}.Debug|Any CPU.ActiveCfg = Debug|x86
19 | {2105FA8A-5A2E-4D99-B0C8-20D96C9470D8}.Debug|Any CPU.Build.0 = Debug|x86
20 | {2105FA8A-5A2E-4D99-B0C8-20D96C9470D8}.Debug|ARM64.ActiveCfg = Debug|ARM64
21 | {2105FA8A-5A2E-4D99-B0C8-20D96C9470D8}.Debug|ARM64.Build.0 = Debug|ARM64
22 | {2105FA8A-5A2E-4D99-B0C8-20D96C9470D8}.Debug|x64.ActiveCfg = Debug|x64
23 | {2105FA8A-5A2E-4D99-B0C8-20D96C9470D8}.Debug|x64.Build.0 = Debug|x64
24 | {2105FA8A-5A2E-4D99-B0C8-20D96C9470D8}.Release|Any CPU.ActiveCfg = Release|x86
25 | {2105FA8A-5A2E-4D99-B0C8-20D96C9470D8}.Release|Any CPU.Build.0 = Release|x86
26 | {2105FA8A-5A2E-4D99-B0C8-20D96C9470D8}.Release|ARM64.ActiveCfg = Release|ARM64
27 | {2105FA8A-5A2E-4D99-B0C8-20D96C9470D8}.Release|ARM64.Build.0 = Release|ARM64
28 | {2105FA8A-5A2E-4D99-B0C8-20D96C9470D8}.Release|x64.ActiveCfg = Release|x64
29 | {2105FA8A-5A2E-4D99-B0C8-20D96C9470D8}.Release|x64.Build.0 = Release|x64
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | GlobalSection(ExtensibilityGlobals) = postSolution
35 | SolutionGuid = {8715CEB1-CC4E-4B3C-8621-C7323C31B77A}
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PowerHexInspector
2 |
3 | [](https://github.com/hlaueriksson/awesome-powertoys-run-plugins)
4 | [](https://github.com/hlaueriksson/awesome-powertoys-run-plugins)
5 |
6 | A simple [PowerToys Run](https://learn.microsoft.com/en-us/windows/powertoys/run) plugin.
7 |
8 | Provides functionality to convert numbers to different bases.
9 |
10 | [简体中文](./README_ZH-CN.md)
11 |
12 | ## Usage
13 |
14 | ### Trigger Keyword
15 |
16 | The current trigger keyword is `insp`.
17 |
18 | ### Input Format
19 |
20 | The input format is:
21 |
22 | insp {base} {input}
23 |
24 | The base can be one of the following values:
25 |
26 | - `b` or `B`: Binary
27 | - `o` or `O`: Octal
28 | - `d` or `D`: Decimal
29 | - `h` or `H`: Hexadecimal
30 | - `a` or `A`: ASCII
31 |
32 | Or use
33 |
34 | insp {input}
35 |
36 | In this case, the input should be a string that follows the rules below:
37 |
38 | - A string starting with `0x` will be considered hexadecimal
39 | - A string starting with `0b` will be considered binary
40 | - A string starting with `0` will be considered octal
41 | - A string surrounded by double quotes will be considered ASCII
42 | - Otherwise, it will be considered decimal
43 |
44 | ### Example
45 |
46 | 
47 |
48 | 
49 |
50 | Clicking or pressing `Enter` will copy the conversion result to the clipboard.
51 |
52 | ## Installation
53 | Download the latest release, extract it, and place the `PowerHexInspector` folder into the `%LOCALAPPDATA%\Microsoft\PowerToys\PowerToys Run\Plugins` directory. Then, restart PowerToys.
--------------------------------------------------------------------------------
/README_ZH-CN.md:
--------------------------------------------------------------------------------
1 | # PowerHexInspector
2 |
3 | [](https://github.com/hlaueriksson/awesome-powertoys-run-plugins)
4 | [](https://github.com/hlaueriksson/awesome-powertoys-run-plugins)
5 |
6 | 一个简单的[powertoys run](https://learn.microsoft.com/en-us/windows/powertoys/run)插件。
7 |
8 | 提供将数字转化为其他进制的功能。
9 |
10 | [English Doc](./README_EN.md)
11 |
12 | ## 使用方法
13 |
14 | ### 触发关键词
15 |
16 | 当前触发关键词为`insp`。
17 |
18 | ### 输入格式
19 |
20 | 输入格式为
21 |
22 | insp {输入进制} {输入}
23 |
24 | 输入进制为以下的值之一
25 |
26 | - `b`或`B`:二进制
27 | - `o`或`O`:八进制
28 | - `d`或`D`:十进制
29 | - `h`或`H`:十六进制
30 | - `a`或`A`:ASCII码
31 |
32 | 或者使用
33 |
34 | insp {输入}
35 |
36 | 此时输入应为一个符合以下规则的字符串
37 |
38 | - 以`0x`开头的字符串会被认为是十六进制
39 | - 以`0b`开头的字符串会被认为是二进制
40 | - 以`0`开头的字符串会被认为是八进制
41 | - 用双引号括起来的字符串会被认为是ASCII码
42 | - 其他情况会被认为是十进制
43 |
44 |
45 | ### 使用演示
46 |
47 | 
48 |
49 | 
50 |
51 | 点击或按下`Enter`会将转换结果复制到剪贴板中。
52 |
53 | ## 安装
54 | 下载最新的release,解压后将`PowerHexInspector`文件夹放入`%LOCALAPPDATA%\Microsoft\PowerToys\PowerToys Run\Plugins`文件夹中,然后重启powertoys即可。
--------------------------------------------------------------------------------
/plugin.json:
--------------------------------------------------------------------------------
1 | {
2 | "ID": "JSAKDJKALSJDIWDI1872Hdhad139319A",
3 | "ActionKeyword": "insp",
4 | "IsGlobal": false,
5 | "Name": "HexInspector",
6 | "Author": "NaroZeol",
7 | "Version": "0.4.0",
8 | "Language": "csharp",
9 | "Website": "https://github.com/NaroZeol/PowerHexInspector",
10 | "ExecuteFileName": "Community.PowerToys.Run.Plugin.HexInspector.dll",
11 | "IcoPathDark": "Images\\HexInspector.dark.png",
12 | "IcoPathLight": "Images\\HexInspector.light.png"
13 | }
14 |
--------------------------------------------------------------------------------
/src/ConvertHelper.cs:
--------------------------------------------------------------------------------
1 | using System.Numerics;
2 | using System.Text;
3 |
4 | namespace Community.PowerToys.Run.Plugin.HexInspector;
5 |
6 | public class ConvertResult(string raw, string formated)
7 | {
8 | public string Raw { get; set; } = raw;
9 | public string Formated { get; set; } = formated;
10 | }
11 |
12 | public class Convert(SettingsHelper settingHelper)
13 | {
14 | private readonly SettingsHelper settings = settingHelper;
15 | public bool is_upper;
16 |
17 | private string HexToBigEndian(string hex)
18 | {
19 | if (hex.Length < 2)
20 | {
21 | return hex; // No need to reverse
22 | }
23 | if (hex.Length % 2 != 0)
24 | {
25 | hex = hex.PadLeft(hex.Length + 1, '0');
26 | }
27 | string[] splited = new string[hex.Length / 2];
28 | for (int i = 0; i < hex.Length / 2; i++)
29 | {
30 | splited[i] = hex.Substring(i * 2, 2);
31 | }
32 | Array.Reverse(splited);
33 | return string.Join("", splited);
34 | }
35 |
36 | private string BinToBigEndian(string bin)
37 | {
38 | if (bin.Length < 8)
39 | {
40 | return bin; // No need to reverse
41 | }
42 | if (bin.Length % 8 != 0)
43 | {
44 | bin = bin.PadLeft(bin.Length + (8 - bin.Length % 8), '0');
45 | }
46 | string[] splited = new string[bin.Length / 8];
47 | for (int i = 0; i < bin.Length / 8; i++)
48 | {
49 | splited[i] = bin.Substring(i * 8, 8);
50 | }
51 | Array.Reverse(splited);
52 | return string.Join("", splited);
53 | }
54 |
55 | private string HexToLittleEndian(string hex)
56 | {
57 | return HexToBigEndian(hex); // Same logic
58 | }
59 |
60 | private string BinToLittleEndian(string bin)
61 | {
62 | return BinToBigEndian(bin); // Same logic
63 | }
64 |
65 | private string SplitBinary(string bin)
66 | {
67 | if (bin.Length % 4 != 0)
68 | {
69 | bin = bin.PadLeft(bin.Length + (4 - bin.Length % 4), '0');
70 | }
71 | string[] splited = new string[bin.Length / 4];
72 | for (int i = 0; i < bin.Length / 4; i++)
73 | {
74 | splited[i] = bin.Substring(i * 4, 4);
75 | }
76 | return string.Join(" ", splited);
77 | }
78 |
79 | public ConvertResult HexFormat(string hex, bool upper)
80 | {
81 | // hex should be in little endian
82 | if (settings.OutputEndian == Endian.BigEndian)
83 | {
84 | hex = HexToBigEndian(hex);
85 | }
86 |
87 | if (upper)
88 | {
89 | return new ConvertResult(hex.ToUpper(), hex.ToUpper());
90 | }
91 | else
92 | {
93 | return new ConvertResult(hex.ToLower(), hex.ToLower());
94 | }
95 | }
96 |
97 | public ConvertResult BinFormat(string bin)
98 | {
99 | // bin should be in little endian
100 | if (settings.OutputEndian == Endian.BigEndian)
101 | {
102 | bin = BinToBigEndian(bin);
103 | }
104 |
105 | if (settings.SplitBinary)
106 | {
107 | return new ConvertResult(bin, SplitBinary(bin));
108 | }
109 | return new ConvertResult(bin, bin);
110 | }
111 |
112 | public ConvertResult OctFormat(string oct)
113 | {
114 | // No need to change octal format
115 | return new ConvertResult(oct, oct);
116 | }
117 |
118 | public ConvertResult DecFormat(string dec)
119 | {
120 | return new ConvertResult(dec, dec);
121 | }
122 |
123 | public ConvertResult AsciiFormat(string ascii)
124 | {
125 | // ascii should be in little endian
126 | if (settings.OutputEndian == Endian.BigEndian)
127 | {
128 | ascii = new string(ascii.Reverse().ToArray());
129 | }
130 |
131 | StringBuilder strb = new StringBuilder(ascii);
132 | for (int i = 0; i < strb.Length; i++)
133 | {
134 | if (char.IsControl(strb[i]))
135 | {
136 | strb[i] = ' ';
137 | }
138 | }
139 | ascii = strb.ToString();
140 |
141 | return new ConvertResult(ascii, ascii);
142 | }
143 |
144 | // Ascii to integer(Decimal)
145 | public string AsciiToInt(string ascii) =>
146 | System.Convert.ToInt64(
147 | System.BitConverter
148 | .ToString(System.Text.Encoding.ASCII.GetBytes(ascii) // ASCII to hex string, e.g. "AB" -> "42-41"
149 | .Reverse().ToArray()) // Convert to little endian
150 | .Replace("-", ""),
151 | (int)Base.Hex
152 | ).ToString();
153 |
154 | // integer(Decimal) to Ascii
155 | public string IntToAscii(string dec) =>
156 | new string (
157 | System.Text.Encoding.ASCII.GetString(
158 | System.BitConverter.GetBytes(System.Convert.ToInt64(dec, 10)))
159 | .TrimEnd('\0') // Remove null character
160 | .Reverse()
161 | .ToArray()
162 | );
163 |
164 | // Convert string to BigInteger(Decimal)
165 | public BigInteger BigIntegerConvert(string input, Base fromBase) => fromBase switch
166 | {
167 | Base.Bin => BigInteger.Parse("0"+input, System.Globalization.NumberStyles.BinaryNumber),
168 | Base.Oct => new Func( // BigInterger.Parse() does not support octal, fxxk mixxxxxft
169 | () => {
170 | input = input.Replace(" ", ""); // Remove space
171 | BigInteger result = 0;
172 | for (int i = 0; i < input.Length; i++)
173 | {
174 | result += (input[i] - '0') * BigInteger.Pow(8, input.Length - i - 1);
175 | }
176 | return result;
177 | }
178 | )(),
179 | Base.Dec => BigInteger.Parse(input),
180 | Base.Hex => BigInteger.Parse("0"+input, System.Globalization.NumberStyles.HexNumber),
181 | Base.Ascii => new Func(
182 | () => {
183 | byte[] bytes = System.Text.Encoding.ASCII.GetBytes(input).Reverse().ToArray();
184 | return new BigInteger(bytes);
185 | }
186 | )(),
187 | _ => throw new System.ArgumentException("Invalid base", nameof(fromBase))
188 | };
189 |
190 | // Convert BigInteger(Decimal) to string
191 | public string ConvertBigInteger(BigInteger input, Base toBase) => toBase switch
192 | {
193 | Base.Bin => input.ToString("B"),
194 | Base.Oct => new Func(
195 | () => {
196 | if (input == 0)
197 | {
198 | return "0";
199 | }
200 |
201 | string result = "";
202 | while (input > 0)
203 | {
204 | result = (input % 8).ToString() + result;
205 | input /= 8;
206 | }
207 | return result;
208 | }
209 | )(),
210 | Base.Dec => input.ToString(),
211 | Base.Hex => input.ToString("X"),
212 | Base.Ascii => new Func(
213 | () => {
214 | byte[] bytes = input.ToByteArray().Reverse().ToArray();
215 | return System.Text.Encoding.ASCII.GetString(bytes);
216 | }
217 | )(),
218 | _ => throw new System.ArgumentException("Invalid base", nameof(toBase))
219 | };
220 |
221 | public ConvertResult UniversalConvert(string input, Base fromBase, Base toBase)
222 | {
223 | // Make sure the input is in the little endian before converting
224 | if (settings.InputEndian == Endian.BigEndian)
225 | {
226 | input = fromBase switch
227 | {
228 | Base.Bin => BinToLittleEndian(input),
229 | Base.Hex => HexToLittleEndian(input),
230 | Base.Ascii => new string(input.Reverse().ToArray()),
231 | _ => input
232 | };
233 | }
234 |
235 | try
236 | {
237 | string dec = settings.BitLength switch
238 | {
239 | BitLength.BYTE when fromBase != Base.Ascii => System.Convert.ToSByte(input, (int)fromBase).ToString(),
240 | BitLength.WORD when fromBase != Base.Ascii => System.Convert.ToInt16(input, (int)fromBase).ToString(),
241 | BitLength.DWORD when fromBase != Base.Ascii => System.Convert.ToInt32(input, (int)fromBase).ToString(),
242 | BitLength.QWORD when fromBase != Base.Ascii => System.Convert.ToInt64(input, (int)fromBase).ToString(),
243 | not BitLength.UNLIMITED when fromBase == Base.Ascii => AsciiToInt(input),
244 | BitLength.UNLIMITED => BigIntegerConvert(input, fromBase).ToString(),
245 | _ => throw new ArgumentException("Invalid base", nameof(fromBase))
246 | };
247 |
248 | string raw = settings.BitLength switch
249 | {
250 | BitLength.BYTE when toBase != Base.Ascii => System.Convert.ToString(System.Convert.ToSByte(dec, 10), (int)toBase),
251 | BitLength.WORD when toBase != Base.Ascii => System.Convert.ToString(System.Convert.ToInt16(dec, 10), (int)toBase),
252 | BitLength.DWORD when toBase != Base.Ascii => System.Convert.ToString(System.Convert.ToInt32(dec, 10), (int)toBase),
253 | BitLength.QWORD when toBase != Base.Ascii => System.Convert.ToString(System.Convert.ToInt64(dec, 10), (int)toBase),
254 | not BitLength.UNLIMITED when toBase == Base.Ascii => IntToAscii(dec),
255 | BitLength.UNLIMITED => ConvertBigInteger(BigInteger.Parse(dec), toBase),
256 | _ => throw new ArgumentException("Invalid base", nameof(toBase))
257 | };
258 |
259 | string formated = toBase switch
260 | {
261 | Base.Bin => BinFormat(raw).Formated,
262 | Base.Oct => OctFormat(raw).Formated,
263 | Base.Dec => DecFormat(raw).Formated,
264 | Base.Hex => HexFormat(raw, is_upper).Formated,
265 | Base.Ascii => AsciiFormat(raw).Formated,
266 | _ => raw
267 | };
268 |
269 | return new ConvertResult(raw, formated);
270 | }
271 | catch (Exception e)
272 | when (e is FormatException || e is InvalidCastException || e is OverflowException || e is ArgumentNullException)
273 | {
274 | return e switch
275 | {
276 | FormatException => new ConvertResult("Invalid format", "Invalid format"),
277 | InvalidCastException => new ConvertResult("Invalid cast", "Invalid cast"),
278 | OverflowException => new ConvertResult("Overflow", "Overflow"),
279 | ArgumentNullException => new ConvertResult("Null argument", "Null argument"),
280 | _ => new ConvertResult("Unknown error", "Unknown error")
281 | };
282 | }
283 | }
284 | }
--------------------------------------------------------------------------------
/src/Enum.cs:
--------------------------------------------------------------------------------
1 | namespace Community.PowerToys.Run.Plugin.HexInspector
2 | {
3 | public enum Base
4 | {
5 | Invalid = -1,
6 | Bin = 2,
7 | Oct = 8,
8 | Dec = 10,
9 | Hex = 16,
10 | Ascii = 256,
11 | }
12 |
13 | public enum Endian
14 | {
15 | LittleEndian = 0,
16 | BigEndian = 1,
17 | }
18 |
19 | public enum BitLength
20 | {
21 | BYTE = 8,
22 | WORD = 16,
23 | DWORD = 32,
24 | QWORD = 64,
25 | UNLIMITED = -1,
26 | }
27 | }
--------------------------------------------------------------------------------
/src/HexInspector.cs:
--------------------------------------------------------------------------------
1 | using Wox.Plugin;
2 | using Wox.Plugin.Logger;
3 | using Microsoft.PowerToys.Settings.UI.Library;
4 | using System.Windows.Controls;
5 | using ManagedCommon;
6 |
7 | namespace Community.PowerToys.Run.Plugin.HexInspector
8 | {
9 | public class Main : IPlugin, IDisposable, ISettingProvider
10 | {
11 | public string Name => "HexInspector";
12 | public string Description => "A simple powertoys run plugin provides fast and easy way to peek other forms of an input value";
13 | public static string PluginID => "JSAKDJKALSJDIWDI1872Hdhad139319A";
14 |
15 | private string IconPath { get; set; }
16 | private PluginInitContext Context { get; set; }
17 | private bool _disposed;
18 | private readonly SettingsHelper settings;
19 | private readonly Convert converter;
20 |
21 | public Main()
22 | {
23 | settings = new SettingsHelper();
24 | converter = new Convert(settings);
25 | }
26 |
27 | private List ProduceResults(Query query)
28 | {
29 | var results = new List();
30 | var conversions = new List<(ConvertResult, Base)>();
31 | bool isKeywordSearch = !string.IsNullOrEmpty(query.ActionKeyword);
32 | bool isEmptySearch = string.IsNullOrEmpty(query.Search);
33 |
34 | if (isEmptySearch && isKeywordSearch)
35 | {
36 | results.Add
37 | (
38 | new Result
39 | {
40 | Title = $"Usage 1: {query.ActionKeyword} [value]",
41 | SubTitle = "[value]: A C-style value, e.g. 65, 0x41, 0b01000001, 0101, \"A\"",
42 | IcoPath = IconPath,
43 | Action = (e) => true
44 | }
45 | );
46 | results.Add
47 | (
48 | new Result
49 | {
50 | Title = $"Usage 2: {query.ActionKeyword} [format] [value]",
51 | SubTitle = "[format]: h/H for hex, b/B for binary, d/D for decimal, o/O for octal, a/A for ascii",
52 | IcoPath = IconPath,
53 | Action = (e) => true
54 | }
55 | );
56 | return results;
57 | }
58 |
59 | QueryInterpretHelper.QueryInterpret(query, out Base queryBase, out string queryValue, out bool isUpper);
60 | (bool vaild, List checkRes) = CheckInput(queryBase, queryValue);
61 | if (!vaild)
62 | {
63 | return checkRes;
64 | }
65 |
66 | converter.is_upper = isUpper;
67 | conversions.Add((converter.UniversalConvert(queryValue, queryBase, Base.Oct), Base.Oct));
68 | conversions.Add((converter.UniversalConvert(queryValue, queryBase, Base.Dec), Base.Dec));
69 | conversions.Add((converter.UniversalConvert(queryValue, queryBase, Base.Hex), Base.Hex));
70 | conversions.Add((converter.UniversalConvert(queryValue, queryBase, Base.Bin), Base.Bin));
71 | conversions.Add((converter.UniversalConvert(queryValue, queryBase, Base.Ascii), Base.Ascii));
72 |
73 | // Create result list
74 | foreach ((ConvertResult res, Base type) in conversions)
75 | {
76 | results.Add
77 | (
78 | new Result
79 | {
80 | Title = res.Formated,
81 | SubTitle = $"{type.ToString().ToUpper()} "
82 | + $"({settings.BitLength}{(type == Base.Bin || type == Base.Hex || type == Base.Ascii ? $" {settings.OutputEndian}" : "")})",
83 | IcoPath = IconPath,
84 | Action = (e) =>
85 | {
86 | UtilsFunc.SetClipboardText(res.Raw);
87 | return true;
88 | }
89 | }
90 | );
91 | }
92 | return results;
93 | }
94 |
95 | private (bool vaild, List checkRes) CheckInput(Base queryBase, string queryValue)
96 | {
97 | if (queryBase == Base.Invalid ||
98 | (queryBase == Base.Ascii && queryValue.Length == 0))
99 | {
100 | return (vaild: false, checkRes: []);
101 | }
102 |
103 | if (settings.BitLength == BitLength.UNLIMITED && queryBase != Base.Ascii && queryValue.Contains('-'))
104 | {
105 | return
106 | (vaild:false,
107 | checkRes: new List {
108 | new Result
109 | {
110 | Title = "Negative number is not supported for unlimited bit length",
111 | SubTitle = "Please select a limited bit length for negative number in settings",
112 | IcoPath = IconPath,
113 | Action = (e) => true
114 | }
115 | });
116 | }
117 |
118 | return (vaild: true, checkRes: null);
119 | }
120 |
121 | public List Query(Query query)
122 | {
123 | var results = new List();
124 |
125 | try
126 | {
127 | results = ProduceResults(query);
128 | }
129 | catch (Exception e)
130 | {
131 | Log.Info($"Unhandled Exception: {e.Message} {e.StackTrace}", typeof(Main));
132 | // Return Error message
133 | return new List {
134 | new Result
135 | {
136 | Title = "Unhandled Exception",
137 | SubTitle = @"Check log(%LOCALAPPDATA%\Microsoft\PowerToys\PowerToys Run\Logs) for more information",
138 | IcoPath = IconPath,
139 | Action = (e) =>
140 | {
141 | UtilsFunc.SetClipboardText(@"%LOCALAPPDATA%\Microsoft\PowerToys\PowerToys Run\Logs");
142 | return true;
143 | }
144 | }
145 | };
146 | }
147 |
148 | return results;
149 | }
150 |
151 | public void Init(PluginInitContext context)
152 | {
153 | Log.Info("HexInspector plugin is initializeing", typeof(Main));
154 | Context = context ?? throw new ArgumentNullException(paramName: nameof(context));
155 |
156 | Context.API.ThemeChanged += OnThemeChanged;
157 | UpdateIconPath(Context.API.GetCurrentTheme());
158 | Log.Info("HexInspector plugin is initialized", typeof(Main));
159 | }
160 |
161 | public Control CreateSettingPanel()
162 | {
163 | throw new NotImplementedException();
164 | }
165 |
166 | public IEnumerable AdditionalOptions { get; } = new List()
167 | {
168 | new PluginAdditionalOption {
169 | Key = "SplitBinary",
170 | DisplayLabel = "Split Binary",
171 | DisplayDescription = "Split binary into 4-bit groups",
172 | Value = true,
173 | },
174 | new PluginAdditionalOption {
175 | Key = "InputEndian",
176 | DisplayLabel = "Input Endian",
177 | DisplayDescription = "Little or Big Endian setting for input, only for binary and hexadecimal",
178 | PluginOptionType = PluginAdditionalOption.AdditionalOptionType.Combobox,
179 | ComboBoxValue = 0,
180 | ComboBoxItems =
181 | [
182 | new KeyValuePair("Little Endian", "0"),
183 | new KeyValuePair("Big Endian", "1"),
184 | ]
185 | },
186 | new PluginAdditionalOption {
187 | Key = "OutputEndian",
188 | DisplayLabel = "Output Endian",
189 | DisplayDescription = "Little or Big Endian setting for output, only for binary and hexadecimal",
190 | PluginOptionType = PluginAdditionalOption.AdditionalOptionType.Combobox,
191 | ComboBoxValue = (int)Endian.LittleEndian,
192 | ComboBoxItems =
193 | [
194 | new KeyValuePair("Little Endian", "0"),
195 | new KeyValuePair("Big Endian", "1"),
196 | ]
197 | },
198 | new PluginAdditionalOption {
199 | Key = "BitLength",
200 | DisplayLabel = "Bit Lengths",
201 | DisplayDescription = "Select the bit length for the output, influence negative number",
202 | PluginOptionType = PluginAdditionalOption.AdditionalOptionType.Combobox,
203 | ComboBoxValue = (int)BitLength.UNLIMITED,
204 | ComboBoxItems =
205 | [
206 | new KeyValuePair("BYTE", "8"),
207 | new KeyValuePair("WORD", "16"),
208 | new KeyValuePair("DWORD", "32"),
209 | new KeyValuePair("QWORD", "64"),
210 | new KeyValuePair("UNLIMITED", "-1"),
211 | ]
212 | }
213 | };
214 |
215 | public void UpdateSettings(PowerLauncherPluginSettings settings)
216 | {
217 | this.settings.UpdateSettings(settings);
218 | return;
219 | }
220 |
221 | private void OnThemeChanged(Theme currentTheme, Theme newTheme)
222 | {
223 | UpdateIconPath(newTheme);
224 | }
225 |
226 | private void UpdateIconPath(Theme theme)
227 | {
228 | if (theme == Theme.Light || theme == Theme.HighContrastWhite)
229 | {
230 | IconPath = "Images/HexInspector.light.png";
231 | }
232 | else
233 | {
234 | IconPath = "Images/HexInspector.dark.png";
235 | }
236 | }
237 |
238 | public void Dispose()
239 | {
240 | Dispose(disposing: true);
241 | GC.SuppressFinalize(this);
242 | }
243 |
244 | protected virtual void Dispose(bool disposing)
245 | {
246 | if (!_disposed)
247 | {
248 | if (disposing)
249 | {
250 | if (Context != null && Context.API != null)
251 | {
252 | Context.API.ThemeChanged -= OnThemeChanged;
253 | }
254 |
255 | _disposed = true;
256 | }
257 | }
258 | }
259 | }
260 | }
--------------------------------------------------------------------------------
/src/QueryInterpretHelper.cs:
--------------------------------------------------------------------------------
1 | using System.Text.RegularExpressions;
2 | using Wox.Plugin;
3 |
4 | namespace Community.PowerToys.Run.Plugin.HexInspector
5 | {
6 | public static class QueryInterpretHelper
7 | {
8 | private static readonly string FilterPattern = "_,";
9 |
10 | private static string ReplaceFirstOccurrence(string input, string pattern, string replacement)
11 | {
12 | Regex regex = new Regex(pattern);
13 | return regex.Replace(input, replacement, 1);
14 | }
15 |
16 | public static void QueryInterpret(Query query, out Base queryBase, out string queryValue, out bool isUpper)
17 | {
18 | var terms = query.Terms;
19 | var raw = query.RawUserQuery.Trim().Substring(query.ActionKeyword.Length).Trim();
20 | queryBase = Base.Invalid;
21 | queryValue = "";
22 | isUpper = false;
23 |
24 | // Use C-Style: (only allow lowercase 'x' and 'b')
25 | // {value} -> Decimal
26 | // 0{value} -> Octal
27 | // 0x{value} -> Hex
28 | // 0b{value} -> Binary
29 | // "{value}" -> ASCII
30 | if (terms.Count == 1 || terms[0][0] == '"')
31 | {
32 | string decimalPattern = @$"^[+-]?([1-9][0-9{FilterPattern}]*)$";
33 | string octalPattern = @$"^[+-]?(0[0-7{FilterPattern}]+)$";
34 | string hexPattern = @$"^[+-]?(0x[0-9a-fA-F{FilterPattern}]+)$";
35 | string binaryPattern = @$"^[+-]?(0b[01{FilterPattern}]+)$";
36 | string asciiPattern = @$"^"".*""$";
37 |
38 | if (Regex.IsMatch(raw, decimalPattern) || raw == "0" || raw == "-0")
39 | {
40 | queryBase = Base.Dec;
41 | queryValue = raw;
42 | }
43 | else if (Regex.IsMatch(raw, octalPattern))
44 | {
45 | queryBase = Base.Oct;
46 | queryValue = ReplaceFirstOccurrence(raw, "0", "");
47 | }
48 | else if (Regex.IsMatch(raw, hexPattern))
49 | {
50 | queryBase = Base.Hex;
51 | queryValue = ReplaceFirstOccurrence(raw, "0x", "");
52 | }
53 | else if (Regex.IsMatch(raw, binaryPattern))
54 | {
55 | queryBase = Base.Bin;
56 | queryValue = ReplaceFirstOccurrence(raw, "0b", "");
57 | }
58 | else if (Regex.IsMatch(raw, asciiPattern))
59 | {
60 | queryBase = Base.Ascii;
61 | queryValue = raw[1..^1]; // only remove the first and last double quotes
62 | }
63 | }
64 | else if (terms.Count >= 2) // Use specific Format: {Keyword} [Format] [Value]
65 | {
66 | queryBase = terms[0].ToLower() switch
67 | {
68 | "h" => Base.Hex,
69 | "b" => Base.Bin,
70 | "d" => Base.Dec,
71 | "o" => Base.Oct,
72 | "a" => Base.Ascii,
73 | _ => Base.Invalid
74 | };
75 | isUpper = char.IsUpper(terms[0][0]);
76 | queryValue = raw[terms[0].Length..].Trim();
77 | }
78 |
79 | if (queryBase != Base.Ascii)
80 | {
81 | queryValue = Regex.Replace(queryValue, $"[{FilterPattern}]", "");
82 | queryValue = queryValue.Trim().Replace(" ", "");
83 | }
84 |
85 | return;
86 | }
87 | }
88 | }
--------------------------------------------------------------------------------
/src/SettingsHelper.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.PowerToys.Settings.UI.Library;
2 |
3 | namespace Community.PowerToys.Run.Plugin.HexInspector
4 | {
5 | public class SettingsHelper
6 | {
7 | public bool SplitBinary;
8 | public Endian InputEndian;
9 | public Endian OutputEndian;
10 | public BitLength BitLength;
11 |
12 | public void UpdateSettings(PowerLauncherPluginSettings settings)
13 | {
14 | var _splitBinary = true;
15 | var _inputEndian = Endian.LittleEndian;
16 | var _outputEndian = Endian.BigEndian;
17 | var _bitLength = BitLength.QWORD;
18 |
19 | if (settings != null && settings.AdditionalOptions != null)
20 | {
21 | var optionSplitBin = settings.AdditionalOptions.FirstOrDefault(x => x.Key == "SplitBinary");
22 | _splitBinary = optionSplitBin?.Value ?? SplitBinary;
23 |
24 | var optionInputEndian = settings.AdditionalOptions.FirstOrDefault(x => x.Key == "InputEndian");
25 | _inputEndian = (Endian)optionInputEndian.ComboBoxValue;
26 |
27 | var optionOutputEndian = settings.AdditionalOptions.FirstOrDefault(x => x.Key == "OutputEndian");
28 | _outputEndian = (Endian)optionOutputEndian.ComboBoxValue;
29 |
30 | var optionBitLength = settings.AdditionalOptions.FirstOrDefault(x => x.Key == "BitLength");
31 | _bitLength = (BitLength)optionBitLength.ComboBoxValue;
32 | }
33 |
34 | SplitBinary = _splitBinary;
35 | InputEndian = _inputEndian;
36 | OutputEndian = _outputEndian;
37 | BitLength = _bitLength;
38 | return;
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/src/Utils.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace Community.PowerToys.Run.Plugin.HexInspector
4 | {
5 | public static class UtilsFunc
6 | {
7 | public static void SetClipboardText(string s)
8 | {
9 | Clipboard.SetDataObject(s);
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------