3

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?

Mauro Ganswer
  • 1,379
  • 1
  • 19
  • 33
  • 1
    Just guessing - would it be possible to hold the "right arrow key down" information in your class and check whether this holds true when "shift" is pressed down as well? You would have to handle the "key up" event to reset that variable, but maybe it's a possibility to do it that way? – Gorgsenegger Jul 03 '12 at 15:42
  • Yes this is an option for managing when the Shift key is pressed, but still I cannot detect when the Shift key is released (while in the meantime the Right arrow have been always held down). I've edited the text in order to comprise your solution – Mauro Ganswer Jul 03 '12 at 20:35
  • Some more research tends to lead me to the assumption that what you want to do is not (in a nice way) possible. The continuously firing KeyDown event indeed seems to stop as soon as the KeyUp for Shift is registered. One question that occurs to me now is why don't you simply use the right arrow key for forward with speed x and the shift key for forward with speed x * 10? You'd have to press more than one key anyway, and this way you wouldn't spend too much time trying to solve this "concurrent key press" problem? – Gorgsenegger Jul 04 '12 at 16:35

2 Answers2

2

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).

Community
  • 1
  • 1
Mauro Ganswer
  • 1,379
  • 1
  • 19
  • 33
0

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.

Joey Dewd
  • 1,804
  • 3
  • 20
  • 43
  • I still do not see a solution for my case: when you have one key held down and you press and then release another key (so you are at the starting point with only the first key still held down), no other key message are processed. – Mauro Ganswer Jul 03 '12 at 20:38
  • True, but for example. You first press the Left key, the bool array keys is now all false except keys[left] (where left is integer of your own choosing) . Now you press right and the keys[right] is set to true. When you press the key you set it to true and in your 'key release' event you set the value to false. They will stay true until you've explicitly said they're false in your key release events. In your logic phase you check for keys that are true and base your actions on those. – Joey Dewd Jul 03 '12 at 21:04
  • Unless I'm missing something, if you try your solution in the code I posted (it's really simple, you just need a Form with a label) it will not work since there will not be any key message to be processed after the second key is pressed and the released. The only way I see it to work is to launch a new Task/Timer in order to continuously check the pressed keys in the bool array, but I do not like too much this solution. – Mauro Ganswer Jul 03 '12 at 21:12