├── .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 | [![Mentioned in Awesome PowerToys Run Plugins](https://awesome.re/mentioned-badge.svg)](https://github.com/hlaueriksson/awesome-powertoys-run-plugins) 4 | [![Mentioned in Awesome PowerToys Run Plugins](https://awesome.re/mentioned-badge-flat.svg)](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 | ![](./Images/examples/ep1.png) 47 | 48 | ![](./Images/examples/ep2.png) 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 | [![Mentioned in Awesome PowerToys Run Plugins](https://awesome.re/mentioned-badge.svg)](https://github.com/hlaueriksson/awesome-powertoys-run-plugins) 4 | [![Mentioned in Awesome PowerToys Run Plugins](https://awesome.re/mentioned-badge-flat.svg)](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 | ![](./Images/examples/ep1.png) 48 | 49 | ![](./Images/examples/ep2.png) 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 | } --------------------------------------------------------------------------------