Keeping numlock off in c# - c#

I would like to use the numlock button for something other than numlock. So basically I would like to turn off numlock when it is pressed and keep it off. I can capture the button press but it still toggles on/off. I want it off, always. Any suggestions?
Not sure WHY anyone would like to know WHY I want this to be done but here is the reason: I have a bluetooth numeric keypad that I want to use to control a machine. Does that justify the question?
After a couple hours of research I came across the following code which did the trick:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
class SetNumlockKeyOn
{
[StructLayout(LayoutKind.Sequential)]
public struct INPUT
{
internal int type;
internal short wVk;
internal short wScan;
internal int dwFlags;
internal int time;
internal IntPtr dwExtraInfo;
int dummy1;
int dummy2;
internal int type1;
internal short wVk1;
internal short wScan1;
internal int dwFlags1;
internal int time1;
internal IntPtr dwExtraInfo1;
int dummy3;
int dummy4;
}
[DllImport("user32.dll")]
static extern int SendInput(uint nInputs, IntPtr pInputs, int cbSize);
public static void SetNumlockOn()
{
if (Control.IsKeyLocked(Keys.NumLock)) return;
const int mouseInpSize = 28;//Hardcoded size of the MOUSEINPUT tag !!!
INPUT input = new INPUT();
input.type = 0x01; //INPUT_KEYBOARD
input.wVk = 0x90; //VK_NUMLOCK
input.wScan = 0;
input.dwFlags = 0; //key-down
input.time = 0;
input.dwExtraInfo = IntPtr.Zero;
input.type1 = 0x01;
input.wVk1 = 0x90;
input.wScan1 = 0;
input.dwFlags1 = 2; //key-up
input.time1 = 0;
input.dwExtraInfo1 = IntPtr.Zero;
IntPtr pI = Marshal.AllocHGlobal(mouseInpSize * 2);
Marshal.StructureToPtr(input, pI, false);
int result = SendInput(2, pI, mouseInpSize); //Hardcoded size of the MOUSEINPUT tag !!!
//if (result == 0 || Marshal.GetLastWin32Error() != 0)
// Console.WriteLine(Marshal.GetLastWin32Error());
Marshal.FreeHGlobal(pI);
}
}

