2012-03-05 2 views
0

Я пытаюсь сделать простое приложение, которое позволяет пользователю перемещаться со стрелками. До сих пор мне удалось позволить пользователю перемещаться вверх, вниз, влево и вправо, переопределяя метод ProcessCmdKey().Detect Arrow Keys - Несколько ключей сразу

protected override bool ProcessCmdKey(ref Message msg, Keys keyData) 
     { 
      if (keyData == Keys.Up) 
      { 
       statek.Y--; 
       return true; 
      } 
      if (keyData == Keys.Left) 
      { 
       statek.X--; 
       return true; 
      } 
      if (keyData == Keys.Right) 
      { 
       statek.X++; 
       return true; 
      } 
      if (keyData == Keys.Down) 
      { 
       statek.Y++; 
       return true; 
      } 
      return base.ProcessCmdKey(ref msg, keyData); 
     } 

Проблема заключается в том, что я хотел бы позволить пользователю перейти по диагонали. Как вверх, так и в то же время. Я попытался найти некоторые решения, но, к сожалению, не повезло. Я попытаюсь изменить его, чтобы клавиши влево/вправо поворачивались/вращаются, поэтому клавиша «вверх» означает «вперед», а не «подниматься». Но в первую очередь мне нужно сделать сразу два ключа.

Итак, вопрос в том, как я могу сделать возможным использовать два ключа одновременно, чтобы двигаться по диагонали?

PS. Atm, я перемещаю эллипс на картинке, меняя Point statek = new Point(250, 470); шнуры, поэтому каждый таймер тикает, он проверяет, изменился ли X или Y, и нарисуйте его на новом месте. Часто клепки - вот как я пытался добиться движения в реальном времени на данный момент. Это не будет сложным приложением.

ответ

2

Сначала нужно создать битовую перечисление держать клавиши со стрелками говорится:

[Flags] 
enum ArrowsPressed 
{ 
    None = 0x00, 
    Left = 0x01, 
    Right = 0x02, 
    Up = 0x04, 
    Down = 0x08, 
    All = 0x0F 
} 

Затем член отслеживать состояние и функции, чтобы изменить его;

ArrowsPressed arrowsPressed; 

void ChangeArrowsState(ArrowsPressed changed, bool isPressed) 
{ 
    if (isPressed) 
    { 
     arrowsPressed |= changed; 
    } 
    else 
    { 
     arrowsPressed &= ArrowsPressed.All^changed; 
    } 
} 

