How to get graphic tablet pen pressure value? - c#

I'm using a Wacom Bamboo Pen tablet and I'd like to be able to get its pen pressure value in my application written in C#. How do I do that? Is there maybe an API that allows one to get pen values on Windows 7?

Wacom provides an extensive API to get data directly from the tablet.The API includes example code for detecting pressure, tilt and other interactions:
Tilt Test: Demonstrates pressure, use of the eraser and pen tilt properties
Pressure Test: Demonstrates how to detect and display pen pressure
These code samples are in C, but there are also examples that in c#.net that include code to handle pressure:
WintabDN: Interface, scribble and tablet control samples using Wintab .NET
Using this project as an example, you can get the pressure like this:
// Create a data object and hook a packetlistener to receive
// updatse by the tablet
m_wtData = new CWintabData();
m_wtData.SetWTPacketEventHandler(handler);
//Handles packet receive event
void handler(object sender,MessageReceivedEventArgs e)
{
//Get the packet id
uint pktID = (uint)eventArgs_I.Message.WParam;
//Get the data for that packet
WintabPacket pkt = m_wtData.GetDataPacket((uint)eventArgs_I.Message.LParam, pktID);
//Grab the pressure
var pressure = pk.pkNormalPressure.pkAbsoluteNormalPressure;
}
Next, here is a CodeProject that explains how to use the Wacom Tablet with the WPF InkCanvas
A good starting point for any tablet related development on windows is also the Ink API.

Can be a starting point
http://www.codeproject.com/Articles/46281/Digitizer-interface-in-C-using-VBTablet
Thats the right link to the project: http://sourceforge.net/projects/vbtablet/

Related

SpatialCoordinateSystem.TryGetTransformTo() from Webcam to Unity space fails in a non-initial, separated spatial environment on HoloLens 2

I have a quite specific problem regarding to a transformation matrix for transformations from the HoloLens 2 webcam space into the current Unity scene space in a Unity+MRTK+OpenXR app. The goal is to acquire the exact camera pose related to a camera frame, which was acquired through Windows.Media.Capture, in Unity space.
My environment:
Unity 2021.3.8.
MRTK v2.8.2
Mixed Reality OpenXR Plug-In v1.6.0
For obtaining the matrix, I first receive a Windows.Perception.Spatial.SpatialCoordinateSystem instance (unityReferenceCoordinateSystem) representing the Unity Space through the MR OpenXR Plug-In as described HERE:
using Windows.Perception.Spatial;
using Microsoft.MixedReality.OpenXR;
SpatialCoordinateSystem unityReferenceCoordinateSystem = PerceptionInterop.GetSceneCoordinateSystem(Pose.identity) as SpatialCoordinateSystem;
and I obtain the camera space (cameraCoordinateSystem) from the Windows.Media.Capture.Frames.MediaFrameReference camera frame instance acquired from a MediaFrameReader by
MediaFrameReference mediaFrame; // acquired camera frame
SpatialCoordinateSystem cameraCoordinateSystem = mediaFrame.CoordinateSystem;
Finally I obtain the required transformation matrix by using SpatialCoordinateSystem.TryGetTransformTo() as you can see in my complete method:
using Microsoft.MixedReality.Toolkit;
public bool TryGetCameraToUnityMatrix(out Matrix4x4 cameraToUnity)
{
// (obtain MediaFrameReader, acquire a camera frame and obtain
// unityReferenceCoordinateSystem and cameraCoordinateSystem as described above)
System.Numerics.Matrix4x4? camToUnitySysMatrix = cameraCoordinateSystem.TryGetTransformTo(unityReferenceCoordinateSystem);
if (!camToUnitySysMatrix.HasValue)
{
return false;
}
cameraToUnity = camToUnitySysMatrix.Value.ToUnity();
return true;
}
This works all fine so far - until I bring the HoloLens into another spatial environment, which is not connected to the environment, which was present when the app was started.
Describing the following scenario should make clear what I mean by that:
Start the app on HL2
Acquire the cameraToUnity matrix as described --> works fine
Set the HL to stand-by
Go to another room, for which the HL's spatial awareness does not know the connection between these two rooms
Wake up HL and open the (still running) app.
Acquire the cameraToUnity matrix. --> FAILS:
camToUnitySysMatrix.HasValue returns false (even though both arguments unityReferenceCoordinateSystem and cameraCoordinateSystem are not null.)
Set the HL to stand-by again
Go back to the initial environment where the app was originaly started
Wake up HL and open the (still running) app.
Acquire the cameraToUnity matrix as described --> works fine again! (camToUnitySysMatrix has valid value again)
I also made sure that unityReferenceCoordinateSystem = PerceptionInterop.GetSceneCoordinateSystem(Pose.identity) is re-called after I changed the environment and also the MediaFrameReader gets freshly instantiated origining from a new MediaCapture instance.
But obviously a transformation between the two SpatialCoordinateSystems seems to fail if it is attempted in the non-initial spatial environment.
Any ideas on how to solve this?
UPDATE
A minimal Unity sample project for reproducing this problem can be found here:
https://github.com/pjaydev/trygettransformto-so
Usually, users should wear the HoloLens device and keep it turned on while moving and operating, so that the device can fully understand the environment. And HoloLens also has some requirements on the size of the site used, if the room is too small, HoloLens may not work properly. If you have confusion about this issue or there is business impact, you can submit a ticket via aka.ms/HLSupport.

