├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── UWPStreamer.sln ├── UWPStreamer ├── App.xaml ├── App.xaml.cs ├── Assets │ ├── 200x200.scale-400.png │ ├── Gamebar.PNG │ ├── LockScreenLogo.scale-200.png │ ├── LogoMaster.png │ ├── NTRInputRedirect.PNG │ ├── NTRSelector.PNG │ ├── Screenshots │ │ ├── Desktop │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ └── 3.png │ │ ├── Hololens │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ └── 3.png │ │ ├── Mobile │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ └── 3.png │ │ └── XboxOne │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ └── 3.png │ ├── SplashScreen.scale-200.png │ ├── Square150x150Logo.scale-200.png │ ├── Square44x44Logo.scale-200.png │ ├── Square44x44Logo.scale-400.png │ ├── Square44x44Logo.targetsize-24_altform-unplated.png │ ├── StoreLogo.scale-100.png │ ├── StoreLogo.scale-125.png │ ├── StoreLogo.scale-150.png │ ├── StoreLogo.scale-200.png │ ├── StoreLogo.scale-400.png │ ├── Wide310x150Logo.scale-200.png │ └── enableDebugger.PNG ├── Helpers │ └── Extensions.cs ├── MainPage.xaml ├── MainPage.xaml.cs ├── Package.StoreAssociation.xml ├── Package.appxmanifest ├── Properties │ ├── AssemblyInfo.cs │ └── Default.rd.xml ├── Services │ ├── NTR.cs │ ├── NTRClient.cs │ ├── NTRInputRedirection.cs │ └── ScriptHelper.cs ├── SettingsDialog.xaml ├── SettingsDialog.xaml.cs ├── UWPStreamer.csproj ├── _pkginfo.txt ├── _scale-100.appx ├── _scale-125.appx ├── _scale-150.appx ├── _scale-400.appx └── project.json └── WPFStreamer ├── App.config ├── App.xaml ├── App.xaml.cs ├── FodyWeavers.xml ├── Helpers └── Extensions.cs ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── Properties ├── AssemblyInfo.cs ├── Resources.Designer.cs ├── Resources.resx ├── Settings.Designer.cs └── Settings.settings ├── Services ├── NTR.cs ├── NTRClient.cs ├── NTRInputRedirection.cs └── ScriptHelper.cs ├── ViewModel ├── MainViewModel.cs └── ViewModelLocator.cs ├── WPFStreamer.csproj └── packages.config /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | [Xx]64/ 19 | [Xx]86/ 20 | [Bb]uild/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | 143 | # TODO: Un-comment the next line if you do not want to checkin 144 | # your web deploy settings because they may include unencrypted 145 | # passwords 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # NuGet Packages 150 | *.nupkg 151 | # The packages folder can be ignored because of Package Restore 152 | **/packages/* 153 | # except build/, which is used as an MSBuild target. 154 | !**/packages/build/ 155 | # Uncomment if necessary however generally it will be regenerated when needed 156 | #!**/packages/repositories.config 157 | # NuGet v3's project.json files produces more ignoreable files 158 | *.nuget.props 159 | *.nuget.targets 160 | 161 | # Microsoft Azure Build Output 162 | csx/ 163 | *.build.csdef 164 | 165 | # Microsoft Azure Emulator 166 | ecf/ 167 | rcf/ 168 | 169 | # Windows Store app package directory 170 | AppPackages/ 171 | BundleArtifacts/ 172 | 173 | # Visual Studio cache files 174 | # files ending in .cache can be ignored 175 | *.[Cc]ache 176 | # but keep track of directories ending in .cache 177 | !*.[Cc]ache/ 178 | 179 | # Others 180 | ClientBin/ 181 | [Ss]tyle[Cc]op.* 182 | ~$* 183 | *~ 184 | *.dbmdl 185 | *.dbproj.schemaview 186 | *.pfx 187 | *.publishsettings 188 | node_modules/ 189 | orleans.codegen.cs 190 | 191 | # RIA/Silverlight projects 192 | Generated_Code/ 193 | 194 | # Backup & report files from converting an old project file 195 | # to a newer Visual Studio version. Backup files are not needed, 196 | # because we have git ;-) 197 | _UpgradeReport_Files/ 198 | Backup*/ 199 | UpgradeLog*.XML 200 | UpgradeLog*.htm 201 | 202 | # SQL Server files 203 | *.mdf 204 | *.ldf 205 | 206 | # Business Intelligence projects 207 | *.rdl.data 208 | *.bim.layout 209 | *.bim_*.settings 210 | 211 | # Microsoft Fakes 212 | FakesAssemblies/ 213 | 214 | # GhostDoc plugin setting file 215 | *.GhostDoc.xml 216 | 217 | # Node.js Tools for Visual Studio 218 | .ntvs_analysis.dat 219 | 220 | # Visual Studio 6 build log 221 | *.plg 222 | 223 | # Visual Studio 6 workspace options file 224 | *.opt 225 | 226 | # Visual Studio LightSwitch build output 227 | **/*.HTMLClient/GeneratedArtifacts 228 | **/*.DesktopClient/GeneratedArtifacts 229 | **/*.DesktopClient/ModelManifest.xml 230 | **/*.Server/GeneratedArtifacts 231 | **/*.Server/ModelManifest.xml 232 | _Pvt_Extensions 233 | 234 | # LightSwitch generated files 235 | GeneratedArtifacts/ 236 | ModelManifest.xml 237 | 238 | # Paket dependency manager 239 | .paket/paket.exe 240 | 241 | # FAKE - F# Make 242 | .fake/ 243 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., httpfsf.org 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute andor modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The Program, below, 65 | refers to any such program or work, and a work based on the Program 66 | means either the Program or any derivative work under copyright law 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications andor translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term modification.) Each licensee is addressed as you. 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the authordonor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution andor use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised andor new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and any 244 | later version, you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS ANDOR OTHER PARTIES 263 | PROVIDE THE PROGRAM AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY ANDOR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the copyright line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it andor modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a copyright disclaimer for the program, if 327 | necessary. Here is a sample; alter the names 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UWPStreamer # 2 | An NTR CFW streaming client targeting [UWP](https://msdn.microsoft.com/windows/uwp/get-started/universal-application-platform-guide?WT.mc_id=iot-0000-pdecarlo) (Xbox One, Hololens, Windows 10, and Windows Phone 10) 3 | 4 | ![Demo](http://i.imgur.com/GTRoCJv.png) 5 | 6 | ## Available in the Windows Store & Precompiled .EXE ## 7 | 8 | [![StoreLink](http://i.imgur.com/C6buqwe.png)](https://www.microsoft.com/store/p/uwpstreamer/9nd66p3vdnxt?WT.mc_id=iot-0000-pdecarlo) 9 | 10 | 11 | - [Windows Store Link](https://www.microsoft.com/store/p/uwpstreamer/9nd66p3vdnxt?WT.mc_id=iot-0000-pdecarlo) 12 | - [Precompiled .EXE](https://github.com/toolboc/UWPStreamer/releases/tag/wpf_v1.0.0.0) 13 | 14 | ## Features ## 15 | * Video Streaming - Stream 3DS screens to remote device 16 | * Input Redirection - Control N3DS with Xbox Gamepad, Keyboard, and other input devices 17 | * Windows Game Bar Support - Allows for integrated features on Windows 10 Desktop including Screen Capture and DVR 18 | 19 | 20 | 21 | ## Instructions for Video Streaming ## 22 | *Assumes you have installed NTR CFW on a New Nintendo 3DS and you know how to get it up and running.* 23 | 24 | 1. Open NTR CFW. Suggested to use [BootNTR Selector](https://gbatemp.net/threads/release-bootntr-selector.432911/) with NTR CFW v3.4 if you are on firmware 11.2 25 | 26 | 2. Make sure that you are connected to your Wi-Fi network and can find your 3DS's local IP 27 | address. 28 | 3. Launch UWPStreamer, and insert your IP address in the settings screen, select options and click "Connect" 29 | 30 | ## NTR Input Redirection Support ## 31 | 32 | *Allows controlling the N3DS with xbox gamepad, keyboard, and other input devices* 33 | 34 | 1. Ensure that you have installed the latest version of [InputRedirectionNTR](https://github.com/Kazo/InputRedirection/releases/tag/NTR-build) 35 | 2. Start "InputProc NTR Stary" on your 3DS after launching NTR 36 | 37 | 3.Connect gamepad to your Win10 Device using USB, Bluetooth, or dongle 38 | 39 | ## Controls ## 40 | * To hide bottom menu use Right-Trigger or Right Mouse-Click (Allows more screen real-estate and block input from controller to menu) 41 | * Disable controller input to the game screen with Left-Trigger  ​(Allows selecting the menu w/out input to game) 42 | * On Desktop push Xbox button or Win+G to launch Game Bar for DVR / Screenshots 43 | 44 | ## Videos ## 45 | 46 | **Xbox One** 47 | 48 | [![Xbox One Demo](https://img.youtube.com/vi/mO7kZx6YRTU/0.jpg)](https://www.youtube.com/watch?v=mO7kZx6YRTU) 49 | 50 | **Hololens** 51 | 52 | [![Hololens Demo](https://img.youtube.com/vi/HVuQsCvUj_o/0.jpg)](https://www.youtube.com/watch?v=HVuQsCvUj_o) 53 | 54 | ## Video Capture ## 55 | [No More Beta Productions](https://www.youtube.com/channel/UCdQDN1V4mMzfOirm08Nm8TA) has created a tutorial video showing how to produce custom overlays with screen recordings taken from UWPStreamer 56 | 57 | **Tutorial** 58 | 59 | [![Capture Tutorial](https://img.youtube.com/vi/I1pQiyEAduA/0.jpg)](https://www.youtube.com/watch?v=I1pQiyEAduA) 60 | 61 | **Video Capture with post effects** 62 | 63 | [![Video Capture Example](https://img.youtube.com/vi/9HNBWVT911o/0.jpg)](https://www.youtube.com/watch?v=9HNBWVT911o) 64 | 65 | ## User Demos ## 66 | 67 | **3DS streaming wirelessly to the Xbox One streaming wirelessly to Windows 10 2-n-1 streaming wirelessly to Roku Stick with Miracast** 68 | 69 | 70 | 71 | **Windows Phone** 72 | 73 | 74 | 75 | **Xbox One** 76 | 77 | 78 | 79 | ## Credits ## 80 | Inspired by RattletraPM's original open-source streamer : [SnickerStream](https://github.com/RattletraPM/Snickerstream). 81 | 82 | Impossible without Cell9's NTR CFW and [BootNTR](https://github.com/44670/BootNTR) 83 | 84 | Input Redirection thanks to Stary2001's [NTR Input Redirection](https://github.com/Stary2001/InputRedirection) and Kazo's [Input Redirection Client](https://github.com/Kazo/InputRedirectionClient) for PC. 85 | 86 | -------------------------------------------------------------------------------- /UWPStreamer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UWPStreamer", "UWPStreamer\UWPStreamer.csproj", "{D727D4AB-F232-4A63-B248-4ECF2A74D940}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WPFStreamer", "WPFStreamer\WPFStreamer.csproj", "{647E65C6-92DA-4609-9660-7C7E9B8947A8}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Debug|ARM = Debug|ARM 14 | Debug|x64 = Debug|x64 15 | Debug|x86 = Debug|x86 16 | Release|Any CPU = Release|Any CPU 17 | Release|ARM = Release|ARM 18 | Release|x64 = Release|x64 19 | Release|x86 = Release|x86 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {D727D4AB-F232-4A63-B248-4ECF2A74D940}.Debug|Any CPU.ActiveCfg = Debug|x86 23 | {D727D4AB-F232-4A63-B248-4ECF2A74D940}.Debug|ARM.ActiveCfg = Debug|ARM 24 | {D727D4AB-F232-4A63-B248-4ECF2A74D940}.Debug|ARM.Build.0 = Debug|ARM 25 | {D727D4AB-F232-4A63-B248-4ECF2A74D940}.Debug|ARM.Deploy.0 = Debug|ARM 26 | {D727D4AB-F232-4A63-B248-4ECF2A74D940}.Debug|x64.ActiveCfg = Debug|x64 27 | {D727D4AB-F232-4A63-B248-4ECF2A74D940}.Debug|x64.Build.0 = Debug|x64 28 | {D727D4AB-F232-4A63-B248-4ECF2A74D940}.Debug|x64.Deploy.0 = Debug|x64 29 | {D727D4AB-F232-4A63-B248-4ECF2A74D940}.Debug|x86.ActiveCfg = Debug|x86 30 | {D727D4AB-F232-4A63-B248-4ECF2A74D940}.Debug|x86.Build.0 = Debug|x86 31 | {D727D4AB-F232-4A63-B248-4ECF2A74D940}.Debug|x86.Deploy.0 = Debug|x86 32 | {D727D4AB-F232-4A63-B248-4ECF2A74D940}.Release|Any CPU.ActiveCfg = Release|x86 33 | {D727D4AB-F232-4A63-B248-4ECF2A74D940}.Release|ARM.ActiveCfg = Release|ARM 34 | {D727D4AB-F232-4A63-B248-4ECF2A74D940}.Release|ARM.Build.0 = Release|ARM 35 | {D727D4AB-F232-4A63-B248-4ECF2A74D940}.Release|ARM.Deploy.0 = Release|ARM 36 | {D727D4AB-F232-4A63-B248-4ECF2A74D940}.Release|x64.ActiveCfg = Release|x64 37 | {D727D4AB-F232-4A63-B248-4ECF2A74D940}.Release|x64.Build.0 = Release|x64 38 | {D727D4AB-F232-4A63-B248-4ECF2A74D940}.Release|x64.Deploy.0 = Release|x64 39 | {D727D4AB-F232-4A63-B248-4ECF2A74D940}.Release|x86.ActiveCfg = Release|x86 40 | {D727D4AB-F232-4A63-B248-4ECF2A74D940}.Release|x86.Build.0 = Release|x86 41 | {D727D4AB-F232-4A63-B248-4ECF2A74D940}.Release|x86.Deploy.0 = Release|x86 42 | {647E65C6-92DA-4609-9660-7C7E9B8947A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {647E65C6-92DA-4609-9660-7C7E9B8947A8}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {647E65C6-92DA-4609-9660-7C7E9B8947A8}.Debug|ARM.ActiveCfg = Debug|Any CPU 45 | {647E65C6-92DA-4609-9660-7C7E9B8947A8}.Debug|ARM.Build.0 = Debug|Any CPU 46 | {647E65C6-92DA-4609-9660-7C7E9B8947A8}.Debug|x64.ActiveCfg = Debug|Any CPU 47 | {647E65C6-92DA-4609-9660-7C7E9B8947A8}.Debug|x64.Build.0 = Debug|Any CPU 48 | {647E65C6-92DA-4609-9660-7C7E9B8947A8}.Debug|x86.ActiveCfg = Debug|Any CPU 49 | {647E65C6-92DA-4609-9660-7C7E9B8947A8}.Debug|x86.Build.0 = Debug|Any CPU 50 | {647E65C6-92DA-4609-9660-7C7E9B8947A8}.Release|Any CPU.ActiveCfg = Release|Any CPU 51 | {647E65C6-92DA-4609-9660-7C7E9B8947A8}.Release|Any CPU.Build.0 = Release|Any CPU 52 | {647E65C6-92DA-4609-9660-7C7E9B8947A8}.Release|ARM.ActiveCfg = Release|Any CPU 53 | {647E65C6-92DA-4609-9660-7C7E9B8947A8}.Release|ARM.Build.0 = Release|Any CPU 54 | {647E65C6-92DA-4609-9660-7C7E9B8947A8}.Release|x64.ActiveCfg = Release|Any CPU 55 | {647E65C6-92DA-4609-9660-7C7E9B8947A8}.Release|x64.Build.0 = Release|Any CPU 56 | {647E65C6-92DA-4609-9660-7C7E9B8947A8}.Release|x86.ActiveCfg = Release|Any CPU 57 | {647E65C6-92DA-4609-9660-7C7E9B8947A8}.Release|x86.Build.0 = Release|Any CPU 58 | EndGlobalSection 59 | GlobalSection(SolutionProperties) = preSolution 60 | HideSolutionNode = FALSE 61 | EndGlobalSection 62 | EndGlobal 63 | -------------------------------------------------------------------------------- /UWPStreamer/App.xaml: -------------------------------------------------------------------------------- 1 |  7 | 8 | 9 | -------------------------------------------------------------------------------- /UWPStreamer/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using InputRedirectionNTR; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Runtime.InteropServices.WindowsRuntime; 7 | using UWPStreamer.Services; 8 | using Windows.ApplicationModel; 9 | using Windows.ApplicationModel.Activation; 10 | using Windows.Foundation; 11 | using Windows.Foundation.Collections; 12 | using Windows.UI.Xaml; 13 | using Windows.UI.Xaml.Controls; 14 | using Windows.UI.Xaml.Controls.Primitives; 15 | using Windows.UI.Xaml.Data; 16 | using Windows.UI.Xaml.Input; 17 | using Windows.UI.Xaml.Media; 18 | using Windows.UI.Xaml.Navigation; 19 | 20 | namespace UWPStreamer 21 | { 22 | /// 23 | /// Provides application-specific behavior to supplement the default Application class. 24 | /// 25 | sealed partial class App : Application 26 | { 27 | 28 | public static NTRClient ntrClient; 29 | public static ScriptHelper scriptHelper; 30 | public static Boolean Connected = false; 31 | 32 | /// 33 | /// Initializes the singleton application object. This is the first line of authored code 34 | /// executed, and as such is the logical equivalent of main() or WinMain(). 35 | /// 36 | public App() 37 | { 38 | ntrClient = new NTRClient(); 39 | scriptHelper = new ScriptHelper(); 40 | 41 | this.InitializeComponent(); 42 | this.RequiresPointerMode = Windows.UI.Xaml.ApplicationRequiresPointerMode.WhenRequested; 43 | this.Suspending += OnSuspending; 44 | } 45 | 46 | /// 47 | /// Invoked when the application is launched normally by the end user. Other entry points 48 | /// will be used such as when the application is launched to open a specific file. 49 | /// 50 | /// Details about the launch request and process. 51 | protected override void OnLaunched(LaunchActivatedEventArgs e) 52 | { 53 | #if DEBUG 54 | if (System.Diagnostics.Debugger.IsAttached) 55 | { 56 | this.DebugSettings.EnableFrameRateCounter = true; 57 | } 58 | #endif 59 | Frame rootFrame = Window.Current.Content as Frame; 60 | 61 | // Do not repeat app initialization when the Window already has content, 62 | // just ensure that the window is active 63 | if (rootFrame == null) 64 | { 65 | // Create a Frame to act as the navigation context and navigate to the first page 66 | rootFrame = new Frame(); 67 | 68 | rootFrame.NavigationFailed += OnNavigationFailed; 69 | 70 | if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) 71 | { 72 | //TODO: Load state from previously suspended application 73 | } 74 | 75 | // Place the frame in the current Window 76 | Window.Current.Content = rootFrame; 77 | } 78 | 79 | if (e.PrelaunchActivated == false) 80 | { 81 | if (rootFrame.Content == null) 82 | { 83 | // When the navigation stack isn't restored navigate to the first page, 84 | // configuring the new page by passing required information as a navigation 85 | // parameter 86 | rootFrame.Navigate(typeof(MainPage), e.Arguments); 87 | } 88 | // Ensure the current window is active 89 | Window.Current.Activate(); 90 | } 91 | } 92 | 93 | /// 94 | /// Invoked when Navigation to a certain page fails 95 | /// 96 | /// The Frame which failed navigation 97 | /// Details about the navigation failure 98 | void OnNavigationFailed(object sender, NavigationFailedEventArgs e) 99 | { 100 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName); 101 | } 102 | 103 | /// 104 | /// Invoked when application execution is being suspended. Application state is saved 105 | /// without knowing whether the application will be terminated or resumed with the contents 106 | /// of memory still intact. 107 | /// 108 | /// The source of the suspend request. 109 | /// Details about the suspend request. 110 | private void OnSuspending(object sender, SuspendingEventArgs e) 111 | { 112 | var deferral = e.SuspendingOperation.GetDeferral(); 113 | //TODO: Save application state and stop any background activity 114 | deferral.Complete(); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /UWPStreamer/Assets/200x200.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/200x200.scale-400.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/Gamebar.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/Gamebar.PNG -------------------------------------------------------------------------------- /UWPStreamer/Assets/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/LogoMaster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/LogoMaster.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/NTRInputRedirect.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/NTRInputRedirect.PNG -------------------------------------------------------------------------------- /UWPStreamer/Assets/NTRSelector.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/NTRSelector.PNG -------------------------------------------------------------------------------- /UWPStreamer/Assets/Screenshots/Desktop/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/Screenshots/Desktop/1.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/Screenshots/Desktop/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/Screenshots/Desktop/2.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/Screenshots/Desktop/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/Screenshots/Desktop/3.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/Screenshots/Hololens/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/Screenshots/Hololens/1.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/Screenshots/Hololens/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/Screenshots/Hololens/2.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/Screenshots/Hololens/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/Screenshots/Hololens/3.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/Screenshots/Mobile/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/Screenshots/Mobile/1.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/Screenshots/Mobile/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/Screenshots/Mobile/2.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/Screenshots/Mobile/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/Screenshots/Mobile/3.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/Screenshots/XboxOne/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/Screenshots/XboxOne/1.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/Screenshots/XboxOne/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/Screenshots/XboxOne/2.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/Screenshots/XboxOne/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/Screenshots/XboxOne/3.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/Square44x44Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/Square44x44Logo.scale-400.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/StoreLogo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/StoreLogo.scale-100.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/StoreLogo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/StoreLogo.scale-125.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/StoreLogo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/StoreLogo.scale-150.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/StoreLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/StoreLogo.scale-200.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/StoreLogo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/StoreLogo.scale-400.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /UWPStreamer/Assets/enableDebugger.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/Assets/enableDebugger.PNG -------------------------------------------------------------------------------- /UWPStreamer/Helpers/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace UWPStreamer.Helpers 8 | { 9 | public static class Extensions 10 | { 11 | public static byte[] StringToByteArray(this String hex) 12 | { 13 | return Enumerable.Range(0, hex.Length) 14 | .Where(x => x % 2 == 0) 15 | .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) 16 | .ToArray(); 17 | } 18 | 19 | /// 20 | /// Get the array slice between the two indexes. 21 | /// ... Inclusive for start index, exclusive for end index. 22 | /// 23 | public static T[] Slice(this T[] source, int start, int end) 24 | { 25 | // Handles negative ends. 26 | if (end < 0) 27 | { 28 | end = source.Length + end; 29 | } 30 | int len = end - start; 31 | 32 | // Return new array. 33 | T[] res = new T[len]; 34 | for (int i = 0; i < len; i++) 35 | { 36 | res[i] = source[i + start]; 37 | } 38 | return res; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /UWPStreamer/MainPage.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 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 | UWPStreamer is an open-source NTR CFW streaming client targeting UWP (Xbox One, Hololens, Windows 10, and Windows Phone 10) 79 | 80 | 81 | Now with support for NTR Input Redirection! 82 | 83 | 84 | You may find instructions, view source code, and report issues at the 85 | Project Homepage 86 | 87 | 88 | To hide bottom menu use Right-Trigger or Right Mouse-Click 89 | 90 | 91 | Toggle controller input with Left-Trigger 92 | 93 | 94 | On Desktop push Xbox button or Win+G to launch Game Bar for DVR / Screenshots 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /UWPStreamer/MainPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using InputRedirectionNTR; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Runtime.InteropServices.WindowsRuntime; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | using UWPStreamer.Services; 10 | using Windows.Foundation; 11 | using Windows.Foundation.Collections; 12 | using Windows.Storage; 13 | using Windows.System; 14 | using Windows.UI.ViewManagement; 15 | using Windows.UI.Xaml; 16 | using Windows.UI.Xaml.Controls; 17 | using Windows.UI.Xaml.Controls.Primitives; 18 | using Windows.UI.Xaml.Data; 19 | using Windows.UI.Xaml.Input; 20 | using Windows.UI.Xaml.Media; 21 | using Windows.UI.Xaml.Media.Imaging; 22 | using Windows.UI.Xaml.Navigation; 23 | 24 | // The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 25 | 26 | namespace UWPStreamer 27 | { 28 | 29 | 30 | /// 31 | /// An empty page that can be used on its own or navigated to within a Frame. 32 | /// 33 | public sealed partial class MainPage : Page 34 | { 35 | ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings; 36 | NTR ntr; 37 | int visualState = 0; 38 | int rotation = 0; 39 | 40 | CancellationTokenSource tokenSource; 41 | CancellationToken ct; 42 | NTRInputRedirection ntrInputRedirection; 43 | Task ntrInputRedirectionTask; 44 | 45 | public MainPage() 46 | { 47 | Window.Current.CoreWindow.KeyUp += CoreWindow_KeyUp; 48 | Window.Current.CoreWindow.PointerReleased += CoreWindow_PointerReleased; 49 | 50 | this.InitializeComponent(); 51 | 52 | ntr = new NTR(); 53 | DataContext = ntr; 54 | Init(); 55 | } 56 | 57 | private void CoreWindow_PointerReleased(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.PointerEventArgs args) 58 | { 59 | if(args.CurrentPoint.Properties.PointerUpdateKind == Windows.UI.Input.PointerUpdateKind.RightButtonReleased) 60 | { 61 | if (bottomCommandBar.ClosedDisplayMode == AppBarClosedDisplayMode.Minimal) 62 | { 63 | bottomCommandBar.ClosedDisplayMode = AppBarClosedDisplayMode.Hidden; 64 | } 65 | else 66 | bottomCommandBar.ClosedDisplayMode = AppBarClosedDisplayMode.Minimal; 67 | } 68 | } 69 | 70 | private void CoreWindow_KeyUp(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.KeyEventArgs args) 71 | { 72 | if (args.VirtualKey == VirtualKey.GamepadRightTrigger && !bottomCommandBar.IsOpen) 73 | { 74 | if (bottomCommandBar.ClosedDisplayMode == AppBarClosedDisplayMode.Minimal) 75 | { 76 | bottomCommandBar.IsEnabled = false; 77 | bottomCommandBar.ClosedDisplayMode = AppBarClosedDisplayMode.Hidden; 78 | } 79 | else 80 | { 81 | bottomCommandBar.IsEnabled = true; 82 | bottomCommandBar.ClosedDisplayMode = AppBarClosedDisplayMode.Minimal; 83 | } 84 | } 85 | 86 | if (args.VirtualKey == VirtualKey.GamepadLeftTrigger) 87 | { 88 | ntrInputRedirection.useGamePad = ntrInputRedirection.useGamePad ? false : true; 89 | } 90 | } 91 | 92 | private void Init() 93 | { 94 | 95 | bool autoConnect = false; 96 | 97 | try 98 | { 99 | autoConnect = (bool)localSettings.Values["autoConnect"]; 100 | } 101 | catch 102 | { 103 | ShowSettings(); 104 | return; 105 | } 106 | 107 | if (autoConnect) 108 | InitRemotePlay(); 109 | else 110 | ShowSettings(); 111 | } 112 | 113 | private async void ShowSettings() 114 | { 115 | SettingsDialog dialog = new SettingsDialog(); 116 | await dialog.ShowAsync(); 117 | 118 | if (dialog.ConnectSelected) 119 | InitRemotePlay(); 120 | } 121 | 122 | private async void InitRemotePlay() 123 | { 124 | ProgressRing.IsActive = true; 125 | 126 | var ip = localSettings.Values["ip"].ToString(); 127 | var priorityMode = Int32.Parse(localSettings.Values["priorityMode"].ToString()); 128 | var priorityFactor = Int32.Parse(localSettings.Values["priorityFactor"].ToString()); 129 | var quality = Int32.Parse(localSettings.Values["quality"].ToString()); 130 | var qosValue = Int32.Parse(localSettings.Values["qosValue"].ToString()); 131 | 132 | try 133 | { 134 | await ntr.InitRemoteplay(ip, priorityMode, priorityFactor, quality, qosValue); 135 | } 136 | catch(Exception e) 137 | { 138 | var messageDialog = new Windows.UI.Popups.MessageDialog("Unable to connect to NTR Debugger on: \n" + ip, "Connection Error"); 139 | ProgressRing.IsActive = false; 140 | await messageDialog.ShowAsync(); 141 | return; 142 | } 143 | 144 | try 145 | { 146 | ntr.NTRRemoteplayConnect(); 147 | } 148 | catch(Exception e) 149 | { 150 | var messageDialog = new Windows.UI.Popups.MessageDialog("Error while streaming to remote 3DS on: \n" + ip, "Stream Interuppted"); 151 | await messageDialog.ShowAsync(); 152 | } 153 | finally 154 | { 155 | startNTRinputRedirection(); 156 | } 157 | 158 | ProgressRing.IsActive = false; 159 | } 160 | 161 | private void startNTRinputRedirection() 162 | { 163 | try 164 | { 165 | tokenSource = new CancellationTokenSource(); 166 | ct = tokenSource.Token; 167 | ntrInputRedirection = new NTRInputRedirection(); 168 | 169 | bottomCommandBar.GotFocus += bottomCommandBar_GotFocus; 170 | bottomCommandBar.LostFocus += bottomCommandBar_LostFocus; 171 | bottomCommandBar.Opening += bottomCommandBar_Opening; 172 | bottomCommandBar.Closed += bottomCommandBar_Closed; 173 | helpPopup.Opened += helpPopup_Opened; 174 | 175 | ntrInputRedirectionTask = new Task(() => { while (true) ntrInputRedirection.ReadMain(); }, ct); 176 | 177 | ntrInputRedirection.CheckConnection(); 178 | ntrInputRedirectionTask.Start(); 179 | } 180 | catch(Exception e) 181 | { 182 | var ip = localSettings.Values["ip"].ToString(); 183 | var messageDialog = new Windows.UI.Popups.MessageDialog("Error Initiating NTR Input Redirection on: \n" + ip, "Input Redirection Error"); 184 | } 185 | } 186 | 187 | private void FullScreenToggleButton_Checked(object sender, RoutedEventArgs e) 188 | { 189 | var appView = ApplicationView.GetForCurrentView(); 190 | 191 | if (appView.TryEnterFullScreenMode()) 192 | ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.FullScreen; 193 | } 194 | 195 | private void FullScreenToggleButton_Unchecked(object sender, RoutedEventArgs e) 196 | { 197 | var appView = ApplicationView.GetForCurrentView(); 198 | ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.PreferredLaunchViewSize; 199 | } 200 | 201 | private void HelpButton_Click(object sender, RoutedEventArgs e) 202 | { 203 | ShowHelp(); 204 | bottomCommandBar.IsOpen = false; 205 | } 206 | 207 | private void ShowHelp() 208 | { 209 | if (!helpPopup.IsOpen) 210 | { 211 | rootPopupBorder.Width = 346; 212 | rootPopupBorder.Height = this.ActualHeight; 213 | helpPopup.HorizontalOffset = Window.Current.Bounds.Width - 346; 214 | helpPopup.IsOpen = true; 215 | } 216 | } 217 | 218 | private async void settingButton_Click(object sender, RoutedEventArgs e) 219 | { 220 | ShowSettings(); 221 | } 222 | 223 | private void displayButton_Click(object sender, RoutedEventArgs e) 224 | { 225 | visualState++; 226 | switch(visualState) 227 | { 228 | case 0: 229 | VisualStateManager.GoToState(this, "BothScreens", false); 230 | break; 231 | case 1: 232 | VisualStateManager.GoToState(this, "TopScreenOnly", false); 233 | break; 234 | case 2: 235 | VisualStateManager.GoToState(this, "BottomScreenOnly", false); 236 | visualState = -1; 237 | break; 238 | 239 | } 240 | } 241 | 242 | private void rotateButton_Click(object sender, RoutedEventArgs e) 243 | { 244 | rotation = (rotation + 90) % 360; 245 | 246 | var c = new CompositeTransform(); 247 | c.Rotation = rotation; 248 | screensGrid.RenderTransform = c; 249 | } 250 | 251 | private void bottomCommandBar_GotFocus(object sender, RoutedEventArgs e) 252 | { 253 | ntrInputRedirection.useGamePad = false; 254 | } 255 | 256 | private void bottomCommandBar_LostFocus(object sender, RoutedEventArgs e) 257 | { 258 | if(!bottomCommandBar.IsOpen && !helpPopup.IsOpen) 259 | ntrInputRedirection.useGamePad = true; 260 | } 261 | 262 | private void bottomCommandBar_Opening(object sender, object e) 263 | { 264 | ntrInputRedirection.useGamePad = false; 265 | } 266 | 267 | private void bottomCommandBar_Closed(object sender, object e) 268 | { 269 | if(!helpPopup.IsOpen) 270 | ntrInputRedirection.useGamePad = true; 271 | } 272 | 273 | private void helpPopup_Opened(object sender, object e) 274 | { 275 | ntrInputRedirection.useGamePad = false; 276 | } 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /UWPStreamer/Package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | UWPStreamer 7 | WINCODER LLC 8 | Assets\StoreLogo.png 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /UWPStreamer/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("UWPStreamer")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("UWPStreamer")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Version information for an assembly consists of the following four values: 18 | // 19 | // Major Version 20 | // Minor Version 21 | // Build Number 22 | // Revision 23 | // 24 | // You can specify all the values or you can default the Build and Revision Numbers 25 | // by using the '*' as shown below: 26 | // [assembly: AssemblyVersion("1.0.*")] 27 | [assembly: AssemblyVersion("1.0.0.0")] 28 | [assembly: AssemblyFileVersion("1.0.0.0")] 29 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /UWPStreamer/Properties/Default.rd.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /UWPStreamer/Services/NTR.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Runtime.CompilerServices; 7 | using System.Runtime.InteropServices.WindowsRuntime; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using UWPStreamer.Helpers; 11 | using Windows.Graphics.Imaging; 12 | using Windows.Networking; 13 | using Windows.Networking.Sockets; 14 | using Windows.Storage.Streams; 15 | using Windows.UI.Core; 16 | using Windows.UI.Xaml.Media; 17 | using Windows.UI.Xaml.Media.Imaging; 18 | 19 | namespace UWPStreamer.Services 20 | { 21 | public class NTR : INotifyPropertyChanged 22 | { 23 | DatagramSocket socket; 24 | List priorityScreenBuffer = new List(); 25 | List secondaryScreenBuffer = new List(); 26 | 27 | private byte priorityExpectedFrame = 0; 28 | private byte secondaryExpectedFrame = 0; 29 | 30 | private byte priorityExpectedPacket = 0; 31 | private byte secondaryExpectedPacket = 0; 32 | 33 | private int activePriorityMode = 1; 34 | 35 | public event PropertyChangedEventHandler PropertyChanged; 36 | 37 | 38 | 39 | //bottom 40 | private ImageSource screen0; 41 | 42 | public ImageSource Screen0 43 | { 44 | get { return screen0; } 45 | set 46 | { 47 | screen0 = value; 48 | OnPropertyChanged(); 49 | } 50 | } 51 | 52 | //top 53 | private ImageSource screen1; 54 | 55 | public ImageSource Screen1 56 | { 57 | get { return screen1; } 58 | set 59 | { 60 | screen1 = value; 61 | OnPropertyChanged(); 62 | } 63 | } 64 | 65 | public NTR() 66 | { 67 | //Screen1 = new BitmapImage(new Uri("ms-appx:///Assets/placeholder.png")); 68 | } 69 | 70 | //This is the TCP package that needs to be sent to the N3DS.Under other cirumstances we'd want to change other bytes but to 71 | //initialize remoteplay we only need to care about bytes 0x10, 0x11, 0x14 and 0x1A. 72 | 73 | //Bytes 0x10 and 0x14 contain, respectively, the priority factor and JPEG quality variables.All we need to do is to convert 74 | //them from DEC to HEX et voilà, they work. 75 | 76 | 77 | //Byte 0x11 is the priority mode byte. This is a weird one: internally, 1 is for top screen and 0 is for bottom screen.If 78 | //you've used NTRClient, howerer, you've probably noticed that the boolean is actually FLIPPED, so 0 is top screen and 79 | //1 is bottom screen.I don't know why cell9 thought this was a good idea so, as we're sending a RAW package here, I've 80 | //decided to NOT flip the boolean.This way, there won't be any confusion regarding what this value actually means, and 81 | 82 | //1 will always mean top screen and 0 bottom screen in this source code. 83 | //Finally, byte 0x1A contains the QoS value.I have no idea why, but NTR expects it to be double its intended value. 84 | 85 | public async Task InitRemoteplay(string ip, int priorityMode = 1, int priorityFactor = 1, int quality = 75, int qosValue = 15) 86 | { 87 | activePriorityMode = priorityMode; 88 | 89 | HostName serverHost = new HostName(ip); 90 | string serverPort = "8000"; 91 | 92 | var hexString = "78563412B80B00000000000085030000"; 93 | hexString = hexString + priorityFactor.ToString("X2"); 94 | hexString = hexString + priorityMode.ToString("X2") + "0000"; 95 | hexString = hexString + quality.ToString("X2") + "0000000000"; 96 | hexString = hexString + (qosValue * 2).ToString("X2"); 97 | string zeroPad = new string('0', 114); 98 | hexString = hexString + zeroPad; 99 | 100 | StreamSocket socket = new StreamSocket(); 101 | await socket.ConnectAsync(serverHost, serverPort); 102 | 103 | BinaryWriter writer = new BinaryWriter(socket.OutputStream.AsStreamForWrite()); 104 | writer.Write(hexString.StringToByteArray()); 105 | 106 | writer.Flush(); 107 | 108 | socket.Dispose(); 109 | Task.Delay(3000).Wait(); 110 | 111 | socket = new StreamSocket(); 112 | await socket.ConnectAsync(serverHost, serverPort); 113 | socket.Dispose(); 114 | 115 | return true; 116 | } 117 | 118 | public async void NTRRemoteplayConnect() 119 | { 120 | if (socket != null) 121 | socket.Dispose(); 122 | 123 | socket = new DatagramSocket(); 124 | string serverPort = "8001"; 125 | socket.MessageReceived += NTRRemoteplayReadJPEG; 126 | await socket.BindServiceNameAsync(serverPort); 127 | } 128 | 129 | private async void NTRRemoteplayReadJPEG(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args) 130 | { 131 | 132 | Stream streamIn = args.GetDataStream().AsStreamForRead(); 133 | BinaryReader reader = new BinaryReader(streamIn); 134 | 135 | //A remoteplay packet sent by NTR looks like this 136 | 137 | //== HEADER == 138 | //0x00: Frame ID 139 | //0x01: First Nibble:if set to 1, it means that the packet is the last one in a JPEG stream.Second Nibble:Screen, 1 = Top / 0 = Bottom 140 | //0x02: Image format, usually this is set to 2 141 | //0x04: Packet number in JPEG stream 142 | 143 | var bytes = reader.ReadBytes(1448).ToList(); 144 | 145 | if (bytes.Count < 4) 146 | return; 147 | 148 | byte currentFrame = bytes[0]; 149 | byte currentScreen = (byte)(bytes[1] & 0x0F); 150 | byte isLastPacket = (byte)((bytes[1] & 0xF0) >> 4); 151 | int currentPacket = bytes[3]; 152 | 153 | //init to currentFrame 154 | if (priorityExpectedFrame == 0 && currentScreen == activePriorityMode) 155 | { 156 | priorityExpectedFrame = currentFrame; 157 | } 158 | else if (secondaryExpectedFrame == 0) 159 | { 160 | secondaryExpectedFrame = currentFrame; 161 | } 162 | 163 | 164 | //= BODY == 165 | //0x05 to 0x0n: JPEG data 166 | if (priorityExpectedFrame == currentFrame && priorityExpectedPacket == currentPacket && activePriorityMode == currentScreen) 167 | { 168 | //priority screen 169 | priorityScreenBuffer.AddRange(bytes.GetRange(4, bytes.Count - 4)); 170 | priorityExpectedPacket++; 171 | 172 | if(isLastPacket == 1) 173 | { 174 | await TryDisplayImage(priorityScreenBuffer, currentScreen); 175 | priorityExpectedFrame = 0; 176 | priorityExpectedPacket = 0; 177 | } 178 | } 179 | else if (currentScreen == activePriorityMode) 180 | { 181 | //Priority Packet Dropped (unexpected packet or frame) 182 | priorityScreenBuffer.Clear(); 183 | priorityExpectedFrame = 0; 184 | priorityExpectedPacket = 0; 185 | 186 | return; 187 | } 188 | else if(secondaryExpectedPacket == currentPacket) 189 | { 190 | //secondary screen 191 | secondaryScreenBuffer.AddRange(bytes.GetRange(4, bytes.Count - 4)); 192 | secondaryExpectedPacket++; 193 | 194 | if(isLastPacket == 1) 195 | { 196 | await TryDisplayImage(secondaryScreenBuffer, currentScreen); 197 | secondaryExpectedFrame = 0; 198 | secondaryExpectedPacket = 0; 199 | } 200 | 201 | return; 202 | } 203 | else 204 | { 205 | //Secondary Packet Dropped (unexpected packet or frame) 206 | secondaryScreenBuffer.Clear(); 207 | secondaryExpectedFrame = 0; 208 | secondaryExpectedPacket = 0; 209 | } 210 | 211 | 212 | } 213 | 214 | private async Task TryDisplayImage(List screenBuffer, int screen) 215 | { 216 | await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, 217 | async () => 218 | { 219 | var bitmapImage = new BitmapImage(); 220 | 221 | var stream = new InMemoryRandomAccessStream(); 222 | await stream.WriteAsync(screenBuffer.ToArray().AsBuffer()); 223 | stream.Seek(0); 224 | 225 | bitmapImage.SetSource(stream); 226 | 227 | if(screen == 1) 228 | Screen1 = bitmapImage; 229 | else 230 | Screen0 = bitmapImage; 231 | } 232 | ); 233 | 234 | screenBuffer.Clear(); 235 | } 236 | 237 | protected void OnPropertyChanged([CallerMemberName] string propertyName = null) 238 | { 239 | //C# 6 null-safe operator. No need to check for event listeners 240 | //If there are no listeners, this will be a noop 241 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 242 | } 243 | 244 | } 245 | } 246 | -------------------------------------------------------------------------------- /UWPStreamer/Services/NTRClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net.Sockets; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace UWPStreamer.Services 9 | { 10 | public class NTRClient 11 | { 12 | public String host; 13 | public int port; 14 | public TcpClient tcp; 15 | public NetworkStream netStream; 16 | public Task packetRecvThread; 17 | private object syncLock = new object(); 18 | int heartbeatSendable; 19 | int timeout; 20 | public delegate void logHandler(string msg); 21 | UInt32 currentSeq; 22 | public volatile int progress = -1; 23 | 24 | int readNetworkStream(NetworkStream stream, byte[] buf, int length) 25 | { 26 | int index = 0; 27 | bool useProgress = false; 28 | 29 | if (length > 100000) 30 | { 31 | useProgress = true; 32 | } 33 | do 34 | { 35 | if (useProgress) 36 | { 37 | progress = (int)(((double)(index) / length) * 100); 38 | } 39 | int len = stream.Read(buf, index, length - index); 40 | if (len == 0) 41 | { 42 | return 0; 43 | } 44 | index += len; 45 | } while (index < length); 46 | progress = -1; 47 | return length; 48 | } 49 | 50 | void packetRecvThreadStart() 51 | { 52 | byte[] buf = new byte[84]; 53 | UInt32[] args = new UInt32[16]; 54 | int ret; 55 | NetworkStream stream = netStream; 56 | 57 | while (true) 58 | { 59 | try 60 | { 61 | ret = readNetworkStream(stream, buf, buf.Length); 62 | if (ret == 0) 63 | { 64 | break; 65 | } 66 | int t = 0; 67 | UInt32 magic = BitConverter.ToUInt32(buf, t); 68 | t += 4; 69 | UInt32 seq = BitConverter.ToUInt32(buf, t); 70 | t += 4; 71 | UInt32 type = BitConverter.ToUInt32(buf, t); 72 | t += 4; 73 | UInt32 cmd = BitConverter.ToUInt32(buf, t); 74 | for (int i = 0; i < args.Length; i++) 75 | { 76 | t += 4; 77 | args[i] = BitConverter.ToUInt32(buf, t); 78 | } 79 | t += 4; 80 | UInt32 dataLen = BitConverter.ToUInt32(buf, t); 81 | 82 | if (magic != 0x12345678) 83 | { 84 | break; 85 | } 86 | 87 | if (cmd == 0) 88 | { 89 | if (dataLen != 0) 90 | { 91 | byte[] dataBuf = new byte[dataLen]; 92 | readNetworkStream(stream, dataBuf, dataBuf.Length); 93 | } 94 | lock (syncLock) 95 | { 96 | heartbeatSendable = 1; 97 | } 98 | continue; 99 | } 100 | if (dataLen != 0) 101 | { 102 | byte[] dataBuf = new byte[dataLen]; 103 | readNetworkStream(stream, dataBuf, dataBuf.Length); 104 | } 105 | } 106 | catch 107 | { 108 | break; 109 | } 110 | } 111 | disconnect(false); 112 | } 113 | 114 | public void setServer(String serverHost, int serverPort) 115 | { 116 | host = serverHost; 117 | port = serverPort; 118 | } 119 | 120 | public Boolean connectToServer() 121 | { 122 | if (tcp != null) 123 | { 124 | disconnect(); 125 | } 126 | tcp = new TcpClient(); 127 | tcp.NoDelay = true; 128 | try 129 | { 130 | if (tcp.ConnectAsync(host, port).Wait(1000)) 131 | { 132 | currentSeq = 0; 133 | netStream = tcp.GetStream(); 134 | heartbeatSendable = 1; 135 | packetRecvThread = new Task(packetRecvThreadStart); 136 | packetRecvThread.Start(); 137 | App.Connected = true; 138 | } 139 | else 140 | { 141 | App.Connected = false; 142 | } 143 | } 144 | catch 145 | { 146 | App.Connected = false; 147 | } 148 | 149 | return App.Connected; 150 | } 151 | 152 | public void disconnect(bool waitPacketThread = true) 153 | { 154 | try 155 | { 156 | if (tcp != null) 157 | { 158 | tcp.Dispose(); 159 | } 160 | if (waitPacketThread) 161 | { 162 | if (packetRecvThread != null) 163 | { 164 | packetRecvThread.Wait(); 165 | } 166 | } 167 | } 168 | catch { } 169 | tcp = null; 170 | App.Connected = false; 171 | } 172 | 173 | public void sendPacket(UInt32 type, UInt32 cmd, UInt32[] args, UInt32 dataLen) 174 | { 175 | int t = 0; 176 | currentSeq += 1000; 177 | byte[] buf = new byte[84]; 178 | BitConverter.GetBytes(0x12345678).CopyTo(buf, t); 179 | t += 4; 180 | BitConverter.GetBytes(currentSeq).CopyTo(buf, t); 181 | t += 4; 182 | BitConverter.GetBytes(type).CopyTo(buf, t); 183 | t += 4; 184 | BitConverter.GetBytes(cmd).CopyTo(buf, t); 185 | for (int i = 0; i < 16; i++) 186 | { 187 | t += 4; 188 | UInt32 arg = 0; 189 | if (args != null) 190 | { 191 | arg = args[i]; 192 | } 193 | BitConverter.GetBytes(arg).CopyTo(buf, t); 194 | } 195 | t += 4; 196 | BitConverter.GetBytes(dataLen).CopyTo(buf, t); 197 | try 198 | { 199 | netStream.Write(buf, 0, buf.Length); 200 | } 201 | catch (Exception) 202 | { 203 | } 204 | } 205 | 206 | public void sendWriteMemPacket(UInt32 addr, UInt32 pid, byte[] buf) 207 | { 208 | UInt32[] args = new UInt32[16]; 209 | args[0] = pid; 210 | args[1] = addr; 211 | args[2] = (UInt32)buf.Length; 212 | sendPacket(1, 10, args, args[2]); 213 | netStream.Write(buf, 0, buf.Length); 214 | } 215 | 216 | public void sendHeartbeatPacket() 217 | { 218 | if (App.Connected) 219 | { 220 | lock (syncLock) 221 | { 222 | if (heartbeatSendable == 1) 223 | { 224 | heartbeatSendable = 0; 225 | sendPacket(0, 0, null, 0); 226 | } 227 | else 228 | { 229 | timeout++; 230 | if (timeout == 5) 231 | { 232 | disconnect(false); 233 | } 234 | } 235 | } 236 | } 237 | 238 | } 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /UWPStreamer/Services/NTRInputRedirection.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework; 2 | using Microsoft.Xna.Framework.Graphics; 3 | using Microsoft.Xna.Framework.Input; 4 | using System; 5 | using System.IO; 6 | using System.Net; 7 | using UWPStreamer; 8 | using Windows.Storage; 9 | 10 | namespace InputRedirectionNTR 11 | { 12 | public class NTRInputRedirection 13 | { 14 | ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings; 15 | 16 | string ipAddress; 17 | byte[] data = new byte[12]; 18 | uint oldbuttons = 0xFFF; 19 | uint newbuttons = 0xFFF; 20 | uint oldtouch = 0x2000000; 21 | uint newtouch = 0x2000000; 22 | uint oldcpad = 0x800800; 23 | uint newcpad = 0x800800; 24 | uint touchclick = 0x00; 25 | uint cpadclick = 0x00; 26 | int Mode = 0; 27 | Keys[] ipKeysToCheck = { Keys.D0, Keys.D1, Keys.D2, Keys.D3, Keys.D4, Keys.D5, Keys.D6, Keys.D7, Keys.D8, Keys.D9, Keys.NumPad0, Keys.NumPad1, Keys.NumPad2, Keys.NumPad3, Keys.NumPad4, Keys.NumPad5, Keys.NumPad6, Keys.NumPad7, Keys.NumPad8, Keys.NumPad9, Keys.Decimal, Keys.OemPeriod, Keys.Back, Keys.Delete, Keys.Escape }; 28 | Keys[] buttonKeysToCheck = { Keys.A, Keys.B, Keys.RightShift, Keys.LeftShift, Keys.Enter, Keys.Right, Keys.Left, Keys.Up, Keys.Down, Keys.R, Keys.L, Keys.X, Keys.Y, Keys.Escape }; 29 | Keys[] KeyboardInput = { Keys.A, Keys.S, Keys.N, Keys.M, Keys.H, Keys.F, Keys.T, Keys.G, Keys.W, Keys.Q, Keys.Z, Keys.X, Keys.Right, Keys.Left, Keys.Up, Keys.Down }; 30 | uint[] GamePadInput = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x020, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800 }; 31 | string[] ButtonNames = { "A", "B", "Select", "Start", "DPad Right", "DPad Left", "DPad Up", "DPad Down", "R", "L", "X", "Y" }; 32 | Keys UpKey; 33 | bool WaitForKeyUp; 34 | bool debug = false; 35 | KeyboardState keyboardState; 36 | GamePadState gamePadState; 37 | uint KeyIndex; 38 | uint OldButton; 39 | public bool useGamePad = true; 40 | 41 | public NTRInputRedirection() 42 | { 43 | ipAddress = localSettings.Values["ip"].ToString(); 44 | } 45 | 46 | public void CheckConnection() 47 | { 48 | if (!App.Connected) 49 | { 50 | App.scriptHelper.connect(ipAddress, 8000); 51 | } 52 | } 53 | 54 | public void ReadMain() 55 | { 56 | if (!WaitForKeyUp) 57 | { 58 | if (Keyboard.GetState().IsKeyDown(Keys.F1)) 59 | { 60 | WaitForKeyUp = true; 61 | UpKey = Keys.F1; 62 | Mode = 1; 63 | } 64 | 65 | if (Keyboard.GetState().IsKeyDown(Keys.F2)) 66 | { 67 | WaitForKeyUp = true; 68 | UpKey = Keys.F2; 69 | Mode = 2; 70 | } 71 | 72 | if (Keyboard.GetState().IsKeyDown(Keys.F3)) 73 | { 74 | WaitForKeyUp = true; 75 | UpKey = Keys.F3; 76 | Mode = 3; 77 | } 78 | 79 | if (Keyboard.GetState().IsKeyDown(Keys.F4)) 80 | { 81 | WaitForKeyUp = true; 82 | UpKey = Keys.F4; 83 | debug = !debug; 84 | 85 | } 86 | 87 | if (Keyboard.GetState().IsKeyDown(Keys.F5)) 88 | { 89 | WaitForKeyUp = true; 90 | UpKey = Keys.F5; 91 | useGamePad = !useGamePad; 92 | 93 | } 94 | } 95 | else 96 | { 97 | if (Keyboard.GetState().IsKeyUp(UpKey)) 98 | { 99 | WaitForKeyUp = false; 100 | } 101 | } 102 | 103 | keyboardState = Keyboard.GetState(); 104 | gamePadState = GamePad.GetState(PlayerIndex.One); 105 | newbuttons = 0x00; 106 | //Keyboard 107 | for (int i = 0; i < GamePadInput.Length; i++) 108 | { 109 | if (keyboardState.IsKeyDown(KeyboardInput[i])) 110 | { 111 | newbuttons += (uint)(0x01 << i); 112 | } 113 | } 114 | 115 | //GamePad 116 | if (useGamePad) 117 | { 118 | if (GamePad.GetState(PlayerIndex.One).Buttons.B == ButtonState.Pressed) 119 | { 120 | if ((newbuttons & GamePadInput[0]) != GamePadInput[0]) 121 | { 122 | newbuttons += GamePadInput[0]; 123 | } 124 | } 125 | 126 | if (GamePad.GetState(PlayerIndex.One).Buttons.A == ButtonState.Pressed) 127 | { 128 | if ((newbuttons & GamePadInput[1]) != GamePadInput[1]) 129 | { 130 | newbuttons += GamePadInput[1]; 131 | } 132 | } 133 | 134 | 135 | if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) 136 | { 137 | if ((newbuttons & GamePadInput[2]) != GamePadInput[2]) 138 | { 139 | newbuttons += GamePadInput[2]; 140 | } 141 | } 142 | 143 | if (GamePad.GetState(PlayerIndex.One).Buttons.Start == ButtonState.Pressed) 144 | { 145 | if ((newbuttons & GamePadInput[3]) != GamePadInput[3]) 146 | { 147 | newbuttons += GamePadInput[3]; 148 | } 149 | } 150 | 151 | if (GamePad.GetState(PlayerIndex.One).DPad.Right == ButtonState.Pressed) 152 | { 153 | if ((newbuttons & GamePadInput[4]) != GamePadInput[4]) 154 | { 155 | newbuttons += GamePadInput[4]; 156 | } 157 | } 158 | 159 | if (GamePad.GetState(PlayerIndex.One).DPad.Left == ButtonState.Pressed) 160 | { 161 | if ((newbuttons & GamePadInput[5]) != GamePadInput[5]) 162 | { 163 | newbuttons += GamePadInput[5]; 164 | } 165 | } 166 | 167 | if (GamePad.GetState(PlayerIndex.One).DPad.Up == ButtonState.Pressed) 168 | { 169 | if ((newbuttons & GamePadInput[6]) != GamePadInput[6]) 170 | { 171 | newbuttons += GamePadInput[6]; 172 | } 173 | } 174 | 175 | if (GamePad.GetState(PlayerIndex.One).DPad.Down == ButtonState.Pressed) 176 | { 177 | if ((newbuttons & GamePadInput[7]) != GamePadInput[7]) 178 | { 179 | newbuttons += GamePadInput[7]; 180 | } 181 | } 182 | 183 | if (GamePad.GetState(PlayerIndex.One).Buttons.RightShoulder == ButtonState.Pressed) 184 | { 185 | if ((newbuttons & GamePadInput[8]) != GamePadInput[8]) 186 | { 187 | newbuttons += GamePadInput[8]; 188 | } 189 | } 190 | 191 | if (GamePad.GetState(PlayerIndex.One).Buttons.LeftShoulder == ButtonState.Pressed) 192 | { 193 | if ((newbuttons & GamePadInput[9]) != GamePadInput[9]) 194 | { 195 | newbuttons += GamePadInput[9]; 196 | } 197 | } 198 | 199 | if (GamePad.GetState(PlayerIndex.One).Buttons.Y == ButtonState.Pressed) 200 | { 201 | if ((newbuttons & GamePadInput[10]) != GamePadInput[10]) 202 | { 203 | newbuttons += GamePadInput[10]; 204 | } 205 | } 206 | 207 | if (GamePad.GetState(PlayerIndex.One).Buttons.X == ButtonState.Pressed) 208 | { 209 | if ((newbuttons & GamePadInput[11]) != GamePadInput[11]) 210 | { 211 | newbuttons += GamePadInput[11]; 212 | } 213 | } 214 | } 215 | 216 | newbuttons ^= 0xFFF; 217 | 218 | touchclick = 0x00; 219 | if (useGamePad) 220 | { 221 | if (GamePad.GetState(PlayerIndex.One).Buttons.RightStick == ButtonState.Pressed) 222 | { 223 | newtouch = (uint)Math.Round(2047.5 + (GamePad.GetState(PlayerIndex.One).ThumbSticks.Right.X * 2047.5)); 224 | newtouch += (uint)Math.Round(2047.5 + (-GamePad.GetState(PlayerIndex.One).ThumbSticks.Right.Y * 2047.5)) << 0x0C; 225 | newtouch += 0x1000000; 226 | } 227 | else 228 | { 229 | newtouch = 0x2000000; 230 | } 231 | } 232 | else 233 | { 234 | newtouch = 0x2000000; 235 | } 236 | 237 | 238 | cpadclick = 0x00; 239 | newcpad = (uint)Math.Round(2047.5 + (GamePad.GetState(PlayerIndex.One).ThumbSticks.Left.X * 2047.5)); 240 | newcpad += (uint)Math.Round(4095 - (2047.5 + (-GamePad.GetState(PlayerIndex.One).ThumbSticks.Left.Y * 2047.5))) << 0x0C; 241 | 242 | if (newcpad == 0x800800) 243 | { 244 | 245 | if (Keyboard.GetState().IsKeyDown(KeyboardInput[12])) 246 | { 247 | newcpad = 0xFFF + (((newcpad >> 0x0C) & 0xFFF) << 0x0C); 248 | } 249 | 250 | if (Keyboard.GetState().IsKeyDown(KeyboardInput[13])) 251 | { 252 | newcpad = (((newcpad >> 0x0C) & 0xFFF) << 0x0C); 253 | } 254 | 255 | if (Keyboard.GetState().IsKeyDown(KeyboardInput[15])) 256 | { 257 | newcpad = (newcpad & 0xFFF) + (0x00 << 0x0C); 258 | } 259 | 260 | if (Keyboard.GetState().IsKeyDown(KeyboardInput[14])) 261 | { 262 | newcpad = (newcpad & 0xFFF) + (0xFFF << 0x0C); 263 | } 264 | } 265 | 266 | if (newcpad != 0x800800) 267 | { 268 | newcpad += 0x1000000; 269 | } 270 | 271 | SendInput(); 272 | } 273 | 274 | private string GetButtonNameFromValue(uint value) 275 | { 276 | string result = "None"; 277 | 278 | for (int i = 0; i < ButtonNames.Length; i++) 279 | { 280 | if ((value >> i) == 0x01) 281 | { 282 | result = ButtonNames[i]; 283 | break; 284 | } 285 | } 286 | 287 | return result; 288 | } 289 | 290 | private void SendInput() 291 | { 292 | if ((newbuttons != oldbuttons) || (newtouch != oldtouch) || (newcpad != oldcpad)) 293 | { 294 | oldbuttons = newbuttons; 295 | oldtouch = newtouch; 296 | oldcpad = newcpad; 297 | 298 | //Buttons 299 | data[0x00] = (byte)(oldbuttons & 0xFF); 300 | data[0x01] = (byte)((oldbuttons >> 0x08) & 0xFF); 301 | data[0x02] = (byte)((oldbuttons >> 0x10) & 0xFF); 302 | data[0x03] = (byte)((oldbuttons >> 0x18) & 0xFF); 303 | 304 | //Touch 305 | data[0x04] = (byte)(oldtouch & 0xFF); 306 | data[0x05] = (byte)((oldtouch >> 0x08) & 0xFF); 307 | data[0x06] = (byte)((oldtouch >> 0x10) & 0xFF); 308 | data[0x07] = (byte)((oldtouch >> 0x18) & 0xFF); 309 | 310 | //CPad 311 | data[0x08] = (byte)(oldcpad & 0xFF); 312 | data[0x09] = (byte)((oldcpad >> 0x08) & 0xFF); 313 | data[0x0A] = (byte)((oldcpad >> 0x10) & 0xFF); 314 | data[0x0B] = (byte)((oldcpad >> 0x18) & 0xFF); 315 | 316 | CheckConnection(); 317 | if (App.Connected) 318 | { 319 | App.scriptHelper.write(0x10DF20, data, 0x10); 320 | } 321 | } 322 | } 323 | } 324 | } 325 | -------------------------------------------------------------------------------- /UWPStreamer/Services/ScriptHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UWPStreamer; 3 | 4 | namespace InputRedirectionNTR 5 | { 6 | public class ScriptHelper 7 | { 8 | public Boolean connect(string host, int port) 9 | { 10 | App.ntrClient.setServer(host, port); 11 | return App.ntrClient.connectToServer(); 12 | } 13 | 14 | public void disconnect() 15 | { 16 | App.ntrClient.disconnect(); 17 | } 18 | 19 | public void write(uint addr, byte[] buf, int pid = -1) 20 | { 21 | App.ntrClient.sendWriteMemPacket(addr, (uint)pid, buf); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /UWPStreamer/SettingsDialog.xaml: -------------------------------------------------------------------------------- 1 |  14 | 15 | 16 | 17 | 18 | Top Screen 19 | Bottom Screen 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /UWPStreamer/SettingsDialog.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices.WindowsRuntime; 6 | using Windows.Foundation; 7 | using Windows.Foundation.Collections; 8 | using Windows.Storage; 9 | using Windows.UI.Xaml; 10 | using Windows.UI.Xaml.Controls; 11 | using Windows.UI.Xaml.Controls.Primitives; 12 | using Windows.UI.Xaml.Data; 13 | using Windows.UI.Xaml.Input; 14 | using Windows.UI.Xaml.Media; 15 | using Windows.UI.Xaml.Navigation; 16 | 17 | // The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238 18 | 19 | namespace UWPStreamer 20 | { 21 | /// 22 | /// An empty page that can be used on its own or navigated to within a Frame. 23 | /// 24 | public sealed partial class SettingsDialog : ContentDialog 25 | { 26 | 27 | public bool ConnectSelected = false; 28 | 29 | public SettingsDialog() 30 | { 31 | this.InitializeComponent(); 32 | LoadSettings(); 33 | } 34 | 35 | private void LoadSettings() 36 | { 37 | var localSettings = ApplicationData.Current.LocalSettings; 38 | 39 | 40 | //defaults 41 | if (!localSettings.Values.ContainsKey("ip")) 42 | localSettings.Values["ip"] = "0.0.0.0"; 43 | if (!localSettings.Values.ContainsKey("priorityMode")) 44 | localSettings.Values["priorityMode"] = 1; 45 | if (!localSettings.Values.ContainsKey("priorityFactor")) 46 | localSettings.Values["priorityFactor"] = 1; 47 | if (!localSettings.Values.ContainsKey("quality")) 48 | localSettings.Values["quality"] = 75; 49 | if (!localSettings.Values.ContainsKey("qosValue")) 50 | localSettings.Values["qosValue"] = 15; 51 | if (!localSettings.Values.ContainsKey("autoConnect")) 52 | localSettings.Values["autoConnect"] = true; 53 | 54 | ipAdressTextBox.Text = (string)localSettings.Values["ip"]; 55 | screenPriorityComboBox.SelectedIndex = 1 - (int)localSettings.Values["priorityMode"]; 56 | priorityFactorTextBox.Text = localSettings.Values["priorityFactor"].ToString(); 57 | imageQualityTextBox.Text = localSettings.Values["quality"].ToString(); 58 | qosValueTextBox.Text = localSettings.Values["qosValue"].ToString(); 59 | autoConnectCheckBox.IsChecked = (bool)localSettings.Values["autoConnect"]; 60 | } 61 | 62 | private void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args) 63 | { 64 | if(saveSettingsCheckBox.IsChecked.Value) 65 | { 66 | SaveSettings(); 67 | } 68 | 69 | ConnectSelected = true; 70 | } 71 | 72 | private void SaveSettings() 73 | { 74 | var localSettings = ApplicationData.Current.LocalSettings; 75 | localSettings.Values["ip"] = ipAdressTextBox.Text; 76 | localSettings.Values["priorityMode"] = 1 - screenPriorityComboBox.SelectedIndex; 77 | localSettings.Values["priorityFactor"] = priorityFactorTextBox.Text; 78 | localSettings.Values["quality"] = imageQualityTextBox.Text; 79 | localSettings.Values["qosValue"] = qosValueTextBox.Text; 80 | localSettings.Values["autoConnect"] = autoConnectCheckBox.IsChecked; 81 | } 82 | 83 | private void ContentDialog_SecondaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args) 84 | { 85 | ConnectSelected = false; 86 | } 87 | 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /UWPStreamer/UWPStreamer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x86 7 | {D727D4AB-F232-4A63-B248-4ECF2A74D940} 8 | AppContainerExe 9 | Properties 10 | UWPStreamer 11 | UWPStreamer 12 | en-US 13 | UAP 14 | 10.0.14393.0 15 | 10.0.14393.0 16 | 14 17 | 512 18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 19 | UWPStreamer_StoreKey.pfx 20 | 1920CC1A3148621F5C6016AFEE9E50C380C34087 21 | False 22 | Always 23 | x86|x64|arm 24 | 25 | 26 | true 27 | bin\x86\Debug\ 28 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 29 | ;2008 30 | full 31 | x86 32 | false 33 | prompt 34 | true 35 | 36 | 37 | bin\x86\Release\ 38 | TRACE;NETFX_CORE;WINDOWS_UWP 39 | true 40 | ;2008 41 | pdbonly 42 | x86 43 | false 44 | prompt 45 | true 46 | true 47 | 48 | 49 | true 50 | bin\ARM\Debug\ 51 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 52 | ;2008 53 | full 54 | ARM 55 | false 56 | prompt 57 | true 58 | 59 | 60 | bin\ARM\Release\ 61 | TRACE;NETFX_CORE;WINDOWS_UWP 62 | true 63 | ;2008 64 | pdbonly 65 | ARM 66 | false 67 | prompt 68 | true 69 | true 70 | 71 | 72 | true 73 | bin\x64\Debug\ 74 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 75 | ;2008 76 | full 77 | x64 78 | false 79 | prompt 80 | true 81 | 82 | 83 | bin\x64\Release\ 84 | TRACE;NETFX_CORE;WINDOWS_UWP 85 | true 86 | ;2008 87 | pdbonly 88 | x64 89 | false 90 | prompt 91 | true 92 | true 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | App.xaml 101 | 102 | 103 | 104 | MainPage.xaml 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | SettingsDialog.xaml 113 | 114 | 115 | 116 | 117 | Designer 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | MSBuild:Compile 142 | Designer 143 | 144 | 145 | MSBuild:Compile 146 | Designer 147 | 148 | 149 | Designer 150 | MSBuild:Compile 151 | 152 | 153 | 154 | 14.0 155 | 156 | 157 | 164 | -------------------------------------------------------------------------------- /UWPStreamer/_pkginfo.txt: -------------------------------------------------------------------------------- 1 | C:\Github\UWPStreamer\UWPStreamer\AppPackages\UWPStreamer_1.1.12.0\UWPStreamer_1.1.12.0_x86_x64_arm.appxbundle 2 | -------------------------------------------------------------------------------- /UWPStreamer/_scale-100.appx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/_scale-100.appx -------------------------------------------------------------------------------- /UWPStreamer/_scale-125.appx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/_scale-125.appx -------------------------------------------------------------------------------- /UWPStreamer/_scale-150.appx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/_scale-150.appx -------------------------------------------------------------------------------- /UWPStreamer/_scale-400.appx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toolboc/UWPStreamer/f396260cadf8f9271126990e59562fee2070d08a/UWPStreamer/_scale-400.appx -------------------------------------------------------------------------------- /UWPStreamer/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "Microsoft.NETCore.UniversalWindowsPlatform": "5.2.2", 4 | "MonoGame.Framework.WindowsUniversal": "3.5.1.1679" 5 | }, 6 | "frameworks": { 7 | "uap10.0": {} 8 | }, 9 | "runtimes": { 10 | "win10-arm": {}, 11 | "win10-arm-aot": {}, 12 | "win10-x86": {}, 13 | "win10-x86-aot": {}, 14 | "win10-x64": {}, 15 | "win10-x64-aot": {} 16 | } 17 | } -------------------------------------------------------------------------------- /WPFStreamer/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 0.0.0.0 15 | 16 | 17 | 1 18 | 19 | 20 | 1 21 | 22 | 23 | 75 24 | 25 | 26 | 15 27 | 28 | 29 | False 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /WPFStreamer/App.xaml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /WPFStreamer/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using InputRedirectionNTR; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Configuration; 5 | using System.Data; 6 | using System.Linq; 7 | using System.Threading.Tasks; 8 | using System.Windows; 9 | using UWPStreamer.Services; 10 | 11 | namespace WPFStreamer 12 | { 13 | /// 14 | /// Interaction logic for App.xaml 15 | /// 16 | public partial class App : Application 17 | { 18 | public static NTRClient ntrClient =new NTRClient(); 19 | public static ScriptHelper scriptHelper = new ScriptHelper(); 20 | public static Boolean Connected = false; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /WPFStreamer/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /WPFStreamer/Helpers/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace UWPStreamer.Helpers 8 | { 9 | public static class Extensions 10 | { 11 | public static byte[] StringToByteArray(this String hex) 12 | { 13 | return Enumerable.Range(0, hex.Length) 14 | .Where(x => x % 2 == 0) 15 | .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) 16 | .ToArray(); 17 | } 18 | 19 | /// 20 | /// Get the array slice between the two indexes. 21 | /// ... Inclusive for start index, exclusive for end index. 22 | /// 23 | public static T[] Slice(this T[] source, int start, int end) 24 | { 25 | // Handles negative ends. 26 | if (end < 0) 27 | { 28 | end = source.Length + end; 29 | } 30 | int len = end - start; 31 | 32 | // Return new array. 33 | T[] res = new T[len]; 34 | for (int i = 0; i < len; i++) 35 | { 36 | res[i] = source[i + start]; 37 | } 38 | return res; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /WPFStreamer/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 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 | Top Screen 79 | Bottom Screen 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 |