├── .gitignore ├── LICENSE ├── README.md ├── appveyor.yml ├── build_appveyor.ps1 ├── dotnet-curses.sln ├── dotnet-curses ├── Constants │ ├── CursesAttribute.cs │ ├── CursesColor.cs │ ├── CursesCursorState.cs │ ├── CursesKey.cs │ ├── CursesLineAcs.cs │ ├── CursesMouseEvent.cs │ └── CursesSoftKeyLabelPosition.cs ├── NativeLibraryLoader │ ├── Kernel32.cs │ ├── LibraryLoader.cs │ ├── NativeLibrary.cs │ ├── PathResolver.cs │ ├── libdl_linux.cs │ └── libdl_osx.cs ├── NativeWrapper │ ├── MouseEvent.cs │ ├── Native.cs │ ├── NativeCommon.cs │ ├── NativeEnvironment.cs │ ├── NativePad.cs │ ├── NativeProperties.cs │ └── NativeWindow.cs ├── PublicApi │ ├── NCursesCommon.cs │ ├── NCursesEnvironment.cs │ ├── NCursesLibraryHandle.cs │ ├── NCursesPad.cs │ ├── NCursesProperties.cs │ └── NCursesWindow.cs ├── Support │ ├── CursesLibraryNames.cs │ ├── DotnetCursesException.cs │ └── NativeExceptionHelper.cs └── dotnet-curses.csproj ├── sample-fireworks ├── MoreCursesLibraryNames.cs ├── Program.cs └── sample-fireworks.csproj └── sample-mouse ├── Program.cs └── sample-mouse.csproj /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015/2017 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # Visual Studio 2017 auto generated files 33 | Generated\ Files/ 34 | 35 | # MSTest test Results 36 | [Tt]est[Rr]esult*/ 37 | [Bb]uild[Ll]og.* 38 | 39 | # NUNIT 40 | *.VisualState.xml 41 | TestResult.xml 42 | 43 | # Build Results of an ATL Project 44 | [Dd]ebugPS/ 45 | [Rr]eleasePS/ 46 | dlldata.c 47 | 48 | # Benchmark Results 49 | BenchmarkDotNet.Artifacts/ 50 | 51 | # .NET Core 52 | project.lock.json 53 | project.fragment.lock.json 54 | artifacts/ 55 | **/Properties/launchSettings.json 56 | 57 | # StyleCop 58 | StyleCopReport.xml 59 | 60 | # Files built by Visual Studio 61 | *_i.c 62 | *_p.c 63 | *_i.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.iobj 68 | *.pch 69 | *.pdb 70 | *.ipdb 71 | *.pgc 72 | *.pgd 73 | *.rsp 74 | *.sbr 75 | *.tlb 76 | *.tli 77 | *.tlh 78 | *.tmp 79 | *.tmp_proj 80 | *.log 81 | *.vspscc 82 | *.vssscc 83 | .builds 84 | *.pidb 85 | *.svclog 86 | *.scc 87 | 88 | # Chutzpah Test files 89 | _Chutzpah* 90 | 91 | # Visual C++ cache files 92 | ipch/ 93 | *.aps 94 | *.ncb 95 | *.opendb 96 | *.opensdf 97 | *.sdf 98 | *.cachefile 99 | *.VC.db 100 | *.VC.VC.opendb 101 | 102 | # Visual Studio profiler 103 | *.psess 104 | *.vsp 105 | *.vspx 106 | *.sap 107 | 108 | # Visual Studio Trace Files 109 | *.e2e 110 | 111 | # TFS 2012 Local Workspace 112 | $tf/ 113 | 114 | # Guidance Automation Toolkit 115 | *.gpState 116 | 117 | # ReSharper is a .NET coding add-in 118 | _ReSharper*/ 119 | *.[Rr]e[Ss]harper 120 | *.DotSettings.user 121 | 122 | # JustCode is a .NET coding add-in 123 | .JustCode 124 | 125 | # TeamCity is a build add-in 126 | _TeamCity* 127 | 128 | # DotCover is a Code Coverage Tool 129 | *.dotCover 130 | 131 | # AxoCover is a Code Coverage Tool 132 | .axoCover/* 133 | !.axoCover/settings.json 134 | 135 | # Visual Studio code coverage results 136 | *.coverage 137 | *.coveragexml 138 | 139 | # NCrunch 140 | _NCrunch_* 141 | .*crunch*.local.xml 142 | nCrunchTemp_* 143 | 144 | # MightyMoose 145 | *.mm.* 146 | AutoTest.Net/ 147 | 148 | # Web workbench (sass) 149 | .sass-cache/ 150 | 151 | # Installshield output folder 152 | [Ee]xpress/ 153 | 154 | # DocProject is a documentation generator add-in 155 | DocProject/buildhelp/ 156 | DocProject/Help/*.HxT 157 | DocProject/Help/*.HxC 158 | DocProject/Help/*.hhc 159 | DocProject/Help/*.hhk 160 | DocProject/Help/*.hhp 161 | DocProject/Help/Html2 162 | DocProject/Help/html 163 | 164 | # Click-Once directory 165 | publish/ 166 | 167 | # Publish Web Output 168 | *.[Pp]ublish.xml 169 | *.azurePubxml 170 | # Note: Comment the next line if you want to checkin your web deploy settings, 171 | # but database connection strings (with potential passwords) will be unencrypted 172 | *.pubxml 173 | *.publishproj 174 | 175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 176 | # checkin your Azure Web App publish settings, but sensitive information contained 177 | # in these scripts will be unencrypted 178 | PublishScripts/ 179 | 180 | # NuGet Packages 181 | *.nupkg 182 | # The packages folder can be ignored because of Package Restore 183 | **/[Pp]ackages/* 184 | # except build/, which is used as an MSBuild target. 185 | !**/[Pp]ackages/build/ 186 | # Uncomment if necessary however generally it will be regenerated when needed 187 | #!**/[Pp]ackages/repositories.config 188 | # NuGet v3's project.json files produces more ignorable files 189 | *.nuget.props 190 | *.nuget.targets 191 | 192 | # Microsoft Azure Build Output 193 | csx/ 194 | *.build.csdef 195 | 196 | # Microsoft Azure Emulator 197 | ecf/ 198 | rcf/ 199 | 200 | # Windows Store app package directories and files 201 | AppPackages/ 202 | BundleArtifacts/ 203 | Package.StoreAssociation.xml 204 | _pkginfo.txt 205 | *.appx 206 | 207 | # Visual Studio cache files 208 | # files ending in .cache can be ignored 209 | *.[Cc]ache 210 | # but keep track of directories ending in .cache 211 | !*.[Cc]ache/ 212 | 213 | # Others 214 | ClientBin/ 215 | ~$* 216 | *~ 217 | *.dbmdl 218 | *.dbproj.schemaview 219 | *.jfm 220 | *.pfx 221 | *.publishsettings 222 | orleans.codegen.cs 223 | 224 | # Including strong name files can present a security risk 225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 226 | #*.snk 227 | 228 | # Since there are multiple workflows, uncomment next line to ignore bower_components 229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 230 | #bower_components/ 231 | 232 | # RIA/Silverlight projects 233 | Generated_Code/ 234 | 235 | # Backup & report files from converting an old project file 236 | # to a newer Visual Studio version. Backup files are not needed, 237 | # because we have git ;-) 238 | _UpgradeReport_Files/ 239 | Backup*/ 240 | UpgradeLog*.XML 241 | UpgradeLog*.htm 242 | ServiceFabricBackup/ 243 | *.rptproj.bak 244 | 245 | # SQL Server files 246 | *.mdf 247 | *.ldf 248 | *.ndf 249 | 250 | # Business Intelligence projects 251 | *.rdl.data 252 | *.bim.layout 253 | *.bim_*.settings 254 | *.rptproj.rsuser 255 | 256 | # Microsoft Fakes 257 | FakesAssemblies/ 258 | 259 | # GhostDoc plugin setting file 260 | *.GhostDoc.xml 261 | 262 | # Node.js Tools for Visual Studio 263 | .ntvs_analysis.dat 264 | node_modules/ 265 | 266 | # Visual Studio 6 build log 267 | *.plg 268 | 269 | # Visual Studio 6 workspace options file 270 | *.opt 271 | 272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 273 | *.vbw 274 | 275 | # Visual Studio LightSwitch build output 276 | **/*.HTMLClient/GeneratedArtifacts 277 | **/*.DesktopClient/GeneratedArtifacts 278 | **/*.DesktopClient/ModelManifest.xml 279 | **/*.Server/GeneratedArtifacts 280 | **/*.Server/ModelManifest.xml 281 | _Pvt_Extensions 282 | 283 | # Paket dependency manager 284 | .paket/paket.exe 285 | paket-files/ 286 | 287 | # FAKE - F# Make 288 | .fake/ 289 | 290 | # JetBrains Rider 291 | .idea/ 292 | *.sln.iml 293 | 294 | # CodeRush 295 | .cr/ 296 | 297 | # Python Tools for Visual Studio (PTVS) 298 | __pycache__/ 299 | *.pyc 300 | 301 | # Cake - Uncomment if you are using it 302 | # tools/** 303 | # !tools/packages.config 304 | 305 | # Tabs Studio 306 | *.tss 307 | 308 | # Telerik's JustMock configuration file 309 | *.jmconfig 310 | 311 | # BizTalk build output 312 | *.btp.cs 313 | *.btm.cs 314 | *.odx.cs 315 | *.xsd.cs 316 | 317 | # OpenCover UI analysis results 318 | OpenCover/ 319 | 320 | # Azure Stream Analytics local run output 321 | ASALocalRun/ 322 | 323 | # MSBuild Binary and Structured Log 324 | *.binlog 325 | 326 | # NVidia Nsight GPU debugger configuration file 327 | *.nvuser 328 | 329 | # MFractors (Xamarin productivity tool) working folder 330 | .mfractor/ 331 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Jon McGuire 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dotnet-curses [![NuGet](https://img.shields.io/nuget/v/dotnet-curses.svg)](https://nuget.org/packages/dotnet-curses) 2 | This is an easy-to-use, fully cross-platform .NET Standard 2.0 wrapper for the Unix NCurses terminal library. The project is able to load the OS-specific native implementation of NCurses at runtime which means you can deploy the same binary to Windows, Linux, or OSX. Most other .NET wrappers use statically-defined references to the native implementation, requiring different builds for different OSes. 3 | 4 | > "Wrapper" means this package DOES NOT include the curses library itself. See _The Native Curses Library_ section below for details. 5 | 6 | ## Usage 7 | This library assumes your application will be compiled as a portable executable. That results in a DLL that can run on Windows, Linux, or OSX, and this library works the same way. At runtime it detects the OS and loads the native OS version of the curses library. Later sections explain how to get the correct .NET runtime on Linux or OSX, where to find an ncurses implementation for Windows, and what to do if ncurses on your OS uses a non-standard library name (generally only a problem on Linux). 8 | 9 | In your own program, you're mainly calling static methods exposed by the `NCurses` class in the `Mindmagma.Curses` namespace. I recommend browsing the `NCurses` class in the Visual Studio object browser window to see exactly what is available (at the time of writing, 91 API calls are available). 10 | 11 | Please restrict opening issues in this repo to topics specific to this project, not about curses in general. For assistance with the curses API itself, questions tagged `ncurses` on [StackOverflow](https://stackoverflow.com/questions/tagged/ncurses) seem to be answered pretty quickly. 12 | 13 | How to use the curses API itself is beyond the scope of this README. I recommend reading either [this](http://www.ibiblio.org/pub/Linux/docs/HOWTO/other-formats/html_single/NCURSES-Programming-HOWTO.html) high-level introduction or the much longer article by Eric S. Raymond [here](https://invisible-island.net/ncurses/ncurses-intro.html). However, a typical start-up sequence using this package might look like this: 14 | 15 | ```csharp 16 | var Screen = NCurses.InitScreen(); 17 | NCurses.NoDelay(Screen, true); 18 | NCurses.NoEcho(); 19 | ``` 20 | 21 | ## The .NET Runtime 22 | The target OS doesn't need to install the developer-oriented .NET SDK. Instead, a much smaller, machine-wide .NET runtime can be installed. For Windows, there is a simple installer [here](https://www.microsoft.com/net/download?initial-os=windows). The same is true of OSX, download an installer [here](https://www.microsoft.com/net/download?initial-os=macos). 23 | 24 | As usual, Linux makes it complicated. Your best bet is to read the documentation about preprequisites [here](https://docs.microsoft.com/en-us/dotnet/core/linux-prerequisites?tabs=netcore2x) and follow the instructions that match your distro. Because distros can vary considerably even between minor releases, you should try to match your _exact_ distro and version for the best chances of success. 25 | 26 | ## The Native Curses Library 27 | OSX always installs ncurses. Linux distros _almost_ always do (if yours does not, unfortunately I probably can't help you). 28 | 29 | For Windows, download it from Thomas Dickey’s site (the current ncurses maintainer) from the 64-bit link under the "MinGW Ports" heading on [this page](https://invisible-island.net/ncurses/#download_mingw), and extract the DLLs anywhere in your `%PATH%`. 30 | 31 | ## Non-Standard Curses Library Filenames 32 | Various platforms, releases and distributions have used different filenames for the curses library. On OSX it usually includes the major version number, and on Linux it's common to include the major and minor version numbers. Windows has never included a cursors implementation, although Thomas Dickey's builds are the de facto standard. 33 | 34 | The _dotnet-curses_ library contains a list of defaults for each platform that are very likely to work. However, if you want to add to these or even replace one or more lists entirely, simply add a class to your project that derives from `CursesLibraryNames` and use one or more of the following: 35 | 36 | ```csharp 37 | public override bool ReplaceWindowsDefaults => true; 38 | public override bool ReplaceLinuxDefaults => true; 39 | public override bool ReplaceOSXDefaults => true; 40 | public override List NamesWindows => new List { "abc.dll", "xyz.dll" }; 41 | public override List NamesLinux => new List { "abc.1.5.so", "abc.so" }; 42 | public override List NamesOSX => new List { "xyz5.dylib", "xyz.dylib" }; 43 | ``` 44 | 45 | The "Replace" properties are false by default. If you leave it at the default but override the corresponding name list, those names will be **added** to the _dotnet-curses_ default list. However, if you override and set a "Replace" property to true, the built-in defaults will be ignored, and only the names you provide will be used. 46 | 47 | Currently the names built into _dotnet-curses_ are as follows and should work for most target environments: 48 | 49 | - Windows: `libncursesw6.dll` 50 | - Linux: `libncurses.so.5.9`, `libncurses.so` 51 | - OSX: `libncurses.dylib` 52 | 53 | ## Native Library Loader 54 | This project includes a separate slightly-modified copy of Eric Mellinoe's [_NativeLibraryLoader_](https://github.com/mellinoe/nativelibraryloader/) project. The project is serving as a prototype for implementing improved native library support directly in a future version of .NET Core (probably 2.2). It was actually incorporated into the _dotnet-curses_ codebase because the dotnet nuget packaging process currently isn't smart enough to combine two projects into a single package. 55 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: '{build}' 2 | skip_tags: true 3 | image: Visual Studio 2017 4 | configuration: Release 5 | build_script: 6 | - ps: ./build_appveyor.ps1 7 | test: off 8 | artifacts: 9 | - path: artifacts/dotnet-curses*.nupkg 10 | only_commits: 11 | files: 12 | - dotnet-curses.sln 13 | - dotnet-curses/ 14 | deploy: 15 | - provider: NuGet 16 | api_key: 17 | secure: UDW8eHW8VDRzr9YolMr6Cs2h6BaieEJvQASj/2xU1x+hG0LLZ8I6d2k0pQRl3oVi 18 | skip_symbols: true 19 | on: 20 | branch: master 21 | - provider: GitHub 22 | auth_token: 23 | secure: +EUQOpgfGayDA+QMrOqaI9wi2mUYdI3RrTU2hJNTMAIfBm/HAIQkCPxIGx+8nDeA 24 | artifact: artifacts/dotnet-curses*.nupkg/ 25 | tag: v$(appveyor_build_version) 26 | on: 27 | branch: master 28 | -------------------------------------------------------------------------------- /build_appveyor.ps1: -------------------------------------------------------------------------------- 1 | echo "build: Build started" 2 | 3 | Push-Location $PSScriptRoot 4 | 5 | if(Test-Path .\artifacts) { 6 | echo "build: Cleaning .\artifacts" 7 | Remove-Item .\artifacts -Force -Recurse 8 | } 9 | 10 | & dotnet restore --no-cache 11 | 12 | $branch = @{ $true = $env:APPVEYOR_REPO_BRANCH; $false = $(git symbolic-ref --short -q HEAD) }[$env:APPVEYOR_REPO_BRANCH -ne $NULL]; 13 | $revision = @{ $true = "{0:00000}" -f [convert]::ToInt32("0" + $env:APPVEYOR_BUILD_NUMBER, 10); $false = "local" }[$env:APPVEYOR_BUILD_NUMBER -ne $NULL]; 14 | 15 | $src = "./dotnet-curses" 16 | Push-Location $src 17 | 18 | echo "build: Packaging project in $src" 19 | 20 | & dotnet pack -c Release -o ..\artifacts --include-source 21 | if($LASTEXITCODE -ne 0) { exit 1 } 22 | 23 | Pop-Location 24 | 25 | Pop-Location 26 | -------------------------------------------------------------------------------- /dotnet-curses.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28010.2003 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-curses", "dotnet-curses\dotnet-curses.csproj", "{E55049C5-B02B-406D-BF19-6A7BC4E17F0D}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "sample-fireworks", "sample-fireworks\sample-fireworks.csproj", "{0D898BD9-91CF-45C9-ACE7-B42F062094F4}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "sample-mouse", "sample-mouse\sample-mouse.csproj", "{8B237AEF-6B72-4223-9A9B-0A9F54A17AFF}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {E55049C5-B02B-406D-BF19-6A7BC4E17F0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {E55049C5-B02B-406D-BF19-6A7BC4E17F0D}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {E55049C5-B02B-406D-BF19-6A7BC4E17F0D}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {E55049C5-B02B-406D-BF19-6A7BC4E17F0D}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {0D898BD9-91CF-45C9-ACE7-B42F062094F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {0D898BD9-91CF-45C9-ACE7-B42F062094F4}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {0D898BD9-91CF-45C9-ACE7-B42F062094F4}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {0D898BD9-91CF-45C9-ACE7-B42F062094F4}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {8B237AEF-6B72-4223-9A9B-0A9F54A17AFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {8B237AEF-6B72-4223-9A9B-0A9F54A17AFF}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {8B237AEF-6B72-4223-9A9B-0A9F54A17AFF}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {8B237AEF-6B72-4223-9A9B-0A9F54A17AFF}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {874C901C-9047-49AA-8735-CC274CACA279} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /dotnet-curses/Constants/CursesAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace Mindmagma.Curses 2 | { 3 | public static class CursesAttribute 4 | { 5 | public const uint NORMAL = 0x00000000U; 6 | public const uint ALTCHARSET = 0x00400000U; 7 | public const uint BLINK = 0x00080000U; 8 | public const uint BOLD = 0x00200000U; 9 | public const uint DIM = 0x00100000U; 10 | public const uint INVIS = 0x00800000U; 11 | public const uint PROTECT = 0x01000000U; 12 | public const uint REVERSE = 0x00040000U; 13 | public const uint STANDOUT = 0x00010000U; 14 | public const uint UNDERLINE = 0x00020000U; 15 | 16 | // masks 17 | public const uint ATTRIBUTES = 0xffffff00U; 18 | public const uint CHARTEXT = 0x000000ffU; 19 | public const uint COLOR = 0x0000ff00U; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /dotnet-curses/Constants/CursesColor.cs: -------------------------------------------------------------------------------- 1 | namespace Mindmagma.Curses 2 | { 3 | public static class CursesColor 4 | { 5 | public const short BLACK = 0x0; 6 | public const short BLUE = 0x4; 7 | public const short GREEN = 0x2; 8 | public const short CYAN = 0x6; 9 | public const short RED = 0x1; 10 | public const short MAGENTA = 0x5; 11 | public const short YELLOW = 0x3; 12 | public const short WHITE = 0x7; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /dotnet-curses/Constants/CursesCursorState.cs: -------------------------------------------------------------------------------- 1 | namespace Mindmagma.Curses 2 | { 3 | public static class CursesCursorState 4 | { 5 | public const int INVISIBLE = 0; 6 | public const int NORMAL = 1; 7 | public const int VERY_VISIBLE = 2; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /dotnet-curses/Constants/CursesKey.cs: -------------------------------------------------------------------------------- 1 | namespace Mindmagma.Curses 2 | { 3 | public static class CursesKey 4 | { 5 | public const int ESC = 0x01B; 6 | public const int CTRLC = 0x003; 7 | public const int CTRLZ = 0x01A; 8 | public const int BREAK = 0x101; 9 | public const int DOWN = 0x102; 10 | public const int UP = 0x103; 11 | public const int LEFT = 0x104; 12 | public const int RIGHT = 0x105; 13 | public const int HOME = 0x106; 14 | public const int BACKSPACE = 0x107; 15 | public const int F0 = 0x108; 16 | public const int DL = 0x148; 17 | public const int IL = 0x149; 18 | public const int DC = 0x14a; 19 | public const int DELETEKEY = 0x14a; 20 | public const int IC = 0x14b; 21 | public const int INSERTKEY = 0x14b; 22 | public const int EIC = 0x14c; 23 | public const int CLEAR = 0x14d; 24 | public const int EOS = 0x14e; 25 | public const int EOL = 0x14f; 26 | public const int SF = 0x150; 27 | public const int SR = 0x151; 28 | public const int NPAGE = 0x152; 29 | public const int PPAGE = 0x153; 30 | public const int STAB = 0x154; 31 | public const int CTAB = 0x155; 32 | public const int CATAB = 0x156; 33 | public const int ENTER = 0x157; 34 | public const int SRESET = 0x158; 35 | public const int RESET = 0x159; 36 | public const int PRINT = 0x15a; 37 | public const int LL = 0x15b; 38 | public const int A1 = 0x15c; 39 | public const int A3 = 0x15d; 40 | public const int B2 = 0x15e; 41 | public const int C1 = 0x15f; 42 | public const int C3 = 0x160; 43 | public const int BTAB = 0x161; 44 | public const int BEG = 0x162; 45 | public const int CANCEL = 0x163; 46 | public const int CLOSE = 0x164; 47 | public const int COMMAND = 0x165; 48 | public const int COPY = 0x166; 49 | public const int CREATE = 0x167; 50 | public const int END = 0x168; 51 | public const int EXIT = 0x169; 52 | public const int FIND = 0x16a; 53 | public const int HELP = 0x16b; 54 | public const int MARK = 0x16c; 55 | public const int MESSAGE = 0x16d; 56 | public const int MOUSE = 0x199; 57 | public const int MOVE = 0x16e; 58 | public const int NEXT = 0x16f; 59 | public const int OPEN = 0x170; 60 | public const int OPTIONS = 0x171; 61 | public const int PREVIOUS = 0x172; 62 | public const int REDO = 0x173; 63 | public const int REFERENCE = 0x174; 64 | public const int REFRESH = 0x175; 65 | public const int REPLACE = 0x176; 66 | public const int RESIZE = 0x19a; 67 | public const int RESTART = 0x177; 68 | public const int RESUME = 0x178; 69 | public const int SAVE = 0x179; 70 | public const int SBEG = 0x17a; 71 | public const int SCANCEL = 0x17b; 72 | public const int SCOMMAND = 0x17c; 73 | public const int SCOPY = 0x17d; 74 | public const int SCREATE = 0x17e; 75 | public const int SDC = 0x17f; 76 | public const int SDL = 0x180; 77 | public const int SELECT = 0x181; 78 | public const int SEND = 0x182; 79 | public const int SEOL = 0x183; 80 | public const int SEXIT = 0x184; 81 | public const int SFIND = 0x185; 82 | public const int SHELP = 0x186; 83 | public const int SHOME = 0x187; 84 | public const int SIC = 0x188; 85 | public const int SLEFT = 0x189; 86 | public const int SMESSAGE = 0x18a; 87 | public const int SMOVE = 0x18b; 88 | public const int SNEXT = 0x18c; 89 | public const int SOPTIONS = 0x18d; 90 | public const int SPREVIOUS = 0x18e; 91 | public const int SPRINT = 0x18f; 92 | public const int SREDO = 0x190; 93 | public const int SREPLACE = 0x191; 94 | public const int SRIGHT = 0x192; 95 | public const int SRSUME = 0x193; 96 | public const int SSAVE = 0x194; 97 | public const int SSUSPEND = 0x195; 98 | public const int SUNDO = 0x196; 99 | public const int SUSPEND = 0x197; 100 | public const int UNDO = 0x198; 101 | 102 | public static int KEY_F(int n) 103 | { 104 | return F0 + n; 105 | } 106 | 107 | public const int MIN = 0x101; 108 | public const int MAX = 0x1ff; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /dotnet-curses/Constants/CursesLineAcs.cs: -------------------------------------------------------------------------------- 1 | namespace Mindmagma.Curses 2 | { 3 | public static class CursesLineAcs 4 | { 5 | public const uint BLOCK = 0x00400030U; 6 | public const uint BOARD = 0x00400068U; 7 | public const uint BTEE = 0x00400076U; 8 | public const uint BULLET = 0x0040007eU; 9 | public const uint CKBOARD = 0x00400061U; 10 | public const uint DARROW = 0x0040002eU; 11 | public const uint DEGREE = 0x00400066U; 12 | public const uint DIAMOND = 0x00400060U; 13 | public const uint GEQUAL = 0x0040007aU; 14 | public const uint HLINE = 0x00400071U; 15 | public const uint LANTERN = 0x00400069U; 16 | public const uint LARROW = 0x0040002cU; 17 | public const uint LEQUAL = 0x00400079U; 18 | public const uint LLCORNER = 0x0040006dU; 19 | public const uint LRCORNER = 0x0040006aU; 20 | public const uint LTEE = 0x00400074U; 21 | public const uint NEQUAL = 0x0040007cU; 22 | public const uint PI = 0x0040007bU; 23 | public const uint PLMINUS = 0x00400067U; 24 | public const uint PLUS = 0x0040006eU; 25 | public const uint RARROW = 0x0040002bU; 26 | public const uint RTEE = 0x00400075U; 27 | public const uint S1 = 0x0040006fU; 28 | public const uint S3 = 0x00400070U; 29 | public const uint S7 = 0x00400072U; 30 | public const uint S9 = 0x00400073U; 31 | public const uint STERLING = 0x0040007dU; 32 | public const uint TTEE = 0x00400077U; 33 | public const uint UARROW = 0x0040002dU; 34 | public const uint ULCORNER = 0x0040006cU; 35 | public const uint URCORNER = 0x0040006bU; 36 | public const uint VLINE = 0x00400078U; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /dotnet-curses/Constants/CursesMouseEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Mindmagma.Curses 2 | { 3 | public static class CursesMouseEvent 4 | { 5 | public static uint BUTTON1_PRESSED = 0x00000002U; 6 | public static uint BUTTON1_RELEASED = 0x00000001U; 7 | public static uint BUTTON1_CLICKED = 0x00000004U; 8 | public static uint BUTTON1_DOUBLE_CLICKED = 0x00000008U; 9 | public static uint BUTTON1_TRIPLE_CLICKED = 0x00000010U; 10 | public static uint BUTTON2_PRESSED = 0x00000080U; 11 | public static uint BUTTON2_RELEASED = 0x00000040U; 12 | public static uint BUTTON2_CLICKED = 0x00000100U; 13 | public static uint BUTTON2_DOUBLE_CLICKED = 0x00000200U; 14 | public static uint BUTTON2_TRIPLE_CLICKED = 0x00000400U; 15 | public static uint BUTTON3_PRESSED = 0x00002000U; 16 | public static uint BUTTON3_RELEASED = 0x00001000U; 17 | public static uint BUTTON3_CLICKED = 0x00004000U; 18 | public static uint BUTTON3_DOUBLE_CLICKED = 0x00008000U; 19 | public static uint BUTTON3_TRIPLE_CLICKED = 0x00010000U; 20 | public static uint BUTTON4_PRESSED = 0x00080000U; 21 | public static uint BUTTON4_RELEASED = 0x00040000U; 22 | public static uint BUTTON4_CLICKED = 0x00100000U; 23 | public static uint BUTTON4_DOUBLE_CLICKED = 0x00200000U; 24 | public static uint BUTTON4_TRIPLE_CLICKED = 0x00400000U; 25 | public static uint BUTTON_SHIFT = 0x02000000U; 26 | public static uint BUTTON_CTRL = 0x01000000U; 27 | public static uint BUTTON_ALT = 0x04000000U; 28 | public static uint ALL_MOUSE_EVENTS = 0x07ffffffU; 29 | public static uint REPORT_MOUSE_POSITION = 0x08000000U; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /dotnet-curses/Constants/CursesSoftKeyLabelPosition.cs: -------------------------------------------------------------------------------- 1 | namespace Mindmagma.Curses 2 | { 3 | public static class CursesSoftKeyLabelPosition 4 | { 5 | public static int LEFT = 0; 6 | public static int CENTER = 1; 7 | public static int RIGHT = 2; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /dotnet-curses/NativeLibraryLoader/Kernel32.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace NativeLibraryLoader 5 | { 6 | internal static class Kernel32 7 | { 8 | [DllImport("kernel32")] 9 | public static extern IntPtr LoadLibrary(string fileName); 10 | 11 | [DllImport("kernel32")] 12 | public static extern IntPtr GetProcAddress(IntPtr module, string procName); 13 | 14 | [DllImport("kernel32")] 15 | public static extern int FreeLibrary(IntPtr module); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /dotnet-curses/NativeLibraryLoader/LibraryLoader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace NativeLibraryLoader 6 | { 7 | /// 8 | /// Exposes functionality for loading native libraries and function pointers. 9 | /// 10 | public abstract class LibraryLoader 11 | { 12 | /// 13 | /// Loads a native library by name and returns an operating system handle to it. 14 | /// 15 | /// The name of the library to open. 16 | /// The operating system handle for the shared library. 17 | public IntPtr LoadNativeLibrary(string name) 18 | { 19 | return LoadNativeLibrary(name, PathResolver.Default); 20 | } 21 | 22 | /// 23 | /// Loads a native library by name and returns an operating system handle to it. 24 | /// 25 | /// An ordered list of names. Each name is tried in turn, until the library is successfully loaded. 26 | /// 27 | /// The operating system handle for the shared library. 28 | public IntPtr LoadNativeLibrary(string[] names) 29 | { 30 | return LoadNativeLibrary(names, PathResolver.Default); 31 | } 32 | 33 | /// 34 | /// Loads a native library by name and returns an operating system handle to it. 35 | /// 36 | /// The name of the library to open. 37 | /// The path resolver to use. 38 | /// The operating system handle for the shared library. 39 | public IntPtr LoadNativeLibrary(string name, PathResolver pathResolver) 40 | { 41 | if (string.IsNullOrEmpty(name)) 42 | { 43 | throw new ArgumentException("Parameter must not be null or empty.", nameof(name)); 44 | } 45 | 46 | IntPtr ret = LoadWithResolver(name, pathResolver); 47 | 48 | if (ret == IntPtr.Zero) 49 | { 50 | throw new FileNotFoundException("Could not find or load the native library: " + name); 51 | } 52 | 53 | return ret; 54 | } 55 | 56 | /// 57 | /// Loads a native library by name and returns an operating system handle to it. 58 | /// 59 | /// An ordered list of names. Each name is tried in turn, until the library is successfully loaded. 60 | /// 61 | /// The path resolver to use. 62 | /// The operating system handle for the shared library. 63 | public IntPtr LoadNativeLibrary(string[] names, PathResolver pathResolver) 64 | { 65 | if (names == null || names.Length == 0) 66 | { 67 | throw new ArgumentException("Parameter must not be null or empty.", nameof(names)); 68 | } 69 | 70 | IntPtr ret = IntPtr.Zero; 71 | foreach (string name in names) 72 | { 73 | ret = LoadWithResolver(name, pathResolver); 74 | if (ret != IntPtr.Zero) 75 | { 76 | break; 77 | } 78 | } 79 | 80 | if (ret == IntPtr.Zero) 81 | { 82 | throw new FileNotFoundException($"Could not find or load the native library from any name: [ {string.Join(", ", names)} ]"); 83 | } 84 | 85 | return ret; 86 | } 87 | 88 | private IntPtr LoadWithResolver(string name, PathResolver pathResolver) 89 | { 90 | if (Path.IsPathRooted(name)) 91 | { 92 | return CoreLoadNativeLibrary(name); 93 | } 94 | else 95 | { 96 | foreach (string loadTarget in pathResolver.EnumeratePossibleLibraryLoadTargets(name)) 97 | { 98 | if (!Path.IsPathRooted(loadTarget) || File.Exists(loadTarget)) 99 | { 100 | IntPtr ret = CoreLoadNativeLibrary(loadTarget); 101 | if (ret != IntPtr.Zero) 102 | { 103 | return ret; 104 | } 105 | } 106 | } 107 | 108 | return IntPtr.Zero; 109 | } 110 | } 111 | 112 | /// 113 | /// Loads a function pointer out of the given library by name. 114 | /// 115 | /// The operating system handle of the opened shared library. 116 | /// The name of the exported function to load. 117 | /// A pointer to the loaded function. 118 | public IntPtr LoadFunctionPointer(IntPtr handle, string functionName) 119 | { 120 | if (string.IsNullOrEmpty(functionName)) 121 | { 122 | throw new ArgumentException("Parameter must not be null or empty.", nameof(functionName)); 123 | } 124 | 125 | return CoreLoadFunctionPointer(handle, functionName); 126 | } 127 | 128 | /// 129 | /// Frees the library represented by the given operating system handle. 130 | /// 131 | /// The handle of the open shared library. 132 | public void FreeNativeLibrary(IntPtr handle) 133 | { 134 | if (handle == IntPtr.Zero) 135 | { 136 | throw new ArgumentException("Parameter must not be zero.", nameof(handle)); 137 | } 138 | 139 | CoreFreeNativeLibrary(handle); 140 | } 141 | 142 | /// 143 | /// Loads a native library by name and returns an operating system handle to it. 144 | /// 145 | /// The name of the library to open. This parameter must not be null or empty. 146 | /// The operating system handle for the shared library. 147 | /// If the library cannot be loaded, IntPtr.Zero should be returned. 148 | protected abstract IntPtr CoreLoadNativeLibrary(string name); 149 | 150 | /// 151 | /// Frees the library represented by the given operating system handle. 152 | /// 153 | /// The handle of the open shared library. This must not be zero. 154 | protected abstract void CoreFreeNativeLibrary(IntPtr handle); 155 | 156 | /// 157 | /// Loads a function pointer out of the given library by name. 158 | /// 159 | /// The operating system handle of the opened shared library. This must not be zero. 160 | /// The name of the exported function to load. This must not be null or empty. 161 | /// A pointer to the loaded function. 162 | protected abstract IntPtr CoreLoadFunctionPointer(IntPtr handle, string functionName); 163 | 164 | /// 165 | /// Returns a default library loader for the running operating system. 166 | /// 167 | /// A LibraryLoader suitable for loading libraries. 168 | public static LibraryLoader GetPlatformDefaultLoader() 169 | { 170 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 171 | { 172 | return new Win32LibraryLoader(); 173 | } 174 | else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) 175 | { 176 | return new LinuxLibraryLoader(); 177 | } 178 | else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) 179 | { 180 | return new OsxLibraryLoader(); 181 | } 182 | 183 | throw new PlatformNotSupportedException("This platform cannot load native libraries."); 184 | } 185 | 186 | private class Win32LibraryLoader : LibraryLoader 187 | { 188 | protected override void CoreFreeNativeLibrary(IntPtr handle) 189 | { 190 | Kernel32.FreeLibrary(handle); 191 | } 192 | 193 | protected override IntPtr CoreLoadFunctionPointer(IntPtr handle, string functionName) 194 | { 195 | return Kernel32.GetProcAddress(handle, functionName); 196 | } 197 | 198 | protected override IntPtr CoreLoadNativeLibrary(string name) 199 | { 200 | return Kernel32.LoadLibrary(name); 201 | } 202 | } 203 | 204 | private class LinuxLibraryLoader : LibraryLoader 205 | { 206 | protected override void CoreFreeNativeLibrary(IntPtr handle) 207 | { 208 | libdl_linux.dlclose(handle); 209 | } 210 | 211 | protected override IntPtr CoreLoadFunctionPointer(IntPtr handle, string functionName) 212 | { 213 | return libdl_linux.dlsym(handle, functionName); 214 | } 215 | 216 | protected override IntPtr CoreLoadNativeLibrary(string name) 217 | { 218 | return libdl_linux.dlopen(name, libdl_linux.RTLD_NOW); 219 | } 220 | } 221 | 222 | private class OsxLibraryLoader : LibraryLoader 223 | { 224 | protected override void CoreFreeNativeLibrary(IntPtr handle) 225 | { 226 | libdl_osx.dlclose(handle); 227 | } 228 | 229 | protected override IntPtr CoreLoadFunctionPointer(IntPtr handle, string functionName) 230 | { 231 | return libdl_osx.dlsym(handle, functionName); 232 | } 233 | 234 | protected override IntPtr CoreLoadNativeLibrary(string name) 235 | { 236 | return libdl_osx.dlopen(name, libdl_linux.RTLD_NOW); 237 | } 238 | } 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /dotnet-curses/NativeLibraryLoader/NativeLibrary.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace NativeLibraryLoader 5 | { 6 | /// 7 | /// Represents a native shared library opened by the operating system. 8 | /// This type can be used to load native function pointers by name. 9 | /// 10 | public class NativeLibrary : IDisposable 11 | { 12 | private static readonly LibraryLoader s_platformDefaultLoader = LibraryLoader.GetPlatformDefaultLoader(); 13 | private readonly LibraryLoader _loader; 14 | 15 | /// 16 | /// The operating system handle of the loaded library. 17 | /// 18 | public IntPtr Handle { get; } 19 | 20 | /// 21 | /// Constructs a new NativeLibrary using the platform's default library loader. 22 | /// 23 | /// The name of the library to load. 24 | public NativeLibrary(string name) : this(name, s_platformDefaultLoader, PathResolver.Default) 25 | { 26 | } 27 | 28 | /// 29 | /// Constructs a new NativeLibrary using the platform's default library loader. 30 | /// 31 | /// An ordered list of names to attempt to load. 32 | public NativeLibrary(string[] names) : this(names, s_platformDefaultLoader, PathResolver.Default) 33 | { 34 | } 35 | 36 | /// 37 | /// Constructs a new NativeLibrary using the specified library loader. 38 | /// 39 | /// The name of the library to load. 40 | /// The loader used to open and close the library, and to load function pointers. 41 | public NativeLibrary(string name, LibraryLoader loader) : this(name, loader, PathResolver.Default) 42 | { 43 | } 44 | 45 | /// 46 | /// Constructs a new NativeLibrary using the specified library loader. 47 | /// 48 | /// An ordered list of names to attempt to load. 49 | /// The loader used to open and close the library, and to load function pointers. 50 | public NativeLibrary(string[] names, LibraryLoader loader) : this(names, loader, PathResolver.Default) 51 | { 52 | } 53 | 54 | /// 55 | /// Constructs a new NativeLibrary using the specified library loader. 56 | /// 57 | /// The name of the library to load. 58 | /// The loader used to open and close the library, and to load function pointers. 59 | /// The path resolver, used to identify possible load targets for the library. 60 | public NativeLibrary(string name, LibraryLoader loader, PathResolver pathResolver) 61 | { 62 | _loader = loader; 63 | Handle = _loader.LoadNativeLibrary(name, pathResolver); 64 | } 65 | 66 | /// 67 | /// Constructs a new NativeLibrary using the specified library loader. 68 | /// 69 | /// An ordered list of names to attempt to load. 70 | /// The loader used to open and close the library, and to load function pointers. 71 | /// The path resolver, used to identify possible load targets for the library. 72 | public NativeLibrary(string[] names, LibraryLoader loader, PathResolver pathResolver) 73 | { 74 | _loader = loader; 75 | Handle = _loader.LoadNativeLibrary(names, pathResolver); 76 | } 77 | 78 | /// 79 | /// Loads a function whose signature matches the given delegate type's signature. 80 | /// 81 | /// The type of delegate to return. 82 | /// The name of the native export. 83 | /// A delegate wrapping the native function. 84 | /// Thrown when no function with the given name 85 | /// is exported from the native library. 86 | public T LoadFunction(string name) 87 | { 88 | IntPtr functionPtr = _loader.LoadFunctionPointer(Handle, name); 89 | if (functionPtr == IntPtr.Zero) 90 | { 91 | throw new InvalidOperationException($"No function was found with the name {name}."); 92 | } 93 | 94 | return Marshal.GetDelegateForFunctionPointer(functionPtr); 95 | } 96 | 97 | /// 98 | /// Loads a function pointer with the given name. 99 | /// 100 | /// The name of the native export. 101 | /// A function pointer for the given name, or 0 if no function with that name exists. 102 | public IntPtr LoadFunction(string name) 103 | { 104 | return _loader.LoadFunctionPointer(Handle, name); 105 | } 106 | 107 | /// 108 | /// Frees the native library. Function pointers retrieved from this library will be void. 109 | /// 110 | public void Dispose() 111 | { 112 | _loader.FreeNativeLibrary(Handle); 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /dotnet-curses/NativeLibraryLoader/PathResolver.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyModel; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace NativeLibraryLoader 8 | { 9 | /// 10 | /// Enumerates possible library load targets. 11 | /// 12 | public abstract class PathResolver 13 | { 14 | /// 15 | /// Returns an enumerator which yields possible library load targets, in priority order. 16 | /// 17 | /// The name of the library to load. 18 | /// An enumerator yielding load targets. 19 | public abstract IEnumerable EnumeratePossibleLibraryLoadTargets(string name); 20 | 21 | /// 22 | /// Gets a default path resolver. 23 | /// 24 | public static PathResolver Default { get; } = new DefaultPathResolver(); 25 | } 26 | 27 | /// 28 | /// Enumerates possible library load targets. This default implementation returns the following load targets: 29 | /// First: The library contained in the applications base folder. 30 | /// Second: The simple name, unchanged. 31 | /// Third: The library as resolved via the default DependencyContext, in the default nuget package cache folder. 32 | /// 33 | public class DefaultPathResolver : PathResolver 34 | { 35 | /// 36 | /// Returns an enumerator which yields possible library load targets, in priority order. 37 | /// 38 | /// The name of the library to load. 39 | /// An enumerator yielding load targets. 40 | public override IEnumerable EnumeratePossibleLibraryLoadTargets(string name) 41 | { 42 | yield return Path.Combine(AppContext.BaseDirectory, name); 43 | yield return name; 44 | if (TryLocateNativeAssetFromDeps(name, out string appLocalNativePath, out string depsResolvedPath)) 45 | { 46 | yield return appLocalNativePath; 47 | yield return depsResolvedPath; 48 | } 49 | } 50 | 51 | private bool TryLocateNativeAssetFromDeps(string name, out string appLocalNativePath, out string depsResolvedPath) 52 | { 53 | DependencyContext defaultContext = DependencyContext.Default; 54 | if (defaultContext == null) 55 | { 56 | appLocalNativePath = null; 57 | depsResolvedPath = null; 58 | return false; 59 | } 60 | 61 | string currentRID = Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment.GetRuntimeIdentifier(); 62 | List allRIDs = new List(); 63 | allRIDs.Add(currentRID); 64 | if (!AddFallbacks(allRIDs, currentRID, defaultContext.RuntimeGraph)) 65 | { 66 | string guessedFallbackRID = GuessFallbackRID(currentRID); 67 | if (guessedFallbackRID != null) 68 | { 69 | allRIDs.Add(guessedFallbackRID); 70 | AddFallbacks(allRIDs, guessedFallbackRID, defaultContext.RuntimeGraph); 71 | } 72 | } 73 | 74 | foreach (string rid in allRIDs) 75 | { 76 | foreach (var runtimeLib in defaultContext.RuntimeLibraries) 77 | { 78 | foreach (var nativeAsset in runtimeLib.GetRuntimeNativeAssets(defaultContext, rid)) 79 | { 80 | if (Path.GetFileName(nativeAsset) == name || Path.GetFileNameWithoutExtension(nativeAsset) == name) 81 | { 82 | appLocalNativePath = Path.Combine( 83 | AppContext.BaseDirectory, 84 | nativeAsset); 85 | appLocalNativePath = Path.GetFullPath(appLocalNativePath); 86 | 87 | depsResolvedPath = Path.Combine( 88 | GetNugetPackagesRootDirectory(), 89 | runtimeLib.Name.ToLowerInvariant(), 90 | runtimeLib.Version, 91 | nativeAsset); 92 | depsResolvedPath = Path.GetFullPath(depsResolvedPath); 93 | 94 | return true; 95 | } 96 | } 97 | } 98 | } 99 | 100 | appLocalNativePath = null; 101 | depsResolvedPath = null; 102 | return false; 103 | } 104 | 105 | private string GuessFallbackRID(string actualRuntimeIdentifier) 106 | { 107 | if (actualRuntimeIdentifier == "osx.10.13-x64") 108 | { 109 | return "osx.10.12-x64"; 110 | } 111 | else if (actualRuntimeIdentifier.StartsWith("osx")) 112 | { 113 | return "osx-x64"; 114 | } 115 | 116 | return null; 117 | } 118 | 119 | private bool AddFallbacks(List fallbacks, string rid, IReadOnlyList allFallbacks) 120 | { 121 | foreach (RuntimeFallbacks fb in allFallbacks) 122 | { 123 | if (fb.Runtime == rid) 124 | { 125 | fallbacks.AddRange(fb.Fallbacks); 126 | return true; 127 | } 128 | } 129 | 130 | return false; 131 | } 132 | 133 | private string GetNugetPackagesRootDirectory() 134 | { 135 | // TODO: Handle alternative package directories, if they are configured. 136 | return Path.Combine(GetUserDirectory(), ".nuget", "packages"); 137 | } 138 | 139 | private string GetUserDirectory() 140 | { 141 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 142 | { 143 | return Environment.GetEnvironmentVariable("USERPROFILE"); 144 | } 145 | else 146 | { 147 | return Environment.GetEnvironmentVariable("HOME"); 148 | } 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /dotnet-curses/NativeLibraryLoader/libdl_linux.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace NativeLibraryLoader 5 | { 6 | internal static class libdl_linux 7 | { 8 | // originally just "libdl" 9 | // https://github.com/mellinoe/nativelibraryloader/issues/2 10 | private const string LibName = "libdl.so.2"; 11 | 12 | public const int RTLD_NOW = 0x002; 13 | 14 | [DllImport(LibName)] 15 | public static extern IntPtr dlopen(string fileName, int flags); 16 | 17 | [DllImport(LibName)] 18 | public static extern IntPtr dlsym(IntPtr handle, string name); 19 | 20 | [DllImport(LibName)] 21 | public static extern int dlclose(IntPtr handle); 22 | 23 | [DllImport(LibName)] 24 | public static extern string dlerror(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /dotnet-curses/NativeLibraryLoader/libdl_osx.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace NativeLibraryLoader 5 | { 6 | class libdl_osx 7 | { 8 | private const string LibName = "libdl"; 9 | 10 | public const int RTLD_NOW = 0x002; 11 | 12 | [DllImport(LibName)] 13 | public static extern IntPtr dlopen(string fileName, int flags); 14 | 15 | [DllImport(LibName)] 16 | public static extern IntPtr dlsym(IntPtr handle, string name); 17 | 18 | [DllImport(LibName)] 19 | public static extern int dlclose(IntPtr handle); 20 | 21 | [DllImport(LibName)] 22 | public static extern string dlerror(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /dotnet-curses/NativeWrapper/MouseEvent.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace Mindmagma.Curses 4 | { 5 | [StructLayout(LayoutKind.Sequential)] 6 | public struct MouseEvent 7 | { 8 | [MarshalAs(UnmanagedType.I2)] 9 | public short id; 10 | 11 | [MarshalAs(UnmanagedType.I4)] 12 | public int x; 13 | 14 | [MarshalAs(UnmanagedType.I4)] 15 | public int y; 16 | 17 | [MarshalAs(UnmanagedType.I4)] 18 | public int z; 19 | 20 | [MarshalAs(UnmanagedType.I8)] 21 | public long bstate; 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /dotnet-curses/NativeWrapper/Native.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Text; 4 | 5 | #pragma warning disable IDE1006 // naming rule violation, methods must begin with uppercase 6 | 7 | // internal support, curses functions are referenced in the other partial classes 8 | 9 | // ncurses export list 10 | // http://invisible-island.net/ncurses/man/ncurses.3x.html#h3-Routine-Name-Index 11 | 12 | // depends upon a modified version of this project until .NET adds this capability 13 | // https://github.com/mellinoe/nativelibraryloader 14 | // https://github.com/dotnet/corefx/issues/17135 15 | 16 | namespace Mindmagma.Curses.Interop 17 | { 18 | internal static partial class Native 19 | { 20 | private static D NativeToDelegate(string exportedFunctionName) 21 | { 22 | return NCursesLibraryHandle.lib.LoadFunction(exportedFunctionName); 23 | } 24 | 25 | private static int MarshalInt(string exportedSymbolName) 26 | { 27 | IntPtr address = NCursesLibraryHandle.lib.LoadFunction(exportedSymbolName); 28 | return (int)Marshal.PtrToStructure(address, typeof(int)); 29 | } 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /dotnet-curses/NativeWrapper/NativeCommon.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Text; 4 | 5 | #pragma warning disable IDE1006 // naming rule violation, methods must begin with uppercase 6 | 7 | // common functions 8 | 9 | namespace Mindmagma.Curses.Interop 10 | { 11 | internal static partial class Native 12 | { 13 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 14 | private delegate int dt_addch(int ch); 15 | private static dt_addch call_addch = NativeToDelegate("addch"); 16 | internal static int addch(int ch) => call_addch(ch); 17 | 18 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 19 | private delegate int dt_assume_default_colors(int f, int b); 20 | private static dt_assume_default_colors call_assume_default_colors = NativeToDelegate("assume_default_colors"); 21 | internal static int assume_default_colors(int f, int b) => call_assume_default_colors(f, b); 22 | 23 | [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)] 24 | private delegate int dt_addstr(string str); 25 | private static dt_addstr call_addstr = NativeToDelegate("addstr"); 26 | internal static int addstr(string str) => call_addstr(str); 27 | 28 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 29 | private delegate int dt_attroff(uint attributes); 30 | private static dt_attroff call_attroff = NativeToDelegate("attroff"); 31 | internal static int attroff(uint attributes) => call_attroff(attributes); 32 | 33 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 34 | private delegate int dt_attron(uint attributes); 35 | private static dt_attron call_attron = NativeToDelegate("attron"); 36 | internal static int attron(uint attributes) => call_attron(attributes); 37 | 38 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 39 | private delegate int dt_attrset(uint attributes); 40 | private static dt_attrset call_attrset = NativeToDelegate("attrset"); 41 | internal static int attrset(uint attributes) => call_attrset(attributes); 42 | 43 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 44 | private delegate int dt_beep(); 45 | private static dt_beep call_beep = NativeToDelegate("beep"); 46 | internal static int beep() => call_beep(); 47 | 48 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 49 | private delegate int dt_bkgd(uint ch); 50 | private static dt_bkgd call_bkgd = NativeToDelegate("bkgd"); 51 | internal static int bkgd(uint ch) => call_bkgd(ch); 52 | 53 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 54 | private delegate int dt_clear(); 55 | private static dt_clear call_clear = NativeToDelegate("clear"); 56 | internal static int clear() => call_clear(); 57 | 58 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 59 | private delegate int dt_color_content(short color, out short red, out short green, out short blue); 60 | private static dt_color_content call_color_content = NativeToDelegate("color_content"); 61 | internal static int color_content(short color, out short red, out short green, out short blue) => call_color_content(color, out red, out green, out blue); 62 | 63 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 64 | private delegate uint dt_COLOR_PAIR(int n); 65 | private static dt_COLOR_PAIR call_COLOR_PAIR = NativeToDelegate("COLOR_PAIR"); 66 | internal static uint COLOR_PAIR(int n) => call_COLOR_PAIR(n); 67 | 68 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 69 | private delegate int dt_clrtobot(); 70 | private static dt_clrtobot call_clrtobot = NativeToDelegate("clrtobot"); 71 | internal static int clrtobot() => call_clrtobot(); 72 | 73 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 74 | private delegate int dt_clrtoeol(); 75 | private static dt_clrtoeol call_clrtoeol = NativeToDelegate("clrtoeol"); 76 | internal static int clrtoeol() => call_clrtoeol(); 77 | 78 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 79 | private delegate int dt_curs_set(int cursorState); 80 | private static dt_curs_set call_curs_set = NativeToDelegate("curs_set"); 81 | internal static int curs_set(int cursorState) => call_curs_set(cursorState); 82 | 83 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 84 | private delegate int dt_delch(); 85 | private static dt_delch call_delch = NativeToDelegate("delch"); 86 | internal static int delch() => call_delch(); 87 | 88 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 89 | private delegate int dt_deleteln(); 90 | private static dt_deleteln call_deleteln = NativeToDelegate("deleteln"); 91 | internal static int deleteln() => call_deleteln(); 92 | 93 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 94 | private delegate int dt_doupdate(); 95 | private static dt_doupdate call_doupdate = NativeToDelegate("doupdate"); 96 | internal static int doupdate() => call_doupdate(); 97 | 98 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 99 | private delegate int dt_echo(); 100 | private static dt_echo call_echo = NativeToDelegate("echo"); 101 | internal static int echo() => call_echo(); 102 | 103 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 104 | private delegate int dt_erase(); 105 | private static dt_erase call_erase = NativeToDelegate("erase"); 106 | internal static int erase() => call_erase(); 107 | 108 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 109 | private delegate int dt_flash(); 110 | private static dt_flash call_flash = NativeToDelegate("flash"); 111 | internal static int flash() => call_flash(); 112 | 113 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 114 | private delegate int dt_flushinp(); 115 | private static dt_flushinp call_flushinp = NativeToDelegate("flushinp"); 116 | internal static int flushinp() => call_flushinp(); 117 | 118 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 119 | private delegate int dt_getch(); 120 | private static dt_getch call_getch = NativeToDelegate("getch"); 121 | internal static int getch() => call_getch(); 122 | 123 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 124 | private delegate int dt_getmouse(out MouseEvent mouseEvent); 125 | private static dt_getmouse call_getmouse = NativeToDelegate("getmouse"); 126 | internal static int getmouse(out MouseEvent mouseEvent) => call_getmouse(out mouseEvent); 127 | 128 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 129 | private delegate int dt_getnstr(StringBuilder message, int numberOfCharacters); 130 | private static dt_getnstr call_getnstr = NativeToDelegate("getnstr"); 131 | internal static int getnstr(StringBuilder message, int numberOfCharacters) => call_getnstr(message, numberOfCharacters); 132 | 133 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 134 | private delegate int dt_getstr(StringBuilder message); 135 | private static dt_getstr call_getstr = NativeToDelegate("getstr"); 136 | internal static int getstr(StringBuilder message) => call_getstr(message); 137 | 138 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 139 | private delegate int dt_init_color(short color, short red, short green, short blue); 140 | private static dt_init_color call_init_color = NativeToDelegate("init_color"); 141 | internal static int init_color(short color, short red, short green, short blue) => call_init_color(color, red, green, blue); 142 | 143 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 144 | private delegate int dt_init_pair(short color, short fg, short bg); 145 | private static dt_init_pair call_init_pair = NativeToDelegate("init_pair"); 146 | internal static int init_pair(short color, short fg, short bg) => call_init_pair(color, fg, bg); 147 | 148 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 149 | private delegate int dt_insch(uint character); 150 | private static dt_insch call_insch = NativeToDelegate("insch"); 151 | internal static int insch(uint character) => call_insch(character); 152 | 153 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 154 | private delegate int dt_insertln(); 155 | private static dt_insertln call_insertln = NativeToDelegate("insertln"); 156 | internal static int insertln() => call_insertln(); 157 | 158 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 159 | private delegate uint dt_mousemask(uint newMask, out uint oldmask); 160 | private static dt_mousemask call_mousemask = NativeToDelegate("mousemask"); 161 | internal static uint mousemask(uint newMask, out uint oldmask) => call_mousemask(newMask, out oldmask); 162 | 163 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 164 | private delegate int dt_move(int y, int x); 165 | private static dt_move call_move = NativeToDelegate("move"); 166 | internal static int move(int y, int x) => call_move(y, x); 167 | 168 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 169 | private delegate int dt_mvaddch(int row, int column, uint character); 170 | private static dt_mvaddch call_mvaddch = NativeToDelegate("mvaddch"); 171 | internal static int mvaddch(int row, int column, uint character) => call_mvaddch(row, column, character); 172 | 173 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 174 | private delegate int dt_mvaddchnstr(int row, int column, uint character, int numberOfCharacters); 175 | private static dt_mvaddchnstr call_mvaddchnstr = NativeToDelegate("mvaddchnstr"); 176 | internal static int mvaddchnstr(int row, int column, uint character, int numberOfCharacters) => call_mvaddchnstr(row, column, character, numberOfCharacters); 177 | 178 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 179 | private delegate int dt_mvaddchstr(int row, int column, uint character); 180 | private static dt_mvaddchstr call_mvaddchstr = NativeToDelegate("mvaddchstr"); 181 | internal static int mvaddchstr(int row, int column, uint character) => call_mvaddchstr(row, column, character); 182 | 183 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 184 | private delegate int dt_mvaddnstr(int row, int column, uint character, int numberOfCharacters); 185 | private static dt_mvaddnstr call_mvaddnstr = NativeToDelegate("mvaddnstr"); 186 | internal static int mvaddnstr(int row, int column, uint character, int numberOfCharacters) => call_mvaddnstr(row, column, character, numberOfCharacters); 187 | 188 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 189 | private delegate int dt_mvaddstr(int row, int column, string message); 190 | private static dt_mvaddstr call_mvaddstr = NativeToDelegate("mvaddstr"); 191 | internal static int mvaddstr(int row, int column, string message) => call_mvaddstr(row, column, message); 192 | 193 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 194 | private delegate short dt_PAIR_NUMBER(uint n); 195 | private static dt_PAIR_NUMBER call_PAIR_NUMBER = NativeToDelegate("PAIR_NUMBER"); 196 | internal static short PAIR_NUMBER(uint n) => call_PAIR_NUMBER(n); 197 | 198 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 199 | private delegate int dt_pair_content(short pair, out short fg, out short bg); 200 | private static dt_pair_content call_pair_content = NativeToDelegate("pair_content"); 201 | internal static int pair_content(short pair, out short fg, out short bg) => call_pair_content(pair, out fg, out bg); 202 | 203 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 204 | private delegate int dt_refresh(); 205 | private static dt_refresh call_refresh = NativeToDelegate("refresh"); 206 | internal static int refresh() => call_refresh(); 207 | 208 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 209 | private delegate int dt_resize_term(int nlines, int ncols); 210 | private static dt_resize_term call_resize_term = NativeToDelegate("resize_term"); 211 | internal static int resize_term(int nlines, int ncols) => call_resize_term(nlines, ncols); 212 | 213 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 214 | private delegate int dt_scrollok(IntPtr window, bool canScroll); 215 | private static dt_scrollok call_scrollok = NativeToDelegate("scrollok"); 216 | internal static int scrollok(IntPtr window, bool canScroll) => call_scrollok(window, canScroll); 217 | 218 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 219 | private delegate int dt_slk_clear(); 220 | private static dt_slk_clear call_slk_clear = NativeToDelegate("slk_clear"); 221 | internal static int slk_clear() => call_slk_clear(); 222 | 223 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 224 | private delegate int dt_slk_init(int numberOfLabels); 225 | private static dt_slk_init call_slk_init = NativeToDelegate("slk_init"); 226 | internal static int slk_init(int numberOfLabels) => call_slk_init(numberOfLabels); 227 | 228 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 229 | private delegate int dt_slk_refresh(); 230 | private static dt_slk_refresh call_slk_refresh = NativeToDelegate("slk_refresh"); 231 | internal static int slk_refresh() => call_slk_refresh(); 232 | 233 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 234 | private delegate int dt_slk_restore(); 235 | private static dt_slk_restore call_slk_restore = NativeToDelegate("slk_restore"); 236 | internal static int slk_restore() => call_slk_restore(); 237 | 238 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 239 | private delegate int dt_slk_set(int labelNumber, string text, int position); 240 | private static dt_slk_set call_slk_set = NativeToDelegate("slk_set"); 241 | internal static int slk_set(int labelNumber, string text, int position) => call_slk_set(labelNumber, text, position); 242 | 243 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 244 | private delegate int dt_start_color(); 245 | private static dt_start_color call_start_color = NativeToDelegate("start_color"); 246 | internal static int start_color() => call_start_color(); 247 | 248 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 249 | private delegate int dt_ungetch(int character); 250 | private static dt_ungetch call_ungetch = NativeToDelegate("ungetch"); 251 | internal static int ungetch(int character) => call_ungetch(character); 252 | 253 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 254 | private delegate int dt_use_default_colors(); 255 | private static dt_use_default_colors call_use_default_colors = NativeToDelegate("use_default_colors"); 256 | internal static int use_default_colors() => call_use_default_colors(); 257 | 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /dotnet-curses/NativeWrapper/NativeEnvironment.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | #pragma warning disable IDE1006 // naming rule violation, methods must begin with uppercase 5 | 6 | // startup/shutdown, trace (debugging), termcaps (terminal metadata), etc. 7 | 8 | namespace Mindmagma.Curses.Interop 9 | { 10 | internal static partial class Native 11 | { 12 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 13 | private delegate bool dt_can_change_color(); 14 | private static dt_can_change_color call_can_change_color = NativeToDelegate("can_change_color"); 15 | internal static bool can_change_color() => call_can_change_color(); 16 | 17 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 18 | private delegate int dt_cbreak(); 19 | private static dt_cbreak call_cbreak = NativeToDelegate("cbreak"); 20 | internal static int cbreak() => call_cbreak(); 21 | 22 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 23 | private delegate int dt_endwin(); 24 | private static dt_endwin call_endwin = NativeToDelegate("endwin"); 25 | internal static int endwin() => call_endwin(); 26 | 27 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 28 | private delegate bool dt_has_colors(); 29 | private static dt_has_colors call_has_colors = NativeToDelegate("has_colors"); 30 | internal static bool has_colors() => call_has_colors(); 31 | 32 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 33 | private delegate IntPtr dt_initscr(); 34 | private static dt_initscr call_initscr = NativeToDelegate("initscr"); 35 | internal static IntPtr initscr() => call_initscr(); 36 | 37 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 38 | private delegate bool dt_isendwin(); 39 | private static dt_isendwin call_isendwin = NativeToDelegate("isendwin"); 40 | internal static bool isendwin() => call_isendwin(); 41 | 42 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 43 | private delegate int dt_napms(int milliseconds); 44 | private static dt_napms call_napms = NativeToDelegate("napms"); 45 | internal static int napms(int milliseconds) => call_napms(milliseconds); 46 | 47 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 48 | private delegate int dt_nocbreak(); 49 | private static dt_nocbreak call_nocbreak = NativeToDelegate("nocbreak"); 50 | internal static int nocbreak() => call_nocbreak(); 51 | 52 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 53 | private delegate int dt_noecho(); 54 | private static dt_noecho call_noecho = NativeToDelegate("noecho"); 55 | internal static int noecho() => call_noecho(); 56 | 57 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 58 | private delegate int dt_noraw(); 59 | private static dt_noraw call_noraw = NativeToDelegate("noraw"); 60 | internal static int noraw() => call_noraw(); 61 | 62 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 63 | private delegate int dt_raw(); 64 | private static dt_raw call_raw = NativeToDelegate("raw"); 65 | internal static int raw() => call_raw(); 66 | 67 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 68 | private delegate int dt_halfdelay(int tenths); 69 | private static dt_halfdelay call_halfdelay = NativeToDelegate("halfdelay"); 70 | internal static int halfdelay(int tenths) => call_halfdelay(tenths); 71 | 72 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 73 | private delegate int dt_timeout(int delay); 74 | private static dt_timeout call_timeout = NativeToDelegate("timeout"); 75 | internal static int timeout(int delay) => call_timeout(delay); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /dotnet-curses/NativeWrapper/NativePad.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Text; 4 | 5 | #pragma warning disable IDE1006 // naming rule violation, methods must begin with uppercase 6 | 7 | // functions for working with curses pads 8 | 9 | namespace Mindmagma.Curses.Interop 10 | { 11 | internal static partial class Native 12 | { 13 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 14 | private delegate IntPtr dt_newpad(int row, int column); 15 | private static dt_newpad call_newpad = NativeToDelegate("newpad"); 16 | internal static IntPtr newpad(int row, int column) => call_newpad(row, column); 17 | 18 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 19 | private delegate int dt_pechochar(IntPtr pad, int character); 20 | private static dt_pechochar call_pechochar = NativeToDelegate("pechochar"); 21 | internal static int pechochar(IntPtr pad, int character) => call_pechochar(pad, character); 22 | 23 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 24 | private delegate int dt_pnoutrefresh(IntPtr pad, int padMinRow, int padMinColumn, int screenMinRow, int screenMinColumn, int screenMaxRow, int screenMaxColumn); 25 | private static dt_pnoutrefresh call_pnoutrefresh = NativeToDelegate("pnoutrefresh"); 26 | internal static int pnoutrefresh(IntPtr pad, int padMinRow, int padMinColumn, int screenMinRow, int screenMinColumn, int screenMaxRow, int screenMaxColumn) 27 | => call_pnoutrefresh(pad, padMinRow, padMinColumn, screenMinRow, screenMinColumn, screenMaxRow, screenMaxColumn); 28 | 29 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 30 | private delegate int dt_prefresh(IntPtr pad, int padMinRow, int padMinColumn, int screenMinRow, int screenMinColumn, int screenMaxRow, int screenMaxColumn); 31 | private static dt_prefresh call_prefresh = NativeToDelegate("prefresh"); 32 | internal static int prefresh(IntPtr pad, int padMinRow, int padMinColumn, int screenMinRow, int screenMinColumn, int screenMaxRow, int screenMaxColumn) 33 | => call_prefresh(pad, padMinRow, padMinColumn, screenMinRow, screenMinColumn, screenMaxRow, screenMaxColumn); 34 | 35 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 36 | private delegate IntPtr dt_subpad(IntPtr parent, int row, int column, int y, int x); 37 | private static dt_subpad call_subpad = NativeToDelegate("subpad"); 38 | internal static IntPtr subpad(IntPtr parent, int row, int column, int y, int x) => call_subpad(parent, row, column, y, x); 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /dotnet-curses/NativeWrapper/NativeProperties.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | #pragma warning disable IDE1006 // naming rule violation, methods must begin with uppercase 4 | 5 | // exported values (LINES, COLS, etc.) 6 | 7 | namespace Mindmagma.Curses.Interop 8 | { 9 | internal static partial class Native 10 | { 11 | 12 | internal static int COLS => MarshalInt("COLS"); 13 | 14 | internal static int LINES => MarshalInt("LINES"); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /dotnet-curses/NativeWrapper/NativeWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Text; 4 | 5 | #pragma warning disable IDE1006 // naming rule violation, methods must begin with uppercase 6 | 7 | // functions for working with curses windows 8 | 9 | namespace Mindmagma.Curses.Interop 10 | { 11 | internal static partial class Native 12 | { 13 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 14 | private delegate int dt_box(IntPtr window, char verticalChar, char horizontalChar); 15 | private static dt_box call_box = NativeToDelegate("box"); 16 | internal static int box(IntPtr window, char verticalChar, char horizontalChar) => call_box(window, verticalChar, horizontalChar); 17 | 18 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 19 | private delegate int dt_copywin(IntPtr sourceWindow, IntPtr destinationWindow, int sourceRow, int sourceColumn, int destinationRow, int destinationColumn, int rowOffset, int columnOffset, bool type); 20 | private static dt_copywin call_copywin = NativeToDelegate("copywin"); 21 | internal static int copywin(IntPtr sourceWindow, IntPtr destinationWindow, int sourceRow, int sourceColumn, int destinationRow, int destinationColumn, int rowOffset, int columnOffset, bool type) 22 | => call_copywin(sourceWindow, destinationWindow, sourceRow, sourceColumn, destinationRow, destinationColumn, rowOffset, columnOffset, type); 23 | 24 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 25 | private delegate int dt_delwin(IntPtr window); 26 | private static dt_delwin call_delwin = NativeToDelegate("delwin"); 27 | internal static int delwin(IntPtr window) => call_delwin(window); 28 | 29 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 30 | private delegate IntPtr dt_derwin(IntPtr window, int rows, int columns, int y, int x); 31 | private static dt_derwin call_derwin = NativeToDelegate("derwin"); 32 | internal static IntPtr derwin(IntPtr window, int rows, int columns, int y, int x) => call_derwin(window, rows, columns, y, x); 33 | 34 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 35 | private delegate IntPtr dt_dupwin(IntPtr window); 36 | private static dt_dupwin call_dupwin = NativeToDelegate("dupwin"); 37 | internal static IntPtr dupwin(IntPtr window) => call_dupwin(window); 38 | 39 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 40 | private delegate int dt_getcurx(IntPtr window); 41 | private static dt_getcurx call_getcurx = NativeToDelegate("getcurx"); 42 | internal static int getcurx(IntPtr window) => call_getcurx(window); 43 | 44 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 45 | private delegate int dt_getcury(IntPtr window); 46 | private static dt_getcury call_getcury = NativeToDelegate("getcury"); 47 | internal static int getcury(IntPtr window) => call_getcury(window); 48 | 49 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 50 | private delegate int dt_getmaxx(IntPtr window); 51 | private static dt_getmaxx call_getmaxx = NativeToDelegate("getmaxx"); 52 | internal static int getmaxx(IntPtr window) => call_getmaxx(window); 53 | 54 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 55 | private delegate int dt_getmaxy(IntPtr window); 56 | private static dt_getmaxy call_getmaxy = NativeToDelegate("getmaxy"); 57 | internal static int getmaxy(IntPtr window) => call_getmaxy(window); 58 | 59 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 60 | private delegate int dt_keypad(IntPtr window, bool enable); 61 | private static dt_keypad call_keypad = NativeToDelegate("keypad"); 62 | internal static int keypad(IntPtr window, bool enable) => call_keypad(window, enable); 63 | 64 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 65 | private delegate int dt_mvwaddch(IntPtr window, int y, int x, char c); 66 | private static dt_mvwaddch call_mvwaddch = NativeToDelegate("mvwaddch"); 67 | internal static int mvwaddch(IntPtr window, int y, int x, char c) => call_mvwaddch(window, y, x, c); 68 | 69 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 70 | private delegate int dt_mvwaddstr(IntPtr window, int y, int x, string message); 71 | private static dt_mvwaddstr call_mvwaddstr = NativeToDelegate("mvwaddstr"); 72 | internal static int mvwaddstr(IntPtr window, int y, int x, string message) => call_mvwaddstr(window, y, x, message); 73 | 74 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 75 | private delegate int dt_mvwin(IntPtr window, int row, int column); 76 | private static dt_mvwin call_mvwin = NativeToDelegate("mvwin"); 77 | internal static int mvwin(IntPtr window, int row, int column) => call_mvwin(window, row, column); 78 | 79 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 80 | private delegate int dt_mvwgetch(IntPtr window, int y, int x); 81 | private static dt_mvwgetch call_mvwgetch = NativeToDelegate("mvwgetch"); 82 | internal static int mvwgetch(IntPtr window, int y, int x) => call_mvwgetch(window, y, x); 83 | 84 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 85 | private delegate uint dt_mvwinch(IntPtr window, int y, int x); 86 | private static dt_mvwinch call_mvwinch = NativeToDelegate("mvwinch"); 87 | internal static uint mvwinch(IntPtr window, int y, int x) => call_mvwinch(window, y, x); 88 | 89 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 90 | private delegate IntPtr dt_newwin(int rows, int columns, int yOrigin, int xOrigin); 91 | private static dt_newwin call_newwin = NativeToDelegate("newwin"); 92 | internal static IntPtr newwin(int rows, int columns, int yOrigin, int xOrigin) => call_newwin(rows, columns, yOrigin, xOrigin); 93 | 94 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 95 | private delegate int dt_nodelay(IntPtr window, bool removeDelay); 96 | private static dt_nodelay call_nodelay = NativeToDelegate("nodelay"); 97 | internal static int nodelay(IntPtr window, bool removeDelay) => call_nodelay(window, removeDelay); 98 | 99 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 100 | private delegate int dt_wtimeout(IntPtr window, int delay); 101 | private static dt_wtimeout call_wtimeout = NativeToDelegate("wtimeout"); 102 | internal static int wtimeout(IntPtr window, int delay) => call_wtimeout(window, delay); 103 | 104 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 105 | private delegate int dt_overlay(IntPtr sourceWindow, IntPtr destinationWindow); 106 | private static dt_overlay call_overlay = NativeToDelegate("overlay"); 107 | internal static int overlay(IntPtr sourceWindow, IntPtr destinationWindow) => call_overlay(sourceWindow, destinationWindow); 108 | 109 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 110 | private delegate int dt_overwrite(IntPtr sourceWindow, IntPtr destinationWindow); 111 | private static dt_overwrite call_overwrite = NativeToDelegate("overwrite"); 112 | internal static int overwrite(IntPtr sourceWindow, IntPtr destinationWindow) => call_overwrite(sourceWindow, destinationWindow); 113 | 114 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 115 | private delegate int dt_scrl(int numberOfLines); 116 | private static dt_scrl call_scrl = NativeToDelegate("scrl"); 117 | internal static int scrl(int numberOfLines) => call_scrl(numberOfLines); 118 | 119 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 120 | private delegate int dt_scroll(IntPtr window); 121 | private static dt_scroll call_scroll = NativeToDelegate("scroll"); 122 | internal static int scroll(IntPtr window) => call_scroll(window); 123 | 124 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 125 | private delegate IntPtr dt_subwin(IntPtr window, int rows, int colums, int y, int x); 126 | private static dt_subwin call_subwin = NativeToDelegate("subwin"); 127 | internal static IntPtr subwin(IntPtr window, int rows, int colums, int y, int x) => call_subwin(window, rows, colums, y, x); 128 | 129 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 130 | private delegate int dt_touchline(IntPtr window, int row, int column); 131 | private static dt_touchline call_touchline = NativeToDelegate("touchline"); 132 | internal static int touchline(IntPtr window, int row, int column) => call_touchline(window, row, column); 133 | 134 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 135 | private delegate int dt_touchwin(IntPtr window); 136 | private static dt_touchwin call_touchwin = NativeToDelegate("touchwin"); 137 | internal static int touchwin(IntPtr window) => call_touchwin(window); 138 | 139 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 140 | private delegate int dt_waddch(IntPtr window, int character); 141 | private static dt_waddch call_waddch = NativeToDelegate("waddch"); 142 | internal static int waddch(IntPtr window, int character) => call_waddch(window, character); 143 | 144 | [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)] 145 | private delegate int dt_waddstr(IntPtr window, string message); 146 | private static dt_waddstr call_waddstr = NativeToDelegate("waddstr"); 147 | internal static int waddstr(IntPtr window, string message) => call_waddstr(window, message); 148 | 149 | [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)] 150 | private delegate int dt_waddnstr(IntPtr win, String str, int n); 151 | private static dt_waddnstr call_waddnstr = NativeToDelegate("waddnstr"); 152 | internal static int waddnstr(IntPtr win, String str, int n) => call_waddnstr(win, str, n); 153 | 154 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 155 | private delegate int dt_wattron(IntPtr window, uint attributes); 156 | private static dt_wattron call_wattron = NativeToDelegate("wattron"); 157 | internal static int wattron(IntPtr window, uint attributes) => call_wattron(window, attributes); 158 | 159 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 160 | private delegate int dt_wattroff(IntPtr window, uint attributes); 161 | private static dt_wattroff call_wattroff = NativeToDelegate("wattroff"); 162 | internal static int wattroff(IntPtr window, uint attributes) => call_wattroff(window, attributes); 163 | 164 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 165 | private delegate int dt_wattrset(IntPtr window, uint attributes); 166 | private static dt_wattrset call_wattrset = NativeToDelegate("wattrset"); 167 | internal static int wattrset(IntPtr window, uint attributes) => call_wattrset(window, attributes); 168 | 169 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 170 | private delegate int dt_wbkgd(IntPtr window, uint ch); 171 | private static dt_wbkgd call_wbkgd = NativeToDelegate("wbkgd"); 172 | internal static int wbkgd(IntPtr window, uint ch) => call_wbkgd(window, ch); 173 | 174 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 175 | private delegate int dt_wborder(IntPtr window, char leftSide, char rightSide, char topSide, char bottomSide, char topLeftHandCorner, char topRightHandCorner, char bottomLeftHandCorner, char bottomRightHandCorner); 176 | private static dt_wborder call_wborder = NativeToDelegate("wborder"); 177 | internal static int wborder(IntPtr window, char leftSide, char rightSide, char topSide, char bottomSide, char topLeftHandCorner, char topRightHandCorner, char bottomLeftHandCorner, char bottomRightHandCorner) 178 | => call_wborder(window, leftSide, rightSide, topSide, bottomSide, topLeftHandCorner, topRightHandCorner, bottomLeftHandCorner, bottomRightHandCorner); 179 | 180 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 181 | private delegate int dt_wclear(IntPtr window); 182 | private static dt_wclear call_wclear = NativeToDelegate("wclear"); 183 | internal static int wclear(IntPtr window) => call_wclear(window); 184 | 185 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 186 | private delegate int dt_wgetch(IntPtr win); 187 | private static dt_wgetch call_wgetch = NativeToDelegate("wgetch"); 188 | internal static int wgetch(IntPtr win) => call_wgetch(win); 189 | 190 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 191 | private delegate uint dt_winch(IntPtr window); 192 | private static dt_winch call_winch = NativeToDelegate("winch"); 193 | internal static uint winch(IntPtr window) => call_winch(window); 194 | 195 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 196 | private delegate int dt_wmove(IntPtr window, int row, int column); 197 | private static dt_wmove call_wmove = NativeToDelegate("wmove"); 198 | internal static int wmove(IntPtr window, int row, int column) => call_wmove(window, row, column); 199 | 200 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 201 | private delegate int dt_wrefresh(IntPtr win); 202 | private static dt_wrefresh call_wrefresh = NativeToDelegate("wrefresh"); 203 | internal static int wrefresh(IntPtr win) => call_wrefresh(win); 204 | 205 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 206 | private delegate int dt_wscrl(IntPtr window, int numberOfLines); 207 | private static dt_wscrl call_wscrl = NativeToDelegate("wscrl"); 208 | internal static int wscrl(IntPtr window, int numberOfLines) => call_wscrl(window, numberOfLines); 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /dotnet-curses/PublicApi/NCursesCommon.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using Mindmagma.Curses.Interop; 3 | 4 | // common functions 5 | 6 | namespace Mindmagma.Curses 7 | { 8 | public static partial class NCurses 9 | { 10 | public static int AddChar(int ch) 11 | { 12 | int result = Native.addch(ch); 13 | NativeExceptionHelper.ThrowOnFailure(result, nameof(AddChar)); 14 | return result; 15 | } 16 | 17 | public static int AddString(string stringToAdd) 18 | { 19 | int result = Native.addstr(stringToAdd); 20 | NativeExceptionHelper.ThrowOnFailure(result, nameof(AddString)); 21 | return result; 22 | } 23 | 24 | public static void AssumeDefaultColors(int f, int b) 25 | { 26 | int result = Native.assume_default_colors(f, b); 27 | NativeExceptionHelper.ThrowOnFailure(result, nameof(AssumeDefaultColors)); 28 | } 29 | 30 | public static void AttributeOff(uint attributes) 31 | { 32 | int result = Native.attroff(attributes); 33 | NativeExceptionHelper.ThrowOnFailure(result, nameof(AttributeOff)); 34 | } 35 | 36 | public static void AttributeOn(uint attributes) 37 | { 38 | int result = Native.attron(attributes); 39 | NativeExceptionHelper.ThrowOnFailure(result, nameof(AttributeOn)); 40 | } 41 | 42 | public static void AttributeSet(uint attributes) 43 | { 44 | int result = Native.attrset(attributes); 45 | NativeExceptionHelper.ThrowOnFailure(result, nameof(AttributeSet)); 46 | } 47 | 48 | public static void Background(uint ch) 49 | { 50 | int result = Native.bkgd(ch); 51 | NativeExceptionHelper.ThrowOnFailure(result, nameof(Background)); 52 | } 53 | 54 | public static void Beep() 55 | { 56 | int result = Native.beep(); 57 | NativeExceptionHelper.ThrowOnFailure(result, nameof(Beep)); 58 | } 59 | 60 | public static void Clear() 61 | { 62 | int result = Native.clear(); 63 | NativeExceptionHelper.ThrowOnFailure(result, nameof(Clear)); 64 | } 65 | 66 | public static void ClearToEndOfLine() 67 | { 68 | int result = Native.clrtoeol(); 69 | NativeExceptionHelper.ThrowOnFailure(result, nameof(ClearToEndOfLine)); 70 | } 71 | 72 | public static void ClearToBottom() 73 | { 74 | int result = Native.clrtobot(); 75 | NativeExceptionHelper.ThrowOnFailure(result, nameof(ClearToBottom)); 76 | } 77 | 78 | public static void ColorContent(short color, out short red, out short green, out short blue) 79 | { 80 | int result = Native.color_content(color, out red, out green, out blue); 81 | NativeExceptionHelper.ThrowOnFailure(result, nameof(ColorContent)); 82 | } 83 | 84 | public static uint ColorPair(int pairNumber) 85 | { 86 | return Native.COLOR_PAIR(pairNumber); 87 | } 88 | 89 | public static void DeleteChar() 90 | { 91 | int result = Native.delch(); 92 | NativeExceptionHelper.ThrowOnFailure(result, nameof(DeleteChar)); 93 | } 94 | 95 | public static void DeleteLine() 96 | { 97 | int result = Native.deleteln(); 98 | NativeExceptionHelper.ThrowOnFailure(result, nameof(DeleteLine)); 99 | } 100 | 101 | public static void DoUpdate() 102 | { 103 | int result = Native.doupdate(); 104 | NativeExceptionHelper.ThrowOnFailure(result, nameof(DoUpdate)); 105 | } 106 | 107 | public static void Echo() 108 | { 109 | int result = Native.echo(); 110 | NativeExceptionHelper.ThrowOnFailure(result, nameof(Echo)); 111 | } 112 | 113 | public static void Erase() 114 | { 115 | int result = Native.erase(); 116 | NativeExceptionHelper.ThrowOnFailure(result, nameof(Erase)); 117 | } 118 | 119 | public static void Flash() 120 | { 121 | int result = Native.flash(); 122 | NativeExceptionHelper.ThrowOnFailure(result, nameof(Flash)); 123 | } 124 | 125 | public static void FlushInputBuffer() 126 | { 127 | int result = Native.flushinp(); 128 | NativeExceptionHelper.ThrowOnFailure(result, nameof(FlushInputBuffer)); 129 | } 130 | 131 | public static int GetChar() 132 | { 133 | int result = Native.getch(); // -1 is no character buffered, not ERR 134 | return result; 135 | } 136 | 137 | public static void GetMouse(out MouseEvent mouseEvent) 138 | { 139 | int result = Native.getmouse(out mouseEvent); 140 | NativeExceptionHelper.ThrowOnFailure(result, nameof(GetMouse)); 141 | } 142 | 143 | public static void GetString(StringBuilder message, int numberOfCharacters) 144 | { 145 | int result = Native.getnstr(message, numberOfCharacters); 146 | NativeExceptionHelper.ThrowOnFailure(result, nameof(GetString)); 147 | } 148 | 149 | public static void GetString(StringBuilder message) 150 | { 151 | int result = Native.getstr(message); 152 | NativeExceptionHelper.ThrowOnFailure(result, nameof(GetString)); 153 | } 154 | 155 | public static void InitColor(short color, short red, short green, short blue) 156 | { 157 | int result = Native.init_color(color, red, green, blue); 158 | NativeExceptionHelper.ThrowOnFailure(result, nameof(InitColor)); 159 | } 160 | 161 | public static int InitPair(short color, short foreground, short background) 162 | { 163 | int result = Native.init_pair(color, foreground, background); 164 | NativeExceptionHelper.ThrowOnFailure(result, nameof(InitPair)); 165 | return result; 166 | } 167 | 168 | public static void InsertChar(uint character) 169 | { 170 | int result = Native.insch(character); 171 | NativeExceptionHelper.ThrowOnFailure(result, nameof(InsertChar)); 172 | } 173 | 174 | public static void InsertLine() 175 | { 176 | int result = Native.insertln(); 177 | NativeExceptionHelper.ThrowOnFailure(result, nameof(InsertLine)); 178 | } 179 | 180 | public static uint MouseMask(uint newMask, out uint oldMask) 181 | { 182 | return Native.mousemask(newMask, out oldMask); 183 | } 184 | 185 | public static int Move(int y, int x) 186 | { 187 | int result = Native.move(y, x); 188 | NativeExceptionHelper.ThrowOnFailure(result, nameof(Move)); 189 | return result; 190 | } 191 | 192 | public static int MoveAddChar(int y, int x, uint character) 193 | { 194 | int result = Native.mvaddch(y, x, character); 195 | NativeExceptionHelper.ThrowOnFailure(result, nameof(MoveAddChar)); 196 | return result; 197 | } 198 | 199 | public static int MoveAddString(int y, int x, string message) 200 | { 201 | int result = Native.mvaddstr(y, x, message); 202 | NativeExceptionHelper.ThrowOnFailure(result, nameof(MoveAddString)); 203 | return result; 204 | } 205 | 206 | public static void PairContent(short pair, out short fg, out short bg) 207 | { 208 | int result = Native.pair_content(pair, out fg, out bg); 209 | NativeExceptionHelper.ThrowOnFailure(result, nameof(PairContent)); 210 | } 211 | 212 | public static short PairNumber(uint pairNumber) 213 | { 214 | return Native.PAIR_NUMBER(pairNumber); 215 | } 216 | 217 | public static int Refresh() 218 | { 219 | int result = Native.refresh(); 220 | NativeExceptionHelper.ThrowOnFailure(result, nameof(Refresh)); 221 | return result; 222 | } 223 | 224 | public static void ResizeTerminal(int numberOfLines, int numberOfColumns) 225 | { 226 | int result = Native.resize_term(numberOfLines, numberOfColumns); 227 | NativeExceptionHelper.ThrowOnFailure(result, nameof(ResizeTerminal)); 228 | } 229 | 230 | public static void ScrollLines(int numberOfLines) 231 | { 232 | int result = Native.scrl(numberOfLines); 233 | NativeExceptionHelper.ThrowOnFailure(result, nameof(ScrollLines)); 234 | } 235 | 236 | public static int SetCursor(int cursorState) 237 | { 238 | int result = Native.curs_set(cursorState); 239 | NativeExceptionHelper.ThrowOnFailure(result, nameof(SetCursor)); 240 | return result; 241 | } 242 | 243 | public static void SoftKeyLabelsClear() 244 | { 245 | int result = Native.slk_clear(); 246 | NativeExceptionHelper.ThrowOnFailure(result, nameof(SoftKeyLabelsClear)); 247 | } 248 | 249 | public static void SoftKeyLabelSet(int labelNumber, string text, int cursesSoftKeyLabelPosition) 250 | { 251 | int result = Native.slk_set(labelNumber, text, cursesSoftKeyLabelPosition); 252 | NativeExceptionHelper.ThrowOnFailure(result, nameof(SoftKeyLabelSet)); 253 | } 254 | 255 | public static void SoftKeyLabelsInit(int numberOfLabels) 256 | { 257 | int result = Native.slk_init(numberOfLabels); 258 | NativeExceptionHelper.ThrowOnFailure(result, nameof(SoftKeyLabelsInit)); 259 | } 260 | 261 | public static void SoftKeyLabelsRefresh() 262 | { 263 | int result = Native.slk_refresh(); 264 | NativeExceptionHelper.ThrowOnFailure(result, nameof(SoftKeyLabelsRefresh)); 265 | } 266 | 267 | public static void SoftKeyLabelsRestore() 268 | { 269 | int result = Native.slk_restore(); 270 | NativeExceptionHelper.ThrowOnFailure(result, nameof(SoftKeyLabelsRestore)); 271 | } 272 | 273 | public static void StartColor() 274 | { 275 | int result = Native.start_color(); 276 | NativeExceptionHelper.ThrowOnFailure(result, nameof(StartColor)); 277 | } 278 | 279 | public static int UngetChar(int character) 280 | { 281 | return Native.ungetch(character); 282 | } 283 | 284 | public static void UseDefaultColors() 285 | { 286 | int result = Native.use_default_colors(); 287 | NativeExceptionHelper.ThrowOnFailure(result, nameof(UseDefaultColors)); 288 | } 289 | 290 | } 291 | } 292 | -------------------------------------------------------------------------------- /dotnet-curses/PublicApi/NCursesEnvironment.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using Mindmagma.Curses.Interop; 4 | 5 | // startup/shutdown, trace (debugging), termcaps (terminal metadata), etc. 6 | 7 | namespace Mindmagma.Curses 8 | { 9 | public static partial class NCurses 10 | { 11 | 12 | public static bool CanChangeColor() 13 | { 14 | return Native.can_change_color(); 15 | } 16 | 17 | /// 18 | /// Individual characters will be returned (rather than "cooked" line-input mode), but some control characters (such as CTRL+C) may still be processed internally. 19 | /// 20 | public static void CBreak() 21 | { 22 | int result = Native.cbreak(); 23 | NativeExceptionHelper.ThrowOnFailure(result, nameof(CBreak)); 24 | } 25 | 26 | public static void EndWin() 27 | { 28 | int result = Native.endwin(); 29 | NativeExceptionHelper.ThrowOnFailure(result, nameof(EndWin)); 30 | } 31 | 32 | public static bool HasColors() 33 | { 34 | return Native.has_colors(); 35 | } 36 | 37 | public static IntPtr InitScreen() 38 | { 39 | IntPtr result = Native.initscr(); 40 | NativeExceptionHelper.ThrowOnFailure(result, nameof(InitScreen)); 41 | return result; 42 | } 43 | 44 | public static bool IsEndWin() 45 | { 46 | return Native.isendwin(); 47 | } 48 | 49 | public static int Nap(int milliseconds) 50 | { 51 | int result = Native.napms(milliseconds); 52 | NativeExceptionHelper.ThrowOnFailure(result, nameof(Nap)); 53 | return result; 54 | } 55 | 56 | /// 57 | /// Returns the terminal to "cooked" line-input mode. 58 | /// 59 | public static void NoCBreak() 60 | { 61 | int result = Native.nocbreak(); 62 | NativeExceptionHelper.ThrowOnFailure(result, nameof(NoCBreak)); 63 | } 64 | 65 | public static void NoEcho() 66 | { 67 | int result = Native.noecho(); 68 | NativeExceptionHelper.ThrowOnFailure(result, nameof(NoEcho)); 69 | } 70 | 71 | /// 72 | /// Returns the terminal to "cooked" line-input mode. 73 | /// 74 | public static void NoRaw() 75 | { 76 | int result = Native.noraw(); 77 | NativeExceptionHelper.ThrowOnFailure(result, nameof(NoRaw)); 78 | } 79 | 80 | /// 81 | /// Individual characters will be returned (rather than "cooked" line-input mode) with no internal processing of control characters. 82 | /// 83 | public static void Raw() 84 | { 85 | int result = Native.raw(); 86 | NativeExceptionHelper.ThrowOnFailure(result, nameof(Raw)); 87 | } 88 | 89 | /// 90 | /// Sets input to half-delay mode where characters are immediately available for input but blocking for tenths of a second with no input ERR is returned. 91 | /// 92 | public static void HalfDelay(int tenths) 93 | { 94 | int result = Native.halfdelay(tenths); 95 | NativeExceptionHelper.ThrowOnFailure(result, nameof(HalfDelay)); 96 | } 97 | 98 | /// 99 | /// Sets blocking or non-blocking mode. 100 | /// If delay is negative, blocking read is used. 101 | /// If delay is zero, non-blocking read is used and no input waiting returns ERR. 102 | /// If delay is positive, read blocks for delay milliseconds and then returns ERR if there is still no input. 103 | /// 104 | public static void TimeOut(int delay) 105 | { 106 | int result = Native.timeout(delay); 107 | NativeExceptionHelper.ThrowOnFailure(result, nameof(TimeOut)); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /dotnet-curses/PublicApi/NCursesLibraryHandle.cs: -------------------------------------------------------------------------------- 1 | using NativeLibraryLoader; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | 7 | // The library handle is retrieved here instead of in Native because 8 | // a constructor in Native would not run until the static fields are 9 | // initialized, and the static fields reference the library handle, 10 | // which causes a TypeInitializer null reference error. 11 | 12 | namespace Mindmagma.Curses.Interop 13 | { 14 | internal static class NCursesLibraryHandle 15 | { 16 | internal static NativeLibrary lib = FindLibrary(); 17 | 18 | private static NativeLibrary FindLibrary() 19 | { 20 | var defaults = new CursesLibraryNames(); 21 | var custom = GetCustomLibraryNames(); 22 | List names; 23 | 24 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 25 | { 26 | names = defaults.NamesWindows; 27 | if (custom != null) 28 | { 29 | if (custom.ReplaceWindowsDefaults) 30 | { 31 | names = custom.NamesWindows; 32 | } 33 | else 34 | { 35 | names.AddRange(custom.NamesWindows); 36 | } 37 | } 38 | } 39 | else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) 40 | { 41 | names = defaults.NamesLinux; 42 | if (custom != null) 43 | { 44 | if (custom.ReplaceLinuxDefaults) 45 | { 46 | names = custom.NamesLinux; 47 | } 48 | else 49 | { 50 | names.AddRange(custom.NamesLinux); 51 | } 52 | } 53 | } 54 | else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) 55 | { 56 | names = defaults.NamesOSX; 57 | if (custom != null) 58 | { 59 | if (custom.ReplaceOSXDefaults) 60 | { 61 | names = custom.NamesOSX; 62 | } 63 | else 64 | { 65 | names.AddRange(custom.NamesOSX); 66 | } 67 | } 68 | } 69 | else 70 | { 71 | throw new Exception("Unsupported OSPlatform, can't locate ncurses library."); 72 | } 73 | 74 | return new NativeLibrary(names.ToArray()); 75 | } 76 | 77 | private static CursesLibraryNames GetCustomLibraryNames() 78 | { 79 | string cname = nameof(CursesLibraryNames).ToString(); 80 | Type t_names = AppDomain.CurrentDomain.GetAssemblies() 81 | .SelectMany(t => t.GetTypes()) 82 | .FirstOrDefault(t => 83 | t.IsClass 84 | && !t.Name.Equals(cname) 85 | && typeof(CursesLibraryNames).IsAssignableFrom(t) 86 | && t.GetConstructor(Type.EmptyTypes) != null); 87 | 88 | return (t_names == null) ? null : (CursesLibraryNames)Activator.CreateInstance(t_names); 89 | } 90 | 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /dotnet-curses/PublicApi/NCursesPad.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using Mindmagma.Curses.Interop; 4 | 5 | // functions for working with curses pads 6 | 7 | namespace Mindmagma.Curses 8 | { 9 | public static partial class NCurses 10 | { 11 | public static IntPtr NewPad(int row, int column) 12 | { 13 | IntPtr result = Native.newpad(row, column); 14 | NativeExceptionHelper.ThrowOnFailure(result, nameof(NewPad)); 15 | return result; 16 | } 17 | 18 | public static int PadEchoChar(IntPtr pad, int character) 19 | { 20 | int result = Native.pechochar(pad, character); 21 | NativeExceptionHelper.ThrowOnFailure(result, nameof(PadEchoChar)); 22 | return result; 23 | } 24 | 25 | public static void PadNOutRefresh(IntPtr pad, int padMinRow, int padMinColumn, int screenMinRow, int screenMinColumn, int screenMaxRow, int screenMaxColumn) 26 | { 27 | int result = Native.pnoutrefresh(pad, padMinRow, padMinColumn, screenMinRow, screenMinColumn, screenMaxRow, screenMaxColumn); 28 | NativeExceptionHelper.ThrowOnFailure(result, nameof(PadNOutRefresh)); 29 | } 30 | 31 | public static void PadRefresh(IntPtr pad, int padMinRow, int padMinColumn, int screenMinRow, int screenMinColumn, int screenMaxRow, int screenMaxColumn) 32 | { 33 | int result = Native.prefresh(pad, padMinRow, padMinColumn, screenMinRow, screenMinColumn, screenMaxRow, screenMaxColumn); 34 | NativeExceptionHelper.ThrowOnFailure(result, nameof(PadRefresh)); 35 | } 36 | 37 | public static IntPtr SubPad(IntPtr parent, int rows, int columns, int y, int x) 38 | { 39 | IntPtr result = Native.subpad(parent, rows, columns, y, x); 40 | NativeExceptionHelper.ThrowOnFailure(result, nameof(SubPad)); 41 | return result; 42 | } 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /dotnet-curses/PublicApi/NCursesProperties.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using Mindmagma.Curses.Interop; 4 | 5 | // exported values (LINES, COLS, etc.) 6 | 7 | namespace Mindmagma.Curses 8 | { 9 | public static partial class NCurses 10 | { 11 | /// 12 | /// The number of columns visible. Maximum X position is one less (zero offset). 13 | /// 14 | public static int Columns => Native.COLS; 15 | 16 | /// 17 | /// The number of rows visible. Maximum Y position is one less (zero offset). 18 | /// 19 | public static int Lines => Native.LINES; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /dotnet-curses/PublicApi/NCursesWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using Mindmagma.Curses.Interop; 4 | 5 | // functions for working with curses windows (including stdscr) 6 | 7 | namespace Mindmagma.Curses 8 | { 9 | public static partial class NCurses 10 | { 11 | public static void Box(IntPtr window, char verticalChar, char horizontalChar) 12 | { 13 | int result = Native.box(window, verticalChar, horizontalChar); 14 | NativeExceptionHelper.ThrowOnFailure(result, nameof(Box)); 15 | } 16 | 17 | public static void ClearWindow(IntPtr window) 18 | { 19 | int result = Native.wclear(window); 20 | NativeExceptionHelper.ThrowOnFailure(result, nameof(ClearWindow)); 21 | } 22 | 23 | public static void CopyWindow(IntPtr sourceWindow, IntPtr destinationWindow, int sourceRow, int sourceColumn, int destinationRow, int destinationColumn, int rowOffset, int columnOffset, bool type) 24 | { 25 | int result = Native.copywin(sourceWindow, destinationWindow, sourceRow, sourceColumn, destinationRow, destinationColumn, rowOffset, columnOffset, type); 26 | NativeExceptionHelper.ThrowOnFailure(result, nameof(CopyWindow)); 27 | } 28 | 29 | public static int DeleteWindow(IntPtr window) 30 | { 31 | int result = Native.delwin(window); 32 | NativeExceptionHelper.ThrowOnFailure(result, nameof(DeleteWindow)); 33 | return result; 34 | } 35 | 36 | public static IntPtr DeriveWindow(IntPtr window, int rows, int columns, int y, int x) 37 | { 38 | IntPtr result = Native.derwin(window, rows, columns, y, x); 39 | NativeExceptionHelper.ThrowOnFailure(result, nameof(DeriveWindow)); 40 | return result; 41 | } 42 | 43 | public static IntPtr DuplicateWindow(IntPtr window) 44 | { 45 | IntPtr result = Native.dupwin(window); 46 | NativeExceptionHelper.ThrowOnFailure(result, nameof(DuplicateWindow)); 47 | return result; 48 | } 49 | 50 | public static void GetMaxYX(IntPtr window, out int y, out int x) 51 | { 52 | y = Native.getmaxy(window); 53 | NativeExceptionHelper.ThrowOnFailure(y, nameof(GetMaxYX)); 54 | x = Native.getmaxx(window); 55 | NativeExceptionHelper.ThrowOnFailure(x, nameof(GetMaxYX)); 56 | } 57 | 58 | public static void GetYX(IntPtr window, out int y, out int x) 59 | { 60 | y = Native.getcury(window); 61 | NativeExceptionHelper.ThrowOnFailure(y, nameof(GetYX)); 62 | x = Native.getcurx(window); 63 | NativeExceptionHelper.ThrowOnFailure(x, nameof(GetYX)); 64 | } 65 | 66 | public static void Keypad(IntPtr window, bool enable) 67 | { 68 | int result = Native.keypad(window, enable); 69 | NativeExceptionHelper.ThrowOnFailure(result, nameof(Keypad)); 70 | } 71 | 72 | public static int MoveWindowAddChar(IntPtr window, int y, int x, char c) 73 | { 74 | int result = Native.mvwaddch(window, y, x, c); 75 | NativeExceptionHelper.ThrowOnFailure(result, nameof(MoveWindowAddChar)); 76 | return result; 77 | } 78 | 79 | public static int MoveWindowAddString(IntPtr window, int y, int x, string message) 80 | { 81 | int result = Native.mvwaddstr(window, y, x, message); 82 | NativeExceptionHelper.ThrowOnFailure(result, nameof(MoveWindowAddString)); 83 | return result; 84 | } 85 | 86 | public static void MoveWindow(IntPtr window, int row, int column) 87 | { 88 | int result = Native.mvwin(window, row, column); 89 | NativeExceptionHelper.ThrowOnFailure(result, nameof(MoveWindow)); 90 | } 91 | 92 | public static int MoveWindowGetChar(IntPtr window, int y, int x) 93 | { 94 | int result = Native.mvwgetch(window, y, x); 95 | NativeExceptionHelper.ThrowOnFailure(result, nameof(MoveWindowGetChar)); 96 | return result; 97 | } 98 | 99 | public static uint MoveWindowInspectChar(IntPtr window, int y, int x) 100 | { 101 | uint result = Native.mvwinch(window, y, x); 102 | NativeExceptionHelper.ThrowOnFailure(result, nameof(MoveWindowInspectChar)); 103 | return result; 104 | } 105 | 106 | public static IntPtr NewWindow(int rows, int columns, int yOrigin, int xOrigin) 107 | { 108 | IntPtr result = Native.newwin(rows, columns, yOrigin, xOrigin); 109 | NativeExceptionHelper.ThrowOnFailure(result, nameof(NewWindow)); 110 | return result; 111 | } 112 | 113 | public static void NoDelay(IntPtr window, bool removeDelay) 114 | { 115 | int result = Native.nodelay(window, removeDelay); 116 | NativeExceptionHelper.ThrowOnFailure(result, nameof(NoDelay)); 117 | } 118 | 119 | public static void WindowTimeOut(IntPtr window, int delay) 120 | { 121 | int result = Native.wtimeout(window, delay); 122 | NativeExceptionHelper.ThrowOnFailure(result, nameof(WindowTimeOut)); 123 | } 124 | 125 | public static void Overlay(IntPtr sourceWindow, IntPtr destinationWindow) 126 | { 127 | int result = Native.overlay(sourceWindow, destinationWindow); 128 | NativeExceptionHelper.ThrowOnFailure(result, nameof(Overlay)); 129 | } 130 | 131 | public static void Overwrite(IntPtr sourceWindow, IntPtr destinationWindow) 132 | { 133 | int result = Native.overwrite(sourceWindow, destinationWindow); 134 | NativeExceptionHelper.ThrowOnFailure(result, nameof(Overwrite)); 135 | } 136 | 137 | public static void Scroll(IntPtr window) 138 | { 139 | int result = Native.scroll(window); 140 | NativeExceptionHelper.ThrowOnFailure(result, nameof(Scroll)); 141 | } 142 | 143 | public static void ScrollOk(IntPtr window, bool canScroll) 144 | { 145 | int result = Native.scrollok(window, canScroll); 146 | NativeExceptionHelper.ThrowOnFailure(result, nameof(ScrollOk)); 147 | } 148 | 149 | public static IntPtr SubWindow(IntPtr parent, int rows, int columns, int y, int x) 150 | { 151 | IntPtr result = Native.subwin(parent, rows, columns, y, x); 152 | NativeExceptionHelper.ThrowOnFailure(result, nameof(SubWindow)); 153 | return result; 154 | } 155 | 156 | public static void TouchLine(IntPtr window, int row, int column) 157 | { 158 | int result = Native.touchline(window, row, column); 159 | NativeExceptionHelper.ThrowOnFailure(result, nameof(TouchLine)); 160 | } 161 | 162 | public static int TouchWindow(IntPtr window) 163 | { 164 | int result = Native.touchwin(window); 165 | NativeExceptionHelper.ThrowOnFailure(result, nameof(TouchWindow)); 166 | return result; 167 | } 168 | 169 | public static int WindowAddChar(IntPtr window, int character) 170 | { 171 | int result = Native.waddch(window, character); 172 | NativeExceptionHelper.ThrowOnFailure(result, nameof(WindowAddChar)); 173 | return result; 174 | } 175 | 176 | public static int WindowAddString(IntPtr window, string message) 177 | { 178 | int result = Native.waddstr(window, message); 179 | NativeExceptionHelper.ThrowOnFailure(result, nameof(WindowAddString)); 180 | return result; 181 | } 182 | 183 | public static int WindowAttributeOn(IntPtr window, uint attributes) 184 | { 185 | int result = Native.wattron(window, attributes); 186 | NativeExceptionHelper.ThrowOnFailure(result, nameof(WindowAttributeOn)); 187 | return result; 188 | } 189 | 190 | public static int WindowAttributeOff(IntPtr window, uint attributes) 191 | { 192 | int result = Native.wattroff(window, attributes); 193 | NativeExceptionHelper.ThrowOnFailure(result, nameof(WindowAttributeOff)); 194 | return result; 195 | } 196 | 197 | public static int WindowAttributeSet(IntPtr window, uint attributes) 198 | { 199 | int result = Native.wattrset(window, attributes); 200 | NativeExceptionHelper.ThrowOnFailure(result, nameof(WindowAttributeSet)); 201 | return result; 202 | } 203 | 204 | public static void WindowBackground(IntPtr window, uint ch) 205 | { 206 | int result = Native.wbkgd(window, ch); 207 | NativeExceptionHelper.ThrowOnFailure(result, nameof(WindowBackground)); 208 | } 209 | 210 | public static void WindowBorder(IntPtr window, char leftSide, char rightSide, char topSide, char bottomSide, char topLeftHandCorner, char topRightHandCorner, char bottomLeftHandCorner, char bottomRightHandCorner) 211 | { 212 | int result = Native.wborder(window, leftSide, rightSide, topSide, bottomSide, topLeftHandCorner, topRightHandCorner, bottomLeftHandCorner, bottomRightHandCorner); 213 | NativeExceptionHelper.ThrowOnFailure(result, nameof(WindowBorder)); 214 | } 215 | 216 | public static int WindowGetChar(IntPtr window) 217 | { 218 | int result = Native.wgetch(window); 219 | NativeExceptionHelper.ThrowOnFailure(result, nameof(WindowGetChar)); 220 | return result; 221 | } 222 | 223 | public static uint WindowInspectChar(IntPtr window) 224 | { 225 | uint result = Native.winch(window); 226 | NativeExceptionHelper.ThrowOnFailure(result, nameof(WindowInspectChar)); 227 | return result; 228 | } 229 | 230 | public static int WindowMove(IntPtr window, int row, int column) 231 | { 232 | int result = Native.wmove(window, row, column); 233 | NativeExceptionHelper.ThrowOnFailure(result, nameof(WindowMove)); 234 | return result; 235 | } 236 | 237 | public static int WindowRefresh(IntPtr window) 238 | { 239 | int result = Native.wrefresh(window); 240 | NativeExceptionHelper.ThrowOnFailure(result, nameof(WindowRefresh)); 241 | return result; 242 | } 243 | 244 | public static void WindowScrollLines(IntPtr window, int numberOfLines) 245 | { 246 | int result = Native.wscrl(window, numberOfLines); 247 | NativeExceptionHelper.ThrowOnFailure(result, nameof(WindowScrollLines)); 248 | } 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /dotnet-curses/Support/CursesLibraryNames.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Mindmagma.Curses 4 | { 5 | /// 6 | /// A library client can implement this interface to expand or 7 | /// replace the default NCurses library names on each target OS. 8 | /// 9 | public class CursesLibraryNames 10 | { 11 | /// 12 | /// Defaults to false, override this to set it to true which ignores 13 | /// the default NCurses library names built into dotnet-curses for 14 | /// OSPlatform.Windows. 15 | /// 16 | public virtual bool ReplaceWindowsDefaults => false; 17 | 18 | /// 19 | /// The list of default NCurses library names built into dotnet-curses 20 | /// for OSPlatform.Windows. Override this to add to the defaults, or 21 | /// also override the Replace property to replace the defaults. 22 | /// 23 | public virtual List NamesWindows => new List { "libncursesw6" }; 24 | 25 | /// 26 | /// Defaults to false, override this to set it to true which ignores 27 | /// the default NCurses library names built into dotnet-curses for 28 | /// OSPlatform.Linux. 29 | /// 30 | public virtual bool ReplaceLinuxDefaults => false; 31 | 32 | /// 33 | /// The list of default NCurses library names built into dotnet-curses 34 | /// for OSPlatform.Linux. Override this to add to the defaults, or 35 | /// also override the Replace property to replace the defaults. 36 | /// 37 | public virtual List NamesLinux => new List { "libncurses.so", "libncurses.so.6", "libncurses.so.5.9" }; 38 | 39 | /// 40 | /// Defaults to false, override this to set it to true which ignores 41 | /// the default NCurses library names built into dotnet-curses for 42 | /// OSPlatform.OSX. 43 | /// 44 | public virtual bool ReplaceOSXDefaults => false; 45 | 46 | /// 47 | /// The list of default NCurses library names built into dotnet-curses 48 | /// for OSPlatform.OSX. Override this to add to the defaults, or 49 | /// also override the Replace property to replace the defaults. 50 | /// 51 | public virtual List NamesOSX => new List { "libncurses.dylib" }; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /dotnet-curses/Support/DotnetCursesException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Mindmagma.Curses 4 | { 5 | public class DotnetCursesException : Exception 6 | { 7 | public DotnetCursesException() 8 | { } 9 | 10 | public DotnetCursesException(string message) : base(message) 11 | { } 12 | 13 | public DotnetCursesException(string message, Exception inner) : base(message, inner) 14 | { } 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /dotnet-curses/Support/NativeExceptionHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Mindmagma.Curses 4 | { 5 | public class NativeExceptionHelper : DotnetCursesException 6 | { 7 | internal NativeExceptionHelper() 8 | { } 9 | 10 | internal NativeExceptionHelper(string message) : base(message) 11 | { } 12 | 13 | internal NativeExceptionHelper(string message, Exception inner) : base (message, inner) 14 | { } 15 | 16 | internal static void ThrowOnFailure(int result, string method) 17 | { 18 | if (result == -1) throw new DotnetCursesException($"{method}() returned ERR"); 19 | } 20 | 21 | internal static void ThrowOnFailure(uint result, string method) 22 | { 23 | if (result == uint.MaxValue) throw new DotnetCursesException($"{method}() returned ERR"); 24 | } 25 | 26 | internal static void ThrowOnFailure(IntPtr result, string method) 27 | { 28 | if (result == IntPtr.Zero) throw new DotnetCursesException($"{method}() returned NULL"); 29 | } 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /dotnet-curses/dotnet-curses.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | Mindmagma.Curses 6 | Portable cross-platform .NET Standard wrapper for the Unix ncurses library 7 | Jon McGuire 8 | 1.0.3 9 | dotnet-curses 10 | curses;ncurses 11 | https://github.com/MV10/dotnet-curses/blob/master/LICENSE 12 | https://github.com/MV10/dotnet-curses/ 13 | git 14 | https://github.com/MV10/dotnet-curses/ 15 | 1.0.3 16 | true 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /sample-fireworks/MoreCursesLibraryNames.cs: -------------------------------------------------------------------------------- 1 | using Mindmagma.Curses; 2 | using System.Collections.Generic; 3 | 4 | namespace sample_fireworks 5 | { 6 | // This is only here to provide an example of supplementing or 7 | // overriding the default library names. The provided name is 8 | // the same as the default. 9 | 10 | public class MoreCursesLibraryNames : CursesLibraryNames 11 | { 12 | public override bool ReplaceWindowsDefaults => true; 13 | public override List NamesWindows => new List { "libncursesw6.dll" }; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /sample-fireworks/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Mindmagma.Curses; 3 | 4 | namespace sample_fireworks 5 | { 6 | // Converted from sushihangover's implemenation of the PDCurses firework.c demo 7 | 8 | class Program 9 | { 10 | private const int FRAMERATE = 150; 11 | 12 | private static IntPtr Screen; 13 | 14 | private static readonly Random rng = new Random(); 15 | 16 | private static readonly short[] color_table = { 17 | CursesColor.RED, 18 | CursesColor.BLUE, 19 | CursesColor.GREEN, 20 | CursesColor.CYAN, 21 | CursesColor.RED, 22 | CursesColor.MAGENTA, 23 | CursesColor.YELLOW, 24 | CursesColor.WHITE 25 | }; 26 | 27 | static void Main(string[] args) 28 | { 29 | Screen = NCurses.InitScreen(); 30 | try 31 | { 32 | Fireworks(); 33 | } 34 | finally 35 | { 36 | NCurses.EndWin(); 37 | } 38 | } 39 | 40 | private static void Fireworks() 41 | { 42 | NCurses.NoDelay(Screen, true); 43 | NCurses.NoEcho(); 44 | 45 | if(NCurses.HasColors()) 46 | { 47 | NCurses.StartColor(); 48 | for (short i = 1; i < 8; i++) 49 | NCurses.InitPair(i, color_table[i], CursesColor.BLACK); 50 | } 51 | 52 | int flag = 0; 53 | while(NCurses.GetChar() == -1) 54 | { 55 | int start, end, row, diff, direction; 56 | do 57 | { 58 | start = rng.Next(NCurses.Columns - 3); 59 | end = rng.Next(NCurses.Columns - 3); 60 | start = (start < 2) ? 2 : start; 61 | end = (end < 2) ? 2 : end; 62 | direction = (start > end) ? -1 : 1; 63 | diff = Math.Abs(start - end); 64 | } while (diff < 2 || diff >= NCurses.Lines - 2); 65 | 66 | NCurses.AttributeSet(CursesAttribute.NORMAL); 67 | for (row = 1; row < diff; ++row) 68 | { 69 | NCurses.MoveAddString(NCurses.Lines - row, row * direction + start, (direction < 0) ? "\\" : "/"); 70 | if (flag++ > 0) 71 | { 72 | MyRefresh(); 73 | NCurses.Erase(); 74 | flag = 0; 75 | } 76 | } 77 | 78 | if (flag++ > 0) 79 | { 80 | MyRefresh(); 81 | flag = 0; 82 | } 83 | 84 | Explode(NCurses.Lines - row, diff * direction + start); 85 | NCurses.Erase(); 86 | MyRefresh(); 87 | } 88 | } 89 | 90 | private static void Explode(int row, int col) 91 | { 92 | NCurses.Erase(); 93 | AddStr(row, col, "-"); 94 | MyRefresh(); 95 | 96 | col--; 97 | 98 | GetColor(); 99 | AddStr(row - 1, col, " - "); 100 | AddStr(row, col, "-+-"); 101 | AddStr(row + 1, col, " - "); 102 | MyRefresh(); 103 | 104 | col--; 105 | 106 | GetColor(); 107 | AddStr(row - 2, col, " --- "); 108 | AddStr(row - 1, col, "-+++-"); 109 | AddStr(row, col, "-+#+-"); 110 | AddStr(row + 1, col, "-+++-"); 111 | AddStr(row + 2, col, " --- "); 112 | MyRefresh(); 113 | 114 | GetColor(); 115 | AddStr(row - 2, col, " +++ "); 116 | AddStr(row - 1, col, "++#++"); 117 | AddStr(row, col, "+# #+"); 118 | AddStr(row + 1, col, "++#++"); 119 | AddStr(row + 2, col, " +++ "); 120 | MyRefresh(); 121 | 122 | GetColor(); 123 | AddStr(row - 2, col, " # "); 124 | AddStr(row - 1, col, "## ##"); 125 | AddStr(row, col, "# #"); 126 | AddStr(row + 1, col, "## ##"); 127 | AddStr(row + 2, col, " # "); 128 | MyRefresh(); 129 | 130 | GetColor(); 131 | AddStr(row - 2, col, " # # "); 132 | AddStr(row - 1, col, "# #"); 133 | AddStr(row, col, " "); 134 | AddStr(row + 1, col, "# #"); 135 | AddStr(row + 2, col, " # # "); 136 | MyRefresh(); 137 | } 138 | 139 | private static void AddStr(int y, int x, string str) 140 | { 141 | if (x >= 0 && x < NCurses.Columns && y >= 0 && y < NCurses.Lines) 142 | NCurses.MoveAddString(y, x, str); 143 | } 144 | 145 | private static void MyRefresh() 146 | { 147 | NCurses.Nap(FRAMERATE); 148 | NCurses.Move(NCurses.Lines - 1, NCurses.Columns - 1); 149 | NCurses.Refresh(); 150 | } 151 | 152 | private static void GetColor() 153 | { 154 | uint bold = (rng.Next(2) > 0) ? CursesAttribute.BOLD : CursesAttribute.NORMAL; 155 | NCurses.AttributeSet(NCurses.ColorPair((short)rng.Next(8)) | bold); 156 | } 157 | 158 | } 159 | } 160 | 161 | -------------------------------------------------------------------------------- /sample-fireworks/sample-fireworks.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.1 6 | sample_fireworks 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /sample-mouse/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Mindmagma.Curses; 3 | 4 | namespace sample_mouse 5 | { 6 | class Program 7 | { 8 | private static IntPtr Screen; 9 | 10 | private static readonly Random rng = new Random(); 11 | 12 | static void Main(string[] args) 13 | { 14 | Screen = NCurses.InitScreen(); 15 | try 16 | { 17 | Mouse(); 18 | } 19 | finally 20 | { 21 | NCurses.EndWin(); 22 | } 23 | } 24 | 25 | static void Mouse() 26 | { 27 | NCurses.NoDelay(Screen, true); 28 | NCurses.NoEcho(); 29 | 30 | NCurses.MoveAddString(0, 0, "Click a button or press any key to exit."); 31 | NCurses.MoveAddString(2, 0, "[X] [Y]"); 32 | 33 | // some terminals require this to differentiate mouse "keys" from random keyboard input 34 | NCurses.Keypad(Screen, true); 35 | 36 | // not reporting mouse movement? 37 | // https://stackoverflow.com/questions/52047158/report-mouse-position-for-ncurses-on-windows/52053196 38 | // https://stackoverflow.com/questions/7462850/mouse-movement-events-in-ncurses 39 | 40 | var eventsToReport = 41 | CursesMouseEvent.BUTTON1_CLICKED | 42 | CursesMouseEvent.BUTTON2_CLICKED | 43 | CursesMouseEvent.REPORT_MOUSE_POSITION; 44 | 45 | var availableMouseEvents = NCurses.MouseMask(eventsToReport, out uint oldMask); 46 | 47 | bool exit = false; 48 | bool update = true; 49 | while(!exit) 50 | { 51 | switch(NCurses.GetChar()) 52 | { 53 | case CursesKey.MOUSE: 54 | try 55 | { 56 | NCurses.GetMouse(out MouseEvent mouse); 57 | NCurses.MoveAddString(3, 0, $"{mouse.x.ToString("000")} {mouse.y.ToString("000")}"); 58 | update = true; 59 | } 60 | catch (DotnetCursesException) 61 | { 62 | // no events in the queue 63 | } 64 | break; 65 | 66 | case -1: 67 | // no input received 68 | break; 69 | 70 | default: 71 | exit = true; 72 | break; 73 | } 74 | 75 | if (update) 76 | { 77 | NCurses.Move(NCurses.Lines - 1, NCurses.Columns - 1); 78 | NCurses.Refresh(); 79 | update = false; 80 | } 81 | } 82 | 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /sample-mouse/sample-mouse.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.1 6 | sample_mouse 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | --------------------------------------------------------------------------------