Take screenshot of external OpenGL game C# with BitBlt (CopyFromScreen)

I am trying to create some kind of antycheat for counter strike (hl) game. Of course funcionality of making a screenshot in-game is built-in, but exploited (detected) by antyss applications, so every time screenshot is taken from the game, antyss is disabling the cheats (so that no cheats are visible on the screenshots)
For the last few days, I've read dozens of threads regarding this topic. Most of them are outdated and are using libraries, that are obsolete right now.
I've read about the approach with mirage driver (which is not working on windows 10), about injecting to the application (of course application/game is not part of my code) and using/incjeting some code with OPEN GL/D3D library (to read backbuffer). Probably this could be in the end the only solution.
But right now I have almost a working solution. I write "almost" because it is working but giving me only some kind of "cached" data. It is giving me a correct screenshot, but if I take another screenshot - still the same screenshot is taken as last time. If while being in-game I minimize the application (full-screen mode) and then get back to the game, the new screenshot taken will have up to date screenshot, but then again, the next screenshot would be exactly the same.
I don't know if it is "by design" or is it "some sort of bug" Nevertheless my question is: Can I force somehow this "reloading" without having to programmatically call some kind of "alt+tab" and then focusing on the application once again?
In this topic:
How to take screenshots of a game with OpenGL
#Andon M. Coleman wrote:
Are you on Windows? In fullscreen mode starting with Windows Vista, there is trouble with anything that tries to capture the front-buffer (including the built-in Alt + PrintScreen). The easiest solution is to change your buffer swap behavior to Copy Swap (PFD_SWAP_COPY, slower but guaranteed to work). Often if you Alt+TAB out and back in after making the fullscreen mode switch that will fix it too; though I have never been able to explain that ;) If you did not write the game in the question, then the second solution may be your only choice if you want to use that code.
This is exactly the problem I am facing. As he wrote: "Alt+Tab" is fixing the problem (although he did not know whether it is a feature or a bug) He proposed to change the buffer swap behavior to Copy Swap(PFD_SWAP_COPY) Any tips on how to change my code with that will also be most welcome (I can try this one) But if I understood correctly, this approach is the viable solution only if you can change this in the game (and this is not my case)
Here is my working code (which in topics about such scenarios was claiming that in this approach the screenshot is BLACK. But it is working for me)
private const int SW_RESTORE = 9;
public void TakeScreenShot()
{
var guid = Guid.NewGuid();
string procName = "hl";
Process proc;
try
{
proc = Process.GetProcessesByName(procName)[0];
}
catch (IndexOutOfRangeException e)
{
return;
}
// Focus on the application
SetForegroundWindow(proc.MainWindowHandle);
ShowWindow(proc.MainWindowHandle, SW_RESTORE);
Thread.Sleep(1000);
Rect rect = new Rect();
IntPtr error = GetWindowRect(proc.MainWindowHandle, ref rect);
while (error == (IntPtr)0)
{
error = GetWindowRect(proc.MainWindowHandle, ref rect);
}
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
using (Bitmap printscreen = new Bitmap(width, height, PixelFormat.Format32bppArgb))
{
using (var graphics = Graphics.FromImage(printscreen))
{
graphics.CopyFromScreen(rect.left,
rect.top,
0,
0,
new Size(width, height),
CopyPixelOperation.SourceCopy);
printscreen.Save($#"{Path.GetTempPath()}\{guid.ToString()}.jpg", ImageFormat.Jpeg);
}
}
}
I want this application to work on Windows7, Windows8, Windows 10. The best would be to cover full screen and windowed mode (but fullscreen is probably more important)
Any advice how to proceed (or why I am getting the "cached" data) would be nice :)
Of course if someone will say (with full authority), that what i want to achieve is impossible with CopyFromScreen (and there is no hack to fix that, apart from minimizing and maximazing the screen) i will consider option with injecting the code. But normally i would want to stay away from this one, as this could be treated as cheat and can lead to VAC ban.
====== UPDATE ======
You can try reproduce the process of taking screenshot by downloading the game (is small one, 260 MB):
https://cssetti.pl/Api/GameDownload.php?GameDownloadId=v43
Then you can copy-paste my code to Linqpad (or any other editor) and run the code. The application after launching will launch the HL process which is then use to try to grab the screenshot.
====== UPDATE 2 ======
In windows mode everything works correctly (the printscreens are ok)