Override KeyDown и KeyUp (не забудьте установить KeyPreview свойство формы к истине, чтобы форма получить ключи в случае управления ребенок хочет, чтобы украсть их,

protected override void OnKeyDown(KeyEventArgs e) 
{ 
    base.OnKeyDown(e); 
    switch (e.KeyCode) 
    { 
     case Keys.Down: 
      ChangeArrowsState(ArrowsPressed.Down, true); 
      break; 
     case Keys.Up: 
      ChangeArrowsState(ArrowsPressed.Up, true); 
      break; 
     case Keys.Left: 
      ChangeArrowsState(ArrowsPressed.Left, true); 
      break; 
     case Keys.Right: 
      ChangeArrowsState(ArrowsPressed.Right, true); 
      break; 
     default: 
      return; 
    } 
    HandleArrows(); 
    e.Handled = true; 
} 
protected override void OnKeyUp(KeyEventArgs e) 
{ 
    base.OnKeyUp(e); 
    switch (e.KeyCode) 
    { 
     case Keys.Down: 
      ChangeArrowsState(ArrowsPressed.Down, false); 
      break; 
     case Keys.Up: 
      ChangeArrowsState(ArrowsPressed.Up, false); 
      break; 
     case Keys.Left: 
      ChangeArrowsState(ArrowsPressed.Left, false); 
      break; 
     case Keys.Right: 
      ChangeArrowsState(ArrowsPressed.Right, false); 
      break; 
     default: 
      return; 
    } 
    e.Handled = true; 
} 

Наконец, используя структура точки провести тест позиции все отслеживаемые ключи и переместить точку в направлении они указывают,

Point position; 
private void HandleArrows() 
{ 
    if ((arrowsPressed & ArrowsPressed.Down) != ArrowsPressed.None) 
    { 
     position.Y++; 
    } 
    if ((arrowsPressed & ArrowsPressed.Up) != ArrowsPressed.None) 
    { 
     position.Y--; 
    } 
    if ((arrowsPressed & ArrowsPressed.Left) != ArrowsPressed.None) 
    { 
     position.X--; 
    } 
    if ((arrowsPressed & ArrowsPressed.Right) != ArrowsPressed.None) 
    { 
     position.X++; 
    } 
    // Do whatever is needed using position 
} 
+0

Это хороший ответ. –

+0

Не работает, ключ перестает повторяться. Требуется таймер. –

+0

@ Ханс Да, вы абсолютно правы. Windows отправляет сообщения WM_KEYDOWN для последней нажатой клавиши. Когда эта клавиша отпускается, движение останавливается. Таймер, безусловно, поможет в этой ситуации, но если использовать таймер, он будет платить за использование Pinvoke для GetKeyboardState. –

2

Вам нужно сохранить список типов всех ключей, находящихся в настоящее время в состоянии Key_Down.

Это позволяет вам отслеживать, какие клавиши нажаты, и решить, какие комбинации действительны.

Каждое событие срабатывает один раз за одно нажатие клавиши. Таким образом, обнаружение двух ключей в одном событии невозможно, но вы можете отследить эту информацию в коллекции, ограниченной вне ваших событий.

1

Улучшенная версия с использованием GetKeyboardState на этот раз вокруг Wi таймера. ll вызывать функцию, которая будет проверять нажатые клавиши, построить перечисление ArrowsPressed и вызвать функцию для выполнения движения. Если вы хотите использовать какой-либо другой ключ, поместите его в словарь virtualKeyToArrowsPressed.

const int VK_LEFT = 0x25; 
const int VK_UP = 0x26; 
const int VK_RIGHT = 0x27; 
const int VK_DOWN = 0x28; 

[DllImport("user32.dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
static extern bool GetKeyboardState(byte[] lpKeyState); 

byte[] keys = new byte[256]; 

[Flags] 
enum ArrowsPressed 
{ 
    None = 0x00, 
    Left = 0x01, 
    Right = 0x02, 
    Up = 0x04, 
    Down = 0x08, 
    All = 0x0F 
} 
Dictionary<int, ArrowsPressed> virtualKeyToArrowsPressed = new Dictionary<int, ArrowsPressed> 
{ 
    { VK_LEFT, ArrowsPressed.Left }, 
    { VK_RIGHT, ArrowsPressed.Right }, 
    { VK_UP, ArrowsPressed.Up }, 
    { VK_DOWN, ArrowsPressed.Down }, 
}; 

protected override void OnLoad(EventArgs e) 
{ 
    base.OnLoad(e); 

    timer1.Tick += timer1_Tick; 
    timer1.Interval = 100; 
    timer1.Start(); 
} 

void timer1_Tick(object sender, EventArgs e) 
{ 
    if (GetKeyboardState(keys)) 
    { 
     ArrowsPressed arrowsPressed = ArrowsPressed.None; 
     foreach (KeyValuePair<int, ArrowsPressed> kvp in virtualKeyToArrowsPressed) 
     { 
      if ((keys[kvp.Key] & 0x80) != 0) 
      { 
       arrowsPressed |= kvp.Value; 
      } 
     } 
     if (arrowsPressed != ArrowsPressed.None) 
     { 
      HandleArrows(arrowsPressed); 
     } 
    } 
} 

Point position; 
private void HandleArrows(ArrowsPressed arrowsPressed) 
{ 
    if ((arrowsPressed & ArrowsPressed.Down) != ArrowsPressed.None) 
    { 
     position.Y++; 
    } 
    if ((arrowsPressed & ArrowsPressed.Up) != ArrowsPressed.None) 
    { 
     position.Y--; 
    } 
    if ((arrowsPressed & ArrowsPressed.Left) != ArrowsPressed.None) 
    { 
     position.X--; 
    } 
    if ((arrowsPressed & ArrowsPressed.Right) != ArrowsPressed.None) 
    { 
     position.X++; 
    } 
    // Do whatever is needed using position 
} 
Смежные вопросы