I'm developing a custom HyperTerminal like application in a WinForms .Net 2.0 application. I have a multiline TextBox in a Panel in which you can interact with a hardware device.
My customer wants to have a custom Caret, a filled rectangle the size of one character space instead of the vertical line that is by default.
I know .Net does not provide an option to do this by default, but there must some Windows function to do it.
These are the list of Native Caret functions provided by Windows you can use them for you application.
[DllImport("User32.dll")]
static extern bool CreateCaret(IntPtr hWnd, int hBitmap, int nWidth, int nHeight);
[DllImport("User32.dll")]
static extern bool SetCaretPos(int x, int y);
[DllImport("User32.dll")]
static extern bool DestroyCaret();
[DllImport("User32.dll")]
static extern bool ShowCaret(IntPtr hWnd);
[DllImport("User32.dll")]
static extern bool HideCaret(IntPtr hWnd);
Refer SharpDevelop, Source Code # src\Libraries\ICSharpCode.TextEditor\Project\Src\Gui\Caret.cs
Assume a form with a textbox on it:
public partial class Form1 : Form
{
[DllImport("user32.dll")]
static extern bool CreateCaret(IntPtr hWnd, IntPtr hBitmap, int nWidth, int nHeight);
[DllImport("user32.dll")]
static extern bool ShowCaret(IntPtr hWnd);
public Form1()
{
InitializeComponent();
}
private void Form1_Shown(object sender, EventArgs e)
{
CreateCaret(textBox1.Handle, IntPtr.Zero, 10, textBox1.Height);
ShowCaret(textBox1.Handle);
}
}
I would use System.Drawing to draw a custom cursor (bitmap), maybe with a timer to let it blink like another cursor.
Get the current position of the Cursor in pixels and draw a bitmap over that cursor. Can be tricky to find the correct position, but should be doable.
Have a look here for Owner drawn textbox in winforms.
Use:
richTextBoxConsole.GetPositionFromCharIndex(cursorPos)
Hide the normal caret and draw your own? Not tested, but should work I think.
Related
How to prevent any editing and selection attempts for ComboBox with ComboBoxStyle.DropDown (not DropDownList!) setting?
I override OnKeyDown and cut any keyboard input but mouse selection events still works and caret is visible.
I can propose you two (simple) methods to set a ComboBox text read-only-like.
Using SendMessage:
In this case, the ComboBox underlying Edit Control is set to ReadOnly and - as already said - its background color is painted with the non-active/disabled color (LTGRAY_BRUSH).
The same as if you set a TextBox control ReadOnly property to true.
[DllImport("User32.dll")]
internal static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("User32.dll", SetLastError = true)]
internal static extern int SendMessage(IntPtr hWnd, uint uMsg, int wParam, int lParam);
private const uint EM_SETREADONLY = 0x00CF;
private void Form1_Load(object sender, EventArgs e)
{
IntPtr EditHandle = FindWindowEx(comboBox1.Handle, IntPtr.Zero, "Edit", null);
SendMessage(EditHandle, EM_SETREADONLY, 1, 0);
}
Discarding any key press using the Control KeyDown event:
In this case, the ComboBox background color of course does not change, but there might be undesired behaviours, depending on its use.
private void comboBox1_KeyDown(object sender, KeyEventArgs e)
{
e.SuppressKeyPress = true;
}
Update:
A method to hide the caret (without subclassing or inheriting):
Here I'm using FindWindowEx again. You can assign the IntPtr EditHandle to a class scope variable and get the Edit control handle once in the Form Load event.
[DllImport("user32")]
internal static extern bool HideCaret(IntPtr hWnd);
[DllImport("user32")]
internal static extern bool ShowCaret(IntPtr hWnd);
private void comboBox1_MouseUp(object sender, MouseEventArgs e)
{
comboBox1.Select(0, 0);
IntPtr EditHandle = FindWindowEx(comboBox1.Handle, IntPtr.Zero, "Edit", null);
HideCaret(EditHandle);
}
I want to change the Caret in a Textbox in C# that it appears wider like in does in old DOS applications.
What i have:
Example what i want:
I tried:
using System.Runtime.InteropServices;
...
[DllImport("user32.dll")]
static extern bool CreateCaret(IntPtr hWnd, IntPtr hBitmap, int nWidth, int nHeight);
[DllImport("user32.dll")]
static extern bool ShowCaret(IntPtr hWnd);
...
public partial class Form1 : Form
{
[DllImport("user32.dll")]
static extern bool CreateCaret(IntPtr hWnd, IntPtr hBitmap, int nWidth, int nHeight);
[DllImport("user32.dll")]
static extern bool ShowCaret(IntPtr hWnd);
public Form1()
{
InitializeComponent();
}
private void Form1_Shown(object sender, EventArgs e)
{
CreateCaret(textBox1.Handle, IntPtr.Zero, 20, textBox1.Height);
ShowCaret(textBox1.Handle);
}
}
But it still looks the same. Any help would be nice. Thanks in advance!
Edit:
This was just an example. My real code looks like:
TextBox textbox = new TextBox();
textbox.MaxLength = fieldLength;
textbox.Width = fieldLength*24;
textbox.MaxLength = maxChars;
this.Controls.Add(textbox);
CreateCaret(textbox.Handle, IntPtr.Zero, 20, textbox.Height);
ShowCaret(textbox.Handle);
The code gets called but doesnt change anything.
Edit2:
I tried the example and it works fine but my problem still exisits:
I cant change the Caret when creating the textbox. Its only possible for a textbox created with the form.
You didn't link the event correctly, you should change to :
public partial class Form1 : Form
{
[DllImport("user32.dll")]
static extern bool CreateCaret(IntPtr hWnd, IntPtr hBitmap, int nWidth, int nHeight);
[DllImport("user32.dll")]
static extern bool ShowCaret(IntPtr hWnd);
public Form1()
{
InitializeComponent();
this.Shown += Form1_Shown;
}
private void Form1_Shown(object sender, EventArgs e)
{
CreateCaret(textBox1.Handle, IntPtr.Zero, 20, textBox1.Height);
ShowCaret(textBox1.Handle);
}
}
What is going on it seems is that the shown event will only initially work. When you leave the textbox by tabbing away and back to the control the caret will be reset by underlying code.
Take a look the answer in this thread.
I took their DrawDaret Method and changed it a bit. Calling DrawCaret on the textbox1.Enter event doesn't work. possibly the textbox implementation will notify the Enter event and then change the caret. This would undo a change done in the Enter event handler regarding to the caret.
EDIT
But the control also has a GotFocus event which you can use.
public partial class Form1 : Form
{
[DllImport("user32.dll")]
static extern bool CreateCaret(IntPtr hWnd, IntPtr hBitmap, int nWidth, int nHeight);
[DllImport("user32.dll")]
static extern bool ShowCaret(IntPtr hWnd);
public Form1()
{
InitializeComponent();
textBox1.GotFocus += new EventHandler(textBox1_GotFocus);
}
void textBox1_GotFocus(object sender, EventArgs e)
{
DrawCaret(textBox1);
}
public void DrawCaret(Control ctrl)
{
var nHeight = 0;
var nWidth = 10;
nHeight = Font.Height;
CreateCaret(ctrl.Handle, IntPtr.Zero, nWidth, nHeight);
ShowCaret(ctrl.Handle);
}
}
I'm trying to use the youtube embedded player ( axshockwaveflash) and make a nice program out of it.
Thing is i'm trying to implement a button that'll replay/next/previous the current video.
what I have atm is:
private void btReplay_Click(object sender, EventArgs e)
{
if (!youtubePlayer.Focus())
{
youtubePlayer.Focus();
SendKeys.Send("0");
}
else
{
SendKeys.Send("0");
}
this.BringToFront();
}
The '0' key press makes the video replay from the start. Only it also makes the form dissappear between other open windows.
As you see i've tried using bringtofront but it won't work.
Any thoughts?
Also if anyone has any experience with this, i also want to play how to enable auto play the next video when using the 'END' key. I know about the autoplay=1 function but it won't seem to work when pressing the END key.
EDIT: Using WinForms btw
You didn't specify whether you use winForms or WPF. This snippet is for winforms.
Here I am giving you a static method that forces any given Form to front:
public static void bringWindowToFront(System.Windows.Forms.Form form)
{
uint foreThread = GetWindowThreadProcessId(GetForegroundWindow(), System.IntPtr.Zero);
uint appThread = GetCurrentThreadId();
const uint SW_SHOW = 5;
if (foreThread != appThread)
{
AttachThreadInput(foreThread, appThread, true);
BringWindowToTop(form.Handle);
ShowWindow(form.Handle, SW_SHOW);
AttachThreadInput(foreThread, appThread, false);
}
else
{
BringWindowToTop(form.Handle);
ShowWindow(form.Handle, SW_SHOW);
}
form.Activate();
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
private static extern bool BringWindowToTop(System.IntPtr hWnd);
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
public static extern uint GetCurrentThreadId();
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern System.IntPtr GetForegroundWindow();
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(System.IntPtr hWnd, System.IntPtr ProcessId);
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool ShowWindow(System.IntPtr hWnd, uint nCmdShow);
this.BringToFront();
this.TopMost = true;
worked for me, silly i didnt think of this.
I need to disable the Mouse Clicks, Mouse movement for a specific windows for a Kiosk application. Is it Feasible in C# ?
I have removed the menu bar and title bar of a specific window, will that be a starting point to achieve the above requirement ? How can i achieve this requirement.
The code for removing the menu bar and title bar using window handle :
#region Constants
//Finds a window by class name
[DllImport("USER32.DLL")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
//Sets a window to be a child window of another window
[DllImport("USER32.DLL")]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
//Sets window attributes
[DllImport("USER32.DLL")]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
//Gets window attributes
[DllImport("USER32.DLL")]
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
[DllImport("user32.dll")]
static extern IntPtr GetMenu(IntPtr hWnd);
[DllImport("user32.dll")]
static extern int GetMenuItemCount(IntPtr hMenu);
[DllImport("user32.dll")]
static extern bool DrawMenuBar(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool RemoveMenu(IntPtr hMenu, uint uPosition, uint uFlags);
//assorted constants needed
public static uint MF_BYPOSITION = 0x400;
public static uint MF_REMOVE = 0x1000;
public static int GWL_STYLE = -16;
public static int WS_CHILD = 0x40000000; //child window
public static int WS_BORDER = 0x00800000; //window with border
public static int WS_DLGFRAME = 0x00400000; //window with double border but no title
public static int WS_CAPTION = WS_BORDER | WS_DLGFRAME; //window with a title bar
public static int WS_SYSMENU = 0x00080000; //window menu
#endregion
public static void WindowsReStyle()
{
Process[] Procs = Process.GetProcesses();
foreach (Process proc in Procs)
{
if (proc.ProcessName.StartsWith("notepad"))
{
IntPtr pFoundWindow = proc.MainWindowHandle;
int style = GetWindowLong(pFoundWindow, GWL_STYLE);
//get menu
IntPtr HMENU = GetMenu(proc.MainWindowHandle);
//get item count
int count = GetMenuItemCount(HMENU);
//loop & remove
for (int i = 0; i < count; i++)
RemoveMenu(HMENU, 0, (MF_BYPOSITION | MF_REMOVE));
//force a redraw
DrawMenuBar(proc.MainWindowHandle);
SetWindowLong(pFoundWindow, GWL_STYLE, (style & ~WS_SYSMENU));
SetWindowLong(pFoundWindow, GWL_STYLE, (style & ~WS_CAPTION));
}
}
}
It sounds like you are looking for EnableWindow. The description is:
Enables or disables mouse and keyboard
input to the specified window or
control. When input is disabled, the
window does not receive input such as
mouse clicks and key presses. When
input is enabled, the window receives
all input.
So you would add
[DllImport("user32.dll")]
static extern bool EnableWindow(IntPtr hWnd, bool enable);
and
EnableWindow(pFoundWindow, false);
This is equivalent to setting the Enabled property on a Windows Forms Form/Control.
You can try to override the WndProc and check for WM_MOUSE* events there. If you dont call the base WndProc for these handled events, it should work.
A point to consider here is that since yours is a kiosk application, will your special mouse handling lead to any problems for Touch screen.
To prevent keyboard input in a window in another process, you need to make a keyboard hook.
You can then check GetForegroundWindow() and suppress the input.
How can I check whether another application is minimized or not? For instance in a loop like this:
foreach(Process p in processes)
{
// Does a process have a window?
// If so, is it minimized, normal, or maximized
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
private struct WINDOWPLACEMENT {
public int length;
public int flags;
public int showCmd;
public System.Drawing.Point ptMinPosition;
public System.Drawing.Point ptMaxPosition;
public System.Drawing.Rectangle rcNormalPosition;
}
if (p.MainWindowHandle != IntPtr.Zero) {
if (p.MainWindowTitle.Contains("Notepad")) {
WINDOWPLACEMENT placement = new WINDOWPLACEMENT();
GetWindowPlacement(p.MainWindowHandle, ref placement);
switch (placement.showCmd) {
case 1:
Console.WriteLine("Normal");
break;
case 2:
Console.WriteLine("Minimized");
break;
case 3:
Console.WriteLine("Maximized");
break;
}
}
}
There is no such thing as a minimized "application." The best alternative would be to check whether the application's Main Window is Iconic (minimized).
IsIconic can be used to check for the iconic state of a window. It will return 1 if a window is minimized. You can call this with process.MainWindowHandle.
If a window is minimized (in Windows Forms at least) both Location.X and Location.Y values are -32000
you can use isZoomed for maximized and isIconic for minimized by injecting user32 dll
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool IsZoomed(IntPtr hWnd);
Instead of enumerating Processes, you should use the native EnumWindows() function and then call IsIconic.