├── .gitattributes ├── .gitignore ├── IMG_20220104_160036.jpg ├── README.md ├── dwm overlay.sln └── dwm overlay ├── MinHook ├── MinHook.h └── libMinHook.x64.lib ├── dllmain.cpp ├── dwm overlay.vcxproj ├── dwm overlay.vcxproj.filters ├── framework.h ├── imgui ├── imconfig.h ├── imgui.cpp ├── imgui.h ├── imgui_draw.cpp ├── imgui_impl_dx11.cpp ├── imgui_impl_dx11.h ├── imgui_impl_win32.cpp ├── imgui_impl_win32.h ├── imgui_internal.h ├── imgui_tables.cpp ├── imgui_widgets.cpp ├── imstb_rectpack.h ├── imstb_textedit.h └── imstb_truetype.h ├── renderer.cpp ├── renderer.h ├── tools.cpp └── tools.h /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | [Xx]64/ 19 | [Xx]86/ 20 | [Bb]uild/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | 143 | # TODO: Un-comment the next line if you do not want to checkin 144 | # your web deploy settings because they may include unencrypted 145 | # passwords 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # NuGet Packages 150 | *.nupkg 151 | # The packages folder can be ignored because of Package Restore 152 | **/packages/* 153 | # except build/, which is used as an MSBuild target. 154 | !**/packages/build/ 155 | # Uncomment if necessary however generally it will be regenerated when needed 156 | #!**/packages/repositories.config 157 | # NuGet v3's project.json files produces more ignoreable files 158 | *.nuget.props 159 | *.nuget.targets 160 | 161 | # Microsoft Azure Build Output 162 | csx/ 163 | *.build.csdef 164 | 165 | # Microsoft Azure Emulator 166 | ecf/ 167 | rcf/ 168 | 169 | # Windows Store app package directory 170 | AppPackages/ 171 | BundleArtifacts/ 172 | 173 | # Visual Studio cache files 174 | # files ending in .cache can be ignored 175 | *.[Cc]ache 176 | # but keep track of directories ending in .cache 177 | !*.[Cc]ache/ 178 | 179 | # Others 180 | ClientBin/ 181 | [Ss]tyle[Cc]op.* 182 | ~$* 183 | *~ 184 | *.dbmdl 185 | *.dbproj.schemaview 186 | *.pfx 187 | *.publishsettings 188 | node_modules/ 189 | orleans.codegen.cs 190 | 191 | # RIA/Silverlight projects 192 | Generated_Code/ 193 | 194 | # Backup & report files from converting an old project file 195 | # to a newer Visual Studio version. Backup files are not needed, 196 | # because we have git ;-) 197 | _UpgradeReport_Files/ 198 | Backup*/ 199 | UpgradeLog*.XML 200 | UpgradeLog*.htm 201 | 202 | # SQL Server files 203 | *.mdf 204 | *.ldf 205 | 206 | # Business Intelligence projects 207 | *.rdl.data 208 | *.bim.layout 209 | *.bim_*.settings 210 | 211 | # Microsoft Fakes 212 | FakesAssemblies/ 213 | 214 | # GhostDoc plugin setting file 215 | *.GhostDoc.xml 216 | 217 | # Node.js Tools for Visual Studio 218 | .ntvs_analysis.dat 219 | 220 | # Visual Studio 6 build log 221 | *.plg 222 | 223 | # Visual Studio 6 workspace options file 224 | *.opt 225 | 226 | # Visual Studio LightSwitch build output 227 | **/*.HTMLClient/GeneratedArtifacts 228 | **/*.DesktopClient/GeneratedArtifacts 229 | **/*.DesktopClient/ModelManifest.xml 230 | **/*.Server/GeneratedArtifacts 231 | **/*.Server/ModelManifest.xml 232 | _Pvt_Extensions 233 | 234 | # LightSwitch generated files 235 | GeneratedArtifacts/ 236 | ModelManifest.xml 237 | 238 | # Paket dependency manager 239 | .paket/paket.exe 240 | 241 | # FAKE - F# Make 242 | .fake/ 243 | -------------------------------------------------------------------------------- /IMG_20220104_160036.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapleSwan/dwm-overlay/3dfa1df375cce67c0449cfb2f9615af2e92a0dc1/IMG_20220104_160036.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dwm-overlay 2 | 系统版本:21H2 19044 3 | ![image](https://github.com/LoxTus/dwm-overlay/blob/master/IMG_20220104_160036.jpg) 4 | -------------------------------------------------------------------------------- /dwm overlay.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.32002.261 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dwm overlay", "dwm overlay\dwm overlay.vcxproj", "{8538C5F6-EF82-452F-BF75-89BBE5D8C5AC}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {8538C5F6-EF82-452F-BF75-89BBE5D8C5AC}.Debug|x64.ActiveCfg = Debug|x64 17 | {8538C5F6-EF82-452F-BF75-89BBE5D8C5AC}.Debug|x64.Build.0 = Debug|x64 18 | {8538C5F6-EF82-452F-BF75-89BBE5D8C5AC}.Debug|x86.ActiveCfg = Debug|Win32 19 | {8538C5F6-EF82-452F-BF75-89BBE5D8C5AC}.Debug|x86.Build.0 = Debug|Win32 20 | {8538C5F6-EF82-452F-BF75-89BBE5D8C5AC}.Release|x64.ActiveCfg = Release|x64 21 | {8538C5F6-EF82-452F-BF75-89BBE5D8C5AC}.Release|x64.Build.0 = Release|x64 22 | {8538C5F6-EF82-452F-BF75-89BBE5D8C5AC}.Release|x86.ActiveCfg = Release|Win32 23 | {8538C5F6-EF82-452F-BF75-89BBE5D8C5AC}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {93FC8162-3E32-480A-8770-EF76A1CA5B8A} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /dwm overlay/MinHook/MinHook.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MinHook - The Minimalistic API Hooking Library for x64/x86 3 | * Copyright (C) 2009-2017 Tsuda Kageyu. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 20 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #pragma once 30 | 31 | #if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__) 32 | #error MinHook supports only x86 and x64 systems. 33 | #endif 34 | 35 | #include 36 | 37 | // MinHook Error Codes. 38 | typedef enum MH_STATUS 39 | { 40 | // Unknown error. Should not be returned. 41 | MH_UNKNOWN = -1, 42 | 43 | // Successful. 44 | MH_OK = 0, 45 | 46 | // MinHook is already initialized. 47 | MH_ERROR_ALREADY_INITIALIZED, 48 | 49 | // MinHook is not initialized yet, or already uninitialized. 50 | MH_ERROR_NOT_INITIALIZED, 51 | 52 | // The hook for the specified target function is already created. 53 | MH_ERROR_ALREADY_CREATED, 54 | 55 | // The hook for the specified target function is not created yet. 56 | MH_ERROR_NOT_CREATED, 57 | 58 | // The hook for the specified target function is already enabled. 59 | MH_ERROR_ENABLED, 60 | 61 | // The hook for the specified target function is not enabled yet, or already 62 | // disabled. 63 | MH_ERROR_DISABLED, 64 | 65 | // The specified pointer is invalid. It points the address of non-allocated 66 | // and/or non-executable region. 67 | MH_ERROR_NOT_EXECUTABLE, 68 | 69 | // The specified target function cannot be hooked. 70 | MH_ERROR_UNSUPPORTED_FUNCTION, 71 | 72 | // Failed to allocate memory. 73 | MH_ERROR_MEMORY_ALLOC, 74 | 75 | // Failed to change the memory protection. 76 | MH_ERROR_MEMORY_PROTECT, 77 | 78 | // The specified module is not loaded. 79 | MH_ERROR_MODULE_NOT_FOUND, 80 | 81 | // The specified function is not found. 82 | MH_ERROR_FUNCTION_NOT_FOUND 83 | } 84 | MH_STATUS; 85 | 86 | // Can be passed as a parameter to MH_EnableHook, MH_DisableHook, 87 | // MH_QueueEnableHook or MH_QueueDisableHook. 88 | #define MH_ALL_HOOKS NULL 89 | 90 | #ifdef __cplusplus 91 | extern "C" { 92 | #endif 93 | 94 | // Initialize the MinHook library. You must call this function EXACTLY ONCE 95 | // at the beginning of your program. 96 | MH_STATUS WINAPI MH_Initialize(VOID); 97 | 98 | // Uninitialize the MinHook library. You must call this function EXACTLY 99 | // ONCE at the end of your program. 100 | MH_STATUS WINAPI MH_Uninitialize(VOID); 101 | 102 | // Creates a hook for the specified target function, in disabled state. 103 | // Parameters: 104 | // pTarget [in] A pointer to the target function, which will be 105 | // overridden by the detour function. 106 | // pDetour [in] A pointer to the detour function, which will override 107 | // the target function. 108 | // ppOriginal [out] A pointer to the trampoline function, which will be 109 | // used to call the original target function. 110 | // This parameter can be NULL. 111 | MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal); 112 | 113 | // Creates a hook for the specified API function, in disabled state. 114 | // Parameters: 115 | // pszModule [in] A pointer to the loaded module name which contains the 116 | // target function. 117 | // pszProcName [in] A pointer to the target function name, which will be 118 | // overridden by the detour function. 119 | // pDetour [in] A pointer to the detour function, which will override 120 | // the target function. 121 | // ppOriginal [out] A pointer to the trampoline function, which will be 122 | // used to call the original target function. 123 | // This parameter can be NULL. 124 | MH_STATUS WINAPI MH_CreateHookApi( 125 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal); 126 | 127 | // Creates a hook for the specified API function, in disabled state. 128 | // Parameters: 129 | // pszModule [in] A pointer to the loaded module name which contains the 130 | // target function. 131 | // pszProcName [in] A pointer to the target function name, which will be 132 | // overridden by the detour function. 133 | // pDetour [in] A pointer to the detour function, which will override 134 | // the target function. 135 | // ppOriginal [out] A pointer to the trampoline function, which will be 136 | // used to call the original target function. 137 | // This parameter can be NULL. 138 | // ppTarget [out] A pointer to the target function, which will be used 139 | // with other functions. 140 | // This parameter can be NULL. 141 | MH_STATUS WINAPI MH_CreateHookApiEx( 142 | LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget); 143 | 144 | // Removes an already created hook. 145 | // Parameters: 146 | // pTarget [in] A pointer to the target function. 147 | MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget); 148 | 149 | // Enables an already created hook. 150 | // Parameters: 151 | // pTarget [in] A pointer to the target function. 152 | // If this parameter is MH_ALL_HOOKS, all created hooks are 153 | // enabled in one go. 154 | MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget); 155 | 156 | // Disables an already created hook. 157 | // Parameters: 158 | // pTarget [in] A pointer to the target function. 159 | // If this parameter is MH_ALL_HOOKS, all created hooks are 160 | // disabled in one go. 161 | MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget); 162 | 163 | // Queues to enable an already created hook. 164 | // Parameters: 165 | // pTarget [in] A pointer to the target function. 166 | // If this parameter is MH_ALL_HOOKS, all created hooks are 167 | // queued to be enabled. 168 | MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget); 169 | 170 | // Queues to disable an already created hook. 171 | // Parameters: 172 | // pTarget [in] A pointer to the target function. 173 | // If this parameter is MH_ALL_HOOKS, all created hooks are 174 | // queued to be disabled. 175 | MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget); 176 | 177 | // Applies all queued changes in one go. 178 | MH_STATUS WINAPI MH_ApplyQueued(VOID); 179 | 180 | // Translates the MH_STATUS to its name as a string. 181 | const char * WINAPI MH_StatusToString(MH_STATUS status); 182 | 183 | #ifdef __cplusplus 184 | } 185 | #endif 186 | -------------------------------------------------------------------------------- /dwm overlay/MinHook/libMinHook.x64.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapleSwan/dwm-overlay/3dfa1df375cce67c0449cfb2f9615af2e92a0dc1/dwm overlay/MinHook/libMinHook.x64.lib -------------------------------------------------------------------------------- /dwm overlay/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : 定义 DLL 应用程序的入口点。 2 | #include "framework.h" 3 | #include "renderer.h" 4 | #include "tools.h" 5 | 6 | BOOL APIENTRY DllMain( HMODULE hModule, 7 | DWORD ul_reason_for_call, 8 | LPVOID lpReserved 9 | ) 10 | { 11 | switch (ul_reason_for_call) 12 | { 13 | case DLL_PROCESS_ATTACH: 14 | 15 | CloseHandle(CreateRemoteThread((HANDLE)-1, nullptr, 0, reinterpret_cast(overlay::Initialize), nullptr, 0, nullptr)); 16 | break; 17 | case DLL_THREAD_ATTACH: 18 | case DLL_THREAD_DETACH: 19 | case DLL_PROCESS_DETACH: 20 | break; 21 | } 22 | return TRUE; 23 | } 24 | 25 | -------------------------------------------------------------------------------- /dwm overlay/dwm overlay.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {8538c5f6-ef82-452f-bf75-89bbe5d8c5ac} 25 | dwmoverlay 26 | 10.0.14393.0 27 | 28 | 29 | 30 | DynamicLibrary 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | DynamicLibrary 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | DynamicLibrary 44 | true 45 | v140 46 | Unicode 47 | 48 | 49 | DynamicLibrary 50 | false 51 | v140 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Level3 88 | true 89 | WIN32;_DEBUG;DWMOVERLAY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 90 | true 91 | Use 92 | pch.h 93 | 94 | 95 | Windows 96 | true 97 | false 98 | 99 | 100 | 101 | 102 | Level3 103 | true 104 | true 105 | true 106 | WIN32;NDEBUG;DWMOVERLAY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 107 | true 108 | Use 109 | pch.h 110 | 111 | 112 | Windows 113 | true 114 | true 115 | true 116 | false 117 | 118 | 119 | 120 | 121 | Level3 122 | true 123 | _DEBUG;DWMOVERLAY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 124 | true 125 | Use 126 | pch.h 127 | 128 | 129 | Windows 130 | true 131 | false 132 | 133 | 134 | 135 | 136 | Level2 137 | true 138 | true 139 | false 140 | NDEBUG;DWMOVERLAY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 141 | true 142 | NotUsing 143 | pch.h 144 | MultiThreaded 145 | Full 146 | Speed 147 | true 148 | 149 | 150 | Windows 151 | false 152 | true 153 | true 154 | false 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /dwm overlay/dwm overlay.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {2d2e20ca-c31f-48b0-8aaf-dded4ddb2bd7} 18 | 19 | 20 | {e48a6cbc-bb08-4bff-bb7d-4e1db39c0936} 21 | 22 | 23 | {614690d3-6481-4fc6-8464-1321c7641d0e} 24 | 25 | 26 | 27 | 28 | 头文件 29 | 30 | 31 | 源文件\tools 32 | 33 | 34 | 源文件\dwmhook 35 | 36 | 37 | 38 | 39 | 源文件 40 | 41 | 42 | 源文件\tools 43 | 44 | 45 | 源文件\dwmhook 46 | 47 | 48 | 源文件\imgui 49 | 50 | 51 | 源文件\imgui 52 | 53 | 54 | 源文件\imgui 55 | 56 | 57 | 源文件\imgui 58 | 59 | 60 | 源文件\imgui 61 | 62 | 63 | 源文件\imgui 64 | 65 | 66 | -------------------------------------------------------------------------------- /dwm overlay/framework.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容 4 | // Windows 头文件 5 | #include 6 | #include 7 | -------------------------------------------------------------------------------- /dwm overlay/imgui/imconfig.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // COMPILE-TIME OPTIONS FOR DEAR IMGUI 3 | // Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. 4 | // You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. 5 | //----------------------------------------------------------------------------- 6 | // A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it) 7 | // B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template. 8 | //----------------------------------------------------------------------------- 9 | // You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp 10 | // files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures. 11 | // Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. 12 | // Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using. 13 | //----------------------------------------------------------------------------- 14 | 15 | #pragma once 16 | 17 | //---- Define assertion handler. Defaults to calling assert(). 18 | // If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement. 19 | //#define IM_ASSERT(_EXPR) MyAssert(_EXPR) 20 | //#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts 21 | 22 | //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows 23 | // Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. 24 | // DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() 25 | // for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details. 26 | //#define IMGUI_API __declspec( dllexport ) 27 | //#define IMGUI_API __declspec( dllimport ) 28 | 29 | //---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names. 30 | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS 31 | 32 | //---- Disable all of Dear ImGui or don't implement standard windows. 33 | // It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp. 34 | //#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty. 35 | //#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended. 36 | //#define IMGUI_DISABLE_METRICS_WINDOW // Disable metrics/debugger and other debug tools: ShowMetricsWindow() and ShowStackToolWindow() will be empty. 37 | 38 | //---- Don't implement some functions to reduce linkage requirements. 39 | //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a) 40 | //#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW) 41 | //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a) 42 | //#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime). 43 | //#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default). 44 | //#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf) 45 | //#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself. 46 | //#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies) 47 | //#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. 48 | //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). 49 | //#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available 50 | 51 | //---- Include imgui_user.h at the end of imgui.h as a convenience 52 | //#define IMGUI_INCLUDE_IMGUI_USER_H 53 | 54 | //---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) 55 | //#define IMGUI_USE_BGRA_PACKED_COLOR 56 | 57 | //---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...) 58 | //#define IMGUI_USE_WCHAR32 59 | 60 | //---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version 61 | // By default the embedded implementations are declared static and not available outside of Dear ImGui sources files. 62 | //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" 63 | //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" 64 | //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION 65 | //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION 66 | 67 | //---- Use stb_printf's faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined) 68 | // Requires 'stb_sprintf.h' to be available in the include path. Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by STB sprintf. 69 | // #define IMGUI_USE_STB_SPRINTF 70 | 71 | //---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui) 72 | // Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided). 73 | // On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'. 74 | //#define IMGUI_ENABLE_FREETYPE 75 | 76 | //---- Use stb_truetype to build and rasterize the font atlas (default) 77 | // The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend. 78 | //#define IMGUI_ENABLE_STB_TRUETYPE 79 | 80 | //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. 81 | // This will be inlined as part of ImVec2 and ImVec4 class declarations. 82 | /* 83 | #define IM_VEC2_CLASS_EXTRA \ 84 | ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \ 85 | operator MyVec2() const { return MyVec2(x,y); } 86 | 87 | #define IM_VEC4_CLASS_EXTRA \ 88 | ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \ 89 | operator MyVec4() const { return MyVec4(x,y,z,w); } 90 | */ 91 | 92 | //---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices. 93 | // Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices). 94 | // Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer. 95 | // Read about ImGuiBackendFlags_RendererHasVtxOffset for details. 96 | //#define ImDrawIdx unsigned int 97 | 98 | //---- Override ImDrawCallback signature (will need to modify renderer backends accordingly) 99 | //struct ImDrawList; 100 | //struct ImDrawCmd; 101 | //typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data); 102 | //#define ImDrawCallback MyImDrawCallback 103 | 104 | //---- Debug Tools: Macro to break in Debugger 105 | // (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.) 106 | //#define IM_DEBUG_BREAK IM_ASSERT(0) 107 | //#define IM_DEBUG_BREAK __debugbreak() 108 | 109 | //---- Debug Tools: Have the Item Picker break in the ItemAdd() function instead of ItemHoverable(), 110 | // (which comes earlier in the code, will catch a few extra items, allow picking items other than Hovered one.) 111 | // This adds a small runtime cost which is why it is not enabled by default. 112 | //#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX 113 | 114 | //---- Debug Tools: Enable slower asserts 115 | //#define IMGUI_DEBUG_PARANOID 116 | 117 | //---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files. 118 | /* 119 | namespace ImGui 120 | { 121 | void MyFunction(const char* name, const MyMatrix44& v); 122 | } 123 | */ 124 | -------------------------------------------------------------------------------- /dwm overlay/imgui/imgui_impl_dx11.cpp: -------------------------------------------------------------------------------- 1 | // dear imgui: Renderer Backend for DirectX11 2 | // This needs to be used along with a Platform Backend (e.g. Win32) 3 | 4 | // Implemented features: 5 | // [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID! 6 | // [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices. 7 | 8 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 9 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. 10 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 11 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 12 | 13 | // CHANGELOG 14 | // (minor and older changes stripped away, please see git history for details) 15 | // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). 16 | // 2021-05-19: DirectX11: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) 17 | // 2021-02-18: DirectX11: Change blending equation to preserve alpha in output buffer. 18 | // 2019-08-01: DirectX11: Fixed code querying the Geometry Shader state (would generally error with Debug layer enabled). 19 | // 2019-07-21: DirectX11: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData. Clearing Hull/Domain/Compute shaders without backup/restore. 20 | // 2019-05-29: DirectX11: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag. 21 | // 2019-04-30: DirectX11: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. 22 | // 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile(). 23 | // 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. 24 | // 2018-08-01: DirectX11: Querying for IDXGIFactory instead of IDXGIFactory1 to increase compatibility. 25 | // 2018-07-13: DirectX11: Fixed unreleased resources in Init and Shutdown functions. 26 | // 2018-06-08: Misc: Extracted imgui_impl_dx11.cpp/.h away from the old combined DX11+Win32 example. 27 | // 2018-06-08: DirectX11: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle. 28 | // 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX11_RenderDrawData() in the .h file so you can call it yourself. 29 | // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. 30 | // 2016-05-07: DirectX11: Disabling depth-write. 31 | 32 | #include "imgui.h" 33 | #include "imgui_impl_dx11.h" 34 | 35 | // DirectX 36 | #include 37 | #include 38 | #include 39 | #ifdef _MSC_VER 40 | #pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below. 41 | #endif 42 | 43 | // DirectX11 data 44 | struct ImGui_ImplDX11_Data 45 | { 46 | ID3D11Device* pd3dDevice; 47 | ID3D11DeviceContext* pd3dDeviceContext; 48 | IDXGIFactory* pFactory; 49 | ID3D11Buffer* pVB; 50 | ID3D11Buffer* pIB; 51 | ID3D11VertexShader* pVertexShader; 52 | ID3D11InputLayout* pInputLayout; 53 | ID3D11Buffer* pVertexConstantBuffer; 54 | ID3D11PixelShader* pPixelShader; 55 | ID3D11SamplerState* pFontSampler; 56 | ID3D11ShaderResourceView* pFontTextureView; 57 | ID3D11RasterizerState* pRasterizerState; 58 | ID3D11BlendState* pBlendState; 59 | ID3D11DepthStencilState* pDepthStencilState; 60 | int VertexBufferSize; 61 | int IndexBufferSize; 62 | 63 | ImGui_ImplDX11_Data() { memset(this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; } 64 | }; 65 | 66 | struct VERTEX_CONSTANT_BUFFER 67 | { 68 | float mvp[4][4]; 69 | }; 70 | 71 | // Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts 72 | // It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. 73 | static ImGui_ImplDX11_Data* ImGui_ImplDX11_GetBackendData() 74 | { 75 | return ImGui::GetCurrentContext() ? (ImGui_ImplDX11_Data*)ImGui::GetIO().BackendRendererUserData : NULL; 76 | } 77 | 78 | // Functions 79 | static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceContext* ctx) 80 | { 81 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); 82 | 83 | // Setup viewport 84 | D3D11_VIEWPORT vp; 85 | memset(&vp, 0, sizeof(D3D11_VIEWPORT)); 86 | vp.Width = draw_data->DisplaySize.x; 87 | vp.Height = draw_data->DisplaySize.y; 88 | vp.MinDepth = 0.0f; 89 | vp.MaxDepth = 1.0f; 90 | vp.TopLeftX = vp.TopLeftY = 0; 91 | ctx->RSSetViewports(1, &vp); 92 | 93 | // Setup shader and vertex buffers 94 | unsigned int stride = sizeof(ImDrawVert); 95 | unsigned int offset = 0; 96 | ctx->IASetInputLayout(bd->pInputLayout); 97 | ctx->IASetVertexBuffers(0, 1, &bd->pVB, &stride, &offset); 98 | ctx->IASetIndexBuffer(bd->pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0); 99 | ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); 100 | ctx->VSSetShader(bd->pVertexShader, NULL, 0); 101 | ctx->VSSetConstantBuffers(0, 1, &bd->pVertexConstantBuffer); 102 | ctx->PSSetShader(bd->pPixelShader, NULL, 0); 103 | ctx->PSSetSamplers(0, 1, &bd->pFontSampler); 104 | ctx->GSSetShader(NULL, NULL, 0); 105 | ctx->HSSetShader(NULL, NULL, 0); // In theory we should backup and restore this as well.. very infrequently used.. 106 | ctx->DSSetShader(NULL, NULL, 0); // In theory we should backup and restore this as well.. very infrequently used.. 107 | ctx->CSSetShader(NULL, NULL, 0); // In theory we should backup and restore this as well.. very infrequently used.. 108 | 109 | // Setup blend state 110 | const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f }; 111 | ctx->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff); 112 | ctx->OMSetDepthStencilState(bd->pDepthStencilState, 0); 113 | ctx->RSSetState(bd->pRasterizerState); 114 | } 115 | 116 | // Render function 117 | void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) 118 | { 119 | // Avoid rendering when minimized 120 | if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f) 121 | return; 122 | 123 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); 124 | ID3D11DeviceContext* ctx = bd->pd3dDeviceContext; 125 | 126 | // Create and grow vertex/index buffers if needed 127 | if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount) 128 | { 129 | if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; } 130 | bd->VertexBufferSize = draw_data->TotalVtxCount + 5000; 131 | D3D11_BUFFER_DESC desc; 132 | memset(&desc, 0, sizeof(D3D11_BUFFER_DESC)); 133 | desc.Usage = D3D11_USAGE_DYNAMIC; 134 | desc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert); 135 | desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; 136 | desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 137 | desc.MiscFlags = 0; 138 | if (bd->pd3dDevice->CreateBuffer(&desc, NULL, &bd->pVB) < 0) 139 | return; 140 | } 141 | if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount) 142 | { 143 | if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; } 144 | bd->IndexBufferSize = draw_data->TotalIdxCount + 10000; 145 | D3D11_BUFFER_DESC desc; 146 | memset(&desc, 0, sizeof(D3D11_BUFFER_DESC)); 147 | desc.Usage = D3D11_USAGE_DYNAMIC; 148 | desc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx); 149 | desc.BindFlags = D3D11_BIND_INDEX_BUFFER; 150 | desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 151 | if (bd->pd3dDevice->CreateBuffer(&desc, NULL, &bd->pIB) < 0) 152 | return; 153 | } 154 | 155 | // Upload vertex/index data into a single contiguous GPU buffer 156 | D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource; 157 | if (ctx->Map(bd->pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK) 158 | return; 159 | if (ctx->Map(bd->pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK) 160 | return; 161 | ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData; 162 | ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData; 163 | for (int n = 0; n < draw_data->CmdListsCount; n++) 164 | { 165 | const ImDrawList* cmd_list = draw_data->CmdLists[n]; 166 | memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); 167 | memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); 168 | vtx_dst += cmd_list->VtxBuffer.Size; 169 | idx_dst += cmd_list->IdxBuffer.Size; 170 | } 171 | ctx->Unmap(bd->pVB, 0); 172 | ctx->Unmap(bd->pIB, 0); 173 | 174 | // Setup orthographic projection matrix into our constant buffer 175 | // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. 176 | { 177 | D3D11_MAPPED_SUBRESOURCE mapped_resource; 178 | if (ctx->Map(bd->pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK) 179 | return; 180 | VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource.pData; 181 | float L = draw_data->DisplayPos.x; 182 | float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; 183 | float T = draw_data->DisplayPos.y; 184 | float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; 185 | float mvp[4][4] = 186 | { 187 | { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, 188 | { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, 189 | { 0.0f, 0.0f, 0.5f, 0.0f }, 190 | { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f }, 191 | }; 192 | memcpy(&constant_buffer->mvp, mvp, sizeof(mvp)); 193 | ctx->Unmap(bd->pVertexConstantBuffer, 0); 194 | } 195 | 196 | // Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!) 197 | struct BACKUP_DX11_STATE 198 | { 199 | UINT ScissorRectsCount, ViewportsCount; 200 | D3D11_RECT ScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; 201 | D3D11_VIEWPORT Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; 202 | ID3D11RasterizerState* RS; 203 | ID3D11BlendState* BlendState; 204 | FLOAT BlendFactor[4]; 205 | UINT SampleMask; 206 | UINT StencilRef; 207 | ID3D11DepthStencilState* DepthStencilState; 208 | ID3D11ShaderResourceView* PSShaderResource; 209 | ID3D11SamplerState* PSSampler; 210 | ID3D11PixelShader* PS; 211 | ID3D11VertexShader* VS; 212 | ID3D11GeometryShader* GS; 213 | UINT PSInstancesCount, VSInstancesCount, GSInstancesCount; 214 | ID3D11ClassInstance *PSInstances[256], *VSInstances[256], *GSInstances[256]; // 256 is max according to PSSetShader documentation 215 | D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology; 216 | ID3D11Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer; 217 | UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset; 218 | DXGI_FORMAT IndexBufferFormat; 219 | ID3D11InputLayout* InputLayout; 220 | }; 221 | BACKUP_DX11_STATE old = {}; 222 | old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; 223 | ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects); 224 | ctx->RSGetViewports(&old.ViewportsCount, old.Viewports); 225 | ctx->RSGetState(&old.RS); 226 | ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask); 227 | ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef); 228 | ctx->PSGetShaderResources(0, 1, &old.PSShaderResource); 229 | ctx->PSGetSamplers(0, 1, &old.PSSampler); 230 | old.PSInstancesCount = old.VSInstancesCount = old.GSInstancesCount = 256; 231 | ctx->PSGetShader(&old.PS, old.PSInstances, &old.PSInstancesCount); 232 | ctx->VSGetShader(&old.VS, old.VSInstances, &old.VSInstancesCount); 233 | ctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer); 234 | ctx->GSGetShader(&old.GS, old.GSInstances, &old.GSInstancesCount); 235 | 236 | ctx->IAGetPrimitiveTopology(&old.PrimitiveTopology); 237 | ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset); 238 | ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); 239 | ctx->IAGetInputLayout(&old.InputLayout); 240 | 241 | // Setup desired DX state 242 | ImGui_ImplDX11_SetupRenderState(draw_data, ctx); 243 | 244 | // Render command lists 245 | // (Because we merged all buffers into a single one, we maintain our own offset into them) 246 | int global_idx_offset = 0; 247 | int global_vtx_offset = 0; 248 | ImVec2 clip_off = draw_data->DisplayPos; 249 | for (int n = 0; n < draw_data->CmdListsCount; n++) 250 | { 251 | const ImDrawList* cmd_list = draw_data->CmdLists[n]; 252 | for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) 253 | { 254 | const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; 255 | if (pcmd->UserCallback != NULL) 256 | { 257 | // User callback, registered via ImDrawList::AddCallback() 258 | // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) 259 | if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) 260 | ImGui_ImplDX11_SetupRenderState(draw_data, ctx); 261 | else 262 | pcmd->UserCallback(cmd_list, pcmd); 263 | } 264 | else 265 | { 266 | // Project scissor/clipping rectangles into framebuffer space 267 | ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y); 268 | ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y); 269 | if (clip_max.x < clip_min.x || clip_max.y < clip_min.y) 270 | continue; 271 | 272 | // Apply scissor/clipping rectangle 273 | const D3D11_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y }; 274 | ctx->RSSetScissorRects(1, &r); 275 | 276 | // Bind texture, Draw 277 | ID3D11ShaderResourceView* texture_srv = (ID3D11ShaderResourceView*)pcmd->GetTexID(); 278 | ctx->PSSetShaderResources(0, 1, &texture_srv); 279 | ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset); 280 | } 281 | } 282 | global_idx_offset += cmd_list->IdxBuffer.Size; 283 | global_vtx_offset += cmd_list->VtxBuffer.Size; 284 | } 285 | 286 | // Restore modified DX state 287 | ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects); 288 | ctx->RSSetViewports(old.ViewportsCount, old.Viewports); 289 | ctx->RSSetState(old.RS); if (old.RS) old.RS->Release(); 290 | ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release(); 291 | ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release(); 292 | ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release(); 293 | ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release(); 294 | ctx->PSSetShader(old.PS, old.PSInstances, old.PSInstancesCount); if (old.PS) old.PS->Release(); 295 | for (UINT i = 0; i < old.PSInstancesCount; i++) if (old.PSInstances[i]) old.PSInstances[i]->Release(); 296 | ctx->VSSetShader(old.VS, old.VSInstances, old.VSInstancesCount); if (old.VS) old.VS->Release(); 297 | ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release(); 298 | ctx->GSSetShader(old.GS, old.GSInstances, old.GSInstancesCount); if (old.GS) old.GS->Release(); 299 | for (UINT i = 0; i < old.VSInstancesCount; i++) if (old.VSInstances[i]) old.VSInstances[i]->Release(); 300 | ctx->IASetPrimitiveTopology(old.PrimitiveTopology); 301 | ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release(); 302 | ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release(); 303 | ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release(); 304 | } 305 | 306 | static void ImGui_ImplDX11_CreateFontsTexture() 307 | { 308 | // Build texture atlas 309 | ImGuiIO& io = ImGui::GetIO(); 310 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); 311 | unsigned char* pixels; 312 | int width, height; 313 | io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); 314 | 315 | // Upload texture to graphics system 316 | { 317 | D3D11_TEXTURE2D_DESC desc; 318 | ZeroMemory(&desc, sizeof(desc)); 319 | desc.Width = width; 320 | desc.Height = height; 321 | desc.MipLevels = 1; 322 | desc.ArraySize = 1; 323 | desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 324 | desc.SampleDesc.Count = 1; 325 | desc.Usage = D3D11_USAGE_DEFAULT; 326 | desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; 327 | desc.CPUAccessFlags = 0; 328 | 329 | ID3D11Texture2D* pTexture = NULL; 330 | D3D11_SUBRESOURCE_DATA subResource; 331 | subResource.pSysMem = pixels; 332 | subResource.SysMemPitch = desc.Width * 4; 333 | subResource.SysMemSlicePitch = 0; 334 | bd->pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture); 335 | IM_ASSERT(pTexture != NULL); 336 | 337 | // Create texture view 338 | D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; 339 | ZeroMemory(&srvDesc, sizeof(srvDesc)); 340 | srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 341 | srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; 342 | srvDesc.Texture2D.MipLevels = desc.MipLevels; 343 | srvDesc.Texture2D.MostDetailedMip = 0; 344 | bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &bd->pFontTextureView); 345 | pTexture->Release(); 346 | } 347 | 348 | // Store our identifier 349 | io.Fonts->SetTexID((ImTextureID)bd->pFontTextureView); 350 | 351 | // Create texture sampler 352 | { 353 | D3D11_SAMPLER_DESC desc; 354 | ZeroMemory(&desc, sizeof(desc)); 355 | desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; 356 | desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; 357 | desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; 358 | desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; 359 | desc.MipLODBias = 0.f; 360 | desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; 361 | desc.MinLOD = 0.f; 362 | desc.MaxLOD = 0.f; 363 | bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler); 364 | } 365 | } 366 | 367 | bool ImGui_ImplDX11_CreateDeviceObjects() 368 | { 369 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); 370 | if (!bd->pd3dDevice) 371 | return false; 372 | if (bd->pFontSampler) 373 | ImGui_ImplDX11_InvalidateDeviceObjects(); 374 | 375 | // By using D3DCompile() from / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A) 376 | // If you would like to use this DX11 sample code but remove this dependency you can: 377 | // 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution] 378 | // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL. 379 | // See https://github.com/ocornut/imgui/pull/638 for sources and details. 380 | 381 | // Create the vertex shader 382 | { 383 | static const char* vertexShader = 384 | "cbuffer vertexBuffer : register(b0) \ 385 | {\ 386 | float4x4 ProjectionMatrix; \ 387 | };\ 388 | struct VS_INPUT\ 389 | {\ 390 | float2 pos : POSITION;\ 391 | float4 col : COLOR0;\ 392 | float2 uv : TEXCOORD0;\ 393 | };\ 394 | \ 395 | struct PS_INPUT\ 396 | {\ 397 | float4 pos : SV_POSITION;\ 398 | float4 col : COLOR0;\ 399 | float2 uv : TEXCOORD0;\ 400 | };\ 401 | \ 402 | PS_INPUT main(VS_INPUT input)\ 403 | {\ 404 | PS_INPUT output;\ 405 | output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\ 406 | output.col = input.col;\ 407 | output.uv = input.uv;\ 408 | return output;\ 409 | }"; 410 | 411 | ID3DBlob* vertexShaderBlob; 412 | if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &vertexShaderBlob, NULL))) 413 | return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob! 414 | if (bd->pd3dDevice->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), NULL, &bd->pVertexShader) != S_OK) 415 | { 416 | vertexShaderBlob->Release(); 417 | return false; 418 | } 419 | 420 | // Create the input layout 421 | D3D11_INPUT_ELEMENT_DESC local_layout[] = 422 | { 423 | { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, pos), D3D11_INPUT_PER_VERTEX_DATA, 0 }, 424 | { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, uv), D3D11_INPUT_PER_VERTEX_DATA, 0 }, 425 | { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)IM_OFFSETOF(ImDrawVert, col), D3D11_INPUT_PER_VERTEX_DATA, 0 }, 426 | }; 427 | if (bd->pd3dDevice->CreateInputLayout(local_layout, 3, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &bd->pInputLayout) != S_OK) 428 | { 429 | vertexShaderBlob->Release(); 430 | return false; 431 | } 432 | vertexShaderBlob->Release(); 433 | 434 | // Create the constant buffer 435 | { 436 | D3D11_BUFFER_DESC desc; 437 | desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER); 438 | desc.Usage = D3D11_USAGE_DYNAMIC; 439 | desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; 440 | desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 441 | desc.MiscFlags = 0; 442 | bd->pd3dDevice->CreateBuffer(&desc, NULL, &bd->pVertexConstantBuffer); 443 | } 444 | } 445 | 446 | // Create the pixel shader 447 | { 448 | static const char* pixelShader = 449 | "struct PS_INPUT\ 450 | {\ 451 | float4 pos : SV_POSITION;\ 452 | float4 col : COLOR0;\ 453 | float2 uv : TEXCOORD0;\ 454 | };\ 455 | sampler sampler0;\ 456 | Texture2D texture0;\ 457 | \ 458 | float4 main(PS_INPUT input) : SV_Target\ 459 | {\ 460 | float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \ 461 | return out_col; \ 462 | }"; 463 | 464 | ID3DBlob* pixelShaderBlob; 465 | if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &pixelShaderBlob, NULL))) 466 | return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob! 467 | if (bd->pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), NULL, &bd->pPixelShader) != S_OK) 468 | { 469 | pixelShaderBlob->Release(); 470 | return false; 471 | } 472 | pixelShaderBlob->Release(); 473 | } 474 | 475 | // Create the blending setup 476 | { 477 | D3D11_BLEND_DESC desc; 478 | ZeroMemory(&desc, sizeof(desc)); 479 | desc.AlphaToCoverageEnable = false; 480 | desc.RenderTarget[0].BlendEnable = true; 481 | desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; 482 | desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; 483 | desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; 484 | desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; 485 | desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; 486 | desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; 487 | desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; 488 | bd->pd3dDevice->CreateBlendState(&desc, &bd->pBlendState); 489 | } 490 | 491 | // Create the rasterizer state 492 | { 493 | D3D11_RASTERIZER_DESC desc; 494 | ZeroMemory(&desc, sizeof(desc)); 495 | desc.FillMode = D3D11_FILL_SOLID; 496 | desc.CullMode = D3D11_CULL_NONE; 497 | desc.ScissorEnable = true; 498 | desc.DepthClipEnable = true; 499 | bd->pd3dDevice->CreateRasterizerState(&desc, &bd->pRasterizerState); 500 | } 501 | 502 | // Create depth-stencil State 503 | { 504 | D3D11_DEPTH_STENCIL_DESC desc; 505 | ZeroMemory(&desc, sizeof(desc)); 506 | desc.DepthEnable = false; 507 | desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; 508 | desc.DepthFunc = D3D11_COMPARISON_ALWAYS; 509 | desc.StencilEnable = false; 510 | desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; 511 | desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; 512 | desc.BackFace = desc.FrontFace; 513 | bd->pd3dDevice->CreateDepthStencilState(&desc, &bd->pDepthStencilState); 514 | } 515 | 516 | ImGui_ImplDX11_CreateFontsTexture(); 517 | 518 | return true; 519 | } 520 | 521 | void ImGui_ImplDX11_InvalidateDeviceObjects() 522 | { 523 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); 524 | if (!bd->pd3dDevice) 525 | return; 526 | 527 | if (bd->pFontSampler) { bd->pFontSampler->Release(); bd->pFontSampler = NULL; } 528 | if (bd->pFontTextureView) { bd->pFontTextureView->Release(); bd->pFontTextureView = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied data->pFontTextureView to io.Fonts->TexID so let's clear that as well. 529 | if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; } 530 | if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; } 531 | if (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = NULL; } 532 | if (bd->pDepthStencilState) { bd->pDepthStencilState->Release(); bd->pDepthStencilState = NULL; } 533 | if (bd->pRasterizerState) { bd->pRasterizerState->Release(); bd->pRasterizerState = NULL; } 534 | if (bd->pPixelShader) { bd->pPixelShader->Release(); bd->pPixelShader = NULL; } 535 | if (bd->pVertexConstantBuffer) { bd->pVertexConstantBuffer->Release(); bd->pVertexConstantBuffer = NULL; } 536 | if (bd->pInputLayout) { bd->pInputLayout->Release(); bd->pInputLayout = NULL; } 537 | if (bd->pVertexShader) { bd->pVertexShader->Release(); bd->pVertexShader = NULL; } 538 | } 539 | 540 | bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context) 541 | { 542 | ImGuiIO& io = ImGui::GetIO(); 543 | IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!"); 544 | 545 | // Setup backend capabilities flags 546 | ImGui_ImplDX11_Data* bd = IM_NEW(ImGui_ImplDX11_Data)(); 547 | io.BackendRendererUserData = (void*)bd; 548 | io.BackendRendererName = "imgui_impl_dx11"; 549 | io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. 550 | 551 | // Get factory from device 552 | IDXGIDevice* pDXGIDevice = NULL; 553 | IDXGIAdapter* pDXGIAdapter = NULL; 554 | IDXGIFactory* pFactory = NULL; 555 | 556 | if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK) 557 | if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK) 558 | if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK) 559 | { 560 | bd->pd3dDevice = device; 561 | bd->pd3dDeviceContext = device_context; 562 | bd->pFactory = pFactory; 563 | } 564 | if (pDXGIDevice) pDXGIDevice->Release(); 565 | if (pDXGIAdapter) pDXGIAdapter->Release(); 566 | bd->pd3dDevice->AddRef(); 567 | bd->pd3dDeviceContext->AddRef(); 568 | 569 | return true; 570 | } 571 | 572 | void ImGui_ImplDX11_Shutdown() 573 | { 574 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); 575 | IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?"); 576 | ImGuiIO& io = ImGui::GetIO(); 577 | 578 | ImGui_ImplDX11_InvalidateDeviceObjects(); 579 | if (bd->pFactory) { bd->pFactory->Release(); } 580 | if (bd->pd3dDevice) { bd->pd3dDevice->Release(); } 581 | if (bd->pd3dDeviceContext) { bd->pd3dDeviceContext->Release(); } 582 | io.BackendRendererName = NULL; 583 | io.BackendRendererUserData = NULL; 584 | IM_DELETE(bd); 585 | } 586 | 587 | void ImGui_ImplDX11_NewFrame() 588 | { 589 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); 590 | IM_ASSERT(bd != NULL && "Did you call ImGui_ImplDX11_Init()?"); 591 | 592 | if (!bd->pFontSampler) 593 | ImGui_ImplDX11_CreateDeviceObjects(); 594 | } 595 | -------------------------------------------------------------------------------- /dwm overlay/imgui/imgui_impl_dx11.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Renderer Backend for DirectX11 2 | // This needs to be used along with a Platform Backend (e.g. Win32) 3 | 4 | // Implemented features: 5 | // [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID! 6 | // [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices. 7 | 8 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 9 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. 10 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 11 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 12 | 13 | #pragma once 14 | #include "imgui.h" // IMGUI_IMPL_API 15 | 16 | struct ID3D11Device; 17 | struct ID3D11DeviceContext; 18 | 19 | IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context); 20 | IMGUI_IMPL_API void ImGui_ImplDX11_Shutdown(); 21 | IMGUI_IMPL_API void ImGui_ImplDX11_NewFrame(); 22 | IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data); 23 | 24 | // Use if you want to reset your rendering device without losing Dear ImGui state. 25 | IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects(); 26 | IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects(); 27 | -------------------------------------------------------------------------------- /dwm overlay/imgui/imgui_impl_win32.cpp: -------------------------------------------------------------------------------- 1 | // dear imgui: Platform Backend for Windows (standard windows API for 32 and 64 bits applications) 2 | // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) 3 | 4 | // Implemented features: 5 | // [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui) 6 | // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. 7 | // [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE). 8 | // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. 9 | 10 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 11 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. 12 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 13 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 14 | 15 | #include "imgui.h" 16 | #include "imgui_impl_win32.h" 17 | #ifndef WIN32_LEAN_AND_MEAN 18 | #define WIN32_LEAN_AND_MEAN 19 | #endif 20 | #include 21 | #include 22 | #include 23 | 24 | // Configuration flags to add in your imconfig.h file: 25 | //#define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD // Disable gamepad support. This was meaningful before <1.81 but we now load XInput dynamically so the option is now less relevant. 26 | 27 | // Using XInput for gamepad (will load DLL dynamically) 28 | #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD 29 | #include 30 | typedef DWORD (WINAPI *PFN_XInputGetCapabilities)(DWORD, DWORD, XINPUT_CAPABILITIES*); 31 | typedef DWORD (WINAPI *PFN_XInputGetState)(DWORD, XINPUT_STATE*); 32 | #endif 33 | 34 | // CHANGELOG 35 | // (minor and older changes stripped away, please see git history for details) 36 | // 2021-08-17: Calling io.AddFocusEvent() on WM_SETFOCUS/WM_KILLFOCUS messages. 37 | // 2021-08-02: Inputs: Fixed keyboard modifiers being reported when host windo doesn't have focus. 38 | // 2021-07-29: Inputs: MousePos is correctly reported when the host platform window is hovered but not focused (using TrackMouseEvent() to receive WM_MOUSELEAVE events). 39 | // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). 40 | // 2021-06-08: Fixed ImGui_ImplWin32_EnableDpiAwareness() and ImGui_ImplWin32_GetDpiScaleForMonitor() to handle Windows 8.1/10 features without a manifest (per-monitor DPI, and properly calls SetProcessDpiAwareness() on 8.1). 41 | // 2021-03-23: Inputs: Clearing keyboard down array when losing focus (WM_KILLFOCUS). 42 | // 2021-02-18: Added ImGui_ImplWin32_EnableAlphaCompositing(). Non Visual Studio users will need to link with dwmapi.lib (MinGW/gcc: use -ldwmapi). 43 | // 2021-02-17: Fixed ImGui_ImplWin32_EnableDpiAwareness() attempting to get SetProcessDpiAwareness from shcore.dll on Windows 8 whereas it is only supported on Windows 8.1. 44 | // 2021-01-25: Inputs: Dynamically loading XInput DLL. 45 | // 2020-12-04: Misc: Fixed setting of io.DisplaySize to invalid/uninitialized data when after hwnd has been closed. 46 | // 2020-03-03: Inputs: Calling AddInputCharacterUTF16() to support surrogate pairs leading to codepoint >= 0x10000 (for more complete CJK inputs) 47 | // 2020-02-17: Added ImGui_ImplWin32_EnableDpiAwareness(), ImGui_ImplWin32_GetDpiScaleForHwnd(), ImGui_ImplWin32_GetDpiScaleForMonitor() helper functions. 48 | // 2020-01-14: Inputs: Added support for #define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD/IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT. 49 | // 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor. 50 | // 2019-05-11: Inputs: Don't filter value from WM_CHAR before calling AddInputCharacter(). 51 | // 2019-01-17: Misc: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent. 52 | // 2019-01-17: Inputs: Added support for mouse buttons 4 and 5 via WM_XBUTTON* messages. 53 | // 2019-01-15: Inputs: Added support for XInput gamepads (if ImGuiConfigFlags_NavEnableGamepad is set by user application). 54 | // 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window. 55 | // 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor. 56 | // 2018-06-10: Inputs: Fixed handling of mouse wheel messages to support fine position messages (typically sent by track-pads). 57 | // 2018-06-08: Misc: Extracted imgui_impl_win32.cpp/.h away from the old combined DX9/DX10/DX11/DX12 examples. 58 | // 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors and ImGuiBackendFlags_HasSetMousePos flags + honor ImGuiConfigFlags_NoMouseCursorChange flag. 59 | // 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling). 60 | // 2018-02-06: Inputs: Added mapping for ImGuiKey_Space. 61 | // 2018-02-06: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set). 62 | // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. 63 | // 2018-01-20: Inputs: Added Horizontal Mouse Wheel support. 64 | // 2018-01-08: Inputs: Added mapping for ImGuiKey_Insert. 65 | // 2018-01-05: Inputs: Added WM_LBUTTONDBLCLK double-click handlers for window classes with the CS_DBLCLKS flag. 66 | // 2017-10-23: Inputs: Added WM_SYSKEYDOWN / WM_SYSKEYUP handlers so e.g. the VK_MENU key can be read. 67 | // 2017-10-23: Inputs: Using Win32 ::SetCapture/::GetCapture() to retrieve mouse positions outside the client area when dragging. 68 | // 2016-11-12: Inputs: Only call Win32 ::SetCursor(NULL) when io.MouseDrawCursor is set. 69 | 70 | struct ImGui_ImplWin32_Data 71 | { 72 | HWND hWnd; 73 | HWND MouseHwnd; 74 | bool MouseTracked; 75 | INT64 Time; 76 | INT64 TicksPerSecond; 77 | ImGuiMouseCursor LastMouseCursor; 78 | bool HasGamepad; 79 | bool WantUpdateHasGamepad; 80 | 81 | #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD 82 | HMODULE XInputDLL; 83 | PFN_XInputGetCapabilities XInputGetCapabilities; 84 | PFN_XInputGetState XInputGetState; 85 | #endif 86 | 87 | ImGui_ImplWin32_Data() { memset(this, 0, sizeof(*this)); } 88 | }; 89 | 90 | // Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts 91 | // It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. 92 | // FIXME: multi-context support is not well tested and probably dysfunctional in this backend. 93 | // FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context. 94 | static ImGui_ImplWin32_Data* ImGui_ImplWin32_GetBackendData() 95 | { 96 | return ImGui::GetCurrentContext() ? (ImGui_ImplWin32_Data*)ImGui::GetIO().BackendPlatformUserData : NULL; 97 | } 98 | 99 | // Functions 100 | bool ImGui_ImplWin32_Init(void* hwnd) 101 | { 102 | ImGuiIO& io = ImGui::GetIO(); 103 | IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!"); 104 | 105 | INT64 perf_frequency, perf_counter; 106 | if (!::QueryPerformanceFrequency((LARGE_INTEGER*)&perf_frequency)) 107 | return false; 108 | if (!::QueryPerformanceCounter((LARGE_INTEGER*)&perf_counter)) 109 | return false; 110 | 111 | // Setup backend capabilities flags 112 | ImGui_ImplWin32_Data* bd = IM_NEW(ImGui_ImplWin32_Data)(); 113 | io.BackendPlatformUserData = (void*)bd; 114 | io.BackendPlatformName = "imgui_impl_win32"; 115 | io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) 116 | io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) 117 | 118 | bd->hWnd = (HWND)hwnd; 119 | bd->WantUpdateHasGamepad = true; 120 | bd->TicksPerSecond = perf_frequency; 121 | bd->Time = perf_counter; 122 | bd->LastMouseCursor = ImGuiMouseCursor_COUNT; 123 | 124 | io.ImeWindowHandle = hwnd; 125 | 126 | // Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime. 127 | io.KeyMap[ImGuiKey_Tab] = VK_TAB; 128 | io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT; 129 | io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT; 130 | io.KeyMap[ImGuiKey_UpArrow] = VK_UP; 131 | io.KeyMap[ImGuiKey_DownArrow] = VK_DOWN; 132 | io.KeyMap[ImGuiKey_PageUp] = VK_PRIOR; 133 | io.KeyMap[ImGuiKey_PageDown] = VK_NEXT; 134 | io.KeyMap[ImGuiKey_Home] = VK_HOME; 135 | io.KeyMap[ImGuiKey_End] = VK_END; 136 | io.KeyMap[ImGuiKey_Insert] = VK_INSERT; 137 | io.KeyMap[ImGuiKey_Delete] = VK_DELETE; 138 | io.KeyMap[ImGuiKey_Backspace] = VK_BACK; 139 | io.KeyMap[ImGuiKey_Space] = VK_SPACE; 140 | io.KeyMap[ImGuiKey_Enter] = VK_RETURN; 141 | io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE; 142 | io.KeyMap[ImGuiKey_KeyPadEnter] = VK_RETURN; 143 | io.KeyMap[ImGuiKey_A] = 'A'; 144 | io.KeyMap[ImGuiKey_C] = 'C'; 145 | io.KeyMap[ImGuiKey_V] = 'V'; 146 | io.KeyMap[ImGuiKey_X] = 'X'; 147 | io.KeyMap[ImGuiKey_Y] = 'Y'; 148 | io.KeyMap[ImGuiKey_Z] = 'Z'; 149 | 150 | // Dynamically load XInput library 151 | #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD 152 | const char* xinput_dll_names[] = 153 | { 154 | "xinput1_4.dll", // Windows 8+ 155 | "xinput1_3.dll", // DirectX SDK 156 | "xinput9_1_0.dll", // Windows Vista, Windows 7 157 | "xinput1_2.dll", // DirectX SDK 158 | "xinput1_1.dll" // DirectX SDK 159 | }; 160 | for (int n = 0; n < IM_ARRAYSIZE(xinput_dll_names); n++) 161 | if (HMODULE dll = ::LoadLibraryA(xinput_dll_names[n])) 162 | { 163 | bd->XInputDLL = dll; 164 | bd->XInputGetCapabilities = (PFN_XInputGetCapabilities)::GetProcAddress(dll, "XInputGetCapabilities"); 165 | bd->XInputGetState = (PFN_XInputGetState)::GetProcAddress(dll, "XInputGetState"); 166 | break; 167 | } 168 | #endif // IMGUI_IMPL_WIN32_DISABLE_GAMEPAD 169 | 170 | return true; 171 | } 172 | 173 | void ImGui_ImplWin32_Shutdown() 174 | { 175 | ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); 176 | IM_ASSERT(bd != NULL && "No platform backend to shutdown, or already shutdown?"); 177 | ImGuiIO& io = ImGui::GetIO(); 178 | 179 | // Unload XInput library 180 | #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD 181 | if (bd->XInputDLL) 182 | ::FreeLibrary(bd->XInputDLL); 183 | #endif // IMGUI_IMPL_WIN32_DISABLE_GAMEPAD 184 | 185 | io.BackendPlatformName = NULL; 186 | io.BackendPlatformUserData = NULL; 187 | IM_DELETE(bd); 188 | } 189 | 190 | static bool ImGui_ImplWin32_UpdateMouseCursor() 191 | { 192 | ImGuiIO& io = ImGui::GetIO(); 193 | if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) 194 | return false; 195 | 196 | ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); 197 | if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) 198 | { 199 | // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor 200 | ::SetCursor(NULL); 201 | } 202 | else 203 | { 204 | // Show OS mouse cursor 205 | LPTSTR win32_cursor = IDC_ARROW; 206 | switch (imgui_cursor) 207 | { 208 | case ImGuiMouseCursor_Arrow: win32_cursor = IDC_ARROW; break; 209 | case ImGuiMouseCursor_TextInput: win32_cursor = IDC_IBEAM; break; 210 | case ImGuiMouseCursor_ResizeAll: win32_cursor = IDC_SIZEALL; break; 211 | case ImGuiMouseCursor_ResizeEW: win32_cursor = IDC_SIZEWE; break; 212 | case ImGuiMouseCursor_ResizeNS: win32_cursor = IDC_SIZENS; break; 213 | case ImGuiMouseCursor_ResizeNESW: win32_cursor = IDC_SIZENESW; break; 214 | case ImGuiMouseCursor_ResizeNWSE: win32_cursor = IDC_SIZENWSE; break; 215 | case ImGuiMouseCursor_Hand: win32_cursor = IDC_HAND; break; 216 | case ImGuiMouseCursor_NotAllowed: win32_cursor = IDC_NO; break; 217 | } 218 | ::SetCursor(::LoadCursor(NULL, win32_cursor)); 219 | } 220 | return true; 221 | } 222 | 223 | static void ImGui_ImplWin32_UpdateMousePos() 224 | { 225 | ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); 226 | ImGuiIO& io = ImGui::GetIO(); 227 | IM_ASSERT(bd->hWnd != 0); 228 | 229 | const ImVec2 mouse_pos_prev = io.MousePos; 230 | io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); 231 | 232 | // Obtain focused and hovered window. We forward mouse input when focused or when hovered (and no other window is capturing) 233 | HWND focused_window = ::GetForegroundWindow(); 234 | HWND hovered_window = bd->MouseHwnd; 235 | HWND mouse_window = NULL; 236 | if (hovered_window && (hovered_window == bd->hWnd || ::IsChild(hovered_window, bd->hWnd))) 237 | mouse_window = hovered_window; 238 | else if (focused_window && (focused_window == bd->hWnd || ::IsChild(focused_window, bd->hWnd))) 239 | mouse_window = focused_window; 240 | if (mouse_window == NULL) 241 | return; 242 | 243 | // Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) 244 | if (io.WantSetMousePos) 245 | { 246 | POINT pos = { (int)mouse_pos_prev.x, (int)mouse_pos_prev.y }; 247 | if (::ClientToScreen(bd->hWnd, &pos)) 248 | ::SetCursorPos(pos.x, pos.y); 249 | } 250 | 251 | // Set Dear ImGui mouse position from OS position 252 | POINT pos; 253 | if (::GetCursorPos(&pos) && ::ScreenToClient(mouse_window, &pos)) 254 | io.MousePos = ImVec2((float)pos.x, (float)pos.y); 255 | } 256 | 257 | // Gamepad navigation mapping 258 | static void ImGui_ImplWin32_UpdateGamepads() 259 | { 260 | #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD 261 | ImGuiIO& io = ImGui::GetIO(); 262 | ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); 263 | memset(io.NavInputs, 0, sizeof(io.NavInputs)); 264 | if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) 265 | return; 266 | 267 | // Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow. 268 | // Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE. 269 | if (bd->WantUpdateHasGamepad) 270 | { 271 | XINPUT_CAPABILITIES caps; 272 | bd->HasGamepad = bd->XInputGetCapabilities ? (bd->XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS) : false; 273 | bd->WantUpdateHasGamepad = false; 274 | } 275 | 276 | io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; 277 | XINPUT_STATE xinput_state; 278 | if (bd->HasGamepad && bd->XInputGetState && bd->XInputGetState(0, &xinput_state) == ERROR_SUCCESS) 279 | { 280 | const XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad; 281 | io.BackendFlags |= ImGuiBackendFlags_HasGamepad; 282 | 283 | #define MAP_BUTTON(NAV_NO, BUTTON_ENUM) { io.NavInputs[NAV_NO] = (gamepad.wButtons & BUTTON_ENUM) ? 1.0f : 0.0f; } 284 | #define MAP_ANALOG(NAV_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; } 285 | MAP_BUTTON(ImGuiNavInput_Activate, XINPUT_GAMEPAD_A); // Cross / A 286 | MAP_BUTTON(ImGuiNavInput_Cancel, XINPUT_GAMEPAD_B); // Circle / B 287 | MAP_BUTTON(ImGuiNavInput_Menu, XINPUT_GAMEPAD_X); // Square / X 288 | MAP_BUTTON(ImGuiNavInput_Input, XINPUT_GAMEPAD_Y); // Triangle / Y 289 | MAP_BUTTON(ImGuiNavInput_DpadLeft, XINPUT_GAMEPAD_DPAD_LEFT); // D-Pad Left 290 | MAP_BUTTON(ImGuiNavInput_DpadRight, XINPUT_GAMEPAD_DPAD_RIGHT); // D-Pad Right 291 | MAP_BUTTON(ImGuiNavInput_DpadUp, XINPUT_GAMEPAD_DPAD_UP); // D-Pad Up 292 | MAP_BUTTON(ImGuiNavInput_DpadDown, XINPUT_GAMEPAD_DPAD_DOWN); // D-Pad Down 293 | MAP_BUTTON(ImGuiNavInput_FocusPrev, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB 294 | MAP_BUTTON(ImGuiNavInput_FocusNext, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB 295 | MAP_BUTTON(ImGuiNavInput_TweakSlow, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB 296 | MAP_BUTTON(ImGuiNavInput_TweakFast, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB 297 | MAP_ANALOG(ImGuiNavInput_LStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); 298 | MAP_ANALOG(ImGuiNavInput_LStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); 299 | MAP_ANALOG(ImGuiNavInput_LStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); 300 | MAP_ANALOG(ImGuiNavInput_LStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32767); 301 | #undef MAP_BUTTON 302 | #undef MAP_ANALOG 303 | } 304 | #endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD 305 | } 306 | 307 | void ImGui_ImplWin32_NewFrame() 308 | { 309 | ImGuiIO& io = ImGui::GetIO(); 310 | ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); 311 | IM_ASSERT(bd != NULL && "Did you call ImGui_ImplWin32_Init()?"); 312 | 313 | // Setup display size (every frame to accommodate for window resizing) 314 | RECT rect = { 0, 0, 0, 0 }; 315 | ::GetClientRect(bd->hWnd, &rect); 316 | io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top)); 317 | 318 | // Setup time step 319 | INT64 current_time = 0; 320 | ::QueryPerformanceCounter((LARGE_INTEGER*)¤t_time); 321 | io.DeltaTime = (float)(current_time - bd->Time) / bd->TicksPerSecond; 322 | bd->Time = current_time; 323 | 324 | // Update OS mouse position 325 | ImGui_ImplWin32_UpdateMousePos(); 326 | 327 | // Update OS mouse cursor with the cursor requested by imgui 328 | ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor(); 329 | if (bd->LastMouseCursor != mouse_cursor) 330 | { 331 | bd->LastMouseCursor = mouse_cursor; 332 | ImGui_ImplWin32_UpdateMouseCursor(); 333 | } 334 | 335 | // Update game controllers (if enabled and available) 336 | ImGui_ImplWin32_UpdateGamepads(); 337 | } 338 | 339 | // Allow compilation with old Windows SDK. MinGW doesn't have default _WIN32_WINNT/WINVER versions. 340 | #ifndef WM_MOUSEHWHEEL 341 | #define WM_MOUSEHWHEEL 0x020E 342 | #endif 343 | #ifndef DBT_DEVNODES_CHANGED 344 | #define DBT_DEVNODES_CHANGED 0x0007 345 | #endif 346 | 347 | // Win32 message handler (process Win32 mouse/keyboard inputs, etc.) 348 | // Call from your application's message handler. 349 | // When implementing your own backend, you can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if Dear ImGui wants to use your inputs. 350 | // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application. 351 | // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application. 352 | // Generally you may always pass all inputs to Dear ImGui, and hide them from your application based on those two flags. 353 | // PS: In this Win32 handler, we use the capture API (GetCapture/SetCapture/ReleaseCapture) to be able to read mouse coordinates when dragging mouse outside of our window bounds. 354 | // PS: We treat DBLCLK messages as regular mouse down messages, so this code will work on windows classes that have the CS_DBLCLKS flag set. Our own example app code doesn't set this flag. 355 | #if 0 356 | // Copy this line into your .cpp file to forward declare the function. 357 | extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); 358 | #endif 359 | IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 360 | { 361 | if (ImGui::GetCurrentContext() == NULL) 362 | return 0; 363 | 364 | ImGuiIO& io = ImGui::GetIO(); 365 | ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); 366 | 367 | switch (msg) 368 | { 369 | case WM_MOUSEMOVE: 370 | // We need to call TrackMouseEvent in order to receive WM_MOUSELEAVE events 371 | bd->MouseHwnd = hwnd; 372 | if (!bd->MouseTracked) 373 | { 374 | TRACKMOUSEEVENT tme = { sizeof(tme), TME_LEAVE, hwnd, 0 }; 375 | ::TrackMouseEvent(&tme); 376 | bd->MouseTracked = true; 377 | } 378 | break; 379 | case WM_MOUSELEAVE: 380 | if (bd->MouseHwnd == hwnd) 381 | bd->MouseHwnd = NULL; 382 | bd->MouseTracked = false; 383 | break; 384 | case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: 385 | case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: 386 | case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: 387 | case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: 388 | { 389 | int button = 0; 390 | if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { button = 0; } 391 | if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1; } 392 | if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { button = 2; } 393 | if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONDBLCLK) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; } 394 | if (!ImGui::IsAnyMouseDown() && ::GetCapture() == NULL) 395 | ::SetCapture(hwnd); 396 | io.MouseDown[button] = true; 397 | return 0; 398 | } 399 | case WM_LBUTTONUP: 400 | case WM_RBUTTONUP: 401 | case WM_MBUTTONUP: 402 | case WM_XBUTTONUP: 403 | { 404 | int button = 0; 405 | if (msg == WM_LBUTTONUP) { button = 0; } 406 | if (msg == WM_RBUTTONUP) { button = 1; } 407 | if (msg == WM_MBUTTONUP) { button = 2; } 408 | if (msg == WM_XBUTTONUP) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; } 409 | io.MouseDown[button] = false; 410 | if (!ImGui::IsAnyMouseDown() && ::GetCapture() == hwnd) 411 | ::ReleaseCapture(); 412 | return 0; 413 | } 414 | case WM_MOUSEWHEEL: 415 | io.MouseWheel += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA; 416 | return 0; 417 | case WM_MOUSEHWHEEL: 418 | io.MouseWheelH += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA; 419 | return 0; 420 | case WM_KEYDOWN: 421 | case WM_KEYUP: 422 | case WM_SYSKEYDOWN: 423 | case WM_SYSKEYUP: 424 | { 425 | bool down = (msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN); 426 | if (wParam < 256) 427 | io.KeysDown[wParam] = down; 428 | if (wParam == VK_CONTROL) 429 | io.KeyCtrl = down; 430 | if (wParam == VK_SHIFT) 431 | io.KeyShift = down; 432 | if (wParam == VK_MENU) 433 | io.KeyAlt = down; 434 | return 0; 435 | } 436 | case WM_SETFOCUS: 437 | case WM_KILLFOCUS: 438 | io.AddFocusEvent(msg == WM_SETFOCUS); 439 | return 0; 440 | case WM_CHAR: 441 | // You can also use ToAscii()+GetKeyboardState() to retrieve characters. 442 | if (wParam > 0 && wParam < 0x10000) 443 | io.AddInputCharacterUTF16((unsigned short)wParam); 444 | return 0; 445 | case WM_SETCURSOR: 446 | if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor()) 447 | return 1; 448 | return 0; 449 | case WM_DEVICECHANGE: 450 | if ((UINT)wParam == DBT_DEVNODES_CHANGED) 451 | bd->WantUpdateHasGamepad = true; 452 | return 0; 453 | } 454 | return 0; 455 | } 456 | 457 | 458 | //-------------------------------------------------------------------------------------------------------- 459 | // DPI-related helpers (optional) 460 | //-------------------------------------------------------------------------------------------------------- 461 | // - Use to enable DPI awareness without having to create an application manifest. 462 | // - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps. 463 | // - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc. 464 | // but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime, 465 | // neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies. 466 | //--------------------------------------------------------------------------------------------------------- 467 | // This is the scheme successfully used by GLFW (from which we borrowed some of the code) and other apps aiming to be highly portable. 468 | // ImGui_ImplWin32_EnableDpiAwareness() is just a helper called by main.cpp, we don't call it automatically. 469 | // If you are trying to implement your own backend for your own engine, you may ignore that noise. 470 | //--------------------------------------------------------------------------------------------------------- 471 | 472 | // Perform our own check with RtlVerifyVersionInfo() instead of using functions from as they 473 | // require a manifest to be functional for checks above 8.1. See https://github.com/ocornut/imgui/issues/4200 474 | static BOOL _IsWindowsVersionOrGreater(WORD major, WORD minor, WORD) 475 | { 476 | typedef LONG(WINAPI* PFN_RtlVerifyVersionInfo)(OSVERSIONINFOEXW*, ULONG, ULONGLONG); 477 | static PFN_RtlVerifyVersionInfo RtlVerifyVersionInfoFn = NULL; 478 | if (RtlVerifyVersionInfoFn == NULL) 479 | if (HMODULE ntdllModule = ::GetModuleHandleA("ntdll.dll")) 480 | RtlVerifyVersionInfoFn = (PFN_RtlVerifyVersionInfo)GetProcAddress(ntdllModule, "RtlVerifyVersionInfo"); 481 | if (RtlVerifyVersionInfoFn == NULL) 482 | return FALSE; 483 | 484 | RTL_OSVERSIONINFOEXW versionInfo = { }; 485 | ULONGLONG conditionMask = 0; 486 | versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW); 487 | versionInfo.dwMajorVersion = major; 488 | versionInfo.dwMinorVersion = minor; 489 | VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); 490 | VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); 491 | return (RtlVerifyVersionInfoFn(&versionInfo, VER_MAJORVERSION | VER_MINORVERSION, conditionMask) == 0) ? TRUE : FALSE; 492 | } 493 | 494 | #define _IsWindowsVistaOrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0600), LOBYTE(0x0600), 0) // _WIN32_WINNT_VISTA 495 | #define _IsWindows8OrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0602), LOBYTE(0x0602), 0) // _WIN32_WINNT_WIN8 496 | #define _IsWindows8Point1OrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0603), LOBYTE(0x0603), 0) // _WIN32_WINNT_WINBLUE 497 | #define _IsWindows10OrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0A00), LOBYTE(0x0A00), 0) // _WIN32_WINNT_WINTHRESHOLD / _WIN32_WINNT_WIN10 498 | 499 | #ifndef DPI_ENUMS_DECLARED 500 | typedef enum { PROCESS_DPI_UNAWARE = 0, PROCESS_SYSTEM_DPI_AWARE = 1, PROCESS_PER_MONITOR_DPI_AWARE = 2 } PROCESS_DPI_AWARENESS; 501 | typedef enum { MDT_EFFECTIVE_DPI = 0, MDT_ANGULAR_DPI = 1, MDT_RAW_DPI = 2, MDT_DEFAULT = MDT_EFFECTIVE_DPI } MONITOR_DPI_TYPE; 502 | #endif 503 | #ifndef _DPI_AWARENESS_CONTEXTS_ 504 | DECLARE_HANDLE(DPI_AWARENESS_CONTEXT); 505 | #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE (DPI_AWARENESS_CONTEXT)-3 506 | #endif 507 | #ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 508 | #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 (DPI_AWARENESS_CONTEXT)-4 509 | #endif 510 | typedef HRESULT(WINAPI* PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); // Shcore.lib + dll, Windows 8.1+ 511 | typedef HRESULT(WINAPI* PFN_GetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*); // Shcore.lib + dll, Windows 8.1+ 512 | typedef DPI_AWARENESS_CONTEXT(WINAPI* PFN_SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); // User32.lib + dll, Windows 10 v1607+ (Creators Update) 513 | 514 | // Helper function to enable DPI awareness without setting up a manifest 515 | void ImGui_ImplWin32_EnableDpiAwareness() 516 | { 517 | if (_IsWindows10OrGreater()) 518 | { 519 | static HINSTANCE user32_dll = ::LoadLibraryA("user32.dll"); // Reference counted per-process 520 | if (PFN_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContextFn = (PFN_SetThreadDpiAwarenessContext)::GetProcAddress(user32_dll, "SetThreadDpiAwarenessContext")) 521 | { 522 | SetThreadDpiAwarenessContextFn(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); 523 | return; 524 | } 525 | } 526 | if (_IsWindows8Point1OrGreater()) 527 | { 528 | static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process 529 | if (PFN_SetProcessDpiAwareness SetProcessDpiAwarenessFn = (PFN_SetProcessDpiAwareness)::GetProcAddress(shcore_dll, "SetProcessDpiAwareness")) 530 | { 531 | SetProcessDpiAwarenessFn(PROCESS_PER_MONITOR_DPI_AWARE); 532 | return; 533 | } 534 | } 535 | #if _WIN32_WINNT >= 0x0600 536 | ::SetProcessDPIAware(); 537 | #endif 538 | } 539 | 540 | #if defined(_MSC_VER) && !defined(NOGDI) 541 | #pragma comment(lib, "gdi32") // Link with gdi32.lib for GetDeviceCaps(). MinGW will require linking with '-lgdi32' 542 | #endif 543 | 544 | float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor) 545 | { 546 | UINT xdpi = 96, ydpi = 96; 547 | if (_IsWindows8Point1OrGreater()) 548 | { 549 | static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process 550 | static PFN_GetDpiForMonitor GetDpiForMonitorFn = NULL; 551 | if (GetDpiForMonitorFn == NULL && shcore_dll != NULL) 552 | GetDpiForMonitorFn = (PFN_GetDpiForMonitor)::GetProcAddress(shcore_dll, "GetDpiForMonitor"); 553 | if (GetDpiForMonitorFn != NULL) 554 | { 555 | GetDpiForMonitorFn((HMONITOR)monitor, MDT_EFFECTIVE_DPI, &xdpi, &ydpi); 556 | IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert! 557 | return xdpi / 96.0f; 558 | } 559 | } 560 | #ifndef NOGDI 561 | const HDC dc = ::GetDC(NULL); 562 | xdpi = ::GetDeviceCaps(dc, LOGPIXELSX); 563 | ydpi = ::GetDeviceCaps(dc, LOGPIXELSY); 564 | IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert! 565 | ::ReleaseDC(NULL, dc); 566 | #endif 567 | return xdpi / 96.0f; 568 | } 569 | 570 | float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd) 571 | { 572 | HMONITOR monitor = ::MonitorFromWindow((HWND)hwnd, MONITOR_DEFAULTTONEAREST); 573 | return ImGui_ImplWin32_GetDpiScaleForMonitor(monitor); 574 | } 575 | 576 | //--------------------------------------------------------------------------------------------------------- 577 | // Transparency related helpers (optional) 578 | //-------------------------------------------------------------------------------------------------------- 579 | 580 | #if defined(_MSC_VER) 581 | #pragma comment(lib, "dwmapi") // Link with dwmapi.lib. MinGW will require linking with '-ldwmapi' 582 | #endif 583 | 584 | // [experimental] 585 | // Borrowed from GLFW's function updateFramebufferTransparency() in src/win32_window.c 586 | // (the Dwm* functions are Vista era functions but we are borrowing logic from GLFW) 587 | void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd) 588 | { 589 | if (!_IsWindowsVistaOrGreater()) 590 | return; 591 | 592 | BOOL composition; 593 | if (FAILED(::DwmIsCompositionEnabled(&composition)) || !composition) 594 | return; 595 | 596 | BOOL opaque; 597 | DWORD color; 598 | if (_IsWindows8OrGreater() || (SUCCEEDED(::DwmGetColorizationColor(&color, &opaque)) && !opaque)) 599 | { 600 | HRGN region = ::CreateRectRgn(0, 0, -1, -1); 601 | DWM_BLURBEHIND bb = {}; 602 | bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; 603 | bb.hRgnBlur = region; 604 | bb.fEnable = TRUE; 605 | ::DwmEnableBlurBehindWindow((HWND)hwnd, &bb); 606 | ::DeleteObject(region); 607 | } 608 | else 609 | { 610 | DWM_BLURBEHIND bb = {}; 611 | bb.dwFlags = DWM_BB_ENABLE; 612 | ::DwmEnableBlurBehindWindow((HWND)hwnd, &bb); 613 | } 614 | } 615 | 616 | //--------------------------------------------------------------------------------------------------------- 617 | -------------------------------------------------------------------------------- /dwm overlay/imgui/imgui_impl_win32.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Platform Backend for Windows (standard windows API for 32 and 64 bits applications) 2 | // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) 3 | 4 | // Implemented features: 5 | // [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui) 6 | // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. 7 | // [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE). 8 | // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. 9 | 10 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 11 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. 12 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 13 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 14 | 15 | #pragma once 16 | #include "imgui.h" // IMGUI_IMPL_API 17 | 18 | IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd); 19 | IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown(); 20 | IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame(); 21 | 22 | // Win32 message handler your application need to call. 23 | // - Intentionally commented out in a '#if 0' block to avoid dragging dependencies on from this helper. 24 | // - You should COPY the line below into your .cpp code to forward declare the function and then you can call it. 25 | #if 0 26 | extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); 27 | #endif 28 | 29 | // DPI-related helpers (optional) 30 | // - Use to enable DPI awareness without having to create an application manifest. 31 | // - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps. 32 | // - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc. 33 | // but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime, 34 | // neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies. 35 | IMGUI_IMPL_API void ImGui_ImplWin32_EnableDpiAwareness(); 36 | IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd); // HWND hwnd 37 | IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // HMONITOR monitor 38 | 39 | // Transparency related helpers (optional) [experimental] 40 | // - Use to enable alpha compositing transparency with the desktop. 41 | // - Use together with e.g. clearing your framebuffer with zero-alpha. 42 | IMGUI_IMPL_API void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd); // HWND hwnd 43 | -------------------------------------------------------------------------------- /dwm overlay/imgui/imstb_rectpack.h: -------------------------------------------------------------------------------- 1 | // [DEAR IMGUI] 2 | // This is a slightly modified version of stb_rect_pack.h 1.00. 3 | // Those changes would need to be pushed into nothings/stb: 4 | // - Added STBRP__CDECL 5 | // Grep for [DEAR IMGUI] to find the changes. 6 | 7 | // stb_rect_pack.h - v1.00 - public domain - rectangle packing 8 | // Sean Barrett 2014 9 | // 10 | // Useful for e.g. packing rectangular textures into an atlas. 11 | // Does not do rotation. 12 | // 13 | // Not necessarily the awesomest packing method, but better than 14 | // the totally naive one in stb_truetype (which is primarily what 15 | // this is meant to replace). 16 | // 17 | // Has only had a few tests run, may have issues. 18 | // 19 | // More docs to come. 20 | // 21 | // No memory allocations; uses qsort() and assert() from stdlib. 22 | // Can override those by defining STBRP_SORT and STBRP_ASSERT. 23 | // 24 | // This library currently uses the Skyline Bottom-Left algorithm. 25 | // 26 | // Please note: better rectangle packers are welcome! Please 27 | // implement them to the same API, but with a different init 28 | // function. 29 | // 30 | // Credits 31 | // 32 | // Library 33 | // Sean Barrett 34 | // Minor features 35 | // Martins Mozeiko 36 | // github:IntellectualKitty 37 | // 38 | // Bugfixes / warning fixes 39 | // Jeremy Jaussaud 40 | // Fabian Giesen 41 | // 42 | // Version history: 43 | // 44 | // 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles 45 | // 0.99 (2019-02-07) warning fixes 46 | // 0.11 (2017-03-03) return packing success/fail result 47 | // 0.10 (2016-10-25) remove cast-away-const to avoid warnings 48 | // 0.09 (2016-08-27) fix compiler warnings 49 | // 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0) 50 | // 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0) 51 | // 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort 52 | // 0.05: added STBRP_ASSERT to allow replacing assert 53 | // 0.04: fixed minor bug in STBRP_LARGE_RECTS support 54 | // 0.01: initial release 55 | // 56 | // LICENSE 57 | // 58 | // See end of file for license information. 59 | 60 | ////////////////////////////////////////////////////////////////////////////// 61 | // 62 | // INCLUDE SECTION 63 | // 64 | 65 | #ifndef STB_INCLUDE_STB_RECT_PACK_H 66 | #define STB_INCLUDE_STB_RECT_PACK_H 67 | 68 | #define STB_RECT_PACK_VERSION 1 69 | 70 | #ifdef STBRP_STATIC 71 | #define STBRP_DEF static 72 | #else 73 | #define STBRP_DEF extern 74 | #endif 75 | 76 | #ifdef __cplusplus 77 | extern "C" { 78 | #endif 79 | 80 | typedef struct stbrp_context stbrp_context; 81 | typedef struct stbrp_node stbrp_node; 82 | typedef struct stbrp_rect stbrp_rect; 83 | 84 | #ifdef STBRP_LARGE_RECTS 85 | typedef int stbrp_coord; 86 | #else 87 | typedef unsigned short stbrp_coord; 88 | #endif 89 | 90 | STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); 91 | // Assign packed locations to rectangles. The rectangles are of type 92 | // 'stbrp_rect' defined below, stored in the array 'rects', and there 93 | // are 'num_rects' many of them. 94 | // 95 | // Rectangles which are successfully packed have the 'was_packed' flag 96 | // set to a non-zero value and 'x' and 'y' store the minimum location 97 | // on each axis (i.e. bottom-left in cartesian coordinates, top-left 98 | // if you imagine y increasing downwards). Rectangles which do not fit 99 | // have the 'was_packed' flag set to 0. 100 | // 101 | // You should not try to access the 'rects' array from another thread 102 | // while this function is running, as the function temporarily reorders 103 | // the array while it executes. 104 | // 105 | // To pack into another rectangle, you need to call stbrp_init_target 106 | // again. To continue packing into the same rectangle, you can call 107 | // this function again. Calling this multiple times with multiple rect 108 | // arrays will probably produce worse packing results than calling it 109 | // a single time with the full rectangle array, but the option is 110 | // available. 111 | // 112 | // The function returns 1 if all of the rectangles were successfully 113 | // packed and 0 otherwise. 114 | 115 | struct stbrp_rect 116 | { 117 | // reserved for your use: 118 | int id; 119 | 120 | // input: 121 | stbrp_coord w, h; 122 | 123 | // output: 124 | stbrp_coord x, y; 125 | int was_packed; // non-zero if valid packing 126 | 127 | }; // 16 bytes, nominally 128 | 129 | 130 | STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes); 131 | // Initialize a rectangle packer to: 132 | // pack a rectangle that is 'width' by 'height' in dimensions 133 | // using temporary storage provided by the array 'nodes', which is 'num_nodes' long 134 | // 135 | // You must call this function every time you start packing into a new target. 136 | // 137 | // There is no "shutdown" function. The 'nodes' memory must stay valid for 138 | // the following stbrp_pack_rects() call (or calls), but can be freed after 139 | // the call (or calls) finish. 140 | // 141 | // Note: to guarantee best results, either: 142 | // 1. make sure 'num_nodes' >= 'width' 143 | // or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' 144 | // 145 | // If you don't do either of the above things, widths will be quantized to multiples 146 | // of small integers to guarantee the algorithm doesn't run out of temporary storage. 147 | // 148 | // If you do #2, then the non-quantized algorithm will be used, but the algorithm 149 | // may run out of temporary storage and be unable to pack some rectangles. 150 | 151 | STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem); 152 | // Optionally call this function after init but before doing any packing to 153 | // change the handling of the out-of-temp-memory scenario, described above. 154 | // If you call init again, this will be reset to the default (false). 155 | 156 | 157 | STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic); 158 | // Optionally select which packing heuristic the library should use. Different 159 | // heuristics will produce better/worse results for different data sets. 160 | // If you call init again, this will be reset to the default. 161 | 162 | enum 163 | { 164 | STBRP_HEURISTIC_Skyline_default=0, 165 | STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, 166 | STBRP_HEURISTIC_Skyline_BF_sortHeight 167 | }; 168 | 169 | 170 | ////////////////////////////////////////////////////////////////////////////// 171 | // 172 | // the details of the following structures don't matter to you, but they must 173 | // be visible so you can handle the memory allocations for them 174 | 175 | struct stbrp_node 176 | { 177 | stbrp_coord x,y; 178 | stbrp_node *next; 179 | }; 180 | 181 | struct stbrp_context 182 | { 183 | int width; 184 | int height; 185 | int align; 186 | int init_mode; 187 | int heuristic; 188 | int num_nodes; 189 | stbrp_node *active_head; 190 | stbrp_node *free_head; 191 | stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' 192 | }; 193 | 194 | #ifdef __cplusplus 195 | } 196 | #endif 197 | 198 | #endif 199 | 200 | ////////////////////////////////////////////////////////////////////////////// 201 | // 202 | // IMPLEMENTATION SECTION 203 | // 204 | 205 | #ifdef STB_RECT_PACK_IMPLEMENTATION 206 | #ifndef STBRP_SORT 207 | #include 208 | #define STBRP_SORT qsort 209 | #endif 210 | 211 | #ifndef STBRP_ASSERT 212 | #include 213 | #define STBRP_ASSERT assert 214 | #endif 215 | 216 | // [DEAR IMGUI] Added STBRP__CDECL 217 | #ifdef _MSC_VER 218 | #define STBRP__NOTUSED(v) (void)(v) 219 | #define STBRP__CDECL __cdecl 220 | #else 221 | #define STBRP__NOTUSED(v) (void)sizeof(v) 222 | #define STBRP__CDECL 223 | #endif 224 | 225 | enum 226 | { 227 | STBRP__INIT_skyline = 1 228 | }; 229 | 230 | STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) 231 | { 232 | switch (context->init_mode) { 233 | case STBRP__INIT_skyline: 234 | STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); 235 | context->heuristic = heuristic; 236 | break; 237 | default: 238 | STBRP_ASSERT(0); 239 | } 240 | } 241 | 242 | STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem) 243 | { 244 | if (allow_out_of_mem) 245 | // if it's ok to run out of memory, then don't bother aligning them; 246 | // this gives better packing, but may fail due to OOM (even though 247 | // the rectangles easily fit). @TODO a smarter approach would be to only 248 | // quantize once we've hit OOM, then we could get rid of this parameter. 249 | context->align = 1; 250 | else { 251 | // if it's not ok to run out of memory, then quantize the widths 252 | // so that num_nodes is always enough nodes. 253 | // 254 | // I.e. num_nodes * align >= width 255 | // align >= width / num_nodes 256 | // align = ceil(width/num_nodes) 257 | 258 | context->align = (context->width + context->num_nodes-1) / context->num_nodes; 259 | } 260 | } 261 | 262 | STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes) 263 | { 264 | int i; 265 | #ifndef STBRP_LARGE_RECTS 266 | STBRP_ASSERT(width <= 0xffff && height <= 0xffff); 267 | #endif 268 | 269 | for (i=0; i < num_nodes-1; ++i) 270 | nodes[i].next = &nodes[i+1]; 271 | nodes[i].next = NULL; 272 | context->init_mode = STBRP__INIT_skyline; 273 | context->heuristic = STBRP_HEURISTIC_Skyline_default; 274 | context->free_head = &nodes[0]; 275 | context->active_head = &context->extra[0]; 276 | context->width = width; 277 | context->height = height; 278 | context->num_nodes = num_nodes; 279 | stbrp_setup_allow_out_of_mem(context, 0); 280 | 281 | // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) 282 | context->extra[0].x = 0; 283 | context->extra[0].y = 0; 284 | context->extra[0].next = &context->extra[1]; 285 | context->extra[1].x = (stbrp_coord) width; 286 | #ifdef STBRP_LARGE_RECTS 287 | context->extra[1].y = (1<<30); 288 | #else 289 | context->extra[1].y = 65535; 290 | #endif 291 | context->extra[1].next = NULL; 292 | } 293 | 294 | // find minimum y position if it starts at x1 295 | static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste) 296 | { 297 | stbrp_node *node = first; 298 | int x1 = x0 + width; 299 | int min_y, visited_width, waste_area; 300 | 301 | STBRP__NOTUSED(c); 302 | 303 | STBRP_ASSERT(first->x <= x0); 304 | 305 | #if 0 306 | // skip in case we're past the node 307 | while (node->next->x <= x0) 308 | ++node; 309 | #else 310 | STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency 311 | #endif 312 | 313 | STBRP_ASSERT(node->x <= x0); 314 | 315 | min_y = 0; 316 | waste_area = 0; 317 | visited_width = 0; 318 | while (node->x < x1) { 319 | if (node->y > min_y) { 320 | // raise min_y higher. 321 | // we've accounted for all waste up to min_y, 322 | // but we'll now add more waste for everything we've visted 323 | waste_area += visited_width * (node->y - min_y); 324 | min_y = node->y; 325 | // the first time through, visited_width might be reduced 326 | if (node->x < x0) 327 | visited_width += node->next->x - x0; 328 | else 329 | visited_width += node->next->x - node->x; 330 | } else { 331 | // add waste area 332 | int under_width = node->next->x - node->x; 333 | if (under_width + visited_width > width) 334 | under_width = width - visited_width; 335 | waste_area += under_width * (min_y - node->y); 336 | visited_width += under_width; 337 | } 338 | node = node->next; 339 | } 340 | 341 | *pwaste = waste_area; 342 | return min_y; 343 | } 344 | 345 | typedef struct 346 | { 347 | int x,y; 348 | stbrp_node **prev_link; 349 | } stbrp__findresult; 350 | 351 | static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height) 352 | { 353 | int best_waste = (1<<30), best_x, best_y = (1 << 30); 354 | stbrp__findresult fr; 355 | stbrp_node **prev, *node, *tail, **best = NULL; 356 | 357 | // align to multiple of c->align 358 | width = (width + c->align - 1); 359 | width -= width % c->align; 360 | STBRP_ASSERT(width % c->align == 0); 361 | 362 | // if it can't possibly fit, bail immediately 363 | if (width > c->width || height > c->height) { 364 | fr.prev_link = NULL; 365 | fr.x = fr.y = 0; 366 | return fr; 367 | } 368 | 369 | node = c->active_head; 370 | prev = &c->active_head; 371 | while (node->x + width <= c->width) { 372 | int y,waste; 373 | y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste); 374 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL 375 | // bottom left 376 | if (y < best_y) { 377 | best_y = y; 378 | best = prev; 379 | } 380 | } else { 381 | // best-fit 382 | if (y + height <= c->height) { 383 | // can only use it if it first vertically 384 | if (y < best_y || (y == best_y && waste < best_waste)) { 385 | best_y = y; 386 | best_waste = waste; 387 | best = prev; 388 | } 389 | } 390 | } 391 | prev = &node->next; 392 | node = node->next; 393 | } 394 | 395 | best_x = (best == NULL) ? 0 : (*best)->x; 396 | 397 | // if doing best-fit (BF), we also have to try aligning right edge to each node position 398 | // 399 | // e.g, if fitting 400 | // 401 | // ____________________ 402 | // |____________________| 403 | // 404 | // into 405 | // 406 | // | | 407 | // | ____________| 408 | // |____________| 409 | // 410 | // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned 411 | // 412 | // This makes BF take about 2x the time 413 | 414 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) { 415 | tail = c->active_head; 416 | node = c->active_head; 417 | prev = &c->active_head; 418 | // find first node that's admissible 419 | while (tail->x < width) 420 | tail = tail->next; 421 | while (tail) { 422 | int xpos = tail->x - width; 423 | int y,waste; 424 | STBRP_ASSERT(xpos >= 0); 425 | // find the left position that matches this 426 | while (node->next->x <= xpos) { 427 | prev = &node->next; 428 | node = node->next; 429 | } 430 | STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); 431 | y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); 432 | if (y + height <= c->height) { 433 | if (y <= best_y) { 434 | if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { 435 | best_x = xpos; 436 | STBRP_ASSERT(y <= best_y); 437 | best_y = y; 438 | best_waste = waste; 439 | best = prev; 440 | } 441 | } 442 | } 443 | tail = tail->next; 444 | } 445 | } 446 | 447 | fr.prev_link = best; 448 | fr.x = best_x; 449 | fr.y = best_y; 450 | return fr; 451 | } 452 | 453 | static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height) 454 | { 455 | // find best position according to heuristic 456 | stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height); 457 | stbrp_node *node, *cur; 458 | 459 | // bail if: 460 | // 1. it failed 461 | // 2. the best node doesn't fit (we don't always check this) 462 | // 3. we're out of memory 463 | if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) { 464 | res.prev_link = NULL; 465 | return res; 466 | } 467 | 468 | // on success, create new node 469 | node = context->free_head; 470 | node->x = (stbrp_coord) res.x; 471 | node->y = (stbrp_coord) (res.y + height); 472 | 473 | context->free_head = node->next; 474 | 475 | // insert the new node into the right starting point, and 476 | // let 'cur' point to the remaining nodes needing to be 477 | // stiched back in 478 | 479 | cur = *res.prev_link; 480 | if (cur->x < res.x) { 481 | // preserve the existing one, so start testing with the next one 482 | stbrp_node *next = cur->next; 483 | cur->next = node; 484 | cur = next; 485 | } else { 486 | *res.prev_link = node; 487 | } 488 | 489 | // from here, traverse cur and free the nodes, until we get to one 490 | // that shouldn't be freed 491 | while (cur->next && cur->next->x <= res.x + width) { 492 | stbrp_node *next = cur->next; 493 | // move the current node to the free list 494 | cur->next = context->free_head; 495 | context->free_head = cur; 496 | cur = next; 497 | } 498 | 499 | // stitch the list back in 500 | node->next = cur; 501 | 502 | if (cur->x < res.x + width) 503 | cur->x = (stbrp_coord) (res.x + width); 504 | 505 | #ifdef _DEBUG 506 | cur = context->active_head; 507 | while (cur->x < context->width) { 508 | STBRP_ASSERT(cur->x < cur->next->x); 509 | cur = cur->next; 510 | } 511 | STBRP_ASSERT(cur->next == NULL); 512 | 513 | { 514 | int count=0; 515 | cur = context->active_head; 516 | while (cur) { 517 | cur = cur->next; 518 | ++count; 519 | } 520 | cur = context->free_head; 521 | while (cur) { 522 | cur = cur->next; 523 | ++count; 524 | } 525 | STBRP_ASSERT(count == context->num_nodes+2); 526 | } 527 | #endif 528 | 529 | return res; 530 | } 531 | 532 | // [DEAR IMGUI] Added STBRP__CDECL 533 | static int STBRP__CDECL rect_height_compare(const void *a, const void *b) 534 | { 535 | const stbrp_rect *p = (const stbrp_rect *) a; 536 | const stbrp_rect *q = (const stbrp_rect *) b; 537 | if (p->h > q->h) 538 | return -1; 539 | if (p->h < q->h) 540 | return 1; 541 | return (p->w > q->w) ? -1 : (p->w < q->w); 542 | } 543 | 544 | // [DEAR IMGUI] Added STBRP__CDECL 545 | static int STBRP__CDECL rect_original_order(const void *a, const void *b) 546 | { 547 | const stbrp_rect *p = (const stbrp_rect *) a; 548 | const stbrp_rect *q = (const stbrp_rect *) b; 549 | return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); 550 | } 551 | 552 | #ifdef STBRP_LARGE_RECTS 553 | #define STBRP__MAXVAL 0xffffffff 554 | #else 555 | #define STBRP__MAXVAL 0xffff 556 | #endif 557 | 558 | STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) 559 | { 560 | int i, all_rects_packed = 1; 561 | 562 | // we use the 'was_packed' field internally to allow sorting/unsorting 563 | for (i=0; i < num_rects; ++i) { 564 | rects[i].was_packed = i; 565 | } 566 | 567 | // sort according to heuristic 568 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare); 569 | 570 | for (i=0; i < num_rects; ++i) { 571 | if (rects[i].w == 0 || rects[i].h == 0) { 572 | rects[i].x = rects[i].y = 0; // empty rect needs no space 573 | } else { 574 | stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); 575 | if (fr.prev_link) { 576 | rects[i].x = (stbrp_coord) fr.x; 577 | rects[i].y = (stbrp_coord) fr.y; 578 | } else { 579 | rects[i].x = rects[i].y = STBRP__MAXVAL; 580 | } 581 | } 582 | } 583 | 584 | // unsort 585 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order); 586 | 587 | // set was_packed flags and all_rects_packed status 588 | for (i=0; i < num_rects; ++i) { 589 | rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); 590 | if (!rects[i].was_packed) 591 | all_rects_packed = 0; 592 | } 593 | 594 | // return the all_rects_packed status 595 | return all_rects_packed; 596 | } 597 | #endif 598 | 599 | /* 600 | ------------------------------------------------------------------------------ 601 | This software is available under 2 licenses -- choose whichever you prefer. 602 | ------------------------------------------------------------------------------ 603 | ALTERNATIVE A - MIT License 604 | Copyright (c) 2017 Sean Barrett 605 | Permission is hereby granted, free of charge, to any person obtaining a copy of 606 | this software and associated documentation files (the "Software"), to deal in 607 | the Software without restriction, including without limitation the rights to 608 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 609 | of the Software, and to permit persons to whom the Software is furnished to do 610 | so, subject to the following conditions: 611 | The above copyright notice and this permission notice shall be included in all 612 | copies or substantial portions of the Software. 613 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 614 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 615 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 616 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 617 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 618 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 619 | SOFTWARE. 620 | ------------------------------------------------------------------------------ 621 | ALTERNATIVE B - Public Domain (www.unlicense.org) 622 | This is free and unencumbered software released into the public domain. 623 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 624 | software, either in source code form or as a compiled binary, for any purpose, 625 | commercial or non-commercial, and by any means. 626 | In jurisdictions that recognize copyright laws, the author or authors of this 627 | software dedicate any and all copyright interest in the software to the public 628 | domain. We make this dedication for the benefit of the public at large and to 629 | the detriment of our heirs and successors. We intend this dedication to be an 630 | overt act of relinquishment in perpetuity of all present and future rights to 631 | this software under copyright law. 632 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 633 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 634 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 635 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 636 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 637 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 638 | ------------------------------------------------------------------------------ 639 | */ 640 | -------------------------------------------------------------------------------- /dwm overlay/imgui/imstb_textedit.h: -------------------------------------------------------------------------------- 1 | // [DEAR IMGUI] 2 | // This is a slightly modified version of stb_textedit.h 1.13. 3 | // Those changes would need to be pushed into nothings/stb: 4 | // - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321) 5 | // Grep for [DEAR IMGUI] to find the changes. 6 | 7 | // stb_textedit.h - v1.13 - public domain - Sean Barrett 8 | // Development of this library was sponsored by RAD Game Tools 9 | // 10 | // This C header file implements the guts of a multi-line text-editing 11 | // widget; you implement display, word-wrapping, and low-level string 12 | // insertion/deletion, and stb_textedit will map user inputs into 13 | // insertions & deletions, plus updates to the cursor position, 14 | // selection state, and undo state. 15 | // 16 | // It is intended for use in games and other systems that need to build 17 | // their own custom widgets and which do not have heavy text-editing 18 | // requirements (this library is not recommended for use for editing large 19 | // texts, as its performance does not scale and it has limited undo). 20 | // 21 | // Non-trivial behaviors are modelled after Windows text controls. 22 | // 23 | // 24 | // LICENSE 25 | // 26 | // See end of file for license information. 27 | // 28 | // 29 | // DEPENDENCIES 30 | // 31 | // Uses the C runtime function 'memmove', which you can override 32 | // by defining STB_TEXTEDIT_memmove before the implementation. 33 | // Uses no other functions. Performs no runtime allocations. 34 | // 35 | // 36 | // VERSION HISTORY 37 | // 38 | // 1.13 (2019-02-07) fix bug in undo size management 39 | // 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash 40 | // 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield 41 | // 1.10 (2016-10-25) supress warnings about casting away const with -Wcast-qual 42 | // 1.9 (2016-08-27) customizable move-by-word 43 | // 1.8 (2016-04-02) better keyboard handling when mouse button is down 44 | // 1.7 (2015-09-13) change y range handling in case baseline is non-0 45 | // 1.6 (2015-04-15) allow STB_TEXTEDIT_memmove 46 | // 1.5 (2014-09-10) add support for secondary keys for OS X 47 | // 1.4 (2014-08-17) fix signed/unsigned warnings 48 | // 1.3 (2014-06-19) fix mouse clicking to round to nearest char boundary 49 | // 1.2 (2014-05-27) fix some RAD types that had crept into the new code 50 | // 1.1 (2013-12-15) move-by-word (requires STB_TEXTEDIT_IS_SPACE ) 51 | // 1.0 (2012-07-26) improve documentation, initial public release 52 | // 0.3 (2012-02-24) bugfixes, single-line mode; insert mode 53 | // 0.2 (2011-11-28) fixes to undo/redo 54 | // 0.1 (2010-07-08) initial version 55 | // 56 | // ADDITIONAL CONTRIBUTORS 57 | // 58 | // Ulf Winklemann: move-by-word in 1.1 59 | // Fabian Giesen: secondary key inputs in 1.5 60 | // Martins Mozeiko: STB_TEXTEDIT_memmove in 1.6 61 | // 62 | // Bugfixes: 63 | // Scott Graham 64 | // Daniel Keller 65 | // Omar Cornut 66 | // Dan Thompson 67 | // 68 | // USAGE 69 | // 70 | // This file behaves differently depending on what symbols you define 71 | // before including it. 72 | // 73 | // 74 | // Header-file mode: 75 | // 76 | // If you do not define STB_TEXTEDIT_IMPLEMENTATION before including this, 77 | // it will operate in "header file" mode. In this mode, it declares a 78 | // single public symbol, STB_TexteditState, which encapsulates the current 79 | // state of a text widget (except for the string, which you will store 80 | // separately). 81 | // 82 | // To compile in this mode, you must define STB_TEXTEDIT_CHARTYPE to a 83 | // primitive type that defines a single character (e.g. char, wchar_t, etc). 84 | // 85 | // To save space or increase undo-ability, you can optionally define the 86 | // following things that are used by the undo system: 87 | // 88 | // STB_TEXTEDIT_POSITIONTYPE small int type encoding a valid cursor position 89 | // STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow 90 | // STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer 91 | // 92 | // If you don't define these, they are set to permissive types and 93 | // moderate sizes. The undo system does no memory allocations, so 94 | // it grows STB_TexteditState by the worst-case storage which is (in bytes): 95 | // 96 | // [4 + 3 * sizeof(STB_TEXTEDIT_POSITIONTYPE)] * STB_TEXTEDIT_UNDOSTATE_COUNT 97 | // + sizeof(STB_TEXTEDIT_CHARTYPE) * STB_TEXTEDIT_UNDOCHAR_COUNT 98 | // 99 | // 100 | // Implementation mode: 101 | // 102 | // If you define STB_TEXTEDIT_IMPLEMENTATION before including this, it 103 | // will compile the implementation of the text edit widget, depending 104 | // on a large number of symbols which must be defined before the include. 105 | // 106 | // The implementation is defined only as static functions. You will then 107 | // need to provide your own APIs in the same file which will access the 108 | // static functions. 109 | // 110 | // The basic concept is that you provide a "string" object which 111 | // behaves like an array of characters. stb_textedit uses indices to 112 | // refer to positions in the string, implicitly representing positions 113 | // in the displayed textedit. This is true for both plain text and 114 | // rich text; even with rich text stb_truetype interacts with your 115 | // code as if there was an array of all the displayed characters. 116 | // 117 | // Symbols that must be the same in header-file and implementation mode: 118 | // 119 | // STB_TEXTEDIT_CHARTYPE the character type 120 | // STB_TEXTEDIT_POSITIONTYPE small type that is a valid cursor position 121 | // STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow 122 | // STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer 123 | // 124 | // Symbols you must define for implementation mode: 125 | // 126 | // STB_TEXTEDIT_STRING the type of object representing a string being edited, 127 | // typically this is a wrapper object with other data you need 128 | // 129 | // STB_TEXTEDIT_STRINGLEN(obj) the length of the string (ideally O(1)) 130 | // STB_TEXTEDIT_LAYOUTROW(&r,obj,n) returns the results of laying out a line of characters 131 | // starting from character #n (see discussion below) 132 | // STB_TEXTEDIT_GETWIDTH(obj,n,i) returns the pixel delta from the xpos of the i'th character 133 | // to the xpos of the i+1'th char for a line of characters 134 | // starting at character #n (i.e. accounts for kerning 135 | // with previous char) 136 | // STB_TEXTEDIT_KEYTOTEXT(k) maps a keyboard input to an insertable character 137 | // (return type is int, -1 means not valid to insert) 138 | // STB_TEXTEDIT_GETCHAR(obj,i) returns the i'th character of obj, 0-based 139 | // STB_TEXTEDIT_NEWLINE the character returned by _GETCHAR() we recognize 140 | // as manually wordwrapping for end-of-line positioning 141 | // 142 | // STB_TEXTEDIT_DELETECHARS(obj,i,n) delete n characters starting at i 143 | // STB_TEXTEDIT_INSERTCHARS(obj,i,c*,n) insert n characters at i (pointed to by STB_TEXTEDIT_CHARTYPE*) 144 | // 145 | // STB_TEXTEDIT_K_SHIFT a power of two that is or'd in to a keyboard input to represent the shift key 146 | // 147 | // STB_TEXTEDIT_K_LEFT keyboard input to move cursor left 148 | // STB_TEXTEDIT_K_RIGHT keyboard input to move cursor right 149 | // STB_TEXTEDIT_K_UP keyboard input to move cursor up 150 | // STB_TEXTEDIT_K_DOWN keyboard input to move cursor down 151 | // STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page 152 | // STB_TEXTEDIT_K_PGDOWN keyboard input to move cursor down a page 153 | // STB_TEXTEDIT_K_LINESTART keyboard input to move cursor to start of line // e.g. HOME 154 | // STB_TEXTEDIT_K_LINEEND keyboard input to move cursor to end of line // e.g. END 155 | // STB_TEXTEDIT_K_TEXTSTART keyboard input to move cursor to start of text // e.g. ctrl-HOME 156 | // STB_TEXTEDIT_K_TEXTEND keyboard input to move cursor to end of text // e.g. ctrl-END 157 | // STB_TEXTEDIT_K_DELETE keyboard input to delete selection or character under cursor 158 | // STB_TEXTEDIT_K_BACKSPACE keyboard input to delete selection or character left of cursor 159 | // STB_TEXTEDIT_K_UNDO keyboard input to perform undo 160 | // STB_TEXTEDIT_K_REDO keyboard input to perform redo 161 | // 162 | // Optional: 163 | // STB_TEXTEDIT_K_INSERT keyboard input to toggle insert mode 164 | // STB_TEXTEDIT_IS_SPACE(ch) true if character is whitespace (e.g. 'isspace'), 165 | // required for default WORDLEFT/WORDRIGHT handlers 166 | // STB_TEXTEDIT_MOVEWORDLEFT(obj,i) custom handler for WORDLEFT, returns index to move cursor to 167 | // STB_TEXTEDIT_MOVEWORDRIGHT(obj,i) custom handler for WORDRIGHT, returns index to move cursor to 168 | // STB_TEXTEDIT_K_WORDLEFT keyboard input to move cursor left one word // e.g. ctrl-LEFT 169 | // STB_TEXTEDIT_K_WORDRIGHT keyboard input to move cursor right one word // e.g. ctrl-RIGHT 170 | // STB_TEXTEDIT_K_LINESTART2 secondary keyboard input to move cursor to start of line 171 | // STB_TEXTEDIT_K_LINEEND2 secondary keyboard input to move cursor to end of line 172 | // STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text 173 | // STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text 174 | // 175 | // Keyboard input must be encoded as a single integer value; e.g. a character code 176 | // and some bitflags that represent shift states. to simplify the interface, SHIFT must 177 | // be a bitflag, so we can test the shifted state of cursor movements to allow selection, 178 | // i.e. (STB_TEXTEDIT_K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow. 179 | // 180 | // You can encode other things, such as CONTROL or ALT, in additional bits, and 181 | // then test for their presence in e.g. STB_TEXTEDIT_K_WORDLEFT. For example, 182 | // my Windows implementations add an additional CONTROL bit, and an additional KEYDOWN 183 | // bit. Then all of the STB_TEXTEDIT_K_ values bitwise-or in the KEYDOWN bit, 184 | // and I pass both WM_KEYDOWN and WM_CHAR events to the "key" function in the 185 | // API below. The control keys will only match WM_KEYDOWN events because of the 186 | // keydown bit I add, and STB_TEXTEDIT_KEYTOTEXT only tests for the KEYDOWN 187 | // bit so it only decodes WM_CHAR events. 188 | // 189 | // STB_TEXTEDIT_LAYOUTROW returns information about the shape of one displayed 190 | // row of characters assuming they start on the i'th character--the width and 191 | // the height and the number of characters consumed. This allows this library 192 | // to traverse the entire layout incrementally. You need to compute word-wrapping 193 | // here. 194 | // 195 | // Each textfield keeps its own insert mode state, which is not how normal 196 | // applications work. To keep an app-wide insert mode, update/copy the 197 | // "insert_mode" field of STB_TexteditState before/after calling API functions. 198 | // 199 | // API 200 | // 201 | // void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line) 202 | // 203 | // void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 204 | // void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 205 | // int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 206 | // int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) 207 | // void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXEDIT_KEYTYPE key) 208 | // 209 | // Each of these functions potentially updates the string and updates the 210 | // state. 211 | // 212 | // initialize_state: 213 | // set the textedit state to a known good default state when initially 214 | // constructing the textedit. 215 | // 216 | // click: 217 | // call this with the mouse x,y on a mouse down; it will update the cursor 218 | // and reset the selection start/end to the cursor point. the x,y must 219 | // be relative to the text widget, with (0,0) being the top left. 220 | // 221 | // drag: 222 | // call this with the mouse x,y on a mouse drag/up; it will update the 223 | // cursor and the selection end point 224 | // 225 | // cut: 226 | // call this to delete the current selection; returns true if there was 227 | // one. you should FIRST copy the current selection to the system paste buffer. 228 | // (To copy, just copy the current selection out of the string yourself.) 229 | // 230 | // paste: 231 | // call this to paste text at the current cursor point or over the current 232 | // selection if there is one. 233 | // 234 | // key: 235 | // call this for keyboard inputs sent to the textfield. you can use it 236 | // for "key down" events or for "translated" key events. if you need to 237 | // do both (as in Win32), or distinguish Unicode characters from control 238 | // inputs, set a high bit to distinguish the two; then you can define the 239 | // various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit 240 | // set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is 241 | // clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to 242 | // anything other type you wante before including. 243 | // 244 | // 245 | // When rendering, you can read the cursor position and selection state from 246 | // the STB_TexteditState. 247 | // 248 | // 249 | // Notes: 250 | // 251 | // This is designed to be usable in IMGUI, so it allows for the possibility of 252 | // running in an IMGUI that has NOT cached the multi-line layout. For this 253 | // reason, it provides an interface that is compatible with computing the 254 | // layout incrementally--we try to make sure we make as few passes through 255 | // as possible. (For example, to locate the mouse pointer in the text, we 256 | // could define functions that return the X and Y positions of characters 257 | // and binary search Y and then X, but if we're doing dynamic layout this 258 | // will run the layout algorithm many times, so instead we manually search 259 | // forward in one pass. Similar logic applies to e.g. up-arrow and 260 | // down-arrow movement.) 261 | // 262 | // If it's run in a widget that *has* cached the layout, then this is less 263 | // efficient, but it's not horrible on modern computers. But you wouldn't 264 | // want to edit million-line files with it. 265 | 266 | 267 | //////////////////////////////////////////////////////////////////////////// 268 | //////////////////////////////////////////////////////////////////////////// 269 | //// 270 | //// Header-file mode 271 | //// 272 | //// 273 | 274 | #ifndef INCLUDE_STB_TEXTEDIT_H 275 | #define INCLUDE_STB_TEXTEDIT_H 276 | 277 | //////////////////////////////////////////////////////////////////////// 278 | // 279 | // STB_TexteditState 280 | // 281 | // Definition of STB_TexteditState which you should store 282 | // per-textfield; it includes cursor position, selection state, 283 | // and undo state. 284 | // 285 | 286 | #ifndef STB_TEXTEDIT_UNDOSTATECOUNT 287 | #define STB_TEXTEDIT_UNDOSTATECOUNT 99 288 | #endif 289 | #ifndef STB_TEXTEDIT_UNDOCHARCOUNT 290 | #define STB_TEXTEDIT_UNDOCHARCOUNT 999 291 | #endif 292 | #ifndef STB_TEXTEDIT_CHARTYPE 293 | #define STB_TEXTEDIT_CHARTYPE int 294 | #endif 295 | #ifndef STB_TEXTEDIT_POSITIONTYPE 296 | #define STB_TEXTEDIT_POSITIONTYPE int 297 | #endif 298 | 299 | typedef struct 300 | { 301 | // private data 302 | STB_TEXTEDIT_POSITIONTYPE where; 303 | STB_TEXTEDIT_POSITIONTYPE insert_length; 304 | STB_TEXTEDIT_POSITIONTYPE delete_length; 305 | int char_storage; 306 | } StbUndoRecord; 307 | 308 | typedef struct 309 | { 310 | // private data 311 | StbUndoRecord undo_rec [STB_TEXTEDIT_UNDOSTATECOUNT]; 312 | STB_TEXTEDIT_CHARTYPE undo_char[STB_TEXTEDIT_UNDOCHARCOUNT]; 313 | short undo_point, redo_point; 314 | int undo_char_point, redo_char_point; 315 | } StbUndoState; 316 | 317 | typedef struct 318 | { 319 | ///////////////////// 320 | // 321 | // public data 322 | // 323 | 324 | int cursor; 325 | // position of the text cursor within the string 326 | 327 | int select_start; // selection start point 328 | int select_end; 329 | // selection start and end point in characters; if equal, no selection. 330 | // note that start may be less than or greater than end (e.g. when 331 | // dragging the mouse, start is where the initial click was, and you 332 | // can drag in either direction) 333 | 334 | unsigned char insert_mode; 335 | // each textfield keeps its own insert mode state. to keep an app-wide 336 | // insert mode, copy this value in/out of the app state 337 | 338 | int row_count_per_page; 339 | // page size in number of row. 340 | // this value MUST be set to >0 for pageup or pagedown in multilines documents. 341 | 342 | ///////////////////// 343 | // 344 | // private data 345 | // 346 | unsigned char cursor_at_end_of_line; // not implemented yet 347 | unsigned char initialized; 348 | unsigned char has_preferred_x; 349 | unsigned char single_line; 350 | unsigned char padding1, padding2, padding3; 351 | float preferred_x; // this determines where the cursor up/down tries to seek to along x 352 | StbUndoState undostate; 353 | } STB_TexteditState; 354 | 355 | 356 | //////////////////////////////////////////////////////////////////////// 357 | // 358 | // StbTexteditRow 359 | // 360 | // Result of layout query, used by stb_textedit to determine where 361 | // the text in each row is. 362 | 363 | // result of layout query 364 | typedef struct 365 | { 366 | float x0,x1; // starting x location, end x location (allows for align=right, etc) 367 | float baseline_y_delta; // position of baseline relative to previous row's baseline 368 | float ymin,ymax; // height of row above and below baseline 369 | int num_chars; 370 | } StbTexteditRow; 371 | #endif //INCLUDE_STB_TEXTEDIT_H 372 | 373 | 374 | //////////////////////////////////////////////////////////////////////////// 375 | //////////////////////////////////////////////////////////////////////////// 376 | //// 377 | //// Implementation mode 378 | //// 379 | //// 380 | 381 | 382 | // implementation isn't include-guarded, since it might have indirectly 383 | // included just the "header" portion 384 | #ifdef STB_TEXTEDIT_IMPLEMENTATION 385 | 386 | #ifndef STB_TEXTEDIT_memmove 387 | #include 388 | #define STB_TEXTEDIT_memmove memmove 389 | #endif 390 | 391 | 392 | ///////////////////////////////////////////////////////////////////////////// 393 | // 394 | // Mouse input handling 395 | // 396 | 397 | // traverse the layout to locate the nearest character to a display position 398 | static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y) 399 | { 400 | StbTexteditRow r; 401 | int n = STB_TEXTEDIT_STRINGLEN(str); 402 | float base_y = 0, prev_x; 403 | int i=0, k; 404 | 405 | r.x0 = r.x1 = 0; 406 | r.ymin = r.ymax = 0; 407 | r.num_chars = 0; 408 | 409 | // search rows to find one that straddles 'y' 410 | while (i < n) { 411 | STB_TEXTEDIT_LAYOUTROW(&r, str, i); 412 | if (r.num_chars <= 0) 413 | return n; 414 | 415 | if (i==0 && y < base_y + r.ymin) 416 | return 0; 417 | 418 | if (y < base_y + r.ymax) 419 | break; 420 | 421 | i += r.num_chars; 422 | base_y += r.baseline_y_delta; 423 | } 424 | 425 | // below all text, return 'after' last character 426 | if (i >= n) 427 | return n; 428 | 429 | // check if it's before the beginning of the line 430 | if (x < r.x0) 431 | return i; 432 | 433 | // check if it's before the end of the line 434 | if (x < r.x1) { 435 | // search characters in row for one that straddles 'x' 436 | prev_x = r.x0; 437 | for (k=0; k < r.num_chars; ++k) { 438 | float w = STB_TEXTEDIT_GETWIDTH(str, i, k); 439 | if (x < prev_x+w) { 440 | if (x < prev_x+w/2) 441 | return k+i; 442 | else 443 | return k+i+1; 444 | } 445 | prev_x += w; 446 | } 447 | // shouldn't happen, but if it does, fall through to end-of-line case 448 | } 449 | 450 | // if the last character is a newline, return that. otherwise return 'after' the last character 451 | if (STB_TEXTEDIT_GETCHAR(str, i+r.num_chars-1) == STB_TEXTEDIT_NEWLINE) 452 | return i+r.num_chars-1; 453 | else 454 | return i+r.num_chars; 455 | } 456 | 457 | // API click: on mouse down, move the cursor to the clicked location, and reset the selection 458 | static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 459 | { 460 | // In single-line mode, just always make y = 0. This lets the drag keep working if the mouse 461 | // goes off the top or bottom of the text 462 | if( state->single_line ) 463 | { 464 | StbTexteditRow r; 465 | STB_TEXTEDIT_LAYOUTROW(&r, str, 0); 466 | y = r.ymin; 467 | } 468 | 469 | state->cursor = stb_text_locate_coord(str, x, y); 470 | state->select_start = state->cursor; 471 | state->select_end = state->cursor; 472 | state->has_preferred_x = 0; 473 | } 474 | 475 | // API drag: on mouse drag, move the cursor and selection endpoint to the clicked location 476 | static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 477 | { 478 | int p = 0; 479 | 480 | // In single-line mode, just always make y = 0. This lets the drag keep working if the mouse 481 | // goes off the top or bottom of the text 482 | if( state->single_line ) 483 | { 484 | StbTexteditRow r; 485 | STB_TEXTEDIT_LAYOUTROW(&r, str, 0); 486 | y = r.ymin; 487 | } 488 | 489 | if (state->select_start == state->select_end) 490 | state->select_start = state->cursor; 491 | 492 | p = stb_text_locate_coord(str, x, y); 493 | state->cursor = state->select_end = p; 494 | } 495 | 496 | ///////////////////////////////////////////////////////////////////////////// 497 | // 498 | // Keyboard input handling 499 | // 500 | 501 | // forward declarations 502 | static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state); 503 | static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state); 504 | static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length); 505 | static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length); 506 | static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length); 507 | 508 | typedef struct 509 | { 510 | float x,y; // position of n'th character 511 | float height; // height of line 512 | int first_char, length; // first char of row, and length 513 | int prev_first; // first char of previous row 514 | } StbFindState; 515 | 516 | // find the x/y location of a character, and remember info about the previous row in 517 | // case we get a move-up event (for page up, we'll have to rescan) 518 | static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *str, int n, int single_line) 519 | { 520 | StbTexteditRow r; 521 | int prev_start = 0; 522 | int z = STB_TEXTEDIT_STRINGLEN(str); 523 | int i=0, first; 524 | 525 | if (n == z) { 526 | // if it's at the end, then find the last line -- simpler than trying to 527 | // explicitly handle this case in the regular code 528 | if (single_line) { 529 | STB_TEXTEDIT_LAYOUTROW(&r, str, 0); 530 | find->y = 0; 531 | find->first_char = 0; 532 | find->length = z; 533 | find->height = r.ymax - r.ymin; 534 | find->x = r.x1; 535 | } else { 536 | find->y = 0; 537 | find->x = 0; 538 | find->height = 1; 539 | while (i < z) { 540 | STB_TEXTEDIT_LAYOUTROW(&r, str, i); 541 | prev_start = i; 542 | i += r.num_chars; 543 | } 544 | find->first_char = i; 545 | find->length = 0; 546 | find->prev_first = prev_start; 547 | } 548 | return; 549 | } 550 | 551 | // search rows to find the one that straddles character n 552 | find->y = 0; 553 | 554 | for(;;) { 555 | STB_TEXTEDIT_LAYOUTROW(&r, str, i); 556 | if (n < i + r.num_chars) 557 | break; 558 | prev_start = i; 559 | i += r.num_chars; 560 | find->y += r.baseline_y_delta; 561 | } 562 | 563 | find->first_char = first = i; 564 | find->length = r.num_chars; 565 | find->height = r.ymax - r.ymin; 566 | find->prev_first = prev_start; 567 | 568 | // now scan to find xpos 569 | find->x = r.x0; 570 | for (i=0; first+i < n; ++i) 571 | find->x += STB_TEXTEDIT_GETWIDTH(str, first, i); 572 | } 573 | 574 | #define STB_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end) 575 | 576 | // make the selection/cursor state valid if client altered the string 577 | static void stb_textedit_clamp(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 578 | { 579 | int n = STB_TEXTEDIT_STRINGLEN(str); 580 | if (STB_TEXT_HAS_SELECTION(state)) { 581 | if (state->select_start > n) state->select_start = n; 582 | if (state->select_end > n) state->select_end = n; 583 | // if clamping forced them to be equal, move the cursor to match 584 | if (state->select_start == state->select_end) 585 | state->cursor = state->select_start; 586 | } 587 | if (state->cursor > n) state->cursor = n; 588 | } 589 | 590 | // delete characters while updating undo 591 | static void stb_textedit_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int len) 592 | { 593 | stb_text_makeundo_delete(str, state, where, len); 594 | STB_TEXTEDIT_DELETECHARS(str, where, len); 595 | state->has_preferred_x = 0; 596 | } 597 | 598 | // delete the section 599 | static void stb_textedit_delete_selection(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 600 | { 601 | stb_textedit_clamp(str, state); 602 | if (STB_TEXT_HAS_SELECTION(state)) { 603 | if (state->select_start < state->select_end) { 604 | stb_textedit_delete(str, state, state->select_start, state->select_end - state->select_start); 605 | state->select_end = state->cursor = state->select_start; 606 | } else { 607 | stb_textedit_delete(str, state, state->select_end, state->select_start - state->select_end); 608 | state->select_start = state->cursor = state->select_end; 609 | } 610 | state->has_preferred_x = 0; 611 | } 612 | } 613 | 614 | // canoncialize the selection so start <= end 615 | static void stb_textedit_sortselection(STB_TexteditState *state) 616 | { 617 | if (state->select_end < state->select_start) { 618 | int temp = state->select_end; 619 | state->select_end = state->select_start; 620 | state->select_start = temp; 621 | } 622 | } 623 | 624 | // move cursor to first character of selection 625 | static void stb_textedit_move_to_first(STB_TexteditState *state) 626 | { 627 | if (STB_TEXT_HAS_SELECTION(state)) { 628 | stb_textedit_sortselection(state); 629 | state->cursor = state->select_start; 630 | state->select_end = state->select_start; 631 | state->has_preferred_x = 0; 632 | } 633 | } 634 | 635 | // move cursor to last character of selection 636 | static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 637 | { 638 | if (STB_TEXT_HAS_SELECTION(state)) { 639 | stb_textedit_sortselection(state); 640 | stb_textedit_clamp(str, state); 641 | state->cursor = state->select_end; 642 | state->select_start = state->select_end; 643 | state->has_preferred_x = 0; 644 | } 645 | } 646 | 647 | #ifdef STB_TEXTEDIT_IS_SPACE 648 | static int is_word_boundary( STB_TEXTEDIT_STRING *str, int idx ) 649 | { 650 | return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1; 651 | } 652 | 653 | #ifndef STB_TEXTEDIT_MOVEWORDLEFT 654 | static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c ) 655 | { 656 | --c; // always move at least one character 657 | while( c >= 0 && !is_word_boundary( str, c ) ) 658 | --c; 659 | 660 | if( c < 0 ) 661 | c = 0; 662 | 663 | return c; 664 | } 665 | #define STB_TEXTEDIT_MOVEWORDLEFT stb_textedit_move_to_word_previous 666 | #endif 667 | 668 | #ifndef STB_TEXTEDIT_MOVEWORDRIGHT 669 | static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *str, int c ) 670 | { 671 | const int len = STB_TEXTEDIT_STRINGLEN(str); 672 | ++c; // always move at least one character 673 | while( c < len && !is_word_boundary( str, c ) ) 674 | ++c; 675 | 676 | if( c > len ) 677 | c = len; 678 | 679 | return c; 680 | } 681 | #define STB_TEXTEDIT_MOVEWORDRIGHT stb_textedit_move_to_word_next 682 | #endif 683 | 684 | #endif 685 | 686 | // update selection and cursor to match each other 687 | static void stb_textedit_prep_selection_at_cursor(STB_TexteditState *state) 688 | { 689 | if (!STB_TEXT_HAS_SELECTION(state)) 690 | state->select_start = state->select_end = state->cursor; 691 | else 692 | state->cursor = state->select_end; 693 | } 694 | 695 | // API cut: delete selection 696 | static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 697 | { 698 | if (STB_TEXT_HAS_SELECTION(state)) { 699 | stb_textedit_delete_selection(str,state); // implicitly clamps 700 | state->has_preferred_x = 0; 701 | return 1; 702 | } 703 | return 0; 704 | } 705 | 706 | // API paste: replace existing selection with passed-in text 707 | static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) 708 | { 709 | // if there's a selection, the paste should delete it 710 | stb_textedit_clamp(str, state); 711 | stb_textedit_delete_selection(str,state); 712 | // try to insert the characters 713 | if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len)) { 714 | stb_text_makeundo_insert(state, state->cursor, len); 715 | state->cursor += len; 716 | state->has_preferred_x = 0; 717 | return 1; 718 | } 719 | // [DEAR IMGUI] 720 | //// remove the undo since we didn't actually insert the characters 721 | //if (state->undostate.undo_point) 722 | // --state->undostate.undo_point; 723 | // note: paste failure will leave deleted selection, may be restored with an undo (see https://github.com/nothings/stb/issues/734 for details) 724 | return 0; 725 | } 726 | 727 | #ifndef STB_TEXTEDIT_KEYTYPE 728 | #define STB_TEXTEDIT_KEYTYPE int 729 | #endif 730 | 731 | // API key: process a keyboard input 732 | static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key) 733 | { 734 | retry: 735 | switch (key) { 736 | default: { 737 | int c = STB_TEXTEDIT_KEYTOTEXT(key); 738 | if (c > 0) { 739 | STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE) c; 740 | 741 | // can't add newline in single-line mode 742 | if (c == '\n' && state->single_line) 743 | break; 744 | 745 | if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) { 746 | stb_text_makeundo_replace(str, state, state->cursor, 1, 1); 747 | STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1); 748 | if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { 749 | ++state->cursor; 750 | state->has_preferred_x = 0; 751 | } 752 | } else { 753 | stb_textedit_delete_selection(str,state); // implicitly clamps 754 | if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { 755 | stb_text_makeundo_insert(state, state->cursor, 1); 756 | ++state->cursor; 757 | state->has_preferred_x = 0; 758 | } 759 | } 760 | } 761 | break; 762 | } 763 | 764 | #ifdef STB_TEXTEDIT_K_INSERT 765 | case STB_TEXTEDIT_K_INSERT: 766 | state->insert_mode = !state->insert_mode; 767 | break; 768 | #endif 769 | 770 | case STB_TEXTEDIT_K_UNDO: 771 | stb_text_undo(str, state); 772 | state->has_preferred_x = 0; 773 | break; 774 | 775 | case STB_TEXTEDIT_K_REDO: 776 | stb_text_redo(str, state); 777 | state->has_preferred_x = 0; 778 | break; 779 | 780 | case STB_TEXTEDIT_K_LEFT: 781 | // if currently there's a selection, move cursor to start of selection 782 | if (STB_TEXT_HAS_SELECTION(state)) 783 | stb_textedit_move_to_first(state); 784 | else 785 | if (state->cursor > 0) 786 | --state->cursor; 787 | state->has_preferred_x = 0; 788 | break; 789 | 790 | case STB_TEXTEDIT_K_RIGHT: 791 | // if currently there's a selection, move cursor to end of selection 792 | if (STB_TEXT_HAS_SELECTION(state)) 793 | stb_textedit_move_to_last(str, state); 794 | else 795 | ++state->cursor; 796 | stb_textedit_clamp(str, state); 797 | state->has_preferred_x = 0; 798 | break; 799 | 800 | case STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT: 801 | stb_textedit_clamp(str, state); 802 | stb_textedit_prep_selection_at_cursor(state); 803 | // move selection left 804 | if (state->select_end > 0) 805 | --state->select_end; 806 | state->cursor = state->select_end; 807 | state->has_preferred_x = 0; 808 | break; 809 | 810 | #ifdef STB_TEXTEDIT_MOVEWORDLEFT 811 | case STB_TEXTEDIT_K_WORDLEFT: 812 | if (STB_TEXT_HAS_SELECTION(state)) 813 | stb_textedit_move_to_first(state); 814 | else { 815 | state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); 816 | stb_textedit_clamp( str, state ); 817 | } 818 | break; 819 | 820 | case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT: 821 | if( !STB_TEXT_HAS_SELECTION( state ) ) 822 | stb_textedit_prep_selection_at_cursor(state); 823 | 824 | state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); 825 | state->select_end = state->cursor; 826 | 827 | stb_textedit_clamp( str, state ); 828 | break; 829 | #endif 830 | 831 | #ifdef STB_TEXTEDIT_MOVEWORDRIGHT 832 | case STB_TEXTEDIT_K_WORDRIGHT: 833 | if (STB_TEXT_HAS_SELECTION(state)) 834 | stb_textedit_move_to_last(str, state); 835 | else { 836 | state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); 837 | stb_textedit_clamp( str, state ); 838 | } 839 | break; 840 | 841 | case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT: 842 | if( !STB_TEXT_HAS_SELECTION( state ) ) 843 | stb_textedit_prep_selection_at_cursor(state); 844 | 845 | state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); 846 | state->select_end = state->cursor; 847 | 848 | stb_textedit_clamp( str, state ); 849 | break; 850 | #endif 851 | 852 | case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT: 853 | stb_textedit_prep_selection_at_cursor(state); 854 | // move selection right 855 | ++state->select_end; 856 | stb_textedit_clamp(str, state); 857 | state->cursor = state->select_end; 858 | state->has_preferred_x = 0; 859 | break; 860 | 861 | case STB_TEXTEDIT_K_DOWN: 862 | case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT: 863 | case STB_TEXTEDIT_K_PGDOWN: 864 | case STB_TEXTEDIT_K_PGDOWN | STB_TEXTEDIT_K_SHIFT: { 865 | StbFindState find; 866 | StbTexteditRow row; 867 | int i, j, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; 868 | int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGDOWN; 869 | int row_count = is_page ? state->row_count_per_page : 1; 870 | 871 | if (!is_page && state->single_line) { 872 | // on windows, up&down in single-line behave like left&right 873 | key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT); 874 | goto retry; 875 | } 876 | 877 | if (sel) 878 | stb_textedit_prep_selection_at_cursor(state); 879 | else if (STB_TEXT_HAS_SELECTION(state)) 880 | stb_textedit_move_to_last(str, state); 881 | 882 | // compute current position of cursor point 883 | stb_textedit_clamp(str, state); 884 | stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); 885 | 886 | for (j = 0; j < row_count; ++j) { 887 | float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x; 888 | int start = find.first_char + find.length; 889 | 890 | if (find.length == 0) 891 | break; 892 | 893 | // [DEAR IMGUI] 894 | // going down while being on the last line shouldn't bring us to that line end 895 | if (STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE) 896 | break; 897 | 898 | // now find character position down a row 899 | state->cursor = start; 900 | STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); 901 | x = row.x0; 902 | for (i=0; i < row.num_chars; ++i) { 903 | float dx = STB_TEXTEDIT_GETWIDTH(str, start, i); 904 | #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE 905 | if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE) 906 | break; 907 | #endif 908 | x += dx; 909 | if (x > goal_x) 910 | break; 911 | ++state->cursor; 912 | } 913 | stb_textedit_clamp(str, state); 914 | 915 | state->has_preferred_x = 1; 916 | state->preferred_x = goal_x; 917 | 918 | if (sel) 919 | state->select_end = state->cursor; 920 | 921 | // go to next line 922 | find.first_char = find.first_char + find.length; 923 | find.length = row.num_chars; 924 | } 925 | break; 926 | } 927 | 928 | case STB_TEXTEDIT_K_UP: 929 | case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT: 930 | case STB_TEXTEDIT_K_PGUP: 931 | case STB_TEXTEDIT_K_PGUP | STB_TEXTEDIT_K_SHIFT: { 932 | StbFindState find; 933 | StbTexteditRow row; 934 | int i, j, prev_scan, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; 935 | int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGUP; 936 | int row_count = is_page ? state->row_count_per_page : 1; 937 | 938 | if (!is_page && state->single_line) { 939 | // on windows, up&down become left&right 940 | key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT); 941 | goto retry; 942 | } 943 | 944 | if (sel) 945 | stb_textedit_prep_selection_at_cursor(state); 946 | else if (STB_TEXT_HAS_SELECTION(state)) 947 | stb_textedit_move_to_first(state); 948 | 949 | // compute current position of cursor point 950 | stb_textedit_clamp(str, state); 951 | stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); 952 | 953 | for (j = 0; j < row_count; ++j) { 954 | float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x; 955 | 956 | // can only go up if there's a previous row 957 | if (find.prev_first == find.first_char) 958 | break; 959 | 960 | // now find character position up a row 961 | state->cursor = find.prev_first; 962 | STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); 963 | x = row.x0; 964 | for (i=0; i < row.num_chars; ++i) { 965 | float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i); 966 | #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE 967 | if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE) 968 | break; 969 | #endif 970 | x += dx; 971 | if (x > goal_x) 972 | break; 973 | ++state->cursor; 974 | } 975 | stb_textedit_clamp(str, state); 976 | 977 | state->has_preferred_x = 1; 978 | state->preferred_x = goal_x; 979 | 980 | if (sel) 981 | state->select_end = state->cursor; 982 | 983 | // go to previous line 984 | // (we need to scan previous line the hard way. maybe we could expose this as a new API function?) 985 | prev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0; 986 | while (prev_scan > 0 && STB_TEXTEDIT_GETCHAR(str, prev_scan - 1) != STB_TEXTEDIT_NEWLINE) 987 | --prev_scan; 988 | find.first_char = find.prev_first; 989 | find.prev_first = prev_scan; 990 | } 991 | break; 992 | } 993 | 994 | case STB_TEXTEDIT_K_DELETE: 995 | case STB_TEXTEDIT_K_DELETE | STB_TEXTEDIT_K_SHIFT: 996 | if (STB_TEXT_HAS_SELECTION(state)) 997 | stb_textedit_delete_selection(str, state); 998 | else { 999 | int n = STB_TEXTEDIT_STRINGLEN(str); 1000 | if (state->cursor < n) 1001 | stb_textedit_delete(str, state, state->cursor, 1); 1002 | } 1003 | state->has_preferred_x = 0; 1004 | break; 1005 | 1006 | case STB_TEXTEDIT_K_BACKSPACE: 1007 | case STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT: 1008 | if (STB_TEXT_HAS_SELECTION(state)) 1009 | stb_textedit_delete_selection(str, state); 1010 | else { 1011 | stb_textedit_clamp(str, state); 1012 | if (state->cursor > 0) { 1013 | stb_textedit_delete(str, state, state->cursor-1, 1); 1014 | --state->cursor; 1015 | } 1016 | } 1017 | state->has_preferred_x = 0; 1018 | break; 1019 | 1020 | #ifdef STB_TEXTEDIT_K_TEXTSTART2 1021 | case STB_TEXTEDIT_K_TEXTSTART2: 1022 | #endif 1023 | case STB_TEXTEDIT_K_TEXTSTART: 1024 | state->cursor = state->select_start = state->select_end = 0; 1025 | state->has_preferred_x = 0; 1026 | break; 1027 | 1028 | #ifdef STB_TEXTEDIT_K_TEXTEND2 1029 | case STB_TEXTEDIT_K_TEXTEND2: 1030 | #endif 1031 | case STB_TEXTEDIT_K_TEXTEND: 1032 | state->cursor = STB_TEXTEDIT_STRINGLEN(str); 1033 | state->select_start = state->select_end = 0; 1034 | state->has_preferred_x = 0; 1035 | break; 1036 | 1037 | #ifdef STB_TEXTEDIT_K_TEXTSTART2 1038 | case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT: 1039 | #endif 1040 | case STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT: 1041 | stb_textedit_prep_selection_at_cursor(state); 1042 | state->cursor = state->select_end = 0; 1043 | state->has_preferred_x = 0; 1044 | break; 1045 | 1046 | #ifdef STB_TEXTEDIT_K_TEXTEND2 1047 | case STB_TEXTEDIT_K_TEXTEND2 | STB_TEXTEDIT_K_SHIFT: 1048 | #endif 1049 | case STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT: 1050 | stb_textedit_prep_selection_at_cursor(state); 1051 | state->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str); 1052 | state->has_preferred_x = 0; 1053 | break; 1054 | 1055 | 1056 | #ifdef STB_TEXTEDIT_K_LINESTART2 1057 | case STB_TEXTEDIT_K_LINESTART2: 1058 | #endif 1059 | case STB_TEXTEDIT_K_LINESTART: 1060 | stb_textedit_clamp(str, state); 1061 | stb_textedit_move_to_first(state); 1062 | if (state->single_line) 1063 | state->cursor = 0; 1064 | else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) 1065 | --state->cursor; 1066 | state->has_preferred_x = 0; 1067 | break; 1068 | 1069 | #ifdef STB_TEXTEDIT_K_LINEEND2 1070 | case STB_TEXTEDIT_K_LINEEND2: 1071 | #endif 1072 | case STB_TEXTEDIT_K_LINEEND: { 1073 | int n = STB_TEXTEDIT_STRINGLEN(str); 1074 | stb_textedit_clamp(str, state); 1075 | stb_textedit_move_to_first(state); 1076 | if (state->single_line) 1077 | state->cursor = n; 1078 | else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) 1079 | ++state->cursor; 1080 | state->has_preferred_x = 0; 1081 | break; 1082 | } 1083 | 1084 | #ifdef STB_TEXTEDIT_K_LINESTART2 1085 | case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT: 1086 | #endif 1087 | case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT: 1088 | stb_textedit_clamp(str, state); 1089 | stb_textedit_prep_selection_at_cursor(state); 1090 | if (state->single_line) 1091 | state->cursor = 0; 1092 | else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) 1093 | --state->cursor; 1094 | state->select_end = state->cursor; 1095 | state->has_preferred_x = 0; 1096 | break; 1097 | 1098 | #ifdef STB_TEXTEDIT_K_LINEEND2 1099 | case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT: 1100 | #endif 1101 | case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: { 1102 | int n = STB_TEXTEDIT_STRINGLEN(str); 1103 | stb_textedit_clamp(str, state); 1104 | stb_textedit_prep_selection_at_cursor(state); 1105 | if (state->single_line) 1106 | state->cursor = n; 1107 | else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) 1108 | ++state->cursor; 1109 | state->select_end = state->cursor; 1110 | state->has_preferred_x = 0; 1111 | break; 1112 | } 1113 | } 1114 | } 1115 | 1116 | ///////////////////////////////////////////////////////////////////////////// 1117 | // 1118 | // Undo processing 1119 | // 1120 | // @OPTIMIZE: the undo/redo buffer should be circular 1121 | 1122 | static void stb_textedit_flush_redo(StbUndoState *state) 1123 | { 1124 | state->redo_point = STB_TEXTEDIT_UNDOSTATECOUNT; 1125 | state->redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT; 1126 | } 1127 | 1128 | // discard the oldest entry in the undo list 1129 | static void stb_textedit_discard_undo(StbUndoState *state) 1130 | { 1131 | if (state->undo_point > 0) { 1132 | // if the 0th undo state has characters, clean those up 1133 | if (state->undo_rec[0].char_storage >= 0) { 1134 | int n = state->undo_rec[0].insert_length, i; 1135 | // delete n characters from all other records 1136 | state->undo_char_point -= n; 1137 | STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) (state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE))); 1138 | for (i=0; i < state->undo_point; ++i) 1139 | if (state->undo_rec[i].char_storage >= 0) 1140 | state->undo_rec[i].char_storage -= n; // @OPTIMIZE: get rid of char_storage and infer it 1141 | } 1142 | --state->undo_point; 1143 | STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) (state->undo_point*sizeof(state->undo_rec[0]))); 1144 | } 1145 | } 1146 | 1147 | // discard the oldest entry in the redo list--it's bad if this 1148 | // ever happens, but because undo & redo have to store the actual 1149 | // characters in different cases, the redo character buffer can 1150 | // fill up even though the undo buffer didn't 1151 | static void stb_textedit_discard_redo(StbUndoState *state) 1152 | { 1153 | int k = STB_TEXTEDIT_UNDOSTATECOUNT-1; 1154 | 1155 | if (state->redo_point <= k) { 1156 | // if the k'th undo state has characters, clean those up 1157 | if (state->undo_rec[k].char_storage >= 0) { 1158 | int n = state->undo_rec[k].insert_length, i; 1159 | // move the remaining redo character data to the end of the buffer 1160 | state->redo_char_point += n; 1161 | STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((STB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE))); 1162 | // adjust the position of all the other records to account for above memmove 1163 | for (i=state->redo_point; i < k; ++i) 1164 | if (state->undo_rec[i].char_storage >= 0) 1165 | state->undo_rec[i].char_storage += n; 1166 | } 1167 | // now move all the redo records towards the end of the buffer; the first one is at 'redo_point' 1168 | // [DEAR IMGUI] 1169 | size_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0])); 1170 | const char* buf_begin = (char*)state->undo_rec; (void)buf_begin; 1171 | const char* buf_end = (char*)state->undo_rec + sizeof(state->undo_rec); (void)buf_end; 1172 | IM_ASSERT(((char*)(state->undo_rec + state->redo_point)) >= buf_begin); 1173 | IM_ASSERT(((char*)(state->undo_rec + state->redo_point + 1) + move_size) <= buf_end); 1174 | STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, move_size); 1175 | 1176 | // now move redo_point to point to the new one 1177 | ++state->redo_point; 1178 | } 1179 | } 1180 | 1181 | static StbUndoRecord *stb_text_create_undo_record(StbUndoState *state, int numchars) 1182 | { 1183 | // any time we create a new undo record, we discard redo 1184 | stb_textedit_flush_redo(state); 1185 | 1186 | // if we have no free records, we have to make room, by sliding the 1187 | // existing records down 1188 | if (state->undo_point == STB_TEXTEDIT_UNDOSTATECOUNT) 1189 | stb_textedit_discard_undo(state); 1190 | 1191 | // if the characters to store won't possibly fit in the buffer, we can't undo 1192 | if (numchars > STB_TEXTEDIT_UNDOCHARCOUNT) { 1193 | state->undo_point = 0; 1194 | state->undo_char_point = 0; 1195 | return NULL; 1196 | } 1197 | 1198 | // if we don't have enough free characters in the buffer, we have to make room 1199 | while (state->undo_char_point + numchars > STB_TEXTEDIT_UNDOCHARCOUNT) 1200 | stb_textedit_discard_undo(state); 1201 | 1202 | return &state->undo_rec[state->undo_point++]; 1203 | } 1204 | 1205 | static STB_TEXTEDIT_CHARTYPE *stb_text_createundo(StbUndoState *state, int pos, int insert_len, int delete_len) 1206 | { 1207 | StbUndoRecord *r = stb_text_create_undo_record(state, insert_len); 1208 | if (r == NULL) 1209 | return NULL; 1210 | 1211 | r->where = pos; 1212 | r->insert_length = (STB_TEXTEDIT_POSITIONTYPE) insert_len; 1213 | r->delete_length = (STB_TEXTEDIT_POSITIONTYPE) delete_len; 1214 | 1215 | if (insert_len == 0) { 1216 | r->char_storage = -1; 1217 | return NULL; 1218 | } else { 1219 | r->char_storage = state->undo_char_point; 1220 | state->undo_char_point += insert_len; 1221 | return &state->undo_char[r->char_storage]; 1222 | } 1223 | } 1224 | 1225 | static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 1226 | { 1227 | StbUndoState *s = &state->undostate; 1228 | StbUndoRecord u, *r; 1229 | if (s->undo_point == 0) 1230 | return; 1231 | 1232 | // we need to do two things: apply the undo record, and create a redo record 1233 | u = s->undo_rec[s->undo_point-1]; 1234 | r = &s->undo_rec[s->redo_point-1]; 1235 | r->char_storage = -1; 1236 | 1237 | r->insert_length = u.delete_length; 1238 | r->delete_length = u.insert_length; 1239 | r->where = u.where; 1240 | 1241 | if (u.delete_length) { 1242 | // if the undo record says to delete characters, then the redo record will 1243 | // need to re-insert the characters that get deleted, so we need to store 1244 | // them. 1245 | 1246 | // there are three cases: 1247 | // there's enough room to store the characters 1248 | // characters stored for *redoing* don't leave room for redo 1249 | // characters stored for *undoing* don't leave room for redo 1250 | // if the last is true, we have to bail 1251 | 1252 | if (s->undo_char_point + u.delete_length >= STB_TEXTEDIT_UNDOCHARCOUNT) { 1253 | // the undo records take up too much character space; there's no space to store the redo characters 1254 | r->insert_length = 0; 1255 | } else { 1256 | int i; 1257 | 1258 | // there's definitely room to store the characters eventually 1259 | while (s->undo_char_point + u.delete_length > s->redo_char_point) { 1260 | // should never happen: 1261 | if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) 1262 | return; 1263 | // there's currently not enough room, so discard a redo record 1264 | stb_textedit_discard_redo(s); 1265 | } 1266 | r = &s->undo_rec[s->redo_point-1]; 1267 | 1268 | r->char_storage = s->redo_char_point - u.delete_length; 1269 | s->redo_char_point = s->redo_char_point - u.delete_length; 1270 | 1271 | // now save the characters 1272 | for (i=0; i < u.delete_length; ++i) 1273 | s->undo_char[r->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u.where + i); 1274 | } 1275 | 1276 | // now we can carry out the deletion 1277 | STB_TEXTEDIT_DELETECHARS(str, u.where, u.delete_length); 1278 | } 1279 | 1280 | // check type of recorded action: 1281 | if (u.insert_length) { 1282 | // easy case: was a deletion, so we need to insert n characters 1283 | STB_TEXTEDIT_INSERTCHARS(str, u.where, &s->undo_char[u.char_storage], u.insert_length); 1284 | s->undo_char_point -= u.insert_length; 1285 | } 1286 | 1287 | state->cursor = u.where + u.insert_length; 1288 | 1289 | s->undo_point--; 1290 | s->redo_point--; 1291 | } 1292 | 1293 | static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 1294 | { 1295 | StbUndoState *s = &state->undostate; 1296 | StbUndoRecord *u, r; 1297 | if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) 1298 | return; 1299 | 1300 | // we need to do two things: apply the redo record, and create an undo record 1301 | u = &s->undo_rec[s->undo_point]; 1302 | r = s->undo_rec[s->redo_point]; 1303 | 1304 | // we KNOW there must be room for the undo record, because the redo record 1305 | // was derived from an undo record 1306 | 1307 | u->delete_length = r.insert_length; 1308 | u->insert_length = r.delete_length; 1309 | u->where = r.where; 1310 | u->char_storage = -1; 1311 | 1312 | if (r.delete_length) { 1313 | // the redo record requires us to delete characters, so the undo record 1314 | // needs to store the characters 1315 | 1316 | if (s->undo_char_point + u->insert_length > s->redo_char_point) { 1317 | u->insert_length = 0; 1318 | u->delete_length = 0; 1319 | } else { 1320 | int i; 1321 | u->char_storage = s->undo_char_point; 1322 | s->undo_char_point = s->undo_char_point + u->insert_length; 1323 | 1324 | // now save the characters 1325 | for (i=0; i < u->insert_length; ++i) 1326 | s->undo_char[u->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u->where + i); 1327 | } 1328 | 1329 | STB_TEXTEDIT_DELETECHARS(str, r.where, r.delete_length); 1330 | } 1331 | 1332 | if (r.insert_length) { 1333 | // easy case: need to insert n characters 1334 | STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length); 1335 | s->redo_char_point += r.insert_length; 1336 | } 1337 | 1338 | state->cursor = r.where + r.insert_length; 1339 | 1340 | s->undo_point++; 1341 | s->redo_point++; 1342 | } 1343 | 1344 | static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length) 1345 | { 1346 | stb_text_createundo(&state->undostate, where, 0, length); 1347 | } 1348 | 1349 | static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length) 1350 | { 1351 | int i; 1352 | STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0); 1353 | if (p) { 1354 | for (i=0; i < length; ++i) 1355 | p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); 1356 | } 1357 | } 1358 | 1359 | static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length) 1360 | { 1361 | int i; 1362 | STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length); 1363 | if (p) { 1364 | for (i=0; i < old_length; ++i) 1365 | p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); 1366 | } 1367 | } 1368 | 1369 | // reset the state to default 1370 | static void stb_textedit_clear_state(STB_TexteditState *state, int is_single_line) 1371 | { 1372 | state->undostate.undo_point = 0; 1373 | state->undostate.undo_char_point = 0; 1374 | state->undostate.redo_point = STB_TEXTEDIT_UNDOSTATECOUNT; 1375 | state->undostate.redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT; 1376 | state->select_end = state->select_start = 0; 1377 | state->cursor = 0; 1378 | state->has_preferred_x = 0; 1379 | state->preferred_x = 0; 1380 | state->cursor_at_end_of_line = 0; 1381 | state->initialized = 1; 1382 | state->single_line = (unsigned char) is_single_line; 1383 | state->insert_mode = 0; 1384 | state->row_count_per_page = 0; 1385 | } 1386 | 1387 | // API initialize 1388 | static void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line) 1389 | { 1390 | stb_textedit_clear_state(state, is_single_line); 1391 | } 1392 | 1393 | #if defined(__GNUC__) || defined(__clang__) 1394 | #pragma GCC diagnostic push 1395 | #pragma GCC diagnostic ignored "-Wcast-qual" 1396 | #endif 1397 | 1398 | static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len) 1399 | { 1400 | return stb_textedit_paste_internal(str, state, (STB_TEXTEDIT_CHARTYPE *) ctext, len); 1401 | } 1402 | 1403 | #if defined(__GNUC__) || defined(__clang__) 1404 | #pragma GCC diagnostic pop 1405 | #endif 1406 | 1407 | #endif//STB_TEXTEDIT_IMPLEMENTATION 1408 | 1409 | /* 1410 | ------------------------------------------------------------------------------ 1411 | This software is available under 2 licenses -- choose whichever you prefer. 1412 | ------------------------------------------------------------------------------ 1413 | ALTERNATIVE A - MIT License 1414 | Copyright (c) 2017 Sean Barrett 1415 | Permission is hereby granted, free of charge, to any person obtaining a copy of 1416 | this software and associated documentation files (the "Software"), to deal in 1417 | the Software without restriction, including without limitation the rights to 1418 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 1419 | of the Software, and to permit persons to whom the Software is furnished to do 1420 | so, subject to the following conditions: 1421 | The above copyright notice and this permission notice shall be included in all 1422 | copies or substantial portions of the Software. 1423 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1424 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1425 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1426 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1427 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 1428 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 1429 | SOFTWARE. 1430 | ------------------------------------------------------------------------------ 1431 | ALTERNATIVE B - Public Domain (www.unlicense.org) 1432 | This is free and unencumbered software released into the public domain. 1433 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 1434 | software, either in source code form or as a compiled binary, for any purpose, 1435 | commercial or non-commercial, and by any means. 1436 | In jurisdictions that recognize copyright laws, the author or authors of this 1437 | software dedicate any and all copyright interest in the software to the public 1438 | domain. We make this dedication for the benefit of the public at large and to 1439 | the detriment of our heirs and successors. We intend this dedication to be an 1440 | overt act of relinquishment in perpetuity of all present and future rights to 1441 | this software under copyright law. 1442 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1443 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1444 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1445 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 1446 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 1447 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 1448 | ------------------------------------------------------------------------------ 1449 | */ 1450 | -------------------------------------------------------------------------------- /dwm overlay/renderer.cpp: -------------------------------------------------------------------------------- 1 | #include "framework.h" 2 | #include "tools.h" 3 | #include "renderer.h" 4 | 5 | 6 | namespace overlay { 7 | 8 | //文件版本: 10.0.19041.1387 9 | //名称: dwmcore.dll 10 | //大小: 3580416 字节(3496 KiB) 11 | //CRC32 : E845F058 12 | //CRC64 : 959E58158672DF18 13 | //SHA256 : c843d140b7ddf98dae7de2267cbd94ad1d14865fe6345f2783ae794d7bb78c67 14 | //SHA1 : de86f64a8e7072ea22298b850e14a9c3198f7a93 15 | //BLAKE2sp : 771a5be4bc2bc9894df8aa580f2d390178bc13e8979a4fd7483d87aa0d587084 16 | //系统版本 WINDOWS10 PRO 21H2 19044.1415 17 | 18 | //IDXGISwapChainDWM1即为我们需要的SwapChain,不同版本系统可能不同 19 | //__int64 __fastcall CD3DDevice::PresentMPO(CD3DDevice *this, struct IDXGISwapChainDWM1 *a2, __int64 a3, char a4) 20 | using Fn_Present = __int64(__fastcall*)(void* thisptr, IDXGISwapChain* a2, __int64 a3, char a4); 21 | 22 | Fn_Present Original_Present = NULL; 23 | 24 | static std::once_flag IsInitialized; 25 | 26 | 27 | static ID3D11Device* g_pd3dDevice = NULL; 28 | static ID3D11DeviceContext* g_pd3dDeviceContext = NULL; 29 | static IDXGISwapChain* g_pSwapChain = NULL; 30 | static ID3D11RenderTargetView* g_mainRenderTargetView = NULL; 31 | 32 | void ImGuiInit() 33 | { 34 | if (SUCCEEDED(g_pSwapChain->GetDevice(__uuidof(ID3D11Device), (void**)&g_pd3dDevice))) { 35 | g_pd3dDevice->GetImmediateContext(&g_pd3dDeviceContext); 36 | } 37 | ID3D11Texture2D* RenderTargetTexture = nullptr; 38 | if (SUCCEEDED(g_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&RenderTargetTexture)))) { 39 | g_pd3dDevice->CreateRenderTargetView(RenderTargetTexture, NULL, &g_mainRenderTargetView); 40 | if (!g_mainRenderTargetView) 41 | return; 42 | RenderTargetTexture->Release(); 43 | } 44 | IMGUI_CHECKVERSION(); 45 | ImGui::CreateContext(); 46 | 47 | //初始化 48 | ImGui_ImplWin32_Init(FindWindow(L"Progman", L"Program Manager")); 49 | ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); 50 | 51 | //设置风格 52 | ImGui::StyleColorsLight(); 53 | 54 | //字体设置 55 | ImGuiIO& io = ImGui::GetIO(); 56 | io.ConfigFlags = ImGuiConfigFlags_NoMouseCursorChange; 57 | io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\msyh.ttc", 16.0F, NULL, io.Fonts->GetGlyphRangesChineseFull()); 58 | } 59 | 60 | void DrawEveryThing(IDXGISwapChain* SwapChain) { 61 | 62 | g_pSwapChain = SwapChain; 63 | std::call_once(IsInitialized, [] {ImGuiInit(); }); 64 | ImGui_ImplDX11_NewFrame(); 65 | ImGui_ImplWin32_NewFrame(); 66 | ImGui::NewFrame(); 67 | 68 | ImGui::Begin("Hello, world!"); 69 | ImGui::Text(u8" Gitbub :https://github.com/LoxTus "); 70 | ImGui::Text(u8" 中文显示测试 "); 71 | ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); 72 | ImGui::End(); 73 | ImGui::GetForegroundDrawList()->AddText(ImVec2(10,10),IM_COL32_WHITE," Hello world !"); 74 | ImGui::GetForegroundDrawList()->AddText(ImVec2(10,30), IM_COL32_WHITE, u8" 中文显示测试 "); 75 | 76 | g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, NULL); 77 | ImGui::Render(); 78 | ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); 79 | 80 | } 81 | 82 | __int64 __fastcall DetourFN(void* thisptr, IDXGISwapChain* a2, __int64 a3, char a4) { 83 | DrawEveryThing(a2); 84 | return Original_Present(thisptr, a2, a3, a4); 85 | } 86 | 87 | ULONG64 GetPresentAddress() 88 | { 89 | auto instruction = pattern_scan("dwmcore.dll","E8 ?? ?? ?? ?? 8B D8 85 C0 78 ?? 41 8A D6 49 8B CF E8 ?? ?? ?? ?? EB ??"); 90 | //instruction + instruction size + offset 91 | //相对地址转换绝对地址 92 | auto offsets = *(LONG*)((ULONG64)instruction + 1); 93 | auto result =(ULONG64)instruction + 5 + offsets; 94 | return result; 95 | } 96 | 97 | 98 | void Initialize() { 99 | ULONG64 PresentAddress = GetPresentAddress(); 100 | if (!PresentAddress) 101 | return; 102 | MH_Initialize(); 103 | MH_CreateHook(PVOID(PresentAddress), DetourFN,(LPVOID*)(&Original_Present)); 104 | MH_EnableHook(MH_ALL_HOOKS); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /dwm overlay/renderer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #pragma comment ( lib, "D3D11.lib") 6 | 7 | #include "imgui/imgui.h" 8 | #include "imgui/imgui_impl_win32.h" 9 | #include "imgui/imgui_impl_dx11.h" 10 | #include "MinHook/MinHook.h" 11 | #pragma comment ( lib, "MinHook/libMinHook.x64.lib") 12 | namespace overlay { 13 | void Initialize(); 14 | } -------------------------------------------------------------------------------- /dwm overlay/tools.cpp: -------------------------------------------------------------------------------- 1 | #include"tools.h" 2 | std::uint8_t* pattern_scan(const char* module_name, const char* signature_value) { 3 | const auto module_handle = GetModuleHandleA((LPCSTR)module_name); 4 | 5 | if (!module_handle) 6 | return nullptr; 7 | 8 | static auto pattern_to_byte = [](const char* pattern) { 9 | auto bytes = std::vector{}; 10 | auto start = const_cast(pattern); 11 | auto end = const_cast(pattern) + std::strlen(pattern); 12 | 13 | for (auto current = start; current < end; ++current) { 14 | if (*current == '?') { 15 | ++current; 16 | 17 | if (*current == '?') 18 | ++current; 19 | 20 | bytes.push_back(-1); 21 | } 22 | else { 23 | bytes.push_back(std::strtoul(current, ¤t, 16)); 24 | } 25 | } 26 | return bytes; 27 | }; 28 | auto dos_header = reinterpret_cast(module_handle); 29 | auto nt_headers = 30 | reinterpret_cast(reinterpret_cast(module_handle) + dos_header->e_lfanew); 31 | 32 | auto size_of_image = nt_headers->OptionalHeader.SizeOfImage; 33 | auto pattern_bytes = pattern_to_byte(signature_value); 34 | auto scan_bytes = reinterpret_cast(module_handle); 35 | 36 | auto s = pattern_bytes.size(); 37 | auto d = pattern_bytes.data(); 38 | 39 | for (auto i = 0ul; i < size_of_image - s; ++i) { 40 | bool found = true; 41 | 42 | for (auto j = 0ul; j < s; ++j) { 43 | if (scan_bytes[i + j] != d[j] && d[j] != -1) { 44 | found = false; 45 | break; 46 | } 47 | } 48 | if (found) 49 | return &scan_bytes[i]; 50 | } 51 | } 52 | 53 | -------------------------------------------------------------------------------- /dwm overlay/tools.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | std::uint8_t* pattern_scan(const char* module_name, const char* signature_value); 6 | --------------------------------------------------------------------------------