I'm creating an on-screen keyboard at the moment to be integrated into an application intended for use on touch-screens. I haven't completed it yet and I'm not necessarily going to post the finished product, but here are the building blocks: a form and a button that will not receive focus. Just note that this behaviour applies to the client area of the form only. If the the user clicks the non-client area, i.e. the title bar and border, then the form will take the focus. This behaviour is just like the in-built Windows OSK.
vb.net Code:
''' <summary>
''' A button control that cannot receive focus.
''' </summary>
Public Class UnselectableButton
Inherits System.Windows.Forms.Button
#Region " Constructors "
''' <summary>
''' Initialises a new instance of the <see cref="UnselectableButton"/> class.
''' </summary>
Public Sub New()
MyBase.New()
'The button cannot receive focus.
Me.SetStyle(ControlStyles.Selectable, False)
End Sub
#End Region 'Constructors
#Region " Variables "
''' <summary>
''' Corresponds to the MA_NOACTIVATE window process reply.
''' </summary>
Private Shared ReadOnly noActivate As New IntPtr(NativeConstants.MA_NOACTIVATE)
#End Region 'Variables
#Region " Methods "
''' <summary>
''' Processes Windows messages.
''' </summary>
''' <remarks>
''' Informs Windows not to activate the window when it is clicked with the mouse. Note that this behaviour applies to the client area of the window only.
''' </remarks>
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
MyBase.WndProc(m)
If m.Msg = NativeConstants.WM_MOUSEACTIVATE Then
'Tell Windows not to activate the window on a mouse click.
m.Result = noActivate
End If
End Sub
Protected Overrides Sub OnClick(ByVal e As System.EventArgs)
MyBase.OnClick(e)
End Sub
#End Region 'Methods
End Class
Last edited by jmcilhinney; Oct 9th, 2007 at 03:34 AM.
Reason: Removed buggy form code. See post #3 for final code.
Hmmm... that form works within the current application but it messes up if you try to "type" into another application. I'll do some more research and post back when I have a solution.
''' If a child window has this style, clicking it does not cause its top-level parent to activate. Although a window that has this style will still receive mouse events, neither it nor its child windows can get the focus.
''' </remarks>
Public Const WS_EX_NOACTIVATE As Integer = &H8000000
''' <summary>
''' This message is sent when the cursor is in an inactive window and the user presses a mouse button.
''' </summary>
Public Const WM_MOUSEACTIVATE As Integer = &H21
''' <summary>
''' Does not activate the window, and does not discard the mouse message.
''' </summary>
''' <remarks>
''' This is one of the possible return values when the <see cref="WM_MOUSEACTIVATE"/> notification is received.
''' </remarks>
Public Const MA_NOACTIVATE As Integer = 3
''' <summary>
''' Displays a window in its most recent size and position. This value is similar to <b>SW_SHOWNORMAL</b>, except the window is not actived.
''' </summary>
''' <remarks>
''' This is one of the possible values for the <b>nCmdShow</b> argument of the <see cref="NativeMethods.ShowWindow">ShowWindow</see> method.
''' </remarks>
Public Const SW_SHOWNOACTIVATE As Integer = 4
End Class
Here is the ShowWindow declaration:
vb Code:
Imports System.Runtime.InteropServices
Friend NotInheritable Class NativeMethods
''' <summary>
''' This function sets the specified window's show state.
''' </summary>
''' <param name="hWnd">
''' Handle to the window.
''' </param>
''' <param name="nCmdShow">
''' <para>Specifies how the window is to be shown.</para>
''' <para>
''' This parameter can be one of the following values.
''' <b>SW_FORCEMINIMIZE</b>
''' Windows 2000/XP: Minimizes a window, even if the thread that owns the window is not responding. This flag should only be used when minimizing windows from a different thread.
''' <b>SW_HIDE</b>
''' Hides the window and activates another window.
''' <b>SW_MAXIMIZE</b>
''' Maximizes the specified window.
''' <b>SW_MINIMIZE</b>
''' Minimizes the specified window and activates the next top-level window in the Z order.
''' <b>SW_RESTORE</b>
''' Activates and displays the window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when restoring a minimized window.
''' <b>SW_SHOW</b>
''' Activates the window and displays it in its current size and position.
''' <b>SW_SHOWDEFAULT</b>
''' Sets the show state based on the SW_ value specified in the STARTUPINFO structure passed to the CreateProcess function by the program that started the application.
''' <b>SW_SHOWMAXIMIZED</b>
''' Activates the window and displays it as a maximized window.
''' <b>SW_SHOWMINIMIZED</b>
''' Activates the window and displays it as a minimized window.
''' <b>SW_SHOWMINNOACTIVE</b>
''' Displays the window as a minimized window. This value is similar to <b>SW_SHOWMINIMIZED</b>, except the window is not activated.
''' <b>SW_SHOWNA</b>
''' Displays the window in its current size and position. This value is similar to <b>SW_SHOW</b>, except the window is not activated.
''' Displays a window in its most recent size and position. This value is similar to <b>SW_SHOWNORMAL</b>, except the window is not actived.
''' <b>SW_SHOWNORMAL</b>
''' Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when displaying the window for the first time.
''' </para>
''' </param>
''' <returns>
''' True if the window was previously visible; otherwise, False.
''' </returns>
<DllImport("user32")> _
Public Shared Function ShowWindow(ByVal hWnd As IntPtr, ByVal nCmdShow As Integer) As Boolean
''' Represents a key on the keyboard that displays a different value if the Shift key is depressed.
''' </summary>
Friend Class DualValueKeyButton
Inherits ShiftableKeyButton
#Region " Variables "
''' <summary>
''' The text displayed on the button when the Shift key is depressed.
''' </summary>
Private _shiftText As String
''' <summary>
''' The text displayed on the button when the Shift key is released.
''' </summary>
Private standardText As String
#End Region 'Variables
#Region " Properties "
''' <summary>
''' Gets or sets the text that is displayed on the button when the Shift key is depressed.
''' </summary>
''' <value>
''' A <b>String</b> containing the button text when the Shift key is depressed.
''' </value>
<Category("Appearance"), _
Description("The text displayed on the button when the Shift key is depressed.")> _
Public Property ShiftText() As String
Get
Return Me._shiftText
End Get
Set(ByVal value As String)
Me._shiftText = value
End Set
End Property
#End Region 'Properties
#Region " Methods "
''' <summary>
''' Overridden. Sets the button text based on whether the Shift key is depressed.
''' </summary>
Protected Overrides Sub SetText()
If Me.Shift Then
If Me.Text <> Me._shiftText Then
'Remember the standard text and display the shift text.
Me.standardText = Me.Text
Me.Text = Me._shiftText
End If
Else
If Me.Text <> Me.standardText Then
'Restore the standard text.
Me.Text = Me.standardText
End If
End If
End Sub
#End Region 'Methods
End Class
vb.net Code:
''' <summary>
''' Represents a key on the keyboard that outputs a letter of the alphabet.
''' </summary>
Friend Class AlphabetKeyButton
Inherits ShiftableKeyButton
#Region " Variables "
''' <summary>
''' Indicates whether the Caps Lock key is depressed.
''' </summary>
Private _capsLock As Boolean
#End Region 'Variables
#Region " Properties "
''' <summary>
''' Sets a value indicating whether the Caps Lock key is depressed.
''' </summary>
''' <value>
''' <b>True</b> if the Caps Lock key is depressed and the button's behaviour should reflect that; otherwise, <b>False</b>.
''' </value>
Public WriteOnly Property CapsLock() As Boolean
Set(ByVal value As Boolean)
If Me._capsLock <> value Then
Me._capsLock = value
Me.SetText()
End If
End Set
End Property
#End Region 'Properties
#Region " Methods "
''' <summary>
''' Overridden. Sets the casing of the text displayed on the button based on the Caps Lock and Shift key states.
''' </summary>
''' <remarks>
''' The text is displayed in upper case if one and only one of the Caps Lock and Shift keys are depressed.
''' </remarks>
Protected Overrides Sub SetText()
Dim upperCase As Boolean = Me._capsLock Xor Me.Shift
If upperCase Then
Me.Text = Me.Text.ToUpper()
Else
Me.Text = Me.Text.ToLower()
End If
End Sub
#End Region 'Methods
End Class
vb.net Code:
''' <summary>
''' A button that represents a key on the keyboard whose behaviour can change when the Shift key is depressed.
''' </summary>
Friend MustInherit Class ShiftableKeyButton
Inherits KeyboardButton
#Region " Variables "
''' <summary>
''' Indicates whether the Shift key is depressed.
''' </summary>
Private _shift As Boolean = False
#End Region 'Variables
#Region " Properties "
''' <summary>
''' Gets or sets a value that indicates whether the Shift key is depressed.
''' </summary>
''' <value>
''' <b>True</b> if the Shift key is depressed and the button's behaviour should reflect that; otherwise, <b>False</b>.
''' </value>
''' <remarks>
''' The property can be set externally but only derived classes can get the property value.
''' </remarks>
Public Property Shift() As Boolean
Protected Get
Return Me._shift
End Get
Set(ByVal value As Boolean)
If Me._shift <> value Then
Me._shift = value
Me.SetText()
End If
End Set
End Property
#End Region 'Properties
#Region " Methods "
''' <summary>
''' Sets the text displayed on the button based on the state of modifier keys.
''' </summary>
Protected MustOverride Sub SetText()
#End Region 'Methods
End Class
vb.net Code:
''' <summary>
''' A button that represents a key on the keyboard.
''' </summary>
Public Class KeyboardButton
Inherits UnselectableButton
#Region " Variables "
''' <summary>
''' The value output when the key is pressed.
''' </summary>
Private _keyOutput As String
#End Region 'Variables
#Region " Properties "
''' <summary>
''' Gets or sets the value output when the key is pressed.
''' </summary>
''' <value>
''' A <b>String</b> containing the value corresponding to the equivalent keyboard key.
''' </value>
''' <remarks>
''' Passing the value of this property to the <see cref="System.Windows.Forms.SendKeys.Send">SendKeys.Send</see> method has the equivalent effect to pressing the corresponding key on the physical keyboard.
''' </remarks>
<Category("Behavior"), _
Description("The string sent to SendKeys.Send when the key is pressed.")> _
''' Overriden. Raises the <see cref="Click"/> event.
''' </summary>
''' <param name="e">
''' An <see cref="EventArgs"/> that contains the event data.
''' </param>
''' <remarks>
''' When the <see cref="ControlStyles">StandardClick</see> and <b>StandardDoubleClick</b> control styles are set the check box will, by default, raise two <b>Click</b> events each time it is clicked. This method suppresses the second event.
''' </remarks>
Protected Overrides Sub OnClick(ByVal e As System.EventArgs)
If Not Me.suppressClick Then
MyBase.OnClick(e)
End If
Me.suppressClick = Not Me.suppressClick
End Sub
''' <summary>
''' Overriden. Raises the <see cref="DoubleClick"/> event.
''' </summary>
''' <param name="e">
''' An <see cref="EventArgs"/> that contains the event data.
''' </param>
''' <remarks>
''' When the <see cref="ControlStyles">StandardClick</see> and <b>StandardDoubleClick</b> control styles are set the check box will, by default, raise a <see cref="Click"/> event after each <b>DoubleClick</b> event. This method suppresses that <b>Click</b> event.
''' </remarks>
Protected Overrides Sub OnDoubleClick(ByVal e As System.EventArgs)
Me.suppressClick = True
MyBase.OnDoubleClick(e)
End Sub
''' <summary>
''' Overriden. Raises the <see cref="MouseClick"/> event.
''' </summary>
''' <param name="e">
''' An <see cref="MouseEventArgs"/> that contains the event data.
''' </param>
''' <remarks>
''' When the <see cref="ControlStyles">StandardClick</see> and <b>StandardDoubleClick</b> control styles are set the check box will, by default, raise two <b>MouseClick</b> events each time it is clicked. This method suppresses the second event.
''' </remarks>
Protected Overrides Sub OnMouseClick(ByVal e As System.Windows.Forms.MouseEventArgs)
If Not Me.suppressMouseClick Then
MyBase.OnMouseClick(e)
End If
Me.suppressMouseClick = Not Me.suppressMouseClick
End Sub
''' <summary>
''' Overriden. Raises the <see cref="MouseDoubleClick"/> event.
''' </summary>
''' <param name="e">
''' An <see cref="MouseEventArgs"/> that contains the event data.
''' </param>
''' <remarks>
''' When the <see cref="ControlStyles">StandardClick</see> and <b>StandardDoubleClick</b> control styles are set the check box will, by default, raise a <see cref="MouseClick"/> event after each <b>MouseDoubleClick</b> event. This method suppresses that <b>MouseClick</b> event.
''' </remarks>
Protected Overrides Sub OnMouseDoubleClick(ByVal e As System.Windows.Forms.MouseEventArgs)
Me.suppressMouseClick = True
MyBase.OnMouseDoubleClick(e)
End Sub
#End Region 'Methods
End Class
vb.net Code:
''' <summary>
''' A check box control that cannot receive focus.
''' </summary>
Public Class UnselectableCheckBox
Inherits System.Windows.Forms.CheckBox
#Region " Constructors "
''' <summary>
''' Initialises a new instance of the <see cref="UnselectableCheckBox"/> class.
''' </summary>
Public Sub New()
MyBase.New()
'The check box cannot receive focus.
Me.SetStyle(ControlStyles.Selectable, False)
End Sub
#End Region 'Constructors
#Region " Methods "
Protected Overrides Sub OnClick(ByVal e As System.EventArgs)
I'm curious as to why you needed to build one rather than using the built in one for Windows. Was there something yours did that Osk didn't?
The Windows OSK is very small and not so great if you're doing everything with it. It's really intended for use with the mouse rather than on a touchscreen. My OSK was larger and less susceptible to "fat finger syndrome". It also matched the rest of my UI, including colour themes defined and controlled within the app. Finally, with the click of a button my OSK was shown occupying a predefined height across the full width of the screen and the application window was resized to occupy the rest. Clicking the same button again would hide the OSK and remaximise the app window. This was a POS application that was designed to be the only thing running on the system; almost like a kiosk.
Last edited by jmcilhinney; Apr 25th, 2008 at 09:48 PM.
I have started new project and added 4 classes NativeMethods, NativeConstants, UnselectableForm and UnselectableButton then opened UnselectableForm and draw UnselectableButton and some other standard controls, when i run the project, i see the form empty.
check the attachment, what's wrong i did?
Last edited by Absolute_Zero; Jul 1st, 2013 at 05:13 PM.
I have started new project and added 4 classes NativeMethods, NativeConstants, UnselectableForm and UnselectableButton then opened UnselectableForm and draw UnselectableButton and some other standard controls, when i run the project, i see the form empty.
check the attachment, what's wrong i did?
You shouldn't touch UnselectableForm. It should be a base class only. When you create your own forms, you derive them from UnselectableForm instead of Form. If your IDE supports it (not sure that Express does) you can select the Inherited Form item template when adding a new form. Otherwise, create the form as normal and then change the base class in the code afterwards.
You can add UnselectableButton controls to a form from the Toolbox, just like any other control. It will be added to the Toolbox automatically when you build.
Is it possible to make the form got the focus when click on its title bar? Currently i have to minimize and restore to make it focused.
As I said back in post #1 of this thread, that's exactly how it works by default. I just tested in VS 2012 and it worked that way as well. You must be doing something else. Here are the steps I took:
1. Created a new WinForms Application project.
2. Added NativeConstants, NativeMethods, UnselectableForm and UnselectableButton classes to the project and copied in the code from this thread.
3. Built the project.
4. Added a new Inherited Form item to the project and selected UnselectableForm as the base.
5. Added three UnselectableButton controls to the new form (Form2).
6. Added a Button and a TextBox to the original form (Form1).
7. Added this code to Form1:
vb.net Code:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Call New Form2().ShowUnactivated()
End Sub
8. Added this code to Form2:
vb.net Code:
Private Sub UnselectableButton1_Click(sender As Object, e As EventArgs) Handles UnselectableButton1.Click
SendKeys.Send("A")
End Sub
Private Sub UnselectableButton2_Click(sender As Object, e As EventArgs) Handles UnselectableButton2.Click
SendKeys.Send("B")
End Sub
Private Sub UnselectableButton3_Click(sender As Object, e As EventArgs) Handles UnselectableButton3.Click
SendKeys.Send("C")
End Sub
9. Ran the project.
10. Clicked Button1 on Form1.
At this stage, Form2 was displayed but did not take focus. If I clicked on the Form2's client area or a button then it did not take focus but it did take focus if I clicked in the title bar or border. If I clicked in the TextBox on Form1 and then clicked on the buttons on Form2, I would see ABC characters appear in the TextBox.
1- Run the project you have created in pos #14 and show Form2
2- Set the focus to any other App, e.g. Notepad (not maximized so you can see the both)
3- Click on Form2 title bar but it is not focused.
1- Run the project you have created in pos #14 and show Form2
2- Set the focus to any other App, e.g. Notepad (not maximized so you can see the both)
3- Click on Form2 title bar but it is not focused.
Hmmm... now I see what you mean. I don't recall having seen that behaviour previously but I'm not sure whether I just never tried to focus the window by clicking the title bar while another application had focus. I might test it on an older version of VS when I get home. Not sure what the solution would be but it might be either, because the window receives the same message and returns the same result whether the window that currently has focus is part of the same application or not.
I have googled a lot for a solution but couldn't find any, and ended with this
Code:
Option Strict On
Option Explicit On
Public Class UnselectableForm
Inherits System.Windows.Forms.Form
Private Const WS_EX_NOACTIVATE As Integer = &H8000000L
Protected Overrides ReadOnly Property CreateParams() As CreateParams
Get
Dim value As CreateParams = MyBase.CreateParams
value .ExStyle = value .ExStyle Or WS_EX_NOACTIVATE
Return value
End Get
End Property
End Class