Here's an example:
public static class NativeMethods
{
public const byte VK_NUMLOCK = 0x90;
public const uint KEYEVENTF_EXTENDEDKEY = 1;
public const int KEYEVENTF_KEYUP = 0x2;
[DllImport("user32.dll")]
public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
public static void SimulateKeyPress(byte keyCode)
{
keybd_event(VK_NUMLOCK, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(VK_NUMLOCK, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
}
public partial class Form1 : Form
{
private bool protectKeys; // To protect from inifite keypress chain reactions
public Form1()
{
InitializeComponent();
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (protectKeys)
return;
if (e.KeyCode == Keys.NumLock &&
!(new Microsoft.VisualBasic.Devices.Keyboard().NumLock))
{
protectKeys = true;
NativeMethods.SimulateKeyPress(NativeMethods.VK_NUMLOCK);
protectKeys = false;
}
}
}

Related

Windows SendInput (Keyboard) Not Working on Disconnect

I am running a c# application that makes use of the sendinputs method in windows to mimic keystrokes. It works fine when I am remoted into the instance, but as soon as I log out it throws an exception. Can anyone offer any thoughts on why this is happening, and how to avoid it?
UPDATE::
here is some sample code that can reproduce the issue.
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ConsoleApplication6
{
class Program
{
class SendKey
{
[StructLayout(LayoutKind.Sequential)]
private struct MOUSEINPUT
{
public int dx;
public int dy;
public int mouseData;
public int dwFlags;
public int time;
public int dwExtraInfo;
};
[StructLayout(LayoutKind.Sequential)]
private struct KEYBDINPUT
{
public short wVk;
public short wScan;
public int dwFlags;
public int time;
public int dwExtraInfo;
};
[StructLayout(LayoutKind.Sequential)]
private struct HARDWAREINPUT
{
public int uMsg;
public short wParamL;
public short wParamH;
};
[StructLayout(LayoutKind.Explicit)]
private struct INPUT
{
[FieldOffset(0)]
public int type;
[FieldOffset(4)]
public MOUSEINPUT no;
[FieldOffset(4)]
public KEYBDINPUT ki;
[FieldOffset(4)]
public HARDWAREINPUT hi;
};
[DllImport("user32.dll")]
private extern static void SendInput(int nInputs, ref INPUT pInputs, int cbsize);
[DllImport("user32.dll", EntryPoint = "MapVirtualKeyA")]
private extern static int MapVirtualKey(int wCode, int wMapType);
private const int INPUT_KEYBOARD = 1;
private const int KEYEVENTF_KEYDOWN = 0x0;
private const int KEYEVENTF_KEYUP = 0x2;
private const int KEYEVENTF_EXTENDEDKEY = 0x1;
private void Send(Keys key, bool isEXTEND)
{
INPUT inp = new INPUT();
inp.type = INPUT_KEYBOARD;
inp.ki.wVk = (short)key;
inp.ki.wScan = (short)MapVirtualKey(inp.ki.wVk, 0);
inp.ki.dwFlags = ((isEXTEND) ? (KEYEVENTF_EXTENDEDKEY) : 0x0) | KEYEVENTF_KEYDOWN;
inp.ki.time = 0;
inp.ki.dwExtraInfo = 0;
SendInput(1, ref inp, Marshal.SizeOf(inp));
System.Threading.Thread.Sleep(100);
inp.ki.dwFlags = ((isEXTEND) ? (KEYEVENTF_EXTENDEDKEY) : 0x0) | KEYEVENTF_KEYUP;
SendInput(1, ref inp, Marshal.SizeOf(inp));
}
static void Main()
{
while(true)
{
System.Threading.Thread.Sleep(2000);
SendKey s = new SendKey();
s.Send(Keys.Z, false);
s.Send(Keys.Left, true);
}
}
}
}
}
if you build this and just run it on a free windows server ec2 instance with notepad in focus it will print zzzzzz continuously while you are remoted into the instance, however, as soon as you remote out of the instance, it will stop printing until you log back in.

Is it possible to capture KeyDown-events and to cancel this Event afterwards in C#?

I want to translate the Latin keyboard to another Keyboard like uyghur or something like. There is an uyghur keyboard, but the coding of keys are so complex that a normal PC User can't type uighur easily.
So my aim is that to create a software solution for this Problem, such as Chinese Input Systems. in that system you can input Chinese Characters from every kind of Keyboard. that is a kind of clever solution so that everyone can use it problem-less.
So my aim is that I want to write a Windows Service Application, which captures every KeyDown-Strike (only Alphabets) and translates the pressed Key to destination (Unicode) Alphabet and simulates again a Key strike with this translated Alphabet. As result the aimed Alphabet will be showed in the cursor-point. In the End my App discards/Stops the original key from the KEYDOWN pressing,
So that it will not be showed any more.
For example:
Press K.
Capturing the K and Translate it to Unicode like 0xFEBD then send back to cursor point.
Cancel or Discard the key down event of the K. This character should not be seen at the cursor point.
Until now the Step 1 and 2 works fine. My problem is that I can't discard/cancel/stop the last key down event for this key strike, after I capture the key down event.
I am not sure if my idea good/effective enough to realize what I am thinking. Now I am trying only. may be you have a better idea that you can suggest me. here is my code for that:
public class Simulate
{
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
static extern UInt32 SendInput(UInt32 numberOfInputs, INPUT[] input, Int32 sizeOfInputStructure);
[StructLayout(LayoutKind.Sequential, Size = 24)]
struct KEYBDINPUT
{
public UInt16 Vk;
public UInt16 Scan;
public UInt32 Flags;
public UInt32 Time;
public UInt32 ExtraInfo;
}
[StructLayout(LayoutKind.Explicit)]
private struct INPUT
{
[FieldOffset(0)]
public int Type;
[FieldOffset(4)]
public KEYBDINPUT ki;
}
public static void UnicodeInput(UInt16 unicode)
{
INPUT down = new INPUT();
down.Type = 1; //INPUT_KEYBOARD
down.ki.Vk = 0;
down.ki.Scan = unicode;
down.ki.Time = 0;
down.ki.Flags = 0x0004; //KEYEVENTF_UNICODE
down.ki.ExtraInfo = 0;
INPUT up = new INPUT();
up.Type = 1; //INPUT_KEYBOARD
up.ki.Vk = 0;
up.ki.Scan = unicode;
up.ki.Time = 0;
up.ki.Flags = 0x0004; //KEYEVENTF_UNICODE
up.ki.ExtraInfo = 0;
INPUT[] input = new INPUT[2];
input[0] = down;
input[1] = up;
SendInput(1, input, Marshal.SizeOf(typeof(INPUT)));
}
}
/// Capture any window key
///
public static class WinKeyCapture
{
private const int WH_KEYBOARD_LL = 13;
private const int WH_CALLWNDPROC = 4;
private const int WM_KEYDOWN = 0x0100;
private const int WM_CHAR = 0x0102;
const int VK_A = 0x08;// 0x41; //up key
const int VK_DOWN = 0x28; //down key
const int VK_LEFT = 0x25;
const int VK_RIGHT = 0x27;
const uint KEYEVENTF_KEYUP = 0x0002;
const uint KEYEVENTF_EXTENDEDKEY = 0x0001;
const uint KEYEVENTF_CTRL = 0x11;
const uint KEYEVENTF_ADD = 0x6B;
const uint VK_LWIN = 0x5b;
private static LowLevelKeyboardProc _proc = WinKeyCapture.HookCallback;
[DllImport("user32.dll")]
public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll", SetLastError = true)]
private static extern uint SendInput(uint numberOfInputs, INPUT[] inputs, int sizeOfInputStructure);
public static void SetHook()
{
SetHook(_proc);
}
public static void UnHook()
{
UnhookWindowsHookEx(_hookID);
}
private static IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
}
}
private static IntPtr _hookID = IntPtr.Zero;
public static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
int vkCode = Marshal.ReadInt32(lParam);
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
// TODO: identify only Alphabets then fire
VKcode(vkCode);
}
//wParam |= 0x4000;
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private static void VKcode(int code)
{
switch (code) // TODO: Complete all other Alphabet-Tranylations
{
case 0x4B:
Simulate.UnicodeInput(0xFEDB);
break;
case 0x54:
Simulate.UnicodeInput(0xFEAD);
break;
case 0x55:
Simulate.UnicodeInput(0xFBE7);
break;
case 0x56:
Simulate.UnicodeInput(0xFEE9);
break;
case 0x59:
Simulate.UnicodeInput(0xFEE1);
break;
case 0x5a:
break;
}
}
/// <summary>
/// simulate key press
/// </summary>
/// <param name="keyCode"></param>
public static void SendKeyPress(KeyCode keyCode)
{
INPUT input = new INPUT {
Type = 1
};
input.Data.Keyboard = new KEYBDINPUT() {
Vk = (ushort)keyCode,
Scan = 0,
Flags = 0,
Time = 0,
ExtraInfo = IntPtr.Zero,
};
INPUT input2 = new INPUT {
Type = 1
};
input2.Data.Keyboard = new KEYBDINPUT() {
Vk = (ushort)keyCode,
Scan = 0,
Flags = 2,
Time = 0,
ExtraInfo = IntPtr.Zero
};
INPUT[] inputs = new INPUT[] { input, input2 };
if (SendInput(2, inputs, Marshal.SizeOf(typeof(INPUT))) == 0)
throw new Exception();
}
/// <summary>
/// simulate key press
/// </summary>
/// <param name="keyCode"></param>
public static void SendUnicodePress(KeyCode keyCode)
{
INPUT input = new INPUT {
Type = 1
};
input.Data.Keyboard = new KEYBDINPUT() {
Vk = (ushort)keyCode,
Scan = 0,
Flags = 0,
Time = 0,
ExtraInfo = IntPtr.Zero,
};
INPUT input2 = new INPUT {
Type = 1
};
input2.Data.Keyboard = new KEYBDINPUT() {
Vk = (ushort)keyCode,
Scan = 0,
Flags = 2,
Time = 0,
ExtraInfo = IntPtr.Zero
};
INPUT[] inputs = new INPUT[] { input, input2 };
if (SendInput(2, inputs, Marshal.SizeOf(typeof(INPUT))) == 0)
throw new Exception();
}
[StructLayout(LayoutKind.Sequential)]
internal struct INPUT
{
public uint Type;
public MOUSEKEYBDHARDWAREINPUT Data;
}
[StructLayout(LayoutKind.Explicit)]
internal struct MOUSEKEYBDHARDWAREINPUT
{
[FieldOffset(0)]
public HARDWAREINPUT Hardware;
[FieldOffset(0)]
public KEYBDINPUT Keyboard;
[FieldOffset(0)]
public MOUSEINPUT Mouse;
}
[StructLayout(LayoutKind.Sequential)]
internal struct HARDWAREINPUT
{
public uint Msg;
public ushort ParamL;
public ushort ParamH;
}
[StructLayout(LayoutKind.Sequential)]
internal struct KEYBDINPUT
{
public ushort Vk;
public ushort Scan;
public uint Flags;
public uint Time;
public IntPtr ExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
internal struct MOUSEINPUT
{
public int X;
public int Y;
public uint MouseData;
public uint Flags;
public uint Time;
public IntPtr ExtraInfo;
}
}

C# hold key in a game application

I'm trying to make a C# application, which is going to control a game. That I'm trying to do is for example: Hold key A for 150ms, Hold left arrow for 500ms and so on.
I was searching a lot and I found the following code. My program firstly target the game and then holding the keys.
I'm holding the keys this way:
Keyboard.HoldKey(Keys.Left);
Thread.sleep(500);
Keyboard.ReleaseKey(Keys.Left);
Here is the Keyboard class:
public class Keyboard
{
public Keyboard()
{
}
[StructLayout(LayoutKind.Explicit, Size = 28)]
public struct Input
{
[FieldOffset(0)]
public uint type;
[FieldOffset(4)]
public KeyboardInput ki;
}
public struct KeyboardInput
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public long time;
public uint dwExtraInfo;
}
const int KEYEVENTF_KEYUP = 0x0002;
const int INPUT_KEYBOARD = 1;
[DllImport("user32.dll")]
public static extern int SendInput(uint cInputs, ref Input inputs, int cbSize);
[DllImport("user32.dll")]
static extern short GetKeyState(int nVirtKey);
[DllImport("user32.dll")]
static extern ushort MapVirtualKey(int wCode, int wMapType);
public static bool IsKeyDown(Keys key)
{
return (GetKeyState((int)key) & -128) == -128;
}
public static void HoldKey(Keys vk)
{
ushort nScan = MapVirtualKey((ushort)vk, 0);
Input input = new Input();
input.type = INPUT_KEYBOARD;
input.ki.wVk = (ushort)vk;
input.ki.wScan = nScan;
input.ki.dwFlags = 0;
input.ki.time = 0;
input.ki.dwExtraInfo = 0;
SendInput(1, ref input, Marshal.SizeOf(input)).ToString();
}
public static void ReleaseKey(Keys vk)
{
ushort nScan = MapVirtualKey((ushort)vk, 0);
Input input = new Input();
input.type = INPUT_KEYBOARD;
input.ki.wVk = (ushort)vk;
input.ki.wScan = nScan;
input.ki.dwFlags = KEYEVENTF_KEYUP;
input.ki.time = 0;
input.ki.dwExtraInfo = 0;
SendInput(1, ref input, Marshal.SizeOf(input));
}
public static void PressKey(Keys vk)
{
HoldKey(vk);
ReleaseKey(vk);
}
}
and its working in notepad/browser etc, but it IS NOT working in any game, no matter fullscreen or window mode.
Can you help me to figure out how I can hold keys in full screen apps/games?
Thanks!
"Hold key A for 150ms, Hold left arrow for 500ms"
See if this works:
Keyboard.HoldKey((byte)Keys.A, 150);
Keyboard.HoldKey((byte)Keys.Left, 500);
Using:
public class Keyboard
{
[DllImport("user32.dll", SetLastError = true)]
static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
const int KEY_DOWN_EVENT = 0x0001; //Key down flag
const int KEY_UP_EVENT = 0x0002; //Key up flag
public static void HoldKey(byte key, int duration)
{
int totalDuration = 0;
while (totalDuration < duration)
{
keybd_event(key, 0, KEY_DOWN_EVENT, 0);
keybd_event(key, 0, KEY_UP_EVENT, 0);
System.Threading.Thread.Sleep(PauseBetweenStrokes);
totalDuration += PauseBetweenStrokes;
}
}
}
You can get it to work with that, this works great for holding down keys:
public class Keyboard
{
const int PauseBetweenStrokes = 50;
[DllImport("user32.dll", SetLastError = true)]
static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
const int KEY_DOWN_EVENT = 0x0001; //Key down flag
const int KEY_UP_EVENT = 0x0002; //Key up flag
public static void HoldKey(byte key, int duration)
{
keybd_event(key, 0, KEY_DOWN_EVENT, 0);
System.Threading.Thread.Sleep(duration);
keybd_event(key, 0, KEY_UP_EVENT, 0);
}
}
I did it with Windown API and SendInput method.
If you define the Keyboard class as:
public static class Keyboard
{
[DllImport("user32.dll", SetLastError = true)]
static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
public static void Delay(int delay)
{
System.Threading.Thread.Sleep(delay);
}
public static void KeyDown(KEYCODE keycode)
{
keybd_event((byte)keycode, 0x0, 0, 0);// presses
}
public static void KeyPress(KEYCODE keycode, int delay = 0)
{
keybd_event((byte)keycode, 0x0, 0, 0);// presses
System.Threading.Thread.Sleep(delay);
keybd_event((byte)keycode, 0x0, 2, 0); //releases
}
public static void KeyUp(KEYCODE keycode)
{
keybd_event((byte)keycode, 0, 2, 0); //release
}
public static void Type(string message)
{
System.Windows.Forms.SendKeys.SendWait(message);
}
}
and the keycode as
public enum KEYCODE {
VK_A = 0x41, VK_B = 0x42, VK_C = 0x43, VK_D = 0x44, VK_E = 0x45, VK_F = 0x46, VK_G = 0x47,
VK_H = 0x48, VK_I = 0x49, VK_J = 0x4A, VK_K = 0x4B, VK_L = 0x4C, VK_M = 0x4D, VK_N = 0x4E, VK_O = 0x4F,
VK_P = 0x50, VK_Q = 0x51, VK_R = 0x52, VK_S = 0x53, VK_T = 0x54, VK_U = 0x55, VK_V = 0x56, VK_W = 0x57,
VK_X = 0x58, VK_Y = 0x59, VK_Z = 0x5A, VK_LSHIFT = 0xA0, VK_RSHIFT = 0xA1, VK_LCONTROL = 0xA2, VK_RCONTROL = 0xA3
}
You can run the following:
Keyboard.KeyDown(KEYCODE.VK_LSHIFT);
Keyboard.KeyPress(KEYCODE.VK_V);
Keyboard.KeyUp(KEYCODE.VK_LSHIFT);
Keyboard.KeyPress(KEYCODE.VK_I);
Keyboard.KeyPress(KEYCODE.VK_N);
Keyboard.KeyPress(KEYCODE.VK_O);
Keyboard.KeyPress(KEYCODE.VK_D);
And it will print Vinod making V in capital since the shift is pressed.
But if you trying to send multiple keystrokes like typing a text you can use the Keyboard.Type() instead like
Keyboard.Type("+vino+d");
and it will print VinoD making V and D capital for more help see the document here
Even I have written something called Robot.cs which has the complete code of Keyboard, Mouse & Process automation.

