Reputation: 1419
In my application I allow the user to scroll a movie by holding down the Right arrow key by using ProcessCmdKey
. Now I would like to give the user the ability to increase the scrolling speed whenever desired. Ideally the user should be able to hold down the Right arrow key, then when he decides to increase the speed he should, without releasing the Right arrow key, hold down also the Shift key and when he decides to go back to the normal speed he should simply release back the Shift key. So the difference in the scrolling speed should be given only from Shift key modifier that should be added or removed to the Right arrow key pressure.
I tried a code like this but with no success (I've a simple label in my form in this test example):
int count = 0;
bool keyRightDown = false;
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Right)
{
keyRightDown = true;
count++;
label.Text = "count = " + count.ToString();
return true;
}
if (keyData == (Keys.Shift | Keys.ShiftKey) && keyRightDown)
{
count += 10;
label.Text = "count = " + count.ToString();
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
protected override bool ProcessKeyMessage(ref Message m)
{
if ((Keys)m.WParam == Keys.Right)
{
if (m.Msg == 0x101) // KEYUP
{
keyDown = false;
return true;
}
}
return base.ProcessKeyMessage(ref m);
}
When the user add the Shift key to the Right arrow the keyData
does not contain (Keys.Shift | Keys.Right)
as I was expecting but (Keys.Shift | Keys.ShiftKey)
. However this issue can still be solved by the boolean keyRightDown
. The main problem is that when the user release back the Shift key by having at this point only the Right arrow pressed, no other calls to neither ProcessCmdKey
nor ProcessKeyMessage
are triggered. How can I achieve my goal?
Upvotes: 3
Views: 2536
Reputation: 1419
The only way I found was to use a combination of calling the GetKeyState
API function (user32.dll) and of a Timer
. Here is as it works on the test app:
System.Windows.Forms.Timer keyManagerTimer = new System.Windows.Forms.Timer();
int count = 0;
public Form1()
{
InitializeComponent();
this.keyManagerTimer.Tick += (s, e) => ProcessKeys();
this.keyManagerTimer.Interval = 25;
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if ((keyData & Keys.Right) != 0)
{
keyManagerTimer.Enabled = true;
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
private void ProcessKeys()
{
bool isShiftKeyPressed = IsKeyPressed(Keys.ShiftKey);
bool isRightKeyPressed = IsKeyPressed(Keys.Right);
if (isRightKeyPressed && !isShiftKeyPressed)
{
count++;
}
else if (isRightKeyPressed && isShiftKeyPressed)
{
count += 10;
}
label.Text = "count = " + count.ToString();
}
public static bool IsKeyPressed(Keys key)
{
return BitConverter.GetBytes(GetKeyState((int)key))[1] > 0;
}
[DllImport("user32")]
private static extern short GetKeyState(int vKey);
In my real code then I disable the Timer
on the Leave
event of the Control
where I have the video. Possibly another solution might have been to use the IMessageFilter (see here).
Upvotes: 2
Reputation: 1824
A possible solution is to store all possible key presses in a bool array then check the bool array if certain values are true. In the case of holding down your button you'd set the button key to true and back to false when the key is released. This is an option I ussualy tend to use when I need to check for multiple key presses.
Upvotes: 0