CapsLock(), InsMode() , NumLock()

This forum is meant for questions about the Visual FoxPro Language support in X#.

Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am

CapsLock(), InsMode() , NumLock()

Post by Karl-Heinz »

Guys,

i'm looking at the mentioned VFP functions. The help description doesn' t give an answer, but after looking at some VFP sites it seems that these funcs change the global input state, and not the input state of the calling thread only. Is that correct ?

regards
Karl-Heinz
atlopes
Posts: 83
Joined: Sat Sep 07, 2019 11:43 am

CapsLock(), InsMode() , NumLock()

Post by atlopes »

Karl-Heinz, the functions CAPSLOCK() and NUMLOCK() set the global state. As for the INSMODE() function, I assume "yes," also, but I'm not quite sure of that.
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am

CapsLock(), InsMode() , NumLock()

Post by Karl-Heinz »

Hi Antonio,

The insert mode is a special beast. Notepad ignores the setting and Winword seems to have its own on/off insert implementation. But it works in a VO/X# window if the edit control uses the OVERWRITE_ONKEY setting.

The attached file is a XIDE viaef. When you look at the Keyboard.prg you'll see that most of the code is encapsulated in the internal class win32, and that GetKeyState() and SendInput() is used to toggle the Capslock, Insert or Num key. Currently there are two unused structures (winHardwareInput and winMouseInput ) included. i'll deactvate or remove them later. As long as the XIDE checkbox '[x] Define debug' is checked you can see in the console when a switch occurs. Later on, i'll also remove the '#ifdef DEBUG ... #endif' code.

Don't be surprised how you have to leave the console window :-) , otherwise its not possible to run the app as a exe. I noticed that a simple 'wait' instead of the 'do while .. enddo' automatically quits the exe. This does not happen if all InsMode() calls are deactivated .... very strange.

Give it a try and let me know how it goes.

regards
Karl-Heinz
Attachments

[The extension viaef has been deactivated and can no longer be displayed.]

User avatar
robert
Posts: 4225
Joined: Fri Aug 21, 2015 10:57 am
Location: Netherlands

CapsLock(), InsMode() , NumLock()

Post by robert »

Karl-Heinz
I think the only relevant thread for these values is the UI Thread. So this should be set globally.
Robert
XSharp Development Team
The Netherlands
robert@xsharp.eu
User avatar
robert
Posts: 4225
Joined: Fri Aug 21, 2015 10:57 am
Location: Netherlands

CapsLock(), InsMode() , NumLock()

Post by robert »

Karl-Heinz,
Is there a reason why you coded this to the Win32 API and did not use Control.isKeyLocked from System.Windows.Forms ?

Robert
XSharp Development Team
The Netherlands
robert@xsharp.eu
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am

CapsLock(), InsMode() , NumLock()

Post by Karl-Heinz »

robert wrote:Karl-Heinz,
Is there a reason why you coded this to the Win32 API and did not use Control.isKeyLocked from System.Windows.Forms ?

Robert
because of the System.Windows.Forms dependency, so from my understanding that doesn t help in a console app ? i also looked at this option:

Code: Select all

USING System.Windows.Input

// required Dll references:  Windowsbase , PresentationCore

FUNCTION KeysTest() AS VOID 
	
 // System.Windows.Input.xxx

 ? Keyboard.IsKeyToggled(Key.NumLock) 
 ? Keyboard.IsKeyToggled(Key.CapsLock)
 ? Keyboard.IsKeyToggled(Key.Insert)
 ? 
  
RETURN

When i get the time i'll take a closer look at the available options. Do you agree that both, windows form and console apps should be supported ?

regards
Karl-Heinz
User avatar
robert
Posts: 4225
Joined: Fri Aug 21, 2015 10:57 am
Location: Netherlands

CapsLock(), InsMode() , NumLock()

Post by robert »

Karl Heinz,
This is the (C#) code inside Control.IsKeyLocked

Code: Select all

public static bool IsKeyLocked(Keys keyVal)
{
	if (keyVal == Keys.Insert || keyVal == Keys.NumLock || keyVal == Keys.Capital || keyVal == Keys.Scroll)
	{
		int keyState = UnsafeNativeMethods.GetKeyState((int)keyVal);
		if (keyVal == Keys.Insert || keyVal == Keys.Capital)
		{
			return (keyState & 1) != 0;
		}
		return (keyState & 0x8001) != 0;
	}
	throw new NotSupportedException(SR.GetString("ControlIsKeyLockedNumCapsScrollLockKeysSupportedOnly"));
}
I think it does exactly what you did to read the state. But it does NOT change the state.
Maybe this code can be used to set the state:
https://stackoverflow.com/questions/136 ... s-lock-key
This does not need all the extra structures.

Robert
XSharp Development Team
The Netherlands
robert@xsharp.eu
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am

CapsLock(), InsMode() , NumLock()

Post by Karl-Heinz »

Hi Robert,

i'm aware of the keybd_event() function and it gives the same results as SendInput(). However, it is recommended to use SendInput() instead.

https://docs.microsoft.com/en-us/window ... eybd_event

regards
Karl-Heinz
User avatar
robert
Posts: 4225
Joined: Fri Aug 21, 2015 10:57 am
Location: Netherlands

CapsLock(), InsMode() , NumLock()

Post by robert »

Karl-Heinz,

Ok, I see. In that case you may want to consider to replace the InputUnion in the winInput structure with just the winKeyboardInput structure, since you are not using the MouseInput and the HardwareInput. That will make the code a bit smaller and easier to understand.
Of course you will have to a few dummy items to the structure because the MouseInput structure is larger (I think you would have to use 2 dummy LONG or DWORD items to get the same size).

Robert
XSharp Development Team
The Netherlands
robert@xsharp.eu
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am

CapsLock(), InsMode() , NumLock()

Post by Karl-Heinz »

Hi Robert;

the modified class now looks like

Code: Select all

INTERNAL CLASS Win32  

	CONST INTERNAL KEYEVENTF_KEYUP := 2 AS INT
	CONST INTERNAL VK_INSERT := 45 AS INT
	CONST INTERNAL VK_NUMLOCK := 144 AS INT
	CONST INTERNAL VK_CAPITAL := 20 AS INT 
    	CONST INTERNAL TYPE_KEYBOARD := 1 AS INT
    
		
	[DllImport("user32.dll", SetLastError := TRUE)] ;
	INTERNAL STATIC METHOD SendInput(nInputs AS DWORD , pInputs AS winInput[], cbSize AS LONG ) AS DWORD

	[DllImport("user32.dll", SetLastError := TRUE)] ;
	INTERNAL STATIC METHOD GetKeyState(nVirtkey AS INT) AS SHORTINT
		
	[StructLayout(LayoutKind.Sequential)];	
	INTERNAL STRUCTURE winKeyboardInput2
		INTERNAL wVk AS WORD 
		INTERNAL wScan AS WORD
		INTERNAL dwFlags AS DWORD
		INTERNAL time AS DWORD
		INTERNAL dwExtraInfo AS IntPtr
		INTERNAL Dummy1 AS DWORD  // <-----
		INTERNAL Dummy2 AS DWORD  // <-----		
	END STRUCTURE 		

	
	[StructLayout(LayoutKind.Sequential)] ;
	INTERNAL STRUCTURE winInput
		INTERNAL Type AS DWORD
		INTERNAL Input AS winKeyboardInput2 
	END STRUCTURE 

END CLASS 

What's still missing are the names i should use:
- name of the modified winKeyboardInput structure ? - currently winKeyboardInput2
- name of the 2 new members ? - currently dummy1 and dummy2

regards
Karl-Heinz
Post Reply