├── LICENSE ├── README.en.md ├── README.jp.md ├── README.md ├── assets ├── image1.en.png ├── image1.jp.png ├── image1.zh.png ├── image2.en.png ├── image2.jp.png └── image2.zh.png ├── build ├── .gitignore ├── nsis │ ├── favicon.ico │ ├── setup.nsi │ └── tools │ │ ├── plugins │ │ ├── System.dll │ │ └── nsExec.dll │ │ └── stubs │ │ ├── uninst │ │ ├── zlib │ │ └── zlib_solid └── nsis_build.bat └── src ├── .gitignore ├── GenshinFishingToy.sln ├── GenshinFishingToy ├── .editorconfig ├── .gitignore ├── App.xaml ├── App.xaml.cs ├── Core │ ├── GenshinRegedit.cs │ ├── GenshinWindow.cs │ ├── HotKey │ │ ├── Hotkey.cs │ │ ├── HotkeyHolder.cs │ │ └── HotkeyHook.cs │ ├── ImageCapture.cs │ ├── ImageExtension.cs │ ├── ImageJigging.cs │ ├── ImageRecognition.cs │ ├── LaunchCtrl.cs │ ├── Logger.cs │ ├── NativeMethods.cs │ ├── Settings │ │ ├── SettingsCache.cs │ │ ├── SettingsDefinition{T}.cs │ │ ├── SettingsManager.cs │ │ └── SettingsSerializer.cs │ ├── SpecialPathProvider.cs │ ├── UIElement │ │ ├── AssemblyUtils.cs │ │ ├── BrushAnimation.cs │ │ ├── BrushConverterX.cs │ │ ├── DpiUtils.cs │ │ ├── FluentSymbol.cs │ │ ├── LanguageManager.cs │ │ ├── NoticeService.cs │ │ ├── ResourceUtils.cs │ │ ├── StoryboardUtils.cs │ │ └── SvgViewboxExtension.cs │ └── UsageManager.cs ├── FodyWeavers.xml ├── FodyWeavers.xsd ├── GenshinFishingToy.csproj ├── GlobalUsing.cs ├── Models │ └── Settings.cs ├── Pack.cs ├── Properties │ └── PublishProfiles │ │ └── FolderProfile.pubxml ├── Resources │ ├── Languages │ │ ├── en-us.xaml │ │ ├── jp.xaml │ │ └── zh-cn.xaml │ ├── demo.gif │ ├── demo.png │ ├── favicon.ico │ ├── favicon.png │ ├── hydro.png │ ├── hydro.svg │ ├── segoe-fluent-icons.ttf │ └── squircle.svg ├── ViewModels │ ├── MainViewModel.cs │ └── NotifyIconViewModel.cs ├── Views │ ├── Behaviors │ │ ├── BorderWindowBehavior.cs │ │ ├── LeftContextMenuBehavior.cs │ │ ├── ToolWindowBehavior.cs │ │ └── UIElementDragMoveBehavior.cs │ ├── Converters │ │ ├── AddConverter.cs │ │ └── LanguageToBoolConverter.cs │ ├── MainWindow.xaml │ ├── MainWindow.xaml.cs │ ├── MotionAreaWindow.xaml │ ├── MotionAreaWindow.xaml.cs │ ├── PreviewForm.Designer.cs │ ├── PreviewForm.cs │ ├── UIElement │ │ ├── DialogWindow.xaml │ │ ├── DialogWindow.xaml.cs │ │ ├── MessageDialog.xaml │ │ ├── MessageDialog.xaml.cs │ │ └── ObservableWindow.cs │ ├── UsageContent.xaml │ └── UsageContent.xaml.cs └── app.manifest ├── GenshinFishingToySetup ├── .gitignore ├── GenshinFishingToySetup.assets.cache ├── GenshinFishingToySetup.wapproj ├── GenshinFishingToySetup_TemporaryKey.pfx ├── Images │ ├── BadgeLogo.scale-100.png │ ├── BadgeLogo.scale-125.png │ ├── BadgeLogo.scale-150.png │ ├── BadgeLogo.scale-200.png │ ├── BadgeLogo.scale-400.png │ ├── LargeTile.scale-100.png │ ├── LargeTile.scale-125.png │ ├── LargeTile.scale-150.png │ ├── LargeTile.scale-200.png │ ├── LargeTile.scale-400.png │ ├── SmallTile.scale-100.png │ ├── SmallTile.scale-125.png │ ├── SmallTile.scale-150.png │ ├── SmallTile.scale-200.png │ ├── SmallTile.scale-400.png │ ├── SplashScreen.scale-100.png │ ├── SplashScreen.scale-125.png │ ├── SplashScreen.scale-150.png │ ├── SplashScreen.scale-200.png │ ├── SplashScreen.scale-400.png │ ├── Square150x150Logo.scale-100.png │ ├── Square150x150Logo.scale-125.png │ ├── Square150x150Logo.scale-150.png │ ├── Square150x150Logo.scale-200.png │ ├── Square150x150Logo.scale-400.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-16.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-24.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-256.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-32.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-48.png │ ├── Square44x44Logo.altform-unplated_targetsize-16.png │ ├── Square44x44Logo.altform-unplated_targetsize-256.png │ ├── Square44x44Logo.altform-unplated_targetsize-32.png │ ├── Square44x44Logo.altform-unplated_targetsize-48.png │ ├── Square44x44Logo.scale-100.png │ ├── Square44x44Logo.scale-125.png │ ├── Square44x44Logo.scale-150.png │ ├── Square44x44Logo.scale-200.png │ ├── Square44x44Logo.scale-400.png │ ├── Square44x44Logo.targetsize-16.png │ ├── Square44x44Logo.targetsize-24.png │ ├── Square44x44Logo.targetsize-24_altform-unplated.png │ ├── Square44x44Logo.targetsize-256.png │ ├── Square44x44Logo.targetsize-32.png │ ├── Square44x44Logo.targetsize-48.png │ ├── StoreLogo.scale-100.png │ ├── StoreLogo.scale-125.png │ ├── StoreLogo.scale-150.png │ ├── StoreLogo.scale-200.png │ ├── StoreLogo.scale-400.png │ ├── Wide310x150Logo.scale-100.png │ ├── Wide310x150Logo.scale-125.png │ ├── Wide310x150Logo.scale-150.png │ ├── Wide310x150Logo.scale-200.png │ └── Wide310x150Logo.scale-400.png └── Package.appxmanifest ├── WindowsGraphicsCapture ├── .gitattributes ├── .gitignore ├── CaptureSampleCore │ ├── BasicCapture.cs │ ├── BasicSampleApplication.cs │ └── CaptureSampleCore.csproj ├── Composition.WindowsRuntimeHelpers │ ├── CaptureHelper.cs │ ├── Composition.WindowsRuntimeHelpers.csproj │ ├── CompositionHelper.cs │ ├── CoreMessagingHelper.cs │ └── Direct3D11Helper.cs ├── LICENSE ├── README.md ├── ScreenCapture.sln └── ScreenCapture │ ├── AssemblyInfo.cs │ ├── GraphicsCapture.cs │ ├── MainWindow.xaml │ ├── MainWindow.xaml.cs │ ├── MonitorEnumerationHelper.cs │ ├── ScreenCapture.csproj │ └── WindowEnumerationHelper.cs └── app_workspace.cmd /README.en.md: -------------------------------------------------------------------------------- 1 | ・[English](README.en.md) ・[中文](README.md) ・[日本語](README.jp.md) 2 | 3 | [![GitHub downloads](https://img.shields.io/github/downloads/genshin-matrix/genshin-fishing-toy/total)](https://github.com/emako/genshin-fishing-toy/releases) 4 | [![GitHub downloads](https://img.shields.io/github/downloads/genshin-matrix/genshin-fishing-toy/latest/total)](https://github.com/emako/genshin-fishing-toy/releases) 5 | 6 | # 🐟 Genshin Fishing Toy 7 | 8 | > Genshin Fishing Toy [(Original Repository)](https://github.com/babalae/genshin-fishing-toy) 9 | 10 | PC Genshin Impact auto fishing machine (Supports different game window sizes). 11 | 12 | `"You just need to be responsible for the rod swing, and then all will be handled!"` 13 | 14 | The simplest automatic fishing machine has its own GUI. Select the fishing box and start fishing. It is easy to use and hands free. 15 | 16 | * Work with visual recognition. 17 | * Delay 0~1s to auto lift the rod after the fish is hooked. 18 | 19 | ## ScreenShot 20 | 21 | 22 | 23 | ![](assets/image1.en.png) 24 | 25 | ![](assets/image2.en.png) 26 | 27 | ## Usage 28 | 29 | demo 30 | 31 | 1. First, move the jigging region to select the recognition region, and you also can resize the region. Just frame the fishing progress bar. Don't frame the fishing progress circle below. 32 | 33 | 2. After confirming that the region position is correct, you can start auto fishing (ShortcutF11). 34 | 35 | > - After the rod is thrown, just waiting for the fish to hook up. The program will auto control mouse according to the image recognition results and complete the fishing progress. 36 | > 37 | > - If you can't auto simulate the key, please try to add this program to the anti-virus software white list, or turn off anti-virus software firstly. 38 | 39 | ## FAQs 40 | - If you are not fishing, you'd better stop the fishing function. 41 | - If the Auto Lifting does not work, please try to increase the height of the fishing region frame. 42 | - When the setup can't be installed. Please ensure that your system has installed the Microsoft Store. The setup depends on the store architecture (MSIX). 43 | 44 | - Runtime environment isnet6.0-windows10.0.18362.0. 45 | 46 | - The fullscreen mode user is recommended to use the windowed in the whole process instead of full screen (shortcut key in the gameAlt+Enter). 47 | -------------------------------------------------------------------------------- /README.jp.md: -------------------------------------------------------------------------------- 1 | ・[English](README.en.md) ・[中文](README.md) ・[日本語](README.jp.md) 2 | 3 | [![GitHub downloads](https://img.shields.io/github/downloads/genshin-matrix/genshin-fishing-toy/total)](https://github.com/emako/genshin-fishing-toy/releases) 4 | [![GitHub downloads](https://img.shields.io/github/downloads/genshin-matrix/genshin-fishing-toy/latest/total)](https://github.com/emako/genshin-fishing-toy/releases) 5 | 6 | # 🐟原神釣り師 7 | 8 | > Genshin Fishing Toy [(元のリポジトリ)](https://github.com/babalae/genshin-fishing-toy) 9 | 10 | PC版の原神自動釣りマシン(ゲームウィンドウサイズ別対応)。 11 | 12 | 「竿を振るだけで、あとは任せときぃ!」 13 | 14 | 最も簡単な自動釣魚機を操作し、釣り枠を選択してから釣りをスタートし、簡単で使いやすく。 15 | 16 | * 視覚識別による自動操作。 17 | * 魚がヒットしてから0~1sの遅延後に自動的に竿をリフティング。 18 | 19 | ## スクショ 20 | 21 | 22 | 23 | ![](assets/image1.jp.png) 24 | 25 | ![](assets/image2.jp.png) 26 | 27 | ## 使い方 28 | 29 | demo 30 | 31 | 1. まずは半透明長方形の釣り枠を移動して識別区域を囲むこと、釣り枠のサイズは調整できる、釣りのプログレスバーを枠に入れるだけでいいので、 下の丸い釣りプログレスを枠に入れないこと。 32 | 2. 釣り枠が正しい位置を囲んだ後、「スタート」してください(ショートカットF11)。 33 | 34 | > - 魚竿を振った後、魚が釣れるのを待つだけ、プログラムは自動的に画像識別に基づいて対応、マウスを任せて釣りを行う。 35 | > 36 | > - もし正常にキーボードなどのシミュレーションが出来ない場合は、本プログラムをアンチウィルスソフトにホワイトリストに追加し、もしくはアンチウィルスソフトを終了後にお使いください。 37 | 38 | ## FAQs 39 | - 釣りをしていない時は釣り機能をストップしたほうがいいのである。 40 | - 自動リフティングができない場合は釣り枠の高さを上げてみてください。 41 | - もしセットアップがインストールできない場合は、システムにアプリストアが実装されているかどうかをご確認ください。セットアップはアプリストアに依存している (MSIX)。 42 | - 実行環境はnet6.0-windows10.0.18362.0。 43 | 44 | - フルスクリーンで利用する方はフルスクリーンではなくウィンドウの表示モードを利用することをお勧めする(ゲーム内のショートカットキーはAlt+Enter)。 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ・[English](README.en.md) ・[中文](README.md) ・[日本語](README.jp.md) 2 | 3 | [![GitHub downloads](https://img.shields.io/github/downloads/genshin-matrix/genshin-fishing-toy/total)](https://github.com/emako/genshin-fishing-toy/releases) 4 | [![GitHub downloads](https://img.shields.io/github/downloads/genshin-matrix/genshin-fishing-toy/latest/total)](https://github.com/emako/genshin-fishing-toy/releases) 5 | 6 | # 🐟原神钓鱼姬 7 | 8 | > Genshin Fishing Toy [(原始仓库)](https://github.com/babalae/genshin-fishing-toy) 9 | 10 | PC原神自动钓鱼机(支持不同游戏窗口大小)。 11 | 12 | 『你只需负责甩竿,后面的放着我来!』 13 | 14 | 操作最简单的自动钓鱼机,选钓鱼框后启动钓鱼,简单易用,解放双手。 15 | 16 | - [x] 采用视觉识别。 17 | - [x] 鱼儿上钩后延迟0~1s自动提竿。 18 | 19 | ## 程序界面 20 | 21 | 22 | 23 | ![](assets/image1.zh.png) 24 | 25 | ![](assets/image2.zh.png) 26 | 27 | ## 使用方法 28 | 29 | demo 30 | 31 | 1. 首先移动半透明矩形钓鱼框选择识别范围,钓鱼框可调整大小,只需要框住钓鱼进度条就可以了, 不要框住下方的钓鱼总进度圈 。 32 | 33 | 2. 确认选框位置正确后,就直接启动进行自动钓鱼啦(快捷键F11)。 34 | 35 | > - 甩竿后直接等待鱼儿上钩即可,程序会自动根据当前图像识别的结果发送对应鼠标操作,自动化提竿、完成钓鱼进度。 36 | > 37 | > - 如果无法正常自动模拟按键,请尝试将本程序添加至杀软白名单,或关闭杀软后使用。 38 | 39 | ## 常见问题 40 | - 如果不在钓鱼的时候最好还是停止钓鱼功能。 41 | - 无法自动提竿的话请尝试调高条框的高度。 42 | 43 | - 若安装包无法安装,请确保你的系统已安装应用商店,安装包依赖商店架构 (MSIX)。 44 | 45 | - 运行环境是net6.0-windows10.0.18362.0。 46 | 47 | - 独占模式建议全程使用窗口模式使用(游戏内快捷键Alt+Enter)。 48 | 49 | - 独占模式下的可正常操作流程: 50 | 51 | > - 启动游戏进程->启动钓鱼姬->退出钓鱼姬->退出游戏进程 52 | 53 | - 独占模式下存在问题的流程: 54 | 55 | > - 启动钓鱼姬->启动游戏进程->退出钓鱼姬->退出游戏进程(无法恢复钓鱼框位置并变成类似-30000多的值) 56 | > 57 | > - 启动游戏进程->启动钓鱼姬->退出游戏进程->退出钓鱼姬(游戏退出瞬间可能会误识别为窗口模式) 58 | 59 | -------------------------------------------------------------------------------- /assets/image1.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/assets/image1.en.png -------------------------------------------------------------------------------- /assets/image1.jp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/assets/image1.jp.png -------------------------------------------------------------------------------- /assets/image1.zh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/assets/image1.zh.png -------------------------------------------------------------------------------- /assets/image2.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/assets/image2.en.png -------------------------------------------------------------------------------- /assets/image2.jp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/assets/image2.jp.png -------------------------------------------------------------------------------- /assets/image2.zh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/assets/image2.zh.png -------------------------------------------------------------------------------- /build/.gitignore: -------------------------------------------------------------------------------- 1 | *.cer 2 | *.msix 3 | *.msixbundle 4 | *.exe 5 | *.7z 6 | -------------------------------------------------------------------------------- /build/nsis/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/build/nsis/favicon.ico -------------------------------------------------------------------------------- /build/nsis/setup.nsi: -------------------------------------------------------------------------------- 1 | !define PRODUCT_NAME "GenshinFishingToy" 2 | !define PRODUCT_VERSION "1.4.0.0" 3 | !define PRODUCT_PUBLISHER "GenshinMatrix" 4 | !define PRODUCT_WEB_SITE "https://github.com/genshin-matrix" 5 | !define PRODUCT_LEGAL "Licensed under MIT" 6 | 7 | VIProductVersion "${PRODUCT_VERSION}" 8 | VIAddVersionKey "ProductVersion" "${PRODUCT_VERSION}" 9 | VIAddVersionKey "ProductName" "${PRODUCT_NAME}" 10 | VIAddVersionKey "CompanyName" "${PRODUCT_PUBLISHER}" 11 | VIAddVersionKey "FileVersion" "${PRODUCT_VERSION}" 12 | VIAddVersionKey "InternalName" "${PRODUCT_NAME}" 13 | VIAddVersionKey "FileDescription" "${PRODUCT_NAME}_Setup" 14 | VIAddVersionKey "Comments" "${PRODUCT_WEB_SITE}" 15 | VIAddVersionKey "LegalCopyright" "${PRODUCT_LEGAL}" 16 | 17 | !addplugindir plugins 18 | 19 | Icon "favicon.ico" 20 | Name "${PRODUCT_NAME}" 21 | OutFile "..\${PRODUCT_NAME}_Setup.exe" 22 | RequestExecutionLevel admin 23 | Page custom MsixSetup 24 | 25 | Function MsixSetup 26 | Call CheckMutex 27 | InitPluginsDir 28 | SetOutPath "$PLUGINSDIR" 29 | File "tools\certmgr.exe" 30 | File "..\app.cer" 31 | nsExec::ExecToLog 'certmgr.exe -add app.cer -s -r localMachine AuthRoot' 32 | File "tools\msixexec.exe" 33 | File "..\app.msixbundle" 34 | nsExec::ExecToLog 'msixexec.exe app.msixbundle' 35 | FunctionEnd 36 | 37 | Function CheckMutex 38 | System::Call 'kernel32::CreateMutexA(i 0, i 0, t "${PRODUCT_NAME}_SetupMutex") i .r1 ?e' 39 | Pop $R0 40 | StrCmp $R0 0 +3 41 | MessageBox MB_OK|MB_ICONEXCLAMATION "Setup is already running." 42 | Abort 43 | FunctionEnd 44 | 45 | Section 46 | SectionEnd 47 | -------------------------------------------------------------------------------- /build/nsis/tools/plugins/System.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/build/nsis/tools/plugins/System.dll -------------------------------------------------------------------------------- /build/nsis/tools/plugins/nsExec.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/build/nsis/tools/plugins/nsExec.dll -------------------------------------------------------------------------------- /build/nsis/tools/stubs/uninst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/build/nsis/tools/stubs/uninst -------------------------------------------------------------------------------- /build/nsis/tools/stubs/zlib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/build/nsis/tools/stubs/zlib -------------------------------------------------------------------------------- /build/nsis/tools/stubs/zlib_solid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/build/nsis/tools/stubs/zlib_solid -------------------------------------------------------------------------------- /build/nsis_build.bat: -------------------------------------------------------------------------------- 1 | cd /d %~dp0 2 | rename GenshinFishingToySetup_*_x64.cer App.cer 3 | rename GenshinFishingToySetup_*_x64.msixbundle App.msixbundle 4 | del App_Setup.exe 5 | nsis\tools\makensis .\nsis\setup.nsi 6 | del GenshinFishingToySetup.exe 7 | rename App_Setup.exe GenshinFishingToySetup.exe 8 | @pause 9 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | # User-specific files 2 | *.suo 3 | *.user 4 | *.userosscache 5 | *.sln.docstates 6 | .vs/ 7 | 8 | # User-specific files (MonoDevelop/Xamarin Studio) 9 | *.userprefs 10 | 11 | # Build results 12 | [Dd]ebug/ 13 | [Dd]ebugPublic/ 14 | [Rr]elease/ 15 | [Rr]eleases/ 16 | x64/ 17 | x86/ 18 | bld/ 19 | [Bb]in/ 20 | [Oo]bj/ 21 | [Ll]og/ 22 | 23 | # Mine 24 | Tmp/ 25 | /packages/ 26 | node_modules/ -------------------------------------------------------------------------------- /src/GenshinFishingToy.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.3.32819.101 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GenshinFishingToy", "GenshinFishingToy\GenshinFishingToy.csproj", "{F17BE4C5-926C-456D-9CC0-606DAE304ED8}" 7 | EndProject 8 | Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "GenshinFishingToySetup", "GenshinFishingToySetup\GenshinFishingToySetup.wapproj", "{A80A34DD-ACBC-4D67-A22D-156A0FFC32A8}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WindowsGraphicsCapture", "WindowsGraphicsCapture", "{61B278E1-2049-475B-B200-3F0C3DDA87C2}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScreenCapture", "WindowsGraphicsCapture\ScreenCapture\ScreenCapture.csproj", "{AB145A23-0897-4517-8EA6-BEB87CB9D26A}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CaptureSampleCore", "WindowsGraphicsCapture\CaptureSampleCore\CaptureSampleCore.csproj", "{D8154C31-38C2-49E2-96A0-69EB76567461}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Composition.WindowsRuntimeHelpers", "WindowsGraphicsCapture\Composition.WindowsRuntimeHelpers\Composition.WindowsRuntimeHelpers.csproj", "{AE6F99F5-AFD5-467E-A082-D4003E3EEECF}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|x64 = Debug|x64 21 | Release|x64 = Release|x64 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {F17BE4C5-926C-456D-9CC0-606DAE304ED8}.Debug|x64.ActiveCfg = Debug|x64 25 | {F17BE4C5-926C-456D-9CC0-606DAE304ED8}.Debug|x64.Build.0 = Debug|x64 26 | {F17BE4C5-926C-456D-9CC0-606DAE304ED8}.Release|x64.ActiveCfg = Release|x64 27 | {F17BE4C5-926C-456D-9CC0-606DAE304ED8}.Release|x64.Build.0 = Release|x64 28 | {A80A34DD-ACBC-4D67-A22D-156A0FFC32A8}.Debug|x64.ActiveCfg = Debug|x64 29 | {A80A34DD-ACBC-4D67-A22D-156A0FFC32A8}.Debug|x64.Build.0 = Debug|x64 30 | {A80A34DD-ACBC-4D67-A22D-156A0FFC32A8}.Debug|x64.Deploy.0 = Debug|x64 31 | {A80A34DD-ACBC-4D67-A22D-156A0FFC32A8}.Release|x64.ActiveCfg = Release|x64 32 | {A80A34DD-ACBC-4D67-A22D-156A0FFC32A8}.Release|x64.Build.0 = Release|x64 33 | {A80A34DD-ACBC-4D67-A22D-156A0FFC32A8}.Release|x64.Deploy.0 = Release|x64 34 | {AB145A23-0897-4517-8EA6-BEB87CB9D26A}.Debug|x64.ActiveCfg = Debug|x64 35 | {AB145A23-0897-4517-8EA6-BEB87CB9D26A}.Debug|x64.Build.0 = Debug|x64 36 | {AB145A23-0897-4517-8EA6-BEB87CB9D26A}.Release|x64.ActiveCfg = Release|x64 37 | {AB145A23-0897-4517-8EA6-BEB87CB9D26A}.Release|x64.Build.0 = Release|x64 38 | {D8154C31-38C2-49E2-96A0-69EB76567461}.Debug|x64.ActiveCfg = Debug|x64 39 | {D8154C31-38C2-49E2-96A0-69EB76567461}.Debug|x64.Build.0 = Debug|x64 40 | {D8154C31-38C2-49E2-96A0-69EB76567461}.Release|x64.ActiveCfg = Release|x64 41 | {D8154C31-38C2-49E2-96A0-69EB76567461}.Release|x64.Build.0 = Release|x64 42 | {AE6F99F5-AFD5-467E-A082-D4003E3EEECF}.Debug|x64.ActiveCfg = Debug|x64 43 | {AE6F99F5-AFD5-467E-A082-D4003E3EEECF}.Debug|x64.Build.0 = Debug|x64 44 | {AE6F99F5-AFD5-467E-A082-D4003E3EEECF}.Release|x64.ActiveCfg = Release|x64 45 | {AE6F99F5-AFD5-467E-A082-D4003E3EEECF}.Release|x64.Build.0 = Release|x64 46 | EndGlobalSection 47 | GlobalSection(SolutionProperties) = preSolution 48 | HideSolutionNode = FALSE 49 | EndGlobalSection 50 | GlobalSection(NestedProjects) = preSolution 51 | {AB145A23-0897-4517-8EA6-BEB87CB9D26A} = {61B278E1-2049-475B-B200-3F0C3DDA87C2} 52 | {D8154C31-38C2-49E2-96A0-69EB76567461} = {61B278E1-2049-475B-B200-3F0C3DDA87C2} 53 | {AE6F99F5-AFD5-467E-A082-D4003E3EEECF} = {61B278E1-2049-475B-B200-3F0C3DDA87C2} 54 | EndGlobalSection 55 | GlobalSection(ExtensibilityGlobals) = postSolution 56 | SolutionGuid = {DFA8F1CD-513D-45D7-856D-378146C4D367} 57 | EndGlobalSection 58 | EndGlobal 59 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | 3 | # IDE0055: Fix formatting 4 | dotnet_diagnostic.IDE0055.severity = none 5 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/.gitignore: -------------------------------------------------------------------------------- 1 | *.7z 2 | .vs/* 3 | bin/* 4 | obj/* 5 | *.user 6 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/App.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | /Resources/segoe-fluent-icons.ttf#Segoe Fluent Icons 25 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using Composition.WindowsRuntimeHelpers; 2 | using GenshinFishingToy.Core; 3 | using GenshinFishingToy.ViewModels; 4 | using Hardcodet.Wpf.TaskbarNotification; 5 | using Microsoft.Toolkit.Uwp.Notifications; 6 | using System; 7 | using System.ComponentModel; 8 | using System.Diagnostics; 9 | using System.Security.Principal; 10 | using System.Threading; 11 | using System.Threading.Tasks; 12 | using System.Windows; 13 | using Windows.System; 14 | 15 | namespace GenshinFishingToy; 16 | 17 | public partial class App : Application 18 | { 19 | private DispatcherQueueController _controller; 20 | public static new App? Current { get; protected set; } = null!; 21 | public TaskbarIcon Taskbar { get; protected set; } = null!; 22 | public static bool IsElevated { get; } = GetElevated(); 23 | 24 | public App() 25 | { 26 | Logger.Info("Startup"); 27 | Current = this; 28 | Current.DispatcherUnhandledException += (_, e) => e.Handled = true; 29 | _controller = CoreMessagingHelper.CreateDispatcherQueueControllerForCurrentThread(); 30 | AppDomain.CurrentDomain.UnhandledException += (s, e) => Logger.Error(e); 31 | ToastNotificationManagerCompat.OnActivated += NotifyIconViewModel.OnNotificationActivated; 32 | NoticeService.ClearNotice(); 33 | if (!EnsureElevated()) return; 34 | CheckSingleInstance(); 35 | InitializeComponent(); 36 | SetupLanguage(); 37 | SettingsManager.Setup(); 38 | CheckOSVersion(); 39 | } 40 | 41 | protected override void OnStartup(StartupEventArgs e) 42 | { 43 | Taskbar = (TaskbarIcon)FindResource("PART_Taskbar"); 44 | base.OnStartup(e); 45 | } 46 | 47 | protected override void OnExit(ExitEventArgs e) 48 | { 49 | NoticeService.ClearNotice(); 50 | base.OnExit(e); 51 | } 52 | 53 | protected void CheckOSVersion() 54 | { 55 | if (!Pack.IsSupported) 56 | { 57 | NoticeService.AddNotice(Mui("Tips"), Mui("SupportedOSVersionTips", Pack.SupportedOSVersion, Pack.CurrentOSVersion), string.Empty, ToastDuration.Short); 58 | } 59 | } 60 | 61 | public bool EnsureElevated() 62 | { 63 | if (!IsElevated) 64 | { 65 | RestartAsElevated('r' + 'u' + 'n' + 'a' + 's'); 66 | return false; 67 | } 68 | return true; 69 | } 70 | 71 | public static void RestartAsElevated(int? exitCode = null) 72 | { 73 | try 74 | { 75 | _ = Process.Start(new ProcessStartInfo() 76 | { 77 | Verb = "runas", 78 | UseShellExecute = true, 79 | FileName = Process.GetCurrentProcess().MainModule!.FileName, 80 | WorkingDirectory = Environment.CurrentDirectory, 81 | }); 82 | } 83 | catch (Win32Exception) 84 | { 85 | return; 86 | } 87 | Current!.Shutdown(); 88 | if (exitCode != null) Environment.Exit(exitCode.Value); 89 | } 90 | 91 | private static bool GetElevated() 92 | { 93 | using WindowsIdentity identity = WindowsIdentity.GetCurrent(); 94 | WindowsPrincipal principal = new(identity); 95 | return principal.IsInRole(WindowsBuiltInRole.Administrator); 96 | } 97 | 98 | public void CheckSingleInstance() 99 | { 100 | EventWaitHandle? handle; 101 | 102 | try 103 | { 104 | handle = EventWaitHandle.OpenExisting(Pack.Alias); 105 | handle.Set(); 106 | Shutdown(); 107 | } 108 | catch (WaitHandleCannotBeOpenedException) 109 | { 110 | handle = new EventWaitHandle(false, EventResetMode.AutoReset, Pack.Alias); 111 | } 112 | GC.KeepAlive(handle); 113 | _ = Task.Run(() => 114 | { 115 | while (handle.WaitOne()) 116 | { 117 | Dispatcher.Invoke(() => 118 | { 119 | MainWindow?.Activate(); 120 | MainWindow?.Focus(); 121 | MainWindow?.Show(); 122 | }); 123 | } 124 | }); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/GenshinRegedit.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32; 2 | using System; 3 | 4 | namespace GenshinFishingToy.Core; 5 | 6 | internal class GenshinRegedit 7 | { 8 | public static string InstallPath 9 | { 10 | get 11 | { 12 | try 13 | { 14 | using RegistryKey hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64); 15 | RegistryKey? key = hklm.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\原神"); 16 | 17 | if (key == null) 18 | { 19 | key = hklm.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Genshin Impact"); 20 | 21 | if (key == null) 22 | { 23 | return null!; 24 | } 25 | } 26 | 27 | object installLocation = key.GetValue("InstallPath")!; 28 | key?.Dispose(); 29 | 30 | if (installLocation != null && !string.IsNullOrEmpty(installLocation.ToString())) 31 | { 32 | return installLocation.ToString()!; 33 | } 34 | } 35 | catch (Exception e) 36 | { 37 | NoticeService.AddNotice(Mui("Tips"), "Failed", e.Message); 38 | } 39 | return null!; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/GenshinWindow.cs: -------------------------------------------------------------------------------- 1 | using GenshinFishingToy.Models; 2 | using GenshinFishingToy.Views; 3 | using System; 4 | using System.Threading.Tasks; 5 | 6 | namespace GenshinFishingToy.Core; 7 | 8 | public class GenshinWindow 9 | { 10 | protected IntPtr hwnd; 11 | public IntPtr Hwnd => hwnd; 12 | 13 | public bool IsSetupClient { get; protected set; } = false; 14 | 15 | internal MotionAreaWindow MotionArea = new(); 16 | 17 | public GenshinWindow() 18 | { 19 | if (LaunchCtrl.TryGetHwnd(out hwnd)) 20 | { 21 | MotionArea.rectGameLatest = NativeMethods.GetWindowRECT(hwnd); 22 | } 23 | } 24 | 25 | public async Task Start() 26 | { 27 | await HasHwnd(); 28 | MotionArea.rectGameLatest = NativeMethods.GetWindowRECT(hwnd); 29 | } 30 | 31 | public async Task HasHwnd() 32 | { 33 | return await LaunchCtrl.IsRunning(async p => 34 | { 35 | hwnd = p?.MainWindowHandle ?? IntPtr.Zero; 36 | }); 37 | } 38 | 39 | public void MouseLeftButtonDown() 40 | { 41 | NativeMethods.Focus(hwnd); 42 | NativeMethods.PostMessage(hwnd, NativeMethods.WM_LBUTTONDOWN, 0, (0 << 16) | 0); 43 | } 44 | 45 | public void MouseLeftButtonUp() 46 | { 47 | NativeMethods.Focus(hwnd); 48 | NativeMethods.PostMessage(hwnd, NativeMethods.WM_LBUTTONUP, 0, (0 << 16) | 0); 49 | } 50 | 51 | public async Task MouseClick(int x, int y) 52 | { 53 | NativeMethods.Focus(hwnd); 54 | NativeMethods.PostMessage(hwnd, NativeMethods.WM_LBUTTONDOWN, 0, (y << 16) | x); 55 | await Task.Delay(80); 56 | NativeMethods.PostMessage(hwnd, NativeMethods.WM_LBUTTONUP, 0, (y << 16) | x); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/HotKey/Hotkey.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace GenshinFishingToy.Core; 5 | 6 | public class Hotkey 7 | { 8 | public bool Alt { get; set; } 9 | public bool Control { get; set; } 10 | public bool Shift { get; set; } 11 | public bool Windows { get; set; } 12 | 13 | private Keys key; 14 | public Keys Key 15 | { 16 | get => key; 17 | set 18 | { 19 | if (value != Keys.ControlKey && value != Keys.Alt && value != Keys.Menu && value != Keys.ShiftKey) 20 | { 21 | key = value; 22 | } 23 | else 24 | { 25 | key = Keys.None; 26 | } 27 | } 28 | } 29 | 30 | public ModifierKeys ModifierKey => 31 | (Windows ? ModifierKeys.Win : 0) | 32 | (Control ? ModifierKeys.Control : 0) | 33 | (Shift ? ModifierKeys.Shift : 0) | 34 | (Alt ? ModifierKeys.Alt : 0); 35 | 36 | public Hotkey() 37 | { 38 | Reset(); 39 | } 40 | 41 | public Hotkey(string hotkeyStr) 42 | { 43 | try 44 | { 45 | string[] keyStrs = hotkeyStr.Replace(" ", "").Split('+'); 46 | foreach (string keyStr in keyStrs) 47 | { 48 | string k = keyStr.ToLower(); 49 | if (k == "win") 50 | Windows = true; 51 | else if (k == "ctrl") 52 | Control = true; 53 | else if (k == "shift") 54 | Shift = true; 55 | else if (k == "alt") 56 | Alt = true; 57 | else 58 | Key = (Keys)Enum.Parse(typeof(Keys), keyStr); 59 | } 60 | } 61 | catch 62 | { 63 | throw new ArgumentException("Invalid Hotkey"); 64 | } 65 | } 66 | 67 | public override string ToString() 68 | { 69 | string str = string.Empty; 70 | if (Key != Keys.None) 71 | { 72 | str = string.Format("{0}{1}{2}{3}{4}", 73 | Windows ? "Win + " : string.Empty, 74 | Control ? "Ctrl + " : string.Empty, 75 | Shift ? "Shift + " : string.Empty, 76 | Alt ? "Alt + " : string.Empty, 77 | Key); 78 | } 79 | return str; 80 | } 81 | 82 | public void Reset() 83 | { 84 | Alt = false; 85 | Control = false; 86 | Shift = false; 87 | Windows = false; 88 | Key = Keys.None; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/HotKey/HotkeyHolder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GenshinFishingToy.Core; 4 | 5 | internal class HotkeyHolder 6 | { 7 | private static Hotkey? hotkey; 8 | private static HotkeyHook? hotkeyHook; 9 | private static Action? keyPressed; 10 | 11 | public static void RegisterHotKey(string hotkeyStr, Action keyPressed = null!) 12 | { 13 | if (string.IsNullOrEmpty(hotkeyStr)) 14 | { 15 | UnregisterHotKey(); 16 | return; 17 | } 18 | 19 | hotkey = new Hotkey(hotkeyStr); 20 | 21 | hotkeyHook?.Dispose(); 22 | hotkeyHook = new HotkeyHook(); 23 | hotkeyHook.KeyPressed -= OnKeyPressed; 24 | hotkeyHook.KeyPressed += OnKeyPressed; 25 | HotkeyHolder.keyPressed = keyPressed; 26 | hotkeyHook.RegisterHotKey(hotkey.ModifierKey, hotkey.Key); 27 | } 28 | 29 | public static void UnregisterHotKey() 30 | { 31 | if (hotkeyHook != null) 32 | { 33 | hotkeyHook.KeyPressed -= OnKeyPressed; 34 | hotkeyHook.UnregisterHotKey(); 35 | hotkeyHook.Dispose(); 36 | } 37 | } 38 | 39 | private static void OnKeyPressed(object? sender, KeyPressedEventArgs e) 40 | { 41 | keyPressed?.Invoke(sender, e); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/HotKey/HotkeyHook.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Windows.Forms; 4 | using System.Windows.Input; 5 | 6 | namespace GenshinFishingToy.Core; 7 | 8 | /// 9 | /// https://stackoverflow.com/questions/2450373/set-global-hotkeys-using-c-sharp 10 | /// 11 | public sealed class HotkeyHook : IDisposable 12 | { 13 | public event EventHandler? KeyPressed; 14 | private readonly Window? window = new(); 15 | private int currentId; 16 | 17 | private class Window : NativeWindow, IDisposable 18 | { 19 | public event EventHandler? KeyPressed; 20 | 21 | public Window() 22 | { 23 | CreateHandle(new CreateParams()); 24 | } 25 | 26 | protected override void WndProc(ref Message m) 27 | { 28 | base.WndProc(ref m); 29 | 30 | if (m.Msg == NativeMethods.WM_HOTKEY) 31 | { 32 | Keys key = (Keys)((int)m.LParam >> 16 & 0xFFFF); 33 | ModifierKeys modifier = (ModifierKeys)((int)m.LParam & 0xFFFF); 34 | 35 | KeyPressed?.Invoke(this, new KeyPressedEventArgs(modifier, key)); 36 | } 37 | } 38 | 39 | public void Dispose() 40 | { 41 | DestroyHandle(); 42 | } 43 | } 44 | 45 | public HotkeyHook() 46 | { 47 | window.KeyPressed += (sender, args) => 48 | { 49 | KeyPressed?.Invoke(this, args); 50 | }; 51 | } 52 | 53 | public void RegisterHotKey(ModifierKeys modifier, Keys key) 54 | { 55 | currentId += 1; 56 | if (!NativeMethods.RegisterHotKey(window!.Handle, currentId, (uint)modifier, (uint)key)) 57 | { 58 | if (Marshal.GetLastWin32Error() == 1409) 59 | throw new InvalidOperationException("Hotkey already occupied"); 60 | else 61 | throw new InvalidOperationException("Hotkey registration failed"); 62 | } 63 | } 64 | 65 | public void UnregisterHotKey() 66 | { 67 | for (int i = currentId; i > 0; i--) 68 | { 69 | NativeMethods.UnregisterHotKey(window!.Handle, i); 70 | } 71 | } 72 | 73 | public void Dispose() 74 | { 75 | UnregisterHotKey(); 76 | window?.Dispose(); 77 | } 78 | } 79 | 80 | public class KeyPressedEventArgs : EventArgs 81 | { 82 | public ModifierKeys Modifier { get; } 83 | public Keys Key { get; } 84 | 85 | internal KeyPressedEventArgs(ModifierKeys modifier, Keys key) 86 | { 87 | Modifier = modifier; 88 | Key = key; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/ImageCapture.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Text.RegularExpressions; 4 | using System.Windows; 5 | using WPFCaptureSample; 6 | 7 | namespace GenshinFishingToy.Core; 8 | 9 | internal static class ImageCapture 10 | { 11 | public static int X { get; set; } 12 | public static int Y { get; set; } 13 | public static int W { get; set; } 14 | public static int H { get; set; } 15 | 16 | public static ImageCaptureType CaptureType = ImageCaptureType.WindowsGraphicsCapture; 17 | 18 | public static void Setup(int x, int y, int w, int h) 19 | { 20 | X = x; 21 | Y = y; 22 | W = w; 23 | H = h; 24 | } 25 | 26 | public static void Setup((int x, int y, int w, int h) rect) 27 | { 28 | Setup(rect.x, rect.y, rect.w, rect.h); 29 | } 30 | 31 | public static void Teardown() 32 | { 33 | GraphicsCapture.Uncapture(); 34 | } 35 | 36 | public static bool IsFullScreen { get; private set; } = false; 37 | public static bool IsFullScreenMode(IntPtr hwnd) 38 | { 39 | int exStyle = NativeMethods.GetWindowLong(hwnd, NativeMethods.GWL_EXSTYLE); 40 | 41 | if ((exStyle & NativeMethods.WS_EX_TOPMOST) != 0) 42 | { 43 | return IsFullScreen = true; 44 | } 45 | return IsFullScreen = false; 46 | } 47 | 48 | private static int GetCaptionHeight(IntPtr? hwnd = null) 49 | { 50 | int captionHeight = default; 51 | 52 | if (hwnd != null && hwnd != IntPtr.Zero) 53 | { 54 | if (!IsFullScreenMode(hwnd.Value)) 55 | { 56 | captionHeight = (int)(SystemParameters.CaptionHeight * DpiUtils.ScaleY); 57 | } 58 | } 59 | return captionHeight; 60 | } 61 | 62 | public static Bitmap Capture(IntPtr? hwnd = null) 63 | { 64 | if (CaptureType == ImageCaptureType.BitBlt) 65 | { 66 | return ImageExtension.Capture(X, Y - GetCaptionHeight(hwnd), W, H, hwnd); 67 | } 68 | else if (CaptureType == ImageCaptureType.WindowsGraphicsCapture) 69 | { 70 | return GraphicsCapture.Capture(X, Y, W, H, hwnd); 71 | } 72 | return null!; 73 | } 74 | 75 | public static Bitmap CaptureLiftingWords(IntPtr? hwnd = null) 76 | { 77 | if (CaptureType == ImageCaptureType.BitBlt) 78 | { 79 | return ImageExtension.Capture(X, Y - GetCaptionHeight(hwnd) + H, W, (int)(H * 2.5d), hwnd); 80 | } 81 | else if (CaptureType == ImageCaptureType.WindowsGraphicsCapture) 82 | { 83 | return GraphicsCapture.Capture(X, Y + H, W, (int)(H * 2.5d), hwnd); 84 | } 85 | return null!; 86 | } 87 | } 88 | 89 | public enum ImageCaptureType 90 | { 91 | /// 92 | /// BitBlt (Windows 7 and up) 93 | /// 94 | BitBlt, 95 | 96 | /// 97 | /// Windows 10 (1903 and up) 98 | /// 99 | WindowsGraphicsCapture, 100 | } 101 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/ImageExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Windows; 4 | using System.Windows.Interop; 5 | using System.Windows.Media; 6 | using System.Windows.Media.Imaging; 7 | 8 | namespace GenshinFishingToy.Core; 9 | 10 | internal static class ImageExtension 11 | { 12 | public static ImageSource ToImageSource(this Bitmap bitmap) 13 | { 14 | IntPtr hBitmap = bitmap.GetHbitmap(); 15 | ImageSource imageSource = Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); 16 | 17 | _ = NativeMethods.DeleteObject(hBitmap); 18 | return imageSource; 19 | } 20 | 21 | public static BitmapSource ToBitmapSource(this Bitmap bitmap) 22 | { 23 | try 24 | { 25 | return Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); 26 | } 27 | catch 28 | { 29 | } 30 | return null!; 31 | } 32 | 33 | public static Bitmap Capture(int x, int y, int w, int h, IntPtr? hwnd = null) 34 | { 35 | try 36 | { 37 | Bitmap copied = new(w, h); 38 | using Graphics g = Graphics.FromImage(copied); 39 | IntPtr hdcDest = g.GetHdc(); 40 | IntPtr hdcSrc = NativeMethods.GetDC(hwnd ?? NativeMethods.GetDesktopWindow()); 41 | _ = NativeMethods.StretchBlt(hdcDest, 0, 0, w, h, hdcSrc, x, y, w, h, CopyPixelOperation.SourceCopy); 42 | g.ReleaseHdc(); 43 | _ = NativeMethods.DeleteDC(hdcDest); 44 | _ = NativeMethods.DeleteDC(hdcSrc); 45 | return copied; 46 | } 47 | catch 48 | { 49 | } 50 | return null!; 51 | } 52 | 53 | public static Bitmap CaptureRodWordsArea(int x, int y, int w, int h, IntPtr? hwnd = null) 54 | { 55 | return Capture(x, y + h, w, h * 2, hwnd); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/ImageRecognition.cs: -------------------------------------------------------------------------------- 1 | using OpenCvSharp; 2 | using OpenCvSharp.Extensions; 3 | using System.Collections.Generic; 4 | using System.Drawing; 5 | using System.Linq; 6 | using Point = OpenCvSharp.Point; 7 | 8 | namespace GenshinFishingToy.Core; 9 | 10 | internal class ImageRecognition 11 | { 12 | public static List GetRect(Bitmap img, bool enableImShow = false) 13 | { 14 | if (img == null) 15 | { 16 | return null!; 17 | } 18 | 19 | using Mat mask = new(); 20 | using Mat rgbMat = new(); 21 | using Mat src = img.ToMat(); 22 | 23 | Cv2.CvtColor(src, rgbMat, ColorConversionCodes.BGR2RGB); 24 | Scalar lowPurple = new(255, 255, 192); 25 | Scalar highPurple = new(255, 255, 192); 26 | Cv2.InRange(rgbMat, lowPurple, highPurple, mask); 27 | Cv2.Threshold(mask, mask, 0, 255, ThresholdTypes.Binary); // 二值化 28 | 29 | Cv2.FindContours(mask, out Point[][] contours, out HierarchyIndex[] hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple, null); 30 | if (contours.Length > 0) 31 | { 32 | Mat imgTar = src.Clone(); 33 | IEnumerable boxes = contours.Select(Cv2.BoundingRect).Where(w => w.Height >= 10); 34 | List rects = boxes.ToList(); 35 | foreach (Rect rect in rects) 36 | { 37 | Cv2.Rectangle(imgTar, new Point(rect.X, rect.Y), new Point(rect.X + rect.Width, rect.Y + rect.Height), Scalar.Red, 2); 38 | } 39 | if (enableImShow) 40 | { 41 | Cv2.ImShow(Mui("RecognitionJiggingDebug"), imgTar); 42 | } 43 | return rects; 44 | } 45 | else 46 | { 47 | return null!; 48 | } 49 | } 50 | 51 | public static Rect MatchWords(Bitmap img, bool enableImShow = false) 52 | { 53 | if (img == null) 54 | { 55 | return default; 56 | } 57 | using Mat src = img.ToMat(); 58 | using Mat result = new(); 59 | 60 | Cv2.CvtColor(src, src, ColorConversionCodes.BGR2RGB); 61 | var lowPurple = new Scalar(253, 253, 253); 62 | var highPurple = new Scalar(255, 255, 255); 63 | Cv2.InRange(src, lowPurple, highPurple, src); 64 | Cv2.Threshold(src, src, 0, 255, ThresholdTypes.Binary); 65 | var kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(20, 20), new Point(-1, -1)); 66 | Cv2.Dilate(src, src, kernel); // 膨胀 67 | 68 | Scalar color = new(0, 0, 255); 69 | Cv2.FindContours(src, out Point[][] contours, out HierarchyIndex[] hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple, null); 70 | if (contours.Length > 0) 71 | { 72 | var imgTar = img.ToMat(); 73 | var boxes = contours.Select(Cv2.BoundingRect); 74 | List rects = boxes.ToList(); 75 | if (rects.Count > 1) 76 | { 77 | rects.Sort((a, b) => b.Height.CompareTo(a.Height)); 78 | } 79 | if (rects[0].Height < src.Height 80 | && rects[0].Width * 1d / rects[0].Height >= 3 // 长宽比判断 81 | && ImageCapture.W > rects[0].Width * 3 // 文字范围3倍小于钓鱼条范围的 82 | && ImageCapture.W * 1d / 2 > rects[0].X // 中轴线判断左 83 | && ImageCapture.W * 1d / 2 < rects[0].X + rects[0].Width) // 中轴线判断右 84 | { 85 | foreach (Rect rect in rects) 86 | { 87 | Cv2.Rectangle(imgTar, new Point(rect.X, rect.Y), new Point(rect.X + rect.Width, rect.Y + rect.Height), Scalar.Red, 2); 88 | } 89 | if (enableImShow) 90 | { 91 | Cv2.ImShow(Mui("RecognitionLiftingDebug"), imgTar); 92 | } 93 | return rects[0]; 94 | } 95 | } 96 | return Rect.Empty; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/LaunchCtrl.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace GenshinFishingToy.Core; 8 | 9 | internal class LaunchCtrl 10 | { 11 | public static async Task SearchRunning() 12 | { 13 | return await Task.Run(() => 14 | { 15 | try 16 | { 17 | Process[] processes = Process.GetProcessesByName("YuanShen"); 18 | 19 | if (processes.Length <= 0) 20 | { 21 | processes = Process.GetProcessesByName("Genshin Impact"); 22 | } 23 | if (processes.Length <= 0) 24 | { 25 | processes = Process.GetProcessesByName("GenshinImpact"); 26 | } 27 | return processes.Length > 0; 28 | } 29 | catch 30 | { 31 | } 32 | return false; 33 | }); 34 | } 35 | 36 | public static async Task IsRunning(Func callback = null!) 37 | { 38 | return await Task.Run(async () => 39 | { 40 | try 41 | { 42 | Process[] processes = Process.GetProcessesByName("YuanShen"); 43 | 44 | if (processes.Length <= 0) 45 | { 46 | processes = Process.GetProcessesByName("Genshin Impact"); 47 | } 48 | if (processes.Length <= 0) 49 | { 50 | processes = Process.GetProcessesByName("GenshinImpact"); 51 | } 52 | if (processes.Length > 0) 53 | { 54 | foreach (Process? process in processes) 55 | { 56 | await callback?.Invoke(process)!; 57 | return true; 58 | } 59 | } 60 | } 61 | catch 62 | { 63 | } 64 | return false; 65 | }); 66 | } 67 | 68 | public static bool TryGetHwnd(out IntPtr hwnd) 69 | { 70 | try 71 | { 72 | Process[] processes = Process.GetProcessesByName("YuanShen"); 73 | 74 | if (processes.Length <= 0) 75 | { 76 | processes = Process.GetProcessesByName("Genshin Impact"); 77 | } 78 | if (processes.Length <= 0) 79 | { 80 | processes = Process.GetProcessesByName("GenshinImpact"); 81 | } 82 | if (processes.Length > 0) 83 | { 84 | foreach (Process? process in processes) 85 | { 86 | hwnd = process?.MainWindowHandle ?? IntPtr.Zero; 87 | return true; 88 | } 89 | } 90 | } 91 | catch 92 | { 93 | } 94 | 95 | hwnd = IntPtr.Zero; 96 | return false; 97 | } 98 | 99 | public static async Task Launch(LaunchParameter launchParameter = null!) 100 | { 101 | if (string.IsNullOrEmpty(GenshinRegedit.InstallPath)) 102 | { 103 | NoticeService.AddNotice(Mui("Tips"), "Failed", "Genshin Impact not installed."); 104 | } 105 | else 106 | { 107 | const string GameFolderName = "Genshin Impact Game"; 108 | 109 | string fileName = Path.Combine(GenshinRegedit.InstallPath, GameFolderName, "YuanShen.exe"); 110 | 111 | if (!File.Exists(fileName)) 112 | { 113 | fileName = Path.Combine(GenshinRegedit.InstallPath, GameFolderName, "GenshinImpact.exe"); 114 | } 115 | 116 | Process? p = Process.Start(new ProcessStartInfo() 117 | { 118 | UseShellExecute = true, 119 | FileName = Path.Combine(GenshinRegedit.InstallPath, GameFolderName, fileName), 120 | Arguments = (launchParameter ?? new()).ToString(), 121 | WorkingDirectory = Path.Combine(GenshinRegedit.InstallPath, GameFolderName), 122 | Verb = "runas", 123 | }); 124 | return p?.MainWindowHandle ?? IntPtr.Zero; 125 | } 126 | return IntPtr.Zero; 127 | } 128 | 129 | internal class LaunchParameter 130 | { 131 | public bool? IsFullScreen { get; set; } = null; 132 | public int? ScreenWidth { get; set; } = null; 133 | public int? ScreenHeight { get; set; } = null; 134 | 135 | public override string ToString() 136 | { 137 | StringBuilder sb = new(); 138 | 139 | if (IsFullScreen != null) 140 | { 141 | sb.Append("-screen-fullscreen").Append(' ').Append(IsFullScreen.Value ? 1 : 0); 142 | } 143 | if (ScreenWidth != null) 144 | { 145 | sb.Append("-screen-width").Append(' ').Append(ScreenWidth); 146 | } 147 | if (ScreenHeight != null) 148 | { 149 | sb.Append("-screen-height").Append(' ').Append(ScreenHeight); 150 | } 151 | return sb.ToString(); 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/Logger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Globalization; 4 | using System.IO.Abstractions; 5 | using System.Reflection; 6 | using System.Text; 7 | 8 | namespace GenshinFishingToy.Core; 9 | 10 | public static class Logger 11 | { 12 | private static readonly FileSystem FileSystem = new(); 13 | private static readonly IPath Path = FileSystem.Path; 14 | private static readonly IDirectory Directory = FileSystem.Directory; 15 | private static readonly string ApplicationLogPath = SpecialPathProvider.GetPath(string.Empty); 16 | private static TextWriterTraceListener TraceListener = null!; 17 | 18 | static Logger() 19 | { 20 | if (!Directory.Exists(ApplicationLogPath)) 21 | { 22 | Directory.CreateDirectory(ApplicationLogPath); 23 | } 24 | 25 | string logFilePath = Path.Combine(ApplicationLogPath, DateTime.Now.ToString(@"yyyyMMdd", CultureInfo.InvariantCulture) + ".log"); 26 | TraceListener = new TextWriterTraceListener(logFilePath); 27 | #if LEGACY 28 | Trace.AutoFlush = true; 29 | Trace.Listeners.Clear(); 30 | Trace.Listeners.Add(TraceListener); 31 | #endif 32 | } 33 | 34 | public static void Info(params object[] values) 35 | { 36 | Log("INFO", string.Join(" ", values)); 37 | } 38 | 39 | public static void Warn(params object[] values) 40 | { 41 | Log("ERROR", string.Join(" ", values)); 42 | } 43 | 44 | public static void Error(params object[] values) 45 | { 46 | Log("ERROR", string.Join(" ", values)); 47 | } 48 | 49 | public static void Fatal(params object[] values) 50 | { 51 | Log("ERROR", string.Join(" ", values)); 52 | #if DEBUG 53 | Debugger.Break(); 54 | #endif 55 | } 56 | 57 | public static void Exception(Exception e, string message = null!) 58 | { 59 | Log( 60 | (message ?? string.Empty) + Environment.NewLine + 61 | e?.Message + Environment.NewLine + 62 | "Inner exception: " + Environment.NewLine + 63 | e?.InnerException?.Message + Environment.NewLine + 64 | "Stack trace: " + Environment.NewLine + 65 | e?.StackTrace, 66 | "ERROR"); 67 | #if DEBUG 68 | Debugger.Break(); 69 | #endif 70 | } 71 | 72 | private static void Log(string type, string message) 73 | { 74 | StringBuilder sb = new(); 75 | 76 | sb.Append(type + "|" + DateTime.Now.ToString(@"yyyy-MM-dd|HH:mm:ss.fff", CultureInfo.InvariantCulture)) 77 | .Append("|" + GetCallerInfo()) 78 | .Append("|" + message); 79 | 80 | Debug.WriteLine(sb.ToString()); 81 | #if DEBUG || EN_LOGGER 82 | TraceListener?.WriteLine(sb.ToString()); 83 | TraceListener?.Flush(); 84 | #endif 85 | } 86 | 87 | private static string GetCallerInfo() 88 | { 89 | StackTrace stackTrace = new(); 90 | 91 | MethodBase methodName = stackTrace.GetFrame(3)?.GetMethod()!; 92 | string? className = methodName?.DeclaringType?.Name; 93 | return className + "|" + methodName?.Name; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/Settings/SettingsCache.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | 4 | namespace GenshinFishingToy.Core; 5 | 6 | internal class SettingsCache : ConcurrentDictionary 7 | { 8 | public T Get(SettingsDefinition definition) 9 | { 10 | string key = definition.Name; 11 | T defaultValue = definition.DefaultValue; 12 | Func? converter = definition.Converter; 13 | 14 | if (!TryGetValue(key, out object? value)) 15 | { 16 | this[key] = defaultValue; 17 | return defaultValue; 18 | } 19 | else 20 | { 21 | if (value is T tValue) 22 | { 23 | return tValue; 24 | } 25 | else 26 | { 27 | if (converter is null) 28 | { 29 | return (T)value!; 30 | } 31 | else 32 | { 33 | return converter.Invoke(value!); 34 | } 35 | } 36 | } 37 | } 38 | 39 | public void Set(SettingsDefinition definition, object? value) 40 | { 41 | string key = definition.Name; 42 | this[key] = value; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/Settings/SettingsDefinition{T}.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace GenshinFishingToy.Core; 4 | 5 | public class SettingsDefinition 6 | { 7 | internal static SettingsCache Cache => SettingsManager.Cache; 8 | 9 | public string Name { get; } 10 | public T DefaultValue { get; } 11 | public Func? Converter { get; } 12 | 13 | public SettingsDefinition(string name, T defaultValue, Func? converter = null) 14 | { 15 | Name = name; 16 | DefaultValue = defaultValue; 17 | Converter = converter ?? DefaultConverter!; 18 | } 19 | 20 | public static T? DefaultConverter(object value) 21 | { 22 | if (value is null) return default; 23 | try 24 | { 25 | return SettingsSerializer.DeserializeObject(SettingsSerializer.SerializeObject(value)); 26 | } 27 | catch 28 | { 29 | try 30 | { 31 | return (T?)typeof(T).Assembly.CreateInstance(typeof(T).FullName!); 32 | } 33 | catch 34 | { 35 | return default; 36 | } 37 | } 38 | } 39 | 40 | public T Get() 41 | { 42 | return Cache.Get(this); 43 | } 44 | 45 | public void Set(T value) 46 | { 47 | Cache.Set(this, value); 48 | } 49 | 50 | public static implicit operator T(SettingsDefinition self) 51 | { 52 | return self.Get(); 53 | } 54 | 55 | public void Relay() 56 | { 57 | Cache.Set(this, Get()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/Settings/SettingsManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace GenshinFishingToy.Core; 5 | 6 | internal class SettingsManager 7 | { 8 | public static event Action? Reloaded; 9 | public static readonly string Path = SpecialPathProvider.GetPath($"{Pack.Alias}.yaml"); 10 | public static SettingsCache Cache = Init(); 11 | 12 | public static void Setup() 13 | { 14 | _ = Cache; 15 | Save(); 16 | } 17 | 18 | public static SettingsCache Init() 19 | { 20 | SettingsCache instance = null!; 21 | 22 | if (File.Exists(Path)) 23 | { 24 | instance = Load(); 25 | } 26 | 27 | if (instance == null) 28 | { 29 | instance = new(); 30 | } 31 | return instance; 32 | } 33 | 34 | public static void Reinit() 35 | { 36 | Cache = Init(); 37 | Reloaded?.Invoke(); 38 | } 39 | 40 | public static SettingsCache Load() 41 | { 42 | return LoadFrom(Path); 43 | } 44 | 45 | public static SettingsCache LoadFrom(string filename) 46 | { 47 | try 48 | { 49 | return SettingsSerializer.DeserializeFile(filename) ?? new(); 50 | } 51 | catch (Exception e) 52 | { 53 | _ = e; 54 | return new(); 55 | } 56 | } 57 | 58 | public static bool Save() 59 | { 60 | return SaveAs(Path); 61 | } 62 | 63 | public static bool SaveAs(string filename, bool overwrite = true) 64 | { 65 | if (!overwrite && File.Exists(filename)) 66 | { 67 | return true; 68 | } 69 | return SettingsSerializer.SerializeFile(Path, Cache); 70 | } 71 | 72 | public static bool SaveAs(string filename, object obj, bool overwrite = true) 73 | { 74 | if (!overwrite && File.Exists(filename)) 75 | { 76 | return true; 77 | } 78 | return SettingsSerializer.SerializeFile(filename, obj); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/Settings/SettingsSerializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using YamlDotNet.Serialization; 4 | 5 | namespace GenshinFishingToy.Core; 6 | 7 | internal class SettingsSerializer 8 | { 9 | public static string SerializeObject(T obj) 10 | { 11 | Serializer serializer = new(); 12 | return serializer.Serialize(obj!); 13 | } 14 | 15 | public static T DeserializeObject(string input) 16 | { 17 | Deserializer deserializer = new(); 18 | return deserializer.Deserialize(input); 19 | } 20 | 21 | public static bool SerializeFile(string fileName, T obj) 22 | { 23 | bool ret = false; 24 | 25 | try 26 | { 27 | Serializer serializer = new(); 28 | string str = serializer.Serialize(obj!); 29 | using StreamWriter sw = File.CreateText(fileName); 30 | 31 | sw.Write(str); 32 | sw.Flush(); 33 | ret = true; 34 | } 35 | catch (Exception e) 36 | { 37 | _ = e; 38 | } 39 | return ret; 40 | } 41 | 42 | public static T DeserializeFile(string fileName) 43 | { 44 | T info = default!; 45 | 46 | try 47 | { 48 | Deserializer deserializer = new(); 49 | using StreamReader reader = new(fileName); 50 | info = deserializer.Deserialize(reader); 51 | } 52 | catch (Exception e) 53 | { 54 | _ = e; 55 | } 56 | return info; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/SpecialPathProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.IO; 4 | 5 | namespace GenshinFishingToy.Core; 6 | 7 | internal class SpecialPathProvider 8 | { 9 | public static string TempPath { get; } = Path.GetTempPath(); 10 | 11 | public static string GetPath(string baseName) 12 | { 13 | MigrateLegacy(baseName); // Remove this line since 2023.12.08 14 | return GetPathInternal(baseName); 15 | } 16 | 17 | internal static string GetPathInternal(string baseName) 18 | { 19 | string appUserPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); 20 | string configPath = Path.Combine(Path.Combine(appUserPath, Pack.Alias), baseName); 21 | 22 | if (!Directory.Exists(new FileInfo(configPath).DirectoryName)) 23 | { 24 | Directory.CreateDirectory(new FileInfo(configPath).DirectoryName!); 25 | } 26 | return configPath; 27 | } 28 | 29 | public static string GetTempPath(string baseName) 30 | { 31 | return Path.Combine(TempPath + Pack.Alias, baseName); 32 | } 33 | 34 | #region Legacy 35 | [Description("Legacy")] 36 | private static string GetPathLegacy(string baseName) 37 | { 38 | string appUserPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); 39 | string configPath = Path.Combine(Path.Combine(appUserPath, Pack.Alias), baseName); 40 | 41 | return configPath; 42 | } 43 | 44 | [Description("Legacy")] 45 | private static void MigrateLegacy(string baseName) 46 | { 47 | try 48 | { 49 | string path = GetPathInternal(baseName); 50 | string pathLegacy = GetPathLegacy(baseName); 51 | 52 | if (!File.Exists(path) && File.Exists(pathLegacy)) 53 | { 54 | File.Copy(pathLegacy, path); 55 | } 56 | } 57 | catch 58 | { 59 | Logger.Warn($"[SpecialPathProvider] Migrate Legacy file `{baseName}` failed."); 60 | } 61 | } 62 | #endregion 63 | } 64 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/UIElement/AssemblyUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Text; 4 | 5 | namespace GenshinFishingToy.Core; 6 | 7 | internal static class AssemblyUtils 8 | { 9 | public static string GetAssemblyVersion(this Assembly assembly, VersionType type = VersionType.Major | VersionType.Minor | VersionType.Build, string prefix = null!, string subfix = null!) 10 | { 11 | Version version = assembly.GetName().Version!; 12 | StringBuilder sb = new(); 13 | 14 | if (prefix != null) 15 | { 16 | sb.Append(prefix); 17 | } 18 | if (type.HasFlag(VersionType.Major)) 19 | { 20 | sb.Append(version!.Major); 21 | } 22 | if (type.HasFlag(VersionType.Minor)) 23 | { 24 | if (sb.Length > 0) 25 | sb.Append("."); 26 | sb.Append(version!.Minor); 27 | } 28 | if (type.HasFlag(VersionType.Build)) 29 | { 30 | if (sb.Length > 0) 31 | sb.Append("."); 32 | sb.Append(version.Build); 33 | } 34 | if (type.HasFlag(VersionType.Revision)) 35 | { 36 | if (sb.Length > 0) 37 | sb.Append("."); 38 | sb.Append(version.Revision); 39 | } 40 | if (subfix != null) 41 | { 42 | sb.Append(subfix); 43 | } 44 | return sb.ToString(); 45 | } 46 | 47 | [Flags] 48 | public enum VersionType 49 | { 50 | Major = 0, 51 | Minor = 1, 52 | Build = 2, 53 | Revision = 4, 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/UIElement/BrushAnimation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using System.Windows; 4 | using System.Windows.Controls; 5 | using System.Windows.Media; 6 | using System.Windows.Media.Animation; 7 | 8 | namespace GenshinFishingToy.Core; 9 | 10 | public class BrushAnimation : AnimationTimeline 11 | { 12 | public Brush From 13 | { 14 | get { return (Brush)GetValue(FromProperty); } 15 | set { SetValue(FromProperty, value); } 16 | } 17 | 18 | public static readonly DependencyProperty FromProperty = 19 | DependencyProperty.Register("From", typeof(Brush), typeof(BrushAnimation)); 20 | 21 | public Brush To 22 | { 23 | get { return (Brush)GetValue(ToProperty); } 24 | set { SetValue(ToProperty, value); } 25 | } 26 | 27 | public static readonly DependencyProperty ToProperty = DependencyProperty.Register("To", typeof(Brush), typeof(BrushAnimation)); 28 | 29 | public override Type TargetPropertyType => typeof(Brush); 30 | 31 | public override object GetCurrentValue(object defaultOriginValue, object defaultDestinationValue, AnimationClock animationClock) 32 | { 33 | return GetCurrentValue((defaultOriginValue as Brush)!, (defaultDestinationValue as Brush)!, animationClock); 34 | } 35 | 36 | protected override Freezable CreateInstanceCore() 37 | { 38 | return new BrushAnimation(); 39 | } 40 | 41 | public object GetCurrentValue(Brush defaultOriginValue, Brush defaultDestinationValue, AnimationClock animationClock) 42 | { 43 | if (!animationClock.CurrentProgress.HasValue) 44 | return Brushes.Transparent; 45 | 46 | defaultOriginValue = From ?? defaultOriginValue; 47 | defaultDestinationValue = To ?? defaultDestinationValue; 48 | 49 | if (animationClock.CurrentProgress.Value == 0) 50 | return defaultOriginValue; 51 | if (animationClock.CurrentProgress.Value == 1) 52 | return defaultDestinationValue; 53 | 54 | if (To != null) 55 | { 56 | if (defaultDestinationValue is SolidColorBrush && ((SolidColorBrush)defaultDestinationValue).Color.A < 255 57 | && (!(defaultOriginValue is SolidColorBrush) || ((SolidColorBrush)defaultOriginValue).Color.A == 255)) 58 | { 59 | return GetVisualBrush(defaultDestinationValue, defaultOriginValue, 1 - animationClock.CurrentProgress.Value); 60 | } 61 | else 62 | { 63 | return GetVisualBrush(defaultOriginValue, defaultDestinationValue, animationClock.CurrentProgress.Value); 64 | } 65 | } 66 | else 67 | { 68 | if (defaultOriginValue is SolidColorBrush && ((SolidColorBrush)defaultOriginValue).Color.A < 255 69 | && (!(defaultDestinationValue is SolidColorBrush) || ((SolidColorBrush)defaultDestinationValue).Color.A == 255)) 70 | { 71 | return GetVisualBrush(defaultOriginValue, defaultDestinationValue, animationClock.CurrentProgress.Value); 72 | } 73 | else 74 | { 75 | return GetVisualBrush(defaultDestinationValue, defaultOriginValue, 1 - animationClock.CurrentProgress.Value); 76 | } 77 | } 78 | } 79 | 80 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 81 | public static VisualBrush GetVisualBrush(Brush background, Brush foreground, double opacity) 82 | { 83 | return new VisualBrush(new Border() 84 | { 85 | Width = 1, 86 | Height = 1, 87 | Background = background, 88 | 89 | Child = new Border() 90 | { 91 | Background = foreground, 92 | Opacity = opacity 93 | } 94 | }); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/UIElement/BrushConverterX.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Media; 2 | 3 | namespace GenshinFishingToy.Core; 4 | 5 | public static class BrushConverterX 6 | { 7 | public static Brush ToBrush(this string colorString) 8 | { 9 | return (new BrushConverter().ConvertFromString(colorString) as Brush)!; 10 | } 11 | 12 | public static Color ToColor(this string colorString) 13 | { 14 | return (Color)ColorConverter.ConvertFromString(colorString); 15 | } 16 | 17 | public static Color ToColor(this Brush brush) 18 | { 19 | return ((SolidColorBrush)brush).Color; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/UIElement/DpiUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows; 3 | 4 | namespace GenshinFishingToy.Core; 5 | 6 | public class DpiUtils 7 | { 8 | public static DpiScale GetScale() 9 | { 10 | IntPtr hdc = NativeMethods.GetDC(IntPtr.Zero); 11 | float scaleX = NativeMethods.GetDeviceCaps(hdc, DeviceCaps.LOGPIXELSX) / 96f; 12 | float scaleY = NativeMethods.GetDeviceCaps(hdc, DeviceCaps.LOGPIXELSY) / 96f; 13 | NativeMethods.ReleaseDC(IntPtr.Zero, hdc); 14 | return new(scaleX, scaleY); 15 | } 16 | 17 | public static double ScaleX => GetScale().DpiScaleX; 18 | public static double ScaleY => GetScale().DpiScaleY; 19 | 20 | public static double ScaleXReci => 1d / ScaleX; 21 | public static double ScaleYReci => 1d / ScaleY; 22 | } 23 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/UIElement/FluentSymbol.cs: -------------------------------------------------------------------------------- 1 | namespace GenshinFishingToy.Core; 2 | 3 | /// 4 | /// https://docs.microsoft.com/en-us/windows/apps/design/style/segoe-fluent-icons-font 5 | /// 6 | internal class FluentSymbol 7 | { 8 | public const string Start = "\xf5b0"; 9 | public const string Stop = "\xe73b"; 10 | 11 | public const string Pin = "\xe718"; 12 | public const string Unpin = "\xe77a"; 13 | } 14 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/UIElement/LanguageManager.cs: -------------------------------------------------------------------------------- 1 | using GenshinFishingToy.Models; 2 | using System; 3 | using System.Globalization; 4 | using System.Threading; 5 | using System.Windows; 6 | 7 | namespace GenshinFishingToy.Core; 8 | 9 | public static class LanguageManager 10 | { 11 | public static string SystemLanguage { get; } = (CultureInfo.CurrentUICulture.TwoLetterISOLanguageName.Clone() as string)!; 12 | 13 | public static void SetupLanguage() 14 | { 15 | if (!string.IsNullOrWhiteSpace(Settings.Language)) 16 | { 17 | Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = new CultureInfo(Settings.Language); 18 | } 19 | #if DEBUG 20 | #if MUI_ZH 21 | Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = new CultureInfo("zh-cn"); 22 | #elif MUI_JP 23 | Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = new CultureInfo("jp"); 24 | #elif MUI_EN 25 | Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = new CultureInfo("en-us"); 26 | #endif 27 | #endif 28 | _ = SetLanguage(); 29 | } 30 | 31 | public static bool SetLanguage() => SystemLanguage switch 32 | { 33 | "zh" => SetLanguage("zh-cn"), 34 | "jp" => SetLanguage("jp"), 35 | "en" or _ => SetLanguage("en-us"), 36 | }; 37 | 38 | public static bool SetLanguage(string name = "en-us") 39 | { 40 | try 41 | { 42 | foreach (ResourceDictionary dictionary in Application.Current.Resources.MergedDictionaries) 43 | { 44 | if (dictionary.Source != null && dictionary.Source.OriginalString.Equals($"/Resources/Languages/{name}.xaml")) 45 | { 46 | Application.Current.Resources.MergedDictionaries.Remove(dictionary); 47 | Application.Current.Resources.MergedDictionaries.Add(dictionary); 48 | return true; 49 | } 50 | } 51 | } 52 | catch (Exception e) 53 | { 54 | _ = e; 55 | } 56 | return false; 57 | } 58 | 59 | public static string Mui(string key) 60 | { 61 | try 62 | { 63 | if (App.Current!.FindResource(key) is string value) 64 | { 65 | return value; 66 | } 67 | } 68 | catch (Exception e) 69 | { 70 | _ = e; 71 | } 72 | return null!; 73 | } 74 | 75 | 76 | public static string Mui(string key, string arg0) 77 | { 78 | return string.Format(Mui(key), arg0); 79 | } 80 | 81 | public static string Mui(string key, string arg0, string arg1) 82 | { 83 | return string.Format(Mui(key), arg0, arg1); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/UIElement/NoticeService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Toolkit.Uwp.Notifications; 2 | using System; 3 | using System.Windows; 4 | 5 | namespace GenshinFishingToy.Core; 6 | 7 | internal static class NoticeService 8 | { 9 | static NoticeService() 10 | { 11 | ClearNotice(); 12 | } 13 | 14 | public static void AddNotice(string header, string title, string detail = null!, ToastDuration duration = ToastDuration.Short) 15 | { 16 | new ToastContentBuilder() 17 | .AddHeader("AddNotice", header, "AddNotice") 18 | .AddText(title) 19 | .AddAttributionTextIf(!string.IsNullOrEmpty(detail), detail) 20 | .SetToastDuration(duration) 21 | .ShowSafe(); 22 | } 23 | 24 | public static void AddNoticeWithButton(string header, string title, string button, (string, string) arg, ToastDuration duration = ToastDuration.Short) 25 | { 26 | new ToastContentBuilder() 27 | .AddHeader("AddNotice", header, "AddNotice") 28 | .AddText(title) 29 | .AddButton(new ToastButton().SetContent(button).AddArgument(arg.Item1, arg.Item2).SetBackgroundActivation()) 30 | .SetToastDuration(duration) 31 | .ShowSafe(); 32 | } 33 | 34 | public static void ClearNotice() 35 | { 36 | try 37 | { 38 | ToastNotificationManagerCompat.History.Clear(); 39 | } 40 | catch 41 | { 42 | } 43 | } 44 | } 45 | 46 | internal static class ToastContentBuilderExtensions 47 | { 48 | public static ToastContentBuilder AddAttributionTextIf(this ToastContentBuilder builder, bool condition, string text) 49 | { 50 | if (condition) 51 | { 52 | return builder.AddAttributionText(text); 53 | } 54 | else 55 | { 56 | return builder.Stub(); 57 | } 58 | } 59 | 60 | public static ToastContentBuilder Stub(this ToastContentBuilder builder) 61 | { 62 | return builder; 63 | } 64 | 65 | public static void ShowSafe(this ToastContentBuilder builder) 66 | { 67 | try 68 | { 69 | Application.Current.Dispatcher.Invoke(builder.Show); 70 | } 71 | catch (Exception) 72 | { 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/UIElement/ResourceUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.IO.Packaging; 4 | using System.Security.Cryptography; 5 | using System.Windows; 6 | using System.Windows.Resources; 7 | 8 | namespace GenshinFishingToy.Core; 9 | 10 | public static class ResourceUtils 11 | { 12 | static ResourceUtils() 13 | { 14 | if (!UriParser.IsKnownScheme("pack")) 15 | _ = PackUriHelper.UriSchemePack; 16 | } 17 | 18 | public static byte[] GetBytes(string uriString) 19 | { 20 | Uri uri = new(uriString); 21 | return GetBytes(uri); 22 | } 23 | 24 | public static byte[] GetBytes(Uri uri) 25 | { 26 | StreamResourceInfo info = Application.GetResourceStream(uri); 27 | using BinaryReader stream = new(info.Stream); 28 | return stream.ReadBytes((int)info.Stream.Length); 29 | } 30 | 31 | public static Stream GetStream(string uriString) 32 | { 33 | Uri uri = new(uriString); 34 | return GetStream(uri); 35 | } 36 | 37 | public static Stream GetStream(Uri uri) 38 | { 39 | StreamResourceInfo info = Application.GetResourceStream(uri); 40 | return info.Stream; 41 | } 42 | 43 | public static string GetMD5(byte[] data) 44 | { 45 | using MD5 provider = MD5.Create(); 46 | byte[] output = provider.ComputeHash(data); 47 | 48 | return BitConverter.ToString(output).Replace("-", ""); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/UIElement/StoryboardUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Windows; 4 | using System.Windows.Media; 5 | using System.Windows.Media.Animation; 6 | 7 | namespace GenshinFishingToy.Core; 8 | 9 | public static class StoryboardUtils 10 | { 11 | public static void BeginBrushStoryboard(DependencyObject dependencyObj, IDictionary toDictionary, double durationSeconds = 0.2d) 12 | { 13 | Storyboard storyboard = new(); 14 | foreach (var keyValue in toDictionary) 15 | { 16 | BrushAnimation anima = new() 17 | { 18 | To = keyValue.Value, 19 | Duration = TimeSpan.FromSeconds(durationSeconds), 20 | }; 21 | Storyboard.SetTarget(anima, dependencyObj); 22 | Storyboard.SetTargetProperty(anima, new PropertyPath(keyValue.Key)); 23 | storyboard.Children.Add(anima); 24 | } 25 | storyboard.Begin(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/UIElement/SvgViewboxExtension.cs: -------------------------------------------------------------------------------- 1 | using SharpVectors.Converters; 2 | using System.Windows.Media; 3 | 4 | namespace GenshinFishingToy.Core; 5 | 6 | internal static class SvgViewboxExtension 7 | { 8 | public static void SetColor(this SvgViewbox control, string color) 9 | { 10 | static void ChangeDrawingGroupColor(DrawingGroup dg, Brush brush) 11 | { 12 | foreach (Drawing d in dg.Children) ChangeDrawingColor(d, brush); 13 | } 14 | 15 | static void ChangeDrawingColor(Drawing d, Brush brush) 16 | { 17 | if (d is DrawingGroup dg) ChangeDrawingGroupColor(dg, brush); 18 | else if (d is GeometryDrawing g) 19 | { 20 | g.Brush = brush; 21 | if (g.Pen != null) g.Pen.Brush = brush; 22 | } 23 | } 24 | 25 | static void ChangeSvgViewboxColor(SvgViewbox control, Brush brush) 26 | { 27 | foreach (Drawing d in control.Drawings.Children) ChangeDrawingColor(d, brush); 28 | } 29 | 30 | control.Dispatcher.Invoke(() => ChangeSvgViewboxColor(control, (new BrushConverter().ConvertFromString(color) as Brush)!)); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Core/UsageManager.cs: -------------------------------------------------------------------------------- 1 | using GenshinFishingToy.Views; 2 | using System.Threading.Tasks; 3 | 4 | namespace GenshinFishingToy.Core; 5 | 6 | internal static class UsageManager 7 | { 8 | public static async Task ShowUsage() 9 | { 10 | await DialogWindow.ShowMessageContent(Mui("Usage"), new UsageContent()); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/GenshinFishingToy.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WinExe 5 | net48 6 | enable 7 | 11.0 8 | True 9 | true 10 | Resources\favicon.ico 11 | app.manifest 12 | x64 13 | 1.5.0 14 | 1.5.0 15 | $(VersionPrefix)1.5.0 16 | GenshinMatrix 17 | GenshinMatrix 18 | True 19 | 20 | 21 | 22 | 23 | 1701;1702;1998; 24 | $(DefineConstants)TRACE; 25 | 26 | 27 | 28 | 1701;1702;1998; 29 | $(DefineConstants)TRACE; 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | all 49 | compile; runtime; build; native; contentfiles; analyzers; buildtransitive 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/GlobalUsing.cs: -------------------------------------------------------------------------------- 1 | global using static GenshinFishingToy.Core.LanguageManager; 2 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Models/Settings.cs: -------------------------------------------------------------------------------- 1 | using GenshinFishingToy.Core; 2 | using System.Reflection; 3 | 4 | namespace GenshinFishingToy.Models; 5 | 6 | [Obfuscation] 7 | public class Settings 8 | { 9 | public static SettingsDefinition ShortcutKey { get; } = new(nameof(ShortcutKey), "F11"); 10 | public static SettingsDefinition Language { get; } = new(nameof(Language), string.Empty); 11 | public static SettingsDefinition<(int, int, int, int)> JigRect { get; } = new(nameof(JigRect), (100, 100, 450, 100)); 12 | public static SettingsDefinition FullScreenWhenSaved { get; } = new(nameof(FullScreenWhenSaved), false); 13 | public static SettingsDefinition Lock { get; } = new(nameof(Lock), false); 14 | public static SettingsDefinition CaptureType { get; } = new(nameof(CaptureType), "WindowsGraphicsCapture"); 15 | public static SettingsDefinition AutoLifting { get; } = new(nameof(AutoLifting), true); 16 | public static SettingsDefinition ShowRecognitionCapture { get; } = new(nameof(ShowRecognitionCapture), false); 17 | public static SettingsDefinition ShowRecognitionJigging { get; } = new(nameof(ShowRecognitionJigging), false); 18 | public static SettingsDefinition ShowRecognitionLifting { get; } = new(nameof(ShowRecognitionLifting), false); 19 | } 20 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Pack.cs: -------------------------------------------------------------------------------- 1 | using GenshinFishingToy.Core; 2 | using System; 3 | 4 | namespace GenshinFishingToy; 5 | 6 | internal static class Pack 7 | { 8 | public static string Name => "GenshinFishingToy"; 9 | public static string Alias => "genshin-fishing-toy"; 10 | public static string Url => "https://github.com/genshin-matrix/genshin-fishing-toy/releases"; 11 | public static string Version => AssemblyUtils.GetAssemblyVersion(typeof(App).Assembly, prefix: "v"); 12 | 13 | public static string SupportedOSVersion => "Windows 10.0.18362.0"; 14 | public static string CurrentOSVersion => $"Windows {Environment.OSVersion.Version.Major}.{Environment.OSVersion.Version.MajorRevision}.{Environment.OSVersion.Version.Build}.{Environment.OSVersion.Version.Minor}"; 15 | public static bool IsSupported => Environment.OSVersion.Platform == PlatformID.Win32NT && Environment.OSVersion.Version.Major >= 10 && Environment.OSVersion.Version.Build >= 18362; 16 | } 17 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Properties/PublishProfiles/FolderProfile.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | Release 8 | x64 9 | bin\x64\Release\net6.0-windows10.0.18362.0\publish\win-x64\ 10 | FileSystem 11 | <_TargetId>Folder 12 | net6.0-windows10.0.18362.0 13 | true 14 | win-x64 15 | true 16 | false 17 | false 18 | 19 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Resources/Languages/en-us.xaml: -------------------------------------------------------------------------------- 1 |  4 | Genshin 5 | FishingToy 6 | Start 7 | Stop 8 | OK 9 | Usage 10 | 0 11 | Prompt for usage. 12 | Top Most 13 | Exit 14 | Software Updates 15 | Tips 16 | Restore Position 17 | Restart 18 | Launch Game 19 | Language 20 | We only support running on an OS version higher than {0}. Your OS version is {1}. 21 | Auto Lifting 22 | Show captupe recognition (Debug) 23 | Show jigging recognition (Debug) 24 | Show lifting recognition (Debug) 25 | Jigging recognition debug 26 | Lifting recognition debug 27 | Lock fishing region 28 | Reset fishing region 29 | Image Capture Type 30 | BitBlt (Windows 7 and up) 31 | Windows 10 (1903 and up) 32 | Not started 33 | Started 34 | Open Config File 35 | Open Config File (Open with) 36 | Open Config File (Open with Notepad) 37 | Reload Config File 38 | Reload the configuration file. If the configuration format is incorrect, it will be restored to the default value. 39 | Open the loading configuration file, and reload it manually after modification. 40 | [Step] 41 | Tips: Must frame region like it. 42 | 1. First, move the jigging region to select the recognition region, and you also can resize the region. Just frame the fishing progress bar. Don't frame the fishing progress circle below. 43 | 2. After confirming that the region position is correct, you can start auto fishing (Shortcut F11). 44 | After the rod is thrown, just waiting for the fish to hook up. The program will auto control mouse according to the image recognition results and complete the fishing progress. 45 | 46 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Resources/Languages/jp.xaml: -------------------------------------------------------------------------------- 1 |  4 | 原神 5 | 釣り師 6 | スタート 7 | ストップ 8 | OK 9 | 使い方 10 | 0 11 | 使い方を表示。 12 | 最上位に表示 13 | 終了 14 | プログラム更新 15 | ヒント 16 | 右下に戻る 17 | リスタート 18 | ケーム起動 19 | 言語 20 | 本プログラムはOSバージョンが{0}もしくはそれより高いOSバージョンのみサポートしています。あなたのOSバージョンは{1}です。 21 | 自動リフティング 22 | キャプチャ画像を表示(デバッグ) 23 | 釣りの識別を表示(デバッグ) 24 | リフティングの識別を表示(デバッグ) 25 | 釣り識別デバッグ 26 | リフティング識別デバッグ 27 | 釣り枠をロック 28 | 釣り枠をリセット 29 | 画像キャプチャモード 30 | BitBlt (Windows 7 以降) 31 | Windows 10 (1903以降) 32 | スタート待ち 33 | スタート済み 34 | 配置ファイルを開く 35 | 配置ファイルを開く (方法を選択して開く) 36 | 配置ファイルを開く (メモ帳として開く) 37 | 配置ファイルをリロード 38 | 配置ファイルをリロード。もしフォーマットが正しくない場合はデフォルトに戻す。 39 | 配置ファイルをオープン。ファイル変更後は手動でリロードしてください。 40 | 〔ステップ〕 41 | ヒント:必ずこのように釣り枠で囲むこと 42 | 1. まずは半透明長方形の釣り枠を移動して識別区域を囲むこと、釣り枠のサイズは調整できる、釣りのプログレスバーを枠に入れるだけでいいので、下の丸い釣りプログレスを枠に入れないこと。 43 | 2. 釣り枠が正しい位置を囲んだ後、「スタート」してください(ショートカットF11)。 44 | 魚竿を振った後、魚が釣れるのを待つだけ、プログラムは自動的に画像識別に基づいて対応、マウスを任せて釣りを行う。 45 | 46 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Resources/Languages/zh-cn.xaml: -------------------------------------------------------------------------------- 1 |  4 | 原神 5 | 钓鱼姫 6 | 启动 7 | 停止 8 | 好的 9 | 使用方法 10 | 0 11 | 提示使用方法。 12 | 顶层显示 13 | 退出 14 | 程序更新 15 | 提示 16 | 恢复到右下角 17 | 重启 18 | 启动游戏 19 | 语言 20 | 我们仅支持系统版本高于{0}。您的系统版本为{1}。 21 | 自动提竿 22 | 显示采集识别(调试) 23 | 显示饵钓识别(调试) 24 | 显示提竿识别(调试) 25 | 饵钓识别调试 26 | 提竿识别调试 27 | 锁定钓鱼框 28 | 重置钓鱼框 29 | 图像采集模式 30 | BitBlt (Windows 7 或更新版本) 31 | Windows 10 (1903或更新版本) 32 | 未启动 33 | 已启动 34 | 打开配置文件 35 | 打开配置文件 (重设方式打开) 36 | 打开配置文件 (以记事本方式打开) 37 | 重载配置文件 38 | 重新加载配置文件,若配置格式不正确则会恢复为默认值。 39 | 打开加载配置文件,修改后请手动重新加载。 40 | 〔使用步骤〕 41 | 友情提示:一定要像这样框钓鱼区 42 | 1. 首先移动半透明矩形选区选择识别范围,钓鱼框可调整大小,只需要框住钓鱼进度条就可以了,不要框住下方的钓鱼总进度圈。 43 | 2. 确认选框位置正确后,就直接启动进行自动钓鱼啦(快捷键F11)。 44 | 甩竿后直接等待鱼儿上钩即可,保持当前原神窗口是激活状态,程序会自动根据当前图像识别的结果发送对应鼠标操作,自动化提竿、完成钓鱼进度。 45 | 46 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Resources/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToy/Resources/demo.gif -------------------------------------------------------------------------------- /src/GenshinFishingToy/Resources/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToy/Resources/demo.png -------------------------------------------------------------------------------- /src/GenshinFishingToy/Resources/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToy/Resources/favicon.ico -------------------------------------------------------------------------------- /src/GenshinFishingToy/Resources/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToy/Resources/favicon.png -------------------------------------------------------------------------------- /src/GenshinFishingToy/Resources/hydro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToy/Resources/hydro.png -------------------------------------------------------------------------------- /src/GenshinFishingToy/Resources/hydro.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Resources/segoe-fluent-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToy/Resources/segoe-fluent-icons.ttf -------------------------------------------------------------------------------- /src/GenshinFishingToy/Resources/squircle.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/ViewModels/NotifyIconViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | using CommunityToolkit.Mvvm.Input; 3 | using GenshinFishingToy.Core; 4 | using GenshinFishingToy.Models; 5 | using Microsoft.Toolkit.Uwp.Notifications; 6 | using System.Collections.Generic; 7 | using System.Diagnostics; 8 | using System.Windows; 9 | using System.Windows.Input; 10 | 11 | namespace GenshinFishingToy.ViewModels 12 | { 13 | public class NotifyIconViewModel : ObservableRecipient 14 | { 15 | public static ICommand ShowOrHideCommand => new RelayCommand(() => 16 | { 17 | if (Application.Current.MainWindow.Visibility == Visibility.Visible) 18 | { 19 | Application.Current.MainWindow.Hide(); 20 | } 21 | else 22 | { 23 | Application.Current.MainWindow.Activate(); 24 | Application.Current.MainWindow.Focus(); 25 | Application.Current.MainWindow.Show(); 26 | } 27 | }); 28 | 29 | public static ICommand RestartCommand => new RelayCommand(() => App.RestartAsElevated()); 30 | public static ICommand ExitCommand => new RelayCommand(() => Application.Current.Shutdown()); 31 | public static ICommand UsageCommand => new RelayCommand(() => _ = UsageManager.ShowUsage()); 32 | 33 | public static ICommand GitHubCommand => new RelayCommand(async app => 34 | { 35 | try 36 | { 37 | _ = Process.Start("explorer.exe", Pack.Url); 38 | } 39 | catch 40 | { 41 | } 42 | }); 43 | 44 | public static ICommand LaunchGameCommand => new RelayCommand(async app => _ = await LaunchCtrl.Launch()); 45 | 46 | public string Language 47 | { 48 | get => Settings.Language.Get(); 49 | set 50 | { 51 | if (string.IsNullOrEmpty(value)) return; 52 | string prev = Language; 53 | Settings.Language.Set(value); 54 | Broadcast(prev, value, nameof(Language)); 55 | SettingsManager.Save(); 56 | } 57 | } 58 | public static ICommand LanguageZH => new RelayCommand(async app => SetLanguagePrivate("zh-cn")); 59 | public static ICommand LanguageJP => new RelayCommand(async app => SetLanguagePrivate("jp")); 60 | public static ICommand LanguageEN => new RelayCommand(async app => SetLanguagePrivate("en-us")); 61 | 62 | private static void SetLanguagePrivate(string name) 63 | { 64 | SetLanguage(name); 65 | Settings.Language.Set(name); 66 | SettingsManager.Save(); 67 | } 68 | 69 | public static void OnNotificationActivated(ToastNotificationActivatedEventArgsCompat e) 70 | { 71 | ToastArguments args = ToastArguments.Parse(e.Argument); 72 | 73 | foreach (KeyValuePair arg in args) 74 | { 75 | (string k, string v) = (arg.Key, arg.Value); 76 | 77 | if (k == "" && v == "") 78 | { 79 | } 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Views/Behaviors/LeftContextMenuBehavior.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xaml.Behaviors; 2 | using System.Windows; 3 | using System.Windows.Controls; 4 | using System.Windows.Controls.Primitives; 5 | 6 | namespace GenshinFishingToy.Views; 7 | 8 | public class LeftContextMenuBehavior : Behavior 9 | { 10 | public Point? PlacementOffset { get; set; } = null; 11 | public PlacementMode Placement { get; set; } = PlacementMode.Bottom; 12 | 13 | public double? PlacementOffsetX 14 | { 15 | get => PlacementOffset?.X; 16 | set => PlacementOffset = value != null ? new(value ?? 0d, PlacementOffset?.Y ?? 0d) : null; 17 | } 18 | 19 | public double? PlacementOffsetY 20 | { 21 | get => PlacementOffset?.Y; 22 | set => PlacementOffset = value != null ? new(PlacementOffset?.X ?? 0d, value ?? 0d) : null; 23 | } 24 | 25 | public LeftContextMenuBehavior() 26 | { 27 | } 28 | 29 | protected override void OnAttached() 30 | { 31 | base.OnAttached(); 32 | Register(AssociatedObject, PlacementOffset, Placement); 33 | } 34 | 35 | protected override void OnDetaching() 36 | { 37 | base.OnDetaching(); 38 | } 39 | 40 | private void Register(FrameworkElement frameworkElement, Point? placementOffset = null, PlacementMode placement = PlacementMode.Bottom) 41 | { 42 | if (frameworkElement?.ContextMenu == null) 43 | { 44 | return; 45 | } 46 | frameworkElement.PreviewMouseRightButtonUp += (s, e) => e.Handled = true; 47 | frameworkElement.MouseRightButtonUp += (s, e) => e.Handled = true; 48 | frameworkElement.PreviewMouseLeftButtonDown += (s, e) => 49 | { 50 | ContextMenu contextMenu = frameworkElement.ContextMenu; 51 | 52 | if (contextMenu != null) 53 | { 54 | if (contextMenu.PlacementTarget != frameworkElement) 55 | { 56 | contextMenu.PlacementTarget = frameworkElement; 57 | contextMenu.PlacementRectangle = new Rect(placementOffset ?? new Point(), new Size(frameworkElement.ActualWidth, frameworkElement.ActualHeight)); 58 | contextMenu.Placement = placement; 59 | contextMenu.StaysOpen = false; 60 | } 61 | contextMenu.IsOpen = !contextMenu.IsOpen; 62 | } 63 | }; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Views/Behaviors/ToolWindowBehavior.cs: -------------------------------------------------------------------------------- 1 | using GenshinFishingToy.Core; 2 | using Microsoft.Xaml.Behaviors; 3 | using System; 4 | using System.Windows; 5 | using System.Windows.Interop; 6 | 7 | namespace GenshinFishingToy.Views; 8 | 9 | public class ToolWindowBehavior : Behavior 10 | { 11 | protected override void OnAttached() 12 | { 13 | AssociatedObject.Loaded += Loaded; 14 | base.OnAttached(); 15 | } 16 | 17 | protected override void OnDetaching() 18 | { 19 | AssociatedObject.Loaded -= Loaded; 20 | base.OnDetaching(); 21 | } 22 | 23 | private void Loaded(object sender, EventArgs e) 24 | { 25 | NativeMethods.SetToolWindow(new WindowInteropHelper(AssociatedObject).Handle); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Views/Behaviors/UIElementDragMoveBehavior.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xaml.Behaviors; 2 | using System; 3 | using System.Windows; 4 | 5 | namespace GenshinFishingToy.Views; 6 | 7 | public class UIElementDragMoveBehavior : Behavior 8 | { 9 | protected override void OnAttached() 10 | { 11 | AssociatedObject.MouseLeftButtonDown += MouseLeftButtonDown; 12 | base.OnAttached(); 13 | } 14 | 15 | protected override void OnDetaching() 16 | { 17 | AssociatedObject.MouseLeftButtonDown -= MouseLeftButtonDown; 18 | base.OnDetaching(); 19 | } 20 | 21 | private void MouseLeftButtonDown(object sender, EventArgs e) 22 | { 23 | Window.GetWindow(sender as UIElement)?.DragMove(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Views/Converters/AddConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Windows.Data; 4 | using Converts = System.Convert; 5 | 6 | namespace GenshinFishingToy.Views; 7 | 8 | internal class AddConverter : IValueConverter 9 | { 10 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 11 | { 12 | if (value is double d) 13 | { 14 | try 15 | { 16 | double p = Converts.ToDouble(parameter); 17 | return d + p; 18 | } 19 | catch 20 | { 21 | } 22 | } 23 | return value; 24 | } 25 | 26 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 27 | { 28 | throw new NotImplementedException(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Views/Converters/LanguageToBoolConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Data; 3 | 4 | namespace GenshinFishingToy.Views; 5 | 6 | public class LanguageToBoolConverter : IValueConverter 7 | { 8 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 9 | { 10 | if (value is string lang) 11 | { 12 | return lang == parameter as string; 13 | } 14 | return value; 15 | } 16 | 17 | public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 18 | { 19 | bool isChecked = (bool)value; 20 | 21 | if (!isChecked) 22 | { 23 | return string.Empty; 24 | } 25 | return (parameter as string) ?? string.Empty; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Views/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using GenshinFishingToy.ViewModels; 2 | using System; 3 | using System.Windows; 4 | 5 | namespace GenshinFishingToy.Views; 6 | 7 | public partial class MainWindow : Window 8 | { 9 | public MainViewModel ViewModel { get; } 10 | 11 | public MainWindow() 12 | { 13 | DataContext = ViewModel = new(this); 14 | InitializeComponent(); 15 | } 16 | 17 | private void MainWindowClosed(object? sender, EventArgs e) 18 | { 19 | Application.Current.Shutdown(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Views/MotionAreaWindow.xaml: -------------------------------------------------------------------------------- 1 |  12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 28 | 29 | 30 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Views/PreviewForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace GenshinFishingToy.Views 2 | { 3 | partial class Preview 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.pictureBox1 = new System.Windows.Forms.PictureBox(); 32 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); 33 | this.SuspendLayout(); 34 | // 35 | // pictureBox1 36 | // 37 | this.pictureBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 38 | | System.Windows.Forms.AnchorStyles.Left) 39 | | System.Windows.Forms.AnchorStyles.Right))); 40 | this.pictureBox1.BackColor = System.Drawing.Color.White; 41 | this.pictureBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; 42 | this.pictureBox1.Location = new System.Drawing.Point(0, 0); 43 | this.pictureBox1.Name = "pictureBox1"; 44 | this.pictureBox1.Size = new System.Drawing.Size(564, 200); 45 | this.pictureBox1.TabIndex = 2; 46 | this.pictureBox1.TabStop = false; 47 | // 48 | // Preview 49 | // 50 | this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); 51 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; 52 | this.ClientSize = new System.Drawing.Size(564, 200); 53 | this.Controls.Add(this.pictureBox1); 54 | this.Name = "Preview"; 55 | this.Text = "Preview"; 56 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); 57 | this.ResumeLayout(false); 58 | 59 | } 60 | 61 | #endregion 62 | private System.Windows.Forms.PictureBox pictureBox1; 63 | } 64 | } -------------------------------------------------------------------------------- /src/GenshinFishingToy/Views/PreviewForm.cs: -------------------------------------------------------------------------------- 1 | using GenshinFishingToy.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.Data; 6 | using System.Drawing; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Security.Policy; 10 | using System.Text; 11 | using System.Threading.Tasks; 12 | using System.Windows.Forms; 13 | using System.Windows.Resources; 14 | 15 | namespace GenshinFishingToy.Views; 16 | 17 | public partial class Preview : Form 18 | { 19 | public Preview() 20 | { 21 | InitializeComponent(); 22 | 23 | using Stream stream = ResourceUtils.GetStream("pack://application:,,,/GenshinFishingToy;component/Resources/favicon.ico"); 24 | Icon = new Icon(stream); 25 | } 26 | 27 | public void SetImage(Bitmap bitmap) 28 | { 29 | try 30 | { 31 | pictureBox1.Image = bitmap?.Clone() as Bitmap; 32 | } 33 | catch 34 | { 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Views/UIElement/DialogWindow.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Views/UIElement/DialogWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using ModernWpf.Controls; 2 | using System; 3 | using System.Threading.Tasks; 4 | using System.Windows; 5 | 6 | namespace GenshinFishingToy.Views; 7 | 8 | public partial class DialogWindow : Window, IDisposable 9 | { 10 | public DialogWindow() 11 | { 12 | InitializeComponent(); 13 | } 14 | 15 | public void Dispose() 16 | { 17 | Close(); 18 | } 19 | 20 | public static async Task ShowMessage(string title, string message) 21 | { 22 | using DialogWindow win = new() 23 | { 24 | Width = SystemParameters.WorkArea.Width, 25 | Height = SystemParameters.WorkArea.Height, 26 | }; 27 | win.Show(); 28 | MessageDialog dialog = new(title, message); 29 | await dialog.ShowAsync(ContentDialogPlacement.Popup); 30 | } 31 | 32 | public static async Task ShowMessageContent(string title, object messageContent) 33 | { 34 | using DialogWindow win = new() 35 | { 36 | Width = SystemParameters.WorkArea.Width, 37 | Height = SystemParameters.WorkArea.Height, 38 | }; 39 | win.Show(); 40 | MessageDialog dialog = new(title, string.Empty, messageContent); 41 | await dialog.ShowAsync(ContentDialogPlacement.Popup); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Views/UIElement/MessageDialog.xaml: -------------------------------------------------------------------------------- 1 |  11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Views/UIElement/MessageDialog.xaml.cs: -------------------------------------------------------------------------------- 1 | using ModernWpf.Controls; 2 | using System.Windows; 3 | 4 | namespace GenshinFishingToy.Views; 5 | 6 | public partial class MessageDialog : ContentDialog 7 | { 8 | public string Message 9 | { 10 | get => (string)GetValue(MessageProperty); 11 | set => SetValue(MessageProperty, value); 12 | } 13 | public static readonly DependencyProperty MessageProperty = DependencyProperty.Register("Message", typeof(string), typeof(MessageDialog), new PropertyMetadata(null!)); 14 | 15 | public object MessageContent 16 | { 17 | get => GetValue(MessageContentProperty); 18 | set => SetValue(MessageContentProperty, value); 19 | } 20 | public static readonly DependencyProperty MessageContentProperty = DependencyProperty.Register("MessageContent", typeof(object), typeof(MessageDialog), new PropertyMetadata(null!)); 21 | 22 | public MessageDialog(string title, string message, object? messageContent = null) 23 | { 24 | Message = message; 25 | MessageContent = messageContent!; 26 | DataContext = this; 27 | InitializeComponent(); 28 | Title = title; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Views/UIElement/ObservableWindow.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Runtime.CompilerServices; 3 | using System.Windows; 4 | 5 | namespace GenshinFishingToy.Views; 6 | 7 | public class ObservableWindow : Window 8 | { 9 | public event PropertyChangedEventHandler? PropertyChanged; 10 | 11 | protected virtual void RaisePropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new(propertyName)); 12 | 13 | protected void Set(ref T field, T newValue, [CallerMemberName] string? propertyName = null) 14 | { 15 | field = newValue; 16 | RaisePropertyChanged(propertyName!); 17 | } 18 | 19 | protected void Set2(ref T field, T newValue, [CallerMemberName] string? propertyName = null) 20 | { 21 | if (!Equals(field, newValue)) 22 | { 23 | field = newValue; 24 | RaisePropertyChanged(propertyName!); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Views/UsageContent.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/Views/UsageContent.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | 3 | namespace GenshinFishingToy.Views 4 | { 5 | public partial class UsageContent : UserControl 6 | { 7 | public UsageContent() 8 | { 9 | InitializeComponent(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/GenshinFishingToy/app.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 54 | 62 | 63 | 64 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/.gitignore: -------------------------------------------------------------------------------- 1 | .vs/* 2 | [Bb]in/ 3 | [Oo]bj/ 4 | AppPackages/* 5 | BundleArtifacts/* 6 | *.user 7 | -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/GenshinFishingToySetup.assets.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/GenshinFishingToySetup.assets.cache -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/GenshinFishingToySetup.wapproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15.0 5 | 6 | 7 | 8 | Debug 9 | x64 10 | 11 | 12 | Release 13 | x64 14 | 15 | 16 | 17 | $(MSBuildExtensionsPath)\Microsoft\DesktopBridge\ 18 | 19 | 20 | 21 | a80a34dd-acbc-4d67-a22d-156a0ffc32a8 22 | 10.0.22621.0 23 | 10.0.18362.0 24 | en-US 25 | True 26 | $(NoWarn);NU1702 27 | ..\GenshinFishingToy\GenshinFishingToy.csproj 28 | False 29 | BDA5C28BFBF227F59EB447A926319726B1F0FD5B 30 | SHA256 31 | False 32 | False 33 | True 34 | x64 35 | 0 36 | 37 | 38 | Always 39 | 40 | 41 | Always 42 | 43 | 44 | 45 | Designer 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/GenshinFishingToySetup_TemporaryKey.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/GenshinFishingToySetup_TemporaryKey.pfx -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/BadgeLogo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/BadgeLogo.scale-100.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/BadgeLogo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/BadgeLogo.scale-125.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/BadgeLogo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/BadgeLogo.scale-150.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/BadgeLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/BadgeLogo.scale-200.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/BadgeLogo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/BadgeLogo.scale-400.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/LargeTile.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/LargeTile.scale-100.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/LargeTile.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/LargeTile.scale-125.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/LargeTile.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/LargeTile.scale-150.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/LargeTile.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/LargeTile.scale-200.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/LargeTile.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/LargeTile.scale-400.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/SmallTile.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/SmallTile.scale-100.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/SmallTile.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/SmallTile.scale-125.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/SmallTile.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/SmallTile.scale-150.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/SmallTile.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/SmallTile.scale-200.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/SmallTile.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/SmallTile.scale-400.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/SplashScreen.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/SplashScreen.scale-100.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/SplashScreen.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/SplashScreen.scale-125.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/SplashScreen.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/SplashScreen.scale-150.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/SplashScreen.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/SplashScreen.scale-400.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square150x150Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square150x150Logo.scale-100.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square150x150Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square150x150Logo.scale-125.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square150x150Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square150x150Logo.scale-150.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square150x150Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square150x150Logo.scale-400.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square44x44Logo.altform-lightunplated_targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square44x44Logo.altform-lightunplated_targetsize-16.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square44x44Logo.altform-lightunplated_targetsize-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square44x44Logo.altform-lightunplated_targetsize-24.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square44x44Logo.altform-lightunplated_targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square44x44Logo.altform-lightunplated_targetsize-256.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square44x44Logo.altform-lightunplated_targetsize-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square44x44Logo.altform-lightunplated_targetsize-32.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square44x44Logo.altform-lightunplated_targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square44x44Logo.altform-lightunplated_targetsize-48.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square44x44Logo.altform-unplated_targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square44x44Logo.altform-unplated_targetsize-16.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square44x44Logo.altform-unplated_targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square44x44Logo.altform-unplated_targetsize-256.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square44x44Logo.altform-unplated_targetsize-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square44x44Logo.altform-unplated_targetsize-32.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square44x44Logo.altform-unplated_targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square44x44Logo.altform-unplated_targetsize-48.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square44x44Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square44x44Logo.scale-100.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square44x44Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square44x44Logo.scale-125.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square44x44Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square44x44Logo.scale-150.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square44x44Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square44x44Logo.scale-400.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square44x44Logo.targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square44x44Logo.targetsize-16.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square44x44Logo.targetsize-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square44x44Logo.targetsize-24.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square44x44Logo.targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square44x44Logo.targetsize-256.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square44x44Logo.targetsize-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square44x44Logo.targetsize-32.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Square44x44Logo.targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Square44x44Logo.targetsize-48.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/StoreLogo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/StoreLogo.scale-100.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/StoreLogo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/StoreLogo.scale-125.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/StoreLogo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/StoreLogo.scale-150.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/StoreLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/StoreLogo.scale-200.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/StoreLogo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/StoreLogo.scale-400.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Wide310x150Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Wide310x150Logo.scale-100.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Wide310x150Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Wide310x150Logo.scale-125.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Wide310x150Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Wide310x150Logo.scale-150.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Images/Wide310x150Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GenshinMatrix/genshin-fishing-toy/ccb0fc8a1171eaa6ef4a134984c0482725835f2b/src/GenshinFishingToySetup/Images/Wide310x150Logo.scale-400.png -------------------------------------------------------------------------------- /src/GenshinFishingToySetup/Package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 9 | 10 | 14 | 15 | 16 | GenshinFishingToy 17 | ema 18 | Images\StoreLogo.png 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/WindowsGraphicsCapture/.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 | -------------------------------------------------------------------------------- /src/WindowsGraphicsCapture/.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 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 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 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /src/WindowsGraphicsCapture/CaptureSampleCore/BasicSampleApplication.cs: -------------------------------------------------------------------------------- 1 | // --------------------------------------------------------------------------------- 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // --------------------------------------------------------------------------------- 24 | 25 | using Composition.WindowsRuntimeHelpers; 26 | using System; 27 | using System.Numerics; 28 | using System.Text.RegularExpressions; 29 | using Windows.Graphics.Capture; 30 | using Windows.Graphics.DirectX.Direct3D11; 31 | using Windows.UI.Composition; 32 | 33 | namespace CaptureSampleCore 34 | { 35 | public class BasicSampleApplication : IDisposable 36 | { 37 | public BasicCapture Capture => capture; 38 | 39 | private Compositor compositor; 40 | private ContainerVisual root; 41 | 42 | private SpriteVisual content; 43 | private CompositionSurfaceBrush brush; 44 | 45 | private IDirect3DDevice device; 46 | private BasicCapture capture; 47 | 48 | public BasicSampleApplication(Compositor c) 49 | { 50 | compositor = c; 51 | device = Direct3D11Helper.CreateDevice(); 52 | 53 | // Setup the root. 54 | root = compositor.CreateContainerVisual(); 55 | root.RelativeSizeAdjustment = Vector2.One; 56 | 57 | // Setup the content. 58 | brush = compositor.CreateSurfaceBrush(); 59 | brush.HorizontalAlignmentRatio = 0.5f; 60 | brush.VerticalAlignmentRatio = 0.5f; 61 | brush.Stretch = CompositionStretch.Uniform; 62 | 63 | var shadow = compositor.CreateDropShadow(); 64 | shadow.Mask = brush; 65 | 66 | content = compositor.CreateSpriteVisual(); 67 | content.AnchorPoint = new Vector2(0.5f); 68 | content.RelativeOffsetAdjustment = new Vector3(0.5f, 0.5f, 0); 69 | content.RelativeSizeAdjustment = Vector2.One; 70 | content.Size = new Vector2(-80, -80); 71 | content.Brush = brush; 72 | content.Shadow = shadow; 73 | root.Children.InsertAtTop(content); 74 | } 75 | 76 | public Visual Visual => root; 77 | 78 | public void Dispose() 79 | { 80 | StopCapture(); 81 | compositor = null; 82 | root.Dispose(); 83 | content.Dispose(); 84 | brush.Dispose(); 85 | device.Dispose(); 86 | } 87 | 88 | public void StartCaptureFromItem(GraphicsCaptureItem item) 89 | { 90 | StopCapture(); 91 | capture = new BasicCapture(device, item); 92 | 93 | var surface = capture.CreateSurface(compositor); 94 | brush.Surface = surface; 95 | 96 | capture.StartCapture(); 97 | } 98 | 99 | public void StopCapture() 100 | { 101 | capture?.Dispose(); 102 | capture = null!; 103 | brush.Surface = null; 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/WindowsGraphicsCapture/CaptureSampleCore/CaptureSampleCore.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 11.0 6 | x64 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/WindowsGraphicsCapture/Composition.WindowsRuntimeHelpers/CaptureHelper.cs: -------------------------------------------------------------------------------- 1 | // --------------------------------------------------------------------------------- 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // --------------------------------------------------------------------------------- 24 | 25 | using System; 26 | using System.Runtime.InteropServices; 27 | using System.Runtime.InteropServices.WindowsRuntime; 28 | using Windows.Graphics.Capture; 29 | 30 | namespace Composition.WindowsRuntimeHelpers 31 | { 32 | public static class CaptureHelper 33 | { 34 | static readonly Guid GraphicsCaptureItemGuid = new Guid("79C3F95B-31F7-4EC2-A464-632EF5D30760"); 35 | 36 | [ComImport] 37 | [Guid("3E68D4BD-7135-4D10-8018-9FB6D9F33FA1")] 38 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 39 | [ComVisible(true)] 40 | interface IInitializeWithWindow 41 | { 42 | void Initialize( 43 | IntPtr hwnd); 44 | } 45 | 46 | [ComImport] 47 | [Guid("3628E81B-3CAC-4C60-B7F4-23CE0E0C3356")] 48 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 49 | [ComVisible(true)] 50 | interface IGraphicsCaptureItemInterop 51 | { 52 | IntPtr CreateForWindow( 53 | [In] IntPtr window, 54 | [In] ref Guid iid); 55 | 56 | IntPtr CreateForMonitor( 57 | [In] IntPtr monitor, 58 | [In] ref Guid iid); 59 | } 60 | 61 | public static void SetWindow(this GraphicsCapturePicker picker, IntPtr hwnd) 62 | { 63 | var interop = (IInitializeWithWindow)(object)picker; 64 | interop.Initialize(hwnd); 65 | } 66 | 67 | public static GraphicsCaptureItem CreateItemForWindow(IntPtr hwnd) 68 | { 69 | var factory = WindowsRuntimeMarshal.GetActivationFactory(typeof(GraphicsCaptureItem)); 70 | var interop = (IGraphicsCaptureItemInterop)factory; 71 | var temp = typeof(GraphicsCaptureItem); 72 | var itemPointer = interop.CreateForWindow(hwnd, GraphicsCaptureItemGuid); 73 | var item = Marshal.GetObjectForIUnknown(itemPointer) as GraphicsCaptureItem; 74 | Marshal.Release(itemPointer); 75 | 76 | return item; 77 | } 78 | 79 | public static GraphicsCaptureItem CreateItemForMonitor(IntPtr hmon) 80 | { 81 | var factory = WindowsRuntimeMarshal.GetActivationFactory(typeof(GraphicsCaptureItem)); 82 | var interop = (IGraphicsCaptureItemInterop)factory; 83 | var temp = typeof(GraphicsCaptureItem); 84 | var itemPointer = interop.CreateForMonitor(hmon, GraphicsCaptureItemGuid); 85 | var item = Marshal.GetObjectForIUnknown(itemPointer) as GraphicsCaptureItem; 86 | Marshal.Release(itemPointer); 87 | 88 | return item; 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/WindowsGraphicsCapture/Composition.WindowsRuntimeHelpers/Composition.WindowsRuntimeHelpers.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 11.0 6 | x64 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/WindowsGraphicsCapture/Composition.WindowsRuntimeHelpers/CompositionHelper.cs: -------------------------------------------------------------------------------- 1 | // --------------------------------------------------------------------------------- 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // --------------------------------------------------------------------------------- 24 | 25 | using System; 26 | using System.Runtime.InteropServices; 27 | using Windows.UI.Composition; 28 | 29 | namespace Composition.WindowsRuntimeHelpers 30 | { 31 | public static class CompositionHelper 32 | { 33 | [ComImport] 34 | [Guid("25297D5C-3AD4-4C9C-B5CF-E36A38512330")] 35 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 36 | [ComVisible(true)] 37 | interface ICompositorInterop 38 | { 39 | ICompositionSurface CreateCompositionSurfaceForHandle( 40 | IntPtr swapChain); 41 | 42 | ICompositionSurface CreateCompositionSurfaceForSwapChain( 43 | IntPtr swapChain); 44 | 45 | CompositionGraphicsDevice CreateGraphicsDevice( 46 | IntPtr renderingDevice); 47 | } 48 | 49 | [ComImport] 50 | [Guid("29E691FA-4567-4DCA-B319-D0F207EB6807")] 51 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 52 | [ComVisible(true)] 53 | interface ICompositorDesktopInterop 54 | { 55 | Windows.UI.Composition.Desktop.DesktopWindowTarget CreateDesktopWindowTarget( 56 | IntPtr hwnd, 57 | bool isTopmost); 58 | } 59 | 60 | public static CompositionTarget CreateDesktopWindowTarget(this Compositor compositor, IntPtr hwnd, bool isTopmost) 61 | { 62 | var desktopInterop = (ICompositorDesktopInterop)((object)compositor); 63 | return desktopInterop.CreateDesktopWindowTarget(hwnd, isTopmost); 64 | } 65 | 66 | public static ICompositionSurface CreateCompositionSurfaceForSwapChain(this Compositor compositor, SharpDX.DXGI.SwapChain1 swapChain) 67 | { 68 | var interop = (ICompositorInterop)(object)compositor; 69 | return interop.CreateCompositionSurfaceForSwapChain(swapChain.NativePointer); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/WindowsGraphicsCapture/Composition.WindowsRuntimeHelpers/CoreMessagingHelper.cs: -------------------------------------------------------------------------------- 1 | // --------------------------------------------------------------------------------- 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // --------------------------------------------------------------------------------- 24 | 25 | using System; 26 | using System.Runtime.InteropServices; 27 | using Windows.System; 28 | 29 | namespace Composition.WindowsRuntimeHelpers 30 | { 31 | public static class CoreMessagingHelper 32 | { 33 | enum DISPATCHERQUEUE_THREAD_APARTMENTTYPE 34 | { 35 | DQTAT_COM_NONE = 0, 36 | DQTAT_COM_ASTA = 1, 37 | DQTAT_COM_STA = 2 38 | } 39 | 40 | enum DISPATCHERQUEUE_THREAD_TYPE 41 | { 42 | DQTYPE_THREAD_DEDICATED = 1, 43 | DQTYPE_THREAD_CURRENT = 2 44 | } 45 | 46 | struct DispatcherQueueOptions 47 | { 48 | public int dwSize; 49 | public DISPATCHERQUEUE_THREAD_TYPE threadType; 50 | public DISPATCHERQUEUE_THREAD_APARTMENTTYPE apartmentType; 51 | } 52 | 53 | [DllImport( 54 | "CoreMessaging.dll", 55 | EntryPoint = "CreateDispatcherQueueController", 56 | SetLastError = true, 57 | CharSet = CharSet.Unicode, 58 | ExactSpelling = true, 59 | CallingConvention = CallingConvention.StdCall 60 | )] 61 | static extern UInt32 CreateDispatcherQueueController(DispatcherQueueOptions options, out IntPtr dispatcherQueueController); 62 | 63 | public static DispatcherQueueController CreateDispatcherQueueControllerForCurrentThread() 64 | { 65 | var options = new DispatcherQueueOptions 66 | { 67 | dwSize = Marshal.SizeOf(), 68 | threadType = DISPATCHERQUEUE_THREAD_TYPE.DQTYPE_THREAD_CURRENT, 69 | apartmentType = DISPATCHERQUEUE_THREAD_APARTMENTTYPE.DQTAT_COM_NONE 70 | }; 71 | 72 | DispatcherQueueController controller = null; 73 | uint hr = CreateDispatcherQueueController(options, out IntPtr controllerPointer); 74 | if (hr == 0) 75 | { 76 | controller = Marshal.GetObjectForIUnknown(controllerPointer) as DispatcherQueueController; 77 | Marshal.Release(controllerPointer); 78 | } 79 | 80 | return controller; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/WindowsGraphicsCapture/Composition.WindowsRuntimeHelpers/Direct3D11Helper.cs: -------------------------------------------------------------------------------- 1 | // --------------------------------------------------------------------------------- 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // --------------------------------------------------------------------------------- 24 | 25 | using System; 26 | using System.Runtime.InteropServices; 27 | using Windows.Graphics.DirectX.Direct3D11; 28 | 29 | namespace Composition.WindowsRuntimeHelpers 30 | { 31 | public static class Direct3D11Helper 32 | { 33 | static Guid IInspectable = new Guid("AF86E2E0-B12D-4c6a-9C5A-D7AA65101E90"); 34 | static Guid ID3D11Resource = new Guid("dc8e63f3-d12b-4952-b47b-5e45026a862d"); 35 | static Guid IDXGIAdapter3 = new Guid("645967A4-1392-4310-A798-8053CE3E93FD"); 36 | static Guid ID3D11Device = new Guid("db6f6ddb-ac77-4e88-8253-819df9bbf140"); 37 | static Guid ID3D11Texture2D = new Guid("6f15aaf2-d208-4e89-9ab4-489535d34f9c"); 38 | 39 | [ComImport] 40 | [Guid("A9B3D012-3DF2-4EE3-B8D1-8695F457D3C1")] 41 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 42 | [ComVisible(true)] 43 | interface IDirect3DDxgiInterfaceAccess 44 | { 45 | IntPtr GetInterface([In] ref Guid iid); 46 | }; 47 | 48 | [DllImport( 49 | "d3d11.dll", 50 | EntryPoint = "CreateDirect3D11DeviceFromDXGIDevice", 51 | SetLastError = true, 52 | CharSet = CharSet.Unicode, 53 | ExactSpelling = true, 54 | CallingConvention = CallingConvention.StdCall 55 | )] 56 | static extern UInt32 CreateDirect3D11DeviceFromDXGIDevice(IntPtr dxgiDevice, out IntPtr graphicsDevice); 57 | 58 | [DllImport( 59 | "d3d11.dll", 60 | EntryPoint = "CreateDirect3D11SurfaceFromDXGISurface", 61 | SetLastError = true, 62 | CharSet = CharSet.Unicode, 63 | ExactSpelling = true, 64 | CallingConvention = CallingConvention.StdCall 65 | )] 66 | static extern UInt32 CreateDirect3D11SurfaceFromDXGISurface(IntPtr dxgiSurface, out IntPtr graphicsSurface); 67 | 68 | public static IDirect3DDevice CreateDevice() 69 | { 70 | return CreateDevice(false); 71 | } 72 | 73 | public static IDirect3DDevice CreateDevice(bool useWARP) 74 | { 75 | var d3dDevice = new SharpDX.Direct3D11.Device( 76 | useWARP ? SharpDX.Direct3D.DriverType.Software : SharpDX.Direct3D.DriverType.Hardware, 77 | SharpDX.Direct3D11.DeviceCreationFlags.BgraSupport); 78 | var device = CreateDirect3DDeviceFromSharpDXDevice(d3dDevice); 79 | return device; 80 | } 81 | 82 | public static IDirect3DDevice CreateDirect3DDeviceFromSharpDXDevice(SharpDX.Direct3D11.Device d3dDevice) 83 | { 84 | IDirect3DDevice device = null; 85 | 86 | // Acquire the DXGI interface for the Direct3D device. 87 | using (var dxgiDevice = d3dDevice.QueryInterface()) 88 | { 89 | // Wrap the native device using a WinRT interop object. 90 | uint hr = CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice.NativePointer, out IntPtr pUnknown); 91 | 92 | if (hr == 0) 93 | { 94 | device = Marshal.GetObjectForIUnknown(pUnknown) as IDirect3DDevice; 95 | Marshal.Release(pUnknown); 96 | } 97 | } 98 | 99 | return device; 100 | } 101 | 102 | public static IDirect3DSurface CreateDirect3DSurfaceFromSharpDXTexture(SharpDX.Direct3D11.Texture2D texture) 103 | { 104 | IDirect3DSurface surface = null; 105 | 106 | // Acquire the DXGI interface for the Direct3D surface. 107 | using (var dxgiSurface = texture.QueryInterface()) 108 | { 109 | // Wrap the native device using a WinRT interop object. 110 | uint hr = CreateDirect3D11SurfaceFromDXGISurface(dxgiSurface.NativePointer, out IntPtr pUnknown); 111 | 112 | if (hr == 0) 113 | { 114 | surface = Marshal.GetObjectForIUnknown(pUnknown) as IDirect3DSurface; 115 | Marshal.Release(pUnknown); 116 | } 117 | } 118 | 119 | return surface; 120 | } 121 | 122 | public static SharpDX.Direct3D11.Device CreateSharpDXDevice(IDirect3DDevice device) 123 | { 124 | var access = (IDirect3DDxgiInterfaceAccess)device; 125 | var d3dPointer = access.GetInterface(ID3D11Device); 126 | var d3dDevice = new SharpDX.Direct3D11.Device(d3dPointer); 127 | return d3dDevice; 128 | } 129 | 130 | public static SharpDX.Direct3D11.Texture2D CreateSharpDXTexture2D(IDirect3DSurface surface) 131 | { 132 | var access = (IDirect3DDxgiInterfaceAccess)surface; 133 | var d3dPointer = access.GetInterface(ID3D11Texture2D); 134 | var d3dSurface = new SharpDX.Direct3D11.Texture2D(d3dPointer); 135 | return d3dSurface; 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/WindowsGraphicsCapture/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Robert Mikhayelyan 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 | -------------------------------------------------------------------------------- /src/WindowsGraphicsCapture/README.md: -------------------------------------------------------------------------------- 1 | # WPF Screen Capture 2 | 3 | This sample demonstrates how to use [Windows.Graphics.Capture](https://docs.microsoft.com/uwp/api/windows.graphics.capture) APIs for displays and windows in a WPF app. It also shows how to launch the system picker, which can manage window enumeration and capture selection for you. 4 | 5 | ![Capture Selection](Images/WPFCapture.png) 6 | 7 | > NOTE: Minimized windows are enumerated but not captured. 8 | 9 | ## Run the sample 10 | 11 | - Visual Studio 2017 or later - [Get a free copy of Visual Studio](http://go.microsoft.com/fwlink/?LinkID=280676) 12 | - .NET Framework 4.7.2 or later 13 | - Windows 10 version 1903 or later 14 | - Windows 10 SDK 18362 or later - [Get the SDK](https://developer.microsoft.com/windows/downloads/windows-10-sdk) 15 | 16 | ## Code at at glance 17 | 18 | This sample uses new APIs available in Windows 10 version 1903, SDK 18362: 19 | 20 | - `CreateForWindow` (HWND) and `CreateForMonitor` (HMON) APIs are in the Windows.Graphics.Capture.Interop.h header. 21 | 22 | ## See also 23 | 24 | [Main ReadMe for this repo](https://github.com/Microsoft/Windows.UI.Composition-Win32-Samples) 25 | 26 | API reference: [Windows.Graphics.Capture Namespace](https://docs.microsoft.com/uwp/api/windows.graphics.capture) 27 | -------------------------------------------------------------------------------- /src/WindowsGraphicsCapture/ScreenCapture.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.421 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScreenCapture", "ScreenCapture\ScreenCapture.csproj", "{4DDD37B1-E3E8-46C1-BDE9-3039A93DAF27}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CaptureSampleCore", "CaptureSampleCore\CaptureSampleCore.csproj", "{502B19A1-292A-4E7F-9C19-B16CA42F1F82}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Composition.WindowsRuntimeHelpers", "Composition.WindowsRuntimeHelpers\Composition.WindowsRuntimeHelpers.csproj", "{EC969287-3D35-410A-806C-0BAAA7564911}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Debug|ARM = Debug|ARM 16 | Debug|x64 = Debug|x64 17 | Debug|x86 = Debug|x86 18 | Release|Any CPU = Release|Any CPU 19 | Release|ARM = Release|ARM 20 | Release|x64 = Release|x64 21 | Release|x86 = Release|x86 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {4DDD37B1-E3E8-46C1-BDE9-3039A93DAF27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {4DDD37B1-E3E8-46C1-BDE9-3039A93DAF27}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {4DDD37B1-E3E8-46C1-BDE9-3039A93DAF27}.Debug|ARM.ActiveCfg = Debug|Any CPU 27 | {4DDD37B1-E3E8-46C1-BDE9-3039A93DAF27}.Debug|ARM.Build.0 = Debug|Any CPU 28 | {4DDD37B1-E3E8-46C1-BDE9-3039A93DAF27}.Debug|x64.ActiveCfg = Debug|Any CPU 29 | {4DDD37B1-E3E8-46C1-BDE9-3039A93DAF27}.Debug|x64.Build.0 = Debug|Any CPU 30 | {4DDD37B1-E3E8-46C1-BDE9-3039A93DAF27}.Debug|x86.ActiveCfg = Debug|Any CPU 31 | {4DDD37B1-E3E8-46C1-BDE9-3039A93DAF27}.Debug|x86.Build.0 = Debug|Any CPU 32 | {4DDD37B1-E3E8-46C1-BDE9-3039A93DAF27}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {4DDD37B1-E3E8-46C1-BDE9-3039A93DAF27}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {4DDD37B1-E3E8-46C1-BDE9-3039A93DAF27}.Release|ARM.ActiveCfg = Release|Any CPU 35 | {4DDD37B1-E3E8-46C1-BDE9-3039A93DAF27}.Release|ARM.Build.0 = Release|Any CPU 36 | {4DDD37B1-E3E8-46C1-BDE9-3039A93DAF27}.Release|x64.ActiveCfg = Release|Any CPU 37 | {4DDD37B1-E3E8-46C1-BDE9-3039A93DAF27}.Release|x64.Build.0 = Release|Any CPU 38 | {4DDD37B1-E3E8-46C1-BDE9-3039A93DAF27}.Release|x86.ActiveCfg = Release|Any CPU 39 | {4DDD37B1-E3E8-46C1-BDE9-3039A93DAF27}.Release|x86.Build.0 = Release|Any CPU 40 | {502B19A1-292A-4E7F-9C19-B16CA42F1F82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {502B19A1-292A-4E7F-9C19-B16CA42F1F82}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {502B19A1-292A-4E7F-9C19-B16CA42F1F82}.Debug|ARM.ActiveCfg = Debug|Any CPU 43 | {502B19A1-292A-4E7F-9C19-B16CA42F1F82}.Debug|ARM.Build.0 = Debug|Any CPU 44 | {502B19A1-292A-4E7F-9C19-B16CA42F1F82}.Debug|x64.ActiveCfg = Debug|Any CPU 45 | {502B19A1-292A-4E7F-9C19-B16CA42F1F82}.Debug|x64.Build.0 = Debug|Any CPU 46 | {502B19A1-292A-4E7F-9C19-B16CA42F1F82}.Debug|x86.ActiveCfg = Debug|Any CPU 47 | {502B19A1-292A-4E7F-9C19-B16CA42F1F82}.Debug|x86.Build.0 = Debug|Any CPU 48 | {502B19A1-292A-4E7F-9C19-B16CA42F1F82}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {502B19A1-292A-4E7F-9C19-B16CA42F1F82}.Release|Any CPU.Build.0 = Release|Any CPU 50 | {502B19A1-292A-4E7F-9C19-B16CA42F1F82}.Release|ARM.ActiveCfg = Release|Any CPU 51 | {502B19A1-292A-4E7F-9C19-B16CA42F1F82}.Release|ARM.Build.0 = Release|Any CPU 52 | {502B19A1-292A-4E7F-9C19-B16CA42F1F82}.Release|x64.ActiveCfg = Release|Any CPU 53 | {502B19A1-292A-4E7F-9C19-B16CA42F1F82}.Release|x64.Build.0 = Release|Any CPU 54 | {502B19A1-292A-4E7F-9C19-B16CA42F1F82}.Release|x86.ActiveCfg = Release|Any CPU 55 | {502B19A1-292A-4E7F-9C19-B16CA42F1F82}.Release|x86.Build.0 = Release|Any CPU 56 | {EC969287-3D35-410A-806C-0BAAA7564911}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 57 | {EC969287-3D35-410A-806C-0BAAA7564911}.Debug|Any CPU.Build.0 = Debug|Any CPU 58 | {EC969287-3D35-410A-806C-0BAAA7564911}.Debug|ARM.ActiveCfg = Debug|Any CPU 59 | {EC969287-3D35-410A-806C-0BAAA7564911}.Debug|ARM.Build.0 = Debug|Any CPU 60 | {EC969287-3D35-410A-806C-0BAAA7564911}.Debug|x64.ActiveCfg = Debug|Any CPU 61 | {EC969287-3D35-410A-806C-0BAAA7564911}.Debug|x64.Build.0 = Debug|Any CPU 62 | {EC969287-3D35-410A-806C-0BAAA7564911}.Debug|x86.ActiveCfg = Debug|Any CPU 63 | {EC969287-3D35-410A-806C-0BAAA7564911}.Debug|x86.Build.0 = Debug|Any CPU 64 | {EC969287-3D35-410A-806C-0BAAA7564911}.Release|Any CPU.ActiveCfg = Release|Any CPU 65 | {EC969287-3D35-410A-806C-0BAAA7564911}.Release|Any CPU.Build.0 = Release|Any CPU 66 | {EC969287-3D35-410A-806C-0BAAA7564911}.Release|ARM.ActiveCfg = Release|Any CPU 67 | {EC969287-3D35-410A-806C-0BAAA7564911}.Release|ARM.Build.0 = Release|Any CPU 68 | {EC969287-3D35-410A-806C-0BAAA7564911}.Release|x64.ActiveCfg = Release|Any CPU 69 | {EC969287-3D35-410A-806C-0BAAA7564911}.Release|x64.Build.0 = Release|Any CPU 70 | {EC969287-3D35-410A-806C-0BAAA7564911}.Release|x86.ActiveCfg = Release|Any CPU 71 | {EC969287-3D35-410A-806C-0BAAA7564911}.Release|x86.Build.0 = Release|Any CPU 72 | EndGlobalSection 73 | GlobalSection(SolutionProperties) = preSolution 74 | HideSolutionNode = FALSE 75 | EndGlobalSection 76 | GlobalSection(ExtensibilityGlobals) = postSolution 77 | SolutionGuid = {2EBE8D8A-1C43-4C9B-BD8D-CBB938E8F1FE} 78 | EndGlobalSection 79 | EndGlobal 80 | -------------------------------------------------------------------------------- /src/WindowsGraphicsCapture/ScreenCapture/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | using System.Windows; 4 | 5 | [assembly: AssemblyCopyright("Copyright © 2019")] 6 | [assembly: ComVisible(false)] 7 | [assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] 8 | -------------------------------------------------------------------------------- /src/WindowsGraphicsCapture/ScreenCapture/GraphicsCapture.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Drawing.Imaging; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace WPFCaptureSample; 7 | 8 | public static class GraphicsCapture 9 | { 10 | public static MainWindow CaptureWindow; 11 | public static Bitmap CaptureBitmap => CaptureWindow.Sample?.Capture?.Bitmap!; 12 | 13 | public static Bitmap Capture(int x, int y, int w, int h, IntPtr? hwnd = null) 14 | { 15 | if (hwnd == null || hwnd == IntPtr.Zero) 16 | { 17 | return null!; 18 | } 19 | 20 | RECT lpRect = default; 21 | GetWindowRect(hwnd.Value, ref lpRect); 22 | float controlsWidth = Math.Max(lpRect.Right - lpRect.Left, 2); 23 | 24 | try 25 | { 26 | if (CaptureWindow == null) 27 | { 28 | CaptureWindow ??= new(); 29 | CaptureWindow.InitComposition(controlsWidth); 30 | CaptureWindow.StartHwndCapture(hwnd!.Value); 31 | } 32 | if (CaptureWindow != null) 33 | { 34 | if (CaptureWindow.Sample?.Capture == null) 35 | { 36 | CaptureWindow.InitComposition(controlsWidth); 37 | CaptureWindow.StartHwndCapture(hwnd!.Value); 38 | } 39 | if (CaptureWindow.ControlsWidth != controlsWidth) 40 | { 41 | CaptureWindow.StopCapture(); 42 | CaptureWindow.InitComposition(controlsWidth); 43 | } 44 | } 45 | 46 | if (CaptureBitmap != null) 47 | { 48 | return CropBitmap(CaptureBitmap, x, y, w, h); 49 | } 50 | } 51 | catch 52 | { 53 | } 54 | return null!; 55 | } 56 | 57 | public static void Uncapture() 58 | { 59 | try 60 | { 61 | CaptureWindow?.StopCapture(); 62 | } 63 | catch 64 | { 65 | } 66 | } 67 | 68 | private static unsafe Bitmap CropBitmap(Bitmap source, int x, int y, int width, int height) 69 | { 70 | if (x < 0 || x + width > source.Width || y < 0 || y + height > source.Height) 71 | { 72 | return source; 73 | } 74 | 75 | Bitmap target = new(width, height, PixelFormat.Format32bppArgb); 76 | 77 | BitmapData sourceData = null!; 78 | BitmapData targetData = null!; 79 | 80 | try 81 | { 82 | sourceData = source.LockBits(new Rectangle(x, y, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); 83 | targetData = target.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); 84 | 85 | byte* sourcePtr = (byte*)sourceData.Scan0; 86 | byte* targetPtr = (byte*)targetData.Scan0; 87 | 88 | int bytesPerRow = width * 4; 89 | 90 | for (int i = 0; i < height; i++) 91 | { 92 | byte* sourceRow = sourcePtr + i * sourceData.Stride; 93 | byte* targetRow = targetPtr + i * targetData.Stride; 94 | 95 | for (int j = 0; j < bytesPerRow; j++) 96 | { 97 | targetRow[j] = sourceRow[j]; 98 | } 99 | } 100 | } 101 | finally 102 | { 103 | if (sourceData != null) 104 | source.UnlockBits(sourceData); 105 | if (targetData != null) 106 | target.UnlockBits(targetData); 107 | } 108 | return target; 109 | } 110 | 111 | [DllImport("user32.dll", SetLastError = true)] 112 | [return: MarshalAs(UnmanagedType.Bool)] 113 | private static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect); 114 | 115 | [StructLayout(LayoutKind.Sequential)] 116 | private struct RECT 117 | { 118 | public int Left; 119 | public int Top; 120 | public int Right; 121 | public int Bottom; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/WindowsGraphicsCapture/ScreenCapture/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  24 | 25 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |