U++ framework
Do not panic. Ask here before giving up.

Home » Developing U++ » U++ Developers corner » Using Pen with U++
Using Pen with U++ [message #56390] Wed, 03 March 2021 16:13 Go to next message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
Hi,

I just got a Wacom Intuos S (pen tablet). I'm planning on supporting using these devices with my software. Using the pen in place of the mouse works mostly as expected.

However, I would like to read the pen pressure in MouseMove(), (and possibly tilt/rotation some day too):

	POINTER_INFO pi;
	POINTER_PEN_INFO ppi;
	
	UINT32 pressure=0;
	
	if(GetPointerInfo(GET_POINTERID_WPARAM(wParam), &pi)) {
	  if(pi.pointerType == PT_PEN) {
	    UINT32 ppid = pi.pointerId;
	    if(GetPointerPenInfo(ppid, &ppi)) pressure=ppi.pressure;
	  }
	}


,but I can't, since I cannot access wParam.

Would it be much trouble to add support inside CtrlCore for getting pen pressure for current MouseMove()?

Unfortunately GetPointerInfo() and GetPointerPenInfo() are only available in Windows 8 and later, so some conditioning is required.

Best regards,

Tom

[Updated on: Wed, 03 March 2021 16:14]

Report message to a moderator

Re: Using Pen with U++ [message #56391 is a reply to message #56390] Wed, 03 March 2021 17:06 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 14291
Registered: November 2005
Ultimate Member
Tom1 wrote on Wed, 03 March 2021 16:13
Hi,

I just got a Wacom Intuos S (pen tablet). I'm planning on supporting using these devices with my software. Using the pen in place of the mouse works mostly as expected.

However, I would like to read the pen pressure in MouseMove(), (and possibly tilt/rotation some day too):

	POINTER_INFO pi;
	POINTER_PEN_INFO ppi;
	
	UINT32 pressure=0;
	
	if(GetPointerInfo(GET_POINTERID_WPARAM(wParam), &pi)) {
	  if(pi.pointerType == PT_PEN) {
	    UINT32 ppid = pi.pointerId;
	    if(GetPointerPenInfo(ppid, &ppi)) pressure=ppi.pressure;
	  }
	}


,but I can't, since I cannot access wParam.

Would it be much trouble to add support inside CtrlCore for getting pen pressure for current MouseMove()?

Unfortunately GetPointerInfo() and GetPointerPenInfo() are only available in Windows 8 and later, so some conditioning is required.

Best regards,

Tom


Sure and you can code around Windows 8 stuff (we do it here and there already, you just need to load the function pointer in the code).

Going to search for cheap tablet Smile

Mirek
Re: Using Pen with U++ [message #56392 is a reply to message #56391] Wed, 03 March 2021 20:40 Go to previous messageGo to next message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
Hi Mirek,

Thanks, sounds great!

I was too frugal to get one with tilt and/or rotation as I don't really need them at this time. So I can only test the pressure part here.

I wonder if Gdk support is straight forward...

Best regards,

Tom
Re: Using Pen with U++ [message #56409 is a reply to message #56392] Tue, 09 March 2021 12:04 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 14291
Registered: November 2005
Ultimate Member
Should be implemented in windows. This works on my computer:

#include <CtrlLib/CtrlLib.h>

using namespace Upp;

struct MyApp : TopWindow {
	Point pos;
	
	Vector<Vector<Tuple<double, Pointf>>> drawing;
	
	virtual void LeftDown(Point p, dword)
	{
		if(IsPointerPen())
			drawing.Add().Add(MakeTuple(GetPenPressure(), p));
		Refresh();
	}

	virtual void MouseMove(Point p, dword keyflags) {
		pos = p;
		if(IsPointerPen() && drawing.GetCount())
			drawing.Top().Add(MakeTuple(GetPenPressure(), p));
		Refresh();
	}
	
	virtual void Paint(Draw& w0)
	{
		DrawPainter w(w0, GetSize());
		w.Clear(SColorPaper());
		
		w.LineCap(LINECAP_ROUND);
		for(const auto& stroke : drawing)
			if(stroke.GetCount())
				for(int i = 0; i < stroke.GetCount() - 1; i++) {
					w.Move(stroke[i].b);
					w.Line(stroke[i + 1].b);
					w.Stroke(DPI(20) * stroke[i].a, Black());
				}
		
		int fcy = GetStdFontCy();
		int y = 10;
		auto Text = [&] (const String& text) {
			w.DrawText(10, y, text);
			y += fcy;
		};
		Text(AsString(pos));
		Text(String() << "Pen: " << IsPointerPen());
		Text(String() << "Pressure: " << GetPenPressure());
		Text(String() << "Rotation: " << GetPenRotation());
		Text(String() << "Tilt: " << GetPenTilt());
		Text(String() << "Barrel: " << IsPenBarrelPressed());
		Text(String() << "Inverted: " << IsPenInverted());
		Text(String() << "Eraser: " << IsPenInverted());
		Refresh();
	}
};

GUI_APP_MAIN
{
	MyApp().Run();
}


Cheap tablet I have bought does not have tilt/rotation support so I cannot test it, but the code is quite straightforward so there is a good chance it will work - it is good that you have that HW in yours Smile

These changes should not break Win7 compatibility, once again would be nice if you tested that.
Re: Using Pen with U++ [message #56410 is a reply to message #56409] Tue, 09 March 2021 13:10 Go to previous messageGo to next message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
Hi Mirek,

Thanks for getting this going! Unfortunately, my hardware returns false for IsPointerPen(). Based on RDUMPs I tried, it never even visits this code in Ctrl::WindowProc() :
	case WM_POINTERDOWN:
	case WM_POINTERUPDATE:
	case WM_POINTERUP:
		...


I will try to dig in further to figure out what's going on...

As for Windows 7, I have none left... I hope someone around here still does.

Best regards,

Tom
Re: Using Pen with U++ [message #56411 is a reply to message #56410] Tue, 09 March 2021 13:27 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 14291
Registered: November 2005
Ultimate Member
Tom1 wrote on Tue, 09 March 2021 13:10
Hi Mirek,

Thanks for getting this going! Unfortunately, my hardware returns false for IsPointerPen(). Based on RDUMPs I tried, it never even visits this code in Ctrl::WindowProc() :
	case WM_POINTERDOWN:
	case WM_POINTERUPDATE:
	case WM_POINTERUP:
		...


I will try to dig in further to figure out what's going on...

As for Windows 7, I have none left... I hope someone around here still does.

Best regards,

Tom


Do you have proper drivers installed? I have found it is not quite easy to get the pen working...

Mirek
Re: Using Pen with U++ [message #56412 is a reply to message #56411] Tue, 09 March 2021 13:41 Go to previous messageGo to next message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
Hi,

Yes, drivers are the current WACOM drivers. The pen does show pressure on Wacom Tablet Properties -control app.

Now I found that I had to enable 'Use Windows Ink' checkbox on Wacom Tablet Properties / Mapping page. Otherwise there will be no WM_POINTER... messages at all. However, this is unfortunate, since this causes drawing to start with a couple of centimeters long straight line before I can draw any curves. Anyway, this gets the IsPointerPen() true!

I also found that:

						if(ppi.penMask & PEN_MASK_ROTATION)
							pen_pressure = ppi.rotation * M_2PI / 360;


should be

						if(ppi.penMask & PEN_MASK_ROTATION)
							pen_rotation = ppi.rotation * M_2PI / 360;


Then the thickness works based on pressure.

Best regards,

Tom
Re: Using Pen with U++ [message #56413 is a reply to message #56412] Tue, 09 March 2021 13:47 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 14291
Registered: November 2005
Ultimate Member
Tom1 wrote on Tue, 09 March 2021 13:41
Hi,

Yes, drivers are the current WACOM drivers. The pen does show pressure on Wacom Tablet Properties -control app.

Now I found that I had to enable 'Use Windows Ink' checkbox on Wacom Tablet Properties / Mapping page. Otherwise there will be no WM_POINTER... messages at all. However, this is unfortunate, since this causes drawing to start with a couple of centimeters long straight line before I can draw any curves. Anyway, this gets the IsPointerPen() true!

I also found that:

						if(ppi.penMask & PEN_MASK_ROTATION)
							pen_pressure = ppi.rotation * M_2PI / 360;


should be

						if(ppi.penMask & PEN_MASK_ROTATION)
							pen_rotation = ppi.rotation * M_2PI / 360;


Then the thickness works based on pressure.

Best regards,

Tom


Thanks, thats a typo, fixed.
Re: Using Pen with U++ [message #56415 is a reply to message #56413] Tue, 09 March 2021 13:59 Go to previous messageGo to next message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
Mirek, did you get a Wacom or something else?

When I start drawing with the pen (and using 'Use Windows Ink' mode), Windows first draws a circle around the pointer and then only after I have moved about two centimeters, it starts drawing... with the first two centimeters of straight line and only thereafter it accurately follows the pen.

I do not know, but this feels like a Windows Ink behavior. Anyway, it makes freehand drawing impossible. I need to figure out how to get rid of this pre-processing of pen movements.

Best regards,

Tom
Re: Using Pen with U++ [message #56416 is a reply to message #56415] Tue, 09 March 2021 14:18 Go to previous messageGo to next message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
Hi,

I can now see that even when using 'Use Windows Ink' -mode, Microsoft's own 'Snip and Sketch' tool can draw tiny features without any 2 cm straight lines starters. There must be something that can be used to turn off that pre-processing programmatically.

Best regards,

Tom
Re: Using Pen with U++ [message #56417 is a reply to message #56415] Tue, 09 March 2021 14:37 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 14291
Registered: November 2005
Ultimate Member
Tom1 wrote on Tue, 09 March 2021 13:59
Mirek, did you get a Wacom or something else?

When I start drawing with the pen (and using 'Use Windows Ink' mode), Windows first draws a circle around the pointer and then only after I have moved about two centimeters, it starts drawing... with the first two centimeters of straight line and only thereafter it accurately follows the pen.

I do not know, but this feels like a Windows Ink behavior. Anyway, it makes freehand drawing impossible. I need to figure out how to get rid of this pre-processing of pen movements.

Best regards,

Tom


XP-PEN. Knowing that you have Wacom, wanted to diversify...
Re: Using Pen with U++ [message #56418 is a reply to message #56417] Tue, 09 March 2021 14:39 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 14291
Registered: November 2005
Ultimate Member
Are you testing with my code? Because I can only speak about that one and with xp-pen, it works fine with my example...

Mirek
Re: Using Pen with U++ [message #56419 is a reply to message #56418] Tue, 09 March 2021 15:07 Go to previous messageGo to next message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
Diversifying input devices sounds a good idea. Especially now that they indeed work differently.

And yes, I'm using your testing code, since diversifying there does not sound too smart...

-

Anyway, now I found that I cannot get any WM_MOUSEMOVE from the first 2 cm on screen when using Wacom with Use Windows Ink enabled. However, all the moves right from start end up in WM_POINTERUPDATE. Now this means that we need to add the following code to WM_POINTERUPDATE for pen and disable it in WM_MOUSEMOVE for pen:

	DoMouse(MOUSEMOVE, Point(lParam));
	DoCursorShape();


However, there's a slight problem here. The lParam coordinates are for the screen not window, so it needs some translation. I don't know yet how to do it...

Best regards,

Tom
Re: Using Pen with U++ [message #56420 is a reply to message #56419] Tue, 09 March 2021 15:59 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 14291
Registered: November 2005
Ultimate Member
Tom1 wrote on Tue, 09 March 2021 15:07
Diversifying input devices sounds a good idea. Especially now that they indeed work differently.

And yes, I'm using your testing code, since diversifying there does not sound too smart...

-

Anyway, now I found that I cannot get any WM_MOUSEMOVE from the first 2 cm on screen when using Wacom with Use Windows Ink enabled. However, all the moves right from start end up in WM_POINTERUPDATE. Now this means that we need to add the following code to WM_POINTERUPDATE for pen and disable it in WM_MOUSEMOVE for pen:


Disable part seems quite hard to do...

Mirek
Re: Using Pen with U++ [message #56421 is a reply to message #56420] Tue, 09 March 2021 16:56 Go to previous messageGo to next message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
How about this approach using EnableMouseInPointer() as follows?
LRESULT Ctrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
	GuiLock __;
	eventid++;
//	LLOG("Ctrl::WindowProc(" << message << ") in " << ::Name(this) << ", focus " << (void *)::GetFocus());
	Ptr<Ctrl> _this = this;
	HWND hwnd = GetHWND();
	
	ONCELOCK {
		EnableMouseInPointer(true); // #1 - enable mouse in WM_POINTER* messages
	};
	
	switch(message) {
	case WM_POINTERDOWN:
	case WM_POINTERUPDATE:
	case WM_POINTERUP:
		{

			POINT p = Point(lParam);
			ScreenToClient(hwnd, &p);

			pen = false;
			pen_pressure = pen_rotation = Null;
			pen_tilt = Null;
			pen_eraser = false;
			pen_barrel = false;
			pen_inverted = false;
			
			static BOOL (WINAPI *GetPointerType)(UINT32 pointerId, POINTER_INPUT_TYPE *pointerType);
			static BOOL (WINAPI *GetPointerInfo)(UINT32 pointerId, POINTER_INFO *pointerInfo);
			static BOOL (WINAPI *GetPointerPenInfo)(UINT32 pointerId, POINTER_PEN_INFO *penInfo);
			static BOOL (WINAPI *GetPointerTouchInfo)(UINT32 pointerId, POINTER_TOUCH_INFO *touchInfo);

			ONCELOCK {
				DllFn(GetPointerType, "User32.dll", "GetPointerType");
				DllFn(GetPointerInfo, "User32.dll", "GetPointerInfo");
				DllFn(GetPointerPenInfo, "User32.dll", "GetPointerPenInfo");
				DllFn(GetPointerTouchInfo, "User32.dll", "GetPointerTouchInfo");
			};
			
			POINTER_INPUT_TYPE pointerType;
			

			UINT32 pointerId = GET_POINTERID_WPARAM(wParam);
			if(GetPointerType && GetPointerPenInfo && GetPointerType(pointerId, &pointerType)) {
				switch(pointerType){
					case PT_PEN:{
						POINTER_PEN_INFO ppi;
						if(GetPointerPenInfo(pointerId, &ppi)) {
							pen = true;
							if(ppi.penFlags & PEN_FLAG_BARREL)
								pen_barrel = true;
							if(ppi.penFlags & PEN_FLAG_INVERTED)
								pen_inverted = true;
							if(ppi.penFlags & PEN_FLAG_ERASER)
								pen_eraser = true;
							if(ppi.penMask & PEN_MASK_PRESSURE)
								pen_pressure = ppi.pressure / 1024.0;
							if(ppi.penMask & PEN_MASK_ROTATION)
								pen_rotation = ppi.rotation * M_2PI / 360;
							if(ppi.penMask & PEN_MASK_TILT_X)
								pen_tilt.x = ppi.tiltX * M_2PI / 360;
							if(ppi.penMask & PEN_MASK_TILT_Y)
								pen_tilt.y = ppi.tiltY * M_2PI / 360;
							
						}
						break;
					}
					case PT_TOUCH:{
						POINTER_TOUCH_INFO pti;
						if(GetPointerTouchInfo(pointerId, &pti)) {
							// Add something touch specific here some day maybe...
						}
						break;
					}
					default:{
						POINTER_INFO pi;
						if(GetPointerInfo(pointerId, &pi)) {
						}
						break;
					}
				}

				if(_this) switch(message){
					case WM_POINTERDOWN:
						ClickActivateWnd();
						DoMouse(LEFTDOWN, Point(p), 0);
						PostInput();
						break;
					case WM_POINTERUP:
						DoMouse(LEFTUP, Point(p), 0);
						PostInput();
						break;
					case WM_POINTERUPDATE:
						DoMouse(MOUSEMOVE, Point(p));
						DoCursorShape();
						break;
				}
				
			}
		}
		break;
	case WM_POINTERLEAVE:
		pen = false;
		break;


Further more, this requires disabling WM_LEFTUP, WM_LEFTDOWN and WM_MOUSEMOVE as they now come in as WM_POINTER* messages.

IMPORTANT WARNING: I have not replicated their function completely in WM_POINTER above as I do not quite understand all the finer details there. Also, I'm worried about breaking everything, so I'll just throw this in 'as is' for you to consider...

Oh and yes, this fixes the 2 cm straight line start issue... Smile

Best regards,

Tom

EDIT: EnableMouseInPointer() is available on Windows8 and above only, so it needs to be loaded in a similar way as the rest of the Pointer -functions.

[Updated on: Tue, 09 March 2021 17:45]

Report message to a moderator

Re: Using Pen with U++ [message #56422 is a reply to message #56421] Tue, 09 March 2021 17:48 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 14291
Registered: November 2005
Ultimate Member
Tom1 wrote on Tue, 09 March 2021 16:56
How about this approach using EnableMouseInPointer() as follows?
LRESULT Ctrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
	GuiLock __;
	eventid++;
//	LLOG("Ctrl::WindowProc(" << message << ") in " << ::Name(this) << ", focus " << (void *)::GetFocus());
	Ptr<Ctrl> _this = this;
	HWND hwnd = GetHWND();
	
	ONCELOCK {
		EnableMouseInPointer(true); // #1 - enable mouse in WM_POINTER* messages
	};
	
	switch(message) {
	case WM_POINTERDOWN:
	case WM_POINTERUPDATE:
	case WM_POINTERUP:
		{

			POINT p = Point(lParam);
			ScreenToClient(hwnd, &p);

			pen = false;
			pen_pressure = pen_rotation = Null;
			pen_tilt = Null;
			pen_eraser = false;
			pen_barrel = false;
			pen_inverted = false;
			
			static BOOL (WINAPI *GetPointerType)(UINT32 pointerId, POINTER_INPUT_TYPE *pointerType);
			static BOOL (WINAPI *GetPointerInfo)(UINT32 pointerId, POINTER_INFO *pointerInfo);
			static BOOL (WINAPI *GetPointerPenInfo)(UINT32 pointerId, POINTER_PEN_INFO *penInfo);
			static BOOL (WINAPI *GetPointerTouchInfo)(UINT32 pointerId, POINTER_TOUCH_INFO *touchInfo);

			ONCELOCK {
				DllFn(GetPointerType, "User32.dll", "GetPointerType");
				DllFn(GetPointerInfo, "User32.dll", "GetPointerInfo");
				DllFn(GetPointerPenInfo, "User32.dll", "GetPointerPenInfo");
				DllFn(GetPointerTouchInfo, "User32.dll", "GetPointerTouchInfo");
			};
			
			POINTER_INPUT_TYPE pointerType;
			

			UINT32 pointerId = GET_POINTERID_WPARAM(wParam);
			if(GetPointerType && GetPointerPenInfo && GetPointerType(pointerId, &pointerType)) {
				switch(pointerType){
					case PT_PEN:{
						POINTER_PEN_INFO ppi;
						if(GetPointerPenInfo(pointerId, &ppi)) {
							pen = true;
							if(ppi.penFlags & PEN_FLAG_BARREL)
								pen_barrel = true;
							if(ppi.penFlags & PEN_FLAG_INVERTED)
								pen_inverted = true;
							if(ppi.penFlags & PEN_FLAG_ERASER)
								pen_eraser = true;
							if(ppi.penMask & PEN_MASK_PRESSURE)
								pen_pressure = ppi.pressure / 1024.0;
							if(ppi.penMask & PEN_MASK_ROTATION)
								pen_rotation = ppi.rotation * M_2PI / 360;
							if(ppi.penMask & PEN_MASK_TILT_X)
								pen_tilt.x = ppi.tiltX * M_2PI / 360;
							if(ppi.penMask & PEN_MASK_TILT_Y)
								pen_tilt.y = ppi.tiltY * M_2PI / 360;
							
						}
						break;
					}
					case PT_TOUCH:{
						POINTER_TOUCH_INFO pti;
						if(GetPointerTouchInfo(pointerId, &pti)) {
							// Add something touch specific here some day maybe...
						}
						break;
					}
					default:{
						POINTER_INFO pi;
						if(GetPointerInfo(pointerId, &pi)) {
						}
						break;
					}
				}

				if(_this) switch(message){
					case WM_POINTERDOWN:
						ClickActivateWnd();
						DoMouse(LEFTDOWN, Point(p), 0);
						PostInput();
						break;
					case WM_POINTERUP:
						DoMouse(LEFTUP, Point(p), 0);
						PostInput();
						break;
					case WM_POINTERUPDATE:
						DoMouse(MOUSEMOVE, Point(p));
						DoCursorShape();
						break;
				}
				
			}
		}
		break;
	case WM_POINTERLEAVE:
		pen = false;
		break;


Further more, this requires disabling WM_LEFTUP, WM_LEFTDOWN and WM_MOUSEMOVE as they now come in as WM_POINTER* messages.

IMPORTANT WARNING: I have not replicated their function completely in WM_POINTER above as I do not quite understand all the finer details there. Also, I'm worried about breaking everything, so I'll just throw this in 'as is' for you to consider...

Oh and yes, this fixes the 2 cm straight line start issue... Smile

Best regards,

Tom

EDIT: EnableMouseInPointer() is available on Windows8 and above only, so it needs to be loaded in a similar way as the rest of the Pointer -functions.


Looks good. Will try tommorow.
Re: Using Pen with U++ [message #56423 is a reply to message #56422] Tue, 09 March 2021 18:14 Go to previous messageGo to next message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
OK, good! But please try this one instead, as it takes into account the Win8 thing and also adds conditional blocking of WM_MOUSEMOVE, WM_LBUTTONUP, WM_LBUTTONDOWN:

LRESULT Ctrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
	GuiLock __;
	eventid++;
//	LLOG("Ctrl::WindowProc(" << message << ") in " << ::Name(this) << ", focus " << (void *)::GetFocus());
	Ptr<Ctrl> _this = this;
	HWND hwnd = GetHWND();
	
	static bool disableOldWMs=false; // When true, blocks out original WM_MOUSEMOVE, WM_LBUTTONUP, WM_LBUTTONDOWN

		
	switch(message) {
	case WM_POINTERDOWN:
	case WM_POINTERUPDATE:
	case WM_POINTERUP:
		{

			POINT p = Point(lParam);
			ScreenToClient(hwnd, &p);

			pen = false;
			pen_pressure = pen_rotation = Null;
			pen_tilt = Null;
			pen_eraser = false;
			pen_barrel = false;
			pen_inverted = false;
			
			static BOOL (WINAPI *EnableMouseInPointer)(WINBOOL fEnable);
			static BOOL (WINAPI *GetPointerType)(UINT32 pointerId, POINTER_INPUT_TYPE *pointerType);
			static BOOL (WINAPI *GetPointerInfo)(UINT32 pointerId, POINTER_INFO *pointerInfo);
			static BOOL (WINAPI *GetPointerPenInfo)(UINT32 pointerId, POINTER_PEN_INFO *penInfo);
			static BOOL (WINAPI *GetPointerTouchInfo)(UINT32 pointerId, POINTER_TOUCH_INFO *touchInfo);

			ONCELOCK {
				DllFn(EnableMouseInPointer, "User32.dll", "EnableMouseInPointer");
				if(EnableMouseInPointer && EnableMouseInPointer(true)) disableOldWMs=true; // Switching over to WM_POINTER* functions for mouse
				
				DllFn(GetPointerType, "User32.dll", "GetPointerType");
				DllFn(GetPointerInfo, "User32.dll", "GetPointerInfo");
				DllFn(GetPointerPenInfo, "User32.dll", "GetPointerPenInfo");
				DllFn(GetPointerTouchInfo, "User32.dll", "GetPointerTouchInfo");
			};
			
			POINTER_INPUT_TYPE pointerType;
			

			UINT32 pointerId = GET_POINTERID_WPARAM(wParam);
			if(GetPointerType && GetPointerPenInfo && GetPointerType(pointerId, &pointerType)) {
				switch(pointerType){
					case PT_PEN:{
						POINTER_PEN_INFO ppi;
						if(GetPointerPenInfo(pointerId, &ppi)) {
							pen = true;
							if(ppi.penFlags & PEN_FLAG_BARREL)
								pen_barrel = true;
							if(ppi.penFlags & PEN_FLAG_INVERTED)
								pen_inverted = true;
							if(ppi.penFlags & PEN_FLAG_ERASER)
								pen_eraser = true;
							if(ppi.penMask & PEN_MASK_PRESSURE)
								pen_pressure = ppi.pressure / 1024.0;
							if(ppi.penMask & PEN_MASK_ROTATION)
								pen_rotation = ppi.rotation * M_2PI / 360;
							if(ppi.penMask & PEN_MASK_TILT_X)
								pen_tilt.x = ppi.tiltX * M_2PI / 360;
							if(ppi.penMask & PEN_MASK_TILT_Y)
								pen_tilt.y = ppi.tiltY * M_2PI / 360;
							
						}
						break;
					}
					case PT_TOUCH:{
						POINTER_TOUCH_INFO pti;
						if(GetPointerTouchInfo(pointerId, &pti)) {
							// Add something touch specific here some day maybe...
						}
						break;
					}
					default:{
						POINTER_INFO pi;
						if(GetPointerInfo(pointerId, &pi)) {
						}
						break;
					}
				}

				if(_this) switch(message){
					case WM_POINTERDOWN:
						ClickActivateWnd();
						DoMouse(LEFTDOWN, Point(p), 0);
						PostInput();
						break;
					case WM_POINTERUP:
						DoMouse(LEFTUP, Point(p), 0);
						PostInput();
						break;
					case WM_POINTERUPDATE:
						DoMouse(MOUSEMOVE, Point(p));
						DoCursorShape();
						break;
				}
				
			}
		}
		break;
	case WM_POINTERLEAVE:
		pen = false;
		break;
...

	case WM_LBUTTONDOWN:
		if(disableOldWMs) break;
...

	case WM_LBUTTONUP:
		if(disableOldWMs) break;
...

	case WM_MOUSEMOVE:
		if(disableOldWMs) break;



Without native POINTER sources, this one should use the original code all the way, I hope...

Best regards,

Tom
Re: Using Pen with U++ [message #56430 is a reply to message #56423] Thu, 11 March 2021 11:21 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 14291
Registered: November 2005
Ultimate Member
So I have some bad news, even if somewhat funny news:

With your code, it starts drawing those nasty initial lines with my XP-PEN... Sad Very Happy

[Updated on: Thu, 11 March 2021 11:22]

Report message to a moderator

Re: Using Pen with U++ [message #56431 is a reply to message #56430] Thu, 11 March 2021 11:53 Go to previous messageGo to next message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
Laughing

OK, if I add this to the beginning of WindowProc():
	switch(message) {
		case WM_POINTERDOWN:
			RLOG("WM_POINTERDOWN");
			break;
		case WM_POINTERUPDATE:
			RLOG("WM_POINTERUPDATE");
			break;
		case WM_POINTERUP:
			RLOG("WM_POINTERUP");
			break;
		case WM_MOUSEMOVE:
			RLOG("WM_MOUSEMOVE");
			break;
		case WM_LBUTTONUP:
			RLOG("WM_LBUTTONUP");
			break;
		case WM_LBUTTONDOWN:
			RLOG("WM_LBUTTONDOWN");
			break;
	}


I will get this sequence for drawing one line:

...
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_POINTERDOWN
WM_POINTERUPDATE
WM_POINTERUPDATE
...
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_LBUTTONDOWN
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
...
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_POINTERUP
WM_MOUSEMOVE
WM_LBUTTONUP
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_MOUSEMOVE
...


How about you?

Best regards,

Tom
Re: Using Pen with U++ [message #56433 is a reply to message #56431] Thu, 11 March 2021 14:16 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 14291
Registered: November 2005
Ultimate Member
Added some log to the testing code too.

	virtual void LeftDown(Point p, dword)
	{
		if(IsPointerPen()) {
			DLOG("Start line");
			drawing.Add().Add(MakeTuple(GetPenPressure(), p));
		}
		Refresh();
	}

	virtual void MouseMove(Point p, dword keyflags) {
		pos = p;
		if(IsPointerPen() && drawing.GetCount()) {
			DLOG("Drawing line, pressure: " << GetPenPressure());
			drawing.Top().Add(MakeTuple(GetPenPressure(), p));
		}
		Refresh();
	}


WM_MOUSEMOVE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_POINTERDOWN
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_LBUTTONDOWN
Start line
WM_MOUSEMOVE
Drawing line, pressure: 0.109375
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.12890625
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.1318359375
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.1337890625
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.1435546875
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.14453125
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.150390625
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.1689453125
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.1767578125
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.205078125
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.220703125
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.2421875
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.24609375
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.2578125
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.2607421875
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.2607421875
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.2607421875
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.2578125
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.2578125
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.2548828125
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.25390625
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.2548828125
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.2548828125
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.267578125
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.2666015625
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.2666015625
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.2685546875
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.267578125
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.267578125
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.267578125
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.26953125
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.2705078125
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.2705078125
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.271484375
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.1015625
WM_POINTERUPDATE
WM_POINTERUP
WM_LBUTTONUP
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_MOUSEMOVE
WM_MOUSEMOVE
WM_MOUSEMOVE
WM_MOUSEMOVE
WM_MOUSEMOVE
WM_MOUSEMOVE


Looking at it, maybe the problem is actually in testing code, at least partially? (drawing line continues after mouseup).

Also note that I am not getting any other WM_POINTER message than UPDATE....

P.S.: Why RLOG? Do you want to forget it in the code? Smile

[Updated on: Thu, 11 March 2021 14:17]

Report message to a moderator

Re: Using Pen with U++ [message #56434 is a reply to message #56433] Thu, 11 March 2021 14:41 Go to previous messageGo to next message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
Actually you do get those WM_POINTERDOWN and WM_POINTERUP. From your log:
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_POINTERDOWN   <<< HERE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_LBUTTONDOWN
Start line
WM_MOUSEMOVE
Drawing line, pressure: 0.109375
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.12890625

...

WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.271484375
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0.1015625
WM_POINTERUPDATE
WM_POINTERUP     <<< HERE
WM_LBUTTONUP
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0
WM_POINTERUPDATE
WM_MOUSEMOVE
Drawing line, pressure: 0
WM_POINTERUPDATE
WM_MOUSEMOVE


What I find strange is that in the end, where you (I guess) take over with mouse, you do not get WM_POINTERUPDATEs. This suggests that the EnableMouseInPointer() is not working for you. Also, all your drawing takes place after WM_MOUSEMOVE and not WM_POINTERUPDATE, for some reason...

It is no wonder the drawing continues at zero width after mouse up, since there is no code for LeftUp to stop it.

Well, my RLOGs... I just use DEBUG mode only after getting in deep trouble... Smile

Best regards,

Tom
Re: Using Pen with U++ [message #56435 is a reply to message #56434] Thu, 11 March 2021 14:54 Go to previous messageGo to next message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
OK, here's a fix for the testing code:
#include <CtrlLib/CtrlLib.h>

using namespace Upp;

struct MyApp : TopWindow {
	Point pos;
	
	Vector<Vector<Tuple<double, Pointf>>> drawing;

	bool pendown;
	
	MyApp(){
		pendown=false;
	}
	
	virtual void LeftUp(Point p, dword)
	{
		if(IsPointerPen()) {
			DLOG("End line");
			pendown=false;
		}
		Refresh();
	}
	
	virtual void LeftDown(Point p, dword)
	{
		if(IsPointerPen()) {
			DLOG("Start line");
			pendown=true;
			drawing.Add().Add(MakeTuple(GetPenPressure(), p));
		}
		Refresh();
	}

	virtual void MouseMove(Point p, dword keyflags) {
		pos = p;
		if(IsPointerPen() && drawing.GetCount() && pendown) {
			DLOG("Drawing line, pressure: " << GetPenPressure());
			drawing.Top().Add(MakeTuple(GetPenPressure(), p));
		}
		Refresh();
	}
	
	virtual void Paint(Draw& w0)
	{
		DrawPainter w(w0, GetSize());
		w.Clear(SColorPaper());
		
		w.LineCap(LINECAP_ROUND);
		for(const auto& stroke : drawing)
			if(stroke.GetCount())
				for(int i = 0; i < stroke.GetCount() - 1; i++) {
					w.Move(stroke[i].b);
					w.Line(stroke[i + 1].b);
					w.Stroke(DPI(20) * stroke[i].a, Black());
				}
		
		int fcy = GetStdFontCy();
		int y = 10;
		auto Text = [&] (const String& text) {
			w.DrawText(10, y, text);
			y += fcy;
		};
		Text(AsString(pos));
		Text(String() << "Pen: " << IsPointerPen());
		Text(String() << "Pressure: " << GetPenPressure());
		Text(String() << "Rotation: " << GetPenRotation());
		Text(String() << "Tilt: " << GetPenTilt());
		Text(String() << "Barrel: " << IsPenBarrelPressed());
		Text(String() << "Inverted: " << IsPenInverted());
		Text(String() << "Eraser: " << IsPenEraserPressed()); // FIXED to IsPenEraserPressed()
		//Refresh(); // REMOVED
	}
};

GUI_APP_MAIN
{
	MyApp().Run();
}


And results for single line draw:

WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERDOWN
Start line
WM_POINTERUPDATE
Drawing line, pressure: 0.107421875
WM_POINTERUPDATE
Drawing line, pressure: 0.154296875
WM_POINTERUPDATE
Drawing line, pressure: 0.205078125
WM_POINTERUPDATE
Drawing line, pressure: 0.2255859375
WM_POINTERUPDATE
Drawing line, pressure: 0.2255859375
WM_POINTERUPDATE
Drawing line, pressure: 0.2255859375
WM_POINTERUPDATE
Drawing line, pressure: 0.228515625
WM_POINTERUPDATE
Drawing line, pressure: 0.2451171875
WM_POINTERUPDATE
Drawing line, pressure: 0.2451171875
WM_MOUSEMOVE
WM_LBUTTONDOWN
WM_MOUSEMOVE
WM_POINTERUPDATE
Drawing line, pressure: 0.244140625
WM_MOUSEMOVE
WM_POINTERUPDATE
Drawing line, pressure: 0.263671875
WM_MOUSEMOVE
WM_POINTERUPDATE
Drawing line, pressure: 0.2802734375
WM_MOUSEMOVE
WM_POINTERUPDATE
Drawing line, pressure: 0.29296875
WM_MOUSEMOVE
WM_POINTERUPDATE
Drawing line, pressure: 0.3056640625
WM_MOUSEMOVE
WM_POINTERUPDATE
Drawing line, pressure: 0.3193359375

...

Drawing line, pressure: 0.4169921875
WM_MOUSEMOVE
WM_POINTERUPDATE
Drawing line, pressure: 0.4052734375
WM_MOUSEMOVE
WM_POINTERUPDATE
Drawing line, pressure: 0.37890625
WM_MOUSEMOVE
WM_POINTERUPDATE
Drawing line, pressure: 0.365234375
WM_MOUSEMOVE
WM_POINTERUPDATE
Drawing line, pressure: 0.3359375
WM_MOUSEMOVE
WM_POINTERUPDATE
Drawing line, pressure: 0.0625
WM_MOUSEMOVE
WM_POINTERUP
End line
WM_LBUTTONUP
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_MOUSEMOVE
WM_POINTERUPDATE
WM_MOUSEMOVE


Best regards,

Tom
Re: Using Pen with U++ [message #56436 is a reply to message #56435] Thu, 11 March 2021 16:26 Go to previous messageGo to next message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
Hi,

This change fixes some tails when drawing fast. (This actually brings in your original 'ignoreclick' code and more.)

	static bool disableOldWMs=false; // When true, blocks out original WM_MOUSEMOVE, WM_LBUTTONUP, WM_LBUTTONDOWN
		
	switch(message) {
	case WM_POINTERDOWN:
	case WM_POINTERUPDATE:
	case WM_POINTERUP:
		{

			POINT p = Point((LONG)lParam);
			ScreenToClient(hwnd, &p);

			pen = false;
			pen_pressure = pen_rotation = Null;
			pen_tilt = Null;
			pen_eraser = false;
			pen_barrel = false;
			pen_inverted = false;
			
			static BOOL (WINAPI *EnableMouseInPointer)(BOOL fEnable);
			static BOOL (WINAPI *GetPointerType)(UINT32 pointerId, POINTER_INPUT_TYPE *pointerType);
			static BOOL (WINAPI *GetPointerInfo)(UINT32 pointerId, POINTER_INFO *pointerInfo);
			static BOOL (WINAPI *GetPointerPenInfo)(UINT32 pointerId, POINTER_PEN_INFO *penInfo);
			static BOOL (WINAPI *GetPointerTouchInfo)(UINT32 pointerId, POINTER_TOUCH_INFO *touchInfo);

			ONCELOCK {
				DllFn(EnableMouseInPointer, "User32.dll", "EnableMouseInPointer");
				if(EnableMouseInPointer && EnableMouseInPointer(true)) disableOldWMs=true; // Switching over to WM_POINTER* functions for mouse
				
				DllFn(GetPointerType, "User32.dll", "GetPointerType");
				DllFn(GetPointerInfo, "User32.dll", "GetPointerInfo");
				DllFn(GetPointerPenInfo, "User32.dll", "GetPointerPenInfo");
				DllFn(GetPointerTouchInfo, "User32.dll", "GetPointerTouchInfo");
			};
			
			POINTER_INPUT_TYPE pointerType;
			

			UINT32 pointerId = GET_POINTERID_WPARAM(wParam);
			if(GetPointerType && GetPointerType(pointerId, &pointerType)) {
				switch(pointerType){
					case PT_PEN:{
						POINTER_PEN_INFO ppi;
						if(GetPointerPenInfo && GetPointerPenInfo(pointerId, &ppi)) {
							pen = true;
							if(ppi.penFlags & PEN_FLAG_BARREL)
								pen_barrel = true;
							if(ppi.penFlags & PEN_FLAG_INVERTED)
								pen_inverted = true;
							if(ppi.penFlags & PEN_FLAG_ERASER)
								pen_eraser = true;
							if(ppi.penMask & PEN_MASK_PRESSURE)
								pen_pressure = ppi.pressure / 1024.0;
							if(ppi.penMask & PEN_MASK_ROTATION)
								pen_rotation = ppi.rotation * M_2PI / 360;
							if(ppi.penMask & PEN_MASK_TILT_X)
								pen_tilt.x = ppi.tiltX * M_2PI / 360;
							if(ppi.penMask & PEN_MASK_TILT_Y)
								pen_tilt.y = ppi.tiltY * M_2PI / 360;
							
						}
						break;
					}
					case PT_TOUCH:{
						POINTER_TOUCH_INFO pti;
						if(GetPointerTouchInfo && GetPointerTouchInfo(pointerId, &pti)) {
							// Add something touch specific here some day maybe...
						}
						break;
					}
					default:{
						POINTER_INFO pi;
						if(GetPointerInfo && GetPointerInfo(pointerId, &pi)) {
						}
						break;
					}
				}

				switch(message){
					case WM_POINTERDOWN:
						ClickActivateWnd();
						if(ignoreclick) return 0L;
						DoMouse(LEFTDOWN, Point(p), 0);
						if(_this) PostInput();
						break;
					case WM_POINTERUP:
						if(ignoreclick) EndIgnore();
						else DoMouse(LEFTUP, Point(p), 0);
						if(_this) PostInput();
						break;
					case WM_POINTERUPDATE:
						if(ignoreclick) {
							EndIgnore();
							return 0L;
						}
						if(_this) DoMouse(MOUSEMOVE, Point(p));
						DoCursorShape();
						break;
						
				}
				return 0L;
			}
		}
		break;
	case WM_POINTERLEAVE:
		pen = false;
		break;



The 'if(disableOldWMs) break;' are still needed in WM_MOUSEMOVE, WM_LBUTTONUP, WM_LBUTTONDOWN.

Does this work for you?

Best regards,

Tom

[Updated on: Thu, 11 March 2021 16:41]

Report message to a moderator

Re: Using Pen with U++ [message #56438 is a reply to message #56436] Fri, 12 March 2021 09:37 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 14291
Registered: November 2005
Ultimate Member
It seems to work, however I feel pretty uneasy that it is handling just LBUTTON messages and leaves the rest to "old" WMs. What about right button and double-clicks? Documentation is pretty sparse there....

If I understand you right, buttons are not a problem with Wacom, just mousemove messages. Maybe we could be more conservative, leave old messages, issue WM_MOUSEMOVE on POINTERUPDATE and solve the problem by ignoring duplicit messages (store screen hwnd and position, only issue mousemove if it changes...)?

Mirek
Re: Using Pen with U++ [message #56439 is a reply to message #56438] Fri, 12 March 2021 09:52 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 14291
Registered: November 2005
Ultimate Member
Or, maybe, just forget about MouseMove and add a new virtual method? E.g.

virtual Pen(Point pos, double pressure, double rotation, Pointf tilt, dword flags);

which would simply be updated on WM_POINTERUPDATE....
Re: Using Pen with U++ [message #56440 is a reply to message #56439] Fri, 12 March 2021 10:18 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 14291
Registered: November 2005
Ultimate Member
BTW, what do you get with

DDUMPHEX(GetMessageExtraInfo());

It looks like that 0xff515704 indicates pen for "old" WM messages, which could be useful in some context...

https://stackoverflow.com/questions/29857587/detect-if-wm-mo usemove-is-caused-by-touch-pen

Mirek
Re: Using Pen with U++ [message #56441 is a reply to message #56438] Fri, 12 March 2021 10:26 Go to previous messageGo to next message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
Hi,

WM_LBUTTONDOWN comes in late with Wacom, so it needs to be caught with WM_POINTERDOWN. WM_MOUSEMOVEs are also missing in the beginning of draw, so WM_POINTERUPDATE needs to replace WM_MOUSEMOVE there.

The only way (I can see) to properly handle each pointing device when more than one exist, is taking the full control of moves and left button to WM_POINTER* messages.

I think that we should aim for the Pen to work in place of a mouse as logically and cleanly as possible without any changes to the final application. I'm thinking of people using pen with U++ applications without specific pen support. Their experience should not suffer.

Only when pressure/tilt/rotation are beneficial for the application, then additional calls should be placed to acquire their values.

If I understand it correctly, the RBUTTON and DOUBLECLICKS are not part of WM_POINTER* message family. Anyway, at least RBUTTON works through the old messages. I have not tried doubleclicking yet... I'll do it after I get back to my tablet later in the afternoon.

Best regards,

Tom
Re: Using Pen with U++ [message #56442 is a reply to message #56440] Fri, 12 March 2021 10:28 Go to previous messageGo to next message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
mirek wrote on Fri, 12 March 2021 11:18
BTW, what do you get with

DDUMPHEX(GetMessageExtraInfo());

It looks like that 0xff515704 indicates pen for "old" WM messages, which could be useful in some context...

https://stackoverflow.com/questions/29857587/detect-if-wm-mo usemove-is-caused-by-touch-pen

Mirek


I'll need to check this when I get to my tablet...

You're moving fast! Just cannot keep up writing my replies... Smile

Best regards,

Tom
Re: Using Pen with U++ [message #56443 is a reply to message #56442] Fri, 12 March 2021 11:56 Go to previous messageGo to next message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
Tom1 wrote on Fri, 12 March 2021 11:28
mirek wrote on Fri, 12 March 2021 11:18
BTW, what do you get with

DDUMPHEX(GetMessageExtraInfo());

It looks like that 0xff515704 indicates pen for "old" WM messages, which could be useful in some context...

https://stackoverflow.com/questions/29857587/detect-if-wm-mo usemove-is-caused-by-touch-pen

Mirek


I'll need to check this when I get to my tablet...

You're moving fast! Just cannot keep up writing my replies... Smile

Best regards,

Tom


It's
GetMessageExtraInfo() = 0x0
all the way for WM_POINTER*, WM_MOUSEMOVE, WM_LBUTTONUP, WM_LBUTTONDOWN...

Best regards,

Tom
Re: Using Pen with U++ [message #56444 is a reply to message #56443] Fri, 12 March 2021 12:35 Go to previous messageGo to next message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
Hi,

It seems, when the pen is moving fast, Windows filters out part of the intermediate pen positions. Therefore, processing GetPointerPenInfoHistory() improves drawing quality especially at higher pen speeds:

	static bool disableOldWMs=false; // When true, blocks out original WM_MOUSEMOVE, WM_LBUTTONUP, WM_LBUTTONDOWN
		
	switch(message) {
	case WM_POINTERDOWN:
	case WM_POINTERUPDATE:
	case WM_POINTERUP:
		{

			POINT p = Point((LONG)lParam);
			ScreenToClient(hwnd, &p);

			pen = false;
			pen_pressure = pen_rotation = Null;
			pen_tilt = Null;
			pen_eraser = false;
			pen_barrel = false;
			pen_inverted = false;
			
			static BOOL (WINAPI *EnableMouseInPointer)(BOOL fEnable);
			static BOOL (WINAPI *GetPointerType)(UINT32 pointerId, POINTER_INPUT_TYPE *pointerType);
			static BOOL (WINAPI *GetPointerInfo)(UINT32 pointerId, POINTER_INFO *pointerInfo);
			static BOOL (WINAPI *GetPointerPenInfo)(UINT32 pointerId, POINTER_PEN_INFO *penInfo);
			static BOOL (WINAPI *GetPointerTouchInfo)(UINT32 pointerId, POINTER_TOUCH_INFO *touchInfo);
			static BOOL (WINAPI *GetPointerPenInfoHistory)(UINT32 pointerId, UINT32 *entriesCount, POINTER_PEN_INFO *penInfo);

			ONCELOCK {
				DllFn(EnableMouseInPointer, "User32.dll", "EnableMouseInPointer");
				if(EnableMouseInPointer && EnableMouseInPointer(true)) disableOldWMs=true; // Switching over to WM_POINTER* functions for mouse
				
				DllFn(GetPointerType, "User32.dll", "GetPointerType");
				DllFn(GetPointerInfo, "User32.dll", "GetPointerInfo");
				DllFn(GetPointerPenInfo, "User32.dll", "GetPointerPenInfo");
				DllFn(GetPointerTouchInfo, "User32.dll", "GetPointerTouchInfo");

				DllFn(GetPointerPenInfoHistory, "User32.dll", "GetPointerPenInfoHistory");
			};
			
			POINTER_INPUT_TYPE pointerType;
			

			UINT32 pointerId = GET_POINTERID_WPARAM(wParam);
			if(GetPointerType && GetPointerType(pointerId, &pointerType)) {
				switch(pointerType){
					case PT_PEN:{
						
						UINT32 hc=256;
						POINTER_PEN_INFO ppit[hc];
						if(message==WM_POINTERUPDATE && GetPointerPenInfoHistory && GetPointerPenInfoHistory(pointerId, &hc, ppit)) {
							for(int i=hc-1;i>=0;i--){
								pen = true;
								if(ppit[i].penFlags & PEN_FLAG_BARREL)
									pen_barrel = true;
								if(ppit[i].penFlags & PEN_FLAG_INVERTED)
									pen_inverted = true;
								if(ppit[i].penFlags & PEN_FLAG_ERASER)
									pen_eraser = true;
								if(ppit[i].penMask & PEN_MASK_PRESSURE)
									pen_pressure = ppit[i].pressure / 1024.0;
								if(ppit[i].penMask & PEN_MASK_ROTATION)
									pen_rotation = ppit[i].rotation * M_2PI / 360;
								if(ppit[i].penMask & PEN_MASK_TILT_X)
									pen_tilt.x = ppit[i].tiltX * M_2PI / 360;
								if(ppit[i].penMask & PEN_MASK_TILT_Y)
									pen_tilt.y = ppit[i].tiltY * M_2PI / 360;
								
								POINT hp = ppit[i].pointerInfo.ptPixelLocation;
								ScreenToClient(hwnd, &hp);
	
								if(ignoreclick) {
									EndIgnore();
									return 0L;
								}
								if(_this) DoMouse(MOUSEMOVE, Point(hp));
								DoCursorShape();
								
							}
							return 0L;
						}
	
						POINTER_PEN_INFO ppi;
						if(GetPointerPenInfo && GetPointerPenInfo(pointerId, &ppi)) {
							if(ppi.pointerInfo.historyCount){
							}
								
							pen = true;
							if(ppi.penFlags & PEN_FLAG_BARREL)
								pen_barrel = true;
							if(ppi.penFlags & PEN_FLAG_INVERTED)
								pen_inverted = true;
							if(ppi.penFlags & PEN_FLAG_ERASER)
								pen_eraser = true;
							if(ppi.penMask & PEN_MASK_PRESSURE)
								pen_pressure = ppi.pressure / 1024.0;
							if(ppi.penMask & PEN_MASK_ROTATION)
								pen_rotation = ppi.rotation * M_2PI / 360;
							if(ppi.penMask & PEN_MASK_TILT_X)
								pen_tilt.x = ppi.tiltX * M_2PI / 360;
							if(ppi.penMask & PEN_MASK_TILT_Y)
								pen_tilt.y = ppi.tiltY * M_2PI / 360;
						}
						break;
					}
					case PT_TOUCH:{
						POINTER_TOUCH_INFO pti;
						if(GetPointerTouchInfo && GetPointerTouchInfo(pointerId, &pti)) {
							// Add something touch specific here some day maybe...
						}
						break;
					}
/*					default:{
						POINTER_INFO pi;
						if(GetPointerInfo && GetPointerInfo(pointerId, &pi)) {
						}
						break;
					}
*/				}

				switch(message){
					case WM_POINTERDOWN:
						ClickActivateWnd();
						if(ignoreclick) return 0L;
						DoMouse(LEFTDOWN, Point(p), 0);
						if(_this) PostInput();
						break;
					case WM_POINTERUP:
						if(ignoreclick) EndIgnore();
						else DoMouse(LEFTUP, Point(p), 0);
						if(_this) PostInput();
						break;
					case WM_POINTERUPDATE:
						if(ignoreclick) {
							EndIgnore();
							return 0L;
						}
						if(_this) DoMouse(MOUSEMOVE, Point(p));
						DoCursorShape();
						break;
						
				}
				return 0L;
			}
		}
		break;
	case WM_POINTERLEAVE:
		pen = false;
		break;
...


Best regards,

Tom
Re: Using Pen with U++ [message #56446 is a reply to message #56444] Fri, 12 March 2021 17:50 Go to previous messageGo to next message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
OK, now I checked LeftDouble(), RightDouble(), RightUp()... and NONE of them works with the above code.

Need to think more...

Best regards,

Tom

EDIT: I'm starting to believe that if WM_POINTER* is used for mouse, it needs processing WM_POINTERUP and WM_POINTERDOWN in a way that checks IS_POINTER_FIRSTBUTTON_WPARAM(wParam), IS_POINTER_SECONDBUTTON_WPARAM(wParam) and so on to detect WM_LBUTTONUP/DOWN and WM_RBUTTONUP/DOWN and others correctly. Seems a bit complex to me. And still DOUBLECLICKs are a mystery.

[Updated on: Fri, 12 March 2021 18:05]

Report message to a moderator

Re: Using Pen with U++ [message #56447 is a reply to message #56446] Fri, 12 March 2021 18:32 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 14291
Registered: November 2005
Ultimate Member
Well, that is about what I expected.

The Pen virtual method seems more and more favorable solution.

Can you please test DDUMPHEX(GetMessageExtraInfo()); ? It would be really helpful in new API, which would use normal mouse, but put K_PEN into flags of Mouse messages... (because we WILL need to distinguish these).

Mirek
Re: Using Pen with U++ [message #56448 is a reply to message #56447] Fri, 12 March 2021 19:04 Go to previous messageGo to next message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
Hi,

GetMessageExtraInfo() returned always zero... Sad

(Reported this earlier.)

Best regards,

Tom
Re: Using Pen with U++ [message #56449 is a reply to message #56448] Fri, 12 March 2021 20:27 Go to previous messageGo to next message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
Mirek,

Can you test this:

	switch(message) {
	case WM_POINTERDOWN:
	case WM_POINTERUPDATE:
	case WM_POINTERUP:
		{

			POINT p = Point((LONG)lParam);
			ScreenToClient(hwnd, &p);

			pen = false;
			pen_pressure = pen_rotation = Null;
			pen_tilt = Null;
			pen_eraser = false;
			pen_barrel = false;
			pen_inverted = false;
			
			static BOOL (WINAPI *EnableMouseInPointer)(BOOL fEnable);
			static BOOL (WINAPI *GetPointerType)(UINT32 pointerId, POINTER_INPUT_TYPE *pointerType);
			static BOOL (WINAPI *GetPointerInfo)(UINT32 pointerId, POINTER_INFO *pointerInfo);
			static BOOL (WINAPI *GetPointerPenInfo)(UINT32 pointerId, POINTER_PEN_INFO *penInfo);
			static BOOL (WINAPI *GetPointerTouchInfo)(UINT32 pointerId, POINTER_TOUCH_INFO *touchInfo);
			static BOOL (WINAPI *GetPointerPenInfoHistory)(UINT32 pointerId, UINT32 *entriesCount, POINTER_PEN_INFO *penInfo);

			ONCELOCK {
				DllFn(GetPointerType, "User32.dll", "GetPointerType");
				DllFn(GetPointerInfo, "User32.dll", "GetPointerInfo");
				DllFn(GetPointerPenInfo, "User32.dll", "GetPointerPenInfo");
				DllFn(GetPointerTouchInfo, "User32.dll", "GetPointerTouchInfo");

				DllFn(GetPointerPenInfoHistory, "User32.dll", "GetPointerPenInfoHistory");
			};
			
			POINTER_INPUT_TYPE pointerType;
			

			UINT32 pointerId = GET_POINTERID_WPARAM(wParam);
			if(GetPointerType && GetPointerType(pointerId, &pointerType)) {
				switch(pointerType){
					case PT_PEN:{
						
						UINT32 hc=256;
						POINTER_PEN_INFO ppit[hc];
						if(message==WM_POINTERUPDATE && GetPointerPenInfoHistory && GetPointerPenInfoHistory(pointerId, &hc, ppit)) {
							for(int i=hc-1;i>=0;i--){
								pen = true;
								if(ppit[i].penFlags & PEN_FLAG_BARREL)
									pen_barrel = true;
								if(ppit[i].penFlags & PEN_FLAG_INVERTED)
									pen_inverted = true;
								if(ppit[i].penFlags & PEN_FLAG_ERASER)
									pen_eraser = true;
								if(ppit[i].penMask & PEN_MASK_PRESSURE)
									pen_pressure = ppit[i].pressure / 1024.0;
								if(ppit[i].penMask & PEN_MASK_ROTATION)
									pen_rotation = ppit[i].rotation * M_2PI / 360;
								if(ppit[i].penMask & PEN_MASK_TILT_X)
									pen_tilt.x = ppit[i].tiltX * M_2PI / 360;
								if(ppit[i].penMask & PEN_MASK_TILT_Y)
									pen_tilt.y = ppit[i].tiltY * M_2PI / 360;
								
								POINT hp = ppit[i].pointerInfo.ptPixelLocation;
								ScreenToClient(hwnd, &hp);
	
								if(ignoreclick) {
									EndIgnore();
									return 0L;
								}
								if(_this) DoMouse(MOUSEMOVE, Point(hp));
								DoCursorShape();
								
							}
							return 0L;
						}
	
						POINTER_PEN_INFO ppi;
						if(GetPointerPenInfo && GetPointerPenInfo(pointerId, &ppi)) {
							pen = true;
							if(ppi.penFlags & PEN_FLAG_BARREL)
								pen_barrel = true;
							if(ppi.penFlags & PEN_FLAG_INVERTED)
								pen_inverted = true;
							if(ppi.penFlags & PEN_FLAG_ERASER)
								pen_eraser = true;
							if(ppi.penMask & PEN_MASK_PRESSURE)
								pen_pressure = ppi.pressure / 1024.0;
							if(ppi.penMask & PEN_MASK_ROTATION)
								pen_rotation = ppi.rotation * M_2PI / 360;
							if(ppi.penMask & PEN_MASK_TILT_X)
								pen_tilt.x = ppi.tiltX * M_2PI / 360;
							if(ppi.penMask & PEN_MASK_TILT_Y)
								pen_tilt.y = ppi.tiltY * M_2PI / 360;
						}
						break;
					}
					case PT_TOUCH:{
						POINTER_TOUCH_INFO pti;
						if(GetPointerTouchInfo && GetPointerTouchInfo(pointerId, &pti)) {
							// Add something touch specific here some day maybe...
						}
						break;
					}
				}

				switch(message){
					case WM_POINTERDOWN:
						ClickActivateWnd();
						if(ignoreclick) return 0L;
						DoMouse(LEFTDOWN, Point(p), 0);
						if(_this) PostInput();
						break;
					case WM_POINTERUP:
						if(ignoreclick) EndIgnore();
						else DoMouse(LEFTUP, Point(p), 0);
						if(_this) PostInput();
						break;
					case WM_POINTERUPDATE:
						if(ignoreclick) {
							EndIgnore();
							return 0L;
						}
						if(_this) DoMouse(MOUSEMOVE, Point(p));
						DoCursorShape();
						break;
						
				}
				return 0L;
			}
		}
		break;
	case WM_POINTERLEAVE:
		pen = false;
		break;


No blocking of original WM_MOUSEMOVE, etc. required at all.

For some reason, with this code I do not get those WM_MOUSEMOVE messages for Pen, but only for mouse. Similarly, WM_POINTER... messages only appear for Pen.

Right clicks and double clicks work for mouse as before. So this is closest to a working solution so far.

Best regards,

Tom
Re: Using Pen with U++ [message #56452 is a reply to message #56449] Sat, 13 March 2021 12:42 Go to previous messageGo to next message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
Hi,

OK, now I found the reason why the original code produced both WM_MOUSEMOVEs and WM_POINTERUPDATEs for the pen moving: When case WM_POINTERUPDATE: exits with break; , it causes some emulation to result in WM_MOUSEMOVE. However, when WM_POINTERUPDATE exits with return 0L; , there will not be any WM_MOUSEMOVE and the two get processed separately and correctly.

This must be the reason why the latest code works.

Best regards,

Tom
Re: Using Pen with U++ [message #56453 is a reply to message #56449] Sat, 13 March 2021 14:19 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 14291
Registered: November 2005
Ultimate Member
Looks good, however, should you return immediately after processing the history?
Re: Using Pen with U++ [message #56454 is a reply to message #56453] Sat, 13 March 2021 14:39 Go to previous messageGo to next message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
mirek wrote on Sat, 13 March 2021 15:19
Looks good, however, should you return immediately after processing the history?


I think so, yes. History[0] contains the latest POINTERUPDATE, so everything gets processed this way.

Best regards,

Tom
Re: Using Pen with U++ [message #56456 is a reply to message #56454] Sat, 13 March 2021 15:07 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 14291
Registered: November 2005
Ultimate Member
OK, done some cleanup/deduplication, I think this might be final. Can you test?

And now important question: Does Wacom work with Linux? Smile

Mirek
Re: Using Pen with U++ [message #56457 is a reply to message #56454] Sat, 13 March 2021 15:10 Go to previous messageGo to next message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
... I'm just thinking about the situation, where an application written with U++ has not been specifically designed to support pen: I think that the barrel button should be mapped to the right mouse button in U++ -- as is the default Windows pen behavior, I think. This (and maybe some other things) should give a reasonable pen experience without any special work on the application itself.

The default pen behavior can be seen in:

https://docs.microsoft.com/en-us/previous-versions/windows/d esktop/inputmsg/wm-pointerdown

Look specifically at IS_POINTER_FIRSTBUTTON_WPARAM(wParam) and IS_POINTER_SECONDBUTTON_WPARAM(wParam)...

Best regards,

Tom

Re: Using Pen with U++ [message #56458 is a reply to message #56456] Sat, 13 March 2021 15:20 Go to previous messageGo to previous message
Tom1
Messages: 1319
Registered: March 2007
Ultimate Contributor
mirek wrote on Sat, 13 March 2021 16:07
OK, done some cleanup/deduplication, I think this might be final. Can you test?

And now important question: Does Wacom work with Linux? Smile

Mirek


Yes, it works just great! Nice cleanup too.

You can remove this too:

static BOOL (WINAPI *EnableMouseInPointer)(BOOL fEnable);


Tracking pen_history is a mystery to me, though... Any reason for that?

Currently my linux is on the virtual machine on top of windows... It does not see pen operations directly. I need to check if I can reconnect the wacom directly to the VM...

Best regards,

Tom

EDIT: A quick search says it should work after installing some X wacom drivers...

[Updated on: Sat, 13 March 2021 15:23]

Report message to a moderator

Previous Topic: WString vs Grapheme Cluster idea (with possible flaw)
Next Topic: .gitignore
Goto Forum:
  


Current Time: Fri May 15 22:46:31 GMT+2 2026

Total time taken to generate the page: 0.01252 seconds