How to workaround .NET Out of memory on GDI+ DrawArc() bug and find reference material

I know GDI+ is a bit antiquated, but I'm currently being forced to use it in in a WinForms app to draw complex CAD type models.
I encountered what I believe is the same issue as:
Why is my c# paint method running out of memory? as described by the currently accepted answer (https://stackoverflow.com/a/7501899/9300908) as well as some comments. I've ensured my brushes, pens, and fonts are disposed of as well as bitmaps and other gdi objects. I'm drawing 10s to 100s of thousands of arcs with the DrawArc() function and the same arc (1.13 degrees) each time is giving me trouble. I suspect I have encountered the small arc bug.
I'm planning to simply draw a line instead of an arc at whenever the conditions exceed a certain threshold, but I'm struggling to define the threshold. I'm trying to find a good source for what size is too small (I see references to < 1 degree, < 2 pixels, < 3.5 degrees) so that I don't need to rely on the exception handler especially when dealing with similarly small arcs.
The referenced answer as well as comments refer to a number of Microsoft Connect articles that are unavailable now that Microsoft Connect is now retired. I don't seem to have the magic sauce to find it in the visual studio developer community where I thought it might be moved to. Anyone have any reference material on the DrawArc bug or maybe an alternative workaround?
Connect references:
http://connect.microsoft.com/VisualStudio/feedback/details/121532/drawarc-out-of-memory-exception-on-small-arcs
http://connect.microsoft.com/VisualStudio/feedback/details/253886/graphics-drawarc-throws-outofmemoryexception-for-no-good-reason
Mentioned on msdn regarding DrawPath:
https://social.msdn.microsoft.com/Forums/vstudio/en-US/4c0aa2b2-6555-4c6f-85fc-8467e86bdf20/systemdrawinggraphicsdrawpath-throws-outofmemoryexception-when-drawing-a-very-small-cubic-bezier?forum=netfxbcl
https://connect.microsoft.com/VisualStudio/feedback/details/182774
Other forums I've found point back to the referenced question.
Update
Environment is x64, .NET 4.5.2
1.13 is the sweepAngle (see below for the effective values). It and the startAngle are both native floats.
I can recreate the exception with this sample code from a new WinForms app.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// g is a graphics object created from a 1920W x 1080H Bitmap:
using (Bitmap mBitmapModel = new Bitmap(1920, 1080))
{
using (Graphics g = Graphics.FromImage(mBitmapModel))
{
float lStartAngle = -0.00816029962F;
float lSweepAngle = 1.13203466F;
RectangleF lRect = new RectangleF(742.741333F, 157.927505F, 3.28945208F, 3.28945208F);
using (Pen lPen = new Pen(Color.Blue, 2F))
{
g.DrawArc(lPen, lRect, lStartAngle, lSweepAngle);
}
}
}
}
}

