bind — X 이벤트가 Tcl 스크립트를 호출하도록 연결하기

bind — X 이벤트가 Tcl 스크립트를 호출하도록 연결하기

Tk의 이벤트 기반 프로그래밍에서 가장 중심이 되는 명령어가 bind예요. X 이벤트(키 입력, 버튼 클릭, 마우스 이동 등)를 Tcl 스크립트와 연결해주거든요. 이벤트 패턴을 어떻게 쓰는지, 바인딩 스크립트에서 % 치환으로 이벤트 정보를 어떻게 꺼내는지, 여러 바인딩이 겹칠 때 어떤 규칙으로 선택되는지를 이해하면 GUI 인터랙션을 자유자재로 다룰 수 있어요.

출처: 문서

본문

문법

bind tag ?sequence? ?+??script?

bind 명령어는 Tcl 스크립트를 X 이벤트와 연결해요.

  • 세 인자가 모두 지정되면, bindtag가 식별하는 윈도우(들)에서 sequence가 주는 이벤트(들)가 발생할 때마다 script(binding script라고 부르는 Tcl 스크립트)가 평가되도록 정리해요.
  • script 앞에 +가 붙으면 기존 sequence 바인딩에 추가되고, 그렇지 않으면 기존 바인딩을 대체해요.
  • script가 빈 문자열이면 sequence의 현재 바인딩이 파괴되어 sequence가 바인딩되지 않은 상태로 남아요.
  • script 인자가 제공되는 모든 경우에 bind는 빈 문자열을 반환해요.

sequencescript 없이 지정되면, 현재 sequence에 바인딩된 스크립트를 반환하거나, sequence에 바인딩이 없으면 빈 문자열을 반환해요. sequencescript도 지정되지 않으면, 반환값은 tag에 대해 바인딩이 존재하는 모든 시퀀스의 원소가 되는 리스트예요.

tag 인자는 바인딩이 적용되는 윈도우(들)를 결정해요. tag.a.b.c처럼 점으로 시작하면 그 윈도우의 경로 이름이어야 하고, 그렇지 않으면 임의의 문자열일 수 있어요.

각 윈도우는 연결된 태그 리스트를 가지고 있고, 바인딩은 그 태그가 윈도우에 지정된 태그들 중 하나일 때 특정 윈도우에 적용돼요. bindtags 명령어로 윈도우에 임의의 binding tag 집합을 할당할 수 있지만, 기본 binding tag는 다음 동작을 제공해요.

  • 태그가 내부(internal) 윈도우의 이름이면 바인딩은 그 윈도우에 적용돼요.
  • 태그가 Button 같은 위젯 클래스의 이름이면 바인딩은 그 클래스의 모든 위젯에 적용돼요.
  • 태그가 toplevel 윈도우의 이름이면 바인딩은 그 toplevel 윈도우와 모든 내부 윈도우에 적용돼요.
  • tagall이면 바인딩은 애플리케이션의 모든 윈도우에 적용돼요.

이벤트 패턴

sequence 인자는 하나 이상의 이벤트 패턴 시퀀스를 지정하며, 패턴 사이에 선택적으로 공백을 둘 수 있어요. 각 이벤트 패턴은 세 가지 형태 중 하나일 수 있어요.

