본문 바로가기

위기관리

웹접근성 : Tab키 활용 시 MouseEvent 와 KeyboardEvent 구분


문제

Tab키를 눌렀을 때 버튼에 focus 가 선택된 상태에서 엔터키를 누르면 MouseEvent 도 같이 발생하므로써 리스너 실행 구간을 두번 반복 호출하는 문제가 생겼습니다. 아래 예제를 보면 Tab키를 누른 후 엔터를 치게되면 두개의 리스너 모두 호출됨을 확인할 수 있습니다.

 

     예제)

     stage.addEventListener( KeyboardEvent.KEY_DOWN, onKeyDownHandler );

     btn.addEventListener( MouseEvent.CLICK, onClickHandler );

 

     private function onKeyDownHandler(): void

     {

          trace( "KeyboardEvent" );

     }

     private function onClickHandler(): void

     {

          trace( "MouseEvent" );

     }

     //출력

     "KeyboardEvent"          <---- 첫번째 출력

     "MouseEvent"             <---- 두번째 출력( 이부분이 출력이 되면 안됨 )

 

     //참고

     Enter키와 Space키 입력 시 이벤트 실행 순서는 시스템이벤트 ---> 인터렉션이벤트 순서로 발생.

 

가정

시스템이벤트( KeyboardEvent )와 인터렉션이벤트( MouseEvent )의 구조를 보면, 기본적으로 Event 클래스를 상속 받고 있습니다.

 

     //상속구조

     KeyboardEvent ---> Event ----> Object

     MouseEvent ---> Event ----> Object

 

언듯보면 Event 클래스를 상속 받았기 때문에 Event 클래스의 stopImmediatePropagation() 메서드를 이용하여, 이벤트 흐름을 제어할 수 있을거 같지만, 실제 구현 과정에서 테스트를 해보니 이벤트타입이 다를 경우 흐름을 제어할 수 없다는 결론을 내리게 됐습니다. 이 부분은 조금 더 연구가 필요할거 같습니다.

 

 

해결

문제를 해결하기에 앞서 각 이벤트의 성향을 집고 넘어가야 합니다. 하나의 버튼에 KeyboardEvent 와 MouseEvent 를 동시에 사용할 때 키보드가 눌리는( KEY_DOWN) 시점에 MouseEvent가 발생한다는 것을  알 수 있습니다. 그럼 해결해야 할 부분은 KeyboardEvent의 KEY_DOWN( 키보드 눌린 ) 시점에 MouseEvent를 받는 리스너 함수 실행구간을 막아주면, 이벤트가 중복 호출되는 문제를 해결할 수 있습니다.

 

     //예제

     var isKeyDown:Boolean = false;

     var selectItem: String = "";


     stage.addEventListener( KeyboardEvent.KEY_DOWN, onKeyboardHandler );

     stage.addEventListener( KeyboardEvent.KEY_UP, onKeyboardHandler );

     btn.addEventListener( MouseEvent.CLICK, onClickHandler);

     btn.addEventListener( FocusEvent.FOCUS_IN, onFocusHandler );

 

     function onFocusHandler( e: FocusEvent ): void
     {
          selectItem = e.currentTarget.name;
          trace( e.currentTarget.name);
     }
     function onKeyboardHandler( e: KeyboardEvent ): void
     { 
          switch( e.type ) {
               case KeyboardEvent.KEY_DOWN :
                    isKeyDown = (e.keyCode == Keyboard.ENTER); //Enter 키일 때 true 설정
                    break;
               case KeyboardEvent.KEY_UP :

                    if( isKeyDown ) {                  
                         trace(selectItem + "에서 키보드 클릭");

                    }
                    isKeyDown = false;

                    break;

          }
     }
     function onClickHandler( e: MouseEvent ): void
     { 
          if ( isKeyDown )  return; //KeyboardEvent.KEY_DOWN 이벤트 발생 시 흐름 중지. 

          trace(e.currentTarget.name + "에서 마우스로 클릭");
     }