diff --git a/Demos/Sharpie.Demos.Bounce/Sharpie.Demos.Bounce.csproj b/Demos/Sharpie.Demos.Bounce/Sharpie.Demos.Bounce.csproj
index 1a49ddb..a773ba0 100644
--- a/Demos/Sharpie.Demos.Bounce/Sharpie.Demos.Bounce.csproj
+++ b/Demos/Sharpie.Demos.Bounce/Sharpie.Demos.Bounce.csproj
@@ -24,7 +24,7 @@
-
+
diff --git a/Demos/Sharpie.Demos.Events/Sharpie.Demos.Events.csproj b/Demos/Sharpie.Demos.Events/Sharpie.Demos.Events.csproj
index 1f4bfa3..6ed9933 100644
--- a/Demos/Sharpie.Demos.Events/Sharpie.Demos.Events.csproj
+++ b/Demos/Sharpie.Demos.Events/Sharpie.Demos.Events.csproj
@@ -24,7 +24,7 @@
-
+
diff --git a/Demos/Sharpie.Demos.Font/Sharpie.Demos.Font.csproj b/Demos/Sharpie.Demos.Font/Sharpie.Demos.Font.csproj
index 439a882..efd2b4e 100644
--- a/Demos/Sharpie.Demos.Font/Sharpie.Demos.Font.csproj
+++ b/Demos/Sharpie.Demos.Font/Sharpie.Demos.Font.csproj
@@ -26,7 +26,7 @@
-
+
diff --git a/Demos/Sharpie.Demos.Slk/Sharpie.Demos.Slk.csproj b/Demos/Sharpie.Demos.Slk/Sharpie.Demos.Slk.csproj
index e471be5..f8f34e7 100644
--- a/Demos/Sharpie.Demos.Slk/Sharpie.Demos.Slk.csproj
+++ b/Demos/Sharpie.Demos.Slk/Sharpie.Demos.Slk.csproj
@@ -24,7 +24,7 @@
-
+
diff --git a/Demos/Sharpie.Demos.Snake/Sharpie.Demos.Snake.csproj b/Demos/Sharpie.Demos.Snake/Sharpie.Demos.Snake.csproj
index a441e4a..b0b4068 100644
--- a/Demos/Sharpie.Demos.Snake/Sharpie.Demos.Snake.csproj
+++ b/Demos/Sharpie.Demos.Snake/Sharpie.Demos.Snake.csproj
@@ -24,7 +24,7 @@
-
+
diff --git a/Demos/Sharpie.Demos.Windows/Sharpie.Demos.Windows.csproj b/Demos/Sharpie.Demos.Windows/Sharpie.Demos.Windows.csproj
index a7dedbd..e509572 100644
--- a/Demos/Sharpie.Demos.Windows/Sharpie.Demos.Windows.csproj
+++ b/Demos/Sharpie.Demos.Windows/Sharpie.Demos.Windows.csproj
@@ -26,7 +26,7 @@
-
+
diff --git a/Sharpie.Tests/CursesBackendTests.cs b/Sharpie.Tests/CursesBackendTests.cs
index 6a07730..3df40b4 100644
--- a/Sharpie.Tests/CursesBackendTests.cs
+++ b/Sharpie.Tests/CursesBackendTests.cs
@@ -49,6 +49,18 @@ private void MockLoadResult(string lib, bool result)
});
}
+ private void VerifyAttempts(params string[] candidates)
+ {
+ foreach (var c in candidates)
+ {
+ _dotNetSystemAdapterMock.Verify(
+ s => s.TryLoadNativeLibrary(c, out It.Ref.IsAny), Times.Once);
+ }
+
+ _dotNetSystemAdapterMock.Verify(
+ s => s.TryLoadNativeLibrary(It.IsAny(), out It.Ref.IsAny), Times.Exactly(candidates.Length));
+ }
+
[TestInitialize]
public void TestInitialize()
{
@@ -147,35 +159,110 @@ public void NCurses2_CallsNCurses1()
out It.Ref.IsAny), Times.Once);
}
- [TestMethod]
- public void NCurses2_ForLinux_HasManyOptionsForNCurses()
+ [TestMethod, DataRow("linux"), DataRow("freebsd")]
+ public void NCurses2_ForLinuxOrFreeBsd_HasSpecificOptions(string op)
{
_dotNetSystemAdapterMock.Setup(s => s.IsLinux)
- .Returns(true);
+ .Returns(op == "linux");
+ _dotNetSystemAdapterMock.Setup(s => s.IsFreeBsd)
+ .Returns(op == "freebsd");
var options = new[]
{
- "ncursesw",
- "libncursesw.so",
- "libncursesw.so.5",
"libncursesw.so.6",
- "ncurses",
- "libncurses.so",
- "libncurses.so.5",
+ "libncursesw.so.5",
+ "libncursesw.so",
+ "ncursesw",
"libncurses.so.6",
+ "libncurses.so.5",
+ "libncurses.so",
+ "ncurses",
};
Should.Throw(() => CursesBackend.NCurses(_dotNetSystemAdapterMock.Object));
- foreach (var option in options)
+ VerifyAttempts(options);
+ }
+
+ [TestMethod]
+ public void NCurses2_ForMacOs_TriesToLoadDefault_IfNoHomeBrewFound()
+ {
+ _dotNetSystemAdapterMock.Setup(s => s.IsMacOs)
+ .Returns(true);
+
+ Should.Throw(() => CursesBackend.NCurses(_dotNetSystemAdapterMock.Object));
+
+ VerifyAttempts("ncurses");
+ }
+
+ [TestMethod]
+ public void NCurses2_ForMacOs_ScansTheLibraryDirectory_IfNoHomeBrewFound()
+ {
+ _dotNetSystemAdapterMock.Setup(s => s.IsMacOs)
+ .Returns(true);
+
+ _dotNetSystemAdapterMock.Setup(s => s.CombinePaths(It.IsAny()))
+ .Returns((string[] ps) => string.Join("+", ps));
+ _dotNetSystemAdapterMock.Setup(s => s.GetEnvironmentVariable("HOMEBREW_PREFIX")).Returns("/h");
+ _dotNetSystemAdapterMock.Setup(s => s.DirectoryExists("/h+lib")).Returns(true);
+ _dotNetSystemAdapterMock.Setup(s => s.EnumerateFiles("/h+lib")).Returns(new[]
{
- _dotNetSystemAdapterMock.Verify(
- s => s.TryLoadNativeLibrary(option, It.IsAny(), It.IsAny(),
- out It.Ref.IsAny), Times.Once);
- }
+ "dummy.txt",
+ "libncurses.10",
+ "libncurses.dylib",
+ "libncurses.a.dylib",
+ "libncurses.1.dylib",
+ "libncurses.10.dylib"
+ });
- _dotNetSystemAdapterMock.Verify(
- s => s.TryLoadNativeLibrary(It.IsAny(), It.IsAny(), It.IsAny(),
- out It.Ref.IsAny), Times.Exactly(options.Length));
+ Should.Throw(() => CursesBackend.NCurses(_dotNetSystemAdapterMock.Object));
+
+ VerifyAttempts("/h+lib+libncurses.1.dylib", "/h+lib+libncurses.10.dylib", "ncurses");
+ }
+
+ [TestMethod]
+ public void NCurses2_ForMacOs_ScansTheCellarDirectories_IfNoHomeBrewFound()
+ {
+ _dotNetSystemAdapterMock.Setup(s => s.IsMacOs)
+ .Returns(true);
+
+ _dotNetSystemAdapterMock.Setup(s => s.CombinePaths(It.IsAny()))
+ .Returns((string[] ps) => string.Join("+", ps));
+ _dotNetSystemAdapterMock.Setup(s => s.GetEnvironmentVariable("HOMEBREW_CELLAR")).Returns("/h");
+ _dotNetSystemAdapterMock.Setup(s => s.DirectoryExists("/h+ncurses")).Returns(true);
+ _dotNetSystemAdapterMock.Setup(s => s.DirectoryExists("/h+ncurses-one+lib")).Returns(true);
+ _dotNetSystemAdapterMock.Setup(s => s.DirectoryExists("/h+ncurses-2+lib")).Returns(true);
+ _dotNetSystemAdapterMock.Setup(s => s.EnumerateDirectories("/h+ncurses")).Returns(new[]
+ {
+ "/h+ncurses-one",
+ "/h+ncurses-2"
+ });
+
+ _dotNetSystemAdapterMock.Setup(s => s.EnumerateFiles("/h+ncurses-one+lib")).Returns(new[]
+ {
+ "dummy.txt",
+ "libncurses.10",
+ "libncurses.dylib",
+ "libncurses.a.dylib",
+ "libncurses.1.dylib",
+ "libncurses.10.dylib"
+ });
+
+ _dotNetSystemAdapterMock.Setup(s => s.EnumerateFiles("/h+ncurses-2+lib")).Returns(new[]
+ {
+ "dummy.txt",
+ "libncurses.2.dylib",
+ "libncurses.12.dylib"
+ });
+
+ Should.Throw(() => CursesBackend.NCurses(_dotNetSystemAdapterMock.Object));
+
+ VerifyAttempts(
+ "/h+ncurses-one+lib+libncurses.1.dylib",
+ "/h+ncurses-2+lib+libncurses.2.dylib",
+ "/h+ncurses-one+lib+libncurses.10.dylib",
+ "/h+ncurses-2+lib+libncurses.12.dylib",
+ "ncurses");
}
+
}
diff --git a/Sharpie.Tests/CursesMouseEventParserTests.cs b/Sharpie.Tests/CursesMouseEventParserTests.cs
new file mode 100644
index 0000000..89b8a12
--- /dev/null
+++ b/Sharpie.Tests/CursesMouseEventParserTests.cs
@@ -0,0 +1,192 @@
+/*
+Copyright (c) 2022, Alexandru Ciobanu
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+namespace Sharpie.Tests;
+
+[TestClass]
+public class CursesMouseEventParserTests
+{
+ [TestMethod]
+ public void Get_ReturnsObject_ForAbi1()
+ {
+ var r = CursesMouseEventParser.Get(1);
+ r.ShouldNotBeNull();
+
+ r.ReportPosition.ShouldBe(8u << 24);
+ r.All.ShouldBe((8u << 24) - 1);
+ }
+
+ [TestMethod]
+ public void Get_ReturnsObject_ForAbi2()
+ {
+ var r = CursesMouseEventParser.Get(2);
+ r.ShouldNotBeNull();
+
+ r.ReportPosition.ShouldBe(8u << 25);
+ r.All.ShouldBe((8u << 25) - 1);
+ }
+
+ [TestMethod]
+ public void Get_ReturnsAbi1_ForUnknownAbi()
+ {
+ CursesMouseEventParser.Get(-1).ShouldBe(CursesMouseEventParser.Get(1));
+ }
+
+ [TestMethod,
+ DataRow(1u << ((1 - 1) * 6), MouseButton.Button1, MouseButtonState.Released),
+ DataRow(2u << ((1 - 1) * 6), MouseButton.Button1, MouseButtonState.Pressed),
+ DataRow(4u << ((1 - 1) * 6), MouseButton.Button1, MouseButtonState.Clicked),
+ DataRow(8u << ((1 - 1) * 6), MouseButton.Button1, MouseButtonState.DoubleClicked),
+ DataRow(16u << ((1 - 1) * 6), MouseButton.Button1, MouseButtonState.TripleClicked),
+
+ DataRow(1u << ((2 - 1) * 6), MouseButton.Button2, MouseButtonState.Released),
+ DataRow(2u << ((2 - 1) * 6), MouseButton.Button2, MouseButtonState.Pressed),
+ DataRow(4u << ((2 - 1) * 6), MouseButton.Button2, MouseButtonState.Clicked),
+ DataRow(8u << ((2 - 1) * 6), MouseButton.Button2, MouseButtonState.DoubleClicked),
+ DataRow(16u << ((2 - 1) * 6), MouseButton.Button2, MouseButtonState.TripleClicked),
+
+ DataRow(1u << ((3 - 1) * 6), MouseButton.Button3, MouseButtonState.Released),
+ DataRow(2u << ((3 - 1) * 6), MouseButton.Button3, MouseButtonState.Pressed),
+ DataRow(4u << ((3 - 1) * 6), MouseButton.Button3, MouseButtonState.Clicked),
+ DataRow(8u << ((3 - 1) * 6), MouseButton.Button3, MouseButtonState.DoubleClicked),
+ DataRow(16u << ((3 - 1) * 6), MouseButton.Button3, MouseButtonState.TripleClicked),
+
+ DataRow(1u << ((4 - 1) * 6), MouseButton.Button4, MouseButtonState.Released),
+ DataRow(2u << ((4 - 1) * 6), MouseButton.Button4, MouseButtonState.Pressed),
+ DataRow(4u << ((4 - 1) * 6), MouseButton.Button4, MouseButtonState.Clicked),
+ DataRow(8u << ((4 - 1) * 6), MouseButton.Button4, MouseButtonState.DoubleClicked),
+ DataRow(16u << ((4 - 1) * 6), MouseButton.Button4, MouseButtonState.TripleClicked)]
+ public void Parse_ParsesTheButtonAndState_ForAbi1(uint raw, MouseButton expButton, MouseButtonState expState)
+ {
+ var parser = CursesMouseEventParser.Get(1);
+ var p = parser.Parse(raw);
+
+ p.ShouldBe((expButton, expState, ModifierKey.None));
+ }
+
+
+ [TestMethod,
+ DataRow(1u << ((1 - 1) * 5), MouseButton.Button1, MouseButtonState.Released),
+ DataRow(2u << ((1 - 1) * 5), MouseButton.Button1, MouseButtonState.Pressed),
+ DataRow(4u << ((1 - 1) * 5), MouseButton.Button1, MouseButtonState.Clicked),
+ DataRow(8u << ((1 - 1) * 5), MouseButton.Button1, MouseButtonState.DoubleClicked),
+ DataRow(16u << ((1 - 1) * 5), MouseButton.Button1, MouseButtonState.TripleClicked),
+
+ DataRow(1u << ((2 - 1) * 5), MouseButton.Button2, MouseButtonState.Released),
+ DataRow(2u << ((2 - 1) * 5), MouseButton.Button2, MouseButtonState.Pressed),
+ DataRow(4u << ((2 - 1) * 5), MouseButton.Button2, MouseButtonState.Clicked),
+ DataRow(8u << ((2 - 1) * 5), MouseButton.Button2, MouseButtonState.DoubleClicked),
+ DataRow(16u << ((2 - 1) * 5), MouseButton.Button2, MouseButtonState.TripleClicked),
+
+ DataRow(1u << ((3 - 1) * 5), MouseButton.Button3, MouseButtonState.Released),
+ DataRow(2u << ((3 - 1) * 5), MouseButton.Button3, MouseButtonState.Pressed),
+ DataRow(4u << ((3 - 1) * 5), MouseButton.Button3, MouseButtonState.Clicked),
+ DataRow(8u << ((3 - 1) * 5), MouseButton.Button3, MouseButtonState.DoubleClicked),
+ DataRow(16u << ((3 - 1) * 5), MouseButton.Button3, MouseButtonState.TripleClicked),
+
+ DataRow(1u << ((4 - 1) * 5), MouseButton.Button4, MouseButtonState.Released),
+ DataRow(2u << ((4 - 1) * 5), MouseButton.Button4, MouseButtonState.Pressed),
+ DataRow(4u << ((4 - 1) * 5), MouseButton.Button4, MouseButtonState.Clicked),
+ DataRow(8u << ((4 - 1) * 5), MouseButton.Button4, MouseButtonState.DoubleClicked),
+ DataRow(16u << ((4 - 1) * 5), MouseButton.Button4, MouseButtonState.TripleClicked),
+
+ DataRow(1u << ((5 - 1) * 5), MouseButton.Button5, MouseButtonState.Released),
+ DataRow(2u << ((5 - 1) * 5), MouseButton.Button5, MouseButtonState.Pressed),
+ DataRow(4u << ((5 - 1) * 5), MouseButton.Button5, MouseButtonState.Clicked),
+ DataRow(8u << ((5 - 1) * 5), MouseButton.Button5, MouseButtonState.DoubleClicked),
+ DataRow(16u << ((5 - 1) * 5), MouseButton.Button5, MouseButtonState.TripleClicked),
+ ]
+ public void Parse_ParsesTheButtonAndState_ForAbi2(uint raw, MouseButton expButton, MouseButtonState expState)
+ {
+ var parser = CursesMouseEventParser.Get(2);
+ var p = parser.Parse(raw);
+
+ p.ShouldBe((expButton, expState, ModifierKey.None));
+ }
+
+ [TestMethod,
+ DataRow(0u, ModifierKey.None),
+ DataRow(1u << 24, ModifierKey.Ctrl),
+ DataRow(2u << 24, ModifierKey.Shift),
+ DataRow(4u << 24, ModifierKey.Alt),
+ DataRow((4u << 24) | (1u << 24), ModifierKey.Alt | ModifierKey.Ctrl),
+ DataRow((2u << 24) | (1u << 24), ModifierKey.Shift | ModifierKey.Ctrl),
+ DataRow((4u << 24) | (2u << 24), ModifierKey.Alt | ModifierKey.Shift),
+ DataRow((1u << 24) | (2u << 24), ModifierKey.Ctrl | ModifierKey.Shift),
+ DataRow((4u << 24) | (1u << 24) | (2u << 24),
+ ModifierKey.Alt | ModifierKey.Shift | ModifierKey.Ctrl)]
+ public void Parse_ParsesTheModifiers_ForAbi1(uint raw, ModifierKey expMod)
+ {
+ var parser = CursesMouseEventParser.Get(1);
+ var p = parser.Parse(raw | 1u);
+
+ p.ShouldBe((MouseButton.Button1, MouseButtonState.Released,expMod));
+ }
+
+
+ [TestMethod,
+ DataRow(0u, ModifierKey.None),
+ DataRow(1u << 25, ModifierKey.Ctrl),
+ DataRow(2u << 25, ModifierKey.Shift),
+ DataRow(4u << 25, ModifierKey.Alt),
+ DataRow((4u << 25) | (1u << 25), ModifierKey.Alt | ModifierKey.Ctrl),
+ DataRow((2u << 25) | (1u << 25), ModifierKey.Shift | ModifierKey.Ctrl),
+ DataRow((4u << 25) | (2u << 25), ModifierKey.Alt | ModifierKey.Shift),
+ DataRow((1u << 25) | (2u << 25), ModifierKey.Ctrl | ModifierKey.Shift),
+ DataRow((4u << 25) | (1u << 25) | (2u << 25),
+ ModifierKey.Alt | ModifierKey.Shift | ModifierKey.Ctrl)]
+ public void Parse_ParsesTheModifiers_ForAbi2(uint raw, ModifierKey expMod)
+ {
+ var parser = CursesMouseEventParser.Get(2);
+ var p = parser.Parse(raw | 1u);
+
+ p.ShouldBe((MouseButton.Button1, MouseButtonState.Released,expMod));
+ }
+
+ [TestMethod,
+ DataRow(0u), DataRow(8u << 24), DataRow(1u << 24)]
+ public void Parse_ReturnsNullIfNoButtonPresent_ForAbi1(uint raw)
+ {
+ var parser = CursesMouseEventParser.Get(1);
+ var p = parser.Parse(raw);
+
+ p.ShouldBeNull();
+ }
+
+ [TestMethod,
+ DataRow(0u), DataRow(8u << 25), DataRow(1u << 25)]
+ public void Parse_ReturnsNullIfNoButtonPresent_ForAbi2(uint raw)
+ {
+ var parser = CursesMouseEventParser.Get(2);
+ var p = parser.Parse(raw);
+
+ p.ShouldBeNull();
+ }
+}
diff --git a/Sharpie.Tests/EventPumpTests.cs b/Sharpie.Tests/EventPumpTests.cs
index fe178fb..0c83b41 100644
--- a/Sharpie.Tests/EventPumpTests.cs
+++ b/Sharpie.Tests/EventPumpTests.cs
@@ -112,6 +112,10 @@ public void TestInitialize()
_cursesMock.Setup(s => s.initscr())
.Returns(new IntPtr(100));
+ _cursesMock.Setup(s => s.mouse_version())
+ .Returns(1);
+
+
_terminal = new(_cursesMock.Object,
new(UseStandardKeySequenceResolvers: false,
ManagedWindows: TestContext.TestName!.Contains("_WhenManaged_")));
@@ -567,7 +571,7 @@ public void Listen1_SkipsInvalidMouseEvents()
var dx = skip ? 10 : 0;
me = new()
{
- x = dx + 5, y = dx + 6, buttonState = (uint) CursesMouseEvent.EventType.ReportPosition
+ x = dx + 5, y = dx + 6, buttonState = 8u << 24 // report position
};
var res = skip ? -1 : 0;
@@ -582,35 +586,17 @@ public void Listen1_SkipsInvalidMouseEvents()
_cursesMock.Verify(v => v.getmouse(out It.Ref.IsAny), Times.Exactly(2));
}
-
- [TestMethod, Timeout(Timeout)]
- public void Listen1_SkipsMouseEvents_WithBadButtons()
- {
- _pump.UseInternalMouseEventResolver = false;
-
- var skip = true;
- _cursesMock.Setup(s => s.getmouse(out It.Ref.IsAny))
- .Returns((out CursesMouseEvent me) =>
- {
- me = new() { buttonState = skip ? 0 : (uint) CursesMouseEvent.EventType.Button2Released };
-
- skip = !skip;
- return 0;
- });
-
- var e = SimulateEventRep(2, (int) CursesKey.Yes, (int) CursesKey.Mouse);
- ((MouseActionEvent) e).Button.ShouldBe(MouseButton.Button2);
-
- _cursesMock.Verify(v => v.getmouse(out It.Ref.IsAny), Times.Exactly(2));
- }
-
+
[TestMethod, Timeout(Timeout)]
public void Listen1_ProcessesMouseMoveEvents()
{
_cursesMock.Setup(s => s.getmouse(out It.Ref.IsAny))
.Returns((out CursesMouseEvent me) =>
{
- me = new() { x = 5, y = 6, buttonState = (uint) CursesMouseEvent.EventType.ReportPosition };
+ me = new()
+ {
+ x = 5, y = 6, buttonState = 8u << 24 // report position
+ };
return 0;
});
@@ -627,7 +613,10 @@ public void Listen1_ProcessesMouseMoveEvents_AndUsesInternalMouseResolver()
_cursesMock.Setup(s => s.getmouse(out It.Ref.IsAny))
.Returns((out CursesMouseEvent me) =>
{
- me = new() { x = 5, y = 6, buttonState = (uint) CursesMouseEvent.EventType.ReportPosition };
+ me = new()
+ {
+ x = 5, y = 6, buttonState = 8u << 24 // report position
+ };
return 0;
});
@@ -651,8 +640,7 @@ public void Listen1_ProcessesMouseActionEvents()
{
x = 5,
y = 6,
- buttonState = (uint) CursesMouseEvent.EventType.Button1Clicked |
- (uint) CursesMouseEvent.EventType.Alt
+ buttonState = (4u << ((1 - 1) * 6)) | (4u << 24) // Button1Clicked + Alt
};
return 0;
@@ -680,8 +668,7 @@ public void Listen1_ProcessesMouseActionEvents_AndUsesInternalMouseResolver()
{
x = 5,
y = 6,
- buttonState = (uint) CursesMouseEvent.EventType.Button1Pressed |
- (uint) CursesMouseEvent.EventType.Alt
+ buttonState = (2u << ((1 - 1) * 6)) | (4u << 24) // Button1Pressed + Alt
};
return 0;
@@ -837,7 +824,10 @@ public void Listen1_ConsidersBreaksInSequences()
_cursesMock.Setup(s => s.getmouse(out It.Ref.IsAny))
.Returns((out CursesMouseEvent me) =>
{
- me = new() { buttonState = (uint) CursesMouseEvent.EventType.ReportPosition };
+ me = new()
+ {
+ buttonState = 8u << 24 // report position
+ };
return 0;
});
diff --git a/Sharpie.Tests/HelpersTests.cs b/Sharpie.Tests/HelpersTests.cs
index 984bf31..8d79d79 100644
--- a/Sharpie.Tests/HelpersTests.cs
+++ b/Sharpie.Tests/HelpersTests.cs
@@ -282,48 +282,6 @@ public void ConvertKeyPressEvent_ConvertsKnownMappings(uint rawKey, Key expKey,
result.modifierKey.ShouldBe(expMod);
}
- [TestMethod, DataRow(CursesMouseEvent.EventType.Button1Released, MouseButton.Button1, MouseButtonState.Released),
- DataRow(CursesMouseEvent.EventType.Button1Pressed, MouseButton.Button1, MouseButtonState.Pressed),
- DataRow(CursesMouseEvent.EventType.Button1Clicked, MouseButton.Button1, MouseButtonState.Clicked),
- DataRow(CursesMouseEvent.EventType.Button1DoubleClicked, MouseButton.Button1, MouseButtonState.DoubleClicked),
- DataRow(CursesMouseEvent.EventType.Button1TripleClicked, MouseButton.Button1, MouseButtonState.TripleClicked),
- DataRow(CursesMouseEvent.EventType.Button2Released, MouseButton.Button2, MouseButtonState.Released),
- DataRow(CursesMouseEvent.EventType.Button2Pressed, MouseButton.Button2, MouseButtonState.Pressed),
- DataRow(CursesMouseEvent.EventType.Button2Clicked, MouseButton.Button2, MouseButtonState.Clicked),
- DataRow(CursesMouseEvent.EventType.Button2DoubleClicked, MouseButton.Button2, MouseButtonState.DoubleClicked),
- DataRow(CursesMouseEvent.EventType.Button2TripleClicked, MouseButton.Button2, MouseButtonState.TripleClicked),
- DataRow(CursesMouseEvent.EventType.Button3Released, MouseButton.Button3, MouseButtonState.Released),
- DataRow(CursesMouseEvent.EventType.Button3Pressed, MouseButton.Button3, MouseButtonState.Pressed),
- DataRow(CursesMouseEvent.EventType.Button3Clicked, MouseButton.Button3, MouseButtonState.Clicked),
- DataRow(CursesMouseEvent.EventType.Button3DoubleClicked, MouseButton.Button3, MouseButtonState.DoubleClicked),
- DataRow(CursesMouseEvent.EventType.Button3TripleClicked, MouseButton.Button3, MouseButtonState.TripleClicked),
- DataRow(CursesMouseEvent.EventType.Button4Released, MouseButton.Button4, MouseButtonState.Released),
- DataRow(CursesMouseEvent.EventType.Button4Pressed, MouseButton.Button4, MouseButtonState.Pressed),
- DataRow(CursesMouseEvent.EventType.Button4Clicked, MouseButton.Button4, MouseButtonState.Clicked),
- DataRow(CursesMouseEvent.EventType.Button4DoubleClicked, MouseButton.Button4, MouseButtonState.DoubleClicked),
- DataRow(CursesMouseEvent.EventType.Button4TripleClicked, MouseButton.Button4, MouseButtonState.TripleClicked)]
- public void ConvertMouseActionEvent_ConvertsKnownMappings(int evt, MouseButton expButton, MouseButtonState expState)
- {
- var result = Helpers.ConvertMouseActionEvent((CursesMouseEvent.EventType) evt);
- result.button.ShouldBe(expButton);
- result.state.ShouldBe(expState);
- }
-
- [TestMethod, DataRow(0, ModifierKey.None), DataRow(CursesMouseEvent.EventType.Alt, ModifierKey.Alt),
- DataRow(CursesMouseEvent.EventType.Ctrl, ModifierKey.Ctrl),
- DataRow(CursesMouseEvent.EventType.Shift, ModifierKey.Shift),
- DataRow(CursesMouseEvent.EventType.Alt | CursesMouseEvent.EventType.Ctrl, ModifierKey.Alt | ModifierKey.Ctrl),
- DataRow(CursesMouseEvent.EventType.Shift | CursesMouseEvent.EventType.Ctrl, ModifierKey.Shift | ModifierKey.Ctrl),
- DataRow(CursesMouseEvent.EventType.Alt | CursesMouseEvent.EventType.Shift, ModifierKey.Alt | ModifierKey.Shift),
- DataRow(CursesMouseEvent.EventType.Ctrl | CursesMouseEvent.EventType.Shift, ModifierKey.Ctrl | ModifierKey.Shift),
- DataRow(CursesMouseEvent.EventType.Alt | CursesMouseEvent.EventType.Ctrl | CursesMouseEvent.EventType.Shift,
- ModifierKey.Alt | ModifierKey.Shift | ModifierKey.Ctrl)]
- public void ConvertMouseActionEvent_MapsModifiers(int evt, ModifierKey expMod)
- {
- var result = Helpers.ConvertMouseActionEvent((CursesMouseEvent.EventType) evt);
- result.modifierKey.ShouldBe(expMod);
- }
-
[TestMethod]
public void EnumerateInHalves_Throws_IfCountIsNegative()
{
diff --git a/Sharpie.Tests/NCursesBackendTests.cs b/Sharpie.Tests/NCursesBackendTests.cs
index 677a649..bf04c27 100644
--- a/Sharpie.Tests/NCursesBackendTests.cs
+++ b/Sharpie.Tests/NCursesBackendTests.cs
@@ -39,9 +39,7 @@ public class NCursesBackendTests
private Mock _dotNetSystemAdapterMock = null!;
private Mock _nativeSymbolResolverMock = null!;
- private static CursesComplexChar MakeTestComplexChar(uint x) =>
- new(x, x, x, x, x,
- x);
+ private static CursesComplexChar MakeTestComplexChar(uint x) => new() { _attrAndColorPair = x };
[TestInitialize]
public void TestInitialize()
@@ -526,6 +524,9 @@ public void initscr_IsRelayedToLibrary(int ret)
public void longname_IsRelayedToLibrary(string ret)
{
var h = Marshal.StringToHGlobalAnsi(ret);
+ _dotNetSystemAdapterMock.Setup(s => s.NativeLibraryAnsiStrPtrToString(It.IsAny()))
+ .CallBase();
+
_nativeSymbolResolverMock.MockResolve(s => s(), h);
_backend.longname()
@@ -536,6 +537,9 @@ public void longname_IsRelayedToLibrary(string ret)
public void termname_IsRelayedToLibrary(string ret)
{
var h = Marshal.StringToHGlobalAnsi(ret);
+ _dotNetSystemAdapterMock.Setup(s => s.NativeLibraryAnsiStrPtrToString(It.IsAny()))
+ .CallBase();
+
_nativeSymbolResolverMock.MockResolve(s => s(), h);
_backend.termname()
@@ -546,6 +550,8 @@ public void termname_IsRelayedToLibrary(string ret)
public void curses_version_IsRelayedToLibrary(string ret)
{
var h = Marshal.StringToHGlobalAnsi(ret);
+ _dotNetSystemAdapterMock.Setup(s => s.NativeLibraryAnsiStrPtrToString(It.IsAny()))
+ .CallBase();
_nativeSymbolResolverMock.MockResolve(s => s(), h);
_backend.curses_version()
@@ -1030,6 +1036,9 @@ public void slk_label_IsRelayedToLibrary(string ret)
{
const int i = 999;
var h = Marshal.StringToHGlobalAnsi(ret);
+ _dotNetSystemAdapterMock.Setup(s => s.NativeLibraryAnsiStrPtrToString(It.IsAny()))
+ .CallBase();
+
_nativeSymbolResolverMock.MockResolve(s => s(i), h);
_backend.slk_label(i)
@@ -1211,6 +1220,10 @@ public void wenclose_IsRelayedToLibrary(bool ret)
public void keybound_IsRelayedToLibrary(string ret)
{
var h = Marshal.StringToHGlobalAnsi(ret);
+
+ _dotNetSystemAdapterMock.Setup(s => s.NativeLibraryAnsiStrPtrToString(It.IsAny()))
+ .CallBase();
+
_nativeSymbolResolverMock.MockResolve(s => s('A', 2), h);
_backend.keybound('A', 2)
@@ -1221,6 +1234,9 @@ public void keybound_IsRelayedToLibrary(string ret)
public void keyname_IsRelayedToLibrary(string ret)
{
var h = Marshal.StringToHGlobalAnsi(ret);
+ _dotNetSystemAdapterMock.Setup(s => s.NativeLibraryAnsiStrPtrToString(It.IsAny()))
+ .CallBase();
+
_nativeSymbolResolverMock.MockResolve(s => s('A'), h);
_backend.keyname('A')
@@ -1231,6 +1247,9 @@ public void keyname_IsRelayedToLibrary(string ret)
public void key_name_IsRelayedToLibrary(string ret)
{
var h = Marshal.StringToHGlobalAnsi(ret);
+ _dotNetSystemAdapterMock.Setup(s => s.NativeLibraryAnsiStrPtrToString(It.IsAny()))
+ .CallBase();
+
_nativeSymbolResolverMock.MockResolve(s => s('A'), h);
_backend.key_name('A')
@@ -1718,6 +1737,9 @@ public void wadd_wchnstr_IsRelayedToLibrary(int ret)
[TestMethod, DataRow(0), DataRow(-1)]
public void init_color_IsRelayedToLibrary(int ret)
{
+ _dotNetSystemAdapterMock.Setup(s => s.NativeLibraryAnsiStrPtrToString(It.IsAny()))
+ .CallBase();
+
_nativeSymbolResolverMock.MockResolve(s => s(1, 2, 3, 4), ret);
_backend.init_color(1, 2, 3, 4)
@@ -1738,7 +1760,9 @@ public void wunctrl_IsRelayedToLibrary(string ret)
{
var ch = new CursesComplexChar();
var h = Marshal.StringToHGlobalUni(ret);
-
+ _dotNetSystemAdapterMock.Setup(s => s.NativeLibraryUnicodeStrPtrToString(It.IsAny()))
+ .CallBase();
+
_nativeSymbolResolverMock.MockResolve(s => s(ref ch), h);
_backend.wunctrl(ch)
@@ -2035,6 +2059,9 @@ public void pair_content_IsRelayedToLibrary(int ret)
[TestMethod, DataRow(0), DataRow(-1)]
public void color_content_IsRelayedToLibrary(int ret)
{
+ _dotNetSystemAdapterMock.Setup(s => s.NativeLibraryAnsiStrPtrToString(It.IsAny()))
+ .CallBase();
+
_nativeSymbolResolverMock.MockResolve()
.Setup(s => s(1, out It.Ref.IsAny, out It.Ref.IsAny,
out It.Ref.IsAny))
@@ -2055,12 +2082,27 @@ public void color_content_IsRelayedToLibrary(int ret)
((int) blue).ShouldBe(33);
}
+ [TestMethod, DataRow("something", -1), DataRow("6.2.3", 2), DataRow("something6.2.3", 2),
+ DataRow("something 5.7", -1), DataRow("something 4.7.5", -1), DataRow("something 5.7.12312", 1)]
+ public void mouse_version_ParsesCursesVersion(string ver, int m)
+ {
+ var h = Marshal.StringToHGlobalAnsi(ver);
+ _dotNetSystemAdapterMock.Setup(s => s.NativeLibraryAnsiStrPtrToString(It.IsAny()))
+ .CallBase();
+ _nativeSymbolResolverMock.MockResolve()
+ .Setup(s => s())
+ .Returns(h);
+
+ _backend.mouse_version()
+ .ShouldBe(m);
+ }
+
[TestMethod, DataRow(0), DataRow(-1)]
public void mousemask_IsRelayedToLibrary(int ret)
{
_nativeSymbolResolverMock.MockResolve()
- .Setup(s => s(1, out It.Ref.IsAny))
- .Returns((int _, out int om) =>
+ .Setup(s => s(1, out It.Ref.IsAny))
+ .Returns((uint _, out uint om) =>
{
om = 11;
return ret;
@@ -2070,9 +2112,10 @@ public void mousemask_IsRelayedToLibrary(int ret)
_backend.mousemask(1, out var old)
.ShouldBe(ret);
- old.ShouldBe(11);
+ old.ShouldBe(11u);
}
+
[TestMethod, DataRow(0), DataRow(-1)]
public void wattr_get_IsRelayedToLibrary(int ret)
{
diff --git a/Sharpie.Tests/NativeLibraryWrapperTests.cs b/Sharpie.Tests/NativeLibraryWrapperTests.cs
index cb59943..4328aa6 100644
--- a/Sharpie.Tests/NativeLibraryWrapperTests.cs
+++ b/Sharpie.Tests/NativeLibraryWrapperTests.cs
@@ -79,6 +79,8 @@ public void TryLoad_TriesToLoadByName_IfHasNoDirectory_ThenByPath()
[TestMethod]
public void TryLoad_TriesToLoadByPath_IfHasDirectory()
{
+ _dotNetSystemAdapterMock.Setup(s => s.GetDirectoryName(It.IsAny()))
+ .Returns("something");
NativeLibraryWrapper.TryLoad(_dotNetSystemAdapterMock.Object, new[] { "hello/world" });
_dotNetSystemAdapterMock.Verify(
diff --git a/Sharpie.Tests/Sharpie.Tests.csproj b/Sharpie.Tests/Sharpie.Tests.csproj
index 0fc3058..9879c47 100644
--- a/Sharpie.Tests/Sharpie.Tests.csproj
+++ b/Sharpie.Tests/Sharpie.Tests.csproj
@@ -22,16 +22,16 @@
-
-
-
-
-
-
+
+
+
+
+
+
-
+
diff --git a/Sharpie.Tests/TerminalTests.cs b/Sharpie.Tests/TerminalTests.cs
index 71ccc09..3c9896e 100644
--- a/Sharpie.Tests/TerminalTests.cs
+++ b/Sharpie.Tests/TerminalTests.cs
@@ -289,19 +289,24 @@ public void Ctor_Throws_WhenCursesFailsToPreparesCaretMode(bool enabled)
.Operation.ShouldBe("curs_set");
}
- [TestMethod, DataRow(true), DataRow(false)]
- public void Ctor_PreparesUseMouse_ByAskingCurses(bool enabled)
+ [TestMethod, DataRow(true, 1), DataRow(true, 2), DataRow(false, 0)]
+ public void Ctor_PreparesUseMouse_ByAskingCurses(bool enabled, int abi)
{
+ _cursesMock.Setup(s => s.mouse_version())
+ .Returns(abi);
+
_terminal = new(_cursesMock.Object, new(UseMouse: enabled, MouseClickInterval: 999));
_terminal.Events.UseInternalMouseEventResolver.ShouldBeFalse();
_cursesMock.Verify(v => v.mouseinterval(999), enabled ? Times.Once : Times.Never);
+ var parser = CursesMouseEventParser.Get(abi);
var expMask = enabled
- ? (int) CursesMouseEvent.EventType.ReportPosition | (int) CursesMouseEvent.EventType.All
+ ? parser.ReportPosition | parser.All
: 0;
- _cursesMock.Verify(v => v.mousemask(expMask, out It.Ref.IsAny), Times.Once);
+ _cursesMock.Verify(v => v.mousemask(expMask, out It.Ref.IsAny), Times.Once);
+ _cursesMock.Verify(v => v.mouse_version(), Times.Exactly(enabled ? 2: 1));
}
[TestMethod]
@@ -316,7 +321,7 @@ public void Ctor_PreparesUseMouse_WithoutClickInterval_ByAskingCurses()
[TestMethod, DataRow(true), DataRow(false), SuppressMessage("ReSharper", "StringLiteralTypo")]
public void Ctor_Throws_WhenCursesFailsToPreparesUseMouse_1(bool enabled)
{
- _cursesMock.Setup(s => s.mousemask(It.IsAny(), out It.Ref.IsAny))
+ _cursesMock.Setup(s => s.mousemask(It.IsAny(), out It.Ref.IsAny))
.Returns(-1);
Should.Throw(() => new Terminal(_cursesMock.Object, new(UseMouse: enabled)))
@@ -880,8 +885,8 @@ public void Dispose_RestoresCursesDefaults()
_cursesMock.Setup(s => s.mouseinterval(It.IsAny()))
.Returns(199);
- _cursesMock.Setup(s => s.mousemask(It.IsAny(), out It.Ref.IsAny))
- .Returns((int _, out int o) =>
+ _cursesMock.Setup(s => s.mousemask(It.IsAny(), out It.Ref.IsAny))
+ .Returns((uint _, out uint o) =>
{
o = 888;
return 0;
@@ -895,20 +900,20 @@ public void Dispose_RestoresCursesDefaults()
_terminal.Dispose();
_cursesMock.Verify(v => v.mouseinterval(199), Times.Once);
- _cursesMock.Verify(v => v.mousemask(888, out It.Ref.IsAny), Times.Once);
+ _cursesMock.Verify(v => v.mousemask(888, out It.Ref.IsAny), Times.Once);
_cursesMock.Verify(v => v.curs_set(66), Times.Once);
}
[TestMethod]
- public void Dispose_DoeNotThrow_IfCursesFails()
+ public void Dispose_DoesNotThrow_IfCursesFails()
{
_terminal = new(_cursesMock.Object, _settings);
_cursesMock.Setup(s => s.mouseinterval(It.IsAny()))
.Returns(-1);
- _cursesMock.Setup(s => s.mousemask(It.IsAny(), out It.Ref.IsAny))
- .Returns((int _, out int o) =>
+ _cursesMock.Setup(s => s.mousemask(It.IsAny(), out It.Ref.IsAny))
+ .Returns((uint _, out uint o) =>
{
o = 888;
return -1;
diff --git a/Sharpie.Tests/UnixNCursesBackendTests.cs b/Sharpie.Tests/UnixNCursesBackendTests.cs
index 33dd4a8..c2e2657 100644
--- a/Sharpie.Tests/UnixNCursesBackendTests.cs
+++ b/Sharpie.Tests/UnixNCursesBackendTests.cs
@@ -30,6 +30,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
namespace Sharpie.Tests;
+using System.Runtime.InteropServices;
using Nito.Disposables;
[TestClass, SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
@@ -107,8 +108,8 @@ public void mousemask_CallsCursesButNotNotConsole_IfCursesFails()
.Returns(true);
_nativeSymbolResolverMock.MockResolve()
- .Setup(s => s(It.IsAny(), out It.Ref.IsAny))
- .Returns((int _, out int o) =>
+ .Setup(s => s(It.IsAny(), out It.Ref.IsAny))
+ .Returns((uint _, out uint o) =>
{
o = 999;
return -1;
@@ -117,25 +118,60 @@ public void mousemask_CallsCursesButNotNotConsole_IfCursesFails()
_backend.mousemask(100, out var old)
.ShouldBe(-1);
- old.ShouldBe(999);
+ old.ShouldBe(999u);
_dotNetSystemAdapterMock.Verify(v => v.OutAndFlush(It.IsAny()), Times.Never);
}
- [TestMethod, SuppressMessage("ReSharper", "IdentifierTypo"), DataRow(0, "\x1b[?1003l"),
- DataRow((int) CursesMouseEvent.EventType.ReportPosition, "\x1b[?1003h"),
- DataRow((int) CursesMouseEvent.EventType.All, "\x1b[?1000h")]
- public void mousemask_CallsCursesAndConsole_IfCursesSucceeds_WithReportPosition(int mask, string exp)
+ [TestMethod, SuppressMessage("ReSharper", "IdentifierTypo"),
+ DataRow(1), DataRow(2)]
+ public void mousemask_OutsToConsole_WhenReportingPosition(int abi)
{
- _dotNetSystemAdapterMock.Setup(s => s.IsFreeBsd)
- .Returns(true);
-
_nativeSymbolResolverMock.MockResolve(
- s => s(It.IsAny(), out It.Ref.IsAny), 0);
+ s => s(It.IsAny(), out It.Ref.IsAny), 0);
+
+ var version = abi == 2 ? "version 6.0.0" : "version 1.0.0";
+ _nativeSymbolResolverMock.MockResolve(
+ s => s(), Marshal.StringToHGlobalAnsi(version));
+ _dotNetSystemAdapterMock.Setup(s => s.NativeLibraryAnsiStrPtrToString(It.IsAny()))
+ .CallBase();
+
+ var parser = CursesMouseEventParser.Get(abi);
+ _backend.mousemask(parser.ReportPosition, out var _)
+ .ShouldBe(0);
- _backend.mousemask(mask, out var _)
+ _dotNetSystemAdapterMock.Verify(v => v.OutAndFlush("\x1b[?1003h"), Times.Once);
+ }
+
+ [TestMethod, SuppressMessage("ReSharper", "IdentifierTypo"),
+ DataRow(1), DataRow(2)]
+ public void mousemask_OutsToConsole_WhenAll(int abi)
+ {
+ _nativeSymbolResolverMock.MockResolve(
+ s => s(It.IsAny(), out It.Ref.IsAny), 0);
+
+ var version = abi == 2 ? "version 6.0.0" : "version 1.0.0";
+ _nativeSymbolResolverMock.MockResolve(
+ s => s(), Marshal.StringToHGlobalAnsi(version));
+ _dotNetSystemAdapterMock.Setup(s => s.NativeLibraryAnsiStrPtrToString(It.IsAny()))
+ .CallBase();
+ var parser = CursesMouseEventParser.Get(abi);
+ _backend.mousemask(parser.All, out var _)
.ShouldBe(0);
- _dotNetSystemAdapterMock.Verify(v => v.OutAndFlush(exp), Times.Once);
+ _dotNetSystemAdapterMock.Verify(v => v.OutAndFlush("\x1b[?1000h"), Times.Once);
+ }
+
+ [TestMethod, SuppressMessage("ReSharper", "IdentifierTypo")]
+ public void mousemask_OutsToConsole_WhenNothing()
+ {
+ _nativeSymbolResolverMock.MockResolve(
+ s => s(It.IsAny(), out It.Ref.IsAny), 0);
+
+ _nativeSymbolResolverMock.MockResolve();
+ _backend.mousemask(0, out var _)
+ .ShouldBe(0);
+
+ _dotNetSystemAdapterMock.Verify(v => v.OutAndFlush("\x1b[?1003l"), Times.Once);
}
}
diff --git a/Sharpie/Abstractions/IColorManager.cs b/Sharpie/Abstractions/IColorManager.cs
index 4a0e6a8..84f9187 100644
--- a/Sharpie/Abstractions/IColorManager.cs
+++ b/Sharpie/Abstractions/IColorManager.cs
@@ -211,3 +211,4 @@ public interface IColorManager
///
(short red, short green, short blue) BreakdownColor(StandardColor color);
}
+
diff --git a/Sharpie/Abstractions/ICursesBackend.cs b/Sharpie/Abstractions/ICursesBackend.cs
index 01790b3..e45f089 100644
--- a/Sharpie/Abstractions/ICursesBackend.cs
+++ b/Sharpie/Abstractions/ICursesBackend.cs
@@ -431,7 +431,9 @@ int wborder_set(IntPtr window, CursesComplexChar leftSide, CursesComplexChar rig
int ungetmouse(CursesMouseEvent @event);
- int mousemask(int newMask, out int oldMask);
+ int mousemask(uint newMask, out uint oldMask);
+
+ int mouse_version();
bool wenclose(IntPtr window, int line, int col);
@@ -445,3 +447,4 @@ int wborder_set(IntPtr window, CursesComplexChar leftSide, CursesComplexChar rig
bool monitor_pending_resize(Action action, [NotNullWhen(true)] out IDisposable? handle);
}
+
diff --git a/Sharpie/Abstractions/IDotNetSystemAdapter.cs b/Sharpie/Abstractions/IDotNetSystemAdapter.cs
index 0501fa1..08e183b 100644
--- a/Sharpie/Abstractions/IDotNetSystemAdapter.cs
+++ b/Sharpie/Abstractions/IDotNetSystemAdapter.cs
@@ -1,84 +1,85 @@
namespace Sharpie.Abstractions;
-using System.Reflection;
-using System.Runtime.Versioning;
-
///
-/// An internal interface used to help test the functionality or native library loader.
+/// An internal interface used to help test the functionality or native library loader.
///
-
internal interface IDotNetSystemAdapter
{
- private sealed class DotNetSystemAdapter: IDotNetSystemAdapter
- {
- }
-
///
- /// The actual instance that connects this interface to the .NET runtime.
+ /// The actual instance that connects this interface to the .NET runtime.
///
- public static IDotNetSystemAdapter Instance = new DotNetSystemAdapter();
-
- ///
- [ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
- bool TryLoadNativeLibrary(string libraryName, Assembly assembly, DllImportSearchPath? searchPath,
- out IntPtr handle) =>
- NativeLibrary.TryLoad(libraryName, assembly, searchPath, out handle);
-
- ///
- [ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
- bool TryLoadNativeLibrary(string libraryPath, out IntPtr handle) => NativeLibrary.TryLoad(libraryPath, out handle);
-
- ///
- [ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
- bool TryGetNativeLibraryExport(IntPtr handle, string name, out IntPtr address) =>
- NativeLibrary.TryGetExport(handle, name, out address);
-
- ///
- [ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
- void FreeNativeLibrary(IntPtr handle) => NativeLibrary.Free(handle);
-
- ///
- [ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
- Delegate NativeLibraryFunctionToDelegate(IntPtr ptr, Type t) => Marshal.GetDelegateForFunctionPointer(ptr, t);
+ public static readonly IDotNetSystemAdapter Instance = new DotNetSystemAdapter();
///
- /// Checks if the operating system is Linux.
+ /// Checks if the operating system is Linux.
///
/// true if the operating system is Linux; false otherwise.
[SupportedOSPlatformGuard("linux"), ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
bool IsLinux => OperatingSystem.IsLinux();
///
- /// Checks if the operating system is FreeBSD.
+ /// Checks if the operating system is FreeBSD.
///
/// true if the operating system is FreeBSD; false otherwise.
[SupportedOSPlatformGuard("freebsd"), ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
bool IsFreeBsd => OperatingSystem.IsFreeBSD();
///
- /// Checks if the operating system is MacOS.
+ /// Checks if the operating system is MacOS.
///
/// true if the operating system is MacOS; false otherwise.
[SupportedOSPlatformGuard("macos"), ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
bool IsMacOs => OperatingSystem.IsMacOS();
///
- /// Checks if the operating system is Unix-like.
+ /// Checks if the operating system is Unix-like.
///
/// true if the operating system is Unix-like; false otherwise.
[SupportedOSPlatformGuard("linux"), SupportedOSPlatformGuard("freebsd"), SupportedOSPlatformGuard("macos"),
ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
bool IsUnixLike => IsLinux || IsFreeBsd || IsMacOs;
+ ///
+ [ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
+ bool TryLoadNativeLibrary(string libraryName, Assembly assembly, DllImportSearchPath? searchPath,
+ out IntPtr handle) =>
+ NativeLibrary.TryLoad(libraryName, assembly, searchPath, out handle);
+
+ ///
+ [ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
+ bool TryLoadNativeLibrary(string libraryPath, out IntPtr handle) => NativeLibrary.TryLoad(libraryPath, out handle);
+
+ ///
+ [ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
+ bool TryGetNativeLibraryExport(IntPtr handle, string name, out IntPtr address) =>
+ NativeLibrary.TryGetExport(handle, name, out address);
+
+ ///
+ [ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
+ void FreeNativeLibrary(IntPtr handle) => NativeLibrary.Free(handle);
+
+ ///
+ [ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
+ Delegate NativeLibraryFunctionToDelegate(IntPtr ptr, Type t) => Marshal.GetDelegateForFunctionPointer(ptr, t);
+
+ ///
+ [ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
+ string? NativeLibraryUnicodeStrPtrToString(IntPtr ptr) => Marshal.PtrToStringUni(ptr);
+
+ ///
+ [ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
+ string? NativeLibraryAnsiStrPtrToString(IntPtr ptr) => Marshal.PtrToStringAnsi(ptr);
+
///
- /// Sets the console title.
+ /// Sets the console title.
///
///
[ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
void SetConsoleTitle(string title) => Console.Title = title;
///
- /// Writes to out and flushes immediately.
+ /// Writes to out and flushes immediately.
///
/// What to write.
[ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
@@ -88,9 +89,39 @@ void OutAndFlush(string what)
Console.Out.Flush();
}
- ///
+ ///
[SupportedOSPlatform("linux"), SupportedOSPlatform("freebsd"), SupportedOSPlatform("macos"),
ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
IDisposable MonitorTerminalResizeSignal(Action action) =>
PosixSignalRegistration.Create(PosixSignal.SIGWINCH, _ => { action(); });
+
+ ///
+ [ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
+ string? GetEnvironmentVariable(string name) => Environment.GetEnvironmentVariable(name);
+
+ ///
+ [ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
+ bool DirectoryExists(string name) => Directory.Exists(name);
+
+ ///
+ [ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
+ string? GetDirectoryName(string path) => Path.GetDirectoryName(path);
+
+ ///
+ [ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
+ string CombinePaths(params string[] paths) => Path.Combine(paths);
+
+ ///
+ [ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
+ IEnumerable EnumerateDirectories(string directory) => Directory.EnumerateDirectories(directory);
+
+ ///
+ [ExcludeFromCodeCoverage(Justification = ".NET runtime interop method.")]
+ IEnumerable EnumerateFiles(string directory) => Directory.EnumerateFiles(directory);
+
+ [ExcludeFromCodeCoverage(Justification = ".NET runtime interop implementation.")]
+ private sealed class DotNetSystemAdapter: IDotNetSystemAdapter
+ {
+ }
}
+
diff --git a/Sharpie/Abstractions/IDrawSurface.cs b/Sharpie/Abstractions/IDrawSurface.cs
index 8144bd7..a88e9fe 100644
--- a/Sharpie/Abstractions/IDrawSurface.cs
+++ b/Sharpie/Abstractions/IDrawSurface.cs
@@ -5,6 +5,11 @@ namespace Sharpie.Abstractions;
///
public interface IDrawSurface
{
+ ///
+ /// The total size of the draw surface.
+ ///
+ public Size Size { get; }
+
///
/// Draws a at a using the given style.
///
@@ -12,9 +17,5 @@ public interface IDrawSurface
/// The rune to draw.
/// The cell style.
void DrawCell(Point location, Rune rune, Style style);
-
- ///
- /// The total size of the draw surface.
- ///
- public Size Size { get; }
}
+
diff --git a/Sharpie/Abstractions/IDrawable.cs b/Sharpie/Abstractions/IDrawable.cs
index 630c6b9..d99a896 100644
--- a/Sharpie/Abstractions/IDrawable.cs
+++ b/Sharpie/Abstractions/IDrawable.cs
@@ -20,3 +20,4 @@ public interface IDrawable
/// Thrown if is null.
void DrawOnto(IDrawSurface destination, Rectangle srcArea, Point destLocation);
}
+
diff --git a/Sharpie/Abstractions/IEventPump.cs b/Sharpie/Abstractions/IEventPump.cs
index fe2f4ff..134e136 100644
--- a/Sharpie/Abstractions/IEventPump.cs
+++ b/Sharpie/Abstractions/IEventPump.cs
@@ -86,3 +86,4 @@ public interface IEventPump
/// This operation is not thread safe.
bool Uses(ResolveEscapeSequenceFunc resolver);
}
+
diff --git a/Sharpie/Abstractions/IInterval.cs b/Sharpie/Abstractions/IInterval.cs
index b008338..9519891 100644
--- a/Sharpie/Abstractions/IInterval.cs
+++ b/Sharpie/Abstractions/IInterval.cs
@@ -11,3 +11,4 @@ public interface IInterval: IDisposable
///
void Stop() => Dispose();
}
+
diff --git a/Sharpie/Abstractions/INativeSymbolResolver.cs b/Sharpie/Abstractions/INativeSymbolResolver.cs
index dfb987d..b8f1b86 100644
--- a/Sharpie/Abstractions/INativeSymbolResolver.cs
+++ b/Sharpie/Abstractions/INativeSymbolResolver.cs
@@ -1,19 +1,18 @@
namespace Sharpie.Abstractions;
-using System.Reflection;
-
///
-/// Interface implemented by objects that can provide native symbols (such as function) to the callers.
-/// The existing implementation is class.
+/// Interface implemented by objects that can provide native symbols (such as function) to the callers.
+/// The existing implementation is class.
///
[PublicAPI]
internal interface INativeSymbolResolver
{
///
- /// Resolves a given function based on its delegate type.
+ /// Resolves a given function based on its delegate type.
///
/// The type of the function.
/// The resolved function.
/// Thrown if the given function could not be resolved.
TDelegate Resolve() where TDelegate: MulticastDelegate;
}
+
diff --git a/Sharpie/Backend/CursesBackend.cs b/Sharpie/Backend/CursesBackend.cs
index e8c5361..74e6575 100644
--- a/Sharpie/Backend/CursesBackend.cs
+++ b/Sharpie/Backend/CursesBackend.cs
@@ -1,18 +1,27 @@
namespace Sharpie.Backend;
+using System.Text.RegularExpressions;
+
///
-/// Provides functionality for obtaining instances.
+/// Provides functionality for obtaining instances.
///
[PublicAPI]
public static class CursesBackend
{
+ private const string NCursesPrefix = "ncurses";
+ private const string LibCPrefix = "libc";
+
///
- /// Internal method that loads the Curses backend from native libraries (and any other support library that is required).
+ /// Internal method that loads the Curses backend from native libraries (and any other support library that is
+ /// required).
///
/// Adapter for .NET functionality.
/// Function that provides paths/names for the native loader.
///
- /// Thrown if or are null.
+ ///
+ /// Thrown if or
+ /// are null.
+ ///
/// Thrown if no suitable library was found.
internal static ICursesBackend NCurses(IDotNetSystemAdapter dotNetSystemAdapter,
Func> libPathResolver)
@@ -20,7 +29,7 @@ internal static ICursesBackend NCurses(IDotNetSystemAdapter dotNetSystemAdapter,
Debug.Assert(dotNetSystemAdapter != null);
Debug.Assert(libPathResolver != null);
- var cw = NativeLibraryWrapper.TryLoad(dotNetSystemAdapter, libPathResolver("ncurses"));
+ var cw = NativeLibraryWrapper.TryLoad(dotNetSystemAdapter, libPathResolver(NCursesPrefix));
if (cw == null)
{
throw new CursesInitializationException();
@@ -28,7 +37,7 @@ internal static ICursesBackend NCurses(IDotNetSystemAdapter dotNetSystemAdapter,
if (dotNetSystemAdapter.IsUnixLike)
{
- var lw = NativeLibraryWrapper.TryLoad(dotNetSystemAdapter, libPathResolver("libc"));
+ var lw = NativeLibraryWrapper.TryLoad(dotNetSystemAdapter, libPathResolver(LibCPrefix));
if (lw == null)
{
throw new CursesInitializationException();
@@ -41,11 +50,11 @@ internal static ICursesBackend NCurses(IDotNetSystemAdapter dotNetSystemAdapter,
}
///
- /// Loads the Curses backend from native libraries (and any other support library that is required).
+ /// Loads the Curses backend from native libraries (and any other support library that is required).
///
/// Function that provides paths/names for the native loader.
///
- /// Thrown if is null.
+ /// Thrown if is null.
/// Thrown if no suitable library was found.
[ExcludeFromCodeCoverage(Justification = "References a singleton .NET object and cannot be tested.")]
public static ICursesBackend NCurses(Func> libPathResolver)
@@ -57,44 +66,107 @@ public static ICursesBackend NCurses(Func> libPathRe
return NCurses(IDotNetSystemAdapter.Instance, libPathResolver);
}
-
///
- /// Internal method that loads the Curses backend from native libraries (and any other support library that is required).
- /// This method uses standard known names for the 'ncurses' and potentially 'libc' libraries.
+ /// Internal method that loads the Curses backend from native libraries (and any other support library that is
+ /// required).
+ /// This method uses standard known names for the 'ncurses' and potentially 'libc' libraries.
///
/// Adapter for .NET functionality.
///
/// Thrown if no suitable library was found.
internal static ICursesBackend NCurses(IDotNetSystemAdapter dotNetSystemAdapter)
{
- return NCurses(dotNetSystemAdapter, s =>
+ return NCurses(dotNetSystemAdapter, lib =>
{
- if ((dotNetSystemAdapter.IsLinux || dotNetSystemAdapter.IsFreeBsd) && s == "ncurses")
+ return lib switch
{
- return new[]
- {
- "ncursesw",
- "libncursesw.so",
- "libncursesw.so.5",
- "libncursesw.so.6",
- "ncurses",
- "libncurses.so",
- "libncurses.so.5",
- "libncurses.so.6",
- };
- }
-
- return new[] { s };
+ NCursesPrefix when dotNetSystemAdapter.IsLinux || dotNetSystemAdapter.IsFreeBsd =>
+ FindLinuxAndFreeBsdNCursesCandidates(),
+ NCursesPrefix when dotNetSystemAdapter.IsMacOs => FindMacOsNCursesCandidates(dotNetSystemAdapter),
+ var _ => new[] { lib }
+ };
});
}
///
- /// Loads the Curses backend from native libraries (and any other support library that is required).
- /// This method uses standard known names for the required libraries.
+ /// Loads the Curses backend from native libraries (and any other support library that is required).
+ /// This method uses standard known names for the required libraries.
///
///
/// Thrown if no suitable library was found.
[ExcludeFromCodeCoverage(Justification = "References a singleton .NET object and cannot be tested.")]
public static ICursesBackend NCurses() => NCurses(IDotNetSystemAdapter.Instance);
+
+ private static IEnumerable<(string name, int version)> GetCandidatesInDirectory(
+ IDotNetSystemAdapter dotNetSystemAdapter, string directory, Regex pattern)
+ {
+ Debug.Assert(dotNetSystemAdapter != null);
+ Debug.Assert(pattern != null);
+ Debug.Assert(!string.IsNullOrEmpty(directory));
+
+ return dotNetSystemAdapter.EnumerateFiles(directory)
+ .Select(f => pattern.Match(f))
+ .Where(m => m.Success)
+ .Select(m => (name: dotNetSystemAdapter.CombinePaths(directory, m.Groups[0]
+ .Value), version: int.Parse(m.Groups[1]
+ .Value)));
+ }
+
+ [SupportedOSPlatform("linux"), SupportedOSPlatform("freebsd")]
+ private static IEnumerable FindLinuxAndFreeBsdNCursesCandidates()
+ {
+ return new[]
+ {
+ "libncursesw.so.6",
+ "libncursesw.so.5",
+ "libncursesw.so",
+ "ncursesw",
+ "libncurses.so.6",
+ "libncurses.so.5",
+ "libncurses.so",
+ NCursesPrefix
+ };
+ }
+
+ [SupportedOSPlatform("macos")]
+ private static IEnumerable FindMacOsNCursesCandidates(IDotNetSystemAdapter dotNetSystemAdapter)
+ {
+ Debug.Assert(dotNetSystemAdapter != null);
+
+ var homeBrewPrefix = dotNetSystemAdapter.GetEnvironmentVariable("HOMEBREW_PREFIX");
+ var homeBrewCellar = dotNetSystemAdapter.GetEnvironmentVariable("HOMEBREW_CELLAR");
+
+ var candidates = new List<(string name, int version)>();
+ var matchRegEx = new Regex(@"libncurses\.(\d+)\.dylib", RegexOptions.Compiled);
+
+ if (!string.IsNullOrEmpty(homeBrewPrefix))
+ {
+ var libPath = dotNetSystemAdapter.CombinePaths(homeBrewPrefix, "lib");
+ if (dotNetSystemAdapter.DirectoryExists(libPath))
+ {
+ candidates.AddRange(GetCandidatesInDirectory(dotNetSystemAdapter, libPath, matchRegEx));
+ }
+ }
+
+ if (!string.IsNullOrEmpty(homeBrewCellar))
+ {
+ var ncursesPath = dotNetSystemAdapter.CombinePaths(homeBrewCellar, NCursesPrefix);
+ if (dotNetSystemAdapter.DirectoryExists(ncursesPath))
+ {
+ foreach (var v in dotNetSystemAdapter.EnumerateDirectories(ncursesPath))
+ {
+ var libPath = dotNetSystemAdapter.CombinePaths(v, "lib");
+ if (dotNetSystemAdapter.DirectoryExists(libPath))
+ {
+ candidates.AddRange(GetCandidatesInDirectory(dotNetSystemAdapter, libPath, matchRegEx));
+ }
+ }
+ }
+ }
+
+ return candidates.OrderByDescending(c => c.version)
+ .Select(c => c.name)
+ .Concat(new[] { NCursesPrefix });
+ }
}
diff --git a/Sharpie/Backend/CursesComplexChar.cs b/Sharpie/Backend/CursesComplexChar.cs
index 4421626..8c924b9 100644
--- a/Sharpie/Backend/CursesComplexChar.cs
+++ b/Sharpie/Backend/CursesComplexChar.cs
@@ -38,21 +38,10 @@ namespace Sharpie.Backend;
SuppressMessage("ReSharper", "PrivateFieldCanBeConvertedToLocalVariable")]
public struct CursesComplexChar
{
- internal CursesComplexChar(uint attrAndColorPair, uint char0, uint char1, uint char2,
- uint char3, uint char4)
- {
- _attrAndColorPair = attrAndColorPair;
- _char0 = char0;
- _char1 = char1;
- _char2 = char2;
- _char3 = char3;
- _char4 = char4;
- }
-
- [MarshalAs(UnmanagedType.U4)] private readonly uint _attrAndColorPair;
- [MarshalAs(UnmanagedType.U4)] private readonly uint _char0;
- [MarshalAs(UnmanagedType.U4)] private readonly uint _char1;
- [MarshalAs(UnmanagedType.U4)] private readonly uint _char2;
- [MarshalAs(UnmanagedType.U4)] private readonly uint _char3;
- [MarshalAs(UnmanagedType.U4)] private readonly uint _char4;
+ [MarshalAs(UnmanagedType.U4)] internal uint _attrAndColorPair;
+ [MarshalAs(UnmanagedType.U4)] internal uint _char0;
+ [MarshalAs(UnmanagedType.U4)] internal uint _char1;
+ [MarshalAs(UnmanagedType.U4)] internal uint _char2;
+ [MarshalAs(UnmanagedType.U4)] internal uint _char3;
+ [MarshalAs(UnmanagedType.U4)] internal uint _char4;
}
diff --git a/Sharpie/Backend/CursesMouseEvent.cs b/Sharpie/Backend/CursesMouseEvent.cs
index c841bdf..e414ea1 100644
--- a/Sharpie/Backend/CursesMouseEvent.cs
+++ b/Sharpie/Backend/CursesMouseEvent.cs
@@ -32,89 +32,14 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
namespace Sharpie.Backend;
///
-/// Internal Curses mouse event.
+/// Curses mouse event - encapsulates the data sent by the backend related to mouse events.
///
[PublicAPI, StructLayout(LayoutKind.Sequential), ExcludeFromCodeCoverage]
public struct CursesMouseEvent
{
- private const int CursesMouseShift = 6;
-
- [PublicAPI]
- public enum Button
- {
- None = 0,
- Button1 = 1,
- Button2 = 2,
- Button3 = 3,
- Button4 = 4,
- Modifiers = 5
- }
-
- [PublicAPI, Flags]
- public enum Action
- {
- ButtonReleased = 1,
- ButtonPressed = ButtonReleased << 1,
- ButtonClicked = ButtonPressed << 1,
- DoubleClicked = ButtonClicked << 1,
- TripleClicked = DoubleClicked << 1,
- Reserved = TripleClicked << 1
- }
-
- [Flags, PublicAPI]
- public enum EventType
- {
- Button1Released = Action.ButtonReleased << ((Button.Button1 - 1) * CursesMouseShift),
-
- Button1Pressed = Action.ButtonPressed << ((Button.Button1 - 1) * CursesMouseShift),
-
- Button1Clicked = Action.ButtonClicked << ((Button.Button1 - 1) * CursesMouseShift),
-
- Button1DoubleClicked = Action.DoubleClicked << ((Button.Button1 - 1) * CursesMouseShift),
-
- Button1TripleClicked = Action.TripleClicked << ((Button.Button1 - 1) * CursesMouseShift),
-
- Button2Released = Action.ButtonReleased << ((Button.Button2 - 1) * CursesMouseShift),
-
- Button2Pressed = Action.ButtonPressed << ((Button.Button2 - 1) * CursesMouseShift),
-
- Button2Clicked = Action.ButtonClicked << ((Button.Button2 - 1) * CursesMouseShift),
-
- Button2DoubleClicked = Action.DoubleClicked << ((Button.Button2 - 1) * CursesMouseShift),
-
- Button2TripleClicked = Action.TripleClicked << ((Button.Button2 - 1) * CursesMouseShift),
-
- Button3Released = Action.ButtonReleased << ((Button.Button3 - 1) * CursesMouseShift),
-
- Button3Pressed = Action.ButtonPressed << ((Button.Button3 - 1) * CursesMouseShift),
-
- Button3Clicked = Action.ButtonClicked << ((Button.Button3 - 1) * CursesMouseShift),
-
- Button3DoubleClicked = Action.DoubleClicked << ((Button.Button3 - 1) * CursesMouseShift),
-
- Button3TripleClicked = Action.TripleClicked << ((Button.Button3 - 1) * CursesMouseShift),
-
- Button4Released = Action.ButtonReleased << ((Button.Button4 - 1) * CursesMouseShift),
-
- Button4Pressed = Action.ButtonPressed << ((Button.Button4 - 1) * CursesMouseShift),
-
- Button4Clicked = Action.ButtonClicked << ((Button.Button4 - 1) * CursesMouseShift),
-
- Button4DoubleClicked = Action.DoubleClicked << ((Button.Button4 - 1) * CursesMouseShift),
-
- Button4TripleClicked = Action.TripleClicked << ((Button.Button4 - 1) * CursesMouseShift),
-
- Ctrl = 1 << ((Button.Modifiers - 1) * CursesMouseShift),
- Shift = 2 << ((Button.Modifiers - 1) * CursesMouseShift),
- Alt = 4 << ((Button.Modifiers - 1) * CursesMouseShift),
-
- ReportPosition = 8 << ((Button.Modifiers - 1) * CursesMouseShift),
- All = ReportPosition - 1
- }
-
- [MarshalAs(UnmanagedType.I2)] public short id;
- [MarshalAs(UnmanagedType.I4)] public int x;
- [MarshalAs(UnmanagedType.I4)] public int y;
- [MarshalAs(UnmanagedType.I4)] public int z;
- [MarshalAs(UnmanagedType.U4)] public uint buttonState;
+ [MarshalAs(UnmanagedType.I2)] internal short id;
+ [MarshalAs(UnmanagedType.I4)] internal int x;
+ [MarshalAs(UnmanagedType.I4)] internal int y;
+ [MarshalAs(UnmanagedType.I4)] internal int z;
+ [MarshalAs(UnmanagedType.U4)] internal uint buttonState;
}
diff --git a/Sharpie/Backend/CursesMouseEventParser.cs b/Sharpie/Backend/CursesMouseEventParser.cs
new file mode 100644
index 0000000..41d0f65
--- /dev/null
+++ b/Sharpie/Backend/CursesMouseEventParser.cs
@@ -0,0 +1,243 @@
+/*
+Copyright (c) 2022, Alexandru Ciobanu
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma warning disable CS1591
+namespace Sharpie.Backend;
+
+///
+/// Provides functionality for parsing Curses mouse events.
+///
+internal abstract class CursesMouseEventParser
+{
+ private static readonly CursesMouseEventParser V1 = new CursesMouseV1EventParser();
+ private static readonly CursesMouseEventParser V2 = new CursesMouseV2EventParser();
+
+ [SuppressMessage("ReSharper", "VirtualMemberCallInConstructor")]
+ protected CursesMouseEventParser()
+ {
+ Button1Released = CalculateButtonState(Action.Released, Button.Button1);
+ Button1Pressed = CalculateButtonState(Action.Pressed, Button.Button1);
+ Button1Clicked = CalculateButtonState(Action.Clicked, Button.Button1);
+ Button1DoubleClicked = CalculateButtonState(Action.DoubleClicked, Button.Button1);
+ Button1TripleClicked = CalculateButtonState(Action.TripleClicked, Button.Button1);
+
+ Button2Released = CalculateButtonState(Action.Released, Button.Button2);
+ Button2Pressed = CalculateButtonState(Action.Pressed, Button.Button2);
+ Button2Clicked = CalculateButtonState(Action.Clicked, Button.Button2);
+ Button2DoubleClicked = CalculateButtonState(Action.DoubleClicked, Button.Button2);
+ Button2TripleClicked = CalculateButtonState(Action.TripleClicked, Button.Button2);
+
+ Button3Released = CalculateButtonState(Action.Released, Button.Button3);
+ Button3Pressed = CalculateButtonState(Action.Pressed, Button.Button3);
+ Button3Clicked = CalculateButtonState(Action.Clicked, Button.Button3);
+ Button3DoubleClicked = CalculateButtonState(Action.DoubleClicked, Button.Button3);
+ Button3TripleClicked = CalculateButtonState(Action.TripleClicked, Button.Button3);
+
+ Button4Released = CalculateButtonState(Action.Released, Button.Button4);
+ Button4Pressed = CalculateButtonState(Action.Pressed, Button.Button4);
+ Button4Clicked = CalculateButtonState(Action.Clicked, Button.Button4);
+ Button4DoubleClicked = CalculateButtonState(Action.DoubleClicked, Button.Button4);
+ Button4TripleClicked = CalculateButtonState(Action.TripleClicked, Button.Button4);
+
+ Button5Released = CalculateButtonState(Action.Released, Button.Button5);
+ Button5Pressed = CalculateButtonState(Action.Pressed, Button.Button5);
+ Button5Clicked = CalculateButtonState(Action.Clicked, Button.Button5);
+ Button5DoubleClicked = CalculateButtonState(Action.DoubleClicked, Button.Button5);
+ Button5TripleClicked = CalculateButtonState(Action.TripleClicked, Button.Button5);
+
+ Ctrl = CalculateModifierState(Modifier.Ctrl);
+ Shift = CalculateModifierState(Modifier.Shift);
+ Alt = CalculateModifierState(Modifier.Alt);
+ ReportPosition = CalculateModifierState(Modifier.ReportPosition);
+
+ All = ReportPosition - 1;
+ }
+
+ private uint Button1Released { get; }
+ private uint Button1Pressed { get; }
+ private uint Button1Clicked { get; }
+ private uint Button1DoubleClicked { get; }
+ private uint Button1TripleClicked { get; }
+ private uint Button2Released { get; }
+ private uint Button2Pressed { get; }
+ private uint Button2Clicked { get; }
+ private uint Button2DoubleClicked { get; }
+ private uint Button2TripleClicked { get; }
+ private uint Button3Released { get; }
+ private uint Button3Pressed { get; }
+ private uint Button3Clicked { get; }
+ private uint Button3DoubleClicked { get; }
+ private uint Button3TripleClicked { get; }
+ private uint Button4Released { get; }
+ private uint Button4Pressed { get; }
+ private uint Button4Clicked { get; }
+ private uint Button4DoubleClicked { get; }
+ private uint Button4TripleClicked { get; }
+ private uint Button5Released { get; }
+ private uint Button5Pressed { get; }
+ private uint Button5Clicked { get; }
+ private uint Button5DoubleClicked { get; }
+ private uint Button5TripleClicked { get; }
+ private uint Ctrl { get; }
+ private uint Shift { get; }
+ private uint Alt { get; }
+ public uint ReportPosition { get; }
+ public uint All { get; }
+
+ protected abstract uint CalculateButtonState(Action action, Button button);
+ protected abstract uint CalculateModifierState(Modifier modifier);
+
+ ///
+ /// Converts a Curses mouse action into proper format.
+ ///
+ /// The raw Curses mouse event flags.
+ /// The mouse action attributes.
+ public (MouseButton button, MouseButtonState state, ModifierKey modifierKey)? Parse(uint flags)
+ {
+ var modifierKey = ModifierKey.None;
+ var button = (MouseButton) 0;
+ var state = (MouseButtonState) 0;
+
+ bool Has(uint flag) => (flags & flag) == flag;
+
+ void MapMod(uint flag, ModifierKey mod)
+ {
+ if (Has(flag))
+ {
+ modifierKey |= mod;
+ }
+ }
+
+ bool MapButton(uint flag, MouseButton b, MouseButtonState s)
+ {
+ var h = Has(flag);
+ if (h)
+ {
+ button = b;
+ state = s;
+ }
+
+ return h;
+ }
+
+ MapMod(Alt, ModifierKey.Alt);
+ MapMod(Ctrl, ModifierKey.Ctrl);
+ MapMod(Shift, ModifierKey.Shift);
+
+ if (MapButton(Button1Released, MouseButton.Button1, MouseButtonState.Released) ||
+ MapButton(Button1Pressed, MouseButton.Button1, MouseButtonState.Pressed) ||
+ MapButton(Button1Clicked, MouseButton.Button1, MouseButtonState.Clicked) ||
+ MapButton(Button1DoubleClicked, MouseButton.Button1, MouseButtonState.DoubleClicked) ||
+ MapButton(Button1TripleClicked, MouseButton.Button1, MouseButtonState.TripleClicked) ||
+ MapButton(Button2Released, MouseButton.Button2, MouseButtonState.Released) ||
+ MapButton(Button2Pressed, MouseButton.Button2, MouseButtonState.Pressed) ||
+ MapButton(Button2Clicked, MouseButton.Button2, MouseButtonState.Clicked) ||
+ MapButton(Button2DoubleClicked, MouseButton.Button2, MouseButtonState.DoubleClicked) ||
+ MapButton(Button2TripleClicked, MouseButton.Button2, MouseButtonState.TripleClicked) ||
+ MapButton(Button3Released, MouseButton.Button3, MouseButtonState.Released) ||
+ MapButton(Button3Pressed, MouseButton.Button3, MouseButtonState.Pressed) ||
+ MapButton(Button3Clicked, MouseButton.Button3, MouseButtonState.Clicked) ||
+ MapButton(Button3DoubleClicked, MouseButton.Button3, MouseButtonState.DoubleClicked) ||
+ MapButton(Button3TripleClicked, MouseButton.Button3, MouseButtonState.TripleClicked) ||
+ MapButton(Button4Released, MouseButton.Button4, MouseButtonState.Released) ||
+ MapButton(Button4Pressed, MouseButton.Button4, MouseButtonState.Pressed) ||
+ MapButton(Button4Clicked, MouseButton.Button4, MouseButtonState.Clicked) ||
+ MapButton(Button4DoubleClicked, MouseButton.Button4, MouseButtonState.DoubleClicked) ||
+ MapButton(Button4TripleClicked, MouseButton.Button4, MouseButtonState.TripleClicked) ||
+ MapButton(Button5Released, MouseButton.Button5, MouseButtonState.Released) ||
+ MapButton(Button5Pressed, MouseButton.Button5, MouseButtonState.Pressed) ||
+ MapButton(Button5Clicked, MouseButton.Button5, MouseButtonState.Clicked) ||
+ MapButton(Button5DoubleClicked, MouseButton.Button5, MouseButtonState.DoubleClicked) ||
+ MapButton(Button5TripleClicked, MouseButton.Button5, MouseButtonState.TripleClicked))
+ {
+ return (button, state, modifierKey);
+ }
+
+ return null;
+ }
+
+ ///
+ /// Gets the mouse event parser based on the provided ABI version.
+ ///
+ /// The ABI version.
+ /// The mouse event parser.
+ public static CursesMouseEventParser Get(int abiVersion) =>
+ abiVersion switch
+ {
+ 2 => V2,
+ var _ => V1
+ };
+
+ private sealed class CursesMouseV1EventParser: CursesMouseEventParser
+ {
+ protected override uint CalculateButtonState(Action action, Button button) =>
+ button switch
+ {
+ Button.Button5 => 1u << 31,
+ var _ => (uint) action << (((int) button - 1) * 6)
+ };
+
+ protected override uint CalculateModifierState(Modifier modifier) => (uint) modifier << 24;
+ }
+
+ private sealed class CursesMouseV2EventParser: CursesMouseEventParser
+ {
+ protected override uint CalculateButtonState(Action action, Button button) =>
+ (uint) action << (((int) button - 1) * 5);
+
+ protected override uint CalculateModifierState(Modifier modifier) => (uint) modifier << 25;
+ }
+
+ protected enum Action
+ {
+ Released = 1,
+ Pressed = Released << 1,
+ Clicked = Pressed << 1,
+ DoubleClicked = Clicked << 1,
+ TripleClicked = DoubleClicked << 1
+ }
+
+ protected enum Modifier
+ {
+ Ctrl = 1,
+ Shift = Ctrl << 1,
+ Alt = Shift << 1,
+ ReportPosition = Alt << 1
+ }
+
+ protected enum Button
+ {
+ Button1 = 1,
+ Button2 = 2,
+ Button3 = 3,
+ Button4 = 4,
+ Button5 = 5
+ }
+}
diff --git a/Sharpie/Backend/LibCFunctionMap.cs b/Sharpie/Backend/LibCFunctionMap.cs
index 7043a2c..b4e30ea 100644
--- a/Sharpie/Backend/LibCFunctionMap.cs
+++ b/Sharpie/Backend/LibCFunctionMap.cs
@@ -31,7 +31,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
namespace Sharpie.Backend;
///
-/// Function map for LibC library.
+/// Function map for LibC library.
///
[SuppressMessage("ReSharper", "IdentifierTypo"), SuppressMessage("ReSharper", "InconsistentNaming")]
internal abstract class LibCFunctionMap
diff --git a/Sharpie/Backend/NCursesBackend.cs b/Sharpie/Backend/NCursesBackend.cs
index 8766046..8bf904d 100644
--- a/Sharpie/Backend/NCursesBackend.cs
+++ b/Sharpie/Backend/NCursesBackend.cs
@@ -2,11 +2,13 @@
namespace Sharpie.Backend;
+using System.Text.RegularExpressions;
+
[PublicAPI]
internal class NCursesBackend: ICursesBackend
{
- public IDotNetSystemAdapter DotNetSystemAdapter { get; }
private readonly INativeSymbolResolver _nCursesSymbolResolver;
+ private int? _mouseAbiVersion;
internal NCursesBackend(IDotNetSystemAdapter dotNetSystemAdapter, INativeSymbolResolver nCursesSymbolResolver)
{
@@ -17,6 +19,8 @@ internal NCursesBackend(IDotNetSystemAdapter dotNetSystemAdapter, INativeSymbolR
_nCursesSymbolResolver = nCursesSymbolResolver;
}
+ public IDotNetSystemAdapter DotNetSystemAdapter { get; }
+
// ReSharper disable IdentifierTypo
// ReSharper disable InconsistentNaming
@@ -34,7 +38,8 @@ internal NCursesBackend(IDotNetSystemAdapter dotNetSystemAdapter, INativeSymbolR
public bool is_nodelay(IntPtr window) => _nCursesSymbolResolver.Resolve()(window);
- public bool is_notimeout(IntPtr window) => _nCursesSymbolResolver.Resolve()(window);
+ public bool is_notimeout(IntPtr window) =>
+ _nCursesSymbolResolver.Resolve()(window);
public bool is_scrollok(IntPtr window) => _nCursesSymbolResolver.Resolve()(window);
@@ -96,7 +101,7 @@ public IntPtr derwin(IntPtr window, int lines, int cols, int beginLine,
public int flushinp() => _nCursesSymbolResolver.Resolve()();
- public int getattrs(IntPtr window) => _nCursesSymbolResolver.Resolve()(window);
+ public int getattrs(IntPtr window) => _nCursesSymbolResolver.Resolve()(window);
public int getcurx(IntPtr window) => _nCursesSymbolResolver.Resolve()(window);
@@ -114,7 +119,8 @@ public IntPtr derwin(IntPtr window, int lines, int cols, int beginLine,
public int getpary(IntPtr window) => _nCursesSymbolResolver.Resolve()(window);
- public int halfdelay(int tenthsOfSec) => _nCursesSymbolResolver.Resolve()(tenthsOfSec);
+ public int halfdelay(int tenthsOfSec) =>
+ _nCursesSymbolResolver.Resolve()(tenthsOfSec);
public bool has_colors() => _nCursesSymbolResolver.Resolve()();
@@ -125,7 +131,8 @@ public IntPtr derwin(IntPtr window, int lines, int cols, int beginLine,
public void idcok(IntPtr window, bool set) =>
_nCursesSymbolResolver.Resolve()(window, set);
- public int idlok(IntPtr window, bool set) => _nCursesSymbolResolver.Resolve()(window, set);
+ public int idlok(IntPtr window, bool set) =>
+ _nCursesSymbolResolver.Resolve()(window, set);
public void immedok(IntPtr window, bool set) =>
_nCursesSymbolResolver.Resolve()(window, set);
@@ -150,7 +157,8 @@ public bool is_wintouched(IntPtr window) =>
_nCursesSymbolResolver.Resolve()(window);
public string? keyname(uint keyCode) =>
- Marshal.PtrToStringAnsi(_nCursesSymbolResolver.Resolve()(keyCode));
+ DotNetSystemAdapter.NativeLibraryAnsiStrPtrToString(
+ _nCursesSymbolResolver.Resolve()(keyCode));
public int keypad(IntPtr window, bool set) =>
_nCursesSymbolResolver.Resolve()(window, set);
@@ -159,7 +167,8 @@ public int leaveok(IntPtr window, bool set) =>
_nCursesSymbolResolver.Resolve()(window, set);
public string? longname() =>
- Marshal.PtrToStringAnsi(_nCursesSymbolResolver.Resolve()());
+ DotNetSystemAdapter.NativeLibraryAnsiStrPtrToString(
+ _nCursesSymbolResolver.Resolve()());
public int meta(IntPtr window, bool set) => _nCursesSymbolResolver.Resolve()(window, set);
@@ -262,7 +271,8 @@ public int slk_attr_set(uint attrs, short colorPair, IntPtr reserved) =>
public int slk_init(int format) => _nCursesSymbolResolver.Resolve()(format);
public string? slk_label(int labelIndex) =>
- Marshal.PtrToStringAnsi(_nCursesSymbolResolver.Resolve()(labelIndex));
+ DotNetSystemAdapter.NativeLibraryAnsiStrPtrToString(
+ _nCursesSymbolResolver.Resolve()(labelIndex));
public int slk_noutrefresh() => _nCursesSymbolResolver.Resolve()();
@@ -286,7 +296,8 @@ public int syncok(IntPtr window, bool set) =>
_nCursesSymbolResolver.Resolve()(window, set);
public string? termname() =>
- Marshal.PtrToStringAnsi(_nCursesSymbolResolver.Resolve()());
+ DotNetSystemAdapter.NativeLibraryAnsiStrPtrToString(
+ _nCursesSymbolResolver.Resolve()());
public int ungetch(uint @char) => _nCursesSymbolResolver.Resolve()(@char);
@@ -346,7 +357,7 @@ public int wechochar(IntPtr window, uint charAndAttrs) =>
public int wgetch(IntPtr window) => _nCursesSymbolResolver.Resolve()(window);
- public int wgetnstr(IntPtr window, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder dest, int length) =>
+ public int wgetnstr(IntPtr window, StringBuilder dest, int length) =>
_nCursesSymbolResolver.Resolve()(window, dest, length);
public int whline(IntPtr window, uint @char, int count) =>
@@ -354,7 +365,7 @@ public int whline(IntPtr window, uint @char, int count) =>
public int winch(IntPtr window) => _nCursesSymbolResolver.Resolve()(window);
- public int winchnstr(IntPtr window, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder dest, int length) =>
+ public int winchnstr(IntPtr window, StringBuilder dest, int length) =>
_nCursesSymbolResolver.Resolve()(window, dest, length);
public int winsch(IntPtr window, uint charAndAttrs) =>
@@ -402,10 +413,12 @@ public int resizeterm(int lines, int cols) =>
_nCursesSymbolResolver.Resolve()(lines, cols);
public string? keybound(uint keyCode, int count) =>
- Marshal.PtrToStringAnsi(_nCursesSymbolResolver.Resolve()(keyCode, count));
+ DotNetSystemAdapter.NativeLibraryAnsiStrPtrToString(
+ _nCursesSymbolResolver.Resolve()(keyCode, count));
public string? curses_version() =>
- Marshal.PtrToStringAnsi(_nCursesSymbolResolver.Resolve()());
+ DotNetSystemAdapter.NativeLibraryAnsiStrPtrToString(_nCursesSymbolResolver
+ .Resolve()());
public int assume_default_colors(int fgColor, int bgColor) =>
_nCursesSymbolResolver.Resolve()(fgColor, bgColor);
@@ -432,7 +445,8 @@ public int getcchar(CursesComplexChar @char, StringBuilder dest, out uint attrs,
reserved);
public string? key_name(uint @char) =>
- Marshal.PtrToStringAnsi(_nCursesSymbolResolver.Resolve()(@char));
+ DotNetSystemAdapter.NativeLibraryAnsiStrPtrToString(
+ _nCursesSymbolResolver.Resolve()(@char));
public int killwchar(out uint @char) => _nCursesSymbolResolver.Resolve()(out @char);
@@ -456,7 +470,7 @@ public int wadd_wch(IntPtr window, CursesComplexChar @char) =>
public int wadd_wchnstr(IntPtr window, CursesComplexChar[] str, int count) =>
_nCursesSymbolResolver.Resolve()(window, str, count);
- public int waddnwstr(IntPtr window, [MarshalAs(UnmanagedType.LPWStr)] string text, int length) =>
+ public int waddnwstr(IntPtr window, string text, int length) =>
_nCursesSymbolResolver.Resolve()(window, text, length);
public int wbkgrnd(IntPtr window, CursesComplexChar @char) =>
@@ -503,7 +517,8 @@ public int wins_wch(IntPtr window, CursesComplexChar @char) =>
_nCursesSymbolResolver.Resolve()(window, ref @char);
public string? wunctrl(CursesComplexChar @char) =>
- Marshal.PtrToStringUni(_nCursesSymbolResolver.Resolve()(ref @char));
+ DotNetSystemAdapter.NativeLibraryUnicodeStrPtrToString(
+ _nCursesSymbolResolver.Resolve()(ref @char));
public int wvline_set(IntPtr window, CursesComplexChar @char, int count) =>
_nCursesSymbolResolver.Resolve()(window, ref @char, count);
@@ -514,9 +529,39 @@ public int getmouse(out CursesMouseEvent @event) =>
public int ungetmouse(CursesMouseEvent @event) =>
_nCursesSymbolResolver.Resolve()(ref @event);
- public virtual int mousemask(int newMask, out int oldMask) =>
+ public virtual int mousemask(uint newMask, out uint oldMask) =>
_nCursesSymbolResolver.Resolve()(newMask, out oldMask);
+ public virtual int mouse_version()
+ {
+ if (_mouseAbiVersion == null)
+ {
+ var ver = curses_version();
+ var abi = -1;
+ if (ver != null)
+ {
+ var versionParser = new Regex(@".*(\d+)\.(\d+)\.(\d+)");
+ var match = versionParser.Match(ver);
+ if (match.Success)
+ {
+ var major = int.Parse(match.Groups[1]
+ .Value);
+
+ abi = major switch
+ {
+ >= 6 => 2,
+ 5 => 1,
+ var _ => abi
+ };
+ }
+ }
+
+ _mouseAbiVersion = abi;
+ }
+
+ return _mouseAbiVersion.Value;
+ }
+
public bool wenclose(IntPtr window, int line, int col) =>
_nCursesSymbolResolver.Resolve()(window, line, col);
diff --git a/Sharpie/Backend/NCursesFunctionMap.cs b/Sharpie/Backend/NCursesFunctionMap.cs
index 61ecead..e9203de 100644
--- a/Sharpie/Backend/NCursesFunctionMap.cs
+++ b/Sharpie/Backend/NCursesFunctionMap.cs
@@ -31,11 +31,14 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
namespace Sharpie.Backend;
///
-/// Function map for NCurses library.
+/// Function map for NCurses library.
///
-[SuppressMessage("ReSharper", "IdentifierTypo"),SuppressMessage("ReSharper", "InconsistentNaming")]
+[SuppressMessage("ReSharper", "IdentifierTypo"), SuppressMessage("ReSharper", "InconsistentNaming")]
internal abstract class NCursesFunctionMap
{
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate int assume_default_colors(int fgColor, int bgColor);
+
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int baudrate();
@@ -54,6 +57,9 @@ internal abstract class NCursesFunctionMap
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int color_content(short color, out short red, out short green, out short blue);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate uint COLOR_PAIR(uint attrs);
+
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int copywin(IntPtr fromWindow, IntPtr toWindow, int srcMinLine, int srcMinCol,
int destMinLine, int destMinCol, int destMaxLine, int destMaxCol,
@@ -62,12 +68,18 @@ public delegate int copywin(IntPtr fromWindow, IntPtr toWindow, int srcMinLine,
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int curs_set(int level);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
+ public delegate IntPtr curses_version();
+
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int def_prog_mode();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int def_shell_mode();
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate int define_key(string keyName, int keyCode);
+
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int delay_output(int delayMillis);
@@ -90,6 +102,9 @@ public delegate IntPtr derwin(IntPtr window, int lines, int cols, int beginLine,
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int endwin();
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate int erasewchar(out uint @char);
+
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void filter();
@@ -100,388 +115,367 @@ public delegate IntPtr derwin(IntPtr window, int lines, int cols, int beginLine,
public delegate int flushinp();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int halfdelay(int tenthsOfSec);
+ public delegate int getattrs(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate bool has_colors();
+ public delegate int getbegx(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate bool has_ic();
+ public delegate int getbegy(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate bool has_il();
+ public delegate int getcchar(ref CursesComplexChar @char, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder dest,
+ out uint attrs, out short colorPair, IntPtr reserved);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate void idcok(IntPtr window, bool set);
+ public delegate int getcurx(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int idlok(IntPtr window, bool set);
+ public delegate int getcury(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate void immedok(IntPtr window, bool set);
+ public delegate int getmaxx(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate IntPtr initscr();
+ public delegate int getmaxy(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int init_color(short color, short red, short green, short blue);
+ public delegate int getmouse(out CursesMouseEvent @event);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int init_pair(short colorPair, short fgColor, short bgColor);
+ public delegate int getparx(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int intrflush(IntPtr window, bool set);
+ public delegate int getpary(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate bool isendwin();
+ public delegate int halfdelay(int tenthsOfSec);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate bool is_linetouched(IntPtr window, int line);
+ public delegate bool has_colors();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate bool is_wintouched(IntPtr window);
-
- [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
- public delegate IntPtr keyname(uint keyCode);
+ public delegate bool has_ic();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int keypad(IntPtr window, bool set);
+ public delegate bool has_il();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int leaveok(IntPtr window, bool set);
-
- [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
- public delegate IntPtr longname();
+ public delegate void idcok(IntPtr window, bool set);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int meta(IntPtr window, bool set);
+ public delegate int idlok(IntPtr window, bool set);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int mvderwin(IntPtr window, int parentLine, int parentCol);
+ public delegate void immedok(IntPtr window, bool set);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int mvwin(IntPtr window, int toLine, int toCol);
+ public delegate int init_color(short color, short red, short green, short blue);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate IntPtr newpad(int lines, int cols);
+ public delegate int init_pair(short colorPair, short fgColor, short bgColor);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate IntPtr newwin(int lines, int cols, int atLine, int atCol);
+ public delegate IntPtr initscr();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int nl();
+ public delegate int intrflush(IntPtr window, bool set);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int nocbreak();
+ public delegate bool is_cleared(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int nodelay(IntPtr window, bool set);
+ public delegate bool is_idcok(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int noecho();
+ public delegate bool is_idlok(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int nonl();
+ public delegate bool is_immedok(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate void noqiflush();
+ public delegate bool is_keypad(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int noraw();
+ public delegate bool is_leaveok(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int notimeout(IntPtr window, bool set);
+ public delegate bool is_linetouched(IntPtr window, int line);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int overlay(IntPtr srcWindow, IntPtr destWindow);
+ public delegate bool is_nodelay(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int overwrite(IntPtr srcWindow, IntPtr destWindow);
+ public delegate bool is_notimeout(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int pair_content(short colorPair, out short fgColor, out short bgColor);
+ public delegate bool is_scrollok(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate uint COLOR_PAIR(uint attrs);
+ public delegate bool is_syncok(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate uint PAIR_NUMBER(uint colorPair);
+ public delegate bool is_term_resized(int lines, int cols);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int pechochar(IntPtr pad, uint charAndAttrs);
+ public delegate bool is_wintouched(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int pnoutrefresh(IntPtr pad, int padMinLine, int padMinCol, int scrMinLine,
- int scrMinCol, int scrMaxLine, int scrMaxCol);
+ public delegate bool isendwin();
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int prefresh(IntPtr pad, int padMinLine, int padMinCol, int scrMinLine,
- int scrMinCol, int scrMaxLine, int scrMaxCol);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
+ public delegate int key_defined(string keyName);
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate void qiflush();
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
+ public delegate IntPtr key_name(uint @char);
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int raw();
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
+ public delegate IntPtr keybound(uint keyCode, int count);
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int resetty();
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
+ public delegate IntPtr keyname(uint keyCode);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int reset_prog_mode();
+ public delegate int keyok(int keyCode, bool set);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int reset_shell_mode();
+ public delegate int keypad(IntPtr window, bool set);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int ripoffline(int lines, ICursesBackend.ripoffline_callback callback);
+ public delegate int killwchar(out uint @char);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int savetty();
+ public delegate int leaveok(IntPtr window, bool set);
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int scrollok(IntPtr window, bool set);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
+ public delegate IntPtr longname();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int slk_attroff(uint attrs);
+ public delegate int meta(IntPtr window, bool set);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int slk_attron(uint attrs);
+ public delegate int mouseinterval(int millis);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int slk_attrset(uint attrs);
+ public delegate int mousemask(uint newMask, out uint oldMask);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int slk_attr();
+ public delegate int mvderwin(IntPtr window, int parentLine, int parentCol);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int slk_attr_set(uint attrs, short colorPair, IntPtr reserved);
+ public delegate int mvwin(IntPtr window, int toLine, int toCol);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int slk_clear();
+ public delegate IntPtr newpad(int lines, int cols);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int slk_color(short colorPair);
+ public delegate IntPtr newwin(int lines, int cols, int atLine, int atCol);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int slk_init(int format);
-
- [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
- public delegate IntPtr slk_label(int labelIndex);
+ public delegate int nl();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int slk_noutrefresh();
+ public delegate int nocbreak();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int slk_refresh();
+ public delegate int nodelay(IntPtr window, bool set);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int slk_restore();
+ public delegate int noecho();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int slk_touch();
+ public delegate void nofilter();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int start_color();
+ public delegate int nonl();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate IntPtr subpad(IntPtr pad, int lines, int cols, int atRow,
- int atCol);
+ public delegate void noqiflush();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate IntPtr subwin(IntPtr window, int lines, int cols, int atLine,
- int atCol);
+ public delegate int noraw();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int syncok(IntPtr window, bool set);
+ public delegate int notimeout(IntPtr window, bool set);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate IntPtr termname();
+ public delegate int overlay(IntPtr srcWindow, IntPtr destWindow);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int ungetch(uint @char);
+ public delegate int overwrite(IntPtr srcWindow, IntPtr destWindow);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate void use_env(bool set);
+ public delegate int pair_content(short colorPair, out short fgColor, out short bgColor);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int waddch(IntPtr window, uint charAndAttrs);
+ public delegate uint PAIR_NUMBER(uint colorPair);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int waddchnstr(IntPtr window, uint[] charsAndAttrs, int length);
+ public delegate int pecho_wchar(IntPtr window, ref CursesComplexChar @char);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wattr_on(IntPtr window, uint attrs, IntPtr reserved);
+ public delegate int pechochar(IntPtr pad, uint charAndAttrs);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wattr_off(IntPtr window, uint attrs, IntPtr reserved);
+ public delegate int pnoutrefresh(IntPtr pad, int padMinLine, int padMinCol, int scrMinLine,
+ int scrMinCol, int scrMaxLine, int scrMaxCol);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wbkgd(IntPtr window, uint charAndAttrs);
+ public delegate int prefresh(IntPtr pad, int padMinLine, int padMinCol, int scrMinLine,
+ int scrMinCol, int scrMaxLine, int scrMaxCol);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate void wbkgdset(IntPtr window, uint charAndAttrs);
+ public delegate void qiflush();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wborder(IntPtr window, uint leftSide, uint rightSide, uint topSide,
- uint bottomSide, uint topLeftCorner, uint topRightCorner, uint bottomLeftCorner,
- uint bottomRightCorner);
+ public delegate int raw();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wchgat(IntPtr window, int count, uint attrs, short colorPair,
- IntPtr reserved);
+ public delegate int reset_prog_mode();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wclear(IntPtr window);
+ public delegate int reset_shell_mode();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wclrtobot(IntPtr window);
+ public delegate int resetty();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wclrtoeol(IntPtr window);
+ public delegate int resize_term(int lines, int cols);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wcolor_set(IntPtr window, short colorPair, IntPtr reserved);
+ public delegate int resizeterm(int lines, int cols);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate void wcursyncup(IntPtr window);
+ public delegate int ripoffline(int lines, ICursesBackend.ripoffline_callback callback);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wdelch(IntPtr window);
+ public delegate int savetty();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wechochar(IntPtr window, uint charAndAttrs);
+ public delegate int scrollok(IntPtr window, bool set);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int werase(IntPtr window);
+ public delegate int set_tabsize(int size);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wgetch(IntPtr window);
-
- [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
- public delegate int wgetnstr(IntPtr window, StringBuilder dest, int length);
+ public delegate int setcchar(out CursesComplexChar @char, [MarshalAs(UnmanagedType.LPWStr)] string text, uint attrs,
+ short colorPair, IntPtr reserved);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int whline(IntPtr window, uint @char, int count);
+ public delegate int slk_attr();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int winch(IntPtr window);
+ public delegate int slk_attr_off(uint attrs, IntPtr reserved);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int winchnstr(IntPtr window, StringBuilder dest, int length);
+ public delegate int slk_attr_on(uint attrs, IntPtr reserved);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int winsch(IntPtr window, uint charAndAttrs);
+ public delegate int slk_attr_set(uint attrs, short colorPair, IntPtr reserved);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int winsdelln(IntPtr window, int count);
+ public delegate int slk_attroff(uint attrs);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wmove(IntPtr window, int newLine, int newCol);
+ public delegate int slk_attron(uint attrs);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wnoutrefresh(IntPtr window);
+ public delegate int slk_attrset(uint attrs);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wredrawln(IntPtr window, int startLine, int lineCount);
+ public delegate int slk_clear();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wrefresh(IntPtr window);
+ public delegate int slk_color(short colorPair);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wscrl(IntPtr window, int count);
+ public delegate int slk_init(int format);
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wsetscrreg(IntPtr window, int top, int bottom);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
+ public delegate IntPtr slk_label(int labelIndex);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate void wsyncdown(IntPtr window);
+ public delegate int slk_noutrefresh();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate void wsyncup(IntPtr window);
+ public delegate int slk_refresh();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate void wtimeout(IntPtr window, int delay);
+ public delegate int slk_restore();
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wtouchln(IntPtr window, int line, int count, int changed);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
+ public delegate int slk_set(int labelIndex, string title, int fmt);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wvline(IntPtr window, uint @char, int count);
+ public delegate int slk_touch();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate bool is_term_resized(int lines, int cols);
+ public delegate int start_color();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int resize_term(int lines, int cols);
+ public delegate IntPtr subpad(IntPtr pad, int lines, int cols, int atRow,
+ int atCol);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int resizeterm(int lines, int cols);
-
- [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
- public delegate IntPtr keybound(uint keyCode, int count);
+ public delegate IntPtr subwin(IntPtr window, int lines, int cols, int atLine,
+ int atCol);
- [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
- public delegate IntPtr curses_version();
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate int syncok(IntPtr window, bool set);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int assume_default_colors(int fgColor, int bgColor);
+ public delegate int term_attrs();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int define_key(string keyName, int keyCode);
+ public delegate IntPtr termname();
- [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
- public delegate int key_defined(string keyName);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate int unget_wch(uint @char);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int keyok(int keyCode, bool set);
+ public delegate int ungetch(uint @char);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int set_tabsize(int size);
+ public delegate int ungetmouse(ref CursesMouseEvent @event);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int use_default_colors();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wresize(IntPtr window, int lines, int columns);
+ public delegate void use_env(bool set);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate void nofilter();
+ public delegate int wadd_wch(IntPtr window, ref CursesComplexChar @char);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int getcchar(ref CursesComplexChar @char, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder dest,
- out uint attrs, out short colorPair, IntPtr reserved);
-
- [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
- public delegate IntPtr key_name(uint @char);
+ public delegate int wadd_wchnstr(IntPtr window, CursesComplexChar[] @char, int count);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int killwchar(out uint @char);
+ public delegate int waddch(IntPtr window, uint charAndAttrs);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int pecho_wchar(IntPtr window, ref CursesComplexChar @char);
+ public delegate int waddchnstr(IntPtr window, uint[] charsAndAttrs, int length);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int setcchar(out CursesComplexChar @char, [MarshalAs(UnmanagedType.LPWStr)] string text, uint attrs,
- short colorPair, IntPtr reserved);
+ public delegate int waddnwstr(IntPtr window, [MarshalAs(UnmanagedType.LPWStr)] string text, int length);
- [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
- public delegate int slk_set(int labelIndex, string title, int fmt);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate int wattr_get(IntPtr window, out uint attrs, out short colorPair, IntPtr reserved);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int term_attrs();
+ public delegate int wattr_off(IntPtr window, uint attrs, IntPtr reserved);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int unget_wch(uint @char);
+ public delegate int wattr_on(IntPtr window, uint attrs, IntPtr reserved);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wadd_wch(IntPtr window, ref CursesComplexChar @char);
+ public delegate int wattr_set(IntPtr window, uint attrs, short colorPair, IntPtr reserved);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wadd_wchnstr(IntPtr window, CursesComplexChar[] @char, int count);
+ public delegate int wbkgd(IntPtr window, uint charAndAttrs);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int waddnwstr(IntPtr window, [MarshalAs(UnmanagedType.LPWStr)] string text, int length);
+ public delegate void wbkgdset(IntPtr window, uint charAndAttrs);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int wbkgrnd(IntPtr window, ref CursesComplexChar @char);
@@ -489,6 +483,11 @@ public delegate int setcchar(out CursesComplexChar @char, [MarshalAs(UnmanagedTy
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void wbkgrndset(IntPtr window, ref CursesComplexChar @char);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate int wborder(IntPtr window, uint leftSide, uint rightSide, uint topSide,
+ uint bottomSide, uint topLeftCorner, uint topRightCorner, uint bottomLeftCorner,
+ uint bottomRightCorner);
+
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int wborder_set(IntPtr window, ref CursesComplexChar leftSide, ref CursesComplexChar rightSide,
ref CursesComplexChar topSide, ref CursesComplexChar bottomSide, ref CursesComplexChar topLeftCorner,
@@ -496,134 +495,135 @@ public delegate int wborder_set(IntPtr window, ref CursesComplexChar leftSide, r
ref CursesComplexChar bottomRightCorner);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wecho_wchar(IntPtr window, ref CursesComplexChar @char);
+ public delegate int wchgat(IntPtr window, int count, uint attrs, short colorPair,
+ IntPtr reserved);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wget_wch(IntPtr window, out uint dest);
+ public delegate int wclear(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wgetbkgrnd(IntPtr window, out CursesComplexChar @char);
+ public delegate int wclrtobot(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wgetn_wstr(IntPtr window, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder dest, int length);
+ public delegate int wclrtoeol(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int whline_set(IntPtr window, ref CursesComplexChar @char, int count);
+ public delegate int wcolor_set(IntPtr window, short colorPair, IntPtr reserved);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int win_wch(IntPtr window, out CursesComplexChar @char);
+ public delegate void wcursyncup(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int win_wchnstr(IntPtr window, CursesComplexChar[] @char, int length);
+ public delegate int wdelch(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int winnwstr(IntPtr window, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder text, int length);
+ public delegate int wecho_wchar(IntPtr window, ref CursesComplexChar @char);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wins_nwstr(IntPtr window, string text, int length);
+ public delegate int wechochar(IntPtr window, uint charAndAttrs);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wins_wch(IntPtr window, ref CursesComplexChar @char);
+ public delegate bool wenclose(IntPtr window, int line, int col);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate IntPtr wunctrl(ref CursesComplexChar @char);
+ public delegate int werase(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wvline_set(IntPtr window, ref CursesComplexChar @char, int count);
+ public delegate int wget_wch(IntPtr window, out uint dest);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int erasewchar(out uint @char);
+ public delegate int wgetbkgrnd(IntPtr window, out CursesComplexChar @char);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int getattrs(IntPtr window);
+ public delegate int wgetch(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int getcurx(IntPtr window);
+ public delegate int wgetn_wstr(IntPtr window, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder dest, int length);
- [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int getcury(IntPtr window);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
+ public delegate int wgetnstr(IntPtr window, StringBuilder dest, int length);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int getbegx(IntPtr window);
+ public delegate IntPtr wgetparent(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int getbegy(IntPtr window);
+ public delegate int wgetscrreg(IntPtr window, out int top, out int bottom);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int getmaxx(IntPtr window);
+ public delegate int whline(IntPtr window, uint @char, int count);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int getmaxy(IntPtr window);
+ public delegate int whline_set(IntPtr window, ref CursesComplexChar @char, int count);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int getparx(IntPtr window);
+ public delegate int win_wch(IntPtr window, out CursesComplexChar @char);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int getpary(IntPtr window);
+ public delegate int win_wchnstr(IntPtr window, CursesComplexChar[] @char, int length);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int slk_attr_off(uint attrs, IntPtr reserved);
+ public delegate int winch(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int slk_attr_on(uint attrs, IntPtr reserved);
+ public delegate int winchnstr(IntPtr window, StringBuilder dest, int length);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wattr_get(IntPtr window, out uint attrs, out short colorPair, IntPtr reserved);
+ public delegate int winnwstr(IntPtr window, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder text, int length);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wattr_set(IntPtr window, uint attrs, short colorPair, IntPtr reserved);
+ public delegate int wins_nwstr(IntPtr window, string text, int length);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate bool is_cleared(IntPtr window);
+ public delegate int wins_wch(IntPtr window, ref CursesComplexChar @char);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate bool is_idcok(IntPtr window);
+ public delegate int winsch(IntPtr window, uint charAndAttrs);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate bool is_idlok(IntPtr window);
+ public delegate int winsdelln(IntPtr window, int count);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate bool is_immedok(IntPtr window);
+ public delegate bool wmouse_trafo(IntPtr window, ref int line, ref int col, bool toScreen);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate bool is_keypad(IntPtr window);
+ public delegate int wmove(IntPtr window, int newLine, int newCol);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate bool is_leaveok(IntPtr window);
+ public delegate int wnoutrefresh(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate bool is_nodelay(IntPtr window);
+ public delegate int wredrawln(IntPtr window, int startLine, int lineCount);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate bool is_notimeout(IntPtr window);
+ public delegate int wrefresh(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate bool is_scrollok(IntPtr window);
+ public delegate int wresize(IntPtr window, int lines, int columns);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate bool is_syncok(IntPtr window);
+ public delegate int wscrl(IntPtr window, int count);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate IntPtr wgetparent(IntPtr window);
+ public delegate int wsetscrreg(IntPtr window, int top, int bottom);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int wgetscrreg(IntPtr window, out int top, out int bottom);
+ public delegate void wsyncdown(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int getmouse(out CursesMouseEvent @event);
+ public delegate void wsyncup(IntPtr window);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int ungetmouse(ref CursesMouseEvent @event);
+ public delegate void wtimeout(IntPtr window, int delay);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int mousemask(int newMask, out int oldMask);
+ public delegate int wtouchln(IntPtr window, int line, int count, int changed);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate bool wenclose(IntPtr window, int line, int col);
+ public delegate IntPtr wunctrl(ref CursesComplexChar @char);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate int mouseinterval(int millis);
+ public delegate int wvline(IntPtr window, uint @char, int count);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- public delegate bool wmouse_trafo(IntPtr window, ref int line, ref int col, bool toScreen);
+ public delegate int wvline_set(IntPtr window, ref CursesComplexChar @char, int count);
}
diff --git a/Sharpie/Backend/NativeLibraryWrapper.cs b/Sharpie/Backend/NativeLibraryWrapper.cs
index de4aa2c..dae88dd 100644
--- a/Sharpie/Backend/NativeLibraryWrapper.cs
+++ b/Sharpie/Backend/NativeLibraryWrapper.cs
@@ -97,8 +97,9 @@ public TDelegate Resolve() where TDelegate: MulticastDelegate
{
Debug.Assert(dotNetSystemAdapter != null);
- if (string.IsNullOrEmpty(Path.GetDirectoryName(libraryNameOrPath)) &&
- dotNetSystemAdapter.TryLoadNativeLibrary(libraryNameOrPath, Assembly.GetCallingAssembly(), null, out var libHandle) ||
+ if (string.IsNullOrEmpty(dotNetSystemAdapter.GetDirectoryName(libraryNameOrPath)) &&
+ dotNetSystemAdapter.TryLoadNativeLibrary(libraryNameOrPath, Assembly.GetCallingAssembly(), null,
+ out var libHandle) ||
dotNetSystemAdapter.TryLoadNativeLibrary(libraryNameOrPath, out libHandle))
{
return new(dotNetSystemAdapter, libHandle);
diff --git a/Sharpie/Backend/UnixNCursesBackend.cs b/Sharpie/Backend/UnixNCursesBackend.cs
index 120d744..1d8ba0e 100644
--- a/Sharpie/Backend/UnixNCursesBackend.cs
+++ b/Sharpie/Backend/UnixNCursesBackend.cs
@@ -31,7 +31,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
namespace Sharpie.Backend;
///
-/// NCurses-backend with unix-specific extensions.
+/// NCurses-backend with unix-specific extensions.
///
[SupportedOSPlatform("linux"), SupportedOSPlatform("macos"), SupportedOSPlatform("freebsd")]
internal sealed class UnixNCursesBackend: NCursesBackend
@@ -39,35 +39,35 @@ internal sealed class UnixNCursesBackend: NCursesBackend
private readonly INativeSymbolResolver _libCSymbolResolver;
///
- /// Creates a new instance of this class.
+ /// Creates a new instance of this class.
///
/// The .NET system adapter.
/// The NCurses symbol resolver.
/// The LibC symbol resolver.
- public UnixNCursesBackend(IDotNetSystemAdapter dotNetSystemAdapter,
- INativeSymbolResolver nCursesSymbolResolver,
- INativeSymbolResolver libCSymbolResolver):
- base(dotNetSystemAdapter, nCursesSymbolResolver)
+ public UnixNCursesBackend(IDotNetSystemAdapter dotNetSystemAdapter, INativeSymbolResolver nCursesSymbolResolver,
+ INativeSymbolResolver libCSymbolResolver): base(dotNetSystemAdapter, nCursesSymbolResolver)
{
Debug.Assert(dotNetSystemAdapter.IsUnixLike);
Debug.Assert(libCSymbolResolver != null);
_libCSymbolResolver = libCSymbolResolver;
}
-
+
// ReSharper disable IdentifierTypo
// ReSharper disable InconsistentNaming
-
- public override int mousemask(int newMask, out int oldMask)
+
+ public override int mousemask(uint newMask, out uint oldMask)
{
var result = base.mousemask(newMask, out oldMask);
if (!result.Failed())
{
+ var parser = CursesMouseEventParser.Get(mouse_version());
+
var csi = "\x1b[?1003l";
- if ((newMask & (int) CursesMouseEvent.EventType.ReportPosition) != 0)
+ if ((newMask & parser.ReportPosition) != 0)
{
csi = "\x1b[?1003h";
- } else if ((newMask & (int) CursesMouseEvent.EventType.All) != 0)
+ } else if ((newMask & parser.All) != 0)
{
csi = "\x1b[?1000h";
}
@@ -90,7 +90,7 @@ public override bool monitor_pending_resize(Action action, [NotNullWhen(true)] o
handle = DotNetSystemAdapter.MonitorTerminalResizeSignal(action);
return true;
}
-
+
// ReSharper restore InconsistentNaming
// ReSharper restore IdentifierTypo
}
diff --git a/Sharpie/Canvas.cs b/Sharpie/Canvas.cs
index 80b9aa5..a6c4017 100644
--- a/Sharpie/Canvas.cs
+++ b/Sharpie/Canvas.cs
@@ -1,7 +1,8 @@
namespace Sharpie;
///
-/// A general-purpose drawing surface that can be latter draw onto any object that implements .
+/// A general-purpose drawing surface that can be latter draw onto any object that implements
+/// .
/// Supports multiple types of drawing operations most commonly used in terminal apps.
///
[PublicAPI]
@@ -557,9 +558,6 @@ public Canvas(Size size)
_cells = new Cell[size.Width, size.Height];
}
- ///
- void IDrawSurface.DrawCell(Point location, Rune rune, Style style) { SetCell(location.X, location.Y, rune, style); }
-
///
public Size Size { get; }
@@ -595,6 +593,9 @@ public void DrawOnto(IDrawSurface destination, Rectangle srcArea, Point destLoca
}
}
+ ///
+ void IDrawSurface.DrawCell(Point location, Rune rune, Style style) { SetCell(location.X, location.Y, rune, style); }
+
private bool InArea(int x, int y) => x >= 0 && x < Size.Width && y >= 0 && y < Size.Height;
private void SetCell(int x, int y, Rune rune, Style style)
@@ -835,7 +836,8 @@ public void Glyph(Point location, GradientGlyphStyle gradientGlyphStyle, int fil
}
///
- /// Draws a line starting at a given starting at a given point vertically or horizontally using line drawing characters.
+ /// Draws a line starting at a given starting at a given point vertically or horizontally using line drawing
+ /// characters.
///
/// The start location.
/// The line orientation.
@@ -920,7 +922,7 @@ public void Line(PointF location, float length, Orientation orientation, LineSty
}
///
- /// Draws a line between two points in the drawing using block characters.
+ /// Draws a line between two points in the drawing using block characters.
///
/// The starting cell.
/// The ending cell.
diff --git a/Sharpie/EventPump.cs b/Sharpie/EventPump.cs
index 92ef477..3cffca5 100644
--- a/Sharpie/EventPump.cs
+++ b/Sharpie/EventPump.cs
@@ -10,6 +10,7 @@ namespace Sharpie;
public sealed class EventPump: IEventPump
{
private readonly IList _keySequenceResolvers = new List();
+ private CursesMouseEventParser _cursesMouseEventParser;
private ConcurrentQueue