Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
Tablet class (Request For Tests)
Message
From
12/10/2018 15:05:00
 
 
To
04/02/2017 11:29:57
General information
Forum:
Visual FoxPro
Category:
Tablet PC
Environment versions
Visual FoxPro:
VFP 9 SP2
Miscellaneous
Thread ID:
01647482
Message ID:
01662576
Views:
58
Thank you Antonio! I will look at that.

>I'm writing the basics of a VFP class to work with tablets. There is already some code out there to handle a few relevant tablet features, like ink input (https://msdn.microsoft.com/en-us/library/ms965060.aspx), and some interesting threads in this and other forums, especially covering application design.
>
>For the moment, the Tablet class is already answering some questions: is this a tablet? is the device working in desktop or tablet mode? how is the screen oriented, in landscape or portrait? did a change in these settings occurred (for instance, did the user rotate the device, or changed to tablet mode)?
>
>Now, as something for your weekend, I am asking for tests and comments because there are a few things that I'm not able to try, or because maybe I'm not taking the right approach to address the different issues. I never executed some of this code, but only assumed it would work based on info I gathered online.
>
>So, if you have a Windows 8 tablet, for example, it would be great to see if the class is holding or, on the contrary, if it fails. But you don't have to have a tablet to contribute to the testing: a Windows 10 desktop, for instance, can operate in tablet mode and have its screen rotated.
>
>The code of the class is not very big, for the moment, so I'll post it here inline. At the bottom, there is a tester program that can be ran to perform the actual tests, so that you won't need to code anything to run the tests: just Copy + Paste the two programs somewhere, and run the second.
>
>Any help with this will be highly appreciated and properly acknowledged.
>
>I hope that this sparks your interest, and that it will engage a fruitful discussion.
>
>1. Tablet.prg
>
>
>*
>* Tablet
>*
>* A utility class to assist in VFP tablet programming
>*
>* Properties:
>*		IsTablet - .T. if PC is a tablet
>*		TabletMode - .T. if running in tablet mode
>*		Orientation - "L" for landscape, "P" for portrait
>*
>* Methods:
>*		IsTabletModeOn() - .T. if running in tablet mode
>*
>* Events:
>*		OnTabletModeChange() - when user changes modes
>*		OnOrientationChange() - when user changes orientation
>*
>
>* Windows message identifiers
>#DEFINE WM_SETTINGCHANGE			0x001A
>#DEFINE WM_DISPLAYCHANGE			0x007E
>
>* For registry inspection
>#DEFINE HKEY_CURRENT_USER			0x80000001
>#DEFINE RRF_RT_DWORD					0x00000018
>
>* System metrics keys
>#DEFINE SM_CONVERTIBLESLATEMODE	0x2003
>#DEFINE SM_TABLETPC					86
>#DEFINE SM_CXFULLSCREEN				16
>#DEFINE SM_CYFULLSCREEN				17
>
>* load the class definition
>IF !SYS(16)$SET("Procedure")
>	SET PROCEDURE TO (SYS(16)) ADDITIVE
>ENDIF
>
>DEFINE CLASS Tablet AS Custom
>
>	HIDDEN OSVersion
>
>	IsTablet = .F.
>	TabletMode = .F.
>	Orientation = ""
>	OSVersion = 0
>
>	_memberdata = '<VFPData>' + ;
>						'<memberdata name="istablet" type="property" display="IsTablet"/>' + ;
>						'<memberdata name="istabletmodeon" type="method" display="IsTabletModeOn"/>' + ;
>						'<memberdata name="onorientationchange" type="method" display="OnOrientationChange"/>' + ;
>						'<memberdata name="ontabletmodechange" type="method" display="OnTabletModeChange"/>' + ;
>						'<memberdata name="orientation" type="property" display="Orientation"/>' + ;
>						'<memberdata name="tabletmode" type="property" display="TabletMode"/>' + ;
>						'</VFPData>'
>
>	FUNCTION Init
>
>		LOCAL WMIService, OperatingSystem
>
>		* declarations, we'll need these functions
>		DECLARE INTEGER GetSystemMetrics IN WIN32API INTEGER Metric
>		DECLARE INTEGER RegGetValue IN WIN32API ;
>			 INTEGER hkey, STRING lpSubKey, STRING lpValue, INTEGER dwFlags, INTEGER @ dwType, STRING @ pvData, INTEGER @ pcbData
>		DECLARE Sleep IN WIN32API INTEGER Milliseconds
>
>		* get the major OS version
>		m.WMIService = GETOBJECT("winmgmts:\\.\root\cimv2")
>		m.OperatingSystem = m.WMIService.InstancesOf("Win32_OperatingSystem").ItemIndex(0)
>		This.OSVersion = VAL(m.OperatingSystem.Version)
>
>		* check if PC is a tablet
>		TRY
>			This.IsTablet = GetSystemMetrics(SM_TABLETPC) != 0
>		CATCH
>			This.IsTablet = .F.
>		ENDTRY
>
>		* set screen orientation
>		This.Orientation = IIF(GetSystemMetrics(SM_CXFULLSCREEN) > GetSystemMetrics(SM_CYFULLSCREEN), "L", "P")
>
>		* set the tablet mode
>		This.IsTabletModeOn()
>	
>		* trap changes that may be broadcasted by Windows
>		BINDEVENT(_VFP.HWnd, WM_SETTINGCHANGE, This, "SystemChanged", 5)
>		BINDEVENT(_VFP.HWnd, WM_DISPLAYCHANGE, This, "SystemChanged", 5)
>
>	ENDFUNC
>	
>	FUNCTION Destroy
>	
>		* forget about all our event bindings
>		UNBINDEVENTS(This)
>	
>	ENDFUNC
>	
>	* when relevant display settings are changed, Windows broadcasts messages to all [top-form] windows
>	* messages are trapped by this method that, in turn, fires the public event
>	HIDDEN PROCEDURE SystemChanged (hWnd AS Integer, WindowsMessage AS Integer, Param1 AS Integer, Param2 AS Integer)
>	
>		LOCAL P2 AS String
>		LOCAL Previous
>		LOCAL Waiting AS Integer
>
>		DO CASE
>		CASE m.WindowsMessage = WM_DISPLAYCHANGE
>
>			m.Previous = This.Orientation
>			
>			* new values for Screen WxH comes in Param2
>			This.Orientation = IIF(m.Param2 % 0x10000 > INT(m.Param2 / 0x10000), "L", "P")
>			
>			* changed?
>			IF m.Previous != This.Orientation
>				
>				RAISEEVENT(This, "OnOrientationChange")
>			ENDIF
>	
>		CASE m.WindowsMessage = WM_SETTINGCHANGE
>
>			* try to fetch a string from Param2
>			TRY
>				m.P2 = STREXTRACT(SYS(2600, m.Param2, 255), "", CHR(0), 1, 2)
>			CATCH
>				m.P2 = ""
>			ENDTRY
>		
>			DO CASE
>			* pre-Windows 10 message for Tablet mode
>			CASE m.P2 == "ConvertibleSlateMode"
>
>				IF This.OSVersion < 10
>					m.Previous = This.TabletMode
>
>					* check tablet mode
>					This.IsTabletModeOn()
>
>					IF m.Previous != This.TabletMode
>						RAISEEVENT(This, "OnTabletModeChange")
>					ENDIF
>
>				ENDIF
>
>			* Windows 10 message for Tablet mode
>			CASE m.P2 == "UserInteractionMode"
>
>				IF This.OSVersion >= 10
>
>					m.Previous = This.TabletMode
>
>					This.IsTabletModeOn()
>					
>					m.Waiting = 250
>					
>					DO WHILE m.Previous = This.TabletMode AND m.Waiting <= 2000
>						* give some time to the system to do its work
>						Sleep(m.Waiting)
>						
>						m.Waiting = m.Waiting * 2
>
>						* check again
>						This.IsTabletModeOn()
>					ENDDO
>					
>					IF m.Previous != This.TabletMode
>						RAISEEVENT(This, "OnTabletModeChange")
>					ENDIF
>				ENDIF
>			ENDCASE
>		ENDCASE
>
>	ENDPROC
>	
>	* verify if the laptop/device is in tablet mode
>	FUNCTION IsTabletModeOn
>
>		* before Windows 10, get a system metric that holds the slate mode
>		IF This.OSVersion < 10
>
>			LOCAL SlateMode
>			
>			TRY
>				m.SlateMode = GetSystemMetrics(SM_CONVERTIBLESLATEMODE)
>			CATCH
>				m.SlateMode = 1
>			ENDTRY
>			
>			This.TabletMode = EMPTY(m.SlateMode)
>
>		* after Windows 10, inspect the registry				
>		ELSE
>
>			LOCAL BufferData AS String
>			LOCAL BufferLen AS Integer
>			LOCAL Zerro AS String
>
>			* check for the registry value
>			m.BufferLen = 4
>			m.Zero = REPLICATE(CHR(0), m.BufferLen)
>			m.BufferData = m.Zero
>
>			RegGetValue(HKEY_CURRENT_USER, ;
>						"SOFTWARE\Microsoft\Windows\CurrentVersion\ImmersiveShell", ;
>						"TabletMode", ;
>						RRF_RT_DWORD, ;
>						0, ;
>						@m.BufferData, ;
>						@m.BufferLen)
>
>			This.TabletMode = m.BufferData != m.Zero
>		ENDIF
>
>		RETURN This.TabletMode
>
>	ENDPROC
>
>	* events 
>	PROCEDURE OnTabletModeChange
>	ENDPROC
>
>	PROCEDURE OnOrientationChange
>	ENDPROC
>
>ENDDEFINE
>
>
>2. tester.prg
>
>
>SET DEFAULT TO (JUSTPATH(SYS(16)))
>
>* put the class definition in scope
>DO Tablet.prg
>
>* a simple error handler, just to help us debug this
>ON ERROR DO ShowError WITH PROGRAM(), LINENO(), MESSAGE(1), MESSAGE(), ERROR()
>
>* the testers: a form and an extended instance of the tablet class, just to output something when there are events 
>LOCAL tester AS TestForm
>LOCAL Controller AS TabletController
>
>m.Controller = CREATEOBJECT("TabletController")
>
>m.tester = CREATEOBJECT("TestForm")
>
>* set a reference to the form in a new property of the tablet class
>m.Controller.OutputForm = m.tester
>
>* display the initial status
>m.Controller.OnOrientationChange()
>m.Controller.OnTabletModeChange()
>
>IF m.Controller.IsTablet
>	m.tester.Caption = "Testing in a tablet"
>	* if it is a tablet, let the user handle orientation change
>	m.tester.cmdChangeDisplayOrientation.Enabled = .F.
>ELSE
>	m.tester.Caption = "Testing in a desktop / laptop"
>ENDIF
>
>* show things as they happen
>m.tester.Show()
>READ EVENTS
>
>ON ERROR
>
>DEFINE CLASS TestForm AS Form
>	ADD OBJECT cmdChangeDisplayOrientation AS CommandButton WITH Top = 10, Left = 10, Caption = "Change Orientation", AutoSize = .T.
>	ADD OBJECT lblTabletMode AS Label WITH Top = 40, Left = 10, AutoSize = .T., Caption = ""
>	ADD OBJECT lblDisplayOrientation AS Label WITH Top = 70, Left = 10, AutoSize = .T., Caption = ""
>
>	* how was the display orientated when we started
>	InitialOrientation = _Screen.DisplayOrientation
>
>	* cycle throuh the different orientations (pressing the space bar will be ok)
>	PROCEDURE cmdChangeDisplayOrientation.Click
>		_Screen.DisplayOrientation = IIF(_Screen.DisplayOrientation = 3,0,_Screen.DisplayOrientation + 1)
>	ENDPROC
>	
>	PROCEDURE Destroy
>		* reset to the initial orientation
>		IF This.cmdChangeDisplayOrientation.Enabled AND _Screen.DisplayOrientation != This.InitialOrientation
>			_Screen.DisplayOrientation = This.InitialOrientation
>		ENDIF
>		CLEAR EVENTS
>	ENDPROC
>
>ENDDEFINE
>
>* extend the class tablet, to react to events (just display the different states)
>DEFINE CLASS TabletController AS tablet
>
>	OutputForm = .NULL.
>
>	FUNCTION OnOrientationChange
>	
>		IF !ISNULL(This.OutputForm)
>			This.OutputForm.lblDisplayOrientation.Caption = ;
>				STREXTRACT("L:Landscape:P:Portrait", This.Orientation + ":",":",1,2)
>		ENDIF
>	
>	ENDFUNC
>
>	FUNCTION OnTabletModeChange
>		IF !ISNULL(This.OutputForm)
>			This.OutputForm.lblTabletMode.Caption = IIF(This.TabletMode,"Tablet mode","Desktop mode")
>		ENDIF
>	ENDFUNC
>
>ENDDEFINE
>
>PROCEDURE ShowError (ProgramName, LineNumber, Source, ErrorText, ErrorNumber)
>
>	MESSAGEBOX(m.ProgramName + ":" + TRANSFORM(m.LineNumber) + CHR(13) + ;
>					m.Source + CHR(13) + CHR(13) + ;
>					TRANSFORM(m.ErrorNumber) + ">" + m.ErrorText)
>	RETURN
>ENDPROC
>
*******************************************************
Save a tree, eat a beaver.
Denis Chassé
Previous
Reply
Map
View

Click here to load this message in the networking platform