가장 단순한 경우는 a[ 같은 하나의 인쇄 ASCII 문자예요. 이 문자는 공백 문자나 < 문자일 수 없어요. 이 형태의 패턴은 그 특정 문자의 KeyPress 이벤트에 매칭돼요.

두 번째 형태는 더 길지만 더 일반적이고, 다음 문법을 가져요:

<modifier-modifier-type-detail>

전체 이벤트 패턴이 꺾쇠 괄호로 감싸여 있어요. 꺾쇠 안에는 0개 이상의 수식자(modifier), 하나의 이벤트 유형(type), 특정 버튼이나 keysym을 식별하는 추가 정보(detail)가 있어요. type과 detail 중 적어도 하나가 있으면 어떤 필드든 생략할 수 있어요. 필드들은 공백이나 대시로 구분해야 해요.

세 번째 형태는 사용자가 정의한 이름 있는 가상 이벤트(virtual event)를 지정하는 데 써요:

<<name>>

전체 가상 이벤트 패턴은 이중 꺾쇠 괄호로 감싸여 있어요. 꺾쇠 안에는 사용자가 정의한 가상 이벤트의 이름이 있어요. ShiftControl 같은 수식자를 가상 이벤트와 결합해 수정할 수는 없어요. 가상 이벤트의 바인딩은 그 가상 이벤트가 정의되기 전에 만들 수 있고, 정의가 동적으로 바뀌면 그 가상 이벤트에 바인딩된 모든 윈도우가 새 정의에 즉시 응답해요.

일부 위젯(예: menu, text)은 내부 상태가 어떤 식으로 갱신될 때 가상 이벤트를 발행해요. 자세한 내용은 각 위젯의 매뉴얼 페이지를 참조하세요.

수식자(Modifiers)

수식자는 다음 값 중 어느 것으로든 구성돼요:

Control  Mod1, M1, Command   Alt  Mod2, M2, Option  Shift  Mod3, M3, Lock
Mod4, M4, Extended  Mod5, M5   Button1, B1  Meta, M   Button2, B2, Double
Button3, B3, Triple  Button4, B4, Quadruple  Button5, B5

여러 값이 쉼표로 나열되어 있으면 그 값들은 동등해요. 대부분의 수식자는 명백한 X 의미를 가져요. 예를 들어 Button1은 이벤트 발생 시 버튼 1이 눌려 있어야 함을 요구해요.

바인딩이 주어진 이벤트에 매칭되려면, 이벤트의 수식자가 이벤트 패턴에 지정된 수식자를 모두 포함해야 해요. 이벤트에는 바인딩에 지정되지 않은 추가 수식자도 있을 수 있어요. 예를 들어 변환(shift) 키와 컨트롤 키를 누른 채 버튼 1을 누르면, <Control-Button-1> 패턴은 그 이벤트에 매칭되지만 <Mod1-Button-1>은 매칭되지 않아요. 수식자를 지정하지 않으면 이벤트에 어떤 수식자 조합이 있어도 무방해요.

MetaM은 키보드의 Meta 키(키심 Meta_RMeta_L)에 연결된 M1~M5 수식자 중 어느 것을 가리켜요. Meta 키가 없거나 어떤 수식자에도 연결되지 않았다면 MetaM은 어떤 이벤트에도 매칭되지 않아요. 마찬가지로 Alt 수식자는 키보드의 alt 키(키심 Alt_LAlt_R)에 연결된 수식자를 가리켜요.

Double, Triple, Quadruple 수식자는 더블 마우스 클릭과 다른 반복 이벤트를 지정하는 편의 수단이에요. 이들은 특정 이벤트 패턴을 2, 3, 4번 반복하게 하고, 시퀀스에 시간·공간 요구도 추가해요: Double, Triple, Quadruple 패턴이 매칭되려면 시퀀스의 모든 이벤트가 시간적으로 가까이, 사이에 큰 마우스 이동 없이 발생해야 해요. 예를 들어 <Double-Button-1>은 추가 시간·공간 요구가 붙은 <Button-1><Button-1>과 동등해요.

CommandOption 수식자는 각각 Mod1Mod2의 동등물로, Macintosh 특유의 수식자 키에 대응해요.

Extended 수식자는 현재 Windows에만 한정돼요. 확장 키보드의 키와 연결된 이벤트에 나타나요. US 키보드에서 확장 키에는 키보드 오른쪽의 Alt·Control 키, 숫자 패드 왼쪽의 커서 키, NumLock 키, Break 키, PrintScreen 키, 숫자 키패드의 /Enter 키가 포함돼요.

이벤트 유형

type 필드는 몇 가지 추가 약어와 함께 표준 X 이벤트 유형 중 아무 것이나 될 수 있어요. Macintosh와 Windows 플랫폼을 더 잘 지원하기 위해 추가된 비표준 X 이벤트 유형 몇 가지도 받아들여요. 유효한 유형의 전체 목록은 다음과 같아요(두 이름이 함께 나타나면 동의어).

Activate  Destroy  Map  ButtonPress, Button  Enter  MapRequest  ButtonRelease
Expose  Motion  Circulate  FocusIn  MouseWheel  CirculateRequest  FocusOut
Property  Colormap  Gravity  Reparent  Configure  KeyPress, Key  ResizeRequest
ConfigureRequest  KeyRelease  Unmap  Create  Leave  Visibility  Deactivate

위 이벤트 대부분은 X 윈도우 시스템의 이벤트와 같은 필드·동작을 가져요. 이 이벤트들의 더 자세한 설명은 어떤 X 윈도우 프로그래밍 책에서도 찾을 수 있어요. 이벤트 몇 개는 Macintosh와 Windows 플랫폼 고유의 기능을 지원하기 위한 X 이벤트 시스템의 확장이에요. 이 이벤트들에 대해 좀 더 자세히 설명할게요.

Activate, Deactivate — 이 두 이벤트는 toplevel의 상태가 바뀔 때 그 toplevel의 모든 하위 윈도우로 보내져요. 포커스 윈도우에 더해 Macintosh와 Windows 플랫폼에는 활성(active) 윈도우라는 개념이 있어요(흔히 포커스를 갖지만 필수는 아니에요). Macintosh에서 활성 윈도우의 위젯은 비활성 윈도우의 위젯과 다른 모양이에요. Activate 이벤트는 toplevel이 비활성에서 활성으로 바뀔 때 모든 하위 윈도우로 보내지고, Deactivate 이벤트는 윈도우 상태가 활성에서 비활성으로 바뀔 때 보내져요. 이 이벤트들에 바인딩할 때 쓸 만한 퍼센트 치환은 없어요.

MouseWheel — 많은 현대 마우스가 스크롤바 없이 문서를 스크롤하는 데 쓰는 마우스 휠을 지원해요. 휠을 돌리면 시스템이 애플리케이션이 스크롤에 쓸 수 있는 MouseWheel 이벤트를 생성해요. 이 이벤트는 현재 마우스 포인터 아래 있는 윈도우로 라우팅돼요. 이벤트를 받으면 %D 치환으로 이벤트의 delta 필드를 얻을 수 있는데, 마우스 휠이 어떻게 움직였는지 설명하는 정수 값이에요. 시스템이 보고하는 최소값은 OS가 정의해요. 값의 부호는 위젯이 어느 방향으로 스크롤해야 하는지 결정해요. 양수 값은 위로, 음수 값은 아래로 스크롤해야 해요.

가로 스크롤은 Shift-MouseWheel 이벤트를 쓰며, 양수 %D delta 치환은 왼쪽으로, 음수는 오른쪽으로 스크롤함을 나타내요. MouseWheelShift-MouseWheel 이벤트를 발생시키는 것은 주로 Windows와 macOS Aqua예요. X11에서 세로 스크롤은 Button-4Button-5 이벤트를 통해, 가로 스크롤은 Shift-Button-4Shift-Button-5 이벤트를 통해 지원돼요. 가로 스크롤 이벤트는 틸트 휠이나 터치패드 같은 다양한 하드웨어 장치에서 발생할 수 있어요. 가로 스크롤은 Shift를 누른 채 세로로 스크롤해도 에뮬레이션할 수 있어요.

KeyPress, KeyRelease — 키가 눌리거나 떼어질 때마다 생성돼요. KeyPressKeyRelease 이벤트는 현재 키보드 포커스를 가진 윈도우로 보내져요.

ButtonPress, ButtonRelease, Motion — 사용자가 마우스 버튼을 누르거나 떼면 ButtonPressButtonRelease 이벤트가 생성되고, 포인터를 움직이면 Motion 이벤트가 생성돼요. ButtonPress, ButtonRelease, Motion 이벤트는 보통 포인터를 포함하는 윈도우로 보내져요.

마우스 버튼을 누르면 포인터를 포함하는 윈도우가 자동으로 임시 포인터 그래브를 얻어요. 이후 ButtonPress, ButtonRelease, Motion 이벤트는 모든 버튼이 떼어질 때까지 포인터가 어느 윈도우에 있든 그 윈도우로 보내져요.

Configure — 크기, 위치, 또는 경계(border) 너비가 바뀔 때, 그리고 때때로 스태킹 순서에서 위치가 바뀌었을 때 윈도우로 보내져요.

Map, Unmap — 윈도우의 매핑 상태가 바뀔 때마다 생성돼요. 윈도우는 언매핑 상태로 만들어져요. Toplevel 윈도우는 normal 상태로 전환될 때 매핑되고, withdrawn·iconic 상태에서는 언매핑돼요. 다른 윈도우는 geometry manager(예: pack이나 grid)의 제어 아래 놓일 때 매핑돼요. 윈도우는 그 자신과 모든 조상이 매핑된 경우에만 볼 수(viewable) 있어요. geometry manager는 보통 자신이 매핑될 때까지 자식을 매핑하지 않고, 자기 자신이 언매핑될 때 모든 자식을 언매핑한다는 점에 유의하세요. 따라서 Tk에서 Map·Unmap 이벤트는 윈도우가 볼 수 있는지 여부를 나타내요.

Visibility — 스태킹 순서에서 위에 있는 다른 윈도우가 윈도우를 완전히 또는 부분적으로 겹치면 그 윈도우는 가려졌다(obscured)고 말해요. Visibility 이벤트는 윈도우의 가림 상태가 바뀔 때마다 생성되고, state 필드(%s)가 새 상태를 지정해요.

Expose — 윈도우의 전부 또는 일부를 다시 그려야 할 때마다 생성돼요(예: 윈도우가 처음 매핑되거나 가려지지 않게 될 때). Tk가 내부적으로 처리하므로 클라이언트 애플리케이션이 Expose 이벤트를 처리할 필요는 보통 없어요.

Destroy — 윈도우가 파괴될 때 그 윈도우로 전달돼요. Destroy 이벤트가 위젯에 전달될 때 그 위젯은 '반쯤 죽은' 상태예요. 위젯은 여전히 존재하지만 관련 연산이 유효하지 않은 결과를 반환하거나 오류를 반환할 수 있어요.

FocusIn, FocusOut — 키보드 포커스가 바뀔 때마다 생성돼요. FocusOut 이벤트는 이전 포커스 윈도우로, FocusIn 이벤트는 새 포커스 윈도우로 보내져요. 또한 이전·새 포커스 윈도우가 공통 부모를 공유하지 않으면, 계층의 중간 윈도우에 가상 교차(crossing) 포커스 이벤트가 보내져요. 따라서 FocusIn 이벤트는 대상 윈도우나 그 하위 중 하나가 포커스를 얻었음을, FocusOut 이벤트는 포커스가 대상 윈도우 계층 밖의 윈도우로 바뀌었음을 나타내요. 키보드 포커스는 focus 호출로 명시적으로, 또는 윈도우 매니저가 암묵적으로 바꿀 수 있어요.

Enter, Leave — 포인터가 윈도우에 들어오면 Enter 이벤트가, 떠나면 Leave 이벤트가 그 윈도우로 보내져요. 포인터 그래브가 적용 중이면 EnterLeave 이벤트는 그래브를 소유한 윈도우에만 전달돼요. 또한 포인터가 두 윈도우 사이를 이동할 때 FocusIn/FocusOut 이벤트와 같은 방식으로 계층의 중간 윈도우에 가상 교차 Enter·Leave 이벤트가 보내져요.

Property — 윈도우에 속한 X 속성이 바뀌거나 삭제될 때마다 그 윈도우로 보내져요. Property 이벤트는 Tk 코어가 처리하므로 보통 Tk 애플리케이션에 전달되지 않아요.

Colormap — 윈도우에 연결된 컬러맵이 바뀌거나, 설치되거나, 설치 해제될 때마다 생성돼요. -colormap 옵션을 지정해 위젯에 전용 컬러맵을 할당할 수 있고, 필요에 따라 컬러맵을 설치·해제하는 책임은 윈도우 매니저에게 있어요. Tk는 이 이벤트 유형에 쓸 만한 세부 사항을 제공하지 않는다는 점에 유의하세요.

MapRequest, CirculateRequest, ResizeRequest, ConfigureRequest, Create — 이 이벤트는 보통 Tk 애플리케이션에 전달되지 않아요. Tk로 X11 윈도우 매니저를 작성할 수 있게 하기 위해 완전성을 위해 포함돼 있어요. (이 이벤트들은 클라이언트가 윈도우에 SubstructureRedirectMask를 선택한 경우에만 전달되는데, Tk 코어는 이 마스크를 사용하지 않아요.)

Gravity, Reparent, CirculateGravityReparent 이벤트는 보통 Tk 애플리케이션에 전달되지 않아요. 완전성을 위해 포함돼 있어요. Circulate 이벤트는 XCirculateSubwindows 프로토콜 요청의 결과로 윈도우가 스태킹 순서의 위나 아래로 이동했음을 나타내요. 스태킹 순서는 Circulate 이벤트를 생성하지 않는 다른 이유로 바뀔 수 있고, Tk는 내부적으로 XCirculateSubwindows()를 사용하지 않는다는 점에 유의하세요. 이 이벤트 유형은 완전성을 위해서만 포함돼 있으며, 윈도우의 스태킹 순서 위치 변경을 추적할 신뢰할 만한 방법은 없어요.

이벤트 상세(detail)

긴 이벤트 지정의 마지막 부분이 detail이에요.

  • ButtonPressButtonRelease 이벤트의 경우, 누르거나 뗀 버튼의 번호(1–5)예요. 버튼 번호를 주면 그 특정 버튼의 이벤트만 매칭되고, 버튼 번호를 주지 않으면 아무 버튼의 이벤트가 매칭돼요. 주의: 특정 버튼 번호를 주는 것은 버튼 수식자를 지정하는 것과 달라요. 전자는 눌리거나 떼어지는 버튼을 가리키고, 후자는 매칭 이벤트가 발생할 때 이미 눌려 있는 다른 버튼을 가리켜요.
  • 버튼 번호를 주면 type은 생략할 수 있는데, 기본값이 ButtonPress로 정해져요. 예를 들어 <1><ButtonPress-1>과 동등해요.

이벤트 유형이 KeyPressKeyRelease이면 detail은 X keysym 형태로 지정할 수 있어요. Keysym은 키보드 특정 키의 텍스트 명세예요. 모든 영숫자 ASCII 문자(예: a는 ASCII 문자 a의 keysym)와, 비영숫자 문자의 설명(comma는 콤마 문자의 keysym), 키보드의 모든 비-ASCII 키 설명(예: Shift_L은 왼쪽 Shift 키의 keysym, F1은 F1 기능 키(존재한다면)의 keysym)을 포함해요. keysym 전체 목록은 여기서 다루지 않아요. 다른 X 문서에서 볼 수 있고 시스템마다 다를 수 있어요. 필요하면 아래에 설명하는 %K 표기로 특정 키의 keysym 이름을 출력할 수 있어요.

keysym detail을 주면 type 필드는 생략할 수 있고 기본값은 KeyPress예요. 예를 들어 <Control-comma><Control-KeyPress-comma>와 동등해요.

바인딩 스크립트와 치환

bindscript 인자는 binding script라고 부르는 Tcl 스크립트로, 주어진 이벤트 시퀀스가 발생할 때마다 실행돼요. 명령어는 bind 명령어가 실행된 것과 같은 인터프리터에서, 전역 레벨로 실행돼요(전역 변수만 접근 가능).

script% 문자가 있으면 스크립트는 직접 실행되지 않아요. 대신 각 %와 그 뒤 문자를 현재 이벤트의 정보로 바꿔 새 스크립트를 생성해요. 치환은 % 다음에 오는 문자에 따라 달라지며, 아래 목록에 정의돼 있어요. 달리 표시되지 않으면 치환 문자열은 현재 이벤트의 주어진 필드의 십진 값이에요.

일부 치환은 특정 이벤트 유형에만 유효해요. 다른 이벤트 유형에 쓰면 치환된 값은 정의되지 않아요.

%%

단일 퍼센트로 치환.

%#

서버가 처리한 마지막 클라이언트 요청의 번호(이벤트의 serial 필드). 모든 이벤트 유형에 유효.

%a

이벤트의 above 필드를 16진수로 포맷. Configure 이벤트에만 유효. 스태킹 순서에서 받는 윈도우 바로 아래의 형제 윈도우를 나타내며, 받는 윈도우가 맨 아래면 0.

%b

눌리거나 떼어진 버튼의 번호. ButtonPress와 ButtonRelease 이벤트에만 유효.

%c

이벤트의 count 필드. Expose 이벤트에만 유효. 아직 윈도우로 전달되지 않은 대기 중인 Expose 이벤트가 count개 있음을 나타냄.

%d

이벤트의 detail 또는 user_data 필드. %d는 detail을 식별하는 문자열로 치환.

  • Enter, Leave, FocusIn, FocusOut 이벤트의 경우 문자열은 다음 중 하나: NotifyAncestor, NotifyNonlinearVirtual, NotifyDetailNone, NotifyPointer, NotifyInferior, NotifyPointerRoot, NotifyNonlinear, NotifyVirtual
  • ConfigureRequest 이벤트의 경우: Above, Opposite, Below, None, Bottom, If, Top, If
  • 가상 이벤트의 경우: 이벤트 생성 시(보통 event generate) user_data 필드에 저장된 값, 또는 필드가 NULL이면 빈 문자열. 키 시퀀스 입력에 해당하는 가상 이벤트(event add 참조)는 user_data를 NULL로 설정.
  • 이 외의 이벤트에서는 치환된 문자열이 정의되지 않음.
%f

이벤트의 focus 필드(0 또는 1). Enter와 Leave 이벤트에만 유효. 받는 윈도우가 포커스 윈도우이거나 그 하위이면 1, 아니면 0.

%h

이벤트의 height 필드. Configure, ConfigureRequest, Create, ResizeRequest, Expose 이벤트에 유효. 윈도우의 새 또는 요청된 높이를 나타냄.

%i

이벤트의 window 필드를 16진수 정수로 표현. 모든 이벤트 유형에 유효.

%k

이벤트의 keycode 필드. KeyPress와 KeyRelease 이벤트에만 유효.

%m

이벤트의 mode 필드. 치환 문자열은 NotifyNormal, NotifyGrab, NotifyUngrab, 또는 NotifyWhileGrabbed 중 하나. Enter, FocusIn, FocusOut, Leave 이벤트에만 유효.

%o

이벤트의 override_redirect 필드. Map, Reparent, Configure 이벤트에만 유효.

%p

이벤트의 place 필드를 PlaceOnTop 또는 PlaceOnBottom 문자열 중 하나로 치환. Circulate와 CirculateRequest 이벤트에만 유효.

%s

이벤트의 state 필드. ButtonPress, ButtonRelease, Enter, KeyPress, KeyRelease, Leave, Motion 이벤트에서는 십진 문자열이 치환. Visibility에서는 VisibilityUnobscured, VisibilityPartiallyObscured, VisibilityFullyObscured 중 하나가 치환. Property 이벤트에서는 속성이 만들어졌거나 수정됐음을 나타내는 NewValue 또는 속성이 제거됐음을 나타내는 Delete 문자열이 치환.

%t

이벤트의 time 필드. 이벤트가 발생한 X 서버 타임스탬프(보통 마지막 서버 리셋 이후의 시간, 밀리초). 대부분의 이벤트에 유효.

%w

이벤트의 width 필드. 윈도우의 새 또는 요청된 너비를 나타냄. Configure, ConfigureRequest, Create, ResizeRequest, Expose 이벤트에만 유효.

%x, %y

이벤트의 x와 y 필드. ButtonPress, ButtonRelease, Motion, KeyPress, KeyRelease, MouseWheel 이벤트에서 %x%y는 받는 윈도우에 상대적인 마우스 포인터 위치를 나타냄. Macintosh의 키 이벤트에서는 Tk에 X11 KeyEvent가 보내지는 순간의 마우스 좌표로, 물리적 누름·뗌 시각보다 약간 늦을 수 있음. Enter와 Leave 이벤트에서는 마우스 포인터가 윈도우를 가로지른 위치(받는 윈도우 상대). Configure와 Create 요청에서는 부모 윈도우에 상대적인 윈도우의 x, y 좌표.

%A

이벤트에 해당하는 UNICODE 문자를 치환하거나, 이벤트가 UNICODE 문자에 해당하지 않으면(예: shift 키가 눌린 경우) 빈 문자열을 치환. X11에서 XmbLookupString(입력 메서드 지원이 꺼져 있으면 XLookupString)이 이벤트에서 UNICODE 문자로의 변환 작업을 모두 수행. X11에서는 KeyPress 이벤트에만 유효. Windows와 macOS/aqua에서는 KeyPress와 KeyRelease 이벤트에 유효.

%B

이벤트의 border_width 필드. Configure, ConfigureRequest, Create 이벤트에만 유효.

%D

MouseWheel 이벤트의 delta 값을 보고. delta 값은 마우스 휠이 움직인 회전 단위를 나타냄. 값의 부호는 마우스 휠이 스크롤된 방향을 나타냄.

%E

이벤트의 send_event 필드. 모든 이벤트 유형에 유효. 0은 '정상' 이벤트, 1은 SendEvent가 생성한 '합성' 이벤트를 나타냄.

%K

이벤트에 해당하는 keysym을 텍스트 문자열로 치환. KeyPress와 KeyRelease 이벤트에만 유효.

%M

이벤트에 대해 지금까지 매칭된 스크립트 기반 바인딩 패턴의 수. 모든 이벤트 유형에 유효.

%N

이벤트에 해당하는 keysym을 십진수로 치환. KeyPress와 KeyRelease 이벤트에만 유효.

%P

갱신되거나 삭제되는 속성의 이름(winfo atom으로 XAtom으로 변환할 수 있음). Property 이벤트에만 유효.

%R

이벤트의 root 윈도우 식별자. root 필드를 포함하는 이벤트에만 유효.

%S

이벤트의 subwindow 윈도우 식별자를 16진수로 포맷. subwindow 필드를 포함하는 이벤트에만 유효.

%T

이벤트의 type 필드. 모든 이벤트 유형에 유효.

%W

이벤트가 보고된 윈도우의 경로 이름(이벤트의 window 필드). 모든 이벤트 유형에 유효.

%X, %Y

이벤트의 x_root와 y_root 필드. 가상-루트 윈도우 매니저를 사용 중이면 치환된 값은 가상 루트의 대응하는 x, y 좌표. ButtonPress, ButtonRelease, Enter, KeyPress, KeyRelease, Leave, Motion 이벤트에만 유효. %x%y와 같은 의미지만 (가상) 루트 윈도우에 상대적인 값.

%-치환의 치환 문자열은 올바른 Tcl 리스트 원소처럼 포맷돼요. 즉 공백이나 $, { 같은 특수 문자 앞에 백슬래시가 붙을 수 있다는 뜻이에요. 이렇게 해야 binding script가 평가될 때 문자열이 Tcl 파서를 통과할 수 있어요. 대부분의 치환은 숫자나 Above 같은 잘 정의된 문자열이라 특별한 포맷이 필요 없어요. 리포맷이 일어나는 가장 흔한 경우는 %A 치환이에요. 예를 들어 scriptinsert %A이고 사용자가 타이핑한 문자가 여는 대괄호라면, 실제 실행되는 스크립트는 insert [이 돼요. 이렇게 되면 insert가 원래 치환 문자열(여는 대괄호)을 첫 인자로 받아요. 추가 백슬래시가 없었다면 Tcl이 스크립트를 제대로 파싱하지 못했을 거예요.

다중 매칭

주어진 X 이벤트에 여러 바인딩이 매칭될 수 있어요. 바인딩들이 서로 다른 tag와 연결돼 있으면 각 바인딩이 순서대로 실행돼요. 기본적으로 위젯 바인딩이 먼저 실행되고, 이어서 클래스 바인딩, toplevel 바인딩, all 바인딩 순서로 실행돼요. bindtags 명령어로 특정 윈도우의 순서를 바꾸거나 윈도우에 추가 binding tag를 연결할 수 있어요.

continuebreak 명령어를 binding script 안에서 써서 매칭된 스크립트 처리를 제어할 수 있어요.

  • binding script 안에서 continue가 호출되면, 이 binding script(다른 + 추가 스크립트 포함)는 끝나지만 Tk는 다른 tag와 연결된 binding script 처리를 계속해요.
  • binding script 안에서 break 명령어가 호출되면 그 스크립트는 끝나고, 그 이벤트에 대해 다른 스크립트는 호출되지 않아요.

binding script에서 호출된 스크립트 안에서는 return -code ok로 처리를 계속하게(추가된 + 스크립트 포함) 하거나, return -code break로 다른 모든 binding script 처리를 중단시킬 수 있어요.

특정 이벤트에 둘 이상의 바인딩이 매칭되고 같은 tag를 가지면, 가장 구체적인 바인딩이 선택되어 그 스크립트가 평가돼요. 여러 매칭 시퀀스 중 어느 것이 더 구체적인지 결정하기 위해 다음 테스트가 순서대로 적용돼요.

  1. 특정 버튼이나 키를 지정하는 이벤트 패턴이 그렇지 않은 것보다 더 구체적.
  2. (매칭된 이벤트 수 기준으로) 더 긴 시퀀스가 더 짧은 시퀀스보다 더 구체적.
  3. 한 패턴의 수식자가 다른 패턴의 수식자 부분집합이면, 수식자가 더 많은 패턴이 더 구체적.
  4. 물리 패턴이 시퀀스에 매칭되는 가상 이벤트는, 가상 이벤트와 연결되지 않은 같은 물리 패턴보다 덜 구체적.
  5. 두 개 이상의 가상 이벤트에 매칭되는 시퀀스가 주어지면 그 중 하나가 선택되지만, 그 순서는 정의되지 않음.

매칭 시퀀스가 둘 이상의 이벤트를 포함하면 테스트 (c)–(e)가 시퀀스에서 가장 최근 이벤트부터 가장 오래된 이벤트 순으로 적용돼요. 이 테스트들이 승자를 결정하지 못하면 가장 최근에 등록된 시퀀스가 승자예요.

같은 시퀀스에 의해 두 개(또는 그 이상)의 가상 이벤트가 모두 촉발되고, 그 가상 이벤트 두 개가 모두 같은 윈도우 태그에 바인딩되어 있으면, 가상 이벤트 중 하나만 촉발되고 그것은 무작위로 선택돼요:

event add <<Paste>> <Control-y>
event add <<Paste>> <Button-2>
event add <<Scroll>> <Button-2>
bind Entry <<Paste>> {puts Paste}
bind Entry <<Scroll>> {puts Scroll}

사용자가 Control-y를 입력하면 <<Paste>> 바인딩이 호출되지만, 버튼 2를 누르면 <<Paste>> 또는 <<Scroll>> 바인딩 중 하나가 호출되는데 정확히 어느 것이 호출될지는 정의되지 않아요.

X 이벤트가 기존 바인딩 어느 것에도 매칭되지 않으면 그 이벤트는 무시돼요. 바인딩되지 않은 이벤트는 오류로 간주되지 않아요.

다중 이벤트 시퀀스와 무시되는 이벤트

bind 명령어에 지정된 시퀀스가 둘 이상의 이벤트 패턴을 포함하면, 최근 이벤트들(현재 이벤트까지 포함)이 주어진 시퀀스에 매칭될 때마다 그 스크립트가 실행돼요. 즉 예를 들어 버튼 1을 반복 클릭하면 <Double-ButtonPress-1> 시퀀스는 첫 번째를 제외한 각 버튼 누름에 매칭돼요.

이벤트 시퀀스 중간에 매칭을 방해할 외부 이벤트가 발생하면, 그 외부 이벤트는 KeyPress나 ButtonPress 이벤트가 아닌 한 무시돼요. 예를 들어 <Double-ButtonPress-1>은 버튼 1 누름들 사이에 ButtonRelease 이벤트(그리고 어쩌면 Motion 이벤트)가 있어도 버튼 1 누름 시퀀스에 매칭돼요.

또한 KeyPress 이벤트 앞에는 수식자 키에 대한 다른 KeyPress 이벤트가 몇 개든 올 수 있는데, 수식자 키가 매칭을 방해하진 않아요. 예를 들어 aB 이벤트 시퀀스는 a 키 누름, a 키 뗌, Shift 키 누름, b 키 누름에 매칭돼요. Shift 누름은 수식자 키이므로 무시되거든요.

마지막으로, 여러 Motion 이벤트가 연속해서 발생하면 바인딩 시퀀스 매칭에는 마지막 것만 사용돼요.

오류

바인딩 스크립트 실행 중 오류가 발생하면 bgerror 메커니즘으로 오류를 보고해요. bgerror 명령어는 전역 레벨에서(어떤 Tcl 프로시저의 문맥 밖에서) 실행돼요.

예제

마우스 더블 클릭 시 마우스 이동을 설명하는 문자열을 출력하도록 정리하기:

bind . <Double-1> {
    puts "hi from (%x,%y)"
}

마지막으로 누른 키의 keysym 이름을 표시하는 작은 GUI:

set keysym "Press any key"
pack [label .l -textvariable keysym -padx 2m -pady 1m]
bind . <Key> {
    set keysym "You pressed %K"
}

더 알아보기

  • bgerror, bindtags, event, focus, grab, keysyms — 이벤트·바인딩 관련 명령어
  • 관련 키워드: binding, event