Detecting when ListView scrollbar reaches the bottom

How do I know when the WinForms ListView scrollbar reaches it's bottom?
When this happens, I want the listview to be populated with more data (which is endless in theory in my case).
The OnScroll event gives me the scroll value from the top, but I have no way of knowing if the user can scroll any further or not.
I found an answer using some code from the great ObjectListView code-project:
http://www.codeproject.com/KB/list/ObjectListView.aspx
call GetScrollInfo:
private const int SIF_RANGE = 0x0001;
private const int SIF_PAGE = 0x0002;
private const int SIF_POS = 0x0004;
private const int SIF_DISABLENOSCROLL = 0x0008;
private const int SIF_TRACKPOS = 0x0010;
private const int SIF_ALL = (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS);
private const int SB_HORZ = 0;
private const int SB_VERT = 1;
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern bool GetScrollInfo(IntPtr hWnd, int fnBar, SCROLLINFO scrollInfo);
public static SCROLLINFO GetFullScrollInfo(ListView lv, bool horizontalBar) {
int fnBar = (horizontalBar ? SB_HORZ : SB_VERT);
SCROLLINFO scrollInfo = new SCROLLINFO();
scrollInfo.fMask = SIF_ALL;
if (GetScrollInfo(lv.Handle, fnBar, scrollInfo))
return scrollInfo;
else
return null;
}
with this data struct:
[StructLayout(LayoutKind.Sequential)]
public class SCROLLINFO
{
public int cbSize = Marshal.SizeOf(typeof(SCROLLINFO));
public int fMask;
public int nMin;
public int nMax;
public int nPage;
public int nPos;
public int nTrackPos;
}
the nMax gives the total max scroll value including the scroll handle itself, so the actually useful max value is nMax - nPage, where nPage is the size of the scroll handle.
This works great !
I'm not able to answer your question directly, but from your description, it sounds like you really want to look into using the virtual mode of a list view for managing a large dataset.
http://msdn.microsoft.com/en-us/library/system.windows.forms.listview.virtualmode.aspx
In the case somebody needs this, I borrow the above code and I improved a little bit to handle onMaximumBottomScroll event using keyboard with down, next page, and end keys, dragging or clicking the scrollbar and reaching the max bottom, and using the mousewheel on vertically or horizontally. This is working for me like a charm.
public partial class OrganizationFilesListView : ListView
{
// Windows messages
private const int WM_VSCROLL = 0x0115;
private const int WM_MOUSEHWHEEL = 0x020E;
private const int WM_MOUSEWHEEL = 0x020A;
private const int WM_KEYDOWN = 0x0100;
// ScrollBar types
private const int SB_VERT = 1; // only for maximum vertical scroll position
// ScrollBar interfaces
private const int SIF_TRACKPOS = 0x10;
private const int SIF_RANGE = 0x01;
private const int SIF_POS = 0x04;
private const int SIF_PAGE = 0x02;
private const int SIF_ALL = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS;
// variable to force to run only once the event
private bool runningOnMaximumBottomScroll = false;
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
SCROLLINFO si = new SCROLLINFO();
si.cbSize = (uint)Marshal.SizeOf(si);
si.fMask = (uint)ScrollInfoMask.SIF_ALL;
bool isMaximumButtomScroll = false;
switch (m.Msg)
{
case WM_VSCROLL:
isMaximumButtomScroll = GetScrollInfo(m.HWnd, SB_VERT, ref si) ? (si.nPage + si.nPos) >= si.nMax : false;
if (isMaximumButtomScroll && !runningOnMaximumBottomScroll)
{
runningOnMaximumBottomScroll = true;
onMaximumBottomScroll(this, new ScrollEventArgs(ScrollEventType.EndScroll, GetScrollPos(this.Handle, SB_VERT)));
runningOnMaximumBottomScroll = false;
}
break;
case WM_MOUSEHWHEEL:
case WM_MOUSEWHEEL:
isMaximumButtomScroll = GetScrollInfo(m.HWnd, SB_VERT, ref si) ? (si.nPage + si.nPos) >= si.nMax : false;
bool isMouseWheelDown = m.Msg == WM_MOUSEWHEEL ? (int)m.WParam < 0 : (int)m.WParam > 0;
if (isMaximumButtomScroll && isMouseWheelDown && !runningOnMaximumBottomScroll)
{
runningOnMaximumBottomScroll = true;
onMaximumBottomScroll(this, new ScrollEventArgs(ScrollEventType.EndScroll, GetScrollPos(this.Handle, SB_VERT)));
runningOnMaximumBottomScroll = false;
}
break;
case WM_KEYDOWN:
isMaximumButtomScroll = GetScrollInfo(m.HWnd, SB_VERT, ref si) ? (si.nPage + si.nPos) >= (si.nMax - 1) : false;
switch (m.WParam.ToInt32())
{
case (int)Keys.Down:
case (int)Keys.PageDown:
case (int)Keys.End:
if (isMaximumButtomScroll && !runningOnMaximumBottomScroll)
{
runningOnMaximumBottomScroll = true;
onMaximumBottomScroll(this, new ScrollEventArgs(ScrollEventType.EndScroll, GetScrollPos(this.Handle, SB_VERT)));
runningOnMaximumBottomScroll = false;
}
break;
}
break;
}
}
public event ScrollEventHandler onMaximumBottomScroll;
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetScrollInfo(IntPtr hwnd, int fnBar, ref SCROLLINFO lpsi);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int GetScrollPos(IntPtr hWnd, int nBar);
[Serializable, StructLayout(LayoutKind.Sequential)]
struct SCROLLINFO
{
public uint cbSize;
public uint fMask;
public int nMin;
public int nMax;
public uint nPage;
public int nPos;
public int nTrackPos;
}
public enum ScrollInfoMask : uint
{
SIF_RANGE = 0x1,
SIF_PAGE = 0x2,
SIF_POS = 0x4,
SIF_DISABLENOSCROLL = 0x8,
SIF_TRACKPOS = 0x10,
SIF_ALL = (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS),
}
}
Done... enjoy it!