How to integrate wacom tablets to WPF [duplicate]

I'm using a Wacom Bamboo Pen tablet and I'd like to be able to get its pen pressure value in my application written in C#. How do I do that? Is there maybe an API that allows one to get pen values on Windows 7?
Wacom provides an extensive API to get data directly from the tablet.The API includes example code for detecting pressure, tilt and other interactions:
Tilt Test: Demonstrates pressure, use of the eraser and pen tilt properties
Pressure Test: Demonstrates how to detect and display pen pressure
These code samples are in C, but there are also examples that in c#.net that include code to handle pressure:
WintabDN: Interface, scribble and tablet control samples using Wintab .NET
Using this project as an example, you can get the pressure like this:
// Create a data object and hook a packetlistener to receive
// updatse by the tablet
m_wtData = new CWintabData();
m_wtData.SetWTPacketEventHandler(handler);
//Handles packet receive event
void handler(object sender,MessageReceivedEventArgs e)
{
//Get the packet id
uint pktID = (uint)eventArgs_I.Message.WParam;
//Get the data for that packet
WintabPacket pkt = m_wtData.GetDataPacket((uint)eventArgs_I.Message.LParam, pktID);
//Grab the pressure
var pressure = pk.pkNormalPressure.pkAbsoluteNormalPressure;
}
Next, here is a CodeProject that explains how to use the Wacom Tablet with the WPF InkCanvas
A good starting point for any tablet related development on windows is also the Ink API.
Can be a starting point
http://www.codeproject.com/Articles/46281/Digitizer-interface-in-C-using-VBTablet
Thats the right link to the project: http://sourceforge.net/projects/vbtablet/

StylusEvent on Windows Surface Pro

I'm developing an application for a Windows Surface Pro. I need to gather the pen pressure on the screen and i figuret out to do.
After solving some issue due to Event (StylusDown, StylusUp and other Stylus event are never raised, bu only mouse event) i landed in a work around.
I will show you the code (taken from some microsoft guide)
Basically is a filter for raw event
class MyFilterPlugin : StylusPlugIn
{
protected override void OnStylusDown(RawStylusInput rawStylusInput)
{
// Call the base class before modifying the data.
base.OnStylusDown(rawStylusInput);
Console.WriteLine("Here");
// Restrict the stylus input.
Filter(rawStylusInput);
}
private void Filter(RawStylusInput rawStylusInput)
{
// Get the StylusPoints that have come in.
StylusPointCollection stylusPoints = rawStylusInput.GetStylusPoints();
// Modify the (X,Y) data to move the points
// inside the acceptable input area, if necessary.
for (int i = 0; i < stylusPoints.Count; i++)
{
Console.WriteLine("p: " + stylusPoints[i].PressureFactor);
StylusPoint sp = stylusPoints[i];
if (sp.X < 50) sp.X = 50;
if (sp.X > 250) sp.X = 250;
if (sp.Y < 50) sp.Y = 50;
if (sp.Y > 250) sp.Y = 250;
stylusPoints[i] = sp;
}
// Copy the modified StylusPoints back to the RawStylusInput.
rawStylusInput.SetStylusPoints(stylusPoints);
}
Added as Filter in StylusPlugin
StylusPlugIns.Add(new MyFilterPlugin());
While i run this, however, i always get 0.5 as PressureFactor (the default value) and inspecting more deep I still can see the evironment of Stylus is not properly set (his Id is 0 for example).
There is a way to gather StylusEvent correctly?
The main point is: i need to gather the pressure (how much pressure) of the pen on the screen.
Thanks a lot.
Some Info: i'm developing with visuals tudio 2012 Ultimate, on a win 7 Pc. I deploy the application in a Surface Pro with windows 8.1. I installed and configured the Surface SDK 2.0 and the Surface Runtime.
For completition i have solved this.
Stylus event (don't know how) conflicted with the Surface SDK. Once i removed the SDK reference from the project all went smooth and the problem i solved.
Now i can gather correctly the pressure of each pen touch and on pen move.
I post this only for community information.

Categories

Resources