Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
Tablet class (Request For Tests)
Message
 
 
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:
01647483
Views:
69
Hi Antonio,

Do you need testing on Windows 10 tablet?

>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
>
"The creative process is nothing but a series of crises." Isaac Bashevis Singer
"My experience is that as soon as people are old enough to know better, they don't know anything at all." Oscar Wilde
"If a nation values anything more than freedom, it will lose its freedom; and the irony of it is that if it is comfort or money that it values more, it will lose that too." W.Somerset Maugham
Previous
Next
Reply
Map
View

Click here to load this message in the networking platform