Scrollbar flicker when calling EnableScrollBar

I'm using p/invoke to call EnableScrollBar from user32.dll (MSDN reference). I noticed that when the scrollbar is enabled, it seems to draw as though no theme is applied and then re-drawn with the theme applied. I've only tested with Windows 7 so far. Is there
any way to stop this from happening?
EDIT: Here's some code to show what happens (dump into a form with scrollbars):
private class Native
{
[DllImport("user32.dll")]
public static extern bool EnableScrollBar(IntPtr hWnd, uint wSBflags, uint wArrows);
public static class SBArrows
{
public const uint ESB_ENABLE_BOTH = 0;
public const uint ESB_DISABLE_BOTH = 3;
public const uint ESB_DISABLE_LEFT = 1;
public const uint ESB_DISABLE_RIGHT = 2;
public const uint ESB_DISABLE_UP = 1;
public const uint ESB_DISABLE_DOWN = 2;
public const uint ESB_DISABLE_LTUP = 1;
public const uint ESB_DISABLE_RTDN = 2;
}
public static class SBFlags
{
public const uint SB_HORZ = 0;
public const uint SB_VERT = 1;
public const uint SB_CTL = 2;
public const uint SB_BOTH = 3;
}
}
private bool Switch = false;
protected override void OnMouseDown(MouseEventArgs e)
{
Native.EnableScrollBar(this.Handle, Native.SBFlags.SB_HORZ, this.Switch ? Native.SBArrows.ESB_DISABLE_BOTH : Native.SBArrows.ESB_ENABLE_BOTH);
this.Switch = !this.Switch;
}
Final Solution
Native.SendMessage(this.Handle, Native.WindowMessages.WM_SETREDRAW, new IntPtr(0), IntPtr.Zero);
Native.EnableScrollBar(this.Handle, Native.SBFlags.SB_HORZ, Native.SBArrows.ESB_ENABLE_BOTH);
Native.SendMessage(this.Handle, Native.WindowMessages.WM_SETREDRAW, new IntPtr(1), IntPtr.Zero);
I don't like this solution much. It does however work:
protected override void OnMouseDown(MouseEventArgs e) {
Native.LockWindowUpdate(this.Handle);
Native.EnableScrollBar(this.Handle, Native.SBFlags.SB_HORZ, this.Switch ? Native.SBArrows.ESB_DISABLE_BOTH : Native.SBArrows.ESB_ENABLE_BOTH);
//this.Invalidate();
Native.LockWindowUpdate(IntPtr.Zero);
this.Switch = !this.Switch;
}

Categories

Resources