├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── aero-overlay.sln ├── aero-overlay.vcxproj ├── aero-overlay.vcxproj.filters ├── include └── aero-overlay │ ├── core │ ├── api_status.hpp │ ├── color.hpp │ └── requirements.hpp │ ├── font.hpp │ ├── overlay.hpp │ └── surface.hpp └── src ├── direct2d ├── d2d_font.cpp ├── d2d_font.hpp ├── d2d_surface.cpp ├── d2d_surface.hpp └── pre_include.hpp ├── overlay.cpp └── utils └── string_converter.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | Debug/ 2 | Release/ 3 | ipch 4 | *.db 5 | *.opendb 6 | 7 | # Compiled Object files 8 | *.slo 9 | *.lo 10 | *.o 11 | *.obj 12 | 13 | # Precompiled Headers 14 | *.gch 15 | *.pch 16 | 17 | # Compiled Dynamic libraries 18 | *.so 19 | *.dylib 20 | *.dll 21 | 22 | # Fortran module files 23 | *.mod 24 | 25 | # Compiled Static libraries 26 | *.lai 27 | *.la 28 | *.a 29 | *.lib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.opensdf 36 | *.user 37 | 38 | ## Ignore Visual Studio temporary files, build results, and 39 | ## files generated by popular Visual Studio add-ons. 40 | 41 | # User-specific files 42 | *.suo 43 | *.user 44 | *.userosscache 45 | *.sln.docstates 46 | *.VC.db 47 | 48 | # User-specific files (MonoDevelop/Xamarin Studio) 49 | *.userprefs 50 | 51 | # Build results 52 | [Dd]ebug/ 53 | [Dd]ebugPublic/ 54 | [Rr]elease/ 55 | [Rr]eleases/ 56 | x64/ 57 | x86/ 58 | build/ 59 | bld/ 60 | [Bb]in/ 61 | [Oo]bj/ 62 | 63 | # Visual Studio 2015 cache/options directory 64 | .vs/ 65 | 66 | # MSTest test Results 67 | [Tt]est[Rr]esult*/ 68 | [Bb]uild[Ll]og.* 69 | 70 | # NUNIT 71 | *.VisualState.xml 72 | TestResult.xml 73 | 74 | # Build Results of an ATL Project 75 | [Dd]ebugPS/ 76 | [Rr]eleasePS/ 77 | dlldata.c 78 | 79 | # DNX 80 | project.lock.json 81 | artifacts/ 82 | 83 | *_i.c 84 | *_p.c 85 | *_i.h 86 | *.ilk 87 | *.meta 88 | *.obj 89 | *.pch 90 | *.pdb 91 | *.pgc 92 | *.pgd 93 | *.rsp 94 | *.sbr 95 | *.tlb 96 | *.tli 97 | *.tlh 98 | *.tmp 99 | *.tmp_proj 100 | *.log 101 | *.vspscc 102 | *.vssscc 103 | .builds 104 | *.pidb 105 | *.svclog 106 | *.scc 107 | 108 | # Chutzpah Test files 109 | _Chutzpah* 110 | 111 | # Visual C++ cache files 112 | ipch/ 113 | *.aps 114 | *.ncb 115 | *.opensdf 116 | *.sdf 117 | *.cachefile 118 | 119 | # Visual Studio profiler 120 | *.psess 121 | *.vsp 122 | *.vspx 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # JustCode is a .NET coding add-in 136 | .JustCode 137 | 138 | # TeamCity is a build add-in 139 | _TeamCity* 140 | 141 | # DotCover is a Code Coverage Tool 142 | *.dotCover 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | 148 | # MightyMoose 149 | *.mm.* 150 | AutoTest.Net/ 151 | 152 | # Web workbench (sass) 153 | .sass-cache/ 154 | 155 | # Installshield output folder 156 | [Ee]xpress/ 157 | 158 | # DocProject is a documentation generator add-in 159 | DocProject/buildhelp/ 160 | DocProject/Help/*.HxT 161 | DocProject/Help/*.HxC 162 | DocProject/Help/*.hhc 163 | DocProject/Help/*.hhk 164 | DocProject/Help/*.hhp 165 | DocProject/Help/Html2 166 | DocProject/Help/html 167 | 168 | # Click-Once directory 169 | publish/ 170 | 171 | # Publish Web Output 172 | *.[Pp]ublish.xml 173 | *.azurePubxml 174 | # TODO: Comment the next line if you want to checkin your web deploy settings 175 | # but database connection strings (with potential passwords) will be unencrypted 176 | *.pubxml 177 | *.publishproj 178 | 179 | # NuGet Packages 180 | *.nupkg 181 | # The packages folder can be ignored because of Package Restore 182 | **/packages/* 183 | # except build/, which is used as an MSBuild target. 184 | !**/packages/build/ 185 | # Uncomment if necessary however generally it will be regenerated when needed 186 | #!**/packages/repositories.config 187 | 188 | # Windows Azure Build Output 189 | csx/ 190 | *.build.csdef 191 | 192 | # Windows Store app package directory 193 | AppPackages/ 194 | 195 | # Visual Studio cache files 196 | # files ending in .cache can be ignored 197 | *.[Cc]ache 198 | # but keep track of directories ending in .cache 199 | !*.[Cc]ache/ 200 | 201 | # Others 202 | ClientBin/ 203 | [Ss]tyle[Cc]op.* 204 | ~$* 205 | *~ 206 | *.dbmdl 207 | *.dbproj.schemaview 208 | *.pfx 209 | *.publishsettings 210 | node_modules/ 211 | orleans.codegen.cs 212 | 213 | # RIA/Silverlight projects 214 | Generated_Code/ 215 | 216 | # Backup & report files from converting an old project file 217 | # to a newer Visual Studio version. Backup files are not needed, 218 | # because we have git ;-) 219 | _UpgradeReport_Files/ 220 | Backup*/ 221 | UpgradeLog*.XML 222 | UpgradeLog*.htm 223 | 224 | # SQL Server files 225 | *.mdf 226 | *.ldf 227 | 228 | # Business Intelligence projects 229 | *.rdl.data 230 | *.bim.layout 231 | *.bim_*.settings 232 | 233 | # Microsoft Fakes 234 | FakesAssemblies/ 235 | 236 | # Node.js Tools for Visual Studio 237 | .ntvs_analysis.dat 238 | 239 | # Visual Studio 6 build log 240 | *.plg 241 | 242 | # Visual Studio 6 workspace options file 243 | *.opt 244 | /.project 245 | *.ini 246 | 247 | # Line Ending Unifier 248 | *.leu 249 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "aero-overlay/contrib/DirectX-SDK"] 2 | path = aero-overlay/contrib/DirectX-SDK 3 | url = https://github.com/ReactiioN1337/DirectX-SDK 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-2020 ReactiioN . 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # aero-overlay 2 | 3 | A transparent window which is located above a target window to have the possibility to draw over it. 4 | My initial code can be found in [1.0 branch](https://github.com/ReactiioN1337/aero-overlay/tree/1.0), 5 | development takes place in `develop` branch. Do **not** push into the `master` branch. 6 | 7 | ## Installation 8 | 9 | > I'm using `/MT` in **release** and `/MTd` in **debug** as runtime library. So either adjust your project settings to mine or vice versa! 10 | 11 | - Clone the repository into your solution directory (I alway do this in `contrib`) 12 | - Right click on your solution 13 | - Add > Existing Project ... > and select the `aero-overlay.vcxproj` 14 | - Right click on your project in your solution 15 | - Add > Reference... > and select `aero-overlay` 16 | - Right click on your project in your solution > Properties 17 | - C/C++ > General > Additional Include Directories and add the `include` directory of this repository! 18 | 19 | ## Usage 20 | 21 | A basic overlay can be created using the title, process id or window handle. 22 | 23 | ```C++ 24 | #include 25 | 26 | std::int32_t main( 27 | const std::int32_t argc, 28 | const char** argv 29 | ) 30 | { 31 | if( argc < 2 ) { 32 | printf( R"(usage: 33 | executable.exe "SuperCoolGameTitle" 34 | )" ); 35 | return -1; 36 | } 37 | 38 | const auto overlay = std::make_unique(); 39 | const auto status = overlay->attach( argv[ 1 ] ); 40 | 41 | if( status != aero::api_status::success ) { 42 | printf( "[>] failed to create overlay: %d\n", status ); 43 | return -1; 44 | } 45 | 46 | const auto surface = overlay->get_surface(); 47 | const auto font = surface->add_font( "test", "Verdana", 12.f ); 48 | 49 | surface->add_callback([&surface, &font] 50 | { 51 | surface->text( 5.f, 5.f, font, 0xFFFFFFFF, "this is an example" ); 52 | } ); 53 | 54 | while( overlay->message_loop() ) { 55 | if( surface->begin_scene() ) { 56 | surface->end_scene(); 57 | } 58 | 59 | std::this_thread::sleep_for( std::chrono::milliseconds( 2 ) ); 60 | } 61 | }; 62 | ``` 63 | 64 | > Callbacks are only executed if the target window is in foreground 65 | 66 | ## Custom rendering support 67 | 68 | With `overlay::set_surface()` you can use your own components. You only need to re-implement the classes `font` and `surface`. 69 | 70 | > This function **must be called** before `attach()`! 71 | 72 | ```C++ 73 | overlay->set_surface( std::make_share() ); 74 | 75 | const auto status = overlay->attach( ... ); 76 | ``` 77 | -------------------------------------------------------------------------------- /aero-overlay.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29509.3 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aero-overlay", "aero-overlay.vcxproj", "{816AFBDE-1DB1-4CD9-AD75-44D41F7C4D67}" 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 | {816AFBDE-1DB1-4CD9-AD75-44D41F7C4D67}.Debug|x64.ActiveCfg = Debug|x64 17 | {816AFBDE-1DB1-4CD9-AD75-44D41F7C4D67}.Debug|x64.Build.0 = Debug|x64 18 | {816AFBDE-1DB1-4CD9-AD75-44D41F7C4D67}.Debug|x86.ActiveCfg = Debug|Win32 19 | {816AFBDE-1DB1-4CD9-AD75-44D41F7C4D67}.Debug|x86.Build.0 = Debug|Win32 20 | {816AFBDE-1DB1-4CD9-AD75-44D41F7C4D67}.Release|x64.ActiveCfg = Release|x64 21 | {816AFBDE-1DB1-4CD9-AD75-44D41F7C4D67}.Release|x64.Build.0 = Release|x64 22 | {816AFBDE-1DB1-4CD9-AD75-44D41F7C4D67}.Release|x86.ActiveCfg = Release|Win32 23 | {816AFBDE-1DB1-4CD9-AD75-44D41F7C4D67}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {AA6F767F-4D9D-4F28-894B-7E28C62F7D75} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /aero-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 | {816AFBDE-1DB1-4CD9-AD75-44D41F7C4D67} 24 | aerooverlay 25 | 10.0 26 | 27 | 28 | 29 | StaticLibrary 30 | true 31 | v142 32 | MultiByte 33 | 34 | 35 | StaticLibrary 36 | false 37 | v142 38 | true 39 | MultiByte 40 | 41 | 42 | StaticLibrary 43 | true 44 | v142 45 | MultiByte 46 | 47 | 48 | StaticLibrary 49 | false 50 | v142 51 | true 52 | MultiByte 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | $(SolutionDir)build\$(Configuration)-$(PlatformTarget)\ 74 | $(SolutionDir)build\$(Configuration)-$(PlatformTarget)\tmp\$(ProjectName)\ 75 | $(IncludePath) 76 | 77 | 78 | $(SolutionDir)build\$(Configuration)-$(PlatformTarget)\ 79 | $(SolutionDir)build\$(Configuration)-$(PlatformTarget)\tmp\$(ProjectName)\ 80 | $(IncludePath) 81 | 82 | 83 | $(SolutionDir)build\$(Configuration)-$(PlatformTarget)\ 84 | $(SolutionDir)build\$(Configuration)-$(PlatformTarget)\tmp\$(ProjectName)\ 85 | $(IncludePath) 86 | 87 | 88 | $(SolutionDir)build\$(Configuration)-$(PlatformTarget)\ 89 | $(SolutionDir)build\$(Configuration)-$(PlatformTarget)\tmp\$(ProjectName)\ 90 | $(IncludePath) 91 | 92 | 93 | 94 | Level3 95 | Disabled 96 | true 97 | true 98 | $(ProjectDir)include;%(AdditionalIncludeDirectories) 99 | stdcpp17 100 | true 101 | MultiThreadedDebug 102 | 103 | 104 | Console 105 | dwmapi.lib;d3d9.lib;%(AdditionalDependencies) 106 | 107 | 108 | 109 | 110 | Level3 111 | Disabled 112 | true 113 | true 114 | $(ProjectDir)include;%(AdditionalIncludeDirectories) 115 | stdcpp17 116 | true 117 | MultiThreadedDebug 118 | 119 | 120 | Console 121 | dwmapi.lib;d3d9.lib;%(AdditionalDependencies) 122 | 123 | 124 | 125 | 126 | Level3 127 | MaxSpeed 128 | true 129 | true 130 | true 131 | true 132 | $(ProjectDir)include;%(AdditionalIncludeDirectories) 133 | stdcpp17 134 | true 135 | MultiThreaded 136 | 137 | 138 | Console 139 | true 140 | true 141 | dwmapi.lib;d3d9.lib;%(AdditionalDependencies) 142 | 143 | 144 | 145 | 146 | Level3 147 | MaxSpeed 148 | true 149 | true 150 | true 151 | true 152 | $(ProjectDir)include;%(AdditionalIncludeDirectories) 153 | stdcpp17 154 | true 155 | MultiThreaded 156 | 157 | 158 | Console 159 | true 160 | true 161 | dwmapi.lib;d3d9.lib;%(AdditionalDependencies) 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /aero-overlay.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;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 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | 29 | 30 | Header Files 31 | 32 | 33 | Header Files 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files 58 | 59 | 60 | -------------------------------------------------------------------------------- /include/aero-overlay/core/api_status.hpp: -------------------------------------------------------------------------------- 1 | ///-------------------------------------------------------------------------------- 2 | ///-- Author ReactiioN 3 | ///-- Copyright 2016-2020, ReactiioN 4 | ///-- License MIT 5 | ///-------------------------------------------------------------------------------- 6 | #pragma once 7 | 8 | #include 9 | 10 | namespace aero { 11 | enum class api_status 12 | : std::uint32_t 13 | { 14 | success = 0, 15 | missing_factory_to_create_font, 16 | missing_family_to_create_font, 17 | failed_to_create_font, 18 | missing_window_handle, 19 | missing_window_title, 20 | failed_to_create_surface_factory, 21 | failed_to_create_render_target, 22 | missing_aero_feature, 23 | failed_to_register_window, 24 | failed_to_create_window, 25 | failed_to_make_window_transparent 26 | }; 27 | 28 | constexpr std::uint32_t api_status_code( 29 | const api_status status 30 | ) 31 | { 32 | return static_cast>( status ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /include/aero-overlay/core/color.hpp: -------------------------------------------------------------------------------- 1 | ///-------------------------------------------------------------------------------- 2 | ///-- Author ReactiioN 3 | ///-- Copyright 2016-2020, ReactiioN 4 | ///-- License MIT 5 | ///-------------------------------------------------------------------------------- 6 | #pragma once 7 | 8 | #include 9 | 10 | namespace aero { 11 | class color final 12 | { 13 | public: 14 | using type_rgba = std::array; 15 | 16 | constexpr static 17 | type_rgba hex_to_rgba( 18 | const std::uint32_t hex 19 | ) 20 | { 21 | return type_rgba{ 22 | static_cast( hex >> 16 & 0xFF ), 23 | static_cast( hex >> 8 & 0xFF ), 24 | static_cast( hex & 0xFF ), 25 | static_cast( hex >> 24 & 0xFF ) 26 | }; 27 | } 28 | 29 | constexpr __forceinline static 30 | std::uint32_t rgba_to_hex( 31 | const type_rgba& rgba 32 | ) 33 | { 34 | return rgba_to_hex( rgba[ 0 ], rgba[ 1 ], rgba[ 2 ], rgba[ 3 ] ); 35 | } 36 | 37 | constexpr __forceinline static 38 | std::uint32_t rgba_to_hex( 39 | const std::uint8_t& r, 40 | const std::uint8_t& g, 41 | const std::uint8_t& b, 42 | const std::uint8_t& a = 255 43 | ) 44 | { 45 | return static_cast( a << 24 | r << 16 | g << 8 | b ); 46 | } 47 | 48 | constexpr __forceinline static 49 | std::uint8_t r_channel( 50 | const std::uint32_t& hex_color 51 | ) 52 | { 53 | return hex_color >> 16 & 0xFF; 54 | } 55 | 56 | constexpr __forceinline static 57 | std::uint8_t g_channel( 58 | const std::uint32_t& hex_color 59 | ) 60 | { 61 | return hex_color >> 8 & 0xFF; 62 | } 63 | 64 | constexpr __forceinline static 65 | std::uint8_t b_channel( 66 | const std::uint32_t& hex_color 67 | ) 68 | { 69 | return hex_color & 0xFF; 70 | } 71 | 72 | constexpr __forceinline static 73 | std::uint8_t a_channel( 74 | const std::uint32_t& hex_color 75 | ) 76 | { 77 | return hex_color >> 24 & 0xFF; 78 | } 79 | 80 | 81 | public: 82 | constexpr color() = default; 83 | 84 | ~color() = default; 85 | 86 | constexpr __forceinline 87 | color( 88 | const color& col 89 | ) = default; 90 | 91 | __forceinline 92 | color( 93 | color&& col 94 | ) noexcept 95 | { 96 | *this = std::move( col ); 97 | } 98 | 99 | constexpr __forceinline 100 | color( 101 | const type_rgba& rgba 102 | ) : _rgba( rgba ) 103 | { } 104 | 105 | constexpr __forceinline 106 | color( 107 | const std::uint32_t hex 108 | ) noexcept 109 | { 110 | set( hex ); 111 | } 112 | 113 | template 114 | constexpr __forceinline 115 | color( 116 | const type_r r, 117 | const type_g g, 118 | const type_b b, 119 | const type_a a = static_cast( 255 ) 120 | ) noexcept 121 | { 122 | set( r, g, b, a ); 123 | } 124 | 125 | constexpr __forceinline 126 | color& operator = ( 127 | const color& rhs 128 | ) noexcept = default; 129 | 130 | __forceinline 131 | color& operator = ( 132 | color&& rhs 133 | ) noexcept 134 | { 135 | _rgba = rhs._rgba; 136 | rhs.set( 0 ); 137 | return *this; 138 | } 139 | 140 | __forceinline 141 | color& operator = ( 142 | const type_rgba& rhs 143 | ) noexcept 144 | { 145 | _rgba = rhs; 146 | return *this; 147 | } 148 | 149 | constexpr __forceinline 150 | color& operator = ( 151 | const std::uint32_t rhs 152 | ) noexcept 153 | { 154 | set( rhs ); 155 | return *this; 156 | } 157 | 158 | constexpr __forceinline 159 | color& operator += ( 160 | const type_rgba& rhs 161 | ) noexcept 162 | { 163 | for( std::size_t i = 0; i < 4; ++i ) { 164 | at( i ) = static_cast( std::clamp( at( i ) + rhs[ i ], 0, 255 ) ); 165 | } 166 | return *this; 167 | } 168 | 169 | constexpr __forceinline 170 | color& operator += ( 171 | const color& rhs 172 | ) noexcept 173 | { 174 | *this += rhs._rgba; 175 | return *this; 176 | } 177 | 178 | constexpr __forceinline 179 | color& operator += ( 180 | const std::uint32_t rhs 181 | ) noexcept 182 | { 183 | 184 | *this += hex_to_rgba( rhs ); 185 | return *this; 186 | } 187 | 188 | constexpr __forceinline 189 | color& operator -= ( 190 | const type_rgba& rhs 191 | ) noexcept 192 | { 193 | for( std::size_t i = 0; i < 4; ++i ) { 194 | at( i ) = static_cast( std::clamp( at( i ) - rhs[ i ], 0, 255 ) ); 195 | } 196 | return *this; 197 | } 198 | 199 | constexpr __forceinline 200 | color& operator -= ( 201 | const color& rhs 202 | ) noexcept 203 | { 204 | *this -= rhs._rgba; 205 | return *this; 206 | } 207 | 208 | constexpr __forceinline 209 | color& operator -= ( 210 | const std::uint32_t rhs 211 | ) noexcept 212 | { 213 | 214 | *this -= hex_to_rgba( rhs ); 215 | return *this; 216 | } 217 | 218 | _NODISCARD __forceinline 219 | color operator + ( 220 | const type_rgba& rhs 221 | ) const noexcept 222 | { 223 | auto lhs = *this; 224 | lhs += rhs; 225 | return lhs; 226 | } 227 | 228 | _NODISCARD __forceinline 229 | color operator + ( 230 | const color& rhs 231 | ) const noexcept 232 | { 233 | auto lhs = *this; 234 | lhs += rhs; 235 | return lhs; 236 | } 237 | 238 | _NODISCARD __forceinline 239 | color operator + ( 240 | const std::uint32_t rhs 241 | ) const noexcept 242 | { 243 | auto lhs = *this; 244 | lhs += rhs; 245 | return lhs; 246 | } 247 | 248 | _NODISCARD __forceinline 249 | color operator - ( 250 | const type_rgba& rhs 251 | ) const noexcept 252 | { 253 | auto lhs = *this; 254 | lhs -= rhs; 255 | return lhs; 256 | } 257 | 258 | _NODISCARD __forceinline 259 | color operator - ( 260 | const color& rhs 261 | ) const noexcept 262 | { 263 | auto lhs = *this; 264 | lhs -= rhs; 265 | return lhs; 266 | } 267 | 268 | _NODISCARD __forceinline 269 | color operator - ( 270 | const std::uint32_t rhs 271 | ) const noexcept 272 | { 273 | auto lhs = *this; 274 | lhs -= rhs; 275 | return lhs; 276 | } 277 | 278 | _NODISCARD constexpr __forceinline 279 | bool operator == ( 280 | const color& rhs 281 | ) const noexcept 282 | { 283 | return rgba_to_hex( _rgba ) == rhs.hex(); 284 | } 285 | 286 | _NODISCARD constexpr __forceinline 287 | bool operator == ( 288 | const std::uint32_t rhs 289 | ) const noexcept 290 | { 291 | return rgba_to_hex( _rgba ) == rhs; 292 | } 293 | 294 | _NODISCARD constexpr __forceinline 295 | bool operator != ( 296 | const color& rhs 297 | ) const noexcept 298 | { 299 | return !( *this == rhs ); 300 | } 301 | 302 | _NODISCARD constexpr __forceinline 303 | bool operator != ( 304 | const std::uint32_t rhs 305 | ) const noexcept 306 | { 307 | return !( *this == rhs ); 308 | } 309 | 310 | constexpr __forceinline 311 | std::uint8_t& at( 312 | const std::size_t index 313 | ) noexcept 314 | { 315 | return _rgba.at( std::clamp( index, static_cast( 0 ), static_cast( 3 ) ) ); 316 | } 317 | 318 | _NODISCARD constexpr __forceinline 319 | const std::uint8_t& at( 320 | const std::size_t index 321 | ) const noexcept 322 | { 323 | return _rgba.at( std::clamp( index, static_cast( 0 ), static_cast( 3 ) ) ); 324 | } 325 | 326 | template 327 | constexpr __forceinline 328 | void set( 329 | const type_r r, 330 | const type_g g, 331 | const type_b b, 332 | const type_a a = static_cast( 255 ) 333 | ) noexcept 334 | { 335 | at( 0 ) = static_cast( std::clamp( static_cast( r ), 0, 255 ) ); 336 | at( 1 ) = static_cast( std::clamp( static_cast( g ), 0, 255 ) ); 337 | at( 2 ) = static_cast( std::clamp( static_cast( b ), 0, 255 ) ); 338 | at( 3 ) = static_cast( std::clamp( static_cast( a ), 0, 255 ) ); 339 | } 340 | 341 | constexpr __forceinline 342 | void set( 343 | const std::uint32_t hex 344 | ) noexcept 345 | { 346 | _rgba = hex_to_rgba( hex ); 347 | } 348 | 349 | constexpr __forceinline 350 | void set_opacity( 351 | const float value 352 | ) noexcept 353 | { 354 | at( 3 ) = static_cast( std::clamp( value, 0.f, 1.f ) * 255.f ); 355 | } 356 | 357 | constexpr __forceinline 358 | void set_norm( 359 | const float r, 360 | const float g, 361 | const float b, 362 | const float a = 1.f 363 | ) noexcept 364 | { 365 | set( 366 | std::clamp( r, 0.f, 1.f ) * 255.f, 367 | std::clamp( g, 0.f, 1.f ) * 255.f, 368 | std::clamp( b, 0.f, 1.f ) * 255.f, 369 | std::clamp( a, 0.f, 1.f ) * 255.f 370 | ); 371 | } 372 | 373 | _NODISCARD constexpr __forceinline 374 | std::uint32_t hex( 375 | ) const noexcept 376 | { 377 | return rgba_to_hex( _rgba ); 378 | } 379 | 380 | template 381 | _NODISCARD constexpr __forceinline 382 | type r( 383 | ) const noexcept 384 | { 385 | return static_cast( at( 0 ) ); 386 | } 387 | 388 | template 389 | _NODISCARD constexpr __forceinline 390 | type g( 391 | ) const noexcept 392 | { 393 | return static_cast( at( 1 ) ); 394 | } 395 | 396 | template 397 | _NODISCARD constexpr __forceinline 398 | type b( 399 | ) const noexcept 400 | { 401 | return static_cast( at( 2 ) ); 402 | } 403 | 404 | template 405 | _NODISCARD constexpr __forceinline 406 | type a( 407 | ) const noexcept 408 | { 409 | return static_cast( at( 3 ) ); 410 | } 411 | 412 | _NODISCARD constexpr __forceinline 413 | float r_norm( 414 | ) const noexcept 415 | { 416 | return r() / 255.f; 417 | } 418 | 419 | _NODISCARD constexpr __forceinline 420 | float g_norm( 421 | ) const noexcept 422 | { 423 | return g() / 255.f; 424 | } 425 | 426 | _NODISCARD constexpr __forceinline 427 | float b_norm( 428 | ) const noexcept 429 | { 430 | return b() / 255.f; 431 | } 432 | 433 | _NODISCARD constexpr __forceinline 434 | float a_norm( 435 | ) const noexcept 436 | { 437 | return a() / 255.f; 438 | } 439 | 440 | private: 441 | type_rgba _rgba{}; 442 | }; 443 | 444 | } 445 | -------------------------------------------------------------------------------- /include/aero-overlay/core/requirements.hpp: -------------------------------------------------------------------------------- 1 | ///-------------------------------------------------------------------------------- 2 | ///-- Author ReactiioN 3 | ///-- Copyright 2016-2020, ReactiioN 4 | ///-- License MIT 5 | ///-------------------------------------------------------------------------------- 6 | #pragma once 7 | #if !defined(_CRT_SECURE_NO_WARNINGS) 8 | #define _CRT_SECURE_NO_WARNINGS 9 | #endif 10 | 11 | #if !defined(NOMINMAX) 12 | #define NOMINMAX 13 | #endif 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | -------------------------------------------------------------------------------- /include/aero-overlay/font.hpp: -------------------------------------------------------------------------------- 1 | ///-------------------------------------------------------------------------------- 2 | ///-- Author ReactiioN 3 | ///-- Copyright 2016-2020, ReactiioN 4 | ///-- License MIT 5 | ///-------------------------------------------------------------------------------- 6 | #pragma once 7 | 8 | #include 9 | 10 | namespace aero { 11 | class font abstract 12 | { 13 | protected: 14 | font( 15 | const std::string& family, 16 | const float height, 17 | const std::uint32_t weight, 18 | const std::uint32_t flags 19 | ) 20 | : _family( family ) 21 | , _height( height ) 22 | , _weight( weight ) 23 | , _flags( flags ) 24 | { } 25 | 26 | public: 27 | virtual ~font() = default; 28 | 29 | virtual api_status create() = 0; 30 | 31 | virtual void release() = 0; 32 | 33 | virtual void** address_of() noexcept = 0; 34 | 35 | virtual void* get_data() const noexcept = 0; 36 | 37 | virtual void get_text_size( 38 | std::wstring_view text, 39 | float* width, 40 | float* height 41 | ) = 0; 42 | 43 | virtual void get_text_size( 44 | std::string_view text, 45 | float* width, 46 | float* height 47 | ) = 0; 48 | 49 | _NODISCARD 50 | std::string_view get_family() const noexcept 51 | { 52 | return _family; 53 | } 54 | 55 | _NODISCARD constexpr 56 | float get_height() const noexcept 57 | { 58 | return _height; 59 | } 60 | 61 | _NODISCARD constexpr 62 | std::uint32_t get_weight() const noexcept 63 | { 64 | return _weight; 65 | } 66 | 67 | _NODISCARD constexpr 68 | std::uint32_t get_flags() const noexcept 69 | { 70 | return _flags; 71 | } 72 | 73 | template 74 | _NODISCARD 75 | type** address_of() noexcept 76 | { 77 | return reinterpret_cast( address_of() ); 78 | } 79 | 80 | template 81 | _NODISCARD 82 | type* get_data() const noexcept 83 | { 84 | return static_cast( get_data() ); 85 | } 86 | protected: 87 | std::string _family; 88 | float _height = 0.f; 89 | std::uint32_t _weight = 0; 90 | std::uint32_t _flags = 0; 91 | }; 92 | 93 | using font_ptr = std::shared_ptr; 94 | } 95 | -------------------------------------------------------------------------------- /include/aero-overlay/overlay.hpp: -------------------------------------------------------------------------------- 1 | ///-------------------------------------------------------------------------------- 2 | ///-- Author ReactiioN 3 | ///-- Copyright 2016-2020, ReactiioN 4 | ///-- License MIT 5 | ///-------------------------------------------------------------------------------- 6 | #pragma once 7 | 8 | #include 9 | 10 | namespace aero { 11 | 12 | class overlay final 13 | { 14 | public: 15 | overlay(); 16 | 17 | overlay( 18 | const overlay& 19 | ) = delete; 20 | 21 | overlay( 22 | overlay&& rhs 23 | ) noexcept; 24 | 25 | ~overlay(); 26 | 27 | overlay& operator = ( 28 | const overlay& 29 | ) = delete; 30 | 31 | overlay& operator = ( 32 | overlay&& rhs 33 | ) noexcept; 34 | 35 | api_status attach( 36 | std::string_view window_title 37 | ); 38 | 39 | api_status attach( 40 | std::uint32_t process_id 41 | ); 42 | 43 | api_status attach( 44 | HWND target_window 45 | ); 46 | 47 | void destroy(); 48 | 49 | _NODISCARD 50 | bool message_loop() const noexcept; 51 | 52 | void scale(); 53 | 54 | void set_surface( 55 | surface_ptr surface 56 | ); 57 | 58 | _NODISCARD __forceinline 59 | const std::string& get_class_name() const noexcept 60 | { 61 | return _class; 62 | } 63 | 64 | _NODISCARD __forceinline 65 | const std::string& get_title() const noexcept 66 | { 67 | return _title; 68 | } 69 | 70 | _NODISCARD 71 | surface_ptr get_surface() const noexcept 72 | { 73 | return _surface; 74 | } 75 | 76 | private: 77 | static std::intptr_t __stdcall window_proc( 78 | void* window_handle, 79 | std::uint32_t message, 80 | std::uintptr_t wparam, 81 | std::intptr_t lparam 82 | ); 83 | 84 | private: 85 | std::string _class; 86 | std::string _title; 87 | HWND _window = nullptr; 88 | HWND _target = nullptr; 89 | std::uint32_t _width = 0; 90 | std::uint32_t _height = 0; 91 | surface_ptr _surface; 92 | }; 93 | 94 | } 95 | -------------------------------------------------------------------------------- /include/aero-overlay/surface.hpp: -------------------------------------------------------------------------------- 1 | ///-------------------------------------------------------------------------------- 2 | ///-- Author ReactiioN 3 | ///-- Copyright 2016-2020, ReactiioN 4 | ///-- License MIT 5 | ///-------------------------------------------------------------------------------- 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | namespace aero { 12 | class surface abstract 13 | { 14 | protected: 15 | using font_map = std::unordered_map; 16 | using render_callback_fn = std::function; 17 | using render_callbacks = std::vector; 18 | 19 | public: 20 | virtual ~surface() = default; 21 | 22 | virtual api_status initialize( 23 | void* overlay_handle, 24 | void* target_handle 25 | ) = 0; 26 | 27 | virtual void release() = 0; 28 | 29 | virtual font_ptr add_font( 30 | const std::string& name, 31 | const std::string& family, 32 | float height, 33 | std::uint32_t weight = 400, 34 | std::uint32_t flags = 0 35 | ) = 0; 36 | 37 | virtual void border_box( 38 | float x, 39 | float y, 40 | float w, 41 | float h, 42 | float thickness, 43 | const color& col, 44 | float thickness_outside = 0.f, 45 | float thickness_inside = 0.f, 46 | const color& col_outside = 0xFF010101, 47 | const color& col_inside = 0xFF010101 48 | ) = 0; 49 | 50 | virtual void line( 51 | float start_x, 52 | float start_y, 53 | float end_x, 54 | float end_y, 55 | const color& col 56 | ) = 0; 57 | 58 | virtual void rect( 59 | float x, 60 | float y, 61 | float w, 62 | float h, 63 | const color& col, 64 | float thickness_outside = 0.f, 65 | const color& col_outside = 0xFF010101 66 | ) = 0; 67 | 68 | virtual void text_ansii( 69 | float x, 70 | float y, 71 | const font_ptr& font, 72 | const color& col, 73 | std::string_view text 74 | ) = 0; 75 | 76 | virtual void text_unicode( 77 | float x, 78 | float y, 79 | const font_ptr& font, 80 | const color& col, 81 | std::wstring_view text 82 | ) = 0; 83 | 84 | virtual bool begin_scene() = 0; 85 | 86 | virtual void end_scene() = 0; 87 | 88 | _NODISCARD constexpr 89 | float get_width() const noexcept 90 | { 91 | return _width; 92 | } 93 | 94 | _NODISCARD constexpr 95 | float get_height() const noexcept 96 | { 97 | return _height; 98 | } 99 | 100 | _NODISCARD constexpr 101 | bool is_visible() const noexcept 102 | { 103 | return _visible; 104 | } 105 | 106 | void add_callback( 107 | render_callback_fn callback 108 | ) 109 | { 110 | if( callback ) { 111 | _callbacks.emplace_back( std::move( callback ) ); 112 | } 113 | } 114 | 115 | _NODISCARD 116 | font_ptr get_font( 117 | const std::string& name 118 | ) const noexcept 119 | { 120 | return _fonts.count( name ) 121 | ? _fonts.at( name ) 122 | : nullptr; 123 | } 124 | 125 | template 126 | void get_text_size( 127 | const std::basic_string_view text, 128 | const font_ptr& font, 129 | float* const width, 130 | float* const height 131 | ) const noexcept 132 | { 133 | static_assert( std::is_same_v || std::is_same_v ); 134 | 135 | if( font ) { 136 | font->get_text_size( text, width, height ); 137 | } 138 | } 139 | 140 | template 141 | void get_text_size( 142 | const std::basic_string_view text, 143 | const std::string& font_name, 144 | float* const width, 145 | float* const height 146 | ) const noexcept 147 | { 148 | get_text_size( text, get_font( font_name ), width, height ); 149 | } 150 | 151 | template 152 | void text( 153 | const float x, 154 | const float y, 155 | const font_ptr& font, 156 | const color& col, 157 | const char* fmt, 158 | arguments&& ...args 159 | ) 160 | { 161 | if( fmt && font ) { 162 | const std::size_t len = std::snprintf( nullptr, 0, fmt, args... ) + 1; 163 | const auto final_len = std::min( len, buffer_size + 1 ); 164 | 165 | char buffer[ buffer_size + 1 ]{}; 166 | std::snprintf( buffer, final_len, fmt, args... ); 167 | 168 | text_ansii( x, y, font, col, std::string( buffer, buffer + final_len - 1 ) ); 169 | } 170 | } 171 | 172 | template 173 | void text( 174 | const float x, 175 | const float y, 176 | const font_ptr& font, 177 | const color& col, 178 | const wchar_t* fmt, 179 | arguments&& ...args 180 | ) 181 | { 182 | if( fmt && font ) { 183 | const std::size_t len = std::swprintf( nullptr, 0, fmt, args... ) + 1; 184 | const auto final_len = std::min( len, buffer_size + 1 ); 185 | 186 | wchar_t buffer[ buffer_size + 1 ]{}; 187 | std::swprintf( buffer, final_len, fmt, args... ); 188 | 189 | text_unicode( x, y, font, col, std::wstring( buffer, buffer + final_len - 1 ) ); 190 | } 191 | } 192 | 193 | protected: 194 | font_map _fonts{}; 195 | render_callbacks _callbacks{}; 196 | float _width = 0.f; 197 | float _height = 0.f; 198 | bool _visible = false; 199 | }; 200 | 201 | using surface_ptr = std::shared_ptr; 202 | } 203 | -------------------------------------------------------------------------------- /src/direct2d/d2d_font.cpp: -------------------------------------------------------------------------------- 1 | ///-------------------------------------------------------------------------------- 2 | ///-- Author ReactiioN 3 | ///-- Copyright 2016-2020, ReactiioN 4 | ///-- License MIT 5 | ///-------------------------------------------------------------------------------- 6 | #include "d2d_font.hpp" 7 | #include "../utils/string_converter.hpp" 8 | 9 | using namespace aero; 10 | 11 | d2d_font::d2d_font( 12 | IDWriteFactory* factory, 13 | const std::string& family, 14 | const float height, 15 | const std::uint32_t weight, 16 | const std::uint32_t flags 17 | ) 18 | : font( family, height, weight, flags ) 19 | , _factory( factory ) 20 | { } 21 | 22 | d2d_font::~d2d_font() 23 | { 24 | // virtual functions can not be executed inside a destructor 25 | kill(); 26 | } 27 | 28 | void d2d_font::kill() 29 | { 30 | release(); 31 | } 32 | 33 | api_status d2d_font::create() 34 | { 35 | if( !_factory ) { 36 | return api_status::missing_factory_to_create_font; 37 | } 38 | if( _family.empty() ) { 39 | return api_status::missing_family_to_create_font; 40 | } 41 | 42 | const auto family = converter::string_to_wstring( _family ); 43 | const auto status = _factory->CreateTextFormat( 44 | family.data(), 45 | nullptr, 46 | static_cast( _weight ), 47 | DWRITE_FONT_STYLE_NORMAL, 48 | static_cast( _flags == 0 ? DWRITE_FONT_STRETCH_NORMAL : _flags ), 49 | _height, 50 | L"en-Us", 51 | &_data 52 | ); 53 | 54 | return SUCCEEDED( status ) 55 | ? api_status::success 56 | : api_status::failed_to_create_font; 57 | } 58 | 59 | void d2d_font::release() 60 | { 61 | detail::safe_release( &_data ); 62 | } 63 | 64 | void** d2d_font::address_of() noexcept 65 | { 66 | return reinterpret_cast( &_data ); 67 | } 68 | 69 | void* d2d_font::get_data() const noexcept 70 | { 71 | return _data; 72 | } 73 | 74 | void d2d_font::get_text_size( 75 | const std::wstring_view text, 76 | float* const width, 77 | float* const height 78 | ) 79 | { 80 | if( !text.empty() ) { 81 | if( !width && !height ) { 82 | return; 83 | } 84 | 85 | IDWriteTextLayout* layout = nullptr; 86 | const auto status = _factory->CreateTextLayout( 87 | text.data(), 88 | static_cast( text.length() ), 89 | _data, 90 | 4096.f, 91 | 4096.f, 92 | &layout 93 | ); 94 | 95 | if( SUCCEEDED( status ) ) { 96 | DWRITE_TEXT_METRICS metrics{}; 97 | if( SUCCEEDED( layout->GetMetrics( &metrics ) ) ) { 98 | if( width ) { 99 | *width = metrics.width; 100 | } 101 | if( height ) { 102 | *height = metrics.height; 103 | } 104 | } 105 | detail::safe_release( &layout ); 106 | } 107 | } 108 | } 109 | 110 | void d2d_font::get_text_size( 111 | const std::string_view text, 112 | float* const width, 113 | float* const height 114 | ) 115 | { 116 | if( !text.empty() ) { 117 | get_text_size( converter::string_to_wstring( text ), width, height ); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/direct2d/d2d_font.hpp: -------------------------------------------------------------------------------- 1 | ///-------------------------------------------------------------------------------- 2 | ///-- Author ReactiioN 3 | ///-- Copyright 2016-2020, ReactiioN 4 | ///-- License MIT 5 | ///-------------------------------------------------------------------------------- 6 | #pragma once 7 | 8 | #include "pre_include.hpp" 9 | 10 | namespace aero { 11 | class d2d_font final 12 | : public font 13 | { 14 | public: 15 | d2d_font( 16 | IDWriteFactory* factory, 17 | const std::string& family, 18 | float height, 19 | std::uint32_t weight, 20 | std::uint32_t flags 21 | ); 22 | 23 | ~d2d_font() override; 24 | 25 | private: 26 | void kill(); 27 | 28 | public: 29 | api_status create() override; 30 | 31 | void release() override; 32 | 33 | void** address_of() noexcept override; 34 | 35 | _NODISCARD 36 | void* get_data() const noexcept override; 37 | 38 | void get_text_size( 39 | std::wstring_view text, 40 | float* width, 41 | float* height 42 | ) override; 43 | 44 | void get_text_size( 45 | std::string_view text, 46 | float* width, 47 | float* height 48 | ) override; 49 | 50 | private: 51 | IDWriteFactory* _factory = nullptr; 52 | IDWriteTextFormat* _data = nullptr; 53 | }; 54 | } 55 | -------------------------------------------------------------------------------- /src/direct2d/d2d_surface.cpp: -------------------------------------------------------------------------------- 1 | ///-------------------------------------------------------------------------------- 2 | ///-- Author ReactiioN 3 | ///-- Copyright 2016-2020, ReactiioN 4 | ///-- License MIT 5 | ///-------------------------------------------------------------------------------- 6 | #include "d2d_surface.hpp" 7 | #include "d2d_font.hpp" 8 | #include "../utils/string_converter.hpp" 9 | 10 | using namespace aero; 11 | 12 | api_status d2d_surface::initialize( 13 | void* overlay_handle, 14 | void* target_handle 15 | ) 16 | { 17 | auto* const hwnd = static_cast( overlay_handle ); 18 | if( !hwnd ) { 19 | return api_status::missing_window_handle; 20 | } 21 | 22 | release(); 23 | 24 | auto status = D2D1CreateFactory( 25 | D2D1_FACTORY_TYPE_MULTI_THREADED, 26 | __uuidof( ID2D1Factory ), 27 | nullptr, 28 | reinterpret_cast( &_factory ) 29 | ); 30 | 31 | if( FAILED( status ) ) { 32 | return api_status::failed_to_create_surface_factory; 33 | } 34 | 35 | status = DWriteCreateFactory( 36 | DWRITE_FACTORY_TYPE_SHARED, 37 | __uuidof( IDWriteFactory ), 38 | reinterpret_cast( &_write_factory ) 39 | ); 40 | 41 | if( FAILED( status ) ) { 42 | return api_status::failed_to_create_surface_factory; 43 | } 44 | 45 | RECT rect{}; 46 | GetClientRect( hwnd, &rect ); 47 | 48 | _width = static_cast( rect.right - rect.left ); 49 | _height = static_cast( rect.bottom - rect.top ); 50 | status = _factory->CreateHwndRenderTarget( 51 | D2D1::RenderTargetProperties( 52 | D2D1_RENDER_TARGET_TYPE_HARDWARE, 53 | D2D1::PixelFormat( 54 | DXGI_FORMAT_UNKNOWN, 55 | D2D1_ALPHA_MODE_PREMULTIPLIED // todo: check 56 | ) 57 | ), 58 | D2D1::HwndRenderTargetProperties( 59 | hwnd, 60 | D2D1::SizeU( 61 | static_cast( _width ), 62 | static_cast( _height ) 63 | ), 64 | D2D1_PRESENT_OPTIONS_IMMEDIATELY 65 | ), 66 | &_render_target 67 | ); 68 | 69 | if( FAILED( status ) ) { 70 | return api_status::failed_to_create_render_target; 71 | } 72 | 73 | _render_target->SetAntialiasMode( D2D1_ANTIALIAS_MODE_ALIASED ); 74 | 75 | status = _render_target->CreateSolidColorBrush( 76 | D2D1::ColorF( 0xFFFFFFFF ), 77 | &_brush 78 | ); 79 | 80 | _window_handle = target_handle; 81 | 82 | return SUCCEEDED( status ) 83 | ? api_status::success 84 | : api_status::failed_to_create_render_target; 85 | } 86 | 87 | void d2d_surface::release() 88 | { 89 | detail::safe_release( &_brush ); 90 | detail::safe_release( &_render_target ); 91 | detail::safe_release( &_write_factory ); 92 | detail::safe_release( &_factory ); 93 | 94 | for( const auto& kp : _fonts ) { 95 | kp.second->release(); 96 | } 97 | 98 | _fonts.clear(); 99 | } 100 | 101 | font_ptr d2d_surface::add_font( 102 | const std::string& name, 103 | const std::string& family, 104 | const float height, 105 | const std::uint32_t weight, 106 | const std::uint32_t flags 107 | ) 108 | { 109 | if( const auto font = get_font( name ) ) { 110 | return font; 111 | } 112 | 113 | auto font = std::make_shared( _write_factory, family, height, weight, flags ); 114 | if( font->create() != api_status::success ) { 115 | return nullptr; 116 | } 117 | 118 | _fonts.insert( std::make_pair( name, std::move( font ) ) ); 119 | 120 | return get_font( name ); 121 | } 122 | 123 | void d2d_surface::border_box( 124 | const float x, 125 | const float y, 126 | const float w, 127 | const float h, 128 | float thickness, 129 | const color& col, 130 | float thickness_outside, 131 | float thickness_inside, 132 | const color& col_outside, 133 | const color& col_inside 134 | ) 135 | { 136 | thickness = detail::round_float( thickness ); 137 | 138 | // top 139 | rect( x, y, w, thickness, col, 0.f ); 140 | // bottom 141 | rect( x, y + h - thickness, w, thickness, col, 0.f ); 142 | // left 143 | rect( x, y, thickness, h, col, 0.f ); 144 | // right 145 | rect( x + w - thickness, y, thickness, h, col, 0.f ); 146 | 147 | if( thickness_outside >= 1.f ) { 148 | thickness_outside = detail::round_float( thickness_outside ); 149 | const auto mod = thickness_outside * 2.f; 150 | 151 | border_box( 152 | x - thickness_outside, 153 | y - thickness_outside, 154 | w + mod, 155 | h + mod, 156 | thickness_outside, 157 | col_outside, 158 | 0.f, 159 | 0.f 160 | ); 161 | } 162 | if( thickness_inside >= 1.f ) { 163 | thickness_inside = detail::round_float( thickness_inside ); 164 | const auto mod = thickness * 2.f; 165 | 166 | border_box( 167 | x + thickness, 168 | y + thickness, 169 | w - mod, 170 | h - mod, 171 | thickness_inside, 172 | col_inside, 173 | 0.f, 174 | 0.f 175 | ); 176 | } 177 | } 178 | 179 | void d2d_surface::line( 180 | const float start_x, 181 | const float start_y, 182 | const float end_x, 183 | const float end_y, 184 | const color& col 185 | ) 186 | { 187 | if( _render_target ) { 188 | set_color( col ); 189 | 190 | _render_target->DrawLine( 191 | D2D1::Point2F( start_x, start_y ), 192 | D2D1::Point2F( end_x, end_y ), 193 | _brush 194 | ); 195 | } 196 | } 197 | 198 | void d2d_surface::rect( 199 | const float x, 200 | const float y, 201 | const float w, 202 | const float h, 203 | const color& col, 204 | const float thickness_outside, 205 | const color& col_outside 206 | ) 207 | { 208 | if( thickness_outside >= 1.f ) { 209 | const auto value = detail::round_float( thickness_outside ); 210 | const auto mod = value * 2.f; 211 | 212 | rect( 213 | x - value, 214 | y - value, 215 | w + mod, 216 | h + mod, 217 | col_outside, 218 | 0.f 219 | ); 220 | } 221 | 222 | set_color( col ); 223 | _render_target->FillRectangle( 224 | D2D1::RectF( x, y, x + w, y + h ), 225 | _brush 226 | ); 227 | } 228 | 229 | void d2d_surface::text_ansii( 230 | const float x, 231 | const float y, 232 | const font_ptr& font, 233 | const color& col, 234 | const std::string_view text 235 | ) 236 | { 237 | if( !text.empty() ) { 238 | text_unicode( x, y, font, col, converter::string_to_wstring( text ) ); 239 | } 240 | } 241 | 242 | void d2d_surface::text_unicode( 243 | const float x, 244 | const float y, 245 | const font_ptr& font, 246 | const color& col, 247 | const std::wstring_view text 248 | ) 249 | { 250 | if( font && !text.empty() ) { 251 | D2D1_RECT_F font_rect{ x, y, 0.f, 0.f }; 252 | font->get_text_size( text, &font_rect.right, &font_rect.bottom ); 253 | 254 | font_rect.right += x + 1.f; 255 | font_rect.bottom += y + 1.f; 256 | 257 | set_color( col ); 258 | 259 | _render_target->DrawText( 260 | text.data(), 261 | static_cast( text.length() ), 262 | font->get_data(), 263 | &font_rect, 264 | _brush 265 | ); 266 | } 267 | } 268 | 269 | bool d2d_surface::begin_scene() 270 | { 271 | if( !_render_target ) { 272 | return false; 273 | } 274 | 275 | _render_target->BeginDraw(); 276 | _render_target->SetTransform( D2D1::Matrix3x2F::Identity() ); 277 | _render_target->Clear(); 278 | 279 | _visible = _window_handle == GetForegroundWindow(); 280 | 281 | if( _visible && !_callbacks.empty() ) { 282 | for( const auto& fn : _callbacks ) { 283 | fn(); 284 | } 285 | } 286 | 287 | return true; 288 | } 289 | 290 | void d2d_surface::end_scene() 291 | { 292 | if( _render_target ) { 293 | _render_target->EndDraw(); 294 | } 295 | } 296 | 297 | void d2d_surface::set_color( 298 | const color& col 299 | ) 300 | { 301 | const auto hex = col.hex(); 302 | if( hex != _last_color ) { 303 | _brush->SetColor( D2D1::ColorF( hex ) ); 304 | _last_color = hex; 305 | } 306 | } 307 | -------------------------------------------------------------------------------- /src/direct2d/d2d_surface.hpp: -------------------------------------------------------------------------------- 1 | ///-------------------------------------------------------------------------------- 2 | ///-- Author ReactiioN 3 | ///-- Copyright 2016-2020, ReactiioN 4 | ///-- License MIT 5 | ///-------------------------------------------------------------------------------- 6 | #pragma once 7 | 8 | #include "pre_include.hpp" 9 | 10 | namespace aero { 11 | class d2d_surface final 12 | : public surface 13 | { 14 | public: 15 | api_status initialize( 16 | void* overlay_handle, 17 | void* target_handle 18 | ) override; 19 | 20 | void release() override; 21 | 22 | font_ptr add_font( 23 | const std::string& name, 24 | const std::string& family, 25 | float height, 26 | std::uint32_t weight, 27 | std::uint32_t flags 28 | ) override; 29 | 30 | void border_box( 31 | float x, 32 | float y, 33 | float w, 34 | float h, 35 | float thickness, 36 | const color& col, 37 | float thickness_outside = 0.f, 38 | float thickness_inside = 0.f, 39 | const color& col_outside = 0xFF010101, 40 | const color& col_inside = 0xFF010101 41 | ) override; 42 | 43 | void line( 44 | float start_x, 45 | float start_y, 46 | float end_x, 47 | float end_y, 48 | const color& col 49 | ) override; 50 | 51 | void rect( 52 | float x, 53 | float y, 54 | float w, 55 | float h, 56 | const color& col, 57 | float thickness_outside = 0.f, 58 | const color& col_outside = 0xFF010101 59 | ) override; 60 | 61 | void text_ansii( 62 | float x, 63 | float y, 64 | const font_ptr& font, 65 | const color& col, 66 | std::string_view text 67 | ) override; 68 | 69 | void text_unicode( 70 | float x, 71 | float y, 72 | const font_ptr& font, 73 | const color& col, 74 | std::wstring_view text 75 | ) override; 76 | 77 | bool begin_scene() override; 78 | 79 | void end_scene() override; 80 | 81 | void set_color( 82 | const color& col 83 | ); 84 | 85 | private: 86 | ID2D1Factory* _factory = nullptr; 87 | IDWriteFactory* _write_factory = nullptr; 88 | ID2D1HwndRenderTarget* _render_target = nullptr; 89 | ID2D1SolidColorBrush* _brush = nullptr; 90 | void* _window_handle = nullptr; 91 | std::uint32_t _last_color = 0; 92 | }; 93 | } 94 | -------------------------------------------------------------------------------- /src/direct2d/pre_include.hpp: -------------------------------------------------------------------------------- 1 | ///-------------------------------------------------------------------------------- 2 | ///-- Author ReactiioN 3 | ///-- Copyright 2016-2020, ReactiioN 4 | ///-- License MIT 5 | ///-------------------------------------------------------------------------------- 6 | #pragma once 7 | 8 | #include 9 | 10 | #if !defined(_D2D1_H_) 11 | #include 12 | #include 13 | #include 14 | #endif 15 | #pragma comment(lib, "d2d1.lib") 16 | #pragma comment(lib, "dwrite.lib") 17 | 18 | #include 19 | 20 | namespace aero::detail { 21 | template 22 | void safe_release( 23 | type** data 24 | ) 25 | { 26 | static_assert( std::is_base_of_v ); 27 | if( data && *data ) { 28 | ( *data )->Release(); 29 | ( *data ) = nullptr; 30 | } 31 | } 32 | 33 | constexpr float round_float( 34 | const float value 35 | ) 36 | { 37 | return static_cast( static_cast( value ) ); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/overlay.cpp: -------------------------------------------------------------------------------- 1 | ///-------------------------------------------------------------------------------- 2 | ///-- Author ReactiioN 3 | ///-- Copyright 2016-2020, ReactiioN 4 | ///-- License MIT 5 | ///-------------------------------------------------------------------------------- 6 | #include 7 | #include 8 | #include 9 | #include "direct2d/d2d_surface.hpp" 10 | using namespace aero; 11 | 12 | template 13 | type get_window_props( 14 | HWND hwnd 15 | ) 16 | { 17 | RECT client{}, window{}; 18 | GetClientRect( hwnd, &client ); 19 | GetWindowRect( hwnd, &window ); 20 | 21 | POINT diff{}; 22 | ClientToScreen( hwnd, &diff ); 23 | 24 | return { 25 | window.left + ( diff.x - window.left ), 26 | window.top + ( diff.y - window.top ), 27 | client.right, 28 | client.bottom 29 | }; 30 | } 31 | 32 | overlay::overlay() 33 | { 34 | const auto random_string = []( const std::size_t length ) 35 | { 36 | constexpr static char charset[] = { 37 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 38 | 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 39 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 40 | 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 41 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 42 | }; 43 | constexpr static std::size_t num_chars = sizeof charset; 44 | 45 | static std::random_device rd; 46 | std::mt19937 gen( rd() ); 47 | const std::uniform_int_distribution engine( 48 | std::numeric_limits::min(), 49 | num_chars - 1 50 | ); 51 | 52 | std::string str( length, '\0' ); 53 | for( auto& c : str ) { 54 | c = charset[ engine( gen ) ]; 55 | } 56 | 57 | return str; 58 | }; 59 | 60 | _class = random_string( 32 ); 61 | _title = random_string( 64 ); 62 | } 63 | 64 | overlay::overlay( 65 | overlay&& rhs 66 | ) noexcept 67 | { 68 | *this = std::move( rhs ); 69 | } 70 | 71 | overlay::~overlay() 72 | { 73 | destroy(); 74 | } 75 | 76 | overlay& overlay::operator = ( 77 | overlay&& rhs 78 | ) noexcept 79 | { 80 | _class = std::move( rhs._class ); 81 | _title = std::move( rhs._title ); 82 | _window = rhs._window; 83 | _target = rhs._target; 84 | _width = rhs._width; 85 | _height = rhs._height; 86 | 87 | rhs._window = nullptr; 88 | rhs._target = nullptr; 89 | rhs._width = 0; 90 | rhs._height = 0; 91 | 92 | return *this; 93 | } 94 | 95 | api_status overlay::attach( 96 | const std::string_view window_title 97 | ) 98 | { 99 | return window_title.empty() 100 | ? api_status::missing_window_title 101 | : attach( FindWindowA( nullptr, window_title.data() ) ); 102 | } 103 | 104 | api_status overlay::attach( 105 | const std::uint32_t process_id 106 | ) 107 | { 108 | using callback_data_type = std::pair; 109 | 110 | auto data = std::make_pair( &process_id, static_cast( nullptr ) ); 111 | 112 | EnumWindows( 113 | []( HWND hwnd, const LPARAM lparam ) -> std::int32_t 114 | { 115 | if( !hwnd ) { 116 | return 1; 117 | } 118 | 119 | DWORD pid = 0; 120 | GetWindowThreadProcessId( hwnd, &pid ); 121 | 122 | auto& data = *reinterpret_cast( lparam ); 123 | if( *data.first == pid ) { 124 | data.second = hwnd; 125 | return 0; 126 | } 127 | return 1; 128 | }, 129 | reinterpret_cast( &data ) 130 | ); 131 | 132 | return attach( data.second ); 133 | } 134 | 135 | api_status overlay::attach( 136 | HWND target_window 137 | ) 138 | { 139 | if( !target_window ) { 140 | return api_status::missing_window_handle; 141 | } 142 | 143 | auto dwm_enabled = 0; 144 | if( FAILED( DwmIsCompositionEnabled( &dwm_enabled ) ) || !dwm_enabled ) { 145 | return api_status::missing_aero_feature; 146 | } 147 | 148 | WNDCLASSEXA wc = { 149 | sizeof( WNDCLASSEX ), 150 | 0, 151 | reinterpret_cast( window_proc ), 152 | 0, 153 | 0, 154 | GetModuleHandleA( nullptr ), 155 | LoadIconA( nullptr, MAKEINTRESOURCEA( 32512 ) ), 156 | LoadCursorA( nullptr, MAKEINTRESOURCEA( 32512 ) ), 157 | nullptr, 158 | nullptr, 159 | _class.data(), 160 | LoadIconA( nullptr, MAKEINTRESOURCEA( 32512 ) ), 161 | }; 162 | 163 | if( !RegisterClassExA( &wc ) ) { 164 | return api_status::failed_to_register_window; 165 | } 166 | 167 | _target = target_window; 168 | _window = CreateWindowExA( 169 | WS_EX_TOPMOST | WS_EX_TRANSPARENT | WS_EX_LAYERED /* | WS_EX_TOOLWINDOW | WS_EX_COMPOSITED*/, 170 | _class.data(), 171 | _title.data(), 172 | WS_POPUP, 173 | CW_USEDEFAULT, 174 | CW_USEDEFAULT, 175 | 800, 176 | 600, 177 | nullptr, 178 | nullptr, 179 | GetModuleHandleA( nullptr ), 180 | this 181 | ); 182 | if( !_window ) { 183 | return api_status::failed_to_create_window; 184 | } 185 | 186 | scale(); 187 | if( !SetLayeredWindowAttributes( _window, RGB( 0, 0, 0 ), 255, LWA_ALPHA ) ) { 188 | return api_status::failed_to_make_window_transparent; 189 | } 190 | 191 | const auto margins = get_window_props( _window ); 192 | if( FAILED( DwmExtendFrameIntoClientArea( _window, &margins ) ) ) { 193 | return api_status::failed_to_make_window_transparent; 194 | } 195 | 196 | ShowWindow( _window, SW_SHOWDEFAULT ); 197 | UpdateWindow( _window ); 198 | 199 | if( !_surface ) { 200 | set_surface( std::make_shared() ); 201 | } 202 | 203 | return _surface->initialize( _window, _target ); 204 | } 205 | 206 | void overlay::destroy() 207 | { 208 | if( !_class.empty() ) { 209 | UnregisterClassA( _class.data(), nullptr ); 210 | } 211 | if( _window ) { 212 | DestroyWindow( _window ); 213 | } 214 | 215 | _window = nullptr; 216 | _target = nullptr; 217 | 218 | if( _surface ) { 219 | _surface->release(); 220 | } 221 | } 222 | 223 | bool overlay::message_loop() const noexcept 224 | { 225 | if( !_window ) { 226 | return false; 227 | } 228 | 229 | MSG msg{}; 230 | if( PeekMessageA( &msg, nullptr, 0, 0, PM_REMOVE ) > 0 ) { 231 | TranslateMessage( &msg ); 232 | DispatchMessageA( &msg ); 233 | 234 | if( msg.message == WM_QUIT ) { 235 | return false; 236 | } 237 | } 238 | 239 | return true; 240 | } 241 | 242 | void overlay::scale() 243 | { 244 | static auto fix = []( long& in, std::uint32_t& out ) 245 | { 246 | if( in == 0 ) { 247 | in++; 248 | out--; 249 | } 250 | else { 251 | in--; 252 | out++; 253 | } 254 | }; 255 | 256 | auto props = get_window_props( _target ); 257 | 258 | _width = static_cast( props.right ); 259 | _height = static_cast( props.bottom ); 260 | 261 | fix( props.left, _width ); 262 | fix( props.top, _height ); 263 | 264 | MoveWindow( 265 | _window, 266 | props.left, 267 | props.top, 268 | static_cast( _width ), 269 | static_cast( _height ), 270 | 1 271 | ); 272 | } 273 | 274 | void overlay::set_surface( 275 | surface_ptr surface 276 | ) 277 | { 278 | if( _surface ) { 279 | _surface->release(); 280 | } 281 | 282 | _surface = std::move( surface ); 283 | } 284 | 285 | std::intptr_t overlay::window_proc( 286 | void* window_handle, 287 | const std::uint32_t message, 288 | const std::uintptr_t wparam, 289 | const std::intptr_t lparam 290 | ) 291 | { 292 | auto* const hwnd = static_cast( window_handle ); 293 | switch( message ) { 294 | case WM_DESTROY: 295 | PostQuitMessage( EXIT_SUCCESS ); 296 | return 0; 297 | case WM_KEYDOWN: 298 | return 0; 299 | case WM_ERASEBKGND: 300 | SendMessageA( hwnd, WM_PAINT, 0, 0 ); 301 | return TRUE; 302 | default: 303 | break; 304 | } 305 | return DefWindowProcA( hwnd, message, wparam, lparam ); 306 | } 307 | -------------------------------------------------------------------------------- /src/utils/string_converter.hpp: -------------------------------------------------------------------------------- 1 | ///-------------------------------------------------------------------------------- 2 | ///-- Author ReactiioN 3 | ///-- Copyright 2016-2020, ReactiioN 4 | ///-- License MIT 5 | ///-------------------------------------------------------------------------------- 6 | #pragma once 7 | 8 | #include 9 | 10 | namespace aero::detail { 11 | template 12 | std::basic_string convert_string_func( 13 | const std::basic_string_view input, 14 | const fn callback 15 | ) 16 | { 17 | const auto len = input.length(); 18 | std::basic_string buf( len, 0 ); 19 | callback( buf.data(), input.data(), len ); 20 | return buf; 21 | } 22 | } 23 | 24 | namespace aero::converter { 25 | static std::string wstring_to_string( 26 | const std::wstring_view input 27 | ) 28 | { 29 | return detail::convert_string_func( input, std::wcstombs ); 30 | } 31 | 32 | static std::wstring string_to_wstring( 33 | const std::string_view input 34 | ) 35 | { 36 | return detail::convert_string_func( input, std::mbstowcs ); 37 | } 38 | } 39 | --------------------------------------------------------------------------------