보통 WinForms TextBox는 Ctrl+C, Ctrl+V 같은 기본 편집 단축키가 그냥 됩니다. 그런데 폼 구성에 따라 이게 먹지 않는 경우가 있습니다. 메뉴에 같은 단축키가 등록돼 있거나, 폼이나 상위 컨트롤이 키 입력을 먼저 가로채면 텍스트 박스까지 키가 오지 않죠. 그럴 때 쓸 수 있는 방법을 세 가지 단계로 정리합니다.
PreviewKeyDown에서 IsInputKey 켜기
가장 간단한 방법은 PreviewKeyDown 이벤트에서 Ctrl이 눌린 키를 "이 컨트롤이 직접 처리할 입력 키"로 표시하는 것입니다.
Private Sub TextBox1_PreviewKeyDown(sender As Object, e As PreviewKeyDownEventArgs) Handles TextBox1.PreviewKeyDown
If e.Control Then e.IsInputKey = True
End Sub
PreviewKeyDown은 키가 컨트롤로 전달되기 전에 먼저 발생하는 이벤트입니다. 여기서 IsInputKey = True로 해 두면 그 키 조합을 단축키 처리 단계에서 가로채지 않고 텍스트 박스에 넘겨 줍니다. 그래서 Ctrl+C·V·X·A·Z가 텍스트 박스 본래 동작대로 돌아옵니다.
모든 텍스트 박스에 적용하려면
화면마다 이벤트를 다는 대신 TextBox를 상속한 사용자 정의 컨트롤을 만들어 쓰면 프로젝트 전체에 한 번에 적용할 수 있습니다. 원래 올렸던 코드는 이렇습니다.
Public Class TextBox
Inherits Windows.Forms.TextBox
Private Overloads Sub OnPreviewKeyDown(e As PreviewKeyDownEventArgs)
MyBase.OnPreviewKeyDown(e)
If e.Control Then e.IsInputKey = True
End Sub
End Class
그런데 이 형태는 Private Overloads라서 기본 클래스의 OnPreviewKeyDown을 재정의하지 않습니다. 컨트롤 내부에서는 원래의 가상 메서드가 불리기 때문에 이 메서드가 실행되지 않을 가능성이 큽니다. 재정의하려면 Protected Overrides로 선언해야 합니다(아래는 그렇게 고친 형태입니다).
Public Class TextBox
Inherits Windows.Forms.TextBox
Protected Overrides Sub OnPreviewKeyDown(e As PreviewKeyDownEventArgs)
MyBase.OnPreviewKeyDown(e)
If e.Control Then e.IsInputKey = True
End Sub
End Class
클래스 이름을 TextBox로 지으면 같은 프로젝트 안에서는 이 클래스가 기본 TextBox보다 먼저 잡히므로, 디자이너 코드의 형식만 바꿔 주면 기존 화면에도 그대로 적용할 수 있습니다. 헷갈리는 게 싫다면 CopyTextBox처럼 다른 이름을 쓰는 편이 낫습니다.
KeyDown에서 직접 처리하기
Visual Studio 버전이나 폼 구성에 따라 위 방법으로도 안 되는 경우가 있었습니다. 그럴 때는 KeyDown에서 키 조합을 직접 확인하고 텍스트 박스의 편집 메서드를 불러 줍니다.
Private Sub textBox1_KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs)
Me.OnKeyDown(e)
If e.Modifiers = Keys.Control AndAlso e.KeyCode = Keys.C Then
textBox1.Copy()
End If
If e.Modifiers = Keys.Control AndAlso e.KeyCode = Keys.V Then
Me.textBox1.Paste()
End If
If e.Modifiers = Keys.Control AndAlso e.KeyCode = Keys.X Then
Me.textBox1.Cut()
End If
If e.Modifiers = Keys.Control AndAlso e.KeyCode = Keys.A Then
Me.textBox1.SelectAll()
End If
If e.Modifiers = Keys.Control AndAlso e.KeyCode = Keys.Z Then
Me.textBox1.Undo()
End If
End Sub
Copy, Paste, Cut, SelectAll, Undo는 모두 TextBox가 원래 갖고 있는 메서드라 클립보드를 직접 다룰 필요가 없습니다. 이 메서드에는 Handles 절이 없으니 AddHandler textBox1.KeyDown, AddressOf textBox1_KeyDown으로 연결하거나 Handles textBox1.KeyDown을 붙여야 동작합니다. 그리고 원래 단축키가 일부라도 살아 있는 상태라면 붙여넣기가 두 번 되는 일이 생길 수 있으니, 처리한 키는 e.SuppressKeyPress = True로 막아 두는 게 안전합니다.
순서로 보면 먼저 메뉴(MenuStrip, ContextMenuStrip)에 같은 단축키가 걸려 있는지, 텍스트 박스의 ShortcutsEnabled가 False로 되어 있지 않은지부터 확인하고, 그래도 안 되면 PreviewKeyDown, 마지막으로 KeyDown 직접 처리 순으로 시도해 보면 됩니다.