2012-03-05 4 views
0

사용자가 화살표로 이동할 수있는 간단한 응용 프로그램을 만들려고합니다. 지금까지 사용자가 ProcessCmdKey() 메서드를 위, 아래, 왼쪽 및 오른쪽으로 우선적으로 이동할 수 있도록 관리했습니다.화살표 키 감지 - 한 번에 여러 개의 키

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); 
     } 

문제는 사용자가 대각선으로 지나가도록하는 것이 좋습니다. 동시에 똑바로 좋아. 불행히도 운이 없으면 몇 가지 해결책을 찾으려고 노력했습니다. 왼쪽/오른쪽 키를 돌리거나 회전하도록 수정하려고합니다. 위로 키는 "앞으로"가 아니라 "올라 가기"를 의미합니다. 하지만 우선, 나는 2 개의 키를 한 번에 만들 필요가있다.

그래서 문제는 대각선으로 이동하기 위해 2 개의 키를 동시에 사용하는 것이 가능하다는 것입니다.

추신. 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; 
    } 
} 
에서 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를 사용하여 타이머 위스콘신 주변이 시간을. 눌려진 키를 검사 할 함수를 호출하고, ArrowsPressed 열거를 구성하고, 함수를 호출하여 을 호출하여 이동을 실행합니다. 다른 키를 사용하려면 virtualKeyToArrowsPressed Dictionary에 넣으십시오.

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 
}