Javascript Cookbook

키보드 동작 캡처하기

문제

textarea 요소의 키보드 이벤트를 캡처하고 어떤 문자를 사용했는지 알고 싶다.

해결

textarea 요소의 키보드 동작을 캡처하고 문자의 ASCII 값을 확인한다.

var inputTextArea = document.getElementById("source");
listenEvent(inputTextArea, "keypress", processKeyStroke);
function processKeyStroke(evt){
    evt = evt ? evt : window.event;
    var key = evt.charCode ? evt.charCode : evt.keyCode;
    //문자가 ASCII 38 또는 '&' 인지 확인
    if(key == "38")
        ...
}

설명

키보드와 관련된 이벤트는 다음과 같다.

  • keydown - 키가 눌렸을 때
  • keyup - 키가 올라올 때
  • keypress - keydown 다음
  • textInput - keypress 다음 (사파리 전용)

키가 아래로 눌리면 키가 눌려 있음을 기록하는 keydown 이벤트가 발생한다. 반면 keypress 이벤트는 문자를 입력했을 때 발생한다. 만일 Shift키와 L 키를 눌러 대문자 L을 입력했다면 keydown 이벤트는 두 번 발생하지만 keypress 이벤트는 한 번만 발생한다. keydown 이벤트는 모든 키를 포착하고 싶을 때만 사용해야 한다.

해결에서 이벤트 처리 함수는 이벤트 객체에 접근해서 눌린 키의 ASCII값을 찾았다. 이 값을 사용할 때 브라우저 호환성 문제가 있다. IE와 오페라는 keyCode를 지원하며 사파리, 파이어폭스, 크롬은 charCode를 지원한다.

아래 코드는 필터링을 원하는 ASCII 문자 코드를 물어보고 textarea에서 문자를 입력하면 '필터링'문자는 입력되지 않는다. 예를 들어 '&'는 38로 입력한다. 이 문자를 입력하면 이벤트가 취소되어 keypress의 기본 동작이 중단되므로 문자가 textarea에 입력되지 않는다.

<!DOCTYPE html>
<head>
<title>Filtering Input</title>
<script>

var filteredChar;

function listenEvent(eventTarget, eventType, eventHandler) {
   if (eventTarget.addEventListener) {
      eventTarget.addEventListener(eventType, eventHandler,false);
   } else if (eventTarget.attachEvent) {
      eventType = "on" + eventType;
      eventTarget.attachEvent(eventType, eventHandler);
  } else {
     eventTarget["on" + eventType] = eventHandler;
  }
}

// cancel event
function  cancelEvent (event) {
   if (event.preventDefault) {
      event.preventDefault();
   } else {
      event.returnValue = false;
   }
}

window.onload=function() {
   filteredChar = prompt("Enter the ASCII value of the keyboard key you want to filter","");
   var inputTA = document.getElementById("source");
   listenEvent(inputTA,"keypress",processClick);
}
function processClick(evt) {
   evt = evt || window.event;
   var key = evt.charCode ? evt.charCode : evt.keyCode;

   // zap that bad boy
   if (key == filteredChar) cancelEvent(evt);
}

</script>
</head>
<body>
<form>
<textarea id="source" rows="20" cols="50"></textarea>
</form>
</body>