WPF Window size not affected by TabTip keyboard - c#

I have a WPF application running on a Windows 8.1 tablet. the application is using the following method to show the virtual keyboard:
public static void OpenKeyboard()
{
ProcessStartInfo startInfo =
new ProcessStartInfo(#"C:\Program Files\Common Files\Microsoft Shared\ink\TabTip.exe")
{
WindowStyle = ProcessWindowStyle.Hidden
};
Process.Start(startInfo);
}
However, the size of the active window that the keyboard is displayed on top of doesn't change accordingly, meaning that if I have a ScrollViewer surrounding all the elements of my window it doesn't respond to the keyboard.
Is there any way to make my windows aware of the keyboard presence?
Update
Tried registering to the SizeChanged event of the window but it's not raised when the keyboard pops up.

Since TabTip.exe is a separate process it doesn't fire any events in your WPF application. Since win 8.1 tabtip does not automatically resize windows anymore. (there have been a lot of complaints about it)
There are a couple of ways you can do this manually. Firstly, Win8 apps have so called "LayoutAware" pages. Something similar can be done in WPF using the VisualStateManager.
This is rather complex and might not be the best solution, but I included it nevertheless (VisualStateManager solution here
Another way is to get the tabtip process from the list of active processes and calculate its width and height and use it to manually resize your screens.
Tabtip is if I remember correctly about 270 in height. You can also directly resize your screens as soon as the process appears. Something like this;
public void OpenKeyboard()
{
ProcessStartInfo startInfo =
new ProcessStartInfo(#"C:\Program Files\Common Files\Microsoft Shared\ink\TabTip.exe")
{
WindowStyle = ProcessWindowStyle.Hidden
};
Process.Start(startInfo);
//this = your window
this.Height -= 270;
}
There is another more clean way. It is a bit difficult and I haven't tried it myself yet. It is possible to grab the process and resize it where you want. You might be able to do it with the Windows API call 'findWindow()', but as far as I know that doesn't always work with tabtip, you might have to use P/Invoke.
To get you started I found some pretty great sources from which I wont steal credit by copying the code here; How to resize another application's window in C#
Changing another applications size and position using P/invoke (win32)
I hope you find this info useful. I know how you feel and have struggled with tabtip myself more often than id like.
Footnote; isn't it easier to just decrease your max window height and move it to the top of the screen when osk is called and put it back when its killed?

As far as I know this happens if the window is maximized or not resizable. Mke sure its state is not maximized before opening the keyboard.

In another answer I provided from my own research on working with tablets, the following S/O link might help you.
Tablet App, Auto Rotation and Taskbar Height Adjustments
I found a variety of things that were not cool, but did come up with some understanding points. Depending on the keyboard, does it actually overlay, or is it part of the anchored taskbar at the bottom of the window with other open tasks. If so, that will inherently change the window available dimensions, almost like a user changing from a lower to higher resolution (or hi/low). This actually changes the view port dimensions for the windows to be displayed. You can hook into
SystemEvents.UserPreferenceChanged and
SystemEvents.DisplaySettingsChanged
to detect and trigger whatever resizing considerations you need. There is also code on forcing your tablet to remain in a single orientation. I needed this because our tablet has a barcode scanner on it and it makes sense to always have the tablet with the scanner NOT pointing to the person, so we have it locked in a specific direction while the app is running.
And lastly, how do you KNOW you have entered (or exited) tablet mode. This shows how to hookup with ManagementEventWatcher to detect when registry entry changes interactively such as rotation, or undocking from a station and becoming free to use in tablet mode.
From your feedback, lets have you try this. From my version of TabTip (Surface Pro tablet), in the top-left is the keyboard settings. From that, if you click on it, it will open a dialog that allow for different keyboard styles from full width, abbreviated, split keyboard and even stylus for writing directly. Below that is an option to have your keyboard docked as the taskbar (left button I circled in red) vs floating window on top of others (I believe yours is running). Try setting your keyboard to a DOCKED state, then check the tablet mode and window environment settings getting changed. Worked for me.

Related

Automatically pop up tablet touch keyboard on WinForms input focus

When I run a WinForms (or Delphi, see at the end) application on Windows 10 in a tablet mode, a touch keyboard does not pop up automatically, when an input box is focused.
I believe that this should happen automatically, without any additional code/setup.
For a test, I have the simplest VS 2015 WinForms desktop application with a single TextBox control.
It's simply the default Windows Forms Application C# project as created by Visual Studio. No code added, no properties changed. Just the TextBox was added, by dropping from the Toolbox (again no properties changed):
this.textBox1 = new System.Windows.Forms.TextBox();
this.textBox1.Location = new System.Drawing.Point(64, 27);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(100, 20);
this.textBox1.TabIndex = 0;
To verify my assumption that the pop up should be automatic:
I've tried to run Windows XP version of notepad.exe on Windows 10. It automatically pops up the touch keyboard. I doubt the Windows XP had any explicit support for touch keyboards.
I've also tried some ancient MFC applications (for example FileZilla 2.2.15 from 2005). It also pops up the touch keyboard on all its input boxes. Again, I'm pretty sure, the MFC had no explicit support for touch keyboards either.
The same for applications built on wxWidgets (for example FileZilla 3.x).
It looks like there's something broken in WinForms that prevents the automatic popup. Interestingly, the automatic pop up works:
for (editable) combo boxes (ComboBox with DropDownStyle = DropDown)
for text boxes in a password mode (TextBox.PasswordChar)
for rich text boxes (RichTextBox)
when the input box has focus at the moment the hardware keyboard is "removed" (I test this by flipping the screen on Lenovo Yoga notebook), but never after.
I've seen all the hints about an explicit popup by running the TabTip.exe. E.g.:
How to use Windows On-Screen Keyboard in C# WinForms
Open and close Windows 8 touch keyboard tabtip under desktop
How do I close the on-screen keyboard process from C# winform correctly?
Keyboard Winforms on Windows 10 (surface)
Most of the "solutions" offer a code like this:
var progFiles = #"C:\Program Files\Common Files\Microsoft Shared\ink";
var keyboardPath = Path.Combine(progFiles, "TabTip.exe");
this.keyboardProc = Process.Start(keyboardPath);
But I cannot believe this could be the "official" way. If for nothing else, then because there's no clean way to hide the keyboard opened by running the TabTip.exe (solutions include hacks like killing the process or sending Esc key).
And actually the above hack does not seem to work anymore in Windows 10 Anniversary Update:
Show touch keyboard (TabTip.exe) in Windows 10 Anniversary edition
Interestingly, I see the same behavior with Delphi/C++ Builder/VCL applications. The keyboard does not pop up for edit boxes (TEdit). It does pop up for combo boxes (TComboBox) and for edit boxes in a password mode (PasswordChar). Interestingly not for TRichEdit, what is notable difference to .NET RichTextBox, that maybe worth investigating.
This (unanswered) question describes an identical behavior:
Application written Delphi XE8 touch in edit boxes keyboard not appear in Windows 10.
The root cause seems to be that Winforms' textBox is not an AutomationElement, while the rest of the mentioned controls (ComboBoxes etc) are.
Quoting Markus von und zu Heber's accepted answer here:
We found it in the article "Automatic Touch Keyboard for TextBoxes in
WPF Applications on Windows 8+", but it also works very good (and even
easier!) for winforms. Thank you, Dmitry Lyalin!
Insert a reference to UIAutomationClient.dll to your project
In the form-load-handler of the application's main window, insert the following code:
var asForm = System.Windows.Automation.AutomationElement.FromHandle(this.Handle);
I've been down this road a few times and have only ever been able to implement the taptip.exe option. And in turn close the window by killing the process. I also found out that with some registry hacks you can get the keyboard to default to the handwriting panel if you so choose. But then that only works in Win8 and fails in Win10. Here is what I've done in case anyone else finds this useful:
RegistryKey registryKey = Registry.CurrentUser.CreateSubKey("Software\\Microsoft\\TabletTip\\1.7");
registryKey?.SetValue("KeyboardLayoutPreference", 0, RegistryValueKind.DWord);
registryKey?.SetValue("LastUsedModalityWasHandwriting", 1, RegistryValueKind.DWord);
Process.Start(#"C:\Program Files\Common Files\Microsoft Shared\ink\TabTip.exe");
I need to give credit to this post for the registry idea: Windows 8 Desktop App: Open tabtip.exe to secondary keyboard (for numeric textbox)
As far as I can tell, launching osk.exe or tabtip.exe pretty much is the "standard" way of making this work. I've found no "official" solution so far.
However, if it were me doing this, I wouldn't be killing the process or sending keys to try and dismiss the keyboard. Instead, you can obtain the window handle when you launch the process, and use that to minimize the window and hide it from the taskbar.
Someone here has gotten the window handle just to close it, but it gives you the idea: Show & hiding the Windows 8 on screen keyboard from WPF
If you need me to, let me know and I'll see if I can find the time to do up a full example.
As hinted by Ofek Shilon's answer, it seems that the touch keyboard can leverage the UI automation.
One can use implementation of UI automation from UIAutomationClient.dll.
For the UI automation to be magically injected into an application, class initializer of the assembly internal class UiaCoreApi have to be triggered.
On can achieve that for example by calling seeming no-op:
AutomationElement.FromHandle(IntPtr)(-1)
Another way is to implement automation UI explicitly. For that implement the ITextProvider/IValueProvider interfaces for the respective input control.
To bind the implementation of the interfaces to the control, handle WM_GETOBJECT window message with lParam = RootObjectId.
For an example of implementation, see
tombam's answer to How to use Windows On-Screen Keyboard in C# WinForms
or directly poster's article Implementing TextBox with on-screen touch keyboard.
Though interestingly, controls, for which touch keyboard works out-of-the-box (like combo box or password edit box, see the answer), do not implement the WM_GETOBJECT/RootObjectId. There must be a different machinery behind them.
Use a RichTextBox instead of a TextBox control. The RichTextBox supports the touch keyboard and will automatically pop up the keyboard when focus is gained. (similar to other input controls such as the combo box)
The RichTextBox also supports the same properties as the TextBox so it should be a drop in change in most cases. (Both controls derive from TextBoxBase)
I have noticed that if the touch keyboard has been dismissed after it pops up, you may have to tap twice on the control to get it to pop back up.

How can I avoid competition between overlapping windows in Windows Forms/SlimDX

I'm creating a Windows Forms application in C# that utilizes the SlimDX(a managed wrapper of the Direct3D API) libraries. Problems arise when I try to take the application fullscreen(a state in which the main window covers the entire desktop area including the taskbar).
The Direct3D device window(main window) displays correctly. The taskbar and other overlapping windows are hidden entirely by the device window. The cursor, however, seems to belong to the window directly beneath the device window. This is evident in the appearance and behavior of the cursor. When I click on the device window focus is changed to the window beneath. This is unexpected behavior for any window.
Also, I am able to click items on the taskbar which will cause a change in focus.
I am changing the window style of the device window to 'TopMost and 'Popup'. Also, I am following the utility class found in the DirectX SDK. When I run a sample from the DX SDK, which uses Win32, this problem doesn't occur. Is it possible that the problem is related to my use of Windows Forms?
There is a lot of code involved in my application so I was hoping for theoretical responses as to why this problem might occur. I found a thread here that describes a problem when taking device fullscreen, however, the solution is unacceptable. It was suggested to use a 'windowed fullscreen mode'. Instead of modifying the adapter display mode for fullscreen, the device window would simply be resized to cover the entire screen. This solution would prevent the use of adapter formats, resolutions, and refresh rates that are available in fullscreen mode.
Any suggestions would be much appreciated!
The problem was due to the nature of controls found in Windows Forms. From MSDN:
A control can be selected and receive input focus if all the following are true: the Selectable value of ControlStyles is set to true, it is contained in another control, and all its parent controls are both visible and enabled.
The device window in my application belongs to a parent window and the parent window becomes nonvisible once fullscreen is enabled. Its possible that a conflict arose due to the 'focus rules' above. To test the theory I examined the return value from DeviceWindow.Focus()(derives from Control.Focus())...which returned false.
My solution was to create a form used for the sole purpose of fullscreen mode changes. Now, when I want to go fullscreen I reset the device with the handle to the new device window. All problems solved...

Is it possible to screenshot a minimized application

I know it's possible to capture a screen of an application that is behind another application, but I can't seem to find anything on capturing the screen of a minimized application.
Anyone happen to know if this is possible? I don't want to get into things like maximizing and minimizing the application really quick.
As #ziplin said with newer version of windows it may be possible (via DWM apis). From c# you can use the Windows API codepack to access the new apis
I don't believe so, simply because i've noticed programs that try to preview a window that is minimized seem to draw a blank on occasion if the window is minimized. Although, some new versions of windows (vista and 7, I believe) do this very thing, but I'm not sure how easy it is to replicate (at all)
: http://www.stardock.com/products/objectdock/
You can't without restoring the window. When a window is minimized, the application is not in a state to render a UI for your application to capture.
If anyone still wants to no a workable solution I tried this one and worked well for me. It does a trick for minimized windows (because windows does not refresh them, on the taskbar the iconic picture shows the last image of the window before it was minimized). And Ziplin above mentioned that Objectdock can capture minimized windows, actually it does the same as Windows, it uses the last image captured before minimizing.
So here is the link: http://www.codeproject.com/Articles/20651/Capturing-Minimized-Window-A-Kid-s-Trick
I've never tried it. This code claims looks reasonable, but has caveats about minimized windows. It is, if nothing else, a place to start.
As a last resort: why not capture window just before it gets minimized?
I know its too late, maybe it might help others.
I thought of a different approach, instead of minimizing, I moved my form outside my screen co-ordinates before capturing the screen and later respawned it.
Below is my code example:
//Move the form beyond the screen
this.StartPosition = FormStartPosition.Manual;
this.Location = new Point(Screen.PrimaryScreen.Bounds.Width + 10, Screen.PrimaryScreen.Bounds.Height + 10);
// Screenshot code here...
//Respawn the form to origin location
this.Location = currentPosition;

Need to pinvoke a .dll or something to change the mouse cursor in WPF

I'm trying to override the cursor for the entire computer
this.Cursor = Cursors.Pen;
System.Windows.Input.Mouse.OverrideCursor = Cursors.Pen;
This works within the WPF "Window", but not anywhere outside it.
What .dll will let me do this?
This behavior is by design, and a good thing.
Look at the native routines, such as SetCursor, and you'll see this:
The cursor is a shared resource. A window should set the cursor shape only when the cursor is in its client area or when the window is capturing mouse input. In systems without a mouse, the window should restore the previous cursor before the cursor leaves the client area or before it relinquishes control to another window.
You shouldn't try to override the cursor for other applications. Doing so is being a bad citizen on the system. As long as your application is active, or you have a window capture mouse input, then the cursor you set via Mouse.OverrideCursor will remain active.
Given that you really don't care about playing nice, though, you can always just go all-out and make your program take over the system. Just run your main window as a full screen application, with a window over each monitor on the system, and set them all to Topmost. Set your cursor, and the mouse will never leave the window.
While you're at it, you should consider downloading a bunch of these nice unicorn images from the StackOverflow Users page, and tile the background of the windows with them. This would really add a nice, subtle effect to the user's desktop.

How can we prevent popup windows appearing on top of the application?

I have a fullscreen window, and I want to prevent pop up windows that appear at the right bottom corner of my screen. I set the Topmost property to true, but apparently it does not help. I also tried activating the form and giving it the focus once it got deactivated, but that did not help either. What is a way to ignore such windows while the user is engaged with the fullscreen app? I am .NET programming in C#.
You can't do it, this fails the "what if two programs tried to do this" test:
those popups are just normal windows like yours, they also use the same top-most style you are using.
if there was a way to always be above other topmost windows they would have used it too rendering it useless (because the authors of the other apps are just as concerned about the user missing their "super important" notifications as you are about them interfering with your full screen app).
You can try and play dirty tricks to force your window to the top of the top-most z-order, but those popups are likely to use the exact same tricks, again making this all useless (and as an extra bonus all those dirty tricks can turn your app into a compatibility nightmare).
You can disable these balloon notifications using these steps:
Click Start, Run and type regedit
Navigate to the following subkey:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced
In the right pane, create a DWORD value named EnableBalloonTips
Double-click the new entry, and give it a value of 0.
Quit Registry Editor.
Log off Windows (this is not very cool...), and then log back on for the changes to take effect.
if you need help in how doing this by program, don't hesitate to ask ;)
I don't think that you can block all the popups, windows might not let you do that. But you can try with SetWindowPos function and pass it HWND_TOP parameter. It might work a little better than Topmost = true.
I used a sys tray popup control on my personal project SvnRadar written in WPF.
The control is at the http://www.hardcodet.net/projects/wpf-notifyicon written by Philipp Sumi.
Very nice.Only thing you will be need to "detach" it from the SysTray screen coordinates and
make it appear where you wish.
Hope it helps.
Good luck.

Categories